[RFC PATCH] coccinelle: api: add flex_array_size.cocci script

From: Denis Efremov
Date: Fri Aug 28 2020 - 12:32:14 EST


Suggest flex_array_size() wrapper to compute the size of a
flexible array member in a structure. The macro additionally
checks for integer overflows.

The cocci script intentionally skips cases where count argument
is not a member of a structure because this introduce false
positives.

Cc: Gustavo A. R. Silva <gustavoars@xxxxxxxxxx>
Cc: Kees Cook <keescook@xxxxxxxxxxxx>
Signed-off-by: Denis Efremov <efremov@xxxxxxxxx>
---
Kees, Gustavo, may I have your acks if you find this script useful?
Currently, it emits following warnings:
./fs/select.c:994:25-26: WARNING opportunity for flex_array_size
./include/linux/avf/virtchnl.h:711:34-35: WARNING opportunity for flex_array_size
./include/linux/avf/virtchnl.h:722:43-44: WARNING opportunity for flex_array_size
./include/linux/avf/virtchnl.h:738:40-41: WARNING opportunity for flex_array_size
./include/linux/avf/virtchnl.h:749:46-47: WARNING opportunity for flex_array_size
./drivers/dma/qcom/bam_dma.c:1055:35-36: WARNING opportunity for flex_array_size
./drivers/md/dm-crypt.c:2895:45-46: WARNING opportunity for flex_array_size
./drivers/md/dm-crypt.c:3381:47-48: WARNING opportunity for flex_array_size
./drivers/md/dm-crypt.c:2484:45-46: WARNING opportunity for flex_array_size
./drivers/md/dm-crypt.c:2484:45-46: WARNING opportunity for flex_array_size
./net/sched/em_canid.c:198:48-49: WARNING opportunity for flex_array_size
./include/linux/filter.h:741:42-43: WARNING opportunity for flex_array_size
./fs/aio.c:677:42-43: WARNING opportunity for flex_array_size
./include/rdma/rdmavt_qp.h:537:31-32: WARNING opportunity for flex_array_size
./include/rdma/rdmavt_qp.h:537:31-32: WARNING opportunity for flex_array_size
./lib/ts_fsm.c:311:49-50: WARNING opportunity for flex_array_size
./mm/slab.c:3407:59-60: WARNING opportunity for flex_array_size
./mm/slab.c:2139:55-56: WARNING opportunity for flex_array_size
./mm/slab.c:3407:59-60: WARNING opportunity for flex_array_size
./mm/slab.c:2139:55-56: WARNING opportunity for flex_array_size

scripts/coccinelle/api/flex_array_size.cocci | 180 +++++++++++++++++++
1 file changed, 180 insertions(+)
create mode 100644 scripts/coccinelle/api/flex_array_size.cocci

diff --git a/scripts/coccinelle/api/flex_array_size.cocci b/scripts/coccinelle/api/flex_array_size.cocci
new file mode 100644
index 000000000000..b5264a826c29
--- /dev/null
+++ b/scripts/coccinelle/api/flex_array_size.cocci
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Suggest flex_array_size() wrapper to compute the size of a
+/// flexible array member in a structure. The macro additionally
+/// checks for integer overflows.
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+// Keywords: flex_array_size
+//
+
+
+virtual context
+virtual report
+virtual org
+virtual patch
+
+@decl_flex@
+identifier name, array, size;
+type TA, TS;
+@@
+
+ struct name {
+ ...
+ TS size;
+ ...
+(
+ TA array[];
+|
+ TA array[\(0\|1\)];
+)
+ };
+
+@ptr_flex@
+identifier decl_flex.name;
+identifier instance;
+@@
+
+ struct name *instance;
+
+@struct_flex@
+identifier decl_flex.name;
+identifier instance;
+@@
+
+ struct name instance;
+
+@ptr_flex_size depends on !patch@
+identifier decl_flex.array, decl_flex.size;
+identifier ptr_flex.instance;
+type decl_flex.TA;
+position p;
+@@
+
+(
+* instance->size * sizeof(TA)@p
+|
+* instance->size * sizeof(*instance->array)@p
+)
+
+@depends on patch exists@
+identifier decl_flex.array, decl_flex.size;
+identifier ptr_flex.instance;
+type decl_flex.TA;
+@@
+
+(
+- instance->size * sizeof(TA)
++ flex_array_size(instance, array, instance->size)
+|
+- instance->size * sizeof(*instance->array)
++ flex_array_size(instance, array, instance->size)
+)
+
+@struct_flex_size depends on !patch@
+identifier decl_flex.array, decl_flex.size;
+identifier struct_flex.instance;
+type decl_flex.TA;
+position p;
+@@
+
+(
+* instance.size * sizeof(TA)@p
+|
+* instance.size * sizeof(*instance->array)@p
+)
+
+@depends on patch exists@
+identifier decl_flex.array, decl_flex.size;
+identifier struct_flex.instance;
+type decl_flex.TA;
+@@
+
+(
+- instance.size * sizeof(TA)
++ flex_array_size(instance, array, instance.size)
+|
+- instance.size * sizeof(*instance->array)
++ flex_array_size(instance, array, instance.size)
+)
+
+@func_arg_flex_size depends on !patch@
+identifier decl_flex.name, decl_flex.array, decl_flex.size;
+identifier func, instance;
+type decl_flex.TA;
+position p;
+@@
+
+ func(..., struct name *instance, ...) {
+ ... when any
+(
+* instance->size * sizeof(TA)@p
+|
+* instance->size * sizeof(*instance->array)@p
+)
+ ...
+ }
+
+@depends on patch exists@
+identifier decl_flex.name, decl_flex.array, decl_flex.size;
+identifier func, instance;
+type decl_flex.TA;
+@@
+
+ func(..., struct name *instance, ...) {
+ ... when any
+(
+- instance->size * sizeof(TA)
++ flex_array_size(instance, array, instance->size)
+|
+- instance->size * sizeof(*instance->array)
++ flex_array_size(instance, array, instance->size)
+)
+ ...
+ }
+
+
+@script:python depends on report@
+p << ptr_flex_size.p;
+@@
+
+coccilib.report.print_report(p[0],
+ "WARNING opportunity for flex_array_size")
+
+@script:python depends on org@
+p << ptr_flex_size.p;
+@@
+
+coccilib.org.print_todo(p[0],
+ "WARNING opportunity for flex_array_size")
+
+@script:python depends on report@
+p << struct_flex_size.p;
+@@
+
+coccilib.report.print_report(p[0],
+ "WARNING opportunity for flex_array_size")
+
+@script:python depends on org@
+p << struct_flex_size.p;
+@@
+
+coccilib.org.print_todo(p[0],
+ "WARNING opportunity for flex_array_size")
+
+@script:python depends on report@
+p << func_arg_flex_size.p;
+@@
+
+coccilib.report.print_report(p[0],
+ "WARNING opportunity for flex_array_size")
+
+@script:python depends on org@
+p << func_arg_flex_size.p;
+@@
+
+coccilib.org.print_todo(p[0],
+ "WARNING opportunity for flex_array_size")
--
2.26.2