Commit 9ed9cac1 authored by Kees Cook's avatar Kees Cook Committed by Vlastimil Babka
Browse files

slab: Remove __malloc attribute from realloc functions



The __malloc attribute should not be applied to "realloc" functions, as
the returned pointer may alias the storage of the prior pointer. Instead
of splitting __malloc from __alloc_size, which would be a huge amount of
churn, just create __realloc_size for the few cases where it is needed.

Thanks to Geert Uytterhoeven <geert@linux-m68k.org> for reporting build
failures with gcc-8 in earlier version which tried to remove the #ifdef.
While the "alloc_size" attribute is available on all GCC versions, I
forgot that it gets disabled explicitly by the kernel in GCC < 9.1 due
to misbehaviors. Add a note to the compiler_attributes.h entry for it.

Cc: Christoph Lameter <cl@linux.com>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: David Rientjes <rientjes@google.com>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Hyeonggon Yoo <42.hyeyoo@gmail.com>
Cc: Marco Elver <elver@google.com>
Cc: linux-mm@kvack.org
Signed-off-by: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatarVlastimil Babka <vbabka@suse.cz>
parent e45cc288
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -35,7 +35,8 @@

/*
 * Note: do not use this directly. Instead, use __alloc_size() since it is conditionally
 * available and includes other attributes.
 * available and includes other attributes. For GCC < 9.1, __alloc_size__ gets undefined
 * in compiler-gcc.h, due to misbehaviors.
 *
 *   gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-alloc_005fsize-function-attribute
 * clang: https://clang.llvm.org/docs/AttributeReference.html#alloc-size
+5 −3
Original line number Diff line number Diff line
@@ -271,14 +271,16 @@ struct ftrace_likely_data {

/*
 * Any place that could be marked with the "alloc_size" attribute is also
 * a place to be marked with the "malloc" attribute. Do this as part of the
 * __alloc_size macro to avoid redundant attributes and to avoid missing a
 * __malloc marking.
 * a place to be marked with the "malloc" attribute, except those that may
 * be performing a _reallocation_, as that may alias the existing pointer.
 * For these, use __realloc_size().
 */
#ifdef __alloc_size__
# define __alloc_size(x, ...)	__alloc_size__(x, ## __VA_ARGS__) __malloc
# define __realloc_size(x, ...)	__alloc_size__(x, ## __VA_ARGS__)
#else
# define __alloc_size(x, ...)	__malloc
# define __realloc_size(x, ...)
#endif

#ifndef asm_volatile_goto
+6 −6
Original line number Diff line number Diff line
@@ -184,7 +184,7 @@ int kmem_cache_shrink(struct kmem_cache *s);
/*
 * Common kmalloc functions provided by all allocators
 */
void * __must_check krealloc(const void *objp, size_t new_size, gfp_t flags) __alloc_size(2);
void * __must_check krealloc(const void *objp, size_t new_size, gfp_t flags) __realloc_size(2);
void kfree(const void *objp);
void kfree_sensitive(const void *objp);
size_t __ksize(const void *objp);
@@ -647,7 +647,7 @@ static inline __alloc_size(1, 2) void *kmalloc_array(size_t n, size_t size, gfp_
 * @new_size: new size of a single member of the array
 * @flags: the type of memory to allocate (see kmalloc)
 */
static inline __alloc_size(2, 3) void * __must_check krealloc_array(void *p,
static inline __realloc_size(2, 3) void * __must_check krealloc_array(void *p,
								      size_t new_n,
								      size_t new_size,
								      gfp_t flags)
@@ -774,7 +774,7 @@ static inline __alloc_size(1, 2) void *kvcalloc(size_t n, size_t size, gfp_t fla
}

extern void *kvrealloc(const void *p, size_t oldsize, size_t newsize, gfp_t flags)
		      __alloc_size(3);
		      __realloc_size(3);
extern void kvfree(const void *addr);
extern void kvfree_sensitive(const void *addr, size_t len);

+2 −2
Original line number Diff line number Diff line
@@ -1150,8 +1150,8 @@ module_init(slab_proc_init);

#endif /* CONFIG_SLAB || CONFIG_SLUB_DEBUG */

static __always_inline void *__do_krealloc(const void *p, size_t new_size,
					   gfp_t flags)
static __always_inline __realloc_size(2) void *
__do_krealloc(const void *p, size_t new_size, gfp_t flags)
{
	void *ret;
	size_t ks;