v5:
- add Acks
- split stddef changes into separate patch
- further refactor reporting code for readability
- adjust enforcement code for greater readability
v4:
- refactor reporting to include offset and remove %p
- explicitly WARN by default for the whitelisting
- add KVM whitelists and harden ioctl handling
v3:
- added LKDTM update patch
- downgrade BUGs to WARNs and fail closed
- add Acks/Reviews from v2
v2:
- added tracing of allocation and usage
- refactored solutions for task_struct
- split up network patches for readability
I intend for this to land via my usercopy hardening tree, so Acks,
Reviewed, and Tested-bys would be greatly appreciated. FWIW, the bulk of
this series has survived for months in 0-day testing and -next, with the
more recently-added offset-reporting having existed there for a week.
Linus, getting your attention early on this -- instead of during the
merge window :) -- would be greatly appreciated. I'm hoping this is a
good time, in a slight lull in PTI and related things needing attention.
----
This series is modified from Brad Spengler/PaX Team's PAX_USERCOPY code
in the last public patch of grsecurity/PaX based on our understanding
of the code. Changes or omissions from the original code are ours and
don't reflect the original grsecurity/PaX code.
David Windsor did the bulk of the porting, refactoring, splitting,
testing, etc; I did some extra tweaks, hunk moving, traces, and extra
patches.
Description from patch 1:
Currently, hardened usercopy performs dynamic bounds checking on slab
cache objects. This is good, but still leaves a lot of kernel memory
available to be copied to/from userspace in the face of bugs. To further
restrict what memory is available for copying, this creates a way to
whitelist specific areas of a given slab cache object for copying to/from
userspace, allowing much finer granularity of access control. Slab caches
that are never exposed to userspace can declare no whitelist for their
objects, thereby keeping them unavailable to userspace via dynamic copy
operations. (Note, an implicit form of whitelisting is the use of constant
sizes in usercopy operations and get_user()/put_user(); these bypass
hardened usercopy checks since these sizes cannot change at runtime.)
To support this whitelist annotation, usercopy region offset and size
members are added to struct kmem_cache. The slab allocator receives a
new function, kmem_cache_create_usercopy(), that creates a new cache
with a usercopy region defined, suitable for declaring spans of fields
within the objects that get copied to/from userspace.
In this patch, the default kmem_cache_create() marks the entire allocation
as whitelisted, leaving it semantically unchanged. Once all fine-grained
whitelists have been added (in subsequent patches), this will be changed
to a usersize of 0, making caches created with kmem_cache_create() not
copyable to/from userspace.
After the entire usercopy whitelist series is applied, less than 15%
of the slab cache memory remains exposed to potential usercopy bugs
after a fresh boot:
Total Slab Memory: 48074720
Usercopyable Memory: 6367532 13.2%
task_struct 0.2% 4480/1630720
RAW 0.3% 300/96000
RAWv6 2.1% 1408/64768
ext4_inode_cache 3.0% 269760/8740224
dentry 11.1% 585984/5273856
mm_struct 29.1% 54912/188448
kmalloc-8 100.0% 24576/24576
kmalloc-16 100.0% 28672/28672
kmalloc-32 100.0% 81920/81920
kmalloc-192 100.0% 96768/96768
kmalloc-128 100.0% 143360/143360
names_cache 100.0% 163840/163840
kmalloc-64 100.0% 167936/167936
kmalloc-256 100.0% 339968/339968
kmalloc-512 100.0% 350720/350720
kmalloc-96 100.0% 455616/455616
kmalloc-8192 100.0% 655360/655360
kmalloc-1024 100.0% 812032/812032
kmalloc-4096 100.0% 819200/819200
kmalloc-2048 100.0% 1310720/1310720
After some kernel build workloads, the percentage (mainly driven by
dentry and inode caches expanding) drops under 10%:
Total Slab Memory: 95516184
Usercopyable Memory: 8497452 8.8%
task_struct 0.2% 4000/1456000
RAW 0.3% 300/96000
RAWv6 2.1% 1408/64768
ext4_inode_cache 3.0% 1217280/39439872
dentry 11.1% 1623200/14608800
mm_struct 29.1% 73216/251264
kmalloc-8 100.0% 24576/24576
kmalloc-16 100.0% 28672/28672
kmalloc-32 100.0% 94208/94208
kmalloc-192 100.0% 96768/96768
kmalloc-128 100.0% 143360/143360
names_cache 100.0% 163840/163840
kmalloc-64 100.0% 245760/245760
kmalloc-256 100.0% 339968/339968
kmalloc-512 100.0% 350720/350720
kmalloc-96 100.0% 563520/563520
kmalloc-8192 100.0% 655360/655360
kmalloc-1024 100.0% 794624/794624
kmalloc-4096 100.0% 819200/819200
kmalloc-2048 100.0% 1257472/1257472
------
The patches are broken in several stages of changes:
Report offsets and drop %p usage:
[PATCH 01/38] usercopy: Remove pointer from overflow report
[PATCH 02/38] usercopy: Enhance and rename report_usercopy()
[PATCH 03/38] usercopy: Include offset in hardened usercopy report
[PATCH 04/38] lkdtm/usercopy: Adjust test to include an offset to
Prepare infrastructure, set up WARN handler, and whitelist kmalloc:
[PATCH 05/38] stddef.h: Introduce sizeof_field()
[PATCH 06/38] usercopy: Prepare for usercopy whitelisting
[PATCH 07/38] usercopy: WARN() on slab cache usercopy region
[PATCH 08/38] usercopy: Allow strict enforcement of whitelists
[PATCH 09/38] usercopy: Mark kmalloc caches as usercopy caches
Update VFS layer for symlinks and other inline storage:
[PATCH 10/38] dcache: Define usercopy region in dentry_cache slab
[PATCH 11/38] vfs: Define usercopy region in names_cache slab caches
[PATCH 12/38] vfs: Copy struct mount.mnt_id to userspace using
[PATCH 13/38] ext4: Define usercopy region in ext4_inode_cache slab
[PATCH 14/38] ext2: Define usercopy region in ext2_inode_cache slab
[PATCH 15/38] jfs: Define usercopy region in jfs_ip slab cache
[PATCH 16/38] befs: Define usercopy region in befs_inode_cache slab
[PATCH 17/38] exofs: Define usercopy region in exofs_inode_cache slab
[PATCH 18/38] orangefs: Define usercopy region in
[PATCH 19/38] ufs: Define usercopy region in ufs_inode_cache slab
[PATCH 20/38] vxfs: Define usercopy region in vxfs_inode slab cache
[PATCH 21/38] cifs: Define usercopy region in cifs_request slab cache
Update scsi layer for inline storage:
[PATCH 22/38] scsi: Define usercopy region in scsi_sense_cache slab
Whitelist a few network protocol-specific areas of memory:
[PATCH 23/38] net: Define usercopy region in struct proto slab cache
[PATCH 24/38] ip: Define usercopy region in IP proto slab cache
[PATCH 25/38] caif: Define usercopy region in caif proto slab cache
[PATCH 26/38] sctp: Define usercopy region in SCTP proto slab cache
[PATCH 27/38] sctp: Copy struct sctp_sock.autoclose to userspace
[PATCH 28/38] net: Restrict unwhitelisted proto caches to size 0
Whitelist areas of process memory:
[PATCH 29/38] fork: Define usercopy region in mm_struct slab caches
[PATCH 30/38] fork: Define usercopy region in thread_stack slab
Deal with per-architecture thread_struct whitelisting:
[PATCH 31/38] fork: Provide usercopy whitelisting for task_struct
[PATCH 32/38] x86: Implement thread_struct whitelist for hardened
[PATCH 33/38] arm64: Implement thread_struct whitelist for hardened
[PATCH 34/38] arm: Implement thread_struct whitelist for hardened
Update KVM for whitelisting:
[PATCH 35/38] kvm: whitelist struct kvm_vcpu_arch
[PATCH 36/38] kvm: x86: fix KVM_XEN_HVM_CONFIG ioctl
Make blacklisting the default:
[PATCH 37/38] usercopy: Restrict non-usercopy caches to size 0
Update LKDTM:
[PATCH 38/38] lkdtm: Update usercopy tests for whitelisting
Thanks!
-Kees (and David)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
Using %p was already mostly useless in the usercopy overflow reports,
so this removes it entirely to avoid confusion now that %p-hashing
is enabled.
Fixes: ad67b74d2469d9b8 ("printk: hash addresses printed with %p")
Signed-off-by: Kees Cook <redacted>
---
mm/usercopy.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
@@ -261,6 +260,6 @@ void __check_object_size(const void *ptr, unsigned long n, bool to_user)return;report:-report_usercopy(ptr,n,to_user,err);+report_usercopy(n,to_user,err);}EXPORT_SYMBOL(__check_object_size);
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
In preparation for refactoring the usercopy checks to pass offset to
the hardened usercopy report, this renames report_usercopy() to the
more accurate usercopy_abort(), marks it as noreturn because it is,
adds a hopefully helpful comment for anyone investigating such reports,
makes the function available to the slab allocators, and adds new "detail"
and "offset" arguments.
Signed-off-by: Kees Cook <redacted>
---
mm/slab.h | 6 ++++++
mm/usercopy.c | 24 +++++++++++++++++++-----
tools/objtool/check.c | 1 +
3 files changed, 26 insertions(+), 5 deletions(-)
@@ -138,6 +138,7 @@ static int __dead_end_function(struct objtool_file *file, struct symbol *func,"__reiserfs_panic","lbug_with_loc","fortify_panic",+"usercopy_abort",};if(func->bind==STB_WEAK)
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
This refactors the hardened usercopy code so that failure reporting can
happen within the checking functions instead of at the top level. This
simplifies the return value handling and allows more details and offsets
to be included in the report. Having the offset can be much more helpful
in understanding hardened usercopy bugs.
Signed-off-by: Kees Cook <redacted>
---
include/linux/slab.h | 12 +++----
mm/slab.c | 8 ++---
mm/slub.c | 14 ++++----
mm/usercopy.c | 95 +++++++++++++++++++++++-----------------------------
4 files changed, 57 insertions(+), 72 deletions(-)
@@ -3831,7 +3831,8 @@ const char *__check_heap_object(const void *ptr, unsigned long n,/* Reject impossible pointers. */if(ptr<page_address(page))-returns->name;+usercopy_abort("SLUB object not in SLUB page?!",NULL,+to_user,0,n);/* Find offset within object. */offset=(ptr-page_address(page))%s->size;
@@ -3839,15 +3840,16 @@ const char *__check_heap_object(const void *ptr, unsigned long n,/* Adjust for redzone and reject if within the redzone. */if(kmem_cache_debug(s)&&s->flags&SLAB_RED_ZONE){if(offset<s->red_left_pad)-returns->name;+usercopy_abort("SLUB object in left red zone",+s->name,to_user,offset,n);offset-=s->red_left_pad;}/* Allow address range falling entirely within object size. */if(offset<=object_size&&n<=object_size-offset)-returnNULL;+return;-returns->name;+usercopy_abort("SLUB object",s->name,to_user,offset,n);}#endif /* CONFIG_HARDENED_USERCOPY */
@@ -86,10 +86,10 @@ void __noreturn usercopy_abort(const char *name, const char *detail,}/* Returns true if any portion of [ptr,ptr+n) over laps with [low,high). */-staticbooloverlaps(constvoid*ptr,unsignedlongn,unsignedlonglow,-unsignedlonghigh)+staticbooloverlaps(constunsignedlongptr,unsignedlongn,+unsignedlonglow,unsignedlonghigh){-unsignedlongcheck_low=(uintptr_t)ptr;+constunsignedlongcheck_low=ptr;unsignedlongcheck_high=check_low+n;/* Does not overlap if entirely above or entirely below. */
@@ -100,15 +100,15 @@ static bool overlaps(const void *ptr, unsigned long n, unsigned long low,}/* Is this address range in the kernel text area? */-staticinlineconstchar*check_kernel_text_object(constvoid*ptr,-unsignedlongn)+staticinlinevoidcheck_kernel_text_object(constunsignedlongptr,+unsignedlongn,boolto_user){unsignedlongtextlow=(unsignedlong)_stext;unsignedlongtexthigh=(unsignedlong)_etext;unsignedlongtextlow_linear,texthigh_linear;if(overlaps(ptr,n,textlow,texthigh))-return"<kernel text>";+usercopy_abort("kernel text",NULL,to_user,ptr-textlow,n);/**Somearchitectureshavevirtualmemorymappingswithasecondary
@@ -121,32 +121,30 @@ static inline const char *check_kernel_text_object(const void *ptr,textlow_linear=(unsignedlong)lm_alias(textlow);/* No different mapping: we're done. */if(textlow_linear==textlow)-returnNULL;+return;/* Check the secondary mapping... */texthigh_linear=(unsignedlong)lm_alias(texthigh);if(overlaps(ptr,n,textlow_linear,texthigh_linear))-return"<linear kernel text>";--returnNULL;+usercopy_abort("linear kernel text",NULL,to_user,+ptr-textlow_linear,n);}-staticinlineconstchar*check_bogus_address(constvoid*ptr,unsignedlongn)+staticinlinevoidcheck_bogus_address(constunsignedlongptr,unsignedlongn,+boolto_user){/* Reject if object wraps past end of memory. */-if((unsignedlong)ptr+n<(unsignedlong)ptr)-return"<wrapped address>";+if(ptr+n<ptr)+usercopy_abort("wrapped address",NULL,to_user,0,ptr+n);/* Reject if NULL or ZERO-allocation. */if(ZERO_OR_NULL_PTR(ptr))-return"<null>";--returnNULL;+usercopy_abort("null address",NULL,to_user,ptr,n);}/* Checks for allocs that are marked in some way as spanning multiple pages. */-staticinlineconstchar*check_page_span(constvoid*ptr,unsignedlongn,-structpage*page,boolto_user)+staticinlinevoidcheck_page_span(constvoid*ptr,unsignedlongn,+structpage*page,boolto_user){#ifdef CONFIG_HARDENED_USERCOPY_PAGESPANconstvoid*end=ptr+n-1;
@@ -163,28 +161,28 @@ static inline const char *check_page_span(const void *ptr, unsigned long n,if(ptr>=(constvoid*)__start_rodata&&end<=(constvoid*)__end_rodata){if(!to_user)-return"<rodata>";-returnNULL;+usercopy_abort("rodata",NULL,to_user,0,n);+return;}/* Allow kernel data region (if not marked as Reserved). */if(ptr>=(constvoid*)_sdata&&end<=(constvoid*)_edata)-returnNULL;+return;/* Allow kernel bss region (if not marked as Reserved). */if(ptr>=(constvoid*)__bss_start&&end<=(constvoid*)__bss_stop)-returnNULL;+return;/* Is the object wholly within one base page? */if(likely(((unsignedlong)ptr&(unsignedlong)PAGE_MASK)==((unsignedlong)end&(unsignedlong)PAGE_MASK)))-returnNULL;+return;/* Allow if fully inside the same compound (__GFP_COMP) page. */endpage=virt_to_head_page(end);if(likely(endpage==page))-returnNULL;+return;/**RejectifrangeisentirelyeitherReserved(i.e.specialor
@@ -194,36 +192,37 @@ static inline const char *check_page_span(const void *ptr, unsigned long n,is_reserved=PageReserved(page);is_cma=is_migrate_cma_page(page);if(!is_reserved&&!is_cma)-return"<spans multiple pages>";+usercopy_abort("spans multiple pages",NULL,to_user,0,n);for(ptr+=PAGE_SIZE;ptr<=end;ptr+=PAGE_SIZE){page=virt_to_head_page(ptr);if(is_reserved&&!PageReserved(page))-return"<spans Reserved and non-Reserved pages>";+usercopy_abort("spans Reserved and non-Reserved pages",+NULL,to_user,0,n);if(is_cma&&!is_migrate_cma_page(page))-return"<spans CMA and non-CMA pages>";+usercopy_abort("spans CMA and non-CMA pages",NULL,+to_user,0,n);}#endif--returnNULL;}-staticinlineconstchar*check_heap_object(constvoid*ptr,unsignedlongn,-boolto_user)+staticinlinevoidcheck_heap_object(constvoid*ptr,unsignedlongn,+boolto_user){structpage*page;if(!virt_addr_valid(ptr))-returnNULL;+return;page=virt_to_head_page(ptr);-/* Check slab allocator for flags and size. */-if(PageSlab(page))-return__check_heap_object(ptr,n,page);--/* Verify object does not incorrectly span multiple pages. */-returncheck_page_span(ptr,n,page,to_user);+if(PageSlab(page)){+/* Check slab allocator for flags and size. */+__check_heap_object(ptr,n,page,to_user);+}else{+/* Verify object does not incorrectly span multiple pages. */+check_page_span(ptr,n,page,to_user);+}}/*
@@ -234,21 +233,15 @@ static inline const char *check_heap_object(const void *ptr, unsigned long n,*/void__check_object_size(constvoid*ptr,unsignedlongn,boolto_user){-constchar*err;-/* Skip all tests if size is zero. */if(!n)return;/* Check for invalid addresses. */-err=check_bogus_address(ptr,n);-if(err)-gotoreport;+check_bogus_address((constunsignedlong)ptr,n,to_user);/* Check for bad heap object. */-err=check_heap_object(ptr,n,to_user);-if(err)-gotoreport;+check_heap_object(ptr,n,to_user);/* Check for bad stack object. */switch(check_stack_object(ptr,n)){
@@ -264,16 +257,10 @@ void __check_object_size(const void *ptr, unsigned long n, bool to_user)*/return;default:-err="<process stack>";-gotoreport;+usercopy_abort("process stack",NULL,to_user,0,n);}/* Check for object in kernel to avoid text exposure. */-err=check_kernel_text_object(ptr,n);-if(!err)-return;--report:-usercopy_abort(err,NULL,to_user,0,n);+check_kernel_text_object((constunsignedlong)ptr,n,to_user);}EXPORT_SYMBOL(__check_object_size);
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
Instead of doubling the size, push the start position up by 16 bytes to
still trigger an overflow. This allows to verify that offset reporting
is working correctly.
Signed-off-by: Kees Cook <redacted>
---
drivers/misc/lkdtm_usercopy.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
@@ -139,27 +141,30 @@ static void do_usercopy_heap_size(bool to_user)memset(one,'A',size);memset(two,'B',size);+test_user_addr=(void__user*)(user_addr+16);+test_kern_addr=one+16;+if(to_user){pr_info("attempting good copy_to_user of correct size\n");-if(copy_to_user((void__user*)user_addr,one,size)){+if(copy_to_user(test_user_addr,test_kern_addr,size/2)){pr_warn("copy_to_user failed unexpectedly?!\n");gotofree_user;}pr_info("attempting bad copy_to_user of too large size\n");-if(copy_to_user((void__user*)user_addr,one,2*size)){+if(copy_to_user(test_user_addr,test_kern_addr,size)){pr_warn("copy_to_user failed, but lacked Oops\n");gotofree_user;}}else{pr_info("attempting good copy_from_user of correct size\n");-if(copy_from_user(one,(void__user*)user_addr,size)){+if(copy_from_user(test_kern_addr,test_user_addr,size/2)){pr_warn("copy_from_user failed unexpectedly?!\n");gotofree_user;}pr_info("attempting bad copy_from_user of too large size\n");-if(copy_from_user(one,(void__user*)user_addr,2*size)){+if(copy_from_user(test_kern_addr,test_user_addr,size)){pr_warn("copy_from_user failed, but lacked Oops\n");gotofree_user;}
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
The size of fields within a structure is needed in a few places in the
kernel already, and will be needed for the usercopy whitelisting when
declaring whitelist regions within structures. This creates a dedicated
macro and redefines offsetofend() to use it.
Existing usage, ignoring the 1200+ lustre assert uses:
$ git grep -E 'sizeof\(\(\((struct )?[a-zA-Z_]+ \*\)0\)->' | \
grep -v staging/lustre | wc -l
65
Signed-off-by: Kees Cook <redacted>
---
include/linux/stddef.h | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: David Windsor <redacted>
This patch prepares the slab allocator to handle caches having annotations
(useroffset and usersize) defining usercopy regions.
This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on
my understanding of the code. Changes or omissions from the original
code are mine and don't reflect the original grsecurity/PaX code.
Currently, hardened usercopy performs dynamic bounds checking on slab
cache objects. This is good, but still leaves a lot of kernel memory
available to be copied to/from userspace in the face of bugs. To further
restrict what memory is available for copying, this creates a way to
whitelist specific areas of a given slab cache object for copying to/from
userspace, allowing much finer granularity of access control. Slab caches
that are never exposed to userspace can declare no whitelist for their
objects, thereby keeping them unavailable to userspace via dynamic copy
operations. (Note, an implicit form of whitelisting is the use of constant
sizes in usercopy operations and get_user()/put_user(); these bypass
hardened usercopy checks since these sizes cannot change at runtime.)
To support this whitelist annotation, usercopy region offset and size
members are added to struct kmem_cache. The slab allocator receives a
new function, kmem_cache_create_usercopy(), that creates a new cache
with a usercopy region defined, suitable for declaring spans of fields
within the objects that get copied to/from userspace.
In this patch, the default kmem_cache_create() marks the entire allocation
as whitelisted, leaving it semantically unchanged. Once all fine-grained
whitelists have been added (in subsequent patches), this will be changed
to a usersize of 0, making caches created with kmem_cache_create() not
copyable to/from userspace.
After the entire usercopy whitelist series is applied, less than 15%
of the slab cache memory remains exposed to potential usercopy bugs
after a fresh boot:
Total Slab Memory: 48074720
Usercopyable Memory: 6367532 13.2%
task_struct 0.2% 4480/1630720
RAW 0.3% 300/96000
RAWv6 2.1% 1408/64768
ext4_inode_cache 3.0% 269760/8740224
dentry 11.1% 585984/5273856
mm_struct 29.1% 54912/188448
kmalloc-8 100.0% 24576/24576
kmalloc-16 100.0% 28672/28672
kmalloc-32 100.0% 81920/81920
kmalloc-192 100.0% 96768/96768
kmalloc-128 100.0% 143360/143360
names_cache 100.0% 163840/163840
kmalloc-64 100.0% 167936/167936
kmalloc-256 100.0% 339968/339968
kmalloc-512 100.0% 350720/350720
kmalloc-96 100.0% 455616/455616
kmalloc-8192 100.0% 655360/655360
kmalloc-1024 100.0% 812032/812032
kmalloc-4096 100.0% 819200/819200
kmalloc-2048 100.0% 1310720/1310720
After some kernel build workloads, the percentage (mainly driven by
dentry and inode caches expanding) drops under 10%:
Total Slab Memory: 95516184
Usercopyable Memory: 8497452 8.8%
task_struct 0.2% 4000/1456000
RAW 0.3% 300/96000
RAWv6 2.1% 1408/64768
ext4_inode_cache 3.0% 1217280/39439872
dentry 11.1% 1623200/14608800
mm_struct 29.1% 73216/251264
kmalloc-8 100.0% 24576/24576
kmalloc-16 100.0% 28672/28672
kmalloc-32 100.0% 94208/94208
kmalloc-192 100.0% 96768/96768
kmalloc-128 100.0% 143360/143360
names_cache 100.0% 163840/163840
kmalloc-64 100.0% 245760/245760
kmalloc-256 100.0% 339968/339968
kmalloc-512 100.0% 350720/350720
kmalloc-96 100.0% 563520/563520
kmalloc-8192 100.0% 655360/655360
kmalloc-1024 100.0% 794624/794624
kmalloc-4096 100.0% 819200/819200
kmalloc-2048 100.0% 1257472/1257472
Signed-off-by: David Windsor <redacted>
[kees: adjust commit log, split out a few extra kmalloc hunks]
[kees: add field names to function declarations]
[kees: convert BUGs to WARNs and fail closed]
[kees: add attack surface reduction analysis to commit log]
Cc: Pekka Enberg <penberg@kernel.org>
Cc: David Rientjes <rientjes@google.com>
Cc: Joonsoo Kim <redacted>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: linux-mm@kvack.org
Cc: linux-xfs@vger.kernel.org
Signed-off-by: Kees Cook <redacted>
Acked-by: Christoph Lameter <redacted>
---
include/linux/slab.h | 27 +++++++++++++++++++++------
include/linux/slab_def.h | 3 +++
include/linux/slub_def.h | 3 +++
mm/slab.c | 2 +-
mm/slab.h | 5 ++++-
mm/slab_common.c | 46 ++++++++++++++++++++++++++++++++++++++--------
mm/slub.c | 11 +++++++++--
7 files changed, 79 insertions(+), 18 deletions(-)
@@ -22,6 +22,8 @@ struct kmem_cache {unsignedintsize;/* The aligned/padded/added on size */unsignedintalign;/* Alignment as calculated */slab_flags_tflags;/* Active flags on the slab */+size_tuseroffset;/* Usercopy region offset */+size_tusersize;/* Usercopy region size */constchar*name;/* Slab name for sysfs */intrefcount;/* Use counter */void(*ctor)(void*);/* Called on object slot creation */
@@ -97,7 +99,8 @@ int __kmem_cache_create(struct kmem_cache *, slab_flags_t flags);externstructkmem_cache*create_kmalloc_cache(constchar*name,size_tsize,slab_flags_tflags);externvoidcreate_boot_cache(structkmem_cache*,constchar*name,-size_tsize,slab_flags_tflags);+size_tsize,slab_flags_tflags,size_tuseroffset,+size_tusersize);intslab_unmergeable(structkmem_cache*s);structkmem_cache*find_mergeable(size_tsize,size_talign,
@@ -879,13 +907,15 @@ bool slab_is_available(void)#ifndef CONFIG_SLOB/* Create a cache during boot when no slab services are available yet */void__initcreate_boot_cache(structkmem_cache*s,constchar*name,size_tsize,-slab_flags_tflags)+slab_flags_tflags,size_tuseroffset,size_tusersize){interr;s->name=name;s->size=s->object_size=size;s->align=calculate_alignment(flags,ARCH_KMALLOC_MINALIGN,size);+s->useroffset=useroffset;+s->usersize=usersize;slab_init_memcg_params(s);
@@ -906,7 +936,7 @@ struct kmem_cache *__init create_kmalloc_cache(const char *name, size_t size,if(!s)panic("Out of memory when creating slab %s\n",name);-create_boot_cache(s,name,size,flags);+create_boot_cache(s,name,size,flags,0,size);list_add(&s->list,&slab_caches);memcg_link_cache(s);s->refcount=1;
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
This patch adds checking of usercopy cache whitelisting, and is modified
from Brad Spengler/PaX Team's PAX_USERCOPY whitelisting code in the
last public patch of grsecurity/PaX based on my understanding of the
code. Changes or omissions from the original code are mine and don't
reflect the original grsecurity/PaX code.
The SLAB and SLUB allocators are modified to WARN() on all copy operations
in which the kernel heap memory being modified falls outside of the cache's
defined usercopy region.
Based on an earlier patch from David Windsor.
Cc: Christoph Lameter <redacted>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: David Rientjes <rientjes@google.com>
Cc: Joonsoo Kim <redacted>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Laura Abbott <redacted>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: linux-mm@kvack.org
Cc: linux-xfs@vger.kernel.org
Signed-off-by: Kees Cook <redacted>
---
mm/slab.c | 22 +++++++++++++++++++---
mm/slab.h | 2 ++
mm/slub.c | 23 +++++++++++++++++++----
mm/usercopy.c | 21 ++++++++++++++++++---
4 files changed, 58 insertions(+), 10 deletions(-)
This introduces CONFIG_HARDENED_USERCOPY_FALLBACK to control the
behavior of hardened usercopy whitelist violations. By default, whitelist
violations will continue to WARN() so that any bad or missing usercopy
whitelists can be discovered without being too disruptive.
If this config is disabled at build time or a system is booted with
"slab_common.usercopy_fallback=0", usercopy whitelists will BUG() instead
of WARN(). This is useful for admins that want to use usercopy whitelists
immediately.
Suggested-by: Matthew Garrett <redacted>
Signed-off-by: Kees Cook <redacted>
---
include/linux/slab.h | 2 ++
mm/slab.c | 3 ++-
mm/slab_common.c | 8 ++++++++
mm/slub.c | 3 ++-
security/Kconfig | 14 ++++++++++++++
5 files changed, 28 insertions(+), 2 deletions(-)
@@ -152,6 +152,20 @@ config HARDENED_USERCOPYorarepartofthekerneltext.Thiskillsentireclassesofheapoverflowexploitsandsimilarkernelmemoryexposures.+configHARDENED_USERCOPY_FALLBACK+bool"Allow usercopy whitelist violations to fallback to object size"+depends onHARDENED_USERCOPY+defaulty+help+Thisisatemporaryoptionthatallowsmissingusercopywhitelists+tobediscoveredviaaWARN()tothekernellog,insteadof+rejectingthecopy,fallingbacktonon-whitelistedhardened+usercopythatcheckstheslaballocationsizeinsteadofthe+whitelistsize.Thisoptionwillberemovedonceitseemslike+allmissingusercopywhitelistshavebeenidentifiedandfixed.+Bootingwith"slab_common.usercopy_fallback=Y/N"canchange+thissetting.+configHARDENED_USERCOPY_PAGESPANbool"Refuse to copy allocations that span multiple pages"depends onHARDENED_USERCOPY
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: David Windsor <redacted>
Mark the kmalloc slab caches as entirely whitelisted. These caches
are frequently used to fulfill kernel allocations that contain data
to be copied to/from userspace. Internal-only uses are also common,
but are scattered in the kernel. For now, mark all the kmalloc caches
as whitelisted.
This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: merged in moved kmalloc hunks, adjust commit log]
Cc: Pekka Enberg <penberg@kernel.org>
Cc: David Rientjes <rientjes@google.com>
Cc: Joonsoo Kim <redacted>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: linux-mm@kvack.org
Cc: linux-xfs@vger.kernel.org
Signed-off-by: Kees Cook <redacted>
Acked-by: Christoph Lameter <redacted>
---
mm/slab.c | 3 ++-
mm/slab.h | 3 ++-
mm/slab_common.c | 10 ++++++----
3 files changed, 10 insertions(+), 6 deletions(-)
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: David Windsor <redacted>
When a dentry name is short enough, it can be stored directly in the
dentry itself (instead in a separate kmalloc allocation). These dentry
short names, stored in struct dentry.d_iname and therefore contained in
the dentry_cache slab cache, need to be coped to userspace.
cache object allocation:
fs/dcache.c:
__d_alloc(...):
...
dentry = kmem_cache_alloc(dentry_cache, ...);
...
dentry->d_name.name = dentry->d_iname;
example usage trace:
filldir+0xb0/0x140
dcache_readdir+0x82/0x170
iterate_dir+0x142/0x1b0
SyS_getdents+0xb5/0x160
fs/readdir.c:
(called via ctx.actor by dir_emit)
filldir(..., const char *name, ...):
...
copy_to_user(..., name, namlen)
fs/libfs.c:
dcache_readdir(...):
...
next = next_positive(dentry, p, 1)
...
dir_emit(..., next->d_name.name, ...)
In support of usercopy hardening, this patch defines a region in the
dentry_cache slab cache in which userspace copy operations are allowed.
This region is known as the slab cache's usercopy region. Slab caches can
now check that each dynamic copy operation involving cache-managed memory
falls entirely within the slab's usercopy region.
This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: adjust hunks for kmalloc-specific things moved later]
[kees: adjust commit log, provide usage trace]
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Kees Cook <redacted>
---
fs/dcache.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
@@ -3601,8 +3601,9 @@ static void __init dcache_init(void)*butitisprobablynotworthitbecauseofthecachenature*ofthedcache.*/-dentry_cache=KMEM_CACHE(dentry,-SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD|SLAB_ACCOUNT);+dentry_cache=KMEM_CACHE_USERCOPY(dentry,+SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD|SLAB_ACCOUNT,+d_iname);/* Hash may have been set up in dcache_init_early */if(!hashdist)
From: David Windsor <redacted>
VFS pathnames are stored in the names_cache slab cache, either inline
or across an entire allocation entry (when approaching PATH_MAX). These
are copied to/from userspace, so they must be entirely whitelisted.
cache object allocation:
include/linux/fs.h:
#define __getname() kmem_cache_alloc(names_cachep, GFP_KERNEL)
example usage trace:
strncpy_from_user+0x4d/0x170
getname_flags+0x6f/0x1f0
user_path_at_empty+0x23/0x40
do_mount+0x69/0xda0
SyS_mount+0x83/0xd0
fs/namei.c:
getname_flags(...):
...
result = __getname();
...
kname = (char *)result->iname;
result->name = kname;
len = strncpy_from_user(kname, filename, EMBEDDED_NAME_MAX);
...
if (unlikely(len == EMBEDDED_NAME_MAX)) {
const size_t size = offsetof(struct filename, iname[1]);
kname = (char *)result;
result = kzalloc(size, GFP_KERNEL);
...
result->name = kname;
len = strncpy_from_user(kname, filename, PATH_MAX);
In support of usercopy hardening, this patch defines the entire cache
object in the names_cache slab cache as whitelisted, since it may entirely
hold name strings to be copied to/from userspace.
This patch is verbatim from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: adjust commit log, add usage trace]
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Kees Cook <redacted>
---
fs/dcache.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
From: David Windsor <redacted>
The mnt_id field can be copied with put_user(), so there is no need to
use copy_to_user(). In both cases, hardened usercopy is being bypassed
since the size is constant, and not open to runtime manipulation.
This patch is verbatim from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: adjust commit log]
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Kees Cook <redacted>
---
fs/fhandle.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
@@ -69,8 +69,7 @@ static long do_sys_name_to_handle(struct path *path,}elseretval=0;/* copy the mount id */-if(copy_to_user(mnt_id,&real_mount(path->mnt)->mnt_id,-sizeof(*mnt_id))||+if(put_user(real_mount(path->mnt)->mnt_id,mnt_id)||copy_to_user(ufh,handle,sizeof(structfile_handle)+handle_bytes))retval=-EFAULT;
From: David Windsor <redacted>
The ext4 symlink pathnames, stored in struct ext4_inode_info.i_data
and therefore contained in the ext4_inode_cache slab cache, need
to be copied to/from userspace.
cache object allocation:
fs/ext4/super.c:
ext4_alloc_inode(...):
struct ext4_inode_info *ei;
...
ei = kmem_cache_alloc(ext4_inode_cachep, GFP_NOFS);
...
return &ei->vfs_inode;
include/trace/events/ext4.h:
#define EXT4_I(inode) \
(container_of(inode, struct ext4_inode_info, vfs_inode))
fs/ext4/namei.c:
ext4_symlink(...):
...
inode->i_link = (char *)&EXT4_I(inode)->i_data;
example usage trace:
readlink_copy+0x43/0x70
vfs_readlink+0x62/0x110
SyS_readlinkat+0x100/0x130
fs/namei.c:
readlink_copy(..., link):
...
copy_to_user(..., link, len)
(inlined into vfs_readlink)
generic_readlink(dentry, ...):
struct inode *inode = d_inode(dentry);
const char *link = inode->i_link;
...
readlink_copy(..., link);
In support of usercopy hardening, this patch defines a region in the
ext4_inode_cache slab cache in which userspace copy operations are
allowed.
This region is known as the slab cache's usercopy region. Slab caches
can now check that each dynamically sized copy operation involving
cache-managed memory falls entirely within the slab's usercopy region.
This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: adjust commit log, provide usage trace]
Cc: "Theodore Ts'o" <tytso@mit.edu>
Cc: Andreas Dilger <adilger.kernel@dilger.ca>
Cc: linux-ext4@vger.kernel.org
Signed-off-by: Kees Cook <redacted>
---
fs/ext4/super.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: David Windsor <redacted>
The ext2 symlink pathnames, stored in struct ext2_inode_info.i_data and
therefore contained in the ext2_inode_cache slab cache, need to be copied
to/from userspace.
cache object allocation:
fs/ext2/super.c:
ext2_alloc_inode(...):
struct ext2_inode_info *ei;
...
ei = kmem_cache_alloc(ext2_inode_cachep, GFP_NOFS);
...
return &ei->vfs_inode;
fs/ext2/ext2.h:
EXT2_I(struct inode *inode):
return container_of(inode, struct ext2_inode_info, vfs_inode);
fs/ext2/namei.c:
ext2_symlink(...):
...
inode->i_link = (char *)&EXT2_I(inode)->i_data;
example usage trace:
readlink_copy+0x43/0x70
vfs_readlink+0x62/0x110
SyS_readlinkat+0x100/0x130
fs/namei.c:
readlink_copy(..., link):
...
copy_to_user(..., link, len);
(inlined into vfs_readlink)
generic_readlink(dentry, ...):
struct inode *inode = d_inode(dentry);
const char *link = inode->i_link;
...
readlink_copy(..., link);
In support of usercopy hardening, this patch defines a region in the
ext2_inode_cache slab cache in which userspace copy operations are
allowed.
This region is known as the slab cache's usercopy region. Slab caches
can now check that each dynamically sized copy operation involving
cache-managed memory falls entirely within the slab's usercopy region.
This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: adjust commit log, provide usage trace]
Cc: Jan Kara <jack@suse.com>
Cc: linux-ext4@vger.kernel.org
Signed-off-by: Kees Cook <redacted>
Acked-by: Jan Kara <jack@suse.cz>
---
fs/ext2/super.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: David Windsor <redacted>
The jfs symlink pathnames, stored in struct jfs_inode_info.i_inline and
therefore contained in the jfs_ip slab cache, need to be copied to/from
userspace.
cache object allocation:
fs/jfs/super.c:
jfs_alloc_inode(...):
...
jfs_inode = kmem_cache_alloc(jfs_inode_cachep, GFP_NOFS);
...
return &jfs_inode->vfs_inode;
fs/jfs/jfs_incore.h:
JFS_IP(struct inode *inode):
return container_of(inode, struct jfs_inode_info, vfs_inode);
fs/jfs/inode.c:
jfs_iget(...):
...
inode->i_link = JFS_IP(inode)->i_inline;
example usage trace:
readlink_copy+0x43/0x70
vfs_readlink+0x62/0x110
SyS_readlinkat+0x100/0x130
fs/namei.c:
readlink_copy(..., link):
...
copy_to_user(..., link, len);
(inlined in vfs_readlink)
generic_readlink(dentry, ...):
struct inode *inode = d_inode(dentry);
const char *link = inode->i_link;
...
readlink_copy(..., link);
In support of usercopy hardening, this patch defines a region in the
jfs_ip slab cache in which userspace copy operations are allowed.
This region is known as the slab cache's usercopy region. Slab caches
can now check that each dynamically sized copy operation involving
cache-managed memory falls entirely within the slab's usercopy region.
This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: adjust commit log, provide usage trace]
Cc: Dave Kleikamp <shaggy@kernel.org>
Cc: jfs-discussion@lists.sourceforge.net
Signed-off-by: Kees Cook <redacted>
Acked-by: Dave Kleikamp <redacted>
---
fs/jfs/super.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
From: David Windsor <redacted>
befs symlink pathnames, stored in struct befs_inode_info.i_data.symlink
and therefore contained in the befs_inode_cache slab cache, need to be
copied to/from userspace.
cache object allocation:
fs/befs/linuxvfs.c:
befs_alloc_inode(...):
...
bi = kmem_cache_alloc(befs_inode_cachep, GFP_KERNEL);
...
return &bi->vfs_inode;
befs_iget(...):
...
strlcpy(befs_ino->i_data.symlink, raw_inode->data.symlink,
BEFS_SYMLINK_LEN);
...
inode->i_link = befs_ino->i_data.symlink;
example usage trace:
readlink_copy+0x43/0x70
vfs_readlink+0x62/0x110
SyS_readlinkat+0x100/0x130
fs/namei.c:
readlink_copy(..., link):
...
copy_to_user(..., link, len);
(inlined in vfs_readlink)
generic_readlink(dentry, ...):
struct inode *inode = d_inode(dentry);
const char *link = inode->i_link;
...
readlink_copy(..., link);
In support of usercopy hardening, this patch defines a region in the
befs_inode_cache slab cache in which userspace copy operations are
allowed.
This region is known as the slab cache's usercopy region. Slab caches
can now check that each dynamically sized copy operation involving
cache-managed memory falls entirely within the slab's usercopy region.
This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: adjust commit log, provide usage trace]
Cc: Luis de Bethencourt <luisbg@kernel.org>
Cc: Salah Triki <salah.triki@gmail.com>
Signed-off-by: Kees Cook <redacted>
Acked-by: Luis de Bethencourt <luisbg@kernel.org>
---
fs/befs/linuxvfs.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: David Windsor <redacted>
The exofs short symlink names, stored in struct exofs_i_info.i_data and
therefore contained in the exofs_inode_cache slab cache, need to be copied
to/from userspace.
cache object allocation:
fs/exofs/super.c:
exofs_alloc_inode(...):
...
oi = kmem_cache_alloc(exofs_inode_cachep, GFP_KERNEL);
...
return &oi->vfs_inode;
fs/exofs/namei.c:
exofs_symlink(...):
...
inode->i_link = (char *)oi->i_data;
example usage trace:
readlink_copy+0x43/0x70
vfs_readlink+0x62/0x110
SyS_readlinkat+0x100/0x130
fs/namei.c:
readlink_copy(..., link):
...
copy_to_user(..., link, len);
(inlined in vfs_readlink)
generic_readlink(dentry, ...):
struct inode *inode = d_inode(dentry);
const char *link = inode->i_link;
...
readlink_copy(..., link);
In support of usercopy hardening, this patch defines a region in the
exofs_inode_cache slab cache in which userspace copy operations are
allowed.
This region is known as the slab cache's usercopy region. Slab caches
can now check that each dynamically sized copy operation involving
cache-managed memory falls entirely within the slab's usercopy region.
This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: adjust commit log, provide usage trace]
Cc: Boaz Harrosh <redacted>
Signed-off-by: Kees Cook <redacted>
---
fs/exofs/super.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: David Windsor <redacted>
orangefs symlink pathnames, stored in struct orangefs_inode_s.link_target
and therefore contained in the orangefs_inode_cache, need to be copied
to/from userspace.
cache object allocation:
fs/orangefs/super.c:
orangefs_alloc_inode(...):
...
orangefs_inode = kmem_cache_alloc(orangefs_inode_cache, ...);
...
return &orangefs_inode->vfs_inode;
fs/orangefs/orangefs-utils.c:
exofs_symlink(...):
...
inode->i_link = orangefs_inode->link_target;
example usage trace:
readlink_copy+0x43/0x70
vfs_readlink+0x62/0x110
SyS_readlinkat+0x100/0x130
fs/namei.c:
readlink_copy(..., link):
...
copy_to_user(..., link, len);
(inlined in vfs_readlink)
generic_readlink(dentry, ...):
struct inode *inode = d_inode(dentry);
const char *link = inode->i_link;
...
readlink_copy(..., link);
In support of usercopy hardening, this patch defines a region in the
orangefs_inode_cache slab cache in which userspace copy operations are
allowed.
This region is known as the slab cache's usercopy region. Slab caches
can now check that each dynamically sized copy operation involving
cache-managed memory falls entirely within the slab's usercopy region.
This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: adjust commit log, provide usage trace]
Cc: Mike Marshall <hubcap@omnibond.com>
Signed-off-by: Kees Cook <redacted>
---
fs/orangefs/super.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: David Windsor <redacted>
The ufs symlink pathnames, stored in struct ufs_inode_info.i_u1.i_symlink
and therefore contained in the ufs_inode_cache slab cache, need to be
copied to/from userspace.
cache object allocation:
fs/ufs/super.c:
ufs_alloc_inode(...):
...
ei = kmem_cache_alloc(ufs_inode_cachep, GFP_NOFS);
...
return &ei->vfs_inode;
fs/ufs/ufs.h:
UFS_I(struct inode *inode):
return container_of(inode, struct ufs_inode_info, vfs_inode);
fs/ufs/namei.c:
ufs_symlink(...):
...
inode->i_link = (char *)UFS_I(inode)->i_u1.i_symlink;
example usage trace:
readlink_copy+0x43/0x70
vfs_readlink+0x62/0x110
SyS_readlinkat+0x100/0x130
fs/namei.c:
readlink_copy(..., link):
...
copy_to_user(..., link, len);
(inlined in vfs_readlink)
generic_readlink(dentry, ...):
struct inode *inode = d_inode(dentry);
const char *link = inode->i_link;
...
readlink_copy(..., link);
In support of usercopy hardening, this patch defines a region in the
ufs_inode_cache slab cache in which userspace copy operations are allowed.
This region is known as the slab cache's usercopy region. Slab caches
can now check that each dynamically sized copy operation involving
cache-managed memory falls entirely within the slab's usercopy region.
This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: adjust commit log, provide usage trace]
Cc: Evgeniy Dushistov <redacted>
Signed-off-by: Kees Cook <redacted>
---
fs/ufs/super.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: David Windsor <redacted>
vxfs symlink pathnames, stored in struct vxfs_inode_info field
vii_immed.vi_immed and therefore contained in the vxfs_inode slab cache,
need to be copied to/from userspace.
cache object allocation:
fs/freevxfs/vxfs_super.c:
vxfs_alloc_inode(...):
...
vi = kmem_cache_alloc(vxfs_inode_cachep, GFP_KERNEL);
...
return &vi->vfs_inode;
fs/freevxfs/vxfs_inode.c:
cxfs_iget(...):
...
inode->i_link = vip->vii_immed.vi_immed;
example usage trace:
readlink_copy+0x43/0x70
vfs_readlink+0x62/0x110
SyS_readlinkat+0x100/0x130
fs/namei.c:
readlink_copy(..., link):
...
copy_to_user(..., link, len);
(inlined in vfs_readlink)
generic_readlink(dentry, ...):
struct inode *inode = d_inode(dentry);
const char *link = inode->i_link;
...
readlink_copy(..., link);
In support of usercopy hardening, this patch defines a region in the
vxfs_inode slab cache in which userspace copy operations are allowed.
This region is known as the slab cache's usercopy region. Slab caches
can now check that each dynamically sized copy operation involving
cache-managed memory falls entirely within the slab's usercopy region.
This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: adjust commit log, provide usage trace]
Cc: Christoph Hellwig <hch@infradead.org>
Signed-off-by: Kees Cook <redacted>
---
fs/freevxfs/vxfs_super.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: David Windsor <redacted>
CIFS request buffers, stored in the cifs_request slab cache, need to be
copied to/from userspace.
cache object allocation:
fs/cifs/cifsfs.c:
cifs_init_request_bufs():
...
cifs_req_poolp = mempool_create_slab_pool(cifs_min_rcv,
cifs_req_cachep);
fs/cifs/misc.c:
cifs_buf_get():
...
ret_buf = mempool_alloc(cifs_req_poolp, GFP_NOFS);
...
return ret_buf;
In support of usercopy hardening, this patch defines a region in the
cifs_request slab cache in which userspace copy operations are allowed.
This region is known as the slab cache's usercopy region. Slab caches
can now check that each dynamically sized copy operation involving
cache-managed memory falls entirely within the slab's usercopy region.
This patch is verbatim from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: adjust commit log, provide usage trace]
Cc: Steve French <sfrench@samba.org>
Cc: linux-cifs@vger.kernel.org
Signed-off-by: Kees Cook <redacted>
---
fs/cifs/cifsfs.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
From: David Windsor <redacted>
SCSI sense buffers, stored in struct scsi_cmnd.sense and therefore
contained in the scsi_sense_cache slab cache, need to be copied to/from
userspace.
cache object allocation:
drivers/scsi/scsi_lib.c:
scsi_select_sense_cache(...):
return ... ? scsi_sense_isadma_cache : scsi_sense_cache
scsi_alloc_sense_buffer(...):
return kmem_cache_alloc_node(scsi_select_sense_cache(), ...);
scsi_init_request(...):
...
cmd->sense_buffer = scsi_alloc_sense_buffer(...);
...
cmd->req.sense = cmd->sense_buffer
example usage trace:
block/scsi_ioctl.c:
(inline from sg_io)
blk_complete_sghdr_rq(...):
struct scsi_request *req = scsi_req(rq);
...
copy_to_user(..., req->sense, len)
scsi_cmd_ioctl(...):
sg_io(...);
In support of usercopy hardening, this patch defines a region in
the scsi_sense_cache slab cache in which userspace copy operations
are allowed.
This region is known as the slab cache's usercopy region. Slab caches
can now check that each dynamically sized copy operation involving
cache-managed memory falls entirely within the slab's usercopy region.
Signed-off-by: David Windsor <redacted>
[kees: adjust commit log, provide usage trace]
Cc: "James E.J. Bottomley" <redacted>
Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: linux-scsi@vger.kernel.org
Signed-off-by: Kees Cook <redacted>
---
drivers/scsi/scsi_lib.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
@@ -79,14 +79,15 @@ int scsi_init_sense_cache(struct Scsi_Host *shost)if(shost->unchecked_isa_dma){scsi_sense_isadma_cache=kmem_cache_create("scsi_sense_cache(DMA)",-SCSI_SENSE_BUFFERSIZE,0,-SLAB_HWCACHE_ALIGN|SLAB_CACHE_DMA,NULL);+SCSI_SENSE_BUFFERSIZE,0,+SLAB_HWCACHE_ALIGN|SLAB_CACHE_DMA,NULL);if(!scsi_sense_isadma_cache)ret=-ENOMEM;}else{scsi_sense_cache=-kmem_cache_create("scsi_sense_cache",-SCSI_SENSE_BUFFERSIZE,0,SLAB_HWCACHE_ALIGN,NULL);+kmem_cache_create_usercopy("scsi_sense_cache",+SCSI_SENSE_BUFFERSIZE,0,SLAB_HWCACHE_ALIGN,+0,SCSI_SENSE_BUFFERSIZE,NULL);if(!scsi_sense_cache)ret=-ENOMEM;}
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: David Windsor <redacted>
In support of usercopy hardening, this patch defines a region in the
struct proto slab cache in which userspace copy operations are allowed.
Some protocols need to copy objects to/from userspace, and they can
declare the region via their proto structure with the new usersize and
useroffset fields. Initially, if no region is specified (usersize ==
0), the entire field is marked as whitelisted. This allows protocols
to be whitelisted in subsequent patches. Once all protocols have been
annotated, the full-whitelist default can be removed.
This region is known as the slab cache's usercopy region. Slab caches
can now check that each dynamically sized copy operation involving
cache-managed memory falls entirely within the slab's usercopy region.
This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: adjust commit log, split off per-proto patches]
[kees: add logic for by-default full-whitelist]
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Paolo Abeni <pabeni@redhat.com>
Cc: David Howells <dhowells@redhat.com>
Cc: netdev@vger.kernel.org
Signed-off-by: Kees Cook <redacted>
---
include/net/sock.h | 2 ++
net/core/sock.c | 6 +++++-
2 files changed, 7 insertions(+), 1 deletion(-)
@@ -1112,6 +1112,8 @@ struct proto {structkmem_cache*slab;unsignedintobj_size;slab_flags_tslab_flags;+size_tuseroffset;/* Usercopy region offset */+size_tusersize;/* Usercopy region size */structpercpu_counter*orphan_count;
@@ -3151,8 +3151,12 @@ static int req_prot_init(const struct proto *prot)intproto_register(structproto*prot,intalloc_slab){if(alloc_slab){-prot->slab=kmem_cache_create(prot->name,prot->obj_size,0,+prot->slab=kmem_cache_create_usercopy(prot->name,+prot->obj_size,0,SLAB_HWCACHE_ALIGN|prot->slab_flags,+prot->usersize?prot->useroffset:0,+prot->usersize?prot->usersize+:prot->obj_size,NULL);if(prot->slab==NULL){
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: David Windsor <redacted>
The ICMP filters for IPv4 and IPv6 raw sockets need to be copied to/from
userspace. In support of usercopy hardening, this patch defines a region
in the struct proto slab cache in which userspace copy operations are
allowed.
example usage trace:
net/ipv4/raw.c:
raw_seticmpfilter(...):
...
copy_from_user(&raw_sk(sk)->filter, ..., optlen)
raw_geticmpfilter(...):
...
copy_to_user(..., &raw_sk(sk)->filter, len)
net/ipv6/raw.c:
rawv6_seticmpfilter(...):
...
copy_from_user(&raw6_sk(sk)->filter, ..., optlen)
rawv6_geticmpfilter(...):
...
copy_to_user(..., &raw6_sk(sk)->filter, len)
This region is known as the slab cache's usercopy region. Slab caches
can now check that each dynamically sized copy operation involving
cache-managed memory falls entirely within the slab's usercopy region.
This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: split from network patch, provide usage trace]
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Alexey Kuznetsov <redacted>
Cc: Hideaki YOSHIFUJI <redacted>
Cc: netdev@vger.kernel.org
Signed-off-by: Kees Cook <redacted>
---
net/ipv4/raw.c | 2 ++
net/ipv6/raw.c | 2 ++
2 files changed, 4 insertions(+)
@@ -1272,6 +1272,8 @@ struct proto rawv6_prot = {.hash=raw_hash_sk,.unhash=raw_unhash_sk,.obj_size=sizeof(structraw6_sock),+.useroffset=offsetof(structraw6_sock,filter),+.usersize=sizeof_field(structraw6_sock,filter),.h.raw_hash=&raw_v6_hashinfo,#ifdef CONFIG_COMPAT.compat_setsockopt=compat_rawv6_setsockopt,
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: David Windsor <redacted>
The CAIF channel connection request parameters need to be copied to/from
userspace. In support of usercopy hardening, this patch defines a region
in the struct proto slab cache in which userspace copy operations are
allowed.
example usage trace:
net/caif/caif_socket.c:
setsockopt(...):
...
copy_from_user(&cf_sk->conn_req.param.data, ..., ol)
This region is known as the slab cache's usercopy region. Slab caches
can now check that each dynamically sized copy operation involving
cache-managed memory falls entirely within the slab's usercopy region.
This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: split from network patch, provide usage trace]
Cc: "David S. Miller" <davem@davemloft.net>
Cc: netdev@vger.kernel.org
Signed-off-by: Kees Cook <redacted>
---
net/caif/caif_socket.c | 2 ++
1 file changed, 2 insertions(+)
@@ -1032,6 +1032,8 @@ static int caif_create(struct net *net, struct socket *sock, int protocol,staticstructprotoprot={.name="PF_CAIF",.owner=THIS_MODULE,.obj_size=sizeof(structcaifsock),+.useroffset=offsetof(structcaifsock,conn_req.param),+.usersize=sizeof_field(structcaifsock,conn_req.param)};if(!capable(CAP_SYS_ADMIN)&&!capable(CAP_NET_ADMIN))
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: David Windsor <redacted>
The SCTP socket event notification subscription information need to be
copied to/from userspace. In support of usercopy hardening, this patch
defines a region in the struct proto slab cache in which userspace copy
operations are allowed. Additionally moves the usercopy fields to be
adjacent for the region to cover both.
example usage trace:
net/sctp/socket.c:
sctp_getsockopt_events(...):
...
copy_to_user(..., &sctp_sk(sk)->subscribe, len)
sctp_setsockopt_events(...):
...
copy_from_user(&sctp_sk(sk)->subscribe, ..., optlen)
sctp_getsockopt_initmsg(...):
...
copy_to_user(..., &sctp_sk(sk)->initmsg, len)
This region is known as the slab cache's usercopy region. Slab caches
can now check that each dynamically sized copy operation involving
cache-managed memory falls entirely within the slab's usercopy region.
This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: split from network patch, move struct members adjacent]
[kees: add SCTPv6 struct whitelist, provide usage trace]
Cc: Vlad Yasevich <redacted>
Cc: Neil Horman <nhorman@tuxdriver.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: linux-sctp@vger.kernel.org
Cc: netdev@vger.kernel.org
Signed-off-by: Kees Cook <redacted>
---
include/net/sctp/structs.h | 9 +++++++--
net/sctp/socket.c | 8 ++++++++
2 files changed, 15 insertions(+), 2 deletions(-)
@@ -8470,6 +8470,10 @@ struct proto sctp_prot = {.unhash=sctp_unhash,.get_port=sctp_get_port,.obj_size=sizeof(structsctp_sock),+.useroffset=offsetof(structsctp_sock,subscribe),+.usersize=offsetof(structsctp_sock,initmsg)-+offsetof(structsctp_sock,subscribe)++sizeof_field(structsctp_sock,initmsg),.sysctl_mem=sysctl_sctp_mem,.sysctl_rmem=sysctl_sctp_rmem,.sysctl_wmem=sysctl_sctp_wmem,
@@ -8509,6 +8513,10 @@ struct proto sctpv6_prot = {.unhash=sctp_unhash,.get_port=sctp_get_port,.obj_size=sizeof(structsctp6_sock),+.useroffset=offsetof(structsctp6_sock,sctp.subscribe),+.usersize=offsetof(structsctp6_sock,sctp.initmsg)-+offsetof(structsctp6_sock,sctp.subscribe)++sizeof_field(structsctp6_sock,sctp.initmsg),.sysctl_mem=sysctl_sctp_mem,.sysctl_rmem=sysctl_sctp_rmem,.sysctl_wmem=sysctl_sctp_wmem,
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: David Windsor <redacted>
The autoclose field can be copied with put_user(), so there is no need to
use copy_to_user(). In both cases, hardened usercopy is being bypassed
since the size is constant, and not open to runtime manipulation.
This patch is verbatim from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: adjust commit log]
Cc: Vlad Yasevich <redacted>
Cc: Neil Horman <nhorman@tuxdriver.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: linux-sctp@vger.kernel.org
Cc: netdev@vger.kernel.org
Signed-off-by: Kees Cook <redacted>
---
net/sctp/socket.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
@@ -5011,7 +5011,7 @@ static int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optvlen=sizeof(int);if(put_user(len,optlen))return-EFAULT;-if(copy_to_user(optval,&sctp_sk(sk)->autoclose,sizeof(int)))+if(put_user(sctp_sk(sk)->autoclose,(int__user*)optval))return-EFAULT;return0;}
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
Now that protocols have been annotated (the copy of icsk_ca_ops->name
is of an ops field from outside the slab cache):
$ git grep 'copy_.*_user.*sk.*->'
caif/caif_socket.c: copy_from_user(&cf_sk->conn_req.param.data, ov, ol)) {
ipv4/raw.c: if (copy_from_user(&raw_sk(sk)->filter, optval, optlen))
ipv4/raw.c: copy_to_user(optval, &raw_sk(sk)->filter, len))
ipv4/tcp.c: if (copy_to_user(optval, icsk->icsk_ca_ops->name, len))
ipv4/tcp.c: if (copy_to_user(optval, icsk->icsk_ulp_ops->name, len))
ipv6/raw.c: if (copy_from_user(&raw6_sk(sk)->filter, optval, optlen))
ipv6/raw.c: if (copy_to_user(optval, &raw6_sk(sk)->filter, len))
sctp/socket.c: if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen))
sctp/socket.c: if (copy_to_user(optval, &sctp_sk(sk)->subscribe, len))
sctp/socket.c: if (copy_to_user(optval, &sctp_sk(sk)->initmsg, len))
we can switch the default proto usercopy region to size 0. Any protocols
needing to add whitelisted regions must annotate the fields with the
useroffset and usersize fields of struct proto.
This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Paolo Abeni <pabeni@redhat.com>
Cc: David Howells <dhowells@redhat.com>
Cc: netdev@vger.kernel.org
Signed-off-by: Kees Cook <redacted>
---
net/core/sock.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
@@ -3154,9 +3154,7 @@ int proto_register(struct proto *prot, int alloc_slab)prot->slab=kmem_cache_create_usercopy(prot->name,prot->obj_size,0,SLAB_HWCACHE_ALIGN|prot->slab_flags,-prot->usersize?prot->useroffset:0,-prot->usersize?prot->usersize-:prot->obj_size,+prot->useroffset,prot->usersize,NULL);if(prot->slab==NULL){
From: David Windsor <redacted>
In support of usercopy hardening, this patch defines a region in the
mm_struct slab caches in which userspace copy operations are allowed.
Only the auxv field is copied to userspace.
cache object allocation:
kernel/fork.c:
#define allocate_mm() (kmem_cache_alloc(mm_cachep, GFP_KERNEL))
dup_mm():
...
mm = allocate_mm();
copy_mm(...):
...
dup_mm();
copy_process(...):
...
copy_mm(...)
_do_fork(...):
...
copy_process(...)
example usage trace:
fs/binfmt_elf.c:
create_elf_tables(...):
...
elf_info = (elf_addr_t *)current->mm->saved_auxv;
...
copy_to_user(..., elf_info, ei_index * sizeof(elf_addr_t))
load_elf_binary(...):
...
create_elf_tables(...);
This region is known as the slab cache's usercopy region. Slab caches
can now check that each dynamically sized copy operation involving
cache-managed memory falls entirely within the slab's usercopy region.
This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: adjust commit log, split patch, provide usage trace]
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Thomas Gleixner <redacted>
Cc: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Kees Cook <redacted>
Acked-by: Rik van Riel <redacted>
---
kernel/fork.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: David Windsor <redacted>
In support of usercopy hardening, this patch defines a region in the
thread_stack slab caches in which userspace copy operations are allowed.
Since the entire thread_stack needs to be available to userspace, the
entire slab contents are whitelisted. Note that the slab-based thread
stack is only present on systems with THREAD_SIZE < PAGE_SIZE and
!CONFIG_VMAP_STACK.
cache object allocation:
kernel/fork.c:
alloc_thread_stack_node(...):
return kmem_cache_alloc_node(thread_stack_cache, ...)
dup_task_struct(...):
...
stack = alloc_thread_stack_node(...)
...
tsk->stack = stack;
copy_process(...):
...
dup_task_struct(...)
_do_fork(...):
...
copy_process(...)
This region is known as the slab cache's usercopy region. Slab caches
can now check that each dynamically sized copy operation involving
cache-managed memory falls entirely within the slab's usercopy region.
This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: adjust commit log, split patch, provide usage trace]
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Thomas Gleixner <redacted>
Cc: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Kees Cook <redacted>
Acked-by: Rik van Riel <redacted>
---
kernel/fork.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
While the blocked and saved_sigmask fields of task_struct are copied to
userspace (via sigmask_to_save() and setup_rt_frame()), it is always
copied with a static length (i.e. sizeof(sigset_t)).
The only portion of task_struct that is potentially dynamically sized and
may be copied to userspace is in the architecture-specific thread_struct
at the end of task_struct.
cache object allocation:
kernel/fork.c:
alloc_task_struct_node(...):
return kmem_cache_alloc_node(task_struct_cachep, ...);
dup_task_struct(...):
...
tsk = alloc_task_struct_node(node);
copy_process(...):
...
dup_task_struct(...)
_do_fork(...):
...
copy_process(...)
example usage trace:
arch/x86/kernel/fpu/signal.c:
__fpu__restore_sig(...):
...
struct task_struct *tsk = current;
struct fpu *fpu = &tsk->thread.fpu;
...
__copy_from_user(&fpu->state.xsave, ..., state_size);
fpu__restore_sig(...):
...
return __fpu__restore_sig(...);
arch/x86/kernel/signal.c:
restore_sigcontext(...):
...
fpu__restore_sig(...)
This introduces arch_thread_struct_whitelist() to let an architecture
declare specifically where the whitelist should be within thread_struct.
If undefined, the entire thread_struct field is left whitelisted.
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Laura Abbott <redacted>
Cc: "Mickaël Salaün" <mic@digikod.net>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Thomas Gleixner <redacted>
Cc: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Kees Cook <redacted>
Acked-by: Rik van Riel <redacted>
---
arch/Kconfig | 11 +++++++++++
include/linux/sched/task.h | 14 ++++++++++++++
kernel/fork.c | 22 ++++++++++++++++++++--
3 files changed, 45 insertions(+), 2 deletions(-)
@@ -242,6 +242,17 @@ config ARCH_INIT_TASKconfigARCH_TASK_STRUCT_ALLOCATORbool+configHAVE_ARCH_THREAD_STRUCT_WHITELIST+bool+depends on!ARCH_TASK_STRUCT_ALLOCATOR+help+Anarchitectureshouldselectthistoprovidehardenedusercopy+knowledgeaboutwhatregionofthethread_structshouldbe+whitelistedforcopyingtouserspace.Normallythisisonlythe+FPUregisters.Specifically,arch_thread_struct_whitelist()+shouldbeimplemented.Withoutthis,theentirethread_struct+fieldintask_structwillbeleftwhitelisted.+# Select if arch has its private alloc_thread_stack() functionconfigARCH_THREAD_STACK_ALLOCATORbool
@@ -458,6 +458,21 @@ static void set_max_threads(unsigned int max_threads_suggested)intarch_task_struct_size__read_mostly;#endif+staticvoidtask_struct_whitelist(unsignedlong*offset,unsignedlong*size)+{+/* Fetch thread_struct whitelist for the architecture. */+arch_thread_struct_whitelist(offset,size);++/*+*Handlezero-sizedwhitelistoremptythread_struct,otherwise+*adjustoffsettopositionofthread_structintask_struct.+*/+if(unlikely(*size==0))+*offset=0;+else+*offset+=offsetof(structtask_struct,thread);+}+void__initfork_init(void){inti;
@@ -466,11 +481,14 @@ void __init fork_init(void)#define ARCH_MIN_TASKALIGN 0#endifintalign=max_t(int,L1_CACHE_BYTES,ARCH_MIN_TASKALIGN);+unsignedlonguseroffset,usersize;/* create a slab on which task_structs can be allocated */-task_struct_cachep=kmem_cache_create("task_struct",+task_struct_whitelist(&useroffset,&usersize);+task_struct_cachep=kmem_cache_create_usercopy("task_struct",arch_task_struct_size,align,-SLAB_PANIC|SLAB_ACCOUNT,NULL);+SLAB_PANIC|SLAB_ACCOUNT,+useroffset,usersize,NULL);#endif/* do the arch specific task caches init */
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
@@ -492,6 +492,14 @@ struct thread_struct {*/};+/* Whitelist the FPU state from the task_struct for hardened usercopy. */+staticinlinevoidarch_thread_struct_whitelist(unsignedlong*offset,+unsignedlong*size)+{+*offset=offsetof(structthread_struct,fpu.state);+*size=fpu_kernel_xstate_size;+}+/**Thread-synchronousstatus.*
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
@@ -113,6 +113,14 @@ struct thread_struct {structdebug_infodebug;/* debugging */};+/* Whitelist the fpsimd_state for copying to userspace. */+staticinlinevoidarch_thread_struct_whitelist(unsignedlong*offset,+unsignedlong*size)+{+*offset=offsetof(structthread_struct,fpsimd_state);+*size=sizeof(structfpsimd_state);+}+#ifdef CONFIG_COMPAT#define task_user_tls(t) \({\
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
ARM does not carry FPU state in the thread structure, so it can declare
no usercopy whitelist at all.
Cc: Russell King <linux@armlinux.org.uk>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Christian Borntraeger <redacted>
Cc: "Peter Zijlstra (Intel)" <peterz@infradead.org>
Cc: linux-arm-kernel@lists.infradead.org
Signed-off-by: Kees Cook <redacted>
---
arch/arm/Kconfig | 1 +
arch/arm/include/asm/processor.h | 7 +++++++
2 files changed, 8 insertions(+)
From: Paolo Bonzini <pbonzini@redhat.com>
On x86, ARM and s390, struct kvm_vcpu_arch has a usercopy region
that is read and written by the KVM_GET/SET_CPUID2 ioctls (x86)
or KVM_GET/SET_ONE_REG (ARM/s390). Without whitelisting the area,
KVM is completely broken on those architectures with usercopy hardening
enabled.
For now, allow writing to the entire struct on all architectures.
The KVM tree will not refine this to an architecture-specific
subset of struct kvm_vcpu_arch.
Cc: kernel-hardening@lists.openwall.com
Cc: Kees Cook <redacted>
Cc: Christian Borntraeger <redacted>
Cc: Christoffer Dall <redacted>
Cc: Radim Krčmář <redacted>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Acked-by: Christoffer Dall <redacted>
Acked-by: Marc Zyngier <redacted>
Acked-by: Christian Borntraeger <redacted>
Signed-off-by: Kees Cook <redacted>
---
virt/kvm/kvm_main.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
@@ -4029,8 +4029,12 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align,/* A kmem cache lets us meet the alignment requirements of fx_save. */if(!vcpu_align)vcpu_align=__alignof__(structkvm_vcpu);-kvm_vcpu_cache=kmem_cache_create("kvm_vcpu",vcpu_size,vcpu_align,-SLAB_ACCOUNT,NULL);+kvm_vcpu_cache=+kmem_cache_create_usercopy("kvm_vcpu",vcpu_size,vcpu_align,+SLAB_ACCOUNT,+offsetof(structkvm_vcpu,arch),+sizeof_field(structkvm_vcpu,arch),+NULL);if(!kvm_vcpu_cache){r=-ENOMEM;gotoout_free_3;
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Paolo Bonzini <pbonzini@redhat.com>
This ioctl is obsolete (it was used by Xenner as far as I know) but
still let's not break it gratuitously... Its handler is copying
directly into struct kvm. Go through a bounce buffer instead, with
the added benefit that we can actually do something useful with the
flags argument---the previous code was exiting with -EINVAL but still
doing the copy.
This technically is a userspace ABI breakage, but since no one should be
using the ioctl, it's a good occasion to see if someone actually
complains.
Cc: kernel-hardening@lists.openwall.com
Cc: Kees Cook <redacted>
Cc: Radim Krčmář <redacted>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kees Cook <redacted>
---
arch/x86/kvm/x86.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
@@ -4238,13 +4238,14 @@ long kvm_arch_vm_ioctl(struct file *filp,mutex_unlock(&kvm->lock);break;caseKVM_XEN_HVM_CONFIG:{+structkvm_xen_hvm_configxhc;r=-EFAULT;-if(copy_from_user(&kvm->arch.xen_hvm_config,argp,-sizeof(structkvm_xen_hvm_config)))+if(copy_from_user(&xhc,argp,sizeof(xhc)))gotoout;r=-EINVAL;-if(kvm->arch.xen_hvm_config.flags)+if(xhc.flags)gotoout;+memcpy(&kvm->arch.xen_hvm_config,&xhc,sizeof(xhc));r=0;break;}
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
With all known usercopied cache whitelists now defined in the
kernel, switch the default usercopy region of kmem_cache_create()
to size 0. Any new caches with usercopy regions will now need to use
kmem_cache_create_usercopy() instead of kmem_cache_create().
This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Cc: David Windsor <redacted>
Cc: Christoph Lameter <redacted>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: David Rientjes <rientjes@google.com>
Cc: Joonsoo Kim <redacted>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: linux-mm@kvack.org
Signed-off-by: Kees Cook <redacted>
---
mm/slab_common.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
This updates the USERCOPY_HEAP_FLAG_* tests to USERCOPY_HEAP_WHITELIST_*,
since the final form of usercopy whitelisting ended up using an offset/size
window instead of the earlier proposed allocation flags.
Signed-off-by: Kees Cook <redacted>
---
drivers/misc/lkdtm.h | 4 +-
drivers/misc/lkdtm_core.c | 4 +-
drivers/misc/lkdtm_usercopy.c | 88 ++++++++++++++++++++++++-------------------
3 files changed, 53 insertions(+), 43 deletions(-)
@@ -20,7 +20,7 @@*/staticvolatilesize_tunconst=0;staticvolatilesize_tcache_size=1024;-staticstructkmem_cache*bad_cache;+staticstructkmem_cache*whitelist_cache;staticconstunsignedchartest_text[]="This is a test.\n";
@@ -177,77 +181,79 @@ static void do_usercopy_heap_size(bool to_user)kfree(two);}-staticvoiddo_usercopy_heap_flag(boolto_user)+/*+*Thischecksforthespecificwhitelistwindowwithinanobject.Ifthis+*testpasses,thendo_usercopy_heap_size()testswillpasstoo.+*/+staticvoiddo_usercopy_heap_whitelist(boolto_user){-unsignedlonguser_addr;-unsignedchar*good_buf=NULL;-unsignedchar*bad_buf=NULL;+unsignedlonguser_alloc;+unsignedchar*buf=NULL;+unsignedchar__user*user_addr;+size_toffset,size;/* Make sure cache was prepared. */-if(!bad_cache){+if(!whitelist_cache){pr_warn("Failed to allocate kernel cache\n");return;}/*-*Allocateonebufferfromeachcache(kmallocwillhavethe-*SLAB_USERCOPYflagalready,but"bad_cache"won't).+*Allocateabufferwithawhitelistedwindowinthebuffer.*/-good_buf=kmalloc(cache_size,GFP_KERNEL);-bad_buf=kmem_cache_alloc(bad_cache,GFP_KERNEL);-if(!good_buf||!bad_buf){-pr_warn("Failed to allocate buffers from caches\n");+buf=kmem_cache_alloc(whitelist_cache,GFP_KERNEL);+if(!buf){+pr_warn("Failed to allocate buffer from whitelist cache\n");gotofree_alloc;}/* Allocate user memory we'll poke at. */-user_addr=vm_mmap(NULL,0,PAGE_SIZE,+user_alloc=vm_mmap(NULL,0,PAGE_SIZE,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_ANONYMOUS|MAP_PRIVATE,0);-if(user_addr>=TASK_SIZE){+if(user_alloc>=TASK_SIZE){pr_warn("Failed to allocate user memory\n");gotofree_alloc;}+user_addr=(void__user*)user_alloc;-memset(good_buf,'A',cache_size);-memset(bad_buf,'B',cache_size);+memset(buf,'B',cache_size);++/* Whitelisted window in buffer, from kmem_cache_create_usercopy. */+offset=(cache_size/4)+unconst;+size=(cache_size/16)+unconst;if(to_user){-pr_info("attempting good copy_to_user with SLAB_USERCOPY\n");-if(copy_to_user((void__user*)user_addr,good_buf,-cache_size)){+pr_info("attempting good copy_to_user inside whitelist\n");+if(copy_to_user(user_addr,buf+offset,size)){pr_warn("copy_to_user failed unexpectedly?!\n");gotofree_user;}-pr_info("attempting bad copy_to_user w/o SLAB_USERCOPY\n");-if(copy_to_user((void__user*)user_addr,bad_buf,-cache_size)){+pr_info("attempting bad copy_to_user outside whitelist\n");+if(copy_to_user(user_addr,buf+offset-1,size)){pr_warn("copy_to_user failed, but lacked Oops\n");gotofree_user;}}else{-pr_info("attempting good copy_from_user with SLAB_USERCOPY\n");-if(copy_from_user(good_buf,(void__user*)user_addr,-cache_size)){+pr_info("attempting good copy_from_user inside whitelist\n");+if(copy_from_user(buf+offset,user_addr,size)){pr_warn("copy_from_user failed unexpectedly?!\n");gotofree_user;}-pr_info("attempting bad copy_from_user w/o SLAB_USERCOPY\n");-if(copy_from_user(bad_buf,(void__user*)user_addr,-cache_size)){+pr_info("attempting bad copy_from_user outside whitelist\n");+if(copy_from_user(buf+offset-1,user_addr,size)){pr_warn("copy_from_user failed, but lacked Oops\n");gotofree_user;}}free_user:-vm_munmap(user_addr,PAGE_SIZE);+vm_munmap(user_alloc,PAGE_SIZE);free_alloc:-if(bad_buf)-kmem_cache_free(bad_cache,bad_buf);-kfree(good_buf);+if(buf)+kmem_cache_free(whitelist_cache,buf);}/* Callable tests. */
--
2.7.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Russell King - ARM Linux <linux@armlinux.org.uk> Date: 2018-01-11 10:24:00
On Wed, Jan 10, 2018 at 06:03:06PM -0800, Kees Cook wrote:
ARM does not carry FPU state in the thread structure, so it can declare
no usercopy whitelist at all.
This comment seems to be misleading. We have stored FP state in the
thread structure for a long time - for example, VFP state is stored
in thread->vfpstate.hard, so we _do_ have floating point state in
the thread structure.
What I think this commit message needs to describe is why we don't
need a whitelist _despite_ having FP state in the thread structure.
At the moment, the commit message is making me think that this patch
is wrong and will introduce a regression.
Thanks.
@@ -45,6 +45,13 @@ struct thread_struct {structdebug_infodebug;};+/* Nothing needs to be usercopy-whitelisted from thread_struct. */+staticinlinevoidarch_thread_struct_whitelist(unsignedlong*offset,+unsignedlong*size)+{+*offset=*size=0;+}+#define INIT_THREAD { }#define start_thread(regs,pc,sp) \
--
2.7.4
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
On Wed, Jan 10, 2018 at 06:02:45PM -0800, Kees Cook wrote:
The ext4 symlink pathnames, stored in struct ext4_inode_info.i_data
and therefore contained in the ext4_inode_cache slab cache, need
to be copied to/from userspace.
Symlink operations to/from userspace aren't common or in the hot path,
and when they are in i_data, limited to at most 60 bytes. Is it worth
it to copy through a bounce buffer so as to disallow any usercopies
into struct ext4_inode_info?
- Ted
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
This code has nothing to do with slab allocation. Move it into
include/linux/uaccess.h where the other user space access definitions are?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
On Thu, Jan 11, 2018 at 9:01 AM, Theodore Ts'o [off-list ref] wrote:
On Wed, Jan 10, 2018 at 06:02:45PM -0800, Kees Cook wrote:
quoted
The ext4 symlink pathnames, stored in struct ext4_inode_info.i_data
and therefore contained in the ext4_inode_cache slab cache, need
to be copied to/from userspace.
Symlink operations to/from userspace aren't common or in the hot path,
and when they are in i_data, limited to at most 60 bytes. Is it worth
it to copy through a bounce buffer so as to disallow any usercopies
into struct ext4_inode_info?
If this is the only place it's exposed, yeah, that might be a way to
avoid the per-FS patches. This would, AIUI, require changing
readlink_copy() to include a bounce buffer, and that would require an
allocation. I kind of prefer just leaving the per-FS whitelists, as
then there's no global overhead added.
-Kees
--
Kees Cook
Pixel Security
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
On Thu, Jan 11, 2018 at 9:01 AM, Theodore Ts'o [off-list ref] wrote:
On Wed, Jan 10, 2018 at 06:02:45PM -0800, Kees Cook wrote:
quoted
The ext4 symlink pathnames, stored in struct ext4_inode_info.i_data
and therefore contained in the ext4_inode_cache slab cache, need
to be copied to/from userspace.
Symlink operations to/from userspace aren't common or in the hot path,
and when they are in i_data, limited to at most 60 bytes. Is it worth
it to copy through a bounce buffer so as to disallow any usercopies
into struct ext4_inode_info?
If this is the only place it's exposed, yeah, that might be a way to
avoid the per-FS patches. This would, AIUI, require changing
readlink_copy() to include a bounce buffer, and that would require an
allocation. I kind of prefer just leaving the per-FS whitelists, as
then there's no global overhead added.
-Kees
--
Kees Cook
Pixel Security
On Thu, Jan 11, 2018 at 2:24 AM, Russell King - ARM Linux
[off-list ref] wrote:
On Wed, Jan 10, 2018 at 06:03:06PM -0800, Kees Cook wrote:
quoted
ARM does not carry FPU state in the thread structure, so it can declare
no usercopy whitelist at all.
This comment seems to be misleading. We have stored FP state in the
thread structure for a long time - for example, VFP state is stored
in thread->vfpstate.hard, so we _do_ have floating point state in
the thread structure.
What I think this commit message needs to describe is why we don't
need a whitelist _despite_ having FP state in the thread structure.
At the moment, the commit message is making me think that this patch
is wrong and will introduce a regression.
Yeah, I will improve this comment; it's not clear enough. The places
where I see state copied to/from userspace are all either static sizes
or already use bounce buffers (or both). e.g.:
err |= __copy_from_user(&hwstate->fpregs, &ufp->fpregs,
sizeof(hwstate->fpregs));
I will adjust the commit log and comment to more clearly describe the
lack of whitelisting due to all-static sized copies.
Thanks!
-Kees
--
Kees Cook
Pixel Security
This code has nothing to do with slab allocation. Move it into
include/linux/uaccess.h where the other user space access definitions are?
Since it was only the mm/sl*b.c files using it, it seemed like the
right place, but it's a reasonable point. I've moved it now.
-Kees
--
Kees Cook
Pixel Security
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Matthew Wilcox <willy@infradead.org> Date: 2018-01-14 22:34:56
On Thu, Jan 11, 2018 at 03:05:14PM -0800, Kees Cook wrote:
On Thu, Jan 11, 2018 at 9:01 AM, Theodore Ts'o [off-list ref] wrote:
quoted
On Wed, Jan 10, 2018 at 06:02:45PM -0800, Kees Cook wrote:
quoted
The ext4 symlink pathnames, stored in struct ext4_inode_info.i_data
and therefore contained in the ext4_inode_cache slab cache, need
to be copied to/from userspace.
Symlink operations to/from userspace aren't common or in the hot path,
and when they are in i_data, limited to at most 60 bytes. Is it worth
it to copy through a bounce buffer so as to disallow any usercopies
into struct ext4_inode_info?
If this is the only place it's exposed, yeah, that might be a way to
avoid the per-FS patches. This would, AIUI, require changing
readlink_copy() to include a bounce buffer, and that would require an
allocation. I kind of prefer just leaving the per-FS whitelists, as
then there's no global overhead added.
I think Ted was proposing having a per-FS patch that would, say, copy
up to 60 bytes to the stack, then memcpy it into the ext4_inode_info.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
@@ -113,6 +113,14 @@ struct thread_struct {structdebug_infodebug;/* debugging */};+/* Whitelist the fpsimd_state for copying to userspace. */+staticinlinevoidarch_thread_struct_whitelist(unsignedlong*offset,+unsignedlong*size)+{+*offset=offsetof(structthread_struct,fpsimd_state);+*size=sizeof(structfpsimd_state);
This should be fpsimd_state.user_fpsimd (fpsimd_state.cpu is important
for correctly context switching and not supposed to be user-accessible.
A user copy that encompasses that is definitely a bug).
Cheers
---Dave
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
@@ -113,6 +113,14 @@ struct thread_struct {structdebug_infodebug;/* debugging */};+/* Whitelist the fpsimd_state for copying to userspace. */+staticinlinevoidarch_thread_struct_whitelist(unsignedlong*offset,+unsignedlong*size)+{+*offset=offsetof(structthread_struct,fpsimd_state);+*size=sizeof(structfpsimd_state);
This should be fpsimd_state.user_fpsimd (fpsimd_state.cpu is important
for correctly context switching and not supposed to be user-accessible.
A user copy that encompasses that is definitely a bug).
So, I actually spent some more time looking at this due to the
comments from rmk on arm32, and I don't think any whitelist is needed
here at all. (i.e. it can be *offset = *size = 0) This is because all
the usercopying I could find uses static sizes or bounce buffers, both
of which bypass the dynamic-size hardened usercopy checks.
I've been running some arm64 builds now with this change, and I
haven't tripped over any problems yet...
-Kees
--
Kees Cook
Pixel Security
@@ -113,6 +113,14 @@ struct thread_struct {structdebug_infodebug;/* debugging */};+/* Whitelist the fpsimd_state for copying to userspace. */+staticinlinevoidarch_thread_struct_whitelist(unsignedlong*offset,+unsignedlong*size)+{+*offset=offsetof(structthread_struct,fpsimd_state);+*size=sizeof(structfpsimd_state);
This should be fpsimd_state.user_fpsimd (fpsimd_state.cpu is important
for correctly context switching and not supposed to be user-accessible.
A user copy that encompasses that is definitely a bug).
So, I actually spent some more time looking at this due to the
comments from rmk on arm32, and I don't think any whitelist is needed
here at all. (i.e. it can be *offset = *size = 0) This is because all
the usercopying I could find uses static sizes or bounce buffers, both
of which bypass the dynamic-size hardened usercopy checks.
Why do static sizes bypass these checks? Just for efficiency?
I've been running some arm64 builds now with this change, and I
haven't tripped over any problems yet...
Sounds fair enough for now.
I haven't ruled out getting rid of the bounce buffers for FPSIMD
copy-in/out. They add stack and runtime overhead, and don't seem
to bring benefits.
Bounce buffers enable copies to succeed or fail atomically, rather
than being half-done and then faulting. This feels cleaner, but
In practice this doesn't seem to matter in real situations.
For SVE there are no bounce buffers, because the register data
can be unreasonably large (at least in theory).
Cheers
---Dave
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Laura Abbott <hidden> Date: 2018-01-18 21:31:42
On 01/10/2018 06:02 PM, Kees Cook wrote:
From: David Windsor <redacted>
The autoclose field can be copied with put_user(), so there is no need to
use copy_to_user(). In both cases, hardened usercopy is being bypassed
since the size is constant, and not open to runtime manipulation.
This patch is verbatim from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Just tried a quick rebase and it looks like this conflicts with
c76f97c99ae6 ("sctp: make use of pre-calculated len")
I don't think we can use put_user if we're copying via the full
len?
Thanks,
Laura
@@ -5011,7 +5011,7 @@ static int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optvlen=sizeof(int);if(put_user(len,optlen))return-EFAULT;-if(copy_to_user(optval,&sctp_sk(sk)->autoclose,sizeof(int)))+if(put_user(sctp_sk(sk)->autoclose,(int__user*)optval))return-EFAULT;return0;}
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
On Thu, Jan 18, 2018 at 1:31 PM, Laura Abbott [off-list ref] wrote:
On 01/10/2018 06:02 PM, Kees Cook wrote:
quoted
From: David Windsor <redacted>
The autoclose field can be copied with put_user(), so there is no need to
use copy_to_user(). In both cases, hardened usercopy is being bypassed
since the size is constant, and not open to runtime manipulation.
This patch is verbatim from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Just tried a quick rebase and it looks like this conflicts with
c76f97c99ae6 ("sctp: make use of pre-calculated len")
I don't think we can use put_user if we're copying via the full
len?
It should be fine, since:
len = sizeof(int);
c76f97c99ae6 just does a swap of sizeof(int) with len, put_user() will
work in either case, since autoclose will always be int sized.
-Kees
@@ -5011,7 +5011,7 @@ static int sctp_getsockopt_autoclose(struct sock
*sk, int len, char __user *optv
len = sizeof(int);
if (put_user(len, optlen))
return -EFAULT;
- if (copy_to_user(optval, &sctp_sk(sk)->autoclose, sizeof(int)))
+ if (put_user(sctp_sk(sk)->autoclose, (int __user *)optval))
return -EFAULT;
return 0;
}
--
Kees Cook
Pixel Security
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: David Windsor <redacted>
Mark the kmalloc slab caches as entirely whitelisted. These caches
are frequently used to fulfill kernel allocations that contain data
to be copied to/from userspace. Internal-only uses are also common,
but are scattered in the kernel. For now, mark all the kmalloc caches
as whitelisted.
This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: merged in moved kmalloc hunks, adjust commit log]
Cc: Pekka Enberg <penberg@kernel.org>
Cc: David Rientjes <rientjes@google.com>
Cc: Joonsoo Kim <redacted>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: linux-mm@kvack.org
Cc: linux-xfs@vger.kernel.org
Signed-off-by: Kees Cook <redacted>
Acked-by: Christoph Lameter <redacted>
---
mm/slab.c | 3 ++-
mm/slab.h | 3 ++-
mm/slab_common.c | 10 ++++++----
3 files changed, 10 insertions(+), 6 deletions(-)
On Tue, Nov 12, 2019 at 08:17:57AM +0100, Jiri Slaby wrote:
On 11. 01. 18, 3:02, Kees Cook wrote:
quoted
From: David Windsor <redacted>
Mark the kmalloc slab caches as entirely whitelisted. These caches
are frequently used to fulfill kernel allocations that contain data
to be copied to/from userspace. Internal-only uses are also common,
but are scattered in the kernel. For now, mark all the kmalloc caches
as whitelisted.
This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY
whitelisting code in the last public patch of grsecurity/PaX based on my
understanding of the code. Changes or omissions from the original code are
mine and don't reflect the original grsecurity/PaX code.
Signed-off-by: David Windsor <redacted>
[kees: merged in moved kmalloc hunks, adjust commit log]
Cc: Pekka Enberg <penberg@kernel.org>
Cc: David Rientjes <rientjes@google.com>
Cc: Joonsoo Kim <redacted>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: linux-mm@kvack.org
Cc: linux-xfs@vger.kernel.org
Signed-off-by: Kees Cook <redacted>
Acked-by: Christoph Lameter <redacted>
---
mm/slab.c | 3 ++-
mm/slab.h | 3 ++-
mm/slab_common.c | 10 ++++++----
3 files changed, 10 insertions(+), 6 deletions(-)
For context from the bug, the trace is:
(<0000000000386c5a> usercopy_abort+0xa2/0xa8)
<000000000036097a> __check_heap_object+0x11a/0x120
<0000000000386b3a> __check_object_size+0x18a/0x208
<000000000079b4ba> skb_copy_datagram_from_iter+0x62/0x240
<000003ff804edd5c> iucv_sock_sendmsg+0x1fc/0x858 Ýaf_iucv¨
<0000000000785894> sock_sendmsg+0x54/0x90
<0000000000785944> sock_write_iter+0x74/0xa0
<000000000038a3f0> new_sync_write+0x110/0x180
<000000000038d42e> vfs_write+0xa6/0x1d0
<000000000038d748> ksys_write+0x60/0xe8
<000000000096a660> system_call+0xdc/0x2e0
I know Al worked on fixing up usercopy checking for iters. I wonder if
there is redundant checking happening here? i.e. haven't iters already
done object size verifications, so they're not needed during iter copy
helpers?
I haven't heard anything new. What did people think of a separate kmem
cache?
Adding Julian and Ursula. A separate kmem cache for iucv might be indeed
a solution for the user hardening issue.
On the other hand not marking the DMA caches still seems questionable.
For reference
https://bugzilla.suse.com/show_bug.cgi?id=1156053
the kernel hardening now triggers a warning.
I haven't heard anything new. What did people think of a separate kmem
cache?
Adding Julian and Ursula. A separate kmem cache for iucv might be indeed
a solution for the user hardening issue.
It should be very clean -- any existing kmallocs already have to be
"special" in the sense that they're marked with the DMA flag. So
converting these to a separate cache should be mostly mechanical.
On the other hand not marking the DMA caches still seems questionable.
My understanding is that exposing DMA memory to userspace copies can
lead to unexpected results, especially for misbehaving hardware, so I'm
not convinced this is a generically bad hardening choice.
-Kees
I haven't heard anything new. What did people think of a separate kmem
cache?
Adding Julian and Ursula. A separate kmem cache for iucv might be indeed
a solution for the user hardening issue.
It should be very clean -- any existing kmallocs already have to be
"special" in the sense that they're marked with the DMA flag. So
converting these to a separate cache should be mostly mechanical.
Linux on System z can run within a guest hosted by the IBM mainframe operating system
z/VM. z/VM offers a transport called Inter-User Communications Vehicle (short IUCV).
It is limited to 4-byte-addresses when sending and receiving data.
One base transport for AF_IUCV sockets in the Linux kernel is this Inter-User
Communications Vehicle of z/VM. AF_IUCV sockets exist for s390 only.
AF_IUCV sockets make use of the base socket layer, and work with sk_buffs for sending
and receiving data of variable length.
Storage for sk_buffs is allocated with __alloc_skb(), which invokes
data = kmalloc_reserve(size, gfp_mask, node, &pfmemalloc);
For IUCV transport the "data"-address should fit into 4 bytes. That's the reason why
we work with GFP_DMA here.
kmem_caches manage memory of fixed size. This does not fit well for sk_buff memory
of variable length. Do you propose to add a kmem_cache solution for sk_buff memory here?
quoted
On the other hand not marking the DMA caches still seems questionable.
My understanding is that exposing DMA memory to userspace copies can
lead to unexpected results, especially for misbehaving hardware, so I'm
not convinced this is a generically bad hardening choice.
We have not yet been reported a memory problem here. Do you have more details, if
this is really a problem for the s390 architecture?
Kind regards, Ursula
From: Christopher Lameter <hidden> Date: 2020-01-29 16:43:36
On Tue, 28 Jan 2020, Kees Cook wrote:
quoted
On the other hand not marking the DMA caches still seems questionable.
My understanding is that exposing DMA memory to userspace copies can
lead to unexpected results, especially for misbehaving hardware, so I'm
not convinced this is a generically bad hardening choice.
"DMA" memory (and thus DMA caches) have nothing to do with DMA. Its a
legacy term. "DMA Memory" is memory limited to a certain
physical address boundary (old restrictions on certain devices only
supporting a limited number of address bits).
DMA can be done to NORMAL memory as well.
From: Christian Borntraeger <hidden> Date: 2020-01-29 17:07:34
On 29.01.20 17:43, Christopher Lameter wrote:
On Tue, 28 Jan 2020, Kees Cook wrote:
quoted
quoted
On the other hand not marking the DMA caches still seems questionable.
My understanding is that exposing DMA memory to userspace copies can
lead to unexpected results, especially for misbehaving hardware, so I'm
not convinced this is a generically bad hardening choice.
"DMA" memory (and thus DMA caches) have nothing to do with DMA. Its a
legacy term. "DMA Memory" is memory limited to a certain
physical address boundary (old restrictions on certain devices only
supporting a limited number of address bits).
DMA can be done to NORMAL memory as well.
Exactly.
I think iucv uses GFP_DMA because z/VM needs those buffers to reside below 2GB (which is ZONA_DMA for s390).
From: Christoph Hellwig <hch@infradead.org> Date: 2020-01-29 17:09:52
On Wed, Jan 29, 2020 at 06:07:14PM +0100, Christian Borntraeger wrote:
quoted
DMA can be done to NORMAL memory as well.
Exactly.
I think iucv uses GFP_DMA because z/VM needs those buffers to reside below 2GB (which is ZONA_DMA for s390).
The normal way to allocate memory with addressing limits would be to
use dma_alloc_coherent and friends. Any chance to switch iucv over to
that? Or is there no device associated with it?
From: Christian Borntraeger <hidden> Date: 2020-01-29 17:20:16
On 29.01.20 18:09, Christoph Hellwig wrote:
On Wed, Jan 29, 2020 at 06:07:14PM +0100, Christian Borntraeger wrote:
quoted
quoted
DMA can be done to NORMAL memory as well.
Exactly.
I think iucv uses GFP_DMA because z/VM needs those buffers to reside below 2GB (which is ZONA_DMA for s390).
The normal way to allocate memory with addressing limits would be to
use dma_alloc_coherent and friends. Any chance to switch iucv over to
that? Or is there no device associated with it?
There is not necessarily a device for that. It is a hypervisor interface (an
instruction that is interpreted by z/VM). We do have the netiucv driver that
creates a virtual nic, but there is also AF_IUCV which works without a device.
But back to the original question: If we mark kmalloc caches as usercopy caches,
we should do the same for DMA kmalloc caches. As outlined by Christoph, this has
nothing to do with device DMA.
On Wed, Jan 29, 2020 at 06:19:56PM +0100, Christian Borntraeger wrote:
On 29.01.20 18:09, Christoph Hellwig wrote:
quoted
On Wed, Jan 29, 2020 at 06:07:14PM +0100, Christian Borntraeger wrote:
quoted
quoted
DMA can be done to NORMAL memory as well.
Exactly.
I think iucv uses GFP_DMA because z/VM needs those buffers to reside below 2GB (which is ZONA_DMA for s390).
The normal way to allocate memory with addressing limits would be to
use dma_alloc_coherent and friends. Any chance to switch iucv over to
that? Or is there no device associated with it?
There is not necessarily a device for that. It is a hypervisor interface (an
instruction that is interpreted by z/VM). We do have the netiucv driver that
creates a virtual nic, but there is also AF_IUCV which works without a device.
But back to the original question: If we mark kmalloc caches as usercopy caches,
we should do the same for DMA kmalloc caches. As outlined by Christoph, this has
nothing to do with device DMA.
Hm, looks like it's allocated from the low 16MB. Seems like poor naming!
:) There seems to be a LOT of stuff using GFP_DMA, and it seems unlikely
those are all expecting low addresses?
Since this has only been a problem on s390, should just s390 gain the
weakening of the usercopy restriction? Something like:
On Thu, Jan 30, 2020 at 8:23 PM Kees Cook [off-list ref] wrote:
On Wed, Jan 29, 2020 at 06:19:56PM +0100, Christian Borntraeger wrote:
quoted
On 29.01.20 18:09, Christoph Hellwig wrote:
quoted
On Wed, Jan 29, 2020 at 06:07:14PM +0100, Christian Borntraeger wrote:
quoted
quoted
DMA can be done to NORMAL memory as well.
Exactly.
I think iucv uses GFP_DMA because z/VM needs those buffers to reside below 2GB (which is ZONA_DMA for s390).
The normal way to allocate memory with addressing limits would be to
use dma_alloc_coherent and friends. Any chance to switch iucv over to
that? Or is there no device associated with it?
There is not necessarily a device for that. It is a hypervisor interface (an
instruction that is interpreted by z/VM). We do have the netiucv driver that
creates a virtual nic, but there is also AF_IUCV which works without a device.
But back to the original question: If we mark kmalloc caches as usercopy caches,
we should do the same for DMA kmalloc caches. As outlined by Christoph, this has
nothing to do with device DMA.
Hm, looks like it's allocated from the low 16MB. Seems like poor naming!
The physical address limit of the DMA zone depends on the architecture
(and the kernel version); e.g. on Linux 4.4 on arm64 (which is used on
the Pixel 2), the DMA zone goes up to 4GiB. Later, arm64 started using
the DMA32 zone for that instead (as was already the case on e.g.
X86-64); but recently (commit 1a8e1cef7603), arm64 started using the
DMA zone again, but now for up to 1GiB. (AFAICS the DMA32 zone can't
be used with kmalloc at all, that only works with the DMA zone.)
:) There seems to be a LOT of stuff using GFP_DMA, and it seems unlikely
those are all expecting low addresses?
I think there's a bunch of (especially really old) hardware where the
hardware can only talk to low physical addresses, e.g. stuff that uses
the ISA bus.
However, there aren't *that* many users of GFP_DMA that actually cause
kmalloc allocations with GFP_DMA - many of the users of GFP_DMA
actually just pass that flag to dma_alloc_coherent()/dma_pool_alloc(),
where it is filtered away and the allocation ultimately doesn't go
through the slab allocator AFAICS, or they pass it directly to the
page allocator, where it has no effect on the usercopy stuff. Looking
on my workstation, there are zero objects allocated in dma-kmalloc-*
slabs:
/sys/kernel/slab# for name in dma-kmalloc-*; do echo "$name: $(cat
$name/objects)"; done
dma-kmalloc-128: 0
dma-kmalloc-16: 0
dma-kmalloc-192: 0
dma-kmalloc-1k: 0
dma-kmalloc-256: 0
dma-kmalloc-2k: 0
dma-kmalloc-32: 0
dma-kmalloc-4k: 0
dma-kmalloc-512: 0
dma-kmalloc-64: 0
dma-kmalloc-8: 0
dma-kmalloc-8k: 0
dma-kmalloc-96: 0
On a Pixel 2, there are a whole five objects allocated across the DMA
zone kmalloc caches:
walleye:/sys/kernel/slab # for name in dma-kmalloc-*; do echo "$name:
$(cat $name/objects)"; done
dma-kmalloc-1024: 0
dma-kmalloc-128: 0
dma-kmalloc-2048: 2
dma-kmalloc-256: 0
dma-kmalloc-4096: 3
dma-kmalloc-512: 0
dma-kmalloc-8192: 0
quoted hunk
Since this has only been a problem on s390, should just s390 gain the
weakening of the usercopy restriction? Something like:
I think dma-kmalloc slabs should be handled the same way as normal
kmalloc slabs. When a dma-kmalloc allocation is freshly created, it is
just normal kernel memory - even if it might later be used for DMA -,
and it should be perfectly fine to copy_from_user() into such
allocations at that point, and to copy_to_user() out of them at the
end. If you look at the places where such allocations are created, you
can see things like kmemdup(), memcpy() and so on - all normal
operations that shouldn't conceptually be different from usercopy in
any relevant way.
On Fri, Jan 31, 2020 at 01:03:40PM +0100, Jann Horn wrote:
I think dma-kmalloc slabs should be handled the same way as normal
kmalloc slabs. When a dma-kmalloc allocation is freshly created, it is
just normal kernel memory - even if it might later be used for DMA -,
and it should be perfectly fine to copy_from_user() into such
allocations at that point, and to copy_to_user() out of them at the
end. If you look at the places where such allocations are created, you
can see things like kmemdup(), memcpy() and so on - all normal
operations that shouldn't conceptually be different from usercopy in
any relevant way.
I can't find where the address limit for dma-kmalloc is implemented.
As to whitelisting all of dma-kmalloc -- I guess I can be talked into
it. It still seems like the memory used for direct hardware
communication shouldn't be exposed to userspace, but it we're dealing
with packet data, etc, then it makes sense not to have to have bounce
buffers, etc.
--
Kees Cook
[pruned bogus addresses from recipient list]
On Sat, Feb 1, 2020 at 6:56 PM Kees Cook [off-list ref] wrote:
On Fri, Jan 31, 2020 at 01:03:40PM +0100, Jann Horn wrote:
quoted
I think dma-kmalloc slabs should be handled the same way as normal
kmalloc slabs. When a dma-kmalloc allocation is freshly created, it is
just normal kernel memory - even if it might later be used for DMA -,
and it should be perfectly fine to copy_from_user() into such
allocations at that point, and to copy_to_user() out of them at the
end. If you look at the places where such allocations are created, you
can see things like kmemdup(), memcpy() and so on - all normal
operations that shouldn't conceptually be different from usercopy in
any relevant way.
I can't find where the address limit for dma-kmalloc is implemented.
dma-kmalloc is a slab that uses GFP_DMA pages.
Things have changed a bit through the kernel versions, but in current
mainline, the zone limit for GFP_DMA is reported from arch code to
generic code via zone_dma_bits, from where it is used to decide which
zones should be used for allocations based on the address limit of a
given device:
kernel/dma/direct.c:
/*
* Most architectures use ZONE_DMA for the first 16 Megabytes, but some use it
* it for entirely different regions. In that case the arch code needs to
* override the variable below for dma-direct to work properly.
*/
unsigned int zone_dma_bits __ro_after_init = 24;
[...]
static gfp_t __dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask,
u64 *phys_limit)
{
[...]
/*
* Optimistically try the zone that the physical address mask falls
* into first. If that returns memory that isn't actually addressable
* we will fallback to the next lower zone and try again.
*
* Note that GFP_DMA32 and GFP_DMA are no ops without the corresponding
* zones.
*/
if (*phys_limit <= DMA_BIT_MASK(zone_dma_bits))
return GFP_DMA;
if (*phys_limit <= DMA_BIT_MASK(32))
return GFP_DMA32;
return 0;
}
There are only a few architectures that override the limit:
powerpc:
/*
* Allow 30-bit DMA for very limited Broadcom wifi chips on many
* powerbooks.
*/
if (IS_ENABLED(CONFIG_PPC32))
zone_dma_bits = 30;
else
zone_dma_bits = 31;
s390:
zone_dma_bits = 31;
and arm64:
#define ARM64_ZONE_DMA_BITS 30
[...]
if (IS_ENABLED(CONFIG_ZONE_DMA)) {
zone_dma_bits = ARM64_ZONE_DMA_BITS;
arm64_dma_phys_limit = max_zone_phys(ARM64_ZONE_DMA_BITS);
}
The actual categorization of page ranges into zones happens via
free_area_init_nodes() or free_area_init_node(); these are provided
with arrays of maximum physical addresses or zone sizes (depending on
which of them is called) by arch-specific code.
For arm64, the caller is zone_sizes_init(). X86 does it in zone_sizes_init().
As to whitelisting all of dma-kmalloc -- I guess I can be talked into
it. It still seems like the memory used for direct hardware
communication shouldn't be exposed to userspace, but it we're dealing
with packet data, etc, then it makes sense not to have to have bounce
buffers, etc.
FWIW, as far as I understand, usercopy doesn't actually have any
effect on drivers that use the modern, proper APIs, since those don't
use the slab allocator at all - as I pointed out in my last mail, the
dma-kmalloc* slabs are used very rarely. (Which is good, because
putting objects from less-than-page-size slabs into iommu entries is a
terrible idea from a security and reliability perspective because it
gives the hardware access to completely unrelated memory.) Instead,
they get pages from the page allocator, and these pages may e.g. be
allocated from the DMA, DMA32 or NORMAL zones depending on the
restrictions imposed by hardware. So I think the usercopy restriction
only affects a few oddball drivers (like this s390 stuff), which is
why you're not seeing more bug reports caused by this.
From: Matthew Wilcox <willy@infradead.org> Date: 2020-02-03 07:46:57
On Sat, Feb 01, 2020 at 08:27:49PM +0100, Jann Horn wrote:
FWIW, as far as I understand, usercopy doesn't actually have any
effect on drivers that use the modern, proper APIs, since those don't
use the slab allocator at all - as I pointed out in my last mail, the
dma-kmalloc* slabs are used very rarely. (Which is good, because
putting objects from less-than-page-size slabs into iommu entries is a
terrible idea from a security and reliability perspective because it
gives the hardware access to completely unrelated memory.) Instead,
they get pages from the page allocator, and these pages may e.g. be
allocated from the DMA, DMA32 or NORMAL zones depending on the
restrictions imposed by hardware. So I think the usercopy restriction
only affects a few oddball drivers (like this s390 stuff), which is
why you're not seeing more bug reports caused by this.
Getting pages from the page allocator is true for dma_alloc_coherent()
and friends. But it's not true for streaming DMA mappings (dma_map_*)
for which the memory usually comes from kmalloc(). If this is something
we want to fix (and I have an awful feeling we're going to regret it
if we say "no, we trust the hardware"), we're going to have to come up
with a new memory allocation API for these cases. Or bounce bugger the
memory for devices we don't trust.
The problem with the dma_map_* API is that memory might end up being
allocated once and then used multiple times by different drivers. eg if
I allocate an NFS packet, it might get sent first to eth0, then (when the
route fails) sent to eth1. Similarly in storage, a RAID-5 driver might
map the same memory several times to send to different disk controllers.
From: Christopher Lameter <hidden> Date: 2020-02-03 17:20:10
On Sat, 1 Feb 2020, Kees Cook wrote:
I can't find where the address limit for dma-kmalloc is implemented.
include/linux/mmzones.h
enum zone_type {
/*
* ZONE_DMA and ZONE_DMA32 are used when there are peripherals not able
* to DMA to all of the addressable memory (ZONE_NORMAL).
* On architectures where this area covers the whole 32 bit address
* space ZONE_DMA32 is used. ZONE_DMA is left for the ones with smaller
* DMA addressing constraints. This distinction is important as a 32bit
* DMA mask is assumed when ZONE_DMA32 is defined. Some 64-bit
* platforms may need both zones as they support peripherals with
* different DMA addressing limitations.
*
* Some examples:
*
* - i386 and x86_64 have a fixed 16M ZONE_DMA and ZONE_DMA32 for the
* rest of the lower 4G.
*
* - arm only uses ZONE_DMA, the size, up to 4G, may vary depending on
* the specific device.
*
* - arm64 has a fixed 1G ZONE_DMA and ZONE_DMA32 for the rest of the
* lower 4G.
*
* - powerpc only uses ZONE_DMA, the size, up to 2G, may vary
* depending on the specific device.
*
* - s390 uses ZONE_DMA fixed to the lower 2G.
*
* - ia64 and riscv only use ZONE_DMA32.
*
* - parisc uses neither.
*/
#ifdef CONFIG_ZONE_DMA
ZONE_DMA,
#endif
#ifdef CONFIG_ZONE_DMA32
ZONE_DMA32,
#endif
/*
* Normal addressable memory is in ZONE_NORMAL. DMA operations can
be
* performed on pages in ZONE_NORMAL if the DMA devices support
* transfers to all addressable memory.
*/
ZONE_NORMAL,
#ifdef CONFIG_HIGHMEM
/*
* A memory area that is only addressable by the kernel through
* mapping portions into its own address space. This is for example
* used by i386 to allow the kernel to address the memory beyond
* 900MB. The kernel will set up special mappings (page
* table entries on i386) for each page that the kernel needs to
* access.
*/
ZONE_HIGHMEM,
#endif
ZONE_MOVABLE,
#ifdef CONFIG_ZONE_DEVICE
ZONE_DEVICE,
#endif
__MAX_NR_ZONES
};
From: Christoph Hellwig <hch@infradead.org> Date: 2020-02-03 17:36:39
On Wed, Jan 29, 2020 at 06:19:56PM +0100, Christian Borntraeger wrote:
There is not necessarily a device for that. It is a hypervisor interface (an
instruction that is interpreted by z/VM). We do have the netiucv driver that
creates a virtual nic, but there is also AF_IUCV which works without a device.
But back to the original question: If we mark kmalloc caches as usercopy caches,
we should do the same for DMA kmalloc caches. As outlined by Christoph, this has
nothing to do with device DMA.
Oh well, s/390 with its weird mix of cpu and I/O again. Everywhere else
where we have addressing limits we do treat that as a DMA address.
We've also had a bit of a lose plan to force ZONE_DMA as a public
interface out, as it is generally the wrong thing to do for drivers.
A ZONE_32 and/or ZONE_31 makes some sense as the backing for the
dma allocator, but it mostly shouldn't be exposed, especially not to
the slab allocator.
From: Christoph Hellwig <hch@infradead.org> Date: 2020-02-03 17:38:27
On Thu, Jan 30, 2020 at 11:23:38AM -0800, Kees Cook wrote:
Hm, looks like it's allocated from the low 16MB. Seems like poor naming!
:) There seems to be a LOT of stuff using GFP_DMA, and it seems unlikely
those are all expecting low addresses?
Most of that is either completely or partially bogus. Besides the
weird S/390 stuff pretty much everything should be using the dma
allocators. A couple really messed up drivers even pass GFP_DMA*
to the dma allocator, but my patches to fix that up seem to be stuck.
From: Christoph Hellwig <hch@infradead.org> Date: 2020-02-03 17:41:46
On Sun, Feb 02, 2020 at 11:46:44PM -0800, Matthew Wilcox wrote:
quoted
gives the hardware access to completely unrelated memory.) Instead,
they get pages from the page allocator, and these pages may e.g. be
allocated from the DMA, DMA32 or NORMAL zones depending on the
restrictions imposed by hardware. So I think the usercopy restriction
only affects a few oddball drivers (like this s390 stuff), which is
why you're not seeing more bug reports caused by this.
Getting pages from the page allocator is true for dma_alloc_coherent()
and friends.
dma_alloc_coherent also has a few other memory sources than the page
allocator..
But it's not true for streaming DMA mappings (dma_map_*)
for which the memory usually comes from kmalloc(). If this is something
we want to fix (and I have an awful feeling we're going to regret it
if we say "no, we trust the hardware"), we're going to have to come up
with a new memory allocation API for these cases. Or bounce bugger the
memory for devices we don't trust.
There aren't too many places that use slab allocations for streaming
mappings, and then do usercopies into them. But I vaguely remember
some usb code getting the annotations for that a while ago.
But if you don't trust your hardware you will need to use IOMMUs and
page aligned memory, or IOMMUs plus bounce buffering for the kmalloc
allocations (we've recently grown code to do that for the intel-iommu
driver, which needs to be lifted into the generic IOMMU code).
I think dma-kmalloc slabs should be handled the same way as normal
kmalloc slabs. When a dma-kmalloc allocation is freshly created, it is
just normal kernel memory - even if it might later be used for DMA -,
and it should be perfectly fine to copy_from_user() into such
allocations at that point, and to copy_to_user() out of them at the
end. If you look at the places where such allocations are created, you
can see things like kmemdup(), memcpy() and so on - all normal
operations that shouldn't conceptually be different from usercopy in
any relevant way.
So, let's do that?
----8<----
From d5190e4e871689a530da3c3fd327be45a88f006a Mon Sep 17 00:00:00 2001
From: Vlastimil Babka <redacted>
Date: Tue, 7 Apr 2020 09:58:00 +0200
Subject: [PATCH] usercopy: Mark dma-kmalloc caches as usercopy caches
We have seen a "usercopy: Kernel memory overwrite attempt detected to SLUB
object 'dma-kmalloc-1 k' (offset 0, size 11)!" error on s390x, as IUCV uses
kmalloc() with __GFP_DMA because of memory address restrictions.
The issue has been discussed [2] and it has been noted that if all the kmalloc
caches are marked as usercopy, there's little reason not to mark dma-kmalloc
caches too. The 'dma' part merely means that __GFP_DMA is used to restrict
memory address range.
As Jann Horn put it [3]:
"I think dma-kmalloc slabs should be handled the same way as normal
kmalloc slabs. When a dma-kmalloc allocation is freshly created, it is
just normal kernel memory - even if it might later be used for DMA -,
and it should be perfectly fine to copy_from_user() into such
allocations at that point, and to copy_to_user() out of them at the
end. If you look at the places where such allocations are created, you
can see things like kmemdup(), memcpy() and so on - all normal
operations that shouldn't conceptually be different from usercopy in
any relevant way."
Thus this patch marks the dma-kmalloc-* caches as usercopy.
[1] https://bugzilla.suse.com/show_bug.cgi?id=1156053
[2] https://lore.kernel.org/kernel-hardening/bfca96db-bbd0-d958-7732-76e36c667c68@suse.cz/
[3] https://lore.kernel.org/kernel-hardening/CAG48ez1a4waGk9kB0WLaSbs4muSoK0AYAVk8=XYaKj4_+6e6Hg@mail.gmail.com/
Signed-off-by: Vlastimil Babka <redacted>
---
mm/slab_common.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
From: Christian Borntraeger <hidden> Date: 2020-04-07 11:06:18
On 07.04.20 10:00, Vlastimil Babka wrote:
On 1/31/20 1:03 PM, Jann Horn wrote:
quoted
I think dma-kmalloc slabs should be handled the same way as normal
kmalloc slabs. When a dma-kmalloc allocation is freshly created, it is
just normal kernel memory - even if it might later be used for DMA -,
and it should be perfectly fine to copy_from_user() into such
allocations at that point, and to copy_to_user() out of them at the
end. If you look at the places where such allocations are created, you
can see things like kmemdup(), memcpy() and so on - all normal
operations that shouldn't conceptually be different from usercopy in
any relevant way.
So, let's do that?
----8<----
From d5190e4e871689a530da3c3fd327be45a88f006a Mon Sep 17 00:00:00 2001
From: Vlastimil Babka <redacted>
Date: Tue, 7 Apr 2020 09:58:00 +0200
Subject: [PATCH] usercopy: Mark dma-kmalloc caches as usercopy caches
We have seen a "usercopy: Kernel memory overwrite attempt detected to SLUB
object 'dma-kmalloc-1 k' (offset 0, size 11)!" error on s390x, as IUCV uses
kmalloc() with __GFP_DMA because of memory address restrictions.
The issue has been discussed [2] and it has been noted that if all the kmalloc
caches are marked as usercopy, there's little reason not to mark dma-kmalloc
caches too. The 'dma' part merely means that __GFP_DMA is used to restrict
memory address range.
As Jann Horn put it [3]:
"I think dma-kmalloc slabs should be handled the same way as normal
kmalloc slabs. When a dma-kmalloc allocation is freshly created, it is
just normal kernel memory - even if it might later be used for DMA -,
and it should be perfectly fine to copy_from_user() into such
allocations at that point, and to copy_to_user() out of them at the
end. If you look at the places where such allocations are created, you
can see things like kmemdup(), memcpy() and so on - all normal
operations that shouldn't conceptually be different from usercopy in
any relevant way."
Thus this patch marks the dma-kmalloc-* caches as usercopy.
[1] https://bugzilla.suse.com/show_bug.cgi?id=1156053
[2] https://lore.kernel.org/kernel-hardening/bfca96db-bbd0-d958-7732-76e36c667c68@suse.cz/
[3] https://lore.kernel.org/kernel-hardening/CAG48ez1a4waGk9kB0WLaSbs4muSoK0AYAVk8=XYaKj4_+6e6Hg@mail.gmail.com/
Signed-off-by: Vlastimil Babka <redacted>