From d3866e5baba082707cc3149d3206cdf04d67d639 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 31 Jul 2024 12:01:54 +1200 Subject: [PATCH] mm: BUG_ON to avoid NULL deference while __GFP_NOFAIL fails MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit We have cases we still fail though callers might have __GFP_NOFAIL. Since they don't check the return, we are exposed to the security risks for NULL deference. Though BUG_ON() is not encouraged by Linus, this is an unrecoverable situation. Christoph Hellwig: The whole freaking point of __GFP_NOFAIL is that callers don't handle allocation failures. So in fact a straight BUG is the right thing here. Vlastimil Babka: It's just not a recoverable situation (WARN_ON is for recoverable situations). The caller cannot handle allocation failure and at the same time asked for an impossible allocation. BUG_ON() is a guaranteed oops with stracktrace etc. We don't need to hope for the later NULL pointer dereference (which might if really unlucky happen from a different context where it's no longer obvious what lead to the allocation failing). Michal Hocko: Linus tends to be against adding new BUG() calls unless the failure is absolutely unrecoverable (e.g. corrupted data structures etc.). I am not sure how he would look at simply incorrect memory allocator usage to blow up the kernel. Now the argument could be made that those failures could cause subtle memory corruptions or even be exploitable which might be a sufficient reason to stop them early. Link: https://lkml.kernel.org/r/20240731000155.109583-4-21cnbao@gmail.com Signed-off-by: Barry Song Reviewed-by: Christoph Hellwig Acked-by: Vlastimil Babka Acked-by: Michal Hocko Cc: Uladzislau Rezki (Sony) Cc: Lorenzo Stoakes Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Cc: Roman Gushchin Cc: Hyeonggon Yoo <42.hyeyoo@gmail.com> Cc: Linus Torvalds Cc: Kees Cook Cc: "Eugenio Pérez" Cc: Hailong.Liu Cc: Jason Wang Cc: Maxime Coquelin Cc: "Michael S. Tsirkin" Cc: Xuan Zhuo Signed-off-by: Andrew Morton --- include/linux/slab.h | 4 +++- mm/page_alloc.c | 4 +++- mm/util.c | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/linux/slab.h b/include/linux/slab.h index c9cb42203183..4a4d1fdc2afe 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -827,8 +827,10 @@ kvmalloc_array_node_noprof(size_t n, size_t size, gfp_t flags, int node) { size_t bytes; - if (unlikely(check_mul_overflow(n, size, &bytes))) + if (unlikely(check_mul_overflow(n, size, &bytes))) { + BUG_ON(flags & __GFP_NOFAIL); return NULL; + } return kvmalloc_node_noprof(bytes, flags, node); } diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 60742d057b05..d2c37f8f8d09 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -4668,8 +4668,10 @@ struct page *__alloc_pages_noprof(gfp_t gfp, unsigned int order, * There are several places where we assume that the order value is sane * so bail out early if the request is out of bound. */ - if (WARN_ON_ONCE_GFP(order > MAX_PAGE_ORDER, gfp)) + if (WARN_ON_ONCE_GFP(order > MAX_PAGE_ORDER, gfp)) { + BUG_ON(gfp & __GFP_NOFAIL); return NULL; + } gfp &= gfp_allowed_mask; /* diff --git a/mm/util.c b/mm/util.c index ac01925a4179..678c647b778f 100644 --- a/mm/util.c +++ b/mm/util.c @@ -667,6 +667,7 @@ void *__kvmalloc_node_noprof(DECL_BUCKET_PARAMS(size, b), gfp_t flags, int node) /* Don't even allow crazy sizes */ if (unlikely(size > INT_MAX)) { + BUG_ON(flags & __GFP_NOFAIL); WARN_ON_ONCE(!(flags & __GFP_NOWARN)); return NULL; } -- 2.50.1