|
Message-ID: <20110820163120.GA7256@openwall.com> Date: Sat, 20 Aug 2011 20:31:20 +0400 From: Solar Designer <solar@...nwall.com> To: kernel-hardening@...ts.openwall.com Subject: Re: kmalloc() nofail allocations Vasiliy, Overall, I like this. My biggest concern is that it implies that the kernel will always have a can't fail memory allocation interface. So if kernel developers at some point want to change this, they'll have a hard time making such changes. On the other hand, the current situation with some code assuming that failures are impossible and some other code checking for them anyway is inconsistent and not very helpful for possible memory allocation semantics changes anyway. So let's give this a try. On Sat, Aug 20, 2011 at 06:27:23PM +0400, Vasiliy Kulikov wrote: > Here is a patch to do it. I've implemented k(m|z)alloc() and > kmem_cache_{z,}alloc() nofail variants. As a result, setuid() cannot > fail with any reason, but EACCES. > > kernel/cred.c is partly moved to _nofail() too, just to show how much > error handling code it removes. This mostly looks good to me. Some comments are below: > +#define kmalloc_nofail(size, flags) \ > +({ \ > + void *p; \ > + (void)BUILD_BUG_ON_ZERO(size > (PAGE_SIZE << (PAGE_ALLOC_COSTLY_ORDER-1))); \ > + if (flags & __GFP_NORETRY) \ > + panic("Attempt to call kmalloc_nofail() with __GFP_NORETRY"); \ > + p = kmalloc(size, flags); \ > + if (p == NULL) \ > + panic("kmalloc_nofail() returned NULL\n"); \ > + p; \ > +}) You need to enclose size and flags in braces in this macro. Also, I think portions of this macro should be moved into a non-inline function defined in some .c file - to reduce total code size. Then the macro (and thus duplicated code) could be shortened to: #define kmalloc_nofail(size, flags) \ ({ \ (void)BUILD_BUG_ON_ZERO((size) > (PAGE_SIZE << (PAGE_ALLOC_COSTLY_ORDER-1))); \ _kmalloc_nofail((size), (flags)); \ }) or to optimize it for speed at the cost of slight size increase: #define kmalloc_nofail(size, flags) \ ({ \ void *p; \ (void)BUILD_BUG_ON_ZERO((size) > (PAGE_SIZE << (PAGE_ALLOC_COSTLY_ORDER-1))); \ p = kmalloc((size), (flags)); \ if (((flags) & __GFP_NORETRY) || p == NULL) \ kmalloc_nofail_panic((flags), p); \ p; \ }) so you have only one instance of a function call on error instead of two calls to panic() and you don't rely on the compiler and linker combining the many instances of constant strings. You can leave these changes for after your initial RFC postings to LKML if you like, though. > +#define kzalloc_nofail(size, flags) \ > + kmalloc_nofail(size, (flags | __GFP_ZERO)) Need braces around flags. > +#define kmem_cache_zalloc_nofail(cache, flags) \ > + kmem_cache_alloc_nofail(cache, (flags | __GFP_ZERO)) Need braces around cache and flags. > +/* This is a slightly weaker check than kmalloc_nofail() as kmem check is runtime check :\ */ > +#define kmem_cache_alloc_nofail(cache, flags) \ > +({ \ > + void *p; \ > + if ((cache)->objsize > (PAGE_SIZE << (PAGE_ALLOC_COSTLY_ORDER-1))) \ > + panic("Too big size (%lu) for kmem_cache_alloc_nofail()!", \ > + (long)(cache)->objsize); \ > + if (flags & __GFP_NORETRY); \ > + panic("Attempt to call kmem_cache_alloc_nofail() with __GFP_NORETRY"); \ > + p = kmem_cache_alloc(cache, flags); \ > + if (p == NULL) \ > + panic("kmem_cache_alloc() returned NULL\n"); \ > + p; \ > +}) Similar comments apply here. Since the size check is runtime anyway, perhaps it should be moved into a non-inline function. Please fix at least the braces, and bring this to LKML for discussion. Thanks, Alexander
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.