Skip to content

Commit d73778e

Browse files
keestehcaster
authored andcommitted
mm/util: Use dedicated slab buckets for memdup_user()
Both memdup_user() and vmemdup_user() handle allocations that are regularly used for exploiting use-after-free type confusion flaws in the kernel (e.g. prctl() PR_SET_VMA_ANON_NAME[1] and setxattr[2][3][4] respectively). Since both are designed for contents coming from userspace, it allows for userspace-controlled allocation sizes. Use a dedicated set of kmalloc buckets so these allocations do not share caches with the global kmalloc buckets. After a fresh boot under Ubuntu 23.10, we can see the caches are already in active use: # grep ^memdup /proc/slabinfo memdup_user-8k 4 4 8192 4 8 : ... memdup_user-4k 8 8 4096 8 8 : ... memdup_user-2k 16 16 2048 16 8 : ... memdup_user-1k 0 0 1024 16 4 : ... memdup_user-512 0 0 512 16 2 : ... memdup_user-256 0 0 256 16 1 : ... memdup_user-128 0 0 128 32 1 : ... memdup_user-64 256 256 64 64 1 : ... memdup_user-32 512 512 32 128 1 : ... memdup_user-16 1024 1024 16 256 1 : ... memdup_user-8 2048 2048 8 512 1 : ... memdup_user-192 0 0 192 21 1 : ... memdup_user-96 168 168 96 42 1 : ... Link: https://starlabs.sg/blog/2023/07-prctl-anon_vma_name-an-amusing-heap-spray/ [1] Link: https://duasynt.com/blog/linux-kernel-heap-spray [2] Link: https://etenal.me/archives/1336 [3] Link: https://github.com/a13xp0p0v/kernel-hack-drill/blob/master/drill_exploit_uaf.c [4] Signed-off-by: Kees Cook <[email protected]> Signed-off-by: Vlastimil Babka <[email protected]>
1 parent 734bbc1 commit d73778e

File tree

1 file changed

+12
-2
lines changed

1 file changed

+12
-2
lines changed

mm/util.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,16 @@ char *kmemdup_nul(const char *s, size_t len, gfp_t gfp)
198198
}
199199
EXPORT_SYMBOL(kmemdup_nul);
200200

201+
static kmem_buckets *user_buckets __ro_after_init;
202+
203+
static int __init init_user_buckets(void)
204+
{
205+
user_buckets = kmem_buckets_create("memdup_user", 0, 0, INT_MAX, NULL);
206+
207+
return 0;
208+
}
209+
subsys_initcall(init_user_buckets);
210+
201211
/**
202212
* memdup_user - duplicate memory region from user space
203213
*
@@ -211,7 +221,7 @@ void *memdup_user(const void __user *src, size_t len)
211221
{
212222
void *p;
213223

214-
p = kmalloc_track_caller(len, GFP_USER | __GFP_NOWARN);
224+
p = kmem_buckets_alloc_track_caller(user_buckets, len, GFP_USER | __GFP_NOWARN);
215225
if (!p)
216226
return ERR_PTR(-ENOMEM);
217227

@@ -237,7 +247,7 @@ void *vmemdup_user(const void __user *src, size_t len)
237247
{
238248
void *p;
239249

240-
p = kvmalloc(len, GFP_USER);
250+
p = kmem_buckets_valloc(user_buckets, len, GFP_USER);
241251
if (!p)
242252
return ERR_PTR(-ENOMEM);
243253

0 commit comments

Comments
 (0)