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
Showing the changes to scripts (2 of 6 files). Show all
Unified · Split
| @@ -7260,17 +7260,42 @@ sub process { · 7259 unmodified lines | |||
| 7260 | "Prefer $3(sizeof(*$1)...) over $3($4...)\n" . $herecurr); | 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 | if ($perl_version_ok && | 7289 | if ($perl_version_ok && |
| 7265 | defined $stat && | 7290 | defined $stat && |
| 7266 | $stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) { | 7291 | $stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) { |
| 7267 | my $oldfunc = $3; | 7292 | my $oldfunc = $3; |
| 7268 | my $a1 = $4; | 7293 | my $a1 = $4; |
| 7269 | my $a2 = $10; | 7294 | my $a2 = $10; |
| 7270 | my $newfunc = "kmalloc_array"; | 7295 | my $newfunc = "kmalloc_objs"; |
| 7271 | $newfunc = "kvmalloc_array" if ($oldfunc eq "kvmalloc"); | 7296 | $newfunc = "kvmalloc_objs" if ($oldfunc eq "kvmalloc"); |
| 7272 | $newfunc = "kvcalloc" if ($oldfunc eq "kvzalloc"); | 7297 | $newfunc = "kvzalloc_objs" if ($oldfunc eq "kvzalloc"); |
| 7273 | $newfunc = "kcalloc" if ($oldfunc eq "kzalloc"); | 7298 | $newfunc = "kzalloc_objs" if ($oldfunc eq "kzalloc"); |
| 7274 | my $r1 = $a1; | 7299 | my $r1 = $a1; |
| 7275 | my $r2 = $a2; | 7300 | my $r2 = $a2; |
| 7276 | if ($a1 =~ /^sizeof\s*\S/) { | 7301 | if ($a1 =~ /^sizeof\s*\S/) { |
| @@ -7286,7 +7311,9 @@ sub process { · 9 unmodified lines | |||
| 7286 | "Prefer $newfunc over $oldfunc with multiply\n" . $herectx) && | 7311 | "Prefer $newfunc over $oldfunc with multiply\n" . $herectx) && |
| 7287 | $cnt == 1 && | 7312 | $cnt == 1 && |
| 7288 | $fix) { | 7313 | $fix) { |
| 7289 | $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; | 7314 | my $sized = trim($r2); |
| 7315 | $sized =~ s/^sizeof\s*\S\(?([^\)]*)\)?$/$1/; | ||
| 7316 | $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; | ||
| 7290 | } | 7317 | } |
| 7291 | } | 7318 | } |
| 7292 | } | 7319 | } |
| @@ -0,0 +1,124 @@ | |||
| 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 | ) | ||