diff options
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/coccinelle/api/devm_kmalloc_objs.cocci | 136 | ||||
| -rw-r--r-- | scripts/coccinelle/free/cleanup-free.cocci | 112 | ||||
| -rw-r--r-- | scripts/coccinelle/misc/array_end.cocci | 73 |
3 files changed, 321 insertions, 0 deletions
diff --git a/scripts/coccinelle/api/devm_kmalloc_objs.cocci b/scripts/coccinelle/api/devm_kmalloc_objs.cocci new file mode 100644 index 000000000000..322f79a2d965 --- /dev/null +++ b/scripts/coccinelle/api/devm_kmalloc_objs.cocci @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0-only +/// Use devm_kmalloc_obj family of macros for allocations +/// +// Confidence: High +// Options: --include-headers-for-types --all-includes --include-headers --keep-comments + +virtual patch + +@initialize:python@ +@@ +import sys + +def alloc_array(name): + func = "FAILED_RENAME" + if name == "devm_kmalloc_array": + func = "devm_kmalloc_objs" + elif name == "devm_kvmalloc_array": + func = "devm_kvmalloc_objs" + elif name == "devm_kcalloc": + func = "devm_kzalloc_objs" + elif name == "devm_kvcalloc": + func = "devm_kvzalloc_objs" + else: + print(f"Unknown transform for {name}", file=sys.stderr) + return func + +// This excludes anything that is assigning to or from integral types or +// string literals. Everything else gets the sizeof() extracted for the +// kmalloc_obj() type/var argument. sizeof(void *) is also excluded because +// it will need case-by-case double-checking to make sure the right type is +// being assigned. +@direct depends on patch && !(file in "tools") && !(file in "samples")@ +typedef u8, u16, u32, u64; +typedef __u8, __u16, __u32, __u64; +typedef uint8_t, uint16_t, uint32_t, uint64_t; +typedef uchar, ushort, uint, ulong; +typedef __le16, __le32, __le64; +typedef __be16, __be32, __be64; +typedef wchar_t; +type INTEGRAL = {u8,__u8,uint8_t,char,unsigned char,uchar,wchar_t, + u16,__u16,uint16_t,unsigned short,ushort, + u32,__u32,uint32_t,unsigned int,uint, + u64,__u64,uint64_t,unsigned long,ulong, + __le16,__le32,__le64,__be16,__be32,__be64}; +char [] STRING; +INTEGRAL *BYTES; +INTEGRAL **BYTES_PTRS; +type TYPE; +expression VAR; +expression GFP; +expression COUNT; +expression FLEX; +expression E; +expression DEV; +identifier ALLOC =~ "^devm_kv?[mz]alloc$"; +fresh identifier ALLOC_OBJ = ALLOC ## "_obj"; +fresh identifier ALLOC_FLEX = ALLOC ## "_flex"; +identifier ALLOC_ARRAY = {devm_kmalloc_array,devm_kvmalloc_array,devm_kcalloc,devm_kvcalloc}; +fresh identifier ALLOC_OBJS = script:python(ALLOC_ARRAY) { alloc_array(ALLOC_ARRAY) }; +@@ + +( +- VAR = ALLOC(DEV,(sizeof(*VAR)), GFP) ++ VAR = ALLOC_OBJ(DEV,*VAR, GFP) +| + ALLOC(DEV,(\(sizeof(STRING)\|sizeof(INTEGRAL)\|sizeof(INTEGRAL *)\)), GFP) +| + BYTES = ALLOC(DEV,(sizeof(E)), GFP) +| + BYTES = ALLOC(DEV,(sizeof(TYPE)), GFP) +| + BYTES_PTRS = ALLOC(DEV,(sizeof(E)), GFP) +| + BYTES_PTRS = ALLOC(DEV,(sizeof(TYPE)), GFP) +| + ALLOC(DEV,(sizeof(void *)), GFP) +| +- ALLOC(DEV,(sizeof(E)), GFP) ++ ALLOC_OBJ(DEV, E, GFP) +| +- ALLOC(DEV,(sizeof(TYPE)), GFP) ++ ALLOC_OBJ(DEV,TYPE, GFP) +| + ALLOC_ARRAY(DEV,COUNT, (\(sizeof(STRING)\|sizeof(INTEGRAL)\|sizeof(INTEGRAL *)\)), GFP) +| + BYTES = ALLOC_ARRAY(DEV, COUNT, (sizeof(E)), GFP) +| + BYTES = ALLOC_ARRAY(DEV,COUNT, (sizeof(TYPE)), GFP) +| + BYTES_PTRS = ALLOC_ARRAY(DEV, COUNT, (sizeof(E)), GFP) +| + BYTES_PTRS = ALLOC_ARRAY(DEV, COUNT, (sizeof(TYPE)), GFP) +| + ALLOC_ARRAY(DEV, (\(sizeof(STRING)\|sizeof(INTEGRAL)\|sizeof(INTEGRAL *)\)), COUNT, GFP) +| + BYTES = ALLOC_ARRAY(DEV, (sizeof(E)), COUNT, GFP) +| + BYTES = ALLOC_ARRAY(DEV, (sizeof(TYPE)), COUNT, GFP) +| + BYTES_PTRS = ALLOC_ARRAY(DEV, (sizeof(E)), COUNT, GFP) +| + BYTES_PTRS = ALLOC_ARRAY(DEV, (sizeof(TYPE)), COUNT, GFP) +| + ALLOC_ARRAY(DEV, COUNT, (sizeof(void *)), GFP) +| + ALLOC_ARRAY(DEV, (sizeof(void *)), COUNT, GFP) +| +- ALLOC_ARRAY(DEV, COUNT, (sizeof(E)), GFP) ++ ALLOC_OBJS(DEV, E, COUNT, GFP) +| +- ALLOC_ARRAY(DEV, COUNT, (sizeof(TYPE)), GFP) ++ ALLOC_OBJS(DEV, TYPE, COUNT, GFP) +| +- ALLOC_ARRAY(DEV, (sizeof(E)), COUNT, GFP) ++ ALLOC_OBJS(DEV, E, COUNT, GFP) +| +- ALLOC_ARRAY(DEV, (sizeof(TYPE)), COUNT, GFP) ++ ALLOC_OBJS(DEV, TYPE, COUNT, GFP) +| +- ALLOC(DEV, struct_size(VAR, FLEX, COUNT), GFP) ++ ALLOC_FLEX(DEV, *VAR, FLEX, COUNT, GFP) +| +- ALLOC(DEV, struct_size_t(TYPE, FLEX, COUNT), GFP) ++ ALLOC_FLEX(DEV, TYPE, FLEX, COUNT, GFP) +) + +@drop_gfp_kernel depends on patch && !(file in "tools") && !(file in "samples")@ +identifier ALLOC = {devm_kmalloc_obj,devm_kmalloc_objs,devm_kmalloc_flex, + devm_kzalloc_obj,devm_kzalloc_objs,devm_kzalloc_flex, + devm_kvmalloc_obj,devm_kvmalloc_objs,devm_kvmalloc_flex, + devm_kvzalloc_obj,devm_kvzalloc_objs,devm_kvzalloc_flex}; +@@ + + ALLOC(... +- , GFP_KERNEL + ) diff --git a/scripts/coccinelle/free/cleanup-free.cocci b/scripts/coccinelle/free/cleanup-free.cocci new file mode 100644 index 000000000000..2aba766b5bbb --- /dev/null +++ b/scripts/coccinelle/free/cleanup-free.cocci @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0-only +/// +/// Find __cleanup(kfree) +/// Using __cleanup(kfree) will pass the stack address of the annotated +/// local variable to kfree, causing an invalid free. +/// I.e., `T v __cleanup(kfree);` --> `kfree(&v);` +/// Such usage is impossible to be correct. +/// +// Confidence: High +// Copyright: (C) 2026 Ella Ma +// Options: --no-includes --include-headers + +virtual report +virtual org + +// Suggesting using __free for the functions with a DEFINE_FREE definition. +// Update this list when new DEFINE_FREE definitions are added. +@free@ +attribute name __cleanup; +symbol kfree, kfree_sensitive, kvfree, kvfree_atomic, free_percpu; +type T; +identifier v, n; +position p; +@@ + +( + T v __cleanup@p( +( + n +& +( + kfree \| kfree_sensitive \| kvfree \| kvfree_atomic \| free_percpu +) +) + ); +| + T v __cleanup@p( +( + n +& +( + kfree \| kfree_sensitive \| kvfree \| kvfree_atomic \| free_percpu +) +) + ) = ...; +) + +@script:python depends on report@ +p << free.p; +n << free.n; +@@ + +msg = f"ERROR: __cleanup({n}) will cause an invalid free: the stack address of the annotated variable will be passed to {n}; declare the variable using __free({n}) to cause the pointee to be freed" +coccilib.report.print_report(p[0], msg) + +@script:python depends on org@ +p << free.p; +n << free.n; +@@ + +msg = f"ERROR: __cleanup({n}) will cause an invalid free: the stack address of the annotated variable will be passed to {n}; declare the variable using __free({n}) to cause the pointee to be freed" +coccilib.org.print_todo(p[0], msg) + + +// Reporting __cleanup usage for the functions without a DEFINE_FREE definition. +// The following list only contains frequently used functions. Supplement it if +// necessary. +@cleanup@ +attribute name __cleanup; +symbol vfree, vfree_atomic, kfree_const; +type T; +identifier v, n; +position p; +@@ + +( + T v __cleanup@p( +( + n +& +( + vfree \| vfree_atomic \| kfree_const +) +) + ); +| + T v __cleanup@p( +( + n +& +( + vfree \| vfree_atomic \| kfree_const +) +) + ) = ...; +) + +@script:python depends on report@ +p << cleanup.p; +n << cleanup.n; +@@ + +msg = f"ERROR: __cleanup({n}) will cause an invalid free: the stack address of the annotated variable will be passed to {n}" +coccilib.report.print_report(p[0], msg) + +@script:python depends on org@ +p << cleanup.p; +n << cleanup.n; +@@ + +msg = f"ERROR: __cleanup({n}) will cause an invalid free: the stack address of the annotated variable will be passed to {n}" +coccilib.org.print_todo(p[0], msg) diff --git a/scripts/coccinelle/misc/array_end.cocci b/scripts/coccinelle/misc/array_end.cocci new file mode 100644 index 000000000000..2f0bbc4ce17d --- /dev/null +++ b/scripts/coccinelle/misc/array_end.cocci @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0-only +/// Use ARRAY_END instead of an expression derived from ARRAY_SIZE +// +// Confidence: High +// Copyright: 2026, Alejandro Colomar <alx@kernel.org> +// Options: --no-includes --include-headers + +virtual patch +virtual context +virtual org +virtual report + +@depends on context disable zero_multiple_format@ +type T; +T[] a; +expression b; +@@ +( +* a + ARRAY_SIZE(a) +| +* &a[0] + ARRAY_SIZE(a) +| +* &a[ARRAY_SIZE(a)] +| +* &a[ARRAY_SIZE(a) - b] +) + +@depends on patch disable zero_multiple_format@ +type T; +T[] a; +expression b; +@@ +( +- (a + ARRAY_SIZE(a)) ++ ARRAY_END(a) +| +- (&a[0] + ARRAY_SIZE(a)) ++ ARRAY_END(a) +| +- (&a[ARRAY_SIZE(a)]) ++ ARRAY_END(a) +| +- (&a[ARRAY_SIZE(a) - b]) ++ ARRAY_END(a) - b +) + +@r depends on org || report disable zero_multiple_format@ +type T; +T[] a; +expression b; +position p; +@@ +( + a@p + ARRAY_SIZE(a) +| + &a[0]@p + ARRAY_SIZE(a) +| + &a[ARRAY_SIZE(a)]@p +| + &a[ARRAY_SIZE(a)@p - b] +) + +@script:python depends on org@ +p << r.p; +@@ + +coccilib.org.print_todo(p[0], "WARNING should use ARRAY_END") + +@script:python depends on report@ +p << r.p; +@@ + +coccilib.report.print_report(p[0], "WARNING: opportunity for ARRAY_END") |
