* [PATCH] mm/usercopy: harden bounds checking for vmalloc allocations
@ 2026-07-22 14:29 Dev Jain
2026-07-23 4:03 ` Kees Cook
0 siblings, 1 reply; 3+ messages in thread
From: Dev Jain @ 2026-07-22 14:29 UTC (permalink / raw)
To: kees, akpm
Cc: Dev Jain, gustavoars, linux-hardening, linux-mm, linux-kernel,
ryan.roberts, anshuman.khandual, david, urezki
The vmalloc allocator stores the actual allocation size inside the
vm_struct structure. We can use this bound in usercopy instead of the
page-aligned va_end to catch usercopy beyond the actual allocation size.
For vmap, the requested_size field is always page-aligned since it maps a
certain number of pages. Same for vm_map_ram (alongwith, not even having
a vm_struct). So the check is only relevant for vmalloc mappings.
Because there are early vm areas registered even before vmalloc_init,
requested_size may be zero. So also check whether the requested_size
is set.
Signed-off-by: Dev Jain <dev.jain@arm.com>
---
Applies on mm-new (3d18f3499c48).
mm/usercopy.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/mm/usercopy.c b/mm/usercopy.c
index 5de7a518b1b1c..772681aff8477 100644
--- a/mm/usercopy.c
+++ b/mm/usercopy.c
@@ -176,10 +176,28 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
if (is_vmalloc_addr(ptr) && !pagefault_disabled()) {
struct vmap_area *area = find_vmap_area(addr);
+ struct vm_struct *vm;
if (!area)
usercopy_abort("vmalloc", "no area", to_user, 0, n);
+ vm = area->vm;
+ /*
+ * Mappings with a vm_struct track the originally requested
+ * size. Check against that rather than the page-rounded
+ * vmap_area->va_end so copies cannot reach vmalloc tail
+ * padding. vmap mappings are always page aligned.
+ */
+ if (vm && (vm->flags & VM_ALLOC) && vm->requested_size) {
+ unsigned long size = vm->requested_size;
+
+ offset = addr - area->va_start;
+ if (offset > size || n > size - offset)
+ usercopy_abort("vmalloc", NULL, to_user,
+ offset, n);
+ return;
+ }
+
if (n > area->va_end - addr) {
offset = addr - area->va_start;
usercopy_abort("vmalloc", NULL, to_user, offset, n);
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH] mm/usercopy: harden bounds checking for vmalloc allocations
2026-07-22 14:29 [PATCH] mm/usercopy: harden bounds checking for vmalloc allocations Dev Jain
@ 2026-07-23 4:03 ` Kees Cook
2026-07-23 5:57 ` Dev Jain
0 siblings, 1 reply; 3+ messages in thread
From: Kees Cook @ 2026-07-23 4:03 UTC (permalink / raw)
To: Dev Jain
Cc: akpm, gustavoars, linux-hardening, linux-mm, linux-kernel,
ryan.roberts, anshuman.khandual, david, urezki
On Wed, Jul 22, 2026 at 02:29:35PM +0000, Dev Jain wrote:
> The vmalloc allocator stores the actual allocation size inside the
> vm_struct structure. We can use this bound in usercopy instead of the
> page-aligned va_end to catch usercopy beyond the actual allocation size.
>
> For vmap, the requested_size field is always page-aligned since it maps a
> certain number of pages. Same for vm_map_ram (alongwith, not even having
> a vm_struct). So the check is only relevant for vmalloc mappings.
>
> Because there are early vm areas registered even before vmalloc_init,
> requested_size may be zero. So also check whether the requested_size
> is set.
>
> Signed-off-by: Dev Jain <dev.jain@arm.com>
Looks good to me! Can you update the LKDTM tests to check for this more
tightened range check with a new vmalloc-based test?
If other mm folks can double-check this, I'll happily take this via the
hardening tree.
Thanks!
-Kees
> ---
> Applies on mm-new (3d18f3499c48).
>
> mm/usercopy.c | 18 ++++++++++++++++++
> 1 file changed, 18 insertions(+)
>
> diff --git a/mm/usercopy.c b/mm/usercopy.c
> index 5de7a518b1b1c..772681aff8477 100644
> --- a/mm/usercopy.c
> +++ b/mm/usercopy.c
> @@ -176,10 +176,28 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
>
> if (is_vmalloc_addr(ptr) && !pagefault_disabled()) {
> struct vmap_area *area = find_vmap_area(addr);
> + struct vm_struct *vm;
>
> if (!area)
> usercopy_abort("vmalloc", "no area", to_user, 0, n);
>
> + vm = area->vm;
> + /*
> + * Mappings with a vm_struct track the originally requested
> + * size. Check against that rather than the page-rounded
> + * vmap_area->va_end so copies cannot reach vmalloc tail
> + * padding. vmap mappings are always page aligned.
> + */
> + if (vm && (vm->flags & VM_ALLOC) && vm->requested_size) {
> + unsigned long size = vm->requested_size;
> +
> + offset = addr - area->va_start;
> + if (offset > size || n > size - offset)
> + usercopy_abort("vmalloc", NULL, to_user,
> + offset, n);
> + return;
> + }
> +
> if (n > area->va_end - addr) {
> offset = addr - area->va_start;
> usercopy_abort("vmalloc", NULL, to_user, offset, n);
> --
> 2.43.0
>
--
Kees Cook
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH] mm/usercopy: harden bounds checking for vmalloc allocations
2026-07-23 4:03 ` Kees Cook
@ 2026-07-23 5:57 ` Dev Jain
0 siblings, 0 replies; 3+ messages in thread
From: Dev Jain @ 2026-07-23 5:57 UTC (permalink / raw)
To: Kees Cook
Cc: akpm, gustavoars, linux-hardening, linux-mm, linux-kernel,
ryan.roberts, anshuman.khandual, david, urezki
On 23/07/26 9:33 am, Kees Cook wrote:
> On Wed, Jul 22, 2026 at 02:29:35PM +0000, Dev Jain wrote:
>> The vmalloc allocator stores the actual allocation size inside the
>> vm_struct structure. We can use this bound in usercopy instead of the
>> page-aligned va_end to catch usercopy beyond the actual allocation size.
>>
>> For vmap, the requested_size field is always page-aligned since it maps a
>> certain number of pages. Same for vm_map_ram (alongwith, not even having
>> a vm_struct). So the check is only relevant for vmalloc mappings.
>>
>> Because there are early vm areas registered even before vmalloc_init,
>> requested_size may be zero. So also check whether the requested_size
>> is set.
>>
>> Signed-off-by: Dev Jain <dev.jain@arm.com>
>
> Looks good to me! Can you update the LKDTM tests to check for this more
> tightened range check with a new vmalloc-based test?
Thanks. I have written the test, I'll send a v2 with it once the mm people
take a look at this.
>
> If other mm folks can double-check this, I'll happily take this via the
> hardening tree.
>
> Thanks!
>
> -Kees
>
>> ---
>> Applies on mm-new (3d18f3499c48).
>>
>> mm/usercopy.c | 18 ++++++++++++++++++
>> 1 file changed, 18 insertions(+)
>>
>> diff --git a/mm/usercopy.c b/mm/usercopy.c
>> index 5de7a518b1b1c..772681aff8477 100644
>> --- a/mm/usercopy.c
>> +++ b/mm/usercopy.c
>> @@ -176,10 +176,28 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
>>
>> if (is_vmalloc_addr(ptr) && !pagefault_disabled()) {
>> struct vmap_area *area = find_vmap_area(addr);
>> + struct vm_struct *vm;
>>
>> if (!area)
>> usercopy_abort("vmalloc", "no area", to_user, 0, n);
>>
>> + vm = area->vm;
>> + /*
>> + * Mappings with a vm_struct track the originally requested
>> + * size. Check against that rather than the page-rounded
>> + * vmap_area->va_end so copies cannot reach vmalloc tail
>> + * padding. vmap mappings are always page aligned.
>> + */
>> + if (vm && (vm->flags & VM_ALLOC) && vm->requested_size) {
>> + unsigned long size = vm->requested_size;
>> +
>> + offset = addr - area->va_start;
>> + if (offset > size || n > size - offset)
>> + usercopy_abort("vmalloc", NULL, to_user,
>> + offset, n);
>> + return;
>> + }
>> +
>> if (n > area->va_end - addr) {
>> offset = addr - area->va_start;
>> usercopy_abort("vmalloc", NULL, to_user, offset, n);
>> --
>> 2.43.0
>>
>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-07-23 5:57 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-22 14:29 [PATCH] mm/usercopy: harden bounds checking for vmalloc allocations Dev Jain
2026-07-23 4:03 ` Kees Cook
2026-07-23 5:57 ` Dev Jain
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox