aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2026-07-24 21:12:21 +0000
committerMark Johnston <markj@FreeBSD.org>2026-07-24 21:12:21 +0000
commit666eab3afc52bf20d57c24e98a6aa667433fb7c2 (patch)
tree804b5bf9abf025cc2c4caf90074879060e0cbbbd
parent990989c31b4637a23e64598a3d9929079bb9a8de (diff)
uma: Avoid allocating from free buckets when KASAN is enabled
When uma_zalloc_arg() hits an empty alloc bucket in the per-CPU cache, it tries swapping the alloc and free buckets in the hope that the free bucket has some items available. If not, it has to lock the zone. Disable this behaviour when KASAN is configured in order to further defer reuse of freed items. This forces a free item to go to the per-domain full bucket cache before it becomes accessible to the allocator. Reviewed by: rlibby MFC after: 1 month Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D58270
-rw-r--r--sys/vm/uma_core.c17
1 files changed, 11 insertions, 6 deletions
diff --git a/sys/vm/uma_core.c b/sys/vm/uma_core.c
index fb72fafe9abc..e5f7d92a4f2a 100644
--- a/sys/vm/uma_core.c
+++ b/sys/vm/uma_core.c
@@ -3782,6 +3782,7 @@ static __noinline bool
cache_alloc(uma_zone_t zone, uma_cache_t cache, void *udata, int flags)
{
uma_bucket_t bucket;
+ uint32_t zflags;
int curdomain, domain;
bool new;
@@ -3791,10 +3792,15 @@ cache_alloc(uma_zone_t zone, uma_cache_t cache, void *udata, int flags)
* If we have run out of items in our alloc bucket see
* if we can switch with the free bucket.
*
- * SMR Zones can't re-use the free bucket until the sequence has
- * expired.
+ * SMR zones can't re-use the free bucket until the sequence has
+ * expired. When KASAN is enabled, we want to avoid re-using free
+ * items in order to improve reliability of use-after-free detection.
*/
- if ((cache_uz_flags(cache) & UMA_ZONE_SMR) == 0 &&
+ zflags = cache_uz_flags(cache);
+ if ((zflags & UMA_ZONE_SMR) == 0 &&
+#ifdef KASAN
+ (zflags & UMA_ZONE_NOKASAN) != 0 &&
+#endif
cache->uc_freebucket.ucb_cnt != 0) {
cache_bucket_swap(&cache->uc_freebucket,
&cache->uc_allocbucket);
@@ -3823,8 +3829,7 @@ cache_alloc(uma_zone_t zone, uma_cache_t cache, void *udata, int flags)
* the critical section.
*/
domain = PCPU_GET(domain);
- if ((cache_uz_flags(cache) & UMA_ZONE_ROUNDROBIN) != 0 ||
- VM_DOMAIN_EMPTY(domain))
+ if ((zflags & UMA_ZONE_ROUNDROBIN) != 0 || VM_DOMAIN_EMPTY(domain))
domain = zone_domain_highest(zone, domain);
bucket = cache_fetch_bucket(zone, cache, domain);
if (bucket == NULL && zone->uz_bucket_size != 0 && !bucketdisable) {
@@ -3849,7 +3854,7 @@ cache_alloc(uma_zone_t zone, uma_cache_t cache, void *udata, int flags)
critical_enter();
cache = &zone->uz_cpu[curcpu];
if (cache->uc_allocbucket.ucb_bucket == NULL &&
- ((cache_uz_flags(cache) & UMA_ZONE_FIRSTTOUCH) == 0 ||
+ ((zflags & UMA_ZONE_FIRSTTOUCH) == 0 ||
(curdomain = PCPU_GET(domain)) == domain ||
VM_DOMAIN_EMPTY(curdomain))) {
if (new)