Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'kmalloc_obj-v7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux

Pull kmalloc_obj updates from Kees Cook:
"Introduce the kmalloc_obj* family of APIs for switching to type-based
kmalloc allocations, away from purely size-based allocations.
Discussed on lkml, with you, and at Linux Plumbers. It's been in -next
for the entire dev cycle.

Before the merge window closes, I'd like to send the treewide
change (generated from the Coccinelle script included here), which
mechanically converts almost 20k callsites from kmalloc* to
kmalloc_obj*:

8007 files changed, 19980 insertions(+), 20838 deletions(-)

This change needed fixes for mismatched types (since now the return
type from allocations is a pointer to the requested type, not "void
*"), and I've been fixing these over the last 4 releases.

These fixes have mostly been trivial mismatches with const qualifiers
or accidentally identical sizes (e.g. same object size: "struct kvec"
vs "struct iovec", or differing pointers to pointers), but I did catch
one case of too-small allocation.

Summary:

- Introduce kmalloc_obj*() family of type-based allocator APIs

- checkpatch: Suggest kmalloc_obj family for sizeof allocations

- coccinelle: Add kmalloc_objs conversion script"

* tag 'kmalloc_obj-v7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
coccinelle: Add kmalloc_objs conversion script
slab: Introduce kmalloc_flex() and family
compiler_types: Introduce __flex_counter() and family
checkpatch: Suggest kmalloc_obj family for sizeof allocations
slab: Introduce kmalloc_obj() and family

+367 -6
+31
Documentation/process/deprecated.rst
··· 372 372 DECLARE_FLEX_ARRAY(struct type2, two); 373 373 }; 374 374 }; 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(struct_size(ptr, flex_member, count), gfp); 391 + ptr = kmalloc(sizeof(struct foo, gfp); 392 + 393 + become, respectively:: 394 + 395 + ptr = kmalloc_obj(*ptr, gfp); 396 + ptr = kzalloc_obj(*ptr, gfp); 397 + ptr = kmalloc_objs(*ptr, count, gfp); 398 + ptr = kzalloc_objs(*ptr, count, gfp); 399 + ptr = kmalloc_flex(*ptr, flex_member, count, gfp); 400 + __auto_type ptr = kmalloc_obj(struct foo, gfp); 401 + 402 + If `ptr->flex_member` is annotated with __counted_by(), the allocation 403 + will automatically fail if `count` is larger than the maximum 404 + representable value that can be stored in the counter member associated 405 + with `flex_member`.
+31
include/linux/compiler_types.h
··· 552 552 #endif 553 553 554 554 /* 555 + * Optional: only supported since gcc >= 15, clang >= 19 556 + * 557 + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-_005f_005fbuiltin_005fcounted_005fby_005fref 558 + * clang: https://clang.llvm.org/docs/LanguageExtensions.html#builtin-counted-by-ref 559 + */ 560 + #if __has_builtin(__builtin_counted_by_ref) 561 + /** 562 + * __flex_counter() - Get pointer to counter member for the given 563 + * flexible array, if it was annotated with __counted_by() 564 + * @FAM: Pointer to flexible array member of an addressable struct instance 565 + * 566 + * For example, with: 567 + * 568 + * struct foo { 569 + * int counter; 570 + * short array[] __counted_by(counter); 571 + * } *p; 572 + * 573 + * __flex_counter(p->array) will resolve to &p->counter. 574 + * 575 + * Note that Clang may not allow this to be assigned to a separate 576 + * variable; it must be used directly. 577 + * 578 + * If p->array is unannotated, this returns (void *)NULL. 579 + */ 580 + #define __flex_counter(FAM) __builtin_counted_by_ref(FAM) 581 + #else 582 + #define __flex_counter(FAM) ((void *)NULL) 583 + #endif 584 + 585 + /* 555 586 * Some versions of gcc do not mark 'asm goto' volatile: 556 587 * 557 588 * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103979
+42
include/linux/overflow.h
··· 552 552 (__member_size((name)->array) / sizeof(*(name)->array) + \ 553 553 __must_be_array((name)->array)) 554 554 555 + /** 556 + * typeof_flex_counter() - Return the type of the counter variable of a given 557 + * flexible array member annotated by __counted_by(). 558 + * @FAM: Instance of flexible array member within a given struct. 559 + * 560 + * Returns: "size_t" if no annotation exists. 561 + */ 562 + #define typeof_flex_counter(FAM) \ 563 + typeof(_Generic(__flex_counter(FAM), \ 564 + void *: (size_t)0, \ 565 + default: *__flex_counter(FAM))) 566 + 567 + /** 568 + * overflows_flex_counter_type() - Check if the counter associated with the 569 + * given flexible array member can represent 570 + * a value. 571 + * @TYPE: Type of the struct that contains the @FAM. 572 + * @FAM: Member name of the FAM within @TYPE. 573 + * @COUNT: Value to check against the __counted_by annotated @FAM's counter. 574 + * 575 + * Returns: true if @COUNT can be represented in the @FAM's counter. When 576 + * @FAM is not annotated with __counted_by(), always returns true. 577 + */ 578 + #define overflows_flex_counter_type(TYPE, FAM, COUNT) \ 579 + (!overflows_type(COUNT, typeof_flex_counter(((TYPE *)NULL)->FAM))) 580 + 581 + /** 582 + * __set_flex_counter() - Set the counter associated with the given flexible 583 + * array member that has been annoated by __counted_by(). 584 + * @FAM: Instance of flexible array member within a given struct. 585 + * @COUNT: Value to store to the __counted_by annotated @FAM_PTR's counter. 586 + * 587 + * This is a no-op if no annotation exists. Count needs to be checked with 588 + * overflows_flex_counter_type() before using this function. 589 + */ 590 + #define __set_flex_counter(FAM, COUNT) \ 591 + ({ \ 592 + *_Generic(__flex_counter(FAM), \ 593 + void *: &(size_t){ 0 }, \ 594 + default: __flex_counter(FAM)) = (COUNT); \ 595 + }) 596 + 555 597 #endif /* __LINUX_OVERFLOW_H */
+106
include/linux/slab.h
··· 12 12 #ifndef _LINUX_SLAB_H 13 13 #define _LINUX_SLAB_H 14 14 15 + #include <linux/bug.h> 15 16 #include <linux/cache.h> 16 17 #include <linux/gfp.h> 17 18 #include <linux/overflow.h> ··· 965 964 966 965 void *kmalloc_nolock_noprof(size_t size, gfp_t gfp_flags, int node); 967 966 #define kmalloc_nolock(...) alloc_hooks(kmalloc_nolock_noprof(__VA_ARGS__)) 967 + 968 + /** 969 + * __alloc_objs - Allocate objects of a given type using 970 + * @KMALLOC: which size-based kmalloc wrapper to allocate with. 971 + * @GFP: GFP flags for the allocation. 972 + * @TYPE: type to allocate space for. 973 + * @COUNT: how many @TYPE objects to allocate. 974 + * 975 + * Returns: Newly allocated pointer to (first) @TYPE of @COUNT-many 976 + * allocated @TYPE objects, or NULL on failure. 977 + */ 978 + #define __alloc_objs(KMALLOC, GFP, TYPE, COUNT) \ 979 + ({ \ 980 + const size_t __obj_size = size_mul(sizeof(TYPE), COUNT); \ 981 + (TYPE *)KMALLOC(__obj_size, GFP); \ 982 + }) 983 + 984 + /** 985 + * __alloc_flex - Allocate an object that has a trailing flexible array 986 + * @KMALLOC: kmalloc wrapper function to use for allocation. 987 + * @GFP: GFP flags for the allocation. 988 + * @TYPE: type of structure to allocate space for. 989 + * @FAM: The name of the flexible array member of @TYPE structure. 990 + * @COUNT: how many @FAM elements to allocate space for. 991 + * 992 + * Returns: Newly allocated pointer to @TYPE with @COUNT-many trailing 993 + * @FAM elements, or NULL on failure or if @COUNT cannot be represented 994 + * by the member of @TYPE that counts the @FAM elements (annotated via 995 + * __counted_by()). 996 + */ 997 + #define __alloc_flex(KMALLOC, GFP, TYPE, FAM, COUNT) \ 998 + ({ \ 999 + const size_t __count = (COUNT); \ 1000 + const size_t __obj_size = struct_size_t(TYPE, FAM, __count); \ 1001 + TYPE *__obj_ptr; \ 1002 + if (WARN_ON_ONCE(overflows_flex_counter_type(TYPE, FAM, __count))) \ 1003 + __obj_ptr = NULL; \ 1004 + else \ 1005 + __obj_ptr = KMALLOC(__obj_size, GFP); \ 1006 + if (__obj_ptr) \ 1007 + __set_flex_counter(__obj_ptr->FAM, __count); \ 1008 + __obj_ptr; \ 1009 + }) 1010 + 1011 + /** 1012 + * kmalloc_obj - Allocate a single instance of the given type 1013 + * @VAR_OR_TYPE: Variable or type to allocate. 1014 + * @GFP: GFP flags for the allocation. 1015 + * 1016 + * Returns: newly allocated pointer to a @VAR_OR_TYPE on success, or NULL 1017 + * on failure. 1018 + */ 1019 + #define kmalloc_obj(VAR_OR_TYPE, GFP) \ 1020 + __alloc_objs(kmalloc, GFP, typeof(VAR_OR_TYPE), 1) 1021 + 1022 + /** 1023 + * kmalloc_objs - Allocate an array of the given type 1024 + * @VAR_OR_TYPE: Variable or type to allocate an array of. 1025 + * @COUNT: How many elements in the array. 1026 + * @GFP: GFP flags for the allocation. 1027 + * 1028 + * Returns: newly allocated pointer to array of @VAR_OR_TYPE on success, 1029 + * or NULL on failure. 1030 + */ 1031 + #define kmalloc_objs(VAR_OR_TYPE, COUNT, GFP) \ 1032 + __alloc_objs(kmalloc, GFP, typeof(VAR_OR_TYPE), COUNT) 1033 + 1034 + /** 1035 + * kmalloc_flex - Allocate a single instance of the given flexible structure 1036 + * @VAR_OR_TYPE: Variable or type to allocate (with its flex array). 1037 + * @FAM: The name of the flexible array member of the structure. 1038 + * @COUNT: How many flexible array member elements are desired. 1039 + * @GFP: GFP flags for the allocation. 1040 + * 1041 + * Returns: newly allocated pointer to @VAR_OR_TYPE on success, NULL on 1042 + * failure. If @FAM has been annotated with __counted_by(), the allocation 1043 + * will immediately fail if @COUNT is larger than what the type of the 1044 + * struct's counter variable can represent. 1045 + */ 1046 + #define kmalloc_flex(VAR_OR_TYPE, FAM, COUNT, GFP) \ 1047 + __alloc_flex(kmalloc, GFP, typeof(VAR_OR_TYPE), FAM, COUNT) 1048 + 1049 + /* All kzalloc aliases for kmalloc_(obj|objs|flex). */ 1050 + #define kzalloc_obj(P, GFP) \ 1051 + __alloc_objs(kzalloc, GFP, typeof(P), 1) 1052 + #define kzalloc_objs(P, COUNT, GFP) \ 1053 + __alloc_objs(kzalloc, GFP, typeof(P), COUNT) 1054 + #define kzalloc_flex(P, FAM, COUNT, GFP) \ 1055 + __alloc_flex(kzalloc, GFP, typeof(P), FAM, COUNT) 1056 + 1057 + /* All kvmalloc aliases for kmalloc_(obj|objs|flex). */ 1058 + #define kvmalloc_obj(P, GFP) \ 1059 + __alloc_objs(kvmalloc, GFP, typeof(P), 1) 1060 + #define kvmalloc_objs(P, COUNT, GFP) \ 1061 + __alloc_objs(kvmalloc, GFP, typeof(P), COUNT) 1062 + #define kvmalloc_flex(P, FAM, COUNT, GFP) \ 1063 + __alloc_flex(kvmalloc, GFP, typeof(P), FAM, COUNT) 1064 + 1065 + /* All kvzalloc aliases for kmalloc_(obj|objs|flex). */ 1066 + #define kvzalloc_obj(P, GFP) \ 1067 + __alloc_objs(kvzalloc, GFP, typeof(P), 1) 1068 + #define kvzalloc_objs(P, COUNT, GFP) \ 1069 + __alloc_objs(kvzalloc, GFP, typeof(P), COUNT) 1070 + #define kvzalloc_flex(P, FAM, COUNT, GFP) \ 1071 + __alloc_flex(kvzalloc, GFP, typeof(P), FAM, COUNT) 968 1072 969 1073 #define kmem_buckets_alloc(_b, _size, _flags) \ 970 1074 alloc_hooks(__kmalloc_node_noprof(PASS_BUCKET_PARAMS(_size, _b), _flags, NUMA_NO_NODE))
+33 -6
scripts/checkpatch.pl
··· 7260 7260 "Prefer $3(sizeof(*$1)...) over $3($4...)\n" . $herecurr); 7261 7261 } 7262 7262 7263 - # check for (kv|k)[mz]alloc with multiplies that could be kmalloc_array/kvmalloc_array/kvcalloc/kcalloc 7263 + # check for (kv|k)[mz]alloc that could be kmalloc_obj/kvmalloc_obj/kzalloc_obj/kvzalloc_obj 7264 + if ($perl_version_ok && 7265 + defined $stat && 7266 + $stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*,/) { 7267 + my $oldfunc = $3; 7268 + my $a1 = $4; 7269 + my $newfunc = "kmalloc_obj"; 7270 + $newfunc = "kvmalloc_obj" if ($oldfunc eq "kvmalloc"); 7271 + $newfunc = "kvzalloc_obj" if ($oldfunc eq "kvzalloc"); 7272 + $newfunc = "kzalloc_obj" if ($oldfunc eq "kzalloc"); 7273 + 7274 + if ($a1 =~ s/^sizeof\s*\S\(?([^\)]*)\)?$/$1/) { 7275 + my $cnt = statement_rawlines($stat); 7276 + my $herectx = get_stat_here($linenr, $cnt, $here); 7277 + 7278 + if (WARN("ALLOC_WITH_SIZEOF", 7279 + "Prefer $newfunc over $oldfunc with sizeof\n" . $herectx) && 7280 + $cnt == 1 && 7281 + $fix) { 7282 + $fixed[$fixlinenr] =~ s/\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*,/$1 = $newfunc($a1,/; 7283 + } 7284 + } 7285 + } 7286 + 7287 + 7288 + # check for (kv|k)[mz]alloc with multiplies that could be kmalloc_objs/kvmalloc_objs/kzalloc_objs/kvzalloc_objs 7264 7289 if ($perl_version_ok && 7265 7290 defined $stat && 7266 7291 $stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) { 7267 7292 my $oldfunc = $3; 7268 7293 my $a1 = $4; 7269 7294 my $a2 = $10; 7270 - my $newfunc = "kmalloc_array"; 7271 - $newfunc = "kvmalloc_array" if ($oldfunc eq "kvmalloc"); 7272 - $newfunc = "kvcalloc" if ($oldfunc eq "kvzalloc"); 7273 - $newfunc = "kcalloc" if ($oldfunc eq "kzalloc"); 7295 + my $newfunc = "kmalloc_objs"; 7296 + $newfunc = "kvmalloc_objs" if ($oldfunc eq "kvmalloc"); 7297 + $newfunc = "kvzalloc_objs" if ($oldfunc eq "kvzalloc"); 7298 + $newfunc = "kzalloc_objs" if ($oldfunc eq "kzalloc"); 7274 7299 my $r1 = $a1; 7275 7300 my $r2 = $a2; 7276 7301 if ($a1 =~ /^sizeof\s*\S/) { ··· 7311 7286 "Prefer $newfunc over $oldfunc with multiply\n" . $herectx) && 7312 7287 $cnt == 1 && 7313 7288 $fix) { 7314 - $fixed[$fixlinenr] =~ s/\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)/$1 . ' = ' . "$newfunc(" . trim($r1) . ', ' . trim($r2)/e; 7289 + my $sized = trim($r2); 7290 + $sized =~ s/^sizeof\s*\S\(?([^\)]*)\)?$/$1/; 7291 + $fixed[$fixlinenr] =~ s/\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)/$1 . ' = ' . "$newfunc(" . $sized . ', ' . trim($r1)/e; 7315 7292 } 7316 7293 } 7317 7294 }
+124
scripts/coccinelle/api/kmalloc_objs.cocci
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /// Use kmalloc_obj family of macros for allocations 3 + /// 4 + // Confidence: High 5 + // Options: --include-headers-for-types --all-includes --include-headers --keep-comments 6 + 7 + virtual patch 8 + 9 + @initialize:python@ 10 + @@ 11 + import sys 12 + 13 + def alloc_array(name): 14 + func = "FAILED_RENAME" 15 + if name == "kmalloc_array": 16 + func = "kmalloc_objs" 17 + elif name == "kvmalloc_array": 18 + func = "kvmalloc_objs" 19 + elif name == "kcalloc": 20 + func = "kzalloc_objs" 21 + elif name == "kvcalloc": 22 + func = "kvzalloc_objs" 23 + else: 24 + print(f"Unknown transform for {name}", file=sys.stderr) 25 + return func 26 + 27 + // This excludes anything that is assigning to or from integral types or 28 + // string literals. Everything else gets the sizeof() extracted for the 29 + // kmalloc_obj() type/var argument. sizeof(void *) is also excluded because 30 + // it will need case-by-case double-checking to make sure the right type is 31 + // being assigned. 32 + @direct depends on patch && !(file in "tools") && !(file in "samples")@ 33 + typedef u8, u16, u32, u64; 34 + typedef __u8, __u16, __u32, __u64; 35 + typedef uint8_t, uint16_t, uint32_t, uint64_t; 36 + typedef uchar, ushort, uint, ulong; 37 + typedef __le16, __le32, __le64; 38 + typedef __be16, __be32, __be64; 39 + typedef wchar_t; 40 + type INTEGRAL = {u8,__u8,uint8_t,char,unsigned char,uchar,wchar_t, 41 + u16,__u16,uint16_t,unsigned short,ushort, 42 + u32,__u32,uint32_t,unsigned int,uint, 43 + u64,__u64,uint64_t,unsigned long,ulong, 44 + __le16,__le32,__le64,__be16,__be32,__be64}; 45 + char [] STRING; 46 + INTEGRAL *BYTES; 47 + INTEGRAL **BYTES_PTRS; 48 + type TYPE; 49 + expression VAR; 50 + expression GFP; 51 + expression COUNT; 52 + expression FLEX; 53 + expression E; 54 + identifier ALLOC =~ "^kv?[mz]alloc$"; 55 + fresh identifier ALLOC_OBJ = ALLOC ## "_obj"; 56 + fresh identifier ALLOC_FLEX = ALLOC ## "_flex"; 57 + identifier ALLOC_ARRAY = {kmalloc_array,kvmalloc_array,kcalloc,kvcalloc}; 58 + fresh identifier ALLOC_OBJS = script:python(ALLOC_ARRAY) { alloc_array(ALLOC_ARRAY) }; 59 + @@ 60 + 61 + ( 62 + - VAR = ALLOC((sizeof(*VAR)), GFP) 63 + + VAR = ALLOC_OBJ(*VAR, GFP) 64 + | 65 + ALLOC((\(sizeof(STRING)\|sizeof(INTEGRAL)\|sizeof(INTEGRAL *)\)), GFP) 66 + | 67 + BYTES = ALLOC((sizeof(E)), GFP) 68 + | 69 + BYTES = ALLOC((sizeof(TYPE)), GFP) 70 + | 71 + BYTES_PTRS = ALLOC((sizeof(E)), GFP) 72 + | 73 + BYTES_PTRS = ALLOC((sizeof(TYPE)), GFP) 74 + | 75 + ALLOC((sizeof(void *)), GFP) 76 + | 77 + - ALLOC((sizeof(E)), GFP) 78 + + ALLOC_OBJ(E, GFP) 79 + | 80 + - ALLOC((sizeof(TYPE)), GFP) 81 + + ALLOC_OBJ(TYPE, GFP) 82 + | 83 + ALLOC_ARRAY(COUNT, (\(sizeof(STRING)\|sizeof(INTEGRAL)\|sizeof(INTEGRAL *)\)), GFP) 84 + | 85 + BYTES = ALLOC_ARRAY(COUNT, (sizeof(E)), GFP) 86 + | 87 + BYTES = ALLOC_ARRAY(COUNT, (sizeof(TYPE)), GFP) 88 + | 89 + BYTES_PTRS = ALLOC_ARRAY(COUNT, (sizeof(E)), GFP) 90 + | 91 + BYTES_PTRS = ALLOC_ARRAY(COUNT, (sizeof(TYPE)), GFP) 92 + | 93 + ALLOC_ARRAY((\(sizeof(STRING)\|sizeof(INTEGRAL)\|sizeof(INTEGRAL *)\)), COUNT, GFP) 94 + | 95 + BYTES = ALLOC_ARRAY((sizeof(E)), COUNT, GFP) 96 + | 97 + BYTES = ALLOC_ARRAY((sizeof(TYPE)), COUNT, GFP) 98 + | 99 + BYTES_PTRS = ALLOC_ARRAY((sizeof(E)), COUNT, GFP) 100 + | 101 + BYTES_PTRS = ALLOC_ARRAY((sizeof(TYPE)), COUNT, GFP) 102 + | 103 + ALLOC_ARRAY(COUNT, (sizeof(void *)), GFP) 104 + | 105 + ALLOC_ARRAY((sizeof(void *)), COUNT, GFP) 106 + | 107 + - ALLOC_ARRAY(COUNT, (sizeof(E)), GFP) 108 + + ALLOC_OBJS(E, COUNT, GFP) 109 + | 110 + - ALLOC_ARRAY(COUNT, (sizeof(TYPE)), GFP) 111 + + ALLOC_OBJS(TYPE, COUNT, GFP) 112 + | 113 + - ALLOC_ARRAY((sizeof(E)), COUNT, GFP) 114 + + ALLOC_OBJS(E, COUNT, GFP) 115 + | 116 + - ALLOC_ARRAY((sizeof(TYPE)), COUNT, GFP) 117 + + ALLOC_OBJS(TYPE, COUNT, GFP) 118 + | 119 + - ALLOC(struct_size(VAR, FLEX, COUNT), GFP) 120 + + ALLOC_FLEX(*VAR, FLEX, COUNT, GFP) 121 + | 122 + - ALLOC(struct_size_t(TYPE, FLEX, COUNT), GFP) 123 + + ALLOC_FLEX(TYPE, FLEX, COUNT, GFP) 124 + )