Skip to content

Commit 2932ba8

Browse files
committed
slab: Introduce kmalloc_obj() and family
Introduce type-aware kmalloc-family helpers to replace the common idioms for single object and arrays of objects allocation: ptr = kmalloc(sizeof(*ptr), gfp); ptr = kmalloc(sizeof(struct some_obj_name), gfp); ptr = kzalloc(sizeof(*ptr), gfp); ptr = kmalloc_array(count, sizeof(*ptr), gfp); ptr = kcalloc(count, sizeof(*ptr), gfp); These become, respectively: ptr = kmalloc_obj(*ptr, gfp); ptr = kmalloc_obj(*ptr, gfp); ptr = kzalloc_obj(*ptr, gfp); ptr = kmalloc_objs(*ptr, count, gfp); ptr = kzalloc_objs(*ptr, count, gfp); Beyond the other benefits outlined below, the primary ergonomic benefit is the elimination of needing "sizeof" nor the type name, and the enforcement of assignment types (they do not return "void *", but rather a pointer to the type of the first argument). The type name _can_ be used, though, in the case where an assignment is indirect (e.g. via "return"). This additionally allows[1] variables to be declared via __auto_type: __auto_type ptr = kmalloc_obj(struct foo, gfp); Internal introspection of the allocated type now becomes possible, allowing for future alignment-aware choices to be made by the allocator and future hardening work that can be type sensitive. For example, adding __alignof(*ptr) as an argument to the internal allocators so that appropriate/efficient alignment choices can be made, or being able to correctly choose per-allocation offset randomization within a bucket that does not break alignment requirements. Link: https://lore.kernel.org/all/CAHk-=wiCOTW5UftUrAnvJkr6769D29tF7Of79gUjdQHS_TkF5A@mail.gmail.com/ [1] Acked-by: Vlastimil Babka <vbabka@suse.cz> Link: https://patch.msgid.link/20251203233036.3212363-1-kees@kernel.org Signed-off-by: Kees Cook <kees@kernel.org>
1 parent 9448598 commit 2932ba8

2 files changed

Lines changed: 82 additions & 0 deletions

File tree

Documentation/process/deprecated.rst

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,3 +372,27 @@ The helper must be used::
372372
DECLARE_FLEX_ARRAY(struct type2, two);
373373
};
374374
};
375+
376+
Open-coded kmalloc assignments for struct objects
377+
-------------------------------------------------
378+
Performing open-coded kmalloc()-family allocation assignments prevents
379+
the kernel (and compiler) from being able to examine the type of the
380+
variable being assigned, which limits any related introspection that
381+
may help with alignment, wrap-around, or additional hardening. The
382+
kmalloc_obj()-family of macros provide this introspection, which can be
383+
used for the common code patterns for single, array, and flexible object
384+
allocations. For example, these open coded assignments::
385+
386+
ptr = kmalloc(sizeof(*ptr), gfp);
387+
ptr = kzalloc(sizeof(*ptr), gfp);
388+
ptr = kmalloc_array(count, sizeof(*ptr), gfp);
389+
ptr = kcalloc(count, sizeof(*ptr), gfp);
390+
ptr = kmalloc(sizeof(struct foo, gfp);
391+
392+
become, respectively::
393+
394+
ptr = kmalloc_obj(*ptr, gfp);
395+
ptr = kzalloc_obj(*ptr, gfp);
396+
ptr = kmalloc_objs(*ptr, count, gfp);
397+
ptr = kzalloc_objs(*ptr, count, gfp);
398+
__auto_type ptr = kmalloc_obj(struct foo, gfp);

include/linux/slab.h

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#ifndef _LINUX_SLAB_H
1313
#define _LINUX_SLAB_H
1414

15+
#include <linux/bug.h>
1516
#include <linux/cache.h>
1617
#include <linux/gfp.h>
1718
#include <linux/overflow.h>
@@ -965,6 +966,63 @@ static __always_inline __alloc_size(1) void *kmalloc_noprof(size_t size, gfp_t f
965966
void *kmalloc_nolock_noprof(size_t size, gfp_t gfp_flags, int node);
966967
#define kmalloc_nolock(...) alloc_hooks(kmalloc_nolock_noprof(__VA_ARGS__))
967968

969+
/**
970+
* __alloc_objs - Allocate objects of a given type using
971+
* @KMALLOC: which size-based kmalloc wrapper to allocate with.
972+
* @GFP: GFP flags for the allocation.
973+
* @TYPE: type to allocate space for.
974+
* @COUNT: how many @TYPE objects to allocate.
975+
*
976+
* Returns: Newly allocated pointer to (first) @TYPE of @COUNT-many
977+
* allocated @TYPE objects, or NULL on failure.
978+
*/
979+
#define __alloc_objs(KMALLOC, GFP, TYPE, COUNT) \
980+
({ \
981+
const size_t __obj_size = size_mul(sizeof(TYPE), COUNT); \
982+
(TYPE *)KMALLOC(__obj_size, GFP); \
983+
})
984+
985+
/**
986+
* kmalloc_obj - Allocate a single instance of the given type
987+
* @VAR_OR_TYPE: Variable or type to allocate.
988+
* @GFP: GFP flags for the allocation.
989+
*
990+
* Returns: newly allocated pointer to a @VAR_OR_TYPE on success, or NULL
991+
* on failure.
992+
*/
993+
#define kmalloc_obj(VAR_OR_TYPE, GFP) \
994+
__alloc_objs(kmalloc, GFP, typeof(VAR_OR_TYPE), 1)
995+
996+
/**
997+
* kmalloc_objs - Allocate an array of the given type
998+
* @VAR_OR_TYPE: Variable or type to allocate an array of.
999+
* @COUNT: How many elements in the array.
1000+
* @GFP: GFP flags for the allocation.
1001+
*
1002+
* Returns: newly allocated pointer to array of @VAR_OR_TYPE on success,
1003+
* or NULL on failure.
1004+
*/
1005+
#define kmalloc_objs(VAR_OR_TYPE, COUNT, GFP) \
1006+
__alloc_objs(kmalloc, GFP, typeof(VAR_OR_TYPE), COUNT)
1007+
1008+
/* All kzalloc aliases for kmalloc_(obj|objs|flex). */
1009+
#define kzalloc_obj(P, GFP) \
1010+
__alloc_objs(kzalloc, GFP, typeof(P), 1)
1011+
#define kzalloc_objs(P, COUNT, GFP) \
1012+
__alloc_objs(kzalloc, GFP, typeof(P), COUNT)
1013+
1014+
/* All kvmalloc aliases for kmalloc_(obj|objs|flex). */
1015+
#define kvmalloc_obj(P, GFP) \
1016+
__alloc_objs(kvmalloc, GFP, typeof(P), 1)
1017+
#define kvmalloc_objs(P, COUNT, GFP) \
1018+
__alloc_objs(kvmalloc, GFP, typeof(P), COUNT)
1019+
1020+
/* All kvzalloc aliases for kmalloc_(obj|objs|flex). */
1021+
#define kvzalloc_obj(P, GFP) \
1022+
__alloc_objs(kvzalloc, GFP, typeof(P), 1)
1023+
#define kvzalloc_objs(P, COUNT, GFP) \
1024+
__alloc_objs(kvzalloc, GFP, typeof(P), COUNT)
1025+
9681026
#define kmem_buckets_alloc(_b, _size, _flags) \
9691027
alloc_hooks(__kmalloc_node_noprof(PASS_BUCKET_PARAMS(_size, _b), _flags, NUMA_NO_NODE))
9701028

0 commit comments

Comments
 (0)