Re: [Cocci] [RESEND] coccinelle: api: rename kzfree to kfree_sensitive

2021-08-05 Thread Denis Efremov
Hi,

On 8/5/21 12:58 PM, Weizhao Ouyang wrote:
> Commit 453431a54934 ("mm, treewide: rename kzfree() to
> kfree_sensitive()") renamed kzfree() to kfree_sensitive(),
> it should be applied to coccinelle.
> 
> Signed-off-by: Weizhao Ouyang 

Acked-by: Denis Efremov 

> ---
>  scripts/coccinelle/api/kvmalloc.cocci | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/scripts/coccinelle/api/kvmalloc.cocci 
> b/scripts/coccinelle/api/kvmalloc.cocci
> index c30dab718a49..5ddcb76b76b0 100644
> --- a/scripts/coccinelle/api/kvmalloc.cocci
> +++ b/scripts/coccinelle/api/kvmalloc.cocci
> @@ -79,7 +79,7 @@ position p : script:python() { relevant(p) };
>} else {
>  ... when != krealloc(E, ...)
>  when any
> -*   \(kfree\|kzfree\)(E)
> +*   \(kfree\|kfree_sensitive\)(E)
>  ...
>}
>  
> 

Regards,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [RESEND PATCH] coccinelle: misc: minmax: suppress patch generation for err returns

2021-06-15 Thread Denis Efremov
Ping?

On 4/28/21 9:03 AM, Denis Efremov wrote:
> There is a standard idiom for "if 'ret' holds an error, return it":
>   return ret < 0 ? ret : 0;
> 
> Developers prefer to keep the things as they are because stylistic
> change to "return min(ret, 0);" breaks readability.
> 
> Let's suppress automatic generation for this type of patches.
> 
> Signed-off-by: Denis Efremov 
> ---
>  scripts/coccinelle/misc/minmax.cocci | 18 +-
>  1 file changed, 17 insertions(+), 1 deletion(-)
> 
> diff --git a/scripts/coccinelle/misc/minmax.cocci 
> b/scripts/coccinelle/misc/minmax.cocci
> index eccdd3eb3452..fcf908b34f27 100644
> --- a/scripts/coccinelle/misc/minmax.cocci
> +++ b/scripts/coccinelle/misc/minmax.cocci
> @@ -116,16 +116,32 @@ func(...)
>   ...>
>  }
>  
> +// Don't generate patches for errcode returns.
> +@errcode depends on patch@
> +position p;
> +identifier func;
> +expression x;
> +binary operator cmp = {<, <=};
> +@@
> +
> +func(...)
> +{
> + <...
> + return ((x) cmp@p 0 ? (x) : 0);
> + ...>
> +}
> +
>  @pmin depends on patch@
>  identifier func;
>  expression x, y;
>  binary operator cmp = {<=, <};
> +position p != errcode.p;
>  @@
>  
>  func(...)
>  {
>   <...
> --((x) cmp (y) ? (x) : (y))
> +-((x) cmp@p (y) ? (x) : (y))
>  +min(x, y)
>   ...>
>  }
> 
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [RESEND PATCH] coccinelle: misc: minmax: suppress patch generation for err returns

2021-04-28 Thread Denis Efremov
There is a standard idiom for "if 'ret' holds an error, return it":
return ret < 0 ? ret : 0;

Developers prefer to keep the things as they are because stylistic
change to "return min(ret, 0);" breaks readability.

Let's suppress automatic generation for this type of patches.

Signed-off-by: Denis Efremov 
---
 scripts/coccinelle/misc/minmax.cocci | 18 +-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/scripts/coccinelle/misc/minmax.cocci 
b/scripts/coccinelle/misc/minmax.cocci
index eccdd3eb3452..fcf908b34f27 100644
--- a/scripts/coccinelle/misc/minmax.cocci
+++ b/scripts/coccinelle/misc/minmax.cocci
@@ -116,16 +116,32 @@ func(...)
...>
 }
 
+// Don't generate patches for errcode returns.
+@errcode depends on patch@
+position p;
+identifier func;
+expression x;
+binary operator cmp = {<, <=};
+@@
+
+func(...)
+{
+   <...
+   return ((x) cmp@p 0 ? (x) : 0);
+   ...>
+}
+
 @pmin depends on patch@
 identifier func;
 expression x, y;
 binary operator cmp = {<=, <};
+position p != errcode.p;
 @@
 
 func(...)
 {
<...
--  ((x) cmp (y) ? (x) : (y))
+-  ((x) cmp@p (y) ? (x) : (y))
 +  min(x, y)
...>
 }
-- 
2.30.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] Incorrect match with when != condition

2021-03-17 Thread Denis Efremov




On 3/17/21 11:32 PM, Julia Lawall wrote:



On Wed, 17 Mar 2021, Denis Efremov wrote:


Hi,

I'm trying to write the check to detect the absence of commit
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=51b2ee7d006a736a9126e8111d1f24e4fd0afaa6
in kernel. The pattern can be:

@err exists@
identifier namlen, dchild, dparent, exp;
position p;
statement S;
@@

compose_entry_fh(..., int namlen, ...)
{
...
if (namlen == 2) {
*   dchild =@p dget_parent(dparent);
... when != dparent == exp->ex_path.dentry


add when forall here.  There does exist a path that does not contain the
dparent == exp->ex_path.dentry test.  That is the path that takesthe first
goto out.


This solved the problem, thanks!
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] Incorrect match with when != condition

2021-03-17 Thread Denis Efremov

Hi,

I'm trying to write the check to detect the absence of commit
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=51b2ee7d006a736a9126e8111d1f24e4fd0afaa6
in kernel. The pattern can be:

@err exists@
identifier namlen, dchild, dparent, exp;
position p;
statement S;
@@

compose_entry_fh(..., int namlen, ...)
{
...
if (namlen == 2) {
*   dchild =@p dget_parent(dparent);
... when != dparent == exp->ex_path.dentry
} else S
...
}

But unfortunately, it matches even the fixed source. I think
that condition "... when != dparent == exp->ex_path.dentry" doesn't
work as expected. Steps to reproduce:

$ cd linux # latest master branch
$ wget 
https://raw.githubusercontent.com/evdenis/cvehound/b2d109c959c299dce10274c1806406fc5653e5d0/cvehound/cve/CVE-2021-3178.cocci
$ spatch -D detect --cocci-file CVE-2021-3178.cocci fs/nfsd/nfs3xdr.c
fs/nfsd/nfs3xdr.c:935:10-11: ERROR: CVE-2021-3178
diff =
--- fs/nfsd/nfs3xdr.c
+++ /tmp/cocci-output-526900-b87df1-nfs3xdr.c
@@ -932,7 +932,6 @@ compose_entry_fh(struct nfsd3_readdirres
 
if (isdotent(name, namlen)) {

if (namlen == 2) {
// !!! shouldn't match because of if (dparent == 
exp->ex_path.dentry) goto out; check after
-   dchild = dget_parent(dparent);
/*
 * Don't return filehandle for ".." if we're at
 * the filesystem or export root:
$ spatch --version
spatch version 1.1.0 compiled with OCaml version 4.11.1

Thanks,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v5] coccinelle: misc: add minmax script

2021-03-08 Thread Denis Efremov
Check for opencoded min(), max() implementations.

Signed-off-by: Denis Efremov 
---
Changes in v2:
 - <... ...> instead of ... when any
 - org mode reports fixed
 - patch rule to drop excessive ()
Changes in v3:
 - "depends on patch && (pmax || pmaxif || pmin || pminif)" fixed
Changes in v4:
 - refarmatting rule removed
 - () brackets added to the patch rules to omit excessive ones
 - org/report prints changed to cycle (for p0 in p: ...)
Changes in v5:
 - parentheses droppped in pminif and pmaxif rules (max_val = x ...)

 scripts/coccinelle/misc/minmax.cocci | 206 +++
 1 file changed, 206 insertions(+)
 create mode 100644 scripts/coccinelle/misc/minmax.cocci

diff --git a/scripts/coccinelle/misc/minmax.cocci 
b/scripts/coccinelle/misc/minmax.cocci
new file mode 100644
index ..eccdd3eb3452
--- /dev/null
+++ b/scripts/coccinelle/misc/minmax.cocci
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Check for opencoded min(), max() implementations.
+/// Generated patches sometimes require adding a cast to fix compile warning.
+/// Warnings/patches scope intentionally limited to a function body.
+///
+// Confidence: Medium
+// Copyright: (C) 2021 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+// Keywords: min, max
+//
+
+
+virtual report
+virtual org
+virtual context
+virtual patch
+
+@rmax depends on !patch@
+identifier func;
+expression x, y;
+binary operator cmp = {>, >=};
+position p;
+@@
+
+func(...)
+{
+   <...
+*  ((x) cmp@p (y) ? (x) : (y))
+   ...>
+}
+
+@rmaxif depends on !patch@
+identifier func;
+expression x, y;
+expression max_val;
+binary operator cmp = {>, >=};
+position p;
+@@
+
+func(...)
+{
+   <...
+*  if ((x) cmp@p (y)) {
+*  max_val = (x);
+*  } else {
+*  max_val = (y);
+*  }
+   ...>
+}
+
+@rmin depends on !patch@
+identifier func;
+expression x, y;
+binary operator cmp = {<, <=};
+position p;
+@@
+
+func(...)
+{
+   <...
+*  ((x) cmp@p (y) ? (x) : (y))
+   ...>
+}
+
+@rminif depends on !patch@
+identifier func;
+expression x, y;
+expression min_val;
+binary operator cmp = {<, <=};
+position p;
+@@
+
+func(...)
+{
+   <...
+*  if ((x) cmp@p (y)) {
+*  min_val = (x);
+*  } else {
+*  min_val = (y);
+*  }
+   ...>
+}
+
+@pmax depends on patch@
+identifier func;
+expression x, y;
+binary operator cmp = {>=, >};
+@@
+
+func(...)
+{
+   <...
+-  ((x) cmp (y) ? (x) : (y))
++  max(x, y)
+   ...>
+}
+
+@pmaxif depends on patch@
+identifier func;
+expression x, y;
+expression max_val;
+binary operator cmp = {>=, >};
+@@
+
+func(...)
+{
+   <...
+-  if ((x) cmp (y)) {
+-  max_val = x;
+-  } else {
+-  max_val = y;
+-  }
++  max_val = max(x, y);
+   ...>
+}
+
+@pmin depends on patch@
+identifier func;
+expression x, y;
+binary operator cmp = {<=, <};
+@@
+
+func(...)
+{
+   <...
+-  ((x) cmp (y) ? (x) : (y))
++  min(x, y)
+   ...>
+}
+
+@pminif depends on patch@
+identifier func;
+expression x, y;
+expression min_val;
+binary operator cmp = {<=, <};
+@@
+
+func(...)
+{
+   <...
+-  if ((x) cmp (y)) {
+-  min_val = x;
+-  } else {
+-  min_val = y;
+-  }
++  min_val = min(x, y);
+   ...>
+}
+
+@script:python depends on report@
+p << rmax.p;
+@@
+
+for p0 in p:
+   coccilib.report.print_report(p0, "WARNING opportunity for max()")
+
+@script:python depends on org@
+p << rmax.p;
+@@
+
+for p0 in p:
+   coccilib.org.print_todo(p0, "WARNING opportunity for max()")
+
+@script:python depends on report@
+p << rmaxif.p;
+@@
+
+for p0 in p:
+   coccilib.report.print_report(p0, "WARNING opportunity for max()")
+
+@script:python depends on org@
+p << rmaxif.p;
+@@
+
+for p0 in p:
+   coccilib.org.print_todo(p0, "WARNING opportunity for max()")
+
+@script:python depends on report@
+p << rmin.p;
+@@
+
+for p0 in p:
+   coccilib.report.print_report(p0, "WARNING opportunity for min()")
+
+@script:python depends on org@
+p << rmin.p;
+@@
+
+for p0 in p:
+   coccilib.org.print_todo(p0, "WARNING opportunity for min()")
+
+@script:python depends on report@
+p << rminif.p;
+@@
+
+for p0 in p:
+   coccilib.report.print_report(p0, "WARNING opportunity for min()")
+
+@script:python depends on org@
+p << rminif.p;
+@@
+
+for p0 in p:
+   coccilib.org.print_todo(p0, "WARNING opportunity for min()")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH] coccinelle: misc: restrict patch mode in flexible_array.cocci

2021-03-08 Thread Denis Efremov
Skip patches generation for structs/unions with a single field.
Changing a zero-length array to a flexible array member in a struct
with no named members breaks the compilation. However, reporting
such cases is still valuable, e.g. commit 637464c59e0b
("ACPI: NFIT: Fix flexible_array.cocci warnings").

Signed-off-by: Denis Efremov 
---
 scripts/coccinelle/misc/flexible_array.cocci | 23 ++--
 1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/scripts/coccinelle/misc/flexible_array.cocci 
b/scripts/coccinelle/misc/flexible_array.cocci
index 947fbaff82a9..f427fd68ed2d 100644
--- a/scripts/coccinelle/misc/flexible_array.cocci
+++ b/scripts/coccinelle/misc/flexible_array.cocci
@@ -51,21 +51,40 @@ position p : script:python() { relevant(p) };
   };
 )
 
+@only_field depends on patch@
+identifier name, array;
+type T;
+position q;
+@@
+
+(
+  struct name {@q
+T array[0];
+  };
+|
+  struct {@q
+T array[0];
+  };
+)
+
 @depends on patch@
 identifier name, array;
 type T;
 position p : script:python() { relevant(p) };
+// position @q with rule "only_field" simplifies
+// handling of bitfields, arrays, etc.
+position q != only_field.q;
 @@
 
 (
-  struct name {
+  struct name {@q
 ...
 T array@p[
 -   0
 ];
   };
 |
-  struct {
+  struct {@q
 ...
 T array@p[
 -   0
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH] coccinelle: misc: update uninitialized_var.cocci documentation

2021-03-07 Thread Denis Efremov
Remove the documentation link from the warning message because commit
3942ea7a10c9 ("deprecated.rst: Remove now removed uninitialized_var")
removed the section from documentation. Update the rule documentation
accordingly.

Signed-off-by: Denis Efremov 
---
 scripts/coccinelle/misc/uninitialized_var.cocci | 15 ++-
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/scripts/coccinelle/misc/uninitialized_var.cocci 
b/scripts/coccinelle/misc/uninitialized_var.cocci
index 8fa845cefe11..69bbaae47e73 100644
--- a/scripts/coccinelle/misc/uninitialized_var.cocci
+++ b/scripts/coccinelle/misc/uninitialized_var.cocci
@@ -1,7 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0-only
 ///
 /// Please, don't reintroduce uninitialized_var().
-/// From Documentation/process/deprecated.rst:
+///
+/// From Documentation/process/deprecated.rst,
+/// commit 4b19bec97c88 ("docs: deprecated.rst: Add uninitialized_var()"):
 ///  For any compiler warnings about uninitialized variables, just add
 ///  an initializer. Using warning-silencing tricks is dangerous as it
 ///  papers over real bugs (or can in the future), and suppresses unrelated
@@ -11,6 +13,11 @@
 ///  obviously redundant, the compiler's dead-store elimination pass will make
 ///  sure there are no needless variable writes.
 ///
+/// Later, commit 3942ea7a10c9 ("deprecated.rst: Remove now removed
+/// uninitialized_var") removed this section because all initializations of
+/// this kind were cleaned-up from the kernel. This cocci rule checks that
+/// the macro is not explicitly or implicitly reintroduced.
+///
 // Confidence: High
 // Copyright: (C) 2020 Denis Efremov ISPRAS
 // Options: --no-includes --include-headers
@@ -40,12 +47,10 @@ position p;
 p << r.p;
 @@
 
-coccilib.report.print_report(p[0],
-  "WARNING this kind of initialization is deprecated 
(https://www.kernel.org/doc/html/latest/process/deprecated.html#uninitialized-var)")
+coccilib.report.print_report(p[0], "WARNING this kind of initialization is 
deprecated")
 
 @script:python depends on org@
 p << r.p;
 @@
 
-coccilib.org.print_todo(p[0],
-  "WARNING this kind of initialization is deprecated 
(https://www.kernel.org/doc/html/latest/process/deprecated.html#uninitialized-var)")
+coccilib.org.print_todo(p[0], "WARNING this kind of initialization is 
deprecated")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v4] coccinelle: misc: add minmax script

2021-03-07 Thread Denis Efremov
Check for opencoded min(), max() implementations.

Signed-off-by: Denis Efremov 
---
Changes in v2:
 - <... ...> instead of ... when any
 - org mode reports fixed
 - patch rule to drop excessive ()
Changes in v3:
 - "depends on patch && (pmax || pmaxif || pmin || pminif)" fixed
Changes in v4:
 - refarmatting rule removed
 - () brackets added to the patch rules to omit excessive ones
 - org/report prints changed to cycle (for p0 in p: ...)

 scripts/coccinelle/misc/minmax.cocci | 206 +++
 1 file changed, 206 insertions(+)
 create mode 100644 scripts/coccinelle/misc/minmax.cocci

diff --git a/scripts/coccinelle/misc/minmax.cocci 
b/scripts/coccinelle/misc/minmax.cocci
new file mode 100644
index ..63eeba1702ec
--- /dev/null
+++ b/scripts/coccinelle/misc/minmax.cocci
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Check for opencoded min(), max() implementations.
+/// Generated patches sometimes require adding a cast to fix compile warning.
+/// Warnings/patches scope intentionally limited to a function body.
+///
+// Confidence: Medium
+// Copyright: (C) 2021 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+// Keywords: min, max
+//
+
+
+virtual report
+virtual org
+virtual context
+virtual patch
+
+@rmax depends on !patch@
+identifier func;
+expression x, y;
+binary operator cmp = {>, >=};
+position p;
+@@
+
+func(...)
+{
+   <...
+*  ((x) cmp@p (y) ? (x) : (y))
+   ...>
+}
+
+@rmaxif depends on !patch@
+identifier func;
+expression x, y;
+expression max_val;
+binary operator cmp = {>, >=};
+position p;
+@@
+
+func(...)
+{
+   <...
+*  if ((x) cmp@p (y)) {
+*  max_val = (x);
+*  } else {
+*  max_val = (y);
+*  }
+   ...>
+}
+
+@rmin depends on !patch@
+identifier func;
+expression x, y;
+binary operator cmp = {<, <=};
+position p;
+@@
+
+func(...)
+{
+   <...
+*  ((x) cmp@p (y) ? (x) : (y))
+   ...>
+}
+
+@rminif depends on !patch@
+identifier func;
+expression x, y;
+expression min_val;
+binary operator cmp = {<, <=};
+position p;
+@@
+
+func(...)
+{
+   <...
+*  if ((x) cmp@p (y)) {
+*  min_val = (x);
+*  } else {
+*  min_val = (y);
+*  }
+   ...>
+}
+
+@pmax depends on patch@
+identifier func;
+expression x, y;
+binary operator cmp = {>=, >};
+@@
+
+func(...)
+{
+   <...
+-  ((x) cmp (y) ? (x) : (y))
++  max(x, y)
+   ...>
+}
+
+@pmaxif depends on patch@
+identifier func;
+expression x, y;
+expression max_val;
+binary operator cmp = {>=, >};
+@@
+
+func(...)
+{
+   <...
+-  if ((x) cmp (y)) {
+-  max_val = (x);
+-  } else {
+-  max_val = (y);
+-  }
++  max_val = max(x, y);
+   ...>
+}
+
+@pmin depends on patch@
+identifier func;
+expression x, y;
+binary operator cmp = {<=, <};
+@@
+
+func(...)
+{
+   <...
+-  ((x) cmp (y) ? (x) : (y))
++  min(x, y)
+   ...>
+}
+
+@pminif depends on patch@
+identifier func;
+expression x, y;
+expression min_val;
+binary operator cmp = {<=, <};
+@@
+
+func(...)
+{
+   <...
+-  if ((x) cmp (y)) {
+-  min_val = (x);
+-  } else {
+-  min_val = (y);
+-  }
++  min_val = min(x, y);
+   ...>
+}
+
+@script:python depends on report@
+p << rmax.p;
+@@
+
+for p0 in p:
+   coccilib.report.print_report(p0, "WARNING opportunity for max()")
+
+@script:python depends on org@
+p << rmax.p;
+@@
+
+for p0 in p:
+   coccilib.org.print_todo(p0, "WARNING opportunity for max()")
+
+@script:python depends on report@
+p << rmaxif.p;
+@@
+
+for p0 in p:
+   coccilib.report.print_report(p0, "WARNING opportunity for max()")
+
+@script:python depends on org@
+p << rmaxif.p;
+@@
+
+for p0 in p:
+   coccilib.org.print_todo(p0, "WARNING opportunity for max()")
+
+@script:python depends on report@
+p << rmin.p;
+@@
+
+for p0 in p:
+   coccilib.report.print_report(p0, "WARNING opportunity for min()")
+
+@script:python depends on org@
+p << rmin.p;
+@@
+
+for p0 in p:
+   coccilib.org.print_todo(p0, "WARNING opportunity for min()")
+
+@script:python depends on report@
+p << rminif.p;
+@@
+
+for p0 in p:
+   coccilib.report.print_report(p0, "WARNING opportunity for min()")
+
+@script:python depends on org@
+p << rminif.p;
+@@
+
+for p0 in p:
+   coccilib.org.print_todo(p0, "WARNING opportunity for min()")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v3] coccinelle: misc: add minmax script

2021-03-05 Thread Denis Efremov
Check for opencoded min(), max() implementations.

Signed-off-by: Denis Efremov 
---
Changes in v2:
 - <... ...> instead of ... when any
 - org mode reports fixed
 - patch rule to drop excessive ()
Changes in v3:
 - "depends on patch && (pmax || pmaxif || pmin || pminif)" fixed

 scripts/coccinelle/misc/minmax.cocci | 224 +++
 1 file changed, 224 insertions(+)
 create mode 100644 scripts/coccinelle/misc/minmax.cocci

diff --git a/scripts/coccinelle/misc/minmax.cocci 
b/scripts/coccinelle/misc/minmax.cocci
new file mode 100644
index ..f577f08d1e6e
--- /dev/null
+++ b/scripts/coccinelle/misc/minmax.cocci
@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Check for opencoded min(), max() implementations.
+/// Generated patches sometimes require adding a cast to fix compile warning.
+/// Warnings/patches scope intentionally limited to a function body.
+///
+// Confidence: Medium
+// Copyright: (C) 2021 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+// Keywords: min, max
+//
+
+
+virtual report
+virtual org
+virtual context
+virtual patch
+
+@rmax depends on !patch@
+identifier func;
+expression x, y;
+binary operator cmp = {>, >=};
+position p;
+@@
+
+func(...)
+{
+   <...
+*  x cmp@p y ? x : y
+   ...>
+}
+
+@rmaxif depends on !patch@
+identifier func;
+expression x, y;
+expression max_val;
+binary operator cmp = {>, >=};
+position p;
+@@
+
+func(...)
+{
+   <...
+*  if (x cmp@p y) {
+*  max_val = x;
+*  } else {
+*  max_val = y;
+*  }
+   ...>
+}
+
+@rmin depends on !patch@
+identifier func;
+expression x, y;
+binary operator cmp = {<, <=};
+position p;
+@@
+
+func(...)
+{
+   <...
+*  x cmp@p y ? x : y
+   ...>
+}
+
+@rminif depends on !patch@
+identifier func;
+expression x, y;
+expression min_val;
+binary operator cmp = {<, <=};
+position p;
+@@
+
+func(...)
+{
+   <...
+*  if (x cmp@p y) {
+*  min_val = x;
+*  } else {
+*  min_val = y;
+*  }
+   ...>
+}
+
+@pmax depends on patch@
+identifier func;
+expression x, y;
+binary operator cmp = {>=, >};
+position p;
+@@
+
+func@p(...)
+{
+   <...
+-  x cmp y ? x : y
++  max(x, y)
+   ...>
+}
+
+@pmaxif depends on patch@
+identifier func;
+expression x, y;
+expression max_val;
+binary operator cmp = {>=, >};
+position p;
+@@
+
+func@p(...)
+{
+   <...
+-  if (x cmp y) {
+-  max_val = x;
+-  } else {
+-  max_val = y;
+-  }
++  max_val = max(x, y);
+   ...>
+}
+
+@pmin depends on patch@
+identifier func;
+expression x, y;
+binary operator cmp = {<=, <};
+position p;
+@@
+
+func@p(...)
+{
+   <...
+-  x cmp y ? x : y
++  min(x, y)
+   ...>
+}
+
+@pminif depends on patch@
+identifier func;
+expression x, y;
+expression min_val;
+binary operator cmp = {<=, <};
+position p;
+@@
+
+func@p(...)
+{
+   <...
+-  if (x cmp y) {
+-  min_val = x;
+-  } else {
+-  min_val = y;
+-  }
++  min_val = min(x, y);
+   ...>
+}
+
+@depends on patch && (pmax || pmaxif || pmin || pminif)@
+identifier func;
+expression x, y;
+position p;
+// FIXME: Coccinelle consumes all available ram and
+// and timeouts on every file.
+// position p = { pmin.p, pminif.p, pmax.p, pmaxif.p };
+@@
+
+func@p(...)
+{
+   <...
+(
+-  (min((x), (y)))
++  min(x, y)
+|
+-  (max((x), (y)))
++  max(x, y)
+)
+   ...>
+}
+
+@script:python depends on report@
+p << rmax.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for max()")
+
+@script:python depends on org@
+p << rmax.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for max()")
+
+@script:python depends on report@
+p << rmaxif.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for max()")
+
+@script:python depends on org@
+p << rmaxif.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for max()")
+
+@script:python depends on report@
+p << rmin.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for min()")
+
+@script:python depends on org@
+p << rmin.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for min()")
+
+@script:python depends on report@
+p << rminif.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for min()")
+
+@script:python depends on org@
+p << rminif.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for min()")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v3] coccinelle: misc: add swap script

2021-03-05 Thread Denis Efremov
Check for opencoded swap() implementation.

Signed-off-by: Denis Efremov 
---
Changes in v2:
 - additional patch rule to drop excessive {}
 - fix indentation in patch mode by anchoring ;
Changes in v3:
 - Rule added for simple (without var init) swap highlighting in !patch mode 
 - "depends on patch && (rpvar || rp)" fixed

 scripts/coccinelle/misc/swap.cocci | 122 +
 1 file changed, 122 insertions(+)
 create mode 100644 scripts/coccinelle/misc/swap.cocci

diff --git a/scripts/coccinelle/misc/swap.cocci 
b/scripts/coccinelle/misc/swap.cocci
new file mode 100644
index ..c5e71b7ef7f5
--- /dev/null
+++ b/scripts/coccinelle/misc/swap.cocci
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Check for opencoded swap() implementation.
+///
+// Confidence: High
+// Copyright: (C) 2021 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+// Keywords: swap
+//
+
+virtual patch
+virtual org
+virtual report
+virtual context
+
+@rvar depends on !patch@
+identifier tmp;
+expression a, b;
+type T;
+position p;
+@@
+
+(
+* T tmp;
+|
+* T tmp = 0;
+|
+* T *tmp = NULL;
+)
+... when != tmp
+* tmp = a;
+* a = b;@p
+* b = tmp;
+... when != tmp
+
+@r depends on !patch@
+identifier tmp;
+expression a, b;
+position p != rvar.p;
+@@
+
+* tmp = a;
+* a = b;@p
+* b = tmp;
+
+@rpvar depends on patch@
+identifier tmp;
+expression a, b;
+type T;
+@@
+
+(
+- T tmp;
+|
+- T tmp = 0;
+|
+- T *tmp = NULL;
+)
+... when != tmp
+- tmp = a;
+- a = b;
+- b = tmp
++ swap(a, b)
+  ;
+... when != tmp
+
+@rp depends on patch@
+identifier tmp;
+expression a, b;
+@@
+
+- tmp = a;
+- a = b;
+- b = tmp
++ swap(a, b)
+  ;
+
+@depends on patch && (rpvar || rp)@
+@@
+
+(
+  for (...;...;...)
+- {
+   swap(...);
+- }
+|
+  while (...)
+- {
+   swap(...);
+- }
+|
+  if (...)
+- {
+   swap(...);
+- }
+)
+
+
+@script:python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for swap()")
+
+@script:python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for swap()")
+
+@script:python depends on report@
+p << rvar.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for swap()")
+
+@script:python depends on org@
+p << rvar.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for swap()")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] release of version 1.1.0

2021-02-27 Thread Denis Efremov



On 2/27/21 12:14 PM, Julia Lawall wrote:
> 
> 
> On Sat, 27 Feb 2021, Denis Efremov wrote:
> 
>> Hi,
>>
>> Great news!
>>
>> Could you please create release tag on GitHub?
>> This will allow me to add this version to tests and add new opam package 
>> version.
>> Currently, I use these versions for tests:
>> https://github.com/evdenis/cvehound/blob/master/.github/workflows/test.yml#L25
> 
> There is no tag at the moment.  I have asked why.
> 
>>
>> BTW, is there 1.0.9 version? I see that fedora provides 1.0.9 version,
>> but there is not release tag for it and there is no opam package for it.
> 
> No, there is no version 1.0.9.  We moved on to 1.1 due to the #spatch
> feature.
> 

Seems like there is a mess. There is a commit with 1.0.9 release planned:
https://github.com/coccinelle/coccinelle/commit/842075f77505386a782030ebffb1acf7f4237737#diff-652d5876e7e73c420820682a12ecdec66ecdec029223e24808e129d64493a967

Repology says that Fedora provides most recent coccinelle version:
https://repology.org/project/coccinelle/versions 
Other distibutives use 1.0.8 version.

On Fedora:
$ sudo dnf info coccinelle 
Installed Packages
Name : coccinelle
Version  : 1.0.9
Release  : 0.14.gitd0fd4c7d.fc33.1 // <== d0fd4c7d commit reference
Architecture : x86_64
Size : 26 M
Source   : coccinelle-1.0.9-0.14.gitd0fd4c7d.fc33.1.src.rpm

$ /usr/bin/spatch --version
spatch version 1.0.8-gc1dbb4f-dirty compiled with OCaml version 4.11.1
Flags passed to the configure script: --build=x86_64-redhat-linux-gnu 
--host=x86_64-redhat-linux-gnu --program-prefix= --disable-dependency-tracking 
--prefix=/usr --exec-prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin 
--sysconfdir=/etc --datadir=/usr/share --includedir=/usr/include 
--libdir=/usr/lib64 --libexecdir=/usr/libexec --localstatedir=/var 
--sharedstatedir=/var/lib --mandir=/usr/share/man --infodir=/usr/share/info 
--with-python=/usr/bin/python3 --with-menhir=/usr/bin/menhir
OCaml scripting support: yes
Python scripting support: yes
Syntax of regular expressions: PCRE

Fedora 33, 1.0.9 version points to commit:
$ fedpkg clone -a coccinelle
$ cd coccinelle
$ git checkout f33
$ cat coccinelle.spec | grep commit
%global commit d0fd4c7dfa70763870914eedee7022fa35f700e2
%global shortcommit d0fd4c7d

Fedora 34 also uses d0fd4c7d as base for 1.0.9 version.
Fedora 32 points to 111d328fee1303f14a5b9def835301d849e41331.

Maybe release 1.0.9 wasn't planned, but as my personal opinion adding 1.0.9 tag 
is not a bad idea
just to reference some commit (for example, d0fd4c7d) and have 1.0.9 version to 
run
backward compatibility tests on it.
https://github.com/coccinelle/coccinelle/releases

Thanks,
Denis

>>
>> On 2/27/21 11:11 AM, Julia Lawall wrote:
>>> A new version 1.1.0 has been released.  The most interesting change is the
>>> ability to put spatch command line options in a .cocci file, for example:
>>>
>>> #spatch --very-quiet -j 8 --recursive-includes --include-headers-for-types
>>>
>>> Other specific improvements are an improved handling of attributes and a
>>> more efficient treatment of header files (all thanks to Jaskaran Singh).
>>>
>>> Various other small issues have been addressed.
>>>
>>> All of these changes have already been available on github.
>>>
>>> julia
>>> ___
>>> Cocci mailing list
>>> Cocci@systeme.lip6.fr
>>> https://systeme.lip6.fr/mailman/listinfo/cocci
>>>
>> ___
>> Cocci mailing list
>> Cocci@systeme.lip6.fr
>> https://systeme.lip6.fr/mailman/listinfo/cocci
>>
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] release of version 1.1.0

2021-02-27 Thread Denis Efremov
Hi,

Great news!

Could you please create release tag on GitHub?
This will allow me to add this version to tests and add new opam package 
version.
Currently, I use these versions for tests:
https://github.com/evdenis/cvehound/blob/master/.github/workflows/test.yml#L25

BTW, is there 1.0.9 version? I see that fedora provides 1.0.9 version,
but there is not release tag for it and there is no opam package for it.

Thanks,
Denis

On 2/27/21 11:11 AM, Julia Lawall wrote:
> A new version 1.1.0 has been released.  The most interesting change is the
> ability to put spatch command line options in a .cocci file, for example:
> 
> #spatch --very-quiet -j 8 --recursive-includes --include-headers-for-types
> 
> Other specific improvements are an improved handling of attributes and a
> more efficient treatment of header files (all thanks to Jaskaran Singh).
> 
> Various other small issues have been addressed.
> 
> All of these changes have already been available on github.
> 
> julia
> ___
> Cocci mailing list
> Cocci@systeme.lip6.fr
> https://systeme.lip6.fr/mailman/listinfo/cocci
> 
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v2] coccinelle: misc: add swap script

2021-02-19 Thread Denis Efremov
Check for opencoded swap() implementation.

Signed-off-by: Denis Efremov 
---
Changes in v2:
 - additional patch rule to drop excessive {}
 - fix indentation in patch mode by anchoring ;

 scripts/coccinelle/misc/swap.cocci | 101 +
 1 file changed, 101 insertions(+)
 create mode 100644 scripts/coccinelle/misc/swap.cocci

diff --git a/scripts/coccinelle/misc/swap.cocci 
b/scripts/coccinelle/misc/swap.cocci
new file mode 100644
index ..d5da9888c222
--- /dev/null
+++ b/scripts/coccinelle/misc/swap.cocci
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Check for opencoded swap() implementation.
+///
+// Confidence: High
+// Copyright: (C) 2021 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+// Keywords: swap
+//
+
+virtual patch
+virtual org
+virtual report
+virtual context
+
+@r depends on !patch@
+identifier tmp;
+expression a, b;
+type T;
+position p;
+@@
+
+(
+* T tmp;
+|
+* T tmp = 0;
+|
+* T *tmp = NULL;
+)
+... when != tmp
+* tmp = a;
+* a = b;@p
+* b = tmp;
+... when != tmp
+
+@rpvar depends on patch@
+identifier tmp;
+expression a, b;
+type T;
+@@
+
+(
+- T tmp;
+|
+- T tmp = 0;
+|
+- T *tmp = NULL;
+)
+... when != tmp
+- tmp = a;
+- a = b;
+- b = tmp
++ swap(a, b)
+  ;
+... when != tmp
+
+
+@rp depends on patch@
+identifier tmp;
+expression a, b;
+@@
+
+- tmp = a;
+- a = b;
+- b = tmp
++ swap(a, b)
+  ;
+
+@depends on (rpvar || rp)@
+@@
+
+(
+  for (...;...;...)
+- {
+   swap(...);
+- }
+|
+  while (...)
+- {
+   swap(...);
+- }
+|
+  if (...)
+- {
+   swap(...);
+- }
+)
+
+
+@script:python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for swap()")
+
+@script:python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for swap()")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [PATCH v2] coccinelle: misc: add minmax script

2021-02-19 Thread Denis Efremov
Sorry for wrong thread, I'll resend v2 to the right one.

Denis

On 2/19/21 12:05 PM, Denis Efremov wrote:
> Check for opencoded min(), max() implementations.
> 
> Signed-off-by: Denis Efremov 
> ---
> 
> Changes in v2:
>  - <... ...> instead of ... when any
>  - org mode reports fixed
>  - patch rule to drop excessive ()
> 
>  scripts/coccinelle/misc/minmax.cocci | 224 +++
>  1 file changed, 224 insertions(+)
>  create mode 100644 scripts/coccinelle/misc/minmax.cocci
> 
> diff --git a/scripts/coccinelle/misc/minmax.cocci 
> b/scripts/coccinelle/misc/minmax.cocci
> new file mode 100644
> index ..61d6b61fd82c
> --- /dev/null
> +++ b/scripts/coccinelle/misc/minmax.cocci
> @@ -0,0 +1,224 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +///
> +/// Check for opencoded min(), max() implementations.
> +/// Generated patches sometimes require adding a cast to fix compile warning.
> +/// Warnings/patches scope intentionally limited to a function body.
> +///
> +// Confidence: Medium
> +// Copyright: (C) 2021 Denis Efremov ISPRAS
> +// Options: --no-includes --include-headers
> +//
> +// Keywords: min, max
> +//
> +
> +
> +virtual report
> +virtual org
> +virtual context
> +virtual patch
> +
> +@rmax depends on !patch@
> +identifier func;
> +expression x, y;
> +binary operator cmp = {>, >=};
> +position p;
> +@@
> +
> +func(...)
> +{
> + <...
> +*x cmp@p y ? x : y
> + ...>
> +}
> +
> +@rmaxif depends on !patch@
> +identifier func;
> +expression x, y;
> +expression max_val;
> +binary operator cmp = {>, >=};
> +position p;
> +@@
> +
> +func(...)
> +{
> + <...
> +*if (x cmp@p y) {
> +*max_val = x;
> +*} else {
> +*max_val = y;
> +*}
> + ...>
> +}
> +
> +@rmin depends on !patch@
> +identifier func;
> +expression x, y;
> +binary operator cmp = {<, <=};
> +position p;
> +@@
> +
> +func(...)
> +{
> + <...
> +*x cmp@p y ? x : y
> + ...>
> +}
> +
> +@rminif depends on !patch@
> +identifier func;
> +expression x, y;
> +expression min_val;
> +binary operator cmp = {<, <=};
> +position p;
> +@@
> +
> +func(...)
> +{
> + <...
> +*if (x cmp@p y) {
> +*min_val = x;
> +*} else {
> +*min_val = y;
> +*}
> + ...>
> +}
> +
> +@pmax depends on patch@
> +identifier func;
> +expression x, y;
> +binary operator cmp = {>=, >};
> +position p;
> +@@
> +
> +func@p(...)
> +{
> + <...
> +-x cmp y ? x : y
> ++max(x, y)
> + ...>
> +}
> +
> +@pmaxif depends on patch@
> +identifier func;
> +expression x, y;
> +expression max_val;
> +binary operator cmp = {>=, >};
> +position p;
> +@@
> +
> +func@p(...)
> +{
> + <...
> +-if (x cmp y) {
> +-max_val = x;
> +-} else {
> +-max_val = y;
> +-}
> ++max_val = max(x, y);
> + ...>
> +}
> +
> +@pmin depends on patch@
> +identifier func;
> +expression x, y;
> +binary operator cmp = {<=, <};
> +position p;
> +@@
> +
> +func@p(...)
> +{
> + <...
> +-x cmp y ? x : y
> ++min(x, y)
> + ...>
> +}
> +
> +@pminif depends on patch@
> +identifier func;
> +expression x, y;
> +expression min_val;
> +binary operator cmp = {<=, <};
> +position p;
> +@@
> +
> +func@p(...)
> +{
> + <...
> +-if (x cmp y) {
> +-min_val = x;
> +-} else {
> +-min_val = y;
> +-}
> ++min_val = min(x, y);
> + ...>
> +}
> +
> +@depends on (pmax || pmaxif || pmin || pminif)@
> +identifier func;
> +expression x, y;
> +position p;
> +// FIXME: Coccinelle consumes all available ram and
> +// and timeouts on every file.
> +// position p = { pmin.p, pminif.p, pmax.p, pmaxif.p };
> +@@
> +
> +func@p(...)
> +{
> + <...
> +(
> +-(min((x), (y)))
> ++min(x, y)
> +|
> +-(max((x), (y)))
> ++max(x, y)
> +)
> + ...>
> +}
> +
> +@script:python depends on report@
> +p << rmax.p;
> +@@
> +
> +coccilib.report.print_report(p[0], "WARNING opportunity for max()")
> +
> +@script:python depends on org@
> +p << rmax.p;
> +@@
> +
> +coccilib.org.print_todo(p[0], "WARNING opportunity for max()")
> +
> +@script:python depends on report@
> +p << rmaxif.p;
> +@@
> +
> +coccilib.report.print_report(p[0], "

[Cocci] [PATCH v2 RESEND] coccinelle: misc: add minmax script

2021-02-19 Thread Denis Efremov
Check for opencoded min(), max() implementations.

Signed-off-by: Denis Efremov 
---

Changes in v2:
 - <... ...> instead of ... when any
 - org mode reports fixed
 - patch rule to drop excessive ()

 scripts/coccinelle/misc/minmax.cocci | 224 +++
 1 file changed, 224 insertions(+)
 create mode 100644 scripts/coccinelle/misc/minmax.cocci

diff --git a/scripts/coccinelle/misc/minmax.cocci 
b/scripts/coccinelle/misc/minmax.cocci
new file mode 100644
index ..61d6b61fd82c
--- /dev/null
+++ b/scripts/coccinelle/misc/minmax.cocci
@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Check for opencoded min(), max() implementations.
+/// Generated patches sometimes require adding a cast to fix compile warning.
+/// Warnings/patches scope intentionally limited to a function body.
+///
+// Confidence: Medium
+// Copyright: (C) 2021 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+// Keywords: min, max
+//
+
+
+virtual report
+virtual org
+virtual context
+virtual patch
+
+@rmax depends on !patch@
+identifier func;
+expression x, y;
+binary operator cmp = {>, >=};
+position p;
+@@
+
+func(...)
+{
+   <...
+*  x cmp@p y ? x : y
+   ...>
+}
+
+@rmaxif depends on !patch@
+identifier func;
+expression x, y;
+expression max_val;
+binary operator cmp = {>, >=};
+position p;
+@@
+
+func(...)
+{
+   <...
+*  if (x cmp@p y) {
+*  max_val = x;
+*  } else {
+*  max_val = y;
+*  }
+   ...>
+}
+
+@rmin depends on !patch@
+identifier func;
+expression x, y;
+binary operator cmp = {<, <=};
+position p;
+@@
+
+func(...)
+{
+   <...
+*  x cmp@p y ? x : y
+   ...>
+}
+
+@rminif depends on !patch@
+identifier func;
+expression x, y;
+expression min_val;
+binary operator cmp = {<, <=};
+position p;
+@@
+
+func(...)
+{
+   <...
+*  if (x cmp@p y) {
+*  min_val = x;
+*  } else {
+*  min_val = y;
+*  }
+   ...>
+}
+
+@pmax depends on patch@
+identifier func;
+expression x, y;
+binary operator cmp = {>=, >};
+position p;
+@@
+
+func@p(...)
+{
+   <...
+-  x cmp y ? x : y
++  max(x, y)
+   ...>
+}
+
+@pmaxif depends on patch@
+identifier func;
+expression x, y;
+expression max_val;
+binary operator cmp = {>=, >};
+position p;
+@@
+
+func@p(...)
+{
+   <...
+-  if (x cmp y) {
+-  max_val = x;
+-  } else {
+-  max_val = y;
+-  }
++  max_val = max(x, y);
+   ...>
+}
+
+@pmin depends on patch@
+identifier func;
+expression x, y;
+binary operator cmp = {<=, <};
+position p;
+@@
+
+func@p(...)
+{
+   <...
+-  x cmp y ? x : y
++  min(x, y)
+   ...>
+}
+
+@pminif depends on patch@
+identifier func;
+expression x, y;
+expression min_val;
+binary operator cmp = {<=, <};
+position p;
+@@
+
+func@p(...)
+{
+   <...
+-  if (x cmp y) {
+-  min_val = x;
+-  } else {
+-  min_val = y;
+-  }
++  min_val = min(x, y);
+   ...>
+}
+
+@depends on (pmax || pmaxif || pmin || pminif)@
+identifier func;
+expression x, y;
+position p;
+// FIXME: Coccinelle consumes all available ram and
+// and timeouts on every file.
+// position p = { pmin.p, pminif.p, pmax.p, pmaxif.p };
+@@
+
+func@p(...)
+{
+   <...
+(
+-  (min((x), (y)))
++  min(x, y)
+|
+-  (max((x), (y)))
++  max(x, y)
+)
+   ...>
+}
+
+@script:python depends on report@
+p << rmax.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for max()")
+
+@script:python depends on org@
+p << rmax.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for max()")
+
+@script:python depends on report@
+p << rmaxif.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for max()")
+
+@script:python depends on org@
+p << rmaxif.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for max()")
+
+@script:python depends on report@
+p << rmin.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for min()")
+
+@script:python depends on org@
+p << rmin.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for min()")
+
+@script:python depends on report@
+p << rminif.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for min()")
+
+@script:python depends on org@
+p << rminif.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for min()")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v2] coccinelle: misc: add minmax script

2021-02-19 Thread Denis Efremov
Check for opencoded min(), max() implementations.

Signed-off-by: Denis Efremov 
---

Changes in v2:
 - <... ...> instead of ... when any
 - org mode reports fixed
 - patch rule to drop excessive ()

 scripts/coccinelle/misc/minmax.cocci | 224 +++
 1 file changed, 224 insertions(+)
 create mode 100644 scripts/coccinelle/misc/minmax.cocci

diff --git a/scripts/coccinelle/misc/minmax.cocci 
b/scripts/coccinelle/misc/minmax.cocci
new file mode 100644
index ..61d6b61fd82c
--- /dev/null
+++ b/scripts/coccinelle/misc/minmax.cocci
@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Check for opencoded min(), max() implementations.
+/// Generated patches sometimes require adding a cast to fix compile warning.
+/// Warnings/patches scope intentionally limited to a function body.
+///
+// Confidence: Medium
+// Copyright: (C) 2021 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+// Keywords: min, max
+//
+
+
+virtual report
+virtual org
+virtual context
+virtual patch
+
+@rmax depends on !patch@
+identifier func;
+expression x, y;
+binary operator cmp = {>, >=};
+position p;
+@@
+
+func(...)
+{
+   <...
+*  x cmp@p y ? x : y
+   ...>
+}
+
+@rmaxif depends on !patch@
+identifier func;
+expression x, y;
+expression max_val;
+binary operator cmp = {>, >=};
+position p;
+@@
+
+func(...)
+{
+   <...
+*  if (x cmp@p y) {
+*  max_val = x;
+*  } else {
+*  max_val = y;
+*  }
+   ...>
+}
+
+@rmin depends on !patch@
+identifier func;
+expression x, y;
+binary operator cmp = {<, <=};
+position p;
+@@
+
+func(...)
+{
+   <...
+*  x cmp@p y ? x : y
+   ...>
+}
+
+@rminif depends on !patch@
+identifier func;
+expression x, y;
+expression min_val;
+binary operator cmp = {<, <=};
+position p;
+@@
+
+func(...)
+{
+   <...
+*  if (x cmp@p y) {
+*  min_val = x;
+*  } else {
+*  min_val = y;
+*  }
+   ...>
+}
+
+@pmax depends on patch@
+identifier func;
+expression x, y;
+binary operator cmp = {>=, >};
+position p;
+@@
+
+func@p(...)
+{
+   <...
+-  x cmp y ? x : y
++  max(x, y)
+   ...>
+}
+
+@pmaxif depends on patch@
+identifier func;
+expression x, y;
+expression max_val;
+binary operator cmp = {>=, >};
+position p;
+@@
+
+func@p(...)
+{
+   <...
+-  if (x cmp y) {
+-  max_val = x;
+-  } else {
+-  max_val = y;
+-  }
++  max_val = max(x, y);
+   ...>
+}
+
+@pmin depends on patch@
+identifier func;
+expression x, y;
+binary operator cmp = {<=, <};
+position p;
+@@
+
+func@p(...)
+{
+   <...
+-  x cmp y ? x : y
++  min(x, y)
+   ...>
+}
+
+@pminif depends on patch@
+identifier func;
+expression x, y;
+expression min_val;
+binary operator cmp = {<=, <};
+position p;
+@@
+
+func@p(...)
+{
+   <...
+-  if (x cmp y) {
+-  min_val = x;
+-  } else {
+-  min_val = y;
+-  }
++  min_val = min(x, y);
+   ...>
+}
+
+@depends on (pmax || pmaxif || pmin || pminif)@
+identifier func;
+expression x, y;
+position p;
+// FIXME: Coccinelle consumes all available ram and
+// and timeouts on every file.
+// position p = { pmin.p, pminif.p, pmax.p, pmaxif.p };
+@@
+
+func@p(...)
+{
+   <...
+(
+-  (min((x), (y)))
++  min(x, y)
+|
+-  (max((x), (y)))
++  max(x, y)
+)
+   ...>
+}
+
+@script:python depends on report@
+p << rmax.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for max()")
+
+@script:python depends on org@
+p << rmax.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for max()")
+
+@script:python depends on report@
+p << rmaxif.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for max()")
+
+@script:python depends on org@
+p << rmaxif.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for max()")
+
+@script:python depends on report@
+p << rmin.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for min()")
+
+@script:python depends on org@
+p << rmin.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for min()")
+
+@script:python depends on report@
+p << rminif.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for min()")
+
+@script:python depends on org@
+p << rminif.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for min()")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [PATCH] coccinelle: misc: add swap script

2021-02-18 Thread Denis Efremov



On 2/18/21 2:29 PM, Julia Lawall wrote:
> 
> 
> On Thu, 18 Feb 2021, Denis Efremov wrote:
> 
>>
>>
>> On 2/18/21 1:17 PM, Julia Lawall wrote:
>>>
>>>
>>> On Thu, 18 Feb 2021, Denis Efremov wrote:
>>>
>>>>
>>>>
>>>> On 2/18/21 12:31 AM, Julia Lawall wrote:
>>>>>> +@depends on patch@
>>>>>> +identifier tmp;
>>>>>> +expression a, b;
>>>>>> +type T;
>>>>>> +@@
>>>>>> +
>>>>>> +(
>>>>>> +- T tmp;
>>>>>> +|
>>>>>> +- T tmp = 0;
>>>>>> +|
>>>>>> +- T *tmp = NULL;
>>>>>> +)
>>>>>> +... when != tmp
>>>>>> +- tmp = a;
>>>>>> +- a = b;
>>>>>> +- b = tmp;
>>>>>> ++ swap(a, b);
>>>>>> +... when != tmp
>>>>>
>>>>> In this rule and the next one, if you remove the final ; from the b = tmp
>>>>> line and from the swap line, and put it into context code afterwards, them
>>>>> the generated code looks better on cases like fs/xfs/xfs_inode.c in the
>>>>> function xfs_lock_two_inodes where two successive swap calls are
>>>>> generated.
>>>>>
>>>>> There are also some cases such as drivers/net/wireless/ath/ath5k/phy.c in
>>>>> the function ath5k_hw_get_median_noise_floor where the swap code makes up
>>>>> a whole if branch.
>>>>
>>>>> In this cases it would be good to remove the {}.
>>>>
>>>> How this can be handled?
>>>>
>>>> If I use this pattern:
>>>> @depends on patch@
>>>> identifier tmp;
>>>> expression a, b;
>>>> @@
>>>>
>>>> (
>>>>   if (...)
>>>> - {
>>>> -   tmp = a;
>>>> -   a = b;
>>>> -   b = tmp
>>>> +   swap(a, b)
>>>> ;
>>>> - }
>>>> |
>>>> -   tmp = a;
>>>> -   a = b;
>>>> -   b = tmp
>>>> +   swap(a, b)
>>>> ;
>>>> )
>>>>
>>>> The tool fails with error:
>>>>
>>>> EXN: Failure("rule starting on line 58: already tagged token:\nC code
>>>> context\nFile \"drivers/net/wireless/ath/ath5k/phy.c\", line 1574,
>>>> column 4, charpos = 41650\n around = 'sort',\n whole content =
>>>> \t\t\t\tsort[j - 1] = tmp;") in drivers/net/wireless/ath/ath5k/phy.c
>>>
>>> A disjunction basically says "at this node in the cfg, can I match the
>>> first patter, or can I match the second pattern, etc."  Unfortunately in
>>> this case the two branches start matching at different nodes, so the short
>>> circuit aspect of a disjunction isn't used, and it matches both patterns.
>>>
>>> The solution is to just make two rules.  The first for the if case and the
>>> second for everything else.
>>>
>>
>>   if (...)
>> - {
>> -   tmp = a;
>> -   a = b;
>> -   b = tmp
>> +   swap(a, b)
>> ;
>> - }
>>
>>
>> This produces "single-line ifs".
>> Maybe generated patches can be improved somehow?
>> Moving -+; doesn't help in this case.
> 
> There is clearly some problem with the management of newlines...
> 
> The other alternative is to just have one rule for introducing swap and
> another for removing the braces around a swap, ie
> 
> if (...)
> - {
>   swap(...);
> - }
> 
> I don't think it would be motivated to remove the newline in that case.

Yes, this works. I'll send v2.

Thanks
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH] coccinelle: misc: add swap script

2021-02-16 Thread Denis Efremov
Check for opencoded swap() implementation.

Signed-off-by: Denis Efremov 
---
 scripts/coccinelle/misc/swap.cocci | 77 ++
 1 file changed, 77 insertions(+)
 create mode 100644 scripts/coccinelle/misc/swap.cocci

diff --git a/scripts/coccinelle/misc/swap.cocci 
b/scripts/coccinelle/misc/swap.cocci
new file mode 100644
index ..38227a5d0855
--- /dev/null
+++ b/scripts/coccinelle/misc/swap.cocci
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Check for opencoded swap() implementation.
+///
+// Confidence: High
+// Copyright: (C) 2021 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+// Keywords: swap
+//
+
+virtual patch
+virtual org
+virtual report
+virtual context
+
+@r depends on !patch@
+identifier tmp;
+expression a, b;
+type T;
+position p;
+@@
+
+(
+* T tmp;
+|
+* T tmp = 0;
+|
+* T *tmp = NULL;
+)
+... when != tmp
+* tmp = a;
+* a = b;@p
+* b = tmp;
+... when != tmp
+
+@depends on patch@
+identifier tmp;
+expression a, b;
+type T;
+@@
+
+(
+- T tmp;
+|
+- T tmp = 0;
+|
+- T *tmp = NULL;
+)
+... when != tmp
+- tmp = a;
+- a = b;
+- b = tmp;
++ swap(a, b);
+... when != tmp
+
+@depends on patch@
+identifier tmp;
+expression a, b;
+@@
+
+- tmp = a;
+- a = b;
+- b = tmp;
++ swap(a, b);
+
+@script:python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for swap()")
+
+@script:python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for swap()")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] Problem with partial patch generation

2021-02-15 Thread Denis Efremov



On 2/15/21 2:47 PM, Julia Lawall wrote:
> 
> 
> On Mon, 15 Feb 2021, Denis Efremov wrote:
> 
>> Hi,
>>
>> I wrote a simple rule (swap.cocci):
>>
>> virtual patch
>>
>> @depends on patch@
>> identifier tmp;
>> expression a, b;
>> type T;
>> @@
>>
>> (
>> - T tmp;
>> |
>> - T tmp = 0;
>> |
>> - T *tmp = NULL;
>> )
>> ... when != tmp
>> - tmp = a;
>> - a = b;
>> - b = tmp;
>> + swap(a, b);
>> ... when != tmp
>>
>> I would expect it to remove a local variable only if there is a match
>> with swap template.
>>
>> However, it generates "partial" patch on 5.11 linux code:
>> $ spatch --version
>> spatch version 1.0.8-00201-g267f9cf8cc82 compiled with OCaml version 4.11.1
>> $ spatch -D patch --sp-file swap.cocci mm/filemap.c
>> --- mm/filemap.c
>> +++ /tmp/cocci-output-445786-88aa66-filemap.c
>> @@ -2348,7 +2348,7 @@ static int generic_file_buffered_read_ge
>> struct file_ra_state *ra = >f_ra;
>> pgoff_t index = iocb->ki_pos >> PAGE_SHIFT;
>> pgoff_t last_index = (iocb->ki_pos + iter->count + PAGE_SIZE-1) >> 
>> PAGE_SHIFT;
>> -   int i, j, nr_got, err = 0;
>> +   int i, nr_got, err = 0;
>>
>> nr = min_t(unsigned long, last_index - index, nr);
>>  find_page:
>>
>> How can I improve the rule?
> 
> I don't get a match with the latest version of Coccinelle.
> 
> If the latest version of Coccinelle were to become a release, would that
> be good enough for you?  Or do you need 1.0.8 to work as well?

I planned to submit the swap rule to scripts/coccinelle. However, I can
create more strict pattern for the patch mode. Maybe adding "when strict"
is suitable here?
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] Problem with partial patch generation

2021-02-15 Thread Denis Efremov
Hi,

I wrote a simple rule (swap.cocci):

virtual patch

@depends on patch@
identifier tmp;
expression a, b;
type T;
@@

(
- T tmp;
|
- T tmp = 0;
|
- T *tmp = NULL;
)
... when != tmp
- tmp = a;
- a = b;
- b = tmp;
+ swap(a, b);
... when != tmp

I would expect it to remove a local variable only if there is a match
with swap template.

However, it generates "partial" patch on 5.11 linux code:
$ spatch --version
spatch version 1.0.8-00201-g267f9cf8cc82 compiled with OCaml version 4.11.1
$ spatch -D patch --sp-file swap.cocci mm/filemap.c
--- mm/filemap.c
+++ /tmp/cocci-output-445786-88aa66-filemap.c
@@ -2348,7 +2348,7 @@ static int generic_file_buffered_read_ge
struct file_ra_state *ra = >f_ra;
pgoff_t index = iocb->ki_pos >> PAGE_SHIFT;
pgoff_t last_index = (iocb->ki_pos + iter->count + PAGE_SIZE-1) >> 
PAGE_SHIFT;
-   int i, j, nr_got, err = 0;
+   int i, nr_got, err = 0;
 
nr = min_t(unsigned long, last_index - index, nr);
 find_page:

How can I improve the rule?

Thanks,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] Backward compatibility issue

2021-02-12 Thread Denis Efremov



On 2/12/21 5:04 PM, Julia Lawall wrote:
> 
> 
> On Thu, 11 Feb 2021, Denis Efremov wrote:
> 
>> Hi, one of my patterns started to fail tests on latest coccinelle.
>> I've bisected the commit that introduces "error". It's:
>> commit db60e916633d2cb3ae31140364783fdf85ed10f4
>> "make information about SmPL iterator and declarer names available to the C 
>> parser"
>>
>> To reproduce the error:
>> $ cd linux
>> $ git checkout 5b01014759991887b1e450c9def01e58c02ab81b
>> $ wget 
>> https://raw.githubusercontent.com/evdenis/cvehound/master/cvehound/cve/CVE-2016-9793.cocci
>> $ spatch -D detect --cocci-file CVE-2016-9793.cocci net/core/sock.c
>> # spatch before db60e916633d2cb3ae31140364783fdf85ed10f4 will find the match
>> net/core/sock.c:718:16-17: ERROR: CVE-2016-9793
>> net/core/sock.c:754:16-17: ERROR: CVE-2016-9793
>> ...
>> # spatch >= db60e916633d2cb3ae31140364783fdf85ed10f4 will not match the same 
>> code
> 
> If you change typedef u32 to symbol u32, it should be good.  It is no use
> to Coccinelle to know that u32 is a typedef in this code.

After changing typedef to symbol, git version starts to match the code,
but coccinelle 1.0.8 starts to fail the detection. Well, this doesn't
solve the problem for me.

What's the difference between symbol and typedef? How can I understand
when to use one or another?

Thanks,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] Backward compatibility issue

2021-02-11 Thread Denis Efremov
Hi, one of my patterns started to fail tests on latest coccinelle.
I've bisected the commit that introduces "error". It's:
commit db60e916633d2cb3ae31140364783fdf85ed10f4
"make information about SmPL iterator and declarer names available to the C 
parser"

To reproduce the error:
$ cd linux
$ git checkout 5b01014759991887b1e450c9def01e58c02ab81b
$ wget 
https://raw.githubusercontent.com/evdenis/cvehound/master/cvehound/cve/CVE-2016-9793.cocci
$ spatch -D detect --cocci-file CVE-2016-9793.cocci net/core/sock.c
# spatch before db60e916633d2cb3ae31140364783fdf85ed10f4 will find the match
net/core/sock.c:718:16-17: ERROR: CVE-2016-9793
net/core/sock.c:754:16-17: ERROR: CVE-2016-9793
...
# spatch >= db60e916633d2cb3ae31140364783fdf85ed10f4 will not match the same 
code

Thanks,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] How to match switch cases and their absence with coccinelle?

2021-01-12 Thread Denis Efremov



On 1/12/21 7:13 PM, Julia Lawall wrote:
> 
> 
> On Tue, 12 Jan 2021, Denis Efremov wrote:
> 
>> Hi,
>>
>> Let's suppose I have this pattern:
>> @fix exists@
>> position p;
>> @@
>>
>> binder_release_work(...)
>> {
>>  ...
>>  switch (...) {
>> *case BINDER_WORK_NODE: ... break;@p
>>  }
>>  ...
> 
> Add when any to the outer ...s

Thanks, this helped.

> 
>> }
>>
>> and I want to match binder_release_work() function in 
>> drivers/android/binder.c
>> file (linux kernel, master)
>>
>> Seems like the rule is not enough, it gives nothing:
>> $ spatch --cocci-file binder.cocci drivers/android/binder.c
>> init_defs_builtins: /usr/lib64/coccinelle/standard.h
>> HANDLING: drivers/android/binder.c
>>
>> 1) What can I do to reliable check that there is a special case in a switch?
>> 2) Is it possible to check that there is no case handling with something 
>> like:
>>  switch (...) {
>>  ... when != case BINDER_WORK_NODE: ... break;
>>  }
> 
> I don't know if that will work.  But you can do it with two rules.  In the
> first rule, you could put a position variable on the switch, and then in
> the second rule, you could make a position variable that is required to be
> different than the first one, and that is also attached to a switch.

Yes, I use this method currently.

Also I faced the problem when I can't use ... in the beginning of enum, i.e.:
struct binder_work {
...
enum binder_work_type {
... // <== will not work
*   BINDER_WORK_NODE,
...
} type;
...
}

This works:
struct binder_work {
...
enum binder_work_type {
// BINDER_WORK_TRANSACTION = ..., // also will not work
BINDER_WORK_TRANSACTION = 1,
BINDER_WORK_TRANSACTION_COMPLETE,
BINDER_WORK_RETURN_ERROR,
*   BINDER_WORK_NODE,
...
} type;
...
}

Thanks,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] How to match switch cases and their absence with coccinelle?

2021-01-12 Thread Denis Efremov
Hi,

Let's suppose I have this pattern:
@fix exists@
position p;
@@

binder_release_work(...)
{
...
switch (...) {
*   case BINDER_WORK_NODE: ... break;@p
}
...
}

and I want to match binder_release_work() function in drivers/android/binder.c
file (linux kernel, master)

Seems like the rule is not enough, it gives nothing:
$ spatch --cocci-file binder.cocci drivers/android/binder.c
init_defs_builtins: /usr/lib64/coccinelle/standard.h
HANDLING: drivers/android/binder.c

1) What can I do to reliable check that there is a special case in a switch?
2) Is it possible to check that there is no case handling with something like:
switch (...) {
... when != case BINDER_WORK_NODE: ... break;
}

Thanks,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] How to match function-like macro calls, e.g. RTA_ALIGN(rta->rta_len)?

2021-01-11 Thread Denis Efremov



On 1/11/21 11:59 PM, Julia Lawall wrote:
> 
> 
> On Mon, 11 Jan 2021, Denis Efremov wrote:
> 
>>
>>
>> On 1/11/21 11:40 PM, Julia Lawall wrote:
>>>
>>>
>>> On Mon, 11 Jan 2021, Denis Efremov wrote:
>>>
>>>>
>>>>
>>>> On 1/11/21 11:23 PM, Julia Lawall wrote:
>>>>>
>>>>>
>>>>> On Mon, 11 Jan 2021, Denis Efremov wrote:
>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> Let's suppose I want to match otx_cpt_aead_cbc_aes_sha_setkey() function 
>>>>>> from
>>>>>> drivers/crypto/marvell/octeontx/otx_cptvf_algs.c file (linux kernel).
>>>>>>
>>>>>> My pattern:
>>>>>> @exists@
>>>>>> identifier rta, param, key, keylen;
>>>>>> position p;
>>>>>> @@
>>>>>>
>>>>>> otx_cpt_aead_cbc_aes_sha_setkey(...,
>>>>>>  unsigned char *key, unsigned int keylen)
>>>>>> {
>>>>>>  ...
>>>>>> *if (RTA_PAYLOAD(rta) < sizeof(*param))@p
>>>>>>  goto badkey;
>>>>>>  ...
>>>>>> *key += RTA_ALIGN(rta->rta_len);
>>>>>> *keylen -= RTA_ALIGN(rta->rta_len);
>>>>>>  ...
>>>>>> }
>>>>>>
>>>>>> $ spatch --no-includes --include-headers --cocci-file test.cocci 
>>>>>> drivers/crypto/marvell/octeontx/otx_cptvf_algs.c
>>>>>> init_defs_builtins: /usr/lib64/coccinelle/standard.h
>>>>>> minus: parse error:
>>>>>>   File "test.cocci", line 13, column 9, charpos = 219
>>>>>>   around = 'RTA_ALIGN',
>>>>>>   whole content = * key += RTA_ALIGN(rta->rta_len);
>>>>>>
>>>>>>
>>>>>> What can I do to match RTA_ALIGN(...) lines?
>>>>>
>>>>> I don't understand the problem.  I took your rule and your command line,
>>>>> and everything was fine.
>>>>
>>>> I use version:
>>>> spatch version 1.0.8-gc1dbb4f-dirty compiled with OCaml version 4.11.1
>>>> Flags passed to the configure script: --build=x86_64-redhat-linux-gnu 
>>>> --host=x86_64-redhat-linux-gnu --program-prefix= 
>>>> --disable-dependency-tracking --prefix=/usr --exec-prefix=/usr 
>>>> --bindir=/usr/bin --sbindir=/usr/sbin --sysconfdir=/etc 
>>>> --datadir=/usr/share --includedir=/usr/include --libdir=/usr/lib64 
>>>> --libexecdir=/usr/libexec --localstatedir=/var --sharedstatedir=/var/lib 
>>>> --mandir=/usr/share/man --infodir=/usr/share/info 
>>>> --with-python=/usr/bin/python3 --with-menhir=/usr/bin/menhir
>>>> OCaml scripting support: yes
>>>> Python scripting support: yes
>>>> Syntax of regular expressions: PCRE
>>>>
>>>> Maybe parsing error is fixed in new versions?
>>>
>>> I can't imagine what would cause a parsing error here.  I don't see what
>>> could be special about RTA_ALIGN.  Normally Coccinelle doesn't even know
>>> that it is a macro.  Maybe you can try to simplify the semantic patch a
>>> little bit and see if there is some change that causes the problem to
>>> disappear?  Does the problem disappear if you use a name other than
>>> RTA_ALIGN?
>>
>> Changing:
>>  key += RTA_ALIGN(rta->rta_len);
>> to:
>>  key = RTA_ALIGN(rta->rta_len);
>>
>> makes the parsing error disappear.
>>
>> Using aop instead of += leads to the same parsing error:
>> assignment operator aop;
>> key aop RTA_ALIGN(rta->rta_len);
>> init_defs_builtins: /usr/lib64/coccinelle/standard.h
>> minus: parse error:
>>   File "test.cocci", line 14, column 10, charpos = 245
>>   around = 'RTA_ALIGN',
>>   whole content = * key aop RTA_ALIGN(rta->rta_len);
> 
> I assume not, but does spatch --parse-cocci test.cocci work?

Works with "key =" pattern, with "key +=" or "key aop" doesn't.
The errors are the same:
spatch --parse-cocci test.cocci 
init_defs_builtins: /usr/lib64/coccinelle/standard.h
minus: parse error: 
  File "test.cocci", line 13, column 9, charpos = 219
  around = 'RTA_ALIGN',
  whole content = * key += RTA_ALIGN(rta->rta_len);

Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] How to match function-like macro calls, e.g. RTA_ALIGN(rta->rta_len)?

2021-01-11 Thread Denis Efremov



On 1/11/21 11:40 PM, Julia Lawall wrote:
> 
> 
> On Mon, 11 Jan 2021, Denis Efremov wrote:
> 
>>
>>
>> On 1/11/21 11:23 PM, Julia Lawall wrote:
>>>
>>>
>>> On Mon, 11 Jan 2021, Denis Efremov wrote:
>>>
>>>> Hi,
>>>>
>>>> Let's suppose I want to match otx_cpt_aead_cbc_aes_sha_setkey() function 
>>>> from
>>>> drivers/crypto/marvell/octeontx/otx_cptvf_algs.c file (linux kernel).
>>>>
>>>> My pattern:
>>>> @exists@
>>>> identifier rta, param, key, keylen;
>>>> position p;
>>>> @@
>>>>
>>>> otx_cpt_aead_cbc_aes_sha_setkey(...,
>>>>unsigned char *key, unsigned int keylen)
>>>> {
>>>>...
>>>> *  if (RTA_PAYLOAD(rta) < sizeof(*param))@p
>>>>goto badkey;
>>>>...
>>>> *  key += RTA_ALIGN(rta->rta_len);
>>>> *  keylen -= RTA_ALIGN(rta->rta_len);
>>>>...
>>>> }
>>>>
>>>> $ spatch --no-includes --include-headers --cocci-file test.cocci 
>>>> drivers/crypto/marvell/octeontx/otx_cptvf_algs.c
>>>> init_defs_builtins: /usr/lib64/coccinelle/standard.h
>>>> minus: parse error:
>>>>   File "test.cocci", line 13, column 9, charpos = 219
>>>>   around = 'RTA_ALIGN',
>>>>   whole content = * key += RTA_ALIGN(rta->rta_len);
>>>>
>>>>
>>>> What can I do to match RTA_ALIGN(...) lines?
>>>
>>> I don't understand the problem.  I took your rule and your command line,
>>> and everything was fine.
>>
>> I use version:
>> spatch version 1.0.8-gc1dbb4f-dirty compiled with OCaml version 4.11.1
>> Flags passed to the configure script: --build=x86_64-redhat-linux-gnu 
>> --host=x86_64-redhat-linux-gnu --program-prefix= 
>> --disable-dependency-tracking --prefix=/usr --exec-prefix=/usr 
>> --bindir=/usr/bin --sbindir=/usr/sbin --sysconfdir=/etc --datadir=/usr/share 
>> --includedir=/usr/include --libdir=/usr/lib64 --libexecdir=/usr/libexec 
>> --localstatedir=/var --sharedstatedir=/var/lib --mandir=/usr/share/man 
>> --infodir=/usr/share/info --with-python=/usr/bin/python3 
>> --with-menhir=/usr/bin/menhir
>> OCaml scripting support: yes
>> Python scripting support: yes
>> Syntax of regular expressions: PCRE
>>
>> Maybe parsing error is fixed in new versions?
> 
> I can't imagine what would cause a parsing error here.  I don't see what
> could be special about RTA_ALIGN.  Normally Coccinelle doesn't even know
> that it is a macro.  Maybe you can try to simplify the semantic patch a
> little bit and see if there is some change that causes the problem to
> disappear?  Does the problem disappear if you use a name other than
> RTA_ALIGN?

Changing:
key += RTA_ALIGN(rta->rta_len);
to:
key = RTA_ALIGN(rta->rta_len);

makes the parsing error disappear.

Using aop instead of += leads to the same parsing error:
assignment operator aop;
key aop RTA_ALIGN(rta->rta_len);
init_defs_builtins: /usr/lib64/coccinelle/standard.h
minus: parse error: 
  File "test.cocci", line 14, column 10, charpos = 245
  around = 'RTA_ALIGN',
  whole content = * key aop RTA_ALIGN(rta->rta_len);

Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] How to match function-like macro calls, e.g. RTA_ALIGN(rta->rta_len)?

2021-01-11 Thread Denis Efremov



On 1/11/21 11:23 PM, Julia Lawall wrote:
> 
> 
> On Mon, 11 Jan 2021, Denis Efremov wrote:
> 
>> Hi,
>>
>> Let's suppose I want to match otx_cpt_aead_cbc_aes_sha_setkey() function from
>> drivers/crypto/marvell/octeontx/otx_cptvf_algs.c file (linux kernel).
>>
>> My pattern:
>> @exists@
>> identifier rta, param, key, keylen;
>> position p;
>> @@
>>
>> otx_cpt_aead_cbc_aes_sha_setkey(...,
>>  unsigned char *key, unsigned int keylen)
>> {
>>  ...
>> *if (RTA_PAYLOAD(rta) < sizeof(*param))@p
>>  goto badkey;
>>  ...
>> *key += RTA_ALIGN(rta->rta_len);
>> *keylen -= RTA_ALIGN(rta->rta_len);
>>  ...
>> }
>>
>> $ spatch --no-includes --include-headers --cocci-file test.cocci 
>> drivers/crypto/marvell/octeontx/otx_cptvf_algs.c
>> init_defs_builtins: /usr/lib64/coccinelle/standard.h
>> minus: parse error:
>>   File "test.cocci", line 13, column 9, charpos = 219
>>   around = 'RTA_ALIGN',
>>   whole content = * key += RTA_ALIGN(rta->rta_len);
>>
>>
>> What can I do to match RTA_ALIGN(...) lines?
> 
> I don't understand the problem.  I took your rule and your command line,
> and everything was fine.

I use version:
spatch version 1.0.8-gc1dbb4f-dirty compiled with OCaml version 4.11.1
Flags passed to the configure script: --build=x86_64-redhat-linux-gnu 
--host=x86_64-redhat-linux-gnu --program-prefix= --disable-dependency-tracking 
--prefix=/usr --exec-prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin 
--sysconfdir=/etc --datadir=/usr/share --includedir=/usr/include 
--libdir=/usr/lib64 --libexecdir=/usr/libexec --localstatedir=/var 
--sharedstatedir=/var/lib --mandir=/usr/share/man --infodir=/usr/share/info 
--with-python=/usr/bin/python3 --with-menhir=/usr/bin/menhir
OCaml scripting support: yes
Python scripting support: yes
Syntax of regular expressions: PCRE

Maybe parsing error is fixed in new versions?

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] How to match function-like macro calls, e.g. RTA_ALIGN(rta->rta_len)?

2021-01-11 Thread Denis Efremov
Hi,

Let's suppose I want to match otx_cpt_aead_cbc_aes_sha_setkey() function from
drivers/crypto/marvell/octeontx/otx_cptvf_algs.c file (linux kernel).

My pattern:
@exists@
identifier rta, param, key, keylen;
position p;
@@

otx_cpt_aead_cbc_aes_sha_setkey(...,
unsigned char *key, unsigned int keylen)
{
...
*   if (RTA_PAYLOAD(rta) < sizeof(*param))@p
goto badkey;
...
*   key += RTA_ALIGN(rta->rta_len);
*   keylen -= RTA_ALIGN(rta->rta_len);
...
}

$ spatch --no-includes --include-headers --cocci-file test.cocci 
drivers/crypto/marvell/octeontx/otx_cptvf_algs.c
init_defs_builtins: /usr/lib64/coccinelle/standard.h
minus: parse error: 
  File "test.cocci", line 13, column 9, charpos = 219
  around = 'RTA_ALIGN',
  whole content = * key += RTA_ALIGN(rta->rta_len);


What can I do to match RTA_ALIGN(...) lines?

Thanks,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v8] coccinelle: api: add kfree_mismatch script

2020-10-16 Thread Denis Efremov
Check that alloc and free types of functions match each other.

Signed-off-by: Denis Efremov 
---
Changes in v2:
 - Lines are limited to 80 characters where possible
 - Confidence changed from High to Medium because of 
   fs/btrfs/send.c:1119 false-positive
 - __vmalloc_area_node() explicitly excluded from analysis
   instead of !(file in "mm/vmalloc.c") condition
Changes in v3:
 - prints style in org && report modes changed for python2
Changes in v4:
 - missing msg argument to print_todo fixed
Changes in v5:
 - fix position p in kfree rule
 - move @kok and @v positions in choice rule after the arguments
 - remove kvmalloc suggestions
Changes in v6:
 - more asterisks added in context mode
 - second @kok added to the choice rule
Changes in v7:
 - file renamed to kfree_mismatch.cocci
 - python function relevant() removed
 - additional rule for filtering free positions added
 - btrfs false-positive fixed
 - confidence level changed to high
 - kvfree_switch rule added
 - names for position variables changed to @a (alloc) and @f (free)
Changes in v8:
 - kzfree() replaced with kfree_sensitive()
 - "position f != free.fok;" simplified to "position f;" in patch
   and kvfree_switch rules

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

diff --git a/scripts/coccinelle/api/kfree_mismatch.cocci 
b/scripts/coccinelle/api/kfree_mismatch.cocci
new file mode 100644
index ..843b794fac7b
--- /dev/null
+++ b/scripts/coccinelle/api/kfree_mismatch.cocci
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Check that kvmalloc'ed memory is freed by kfree functions,
+/// vmalloc'ed by vfree functions and kvmalloc'ed by kvfree
+/// functions.
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+
+virtual patch
+virtual report
+virtual org
+virtual context
+
+@alloc@
+expression E, E1;
+position kok, vok;
+@@
+
+(
+  if (...) {
+...
+E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|
+  kmalloc_node\|kzalloc_node\|kmalloc_array\|
+  kmalloc_array_node\|kcalloc_node\)(...)@kok
+...
+  } else {
+...
+E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|
+  vzalloc_node\|vmalloc_exec\|vmalloc_32\|
+  vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|
+  __vmalloc_node\)(...)@vok
+...
+  }
+|
+  E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+kmalloc_array\|kmalloc_array_node\|kcalloc_node\)(...)@kok
+  ... when != E = E1
+  when any
+  if (E == NULL) {
+...
+E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|
+  vzalloc_node\|vmalloc_exec\|vmalloc_32\|
+  vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|
+  __vmalloc_node\)(...)@vok
+...
+  }
+)
+
+@free@
+expression E;
+position fok;
+@@
+
+  E = \(kvmalloc\|kvzalloc\|kvcalloc\|kvzalloc_node\|kvmalloc_node\|
+kvmalloc_array\)(...)
+  ...
+  kvfree(E)@fok
+
+@vfree depends on !patch@
+expression E;
+position a != alloc.kok;
+position f != free.fok;
+@@
+
+* E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|
+*   kzalloc_node\|kmalloc_array\|kmalloc_array_node\|
+*   kcalloc_node\)(...)@a
+  ... when != if (...) { ... E = 
\(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|__vmalloc_node\)(...);
 ... }
+  when != is_vmalloc_addr(E)
+  when any
+* \(vfree\|vfree_atomic\|kvfree\)(E)@f
+
+@depends on patch exists@
+expression E;
+position a != alloc.kok;
+position f != free.fok;
+@@
+
+  E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|
+kzalloc_node\|kmalloc_array\|kmalloc_array_node\|
+kcalloc_node\)(...)@a
+  ... when != if (...) { ... E = 
\(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|__vmalloc_node\)(...);
 ... }
+  when != is_vmalloc_addr(E)
+  when any
+- \(vfree\|vfree_atomic\|kvfree\)(E)@f
++ kfree(E)
+
+@kfree depends on !patch@
+expression E;
+position a != alloc.vok;
+position f != free.fok;
+@@
+
+* E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|
+*   vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|
+*   __vmalloc_node_range\|__vmalloc_node\)(...)@a
+  ... when != is_vmalloc_addr(E)
+  when any
+* \(kfree\|kfree_sensitive\|kvfree\)(E)@f
+
+@depends on patch exists@
+expression E;
+position a != alloc.vok;
+position f != free.fok;
+@@
+
+  E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|
+vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|
+__vmalloc_node_range\|__vmalloc_node\)(...)@a
+  ... when != is_vmalloc_addr(E)
+  when any
+- \(kfree\|kvfree\)(E)@f
++ vfree(E)
+
+@k

[Cocci] [PATCH] coccinelle: api: kfree_sensitive: print memset position

2020-10-09 Thread Denis Efremov
Print memset() call position in addition to the kfree() position to
ease issues identification.

Signed-off-by: Denis Efremov 
---
 scripts/coccinelle/api/kfree_sensitive.cocci | 10 ++
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/scripts/coccinelle/api/kfree_sensitive.cocci 
b/scripts/coccinelle/api/kfree_sensitive.cocci
index e4a066a0b77d..8d980ebf3223 100644
--- a/scripts/coccinelle/api/kfree_sensitive.cocci
+++ b/scripts/coccinelle/api/kfree_sensitive.cocci
@@ -85,14 +85,16 @@ type T;
 
 @script:python depends on report@
 p << r.p;
+m << r.m;
 @@
 
-coccilib.report.print_report(p[0],
-  "WARNING: opportunity for kfree_sensitive/kvfree_sensitive")
+msg = "WARNING opportunity for kfree_sensitive/kvfree_sensitive (memset at 
line %s)"
+coccilib.report.print_report(p[0], msg % (m[0].line))
 
 @script:python depends on org@
 p << r.p;
+m << r.m;
 @@
 
-coccilib.org.print_todo(p[0],
-  "WARNING: opportunity for kfree_sensitive/kvfree_sensitive")
+msg = "WARNING opportunity for kfree_sensitive/kvfree_sensitive (memset at 
line %s)"
+coccilib.org.print_todo(p[0], msg % (m[0].line))
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] kzfree script

2020-10-02 Thread Denis Efremov
On 10/2/20 5:13 PM, Julia Lawall wrote:
> 
> 
> On Fri, 2 Oct 2020, Denis Efremov wrote:
> 
>> Hi,
>>
>> On 10/2/20 5:01 PM, Julia Lawall wrote:
>>> Denis,
>>>
>>> In the rule proposing kzfree_sensitive, I think it would be helpful to
>>> also highlight the memset line.
>>
>> What do you mean? It's "highlighted" in context mode. Do you mean adding
>> position argument to memset call and showing this position in the warning
>> messages?
> 
> Yes, that seems to be what I mean.  0-day generated a message from the
> script, and I had to hunt around for the reason why it was doing that.  So
> it would be nice to have the memset highlighted.  It seems that the
> non-patch 0-day messages are generated from the report mode.
> 

Ok, I will send a patch for it.

Thanks,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] kzfree script

2020-10-02 Thread Denis Efremov
Hi,

On 10/2/20 5:01 PM, Julia Lawall wrote:
> Denis,
> 
> In the rule proposing kzfree_sensitive, I think it would be helpful to
> also highlight the memset line.

What do you mean? It's "highlighted" in context mode. Do you mean adding
position argument to memset call and showing this position in the warning
messages?

Thanks,
Denis

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v4] coccinelle: api: add kvmalloc script

2020-09-30 Thread Denis Efremov
Suggest kvmalloc, kvfree instead of opencoded patterns.

Signed-off-by: Denis Efremov 
---
Changes in v2:
 - binary operator cmp added
 - NULL comparisions simplified
 - "T x" case added to !patch mode
Changes in v3:
 - kvfree rules added
Changes in v4:
 - pattern updated to match only GFP_KERNEL/__GFP_NOWARN flags
   to avoid possible false-positives

All patches are sent:
[1] https://lore.kernel.org/patchwork/patch/1296428/
[2] https://lore.kernel.org/patchwork/patch/1296636/
[3] https://lore.kernel.org/patchwork/patch/1282895/
[4] https://lore.kernel.org/patchwork/patch/1296631/

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

diff --git a/scripts/coccinelle/api/kvmalloc.cocci 
b/scripts/coccinelle/api/kvmalloc.cocci
new file mode 100644
index ..c30dab718a49
--- /dev/null
+++ b/scripts/coccinelle/api/kvmalloc.cocci
@@ -0,0 +1,256 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Find if/else condition with kmalloc/vmalloc calls.
+/// Suggest to use kvmalloc instead. Same for kvfree.
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+
+virtual patch
+virtual report
+virtual org
+virtual context
+
+@initialize:python@
+@@
+filter = frozenset(['kvfree'])
+
+def relevant(p):
+return not (filter & {el.current_element for el in p})
+
+@kvmalloc depends on !patch@
+expression E, E1, size;
+identifier flags;
+binary operator cmp = {<=, <, ==, >, >=};
+identifier x;
+type T;
+position p;
+@@
+
+(
+* if (size cmp E1 || ...)@p {
+...
+*E = \(kmalloc\|kzalloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+*  kmalloc_array\|kmalloc_array_node\|kcalloc_node\)
+*  (..., size, 
\(flags\|GFP_KERNEL\|\(GFP_KERNEL\|flags\)|__GFP_NOWARN\), ...)
+...
+  } else {
+...
+*E = \(vmalloc\|vzalloc\|vmalloc_node\|vzalloc_node\)(..., size, ...)
+...
+  }
+|
+* E = \(kmalloc\|kzalloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+*   kmalloc_array\|kmalloc_array_node\|kcalloc_node\)
+*   (..., size, \(flags\|GFP_KERNEL\|\(GFP_KERNEL\|flags\)|__GFP_NOWARN\), 
...)
+  ... when != E = E1
+  when != size = E1
+  when any
+* if (E == NULL)@p {
+...
+*   E = \(vmalloc\|vzalloc\|vmalloc_node\|vzalloc_node\)(..., size, ...)
+...
+  }
+|
+* T x = \(kmalloc\|kzalloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+* kmalloc_array\|kmalloc_array_node\|kcalloc_node\)
+* (..., size, 
\(flags\|GFP_KERNEL\|\(GFP_KERNEL\|flags\)|__GFP_NOWARN\), ...);
+  ... when != x = E1
+  when != size = E1
+  when any
+* if (x == NULL)@p {
+...
+*   x = \(vmalloc\|vzalloc\|vmalloc_node\|vzalloc_node\)(..., size, ...)
+...
+  }
+)
+
+@kvfree depends on !patch@
+expression E;
+position p : script:python() { relevant(p) };
+@@
+
+* if (is_vmalloc_addr(E))@p {
+...
+*   vfree(E)
+...
+  } else {
+... when != krealloc(E, ...)
+when any
+*   \(kfree\|kzfree\)(E)
+...
+  }
+
+@depends on patch@
+expression E, E1, size, node;
+binary operator cmp = {<=, <, ==, >, >=};
+identifier flags, x;
+type T;
+@@
+
+(
+- if (size cmp E1)
+-E = kmalloc(size, flags);
+- else
+-E = vmalloc(size);
++ E = kvmalloc(size, flags);
+|
+- if (size cmp E1)
+-E = kmalloc(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\));
+- else
+-E = vmalloc(size);
++ E = kvmalloc(size, GFP_KERNEL);
+|
+- E = kmalloc(size, flags | __GFP_NOWARN);
+- if (E == NULL)
+-   E = vmalloc(size);
++ E = kvmalloc(size, flags);
+|
+- E = kmalloc(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\));
+- if (E == NULL)
+-   E = vmalloc(size);
++ E = kvmalloc(size, GFP_KERNEL);
+|
+- T x = kmalloc(size, flags | __GFP_NOWARN);
+- if (x == NULL)
+-   x = vmalloc(size);
++ T x = kvmalloc(size, flags);
+|
+- T x = kmalloc(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\));
+- if (x == NULL)
+-   x = vmalloc(size);
++ T x = kvmalloc(size, GFP_KERNEL);
+|
+- if (size cmp E1)
+-E = kzalloc(size, flags);
+- else
+-E = vzalloc(size);
++ E = kvzalloc(size, flags);
+|
+- if (size cmp E1)
+-E = kzalloc(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\));
+- else
+-E = vzalloc(size);
++ E = kvzalloc(size, GFP_KERNEL);
+|
+- E = kzalloc(size, flags | __GFP_NOWARN);
+- if (E == NULL)
+-   E = vzalloc(size);
++ E = kvzalloc(size, flags);
+|
+- E = kzalloc(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\));
+- if (E == NULL)
+-   E = vzalloc(size);
++ E = kvzalloc(size, GFP_KERNEL);
+|
+- T x = kzalloc(size, flags | __GFP_NOWARN);
+- if (x == NULL)
+-   x = vzalloc(size);
++ T x = kvzalloc(size, flags);
+|
+- T x = kzalloc(size, \(GFP_KERNEL\|GFP_KERNEL|__GFP_NOWARN\));
+- if (x == NULL)
+-   x = vzalloc(size);
++ T x = kvzalloc(size, GFP_KERNEL);
+|
+- if (size cmp E1)
+-E = kmalloc_node(size, flags, node);
+- else
+-E = vmalloc_node(size, node);
++ E = kvmalloc_node(size, flags,

[Cocci] [PATCH v3] coccinelle: misc: add flexible_array.cocci script

2020-09-21 Thread Denis Efremov
One-element and zero-length arrays are deprecated [1]. Kernel
code should always use "flexible array members" instead, except
for existing uapi definitions.

The script warns about one-element and zero-length arrays in structs.

[1] commit 68e4cd17e218 ("docs: deprecated.rst: Add zero-length and
one-element arrays")

Cc: Kees Cook 
Cc: Gustavo A. R. Silva 
Signed-off-by: Denis Efremov 
---
Changes in v2:
 - all uapi headers are now filtered-out. Unfortunately, coccinelle
   doesn't provide structure names in Location.current_element.
   For structures the field is always "something_else". Thus, there is
   no easy way to create a list of existing structures in uapi headers
   and suppress the warning only for them, but not for the newly added
   uapi structures.
 - The pattern doesn't require 2+ fields in a structure/union anymore.
   Now it also checks single field structures/unions.
 - The pattern simplified and now uses disjuction in array elements
   (Thanks, Markus)
 - Unions are removed from patch mode
 - one-element arrays are removed from patch mode. Correct patch may
   involve turning the array to a simple field instead of a flexible
   array.
Changes in v3:
 - exists removed from "depends on patch"
 - position argument fixed in org mode
 - link to the online documentation added to the warning message

 scripts/coccinelle/misc/flexible_array.cocci | 88 
 1 file changed, 88 insertions(+)
 create mode 100644 scripts/coccinelle/misc/flexible_array.cocci

diff --git a/scripts/coccinelle/misc/flexible_array.cocci 
b/scripts/coccinelle/misc/flexible_array.cocci
new file mode 100644
index ..947fbaff82a9
--- /dev/null
+++ b/scripts/coccinelle/misc/flexible_array.cocci
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Zero-length and one-element arrays are deprecated, see
+/// Documentation/process/deprecated.rst
+/// Flexible-array members should be used instead.
+///
+//
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS.
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual context
+virtual report
+virtual org
+virtual patch
+
+@initialize:python@
+@@
+def relevant(positions):
+for p in positions:
+if "uapi" in p.file:
+ return False
+return True
+
+@r depends on !patch@
+identifier name, array;
+type T;
+position p : script:python() { relevant(p) };
+@@
+
+(
+  struct name {
+...
+*   T array@p[\(0\|1\)];
+  };
+|
+  struct {
+...
+*   T array@p[\(0\|1\)];
+  };
+|
+  union name {
+...
+*   T array@p[\(0\|1\)];
+  };
+|
+  union {
+...
+*   T array@p[\(0\|1\)];
+  };
+)
+
+@depends on patch@
+identifier name, array;
+type T;
+position p : script:python() { relevant(p) };
+@@
+
+(
+  struct name {
+...
+T array@p[
+-   0
+];
+  };
+|
+  struct {
+...
+T array@p[
+-   0
+];
+  };
+)
+
+@script: python depends on report@
+p << r.p;
+@@
+
+msg = "WARNING use flexible-array member instead 
(https://www.kernel.org/doc/html/latest/process/deprecated.html#zero-length-and-one-element-arrays)"
+coccilib.report.print_report(p[0], msg)
+
+@script: python depends on org@
+p << r.p;
+@@
+
+msg = "WARNING use flexible-array member instead 
(https://www.kernel.org/doc/html/latest/process/deprecated.html#zero-length-and-one-element-arrays)"
+coccilib.org.print_todo(p[0], msg)
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [PATCH v7] coccinelle: api: add kfree_mismatch script

2020-09-21 Thread Denis Efremov
Hi,

On 8/3/20 9:34 PM, Denis Efremov wrote:
> Check that alloc and free types of functions match each other.

Julia, I've just send the patches to fix all the warnings emitted by the script.

[1] https://lore.kernel.org/patchwork/patch/1309731/
[2] https://lore.kernel.org/patchwork/patch/1309273/
[3] https://lore.kernel.org/patchwork/patch/1309275/

Other inconsistencies and bugs detected by this script:

1e814d630fd1 drm/amd/display: Use kfree() to free rgb_user in 
calculate_user_regamma_ramp()
842540075974 drm/amd/display: Use kvfree() to free coeff in build_regamma()
f5e383ac8b58 iommu/pamu: Use kzfree() in fsl_pamu_probe()
36b26e37 net/mlx5: Use kfree(ft->g) in arfs_create_groups()
114427b8927a drm/panfrost: Use kvfree() to free bo->sgts
742532d11d83 f2fs: use kfree() instead of kvfree() to free superblock data
47a357de2b6b net/mlx5: DR, Fix freeing in dr_create_rc_qp()
a8c73c1a614f io_uring: use kvfree() in io_sqe_buffer_register()
7f89cc07d22a cxgb4: Use kfree() instead kvfree() where appropriate
bb2359f4dbe9 bpf: Change kvfree to kfree in generic_map_lookup_batch()


> Changes in v2:
>  - Lines are limited to 80 characters where possible
>  - Confidence changed from High to Medium because of 
>fs/btrfs/send.c:1119 false-positive
>  - __vmalloc_area_node() explicitly excluded from analysis
>instead of !(file in "mm/vmalloc.c") condition
> Changes in v3:
>  - prints style in org && report modes changed for python2
> Changes in v4:
>  - missing msg argument to print_todo fixed
> Changes in v5:
>  - fix position p in kfree rule
>  - move @kok and @v positions in choice rule after the arguments
>  - remove kvmalloc suggestions
> Changes in v6:
>  - more asterisks added in context mode
>  - second @kok added to the choice rule
> Changes in v7:
>  - file renamed to kfree_mismatch.cocci
>  - python function relevant() removed
>  - additional rule for filtering free positions added
>  - btrfs false-positive fixed
>  - confidence level changed to high
>  - kvfree_switch rule added
>  - names for position variables changed to @a (alloc) and @f (free)

Is there something I can improve in this cocci script to be accepted?

Thanks,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v2] coccinelle: misc: add excluded_middle.cocci script

2020-09-21 Thread Denis Efremov
Check for !A || A && B condition. It's equivalent to !A || B.

Signed-off-by: Denis Efremov 
---
Changes in v2:
 - spelling mistake fixed
 - position variable moved on the && operator
 - patch pattern changed to - (A && B)
 - word "condition" removed from warning message

 scripts/coccinelle/misc/excluded_middle.cocci | 39 +++
 1 file changed, 39 insertions(+)
 create mode 100644 scripts/coccinelle/misc/excluded_middle.cocci

diff --git a/scripts/coccinelle/misc/excluded_middle.cocci 
b/scripts/coccinelle/misc/excluded_middle.cocci
new file mode 100644
index ..ab28393e4843
--- /dev/null
+++ b/scripts/coccinelle/misc/excluded_middle.cocci
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Condition !A || A && B is equivalent to !A || B.
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+@r depends on !patch@
+expression A, B;
+position p;
+@@
+
+* !A || (A &&@p B)
+
+@depends on patch@
+expression A, B;
+@@
+
+  !A ||
+-   (A && B)
++   B
+
+@script:python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING !A || A && B is equivalent to !A 
|| B")
+
+@script:python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING !A || A && B is equivalent to !A || B")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [PATCH v2] coccinelle: misc: add flexible_array.cocci script

2020-09-13 Thread Denis Efremov
Hi,

On 9/12/20 5:43 PM, Julia Lawall wrote:
> 
> 
> On Mon, 10 Aug 2020, Denis Efremov wrote:
> 
>> Commit 68e4cd17e218 ("docs: deprecated.rst: Add zero-length and one-element
>> arrays") marks one-element and zero-length arrays as deprecated. Kernel
>> code should always use "flexible array members" instead.
>>
>> The script warns about one-element and zero-length arrays in structs.
>>
>> Cc: Kees Cook 
>> Cc: Gustavo A. R. Silva 
>> Signed-off-by: Denis Efremov 
>> ---
>> Changes in v2:
>>  - all uapi headers are now filtered-out. Unfortunately, coccinelle
>>doesn't provide structure names in Location.current_element.
>>For structures the field is always "something_else". Thus, there is
>>no easy way to create a list of existing structures in uapi headers
>>and suppress the warning only for them, but not for the newly added
>>uapi structures.
>>  - The pattern doesn't require 2+ fields in a structure/union anymore.
>>Now it also checks single field structures/unions.
>>  - The pattern simplified and now uses disjuction in array elements
>>(Thanks, Markus)
>>  - Unions are removed from patch mode
>>  - one-element arrays are removed from patch mode. Correct patch may
>>involve turning the array to a simple field instead of a flexible
>>array.
>>
>> On the current master branch, the rule generates:
>>  - context: https://gist.github.com/evdenis/e2b4323491f9eff35376372df07f723c
>>  - patch: https://gist.github.com/evdenis/46081da9d68ecefd07edc3769cebcf32
>>
>>  scripts/coccinelle/misc/flexible_array.cocci | 88 
>>  1 file changed, 88 insertions(+)
>>  create mode 100644 scripts/coccinelle/misc/flexible_array.cocci
>>
>> diff --git a/scripts/coccinelle/misc/flexible_array.cocci 
>> b/scripts/coccinelle/misc/flexible_array.cocci
>> new file mode 100644
>> index ..bf6dcda1783e
>> --- /dev/null
>> +++ b/scripts/coccinelle/misc/flexible_array.cocci
>> @@ -0,0 +1,88 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +///
>> +/// Zero-length and one-element arrays are deprecated, see
>> +/// Documentation/process/deprecated.rst
>> +/// Flexible-array members should be used instead.
>> +///
>> +//
>> +// Confidence: High
>> +// Copyright: (C) 2020 Denis Efremov ISPRAS.
>> +// Comments:
>> +// Options: --no-includes --include-headers
>> +
>> +virtual context
>> +virtual report
>> +virtual org
>> +virtual patch
>> +
>> +@initialize:python@
>> +@@
>> +def relevant(positions):
>> +for p in positions:
>> +if "uapi" in p.file:
>> + return False
>> +return True
>> +
>> +@r depends on !patch@
>> +identifier name, array;
>> +type T;
>> +position p : script:python() { relevant(p) };
>> +@@
>> +
>> +(
>> +  struct name {
>> +...
>> +*   T array@p[\(0\|1\)];
>> +  };
>> +|
>> +  struct {
>> +...
>> +*   T array@p[\(0\|1\)];
>> +  };
>> +|
>> +  union name {
>> +...
>> +*   T array@p[\(0\|1\)];
>> +  };
>> +|
>> +  union {
>> +...
>> +*   T array@p[\(0\|1\)];
>> +  };
>> +)
>> +
>> +@depends on patch exists@
> 
> exists is not necessary here.  There are not multiple control-flow paths
> through a structure declaration.
> 
>> +identifier name, array;
>> +type T;
>> +position p : script:python() { relevant(p) };
>> +@@
>> +
>> +(
>> +  struct name {
>> +...
>> +T array@p[
>> +-   0
>> +];
>> +  };
>> +|
>> +  struct {
>> +...
>> +T array@p[
>> +-   0
>> +];
>> +  };
>> +)
>> +
>> +@script: python depends on report@
>> +p << r.p;
>> +@@
>> +
>> +msg = "WARNING: use flexible-array member instead"
>> +coccilib.report.print_report(p[0], msg)
>> +
>> +@script: python depends on org@
>> +p << r.p;
>> +@@
>> +
>> +msg = "WARNING: use flexible-array member instead"
>> +coccilib.org.print_todo(p, msg)
> 
> This should be coccilib.org.print_todo(p[0], msg)
> 


Thanks, I will send v3 with fixes and proper links to online documentation.

Regards,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [PATCH] scripts: kzfree.cocci: Deprecate use of kzfree

2020-09-11 Thread Denis Efremov
Hi,

same patch
https://lkml.org/lkml/2020/8/11/130

Julia, I've send all the patches to fix existing 
kfree_sensitive/kvfree_sensitive reports.

https://lkml.org/lkml/2020/8/27/168
https://lkml.org/lkml/2020/8/27/93

Thanks,
Denis

On 9/11/20 4:49 PM, Alex Dewar wrote:
> kzfree() is effectively deprecated as of commit 453431a54934 ("mm,
> treewide: rename kzfree() to kfree_sensitive()"). It is currently just a
> legacy alias for kfree_sensitive(), which achieves the same thing.
> 
> Update kzfree.cocci accordingly:
> 1) Replace instances of kzfree with kfree_sensitive
> 2) Merge different rules for memset/memset_explicit as kzfree and
>kfree_sensitive are now equivalent
> 3) Rename script to kfree_sensitive.cocci
> 
> In addition:
> 4) Move the script to the free/ subfolder, where it would seem to fit
>better
> 
> Signed-off-by: Alex Dewar 
> ---
>  .../kfree_sensitive.cocci}| 38 +--
>  1 file changed, 10 insertions(+), 28 deletions(-)
>  rename scripts/coccinelle/{api/kzfree.cocci => free/kfree_sensitive.cocci} 
> (59%)
> 
> diff --git a/scripts/coccinelle/api/kzfree.cocci 
> b/scripts/coccinelle/free/kfree_sensitive.cocci
> similarity index 59%
> rename from scripts/coccinelle/api/kzfree.cocci
> rename to scripts/coccinelle/free/kfree_sensitive.cocci
> index 33625bd7cec9..a87f93f2ed5c 100644
> --- a/scripts/coccinelle/api/kzfree.cocci
> +++ b/scripts/coccinelle/free/kfree_sensitive.cocci
> @@ -1,13 +1,13 @@
>  // SPDX-License-Identifier: GPL-2.0-only
>  ///
> -/// Use kzfree, kvfree_sensitive rather than memset or
> -/// memzero_explicit followed by kfree
> +/// Use k{,v}free_sensitive rather than memset or memzero_explicit followed 
> by
> +/// k{,v}free
>  ///
>  // Confidence: High
>  // Copyright: (C) 2020 Denis Efremov ISPRAS
>  // Options: --no-includes --include-headers
>  //
> -// Keywords: kzfree, kvfree_sensitive
> +// Keywords: kfree_sensitive, kvfree_sensitive
>  //
>  
>  virtual context
> @@ -18,7 +18,7 @@ virtual report
>  @initialize:python@
>  @@
>  # kmalloc_oob_in_memset uses memset to explicitly trigger out-of-bounds 
> access
> -filter = frozenset(['kmalloc_oob_in_memset', 'kzfree', 'kvfree_sensitive'])
> +filter = frozenset(['kmalloc_oob_in_memset', 'kfree_sensitive', 
> 'kvfree_sensitive'])
>  
>  def relevant(p):
>  return not (filter & {el.current_element for el in p})
> @@ -53,34 +53,16 @@ position m != cond.ok;
>  type T;
>  @@
>  
> +(
>  - memzero_explicit@m((T)E, size);
> -  ... when != E
> -  when strict
> -// TODO: uncomment when kfree_sensitive will be merged.
> -// Only this case is commented out because developers
> -// may not like patches like this since kzfree uses memset
> -// internally (not memzero_explicit).
> -//(
> -//- kfree(E)@p;
> -//+ kfree_sensitive(E);
> -//|
> -- \(vfree\|kvfree\)(E)@p;
> -+ kvfree_sensitive(E, size);
> -//)
> -
> -@rp_memset depends on patch@
> -expression E, size;
> -position p : script:python() { relevant(p) };
> -position m != cond.ok;
> -type T;
> -@@
> -
> +|
>  - memset@m((T)E, 0, size);
> +)
>... when != E
>when strict
>  (
>  - kfree(E)@p;
> -+ kzfree(E);
> ++ kfree_sensitive(E);
>  |
>  - \(vfree\|kvfree\)(E)@p;
>  + kvfree_sensitive(E, size);
> @@ -91,11 +73,11 @@ p << r.p;
>  @@
>  
>  coccilib.report.print_report(p[0],
> -  "WARNING: opportunity for kzfree/kvfree_sensitive")
> +  "WARNING: opportunity for k{,v}free_sensitive")
>  
>  @script:python depends on org@
>  p << r.p;
>  @@
>  
>  coccilib.org.print_todo(p[0],
> -  "WARNING: opportunity for kzfree/kvfree_sensitive")
> +  "WARNING: opportunity for k{,v}free_sensitive")
> 
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH] coccinelle: misc: add excluded_middle.cocci script

2020-09-02 Thread Denis Efremov
Check for "!A || A && B" condition. It's equivalent to
"!A || B" condition.

Signed-off-by: Denis Efremov 
---
 scripts/coccinelle/misc/excluded_middle.cocci | 40 +++
 1 file changed, 40 insertions(+)
 create mode 100644 scripts/coccinelle/misc/excluded_middle.cocci

diff --git a/scripts/coccinelle/misc/excluded_middle.cocci 
b/scripts/coccinelle/misc/excluded_middle.cocci
new file mode 100644
index ..1b8c20f13966
--- /dev/null
+++ b/scripts/coccinelle/misc/excluded_middle.cocci
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Condition "!A || A && B" is equalent to "!A || B".
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+@r depends on !patch@
+expression A, B;
+position p;
+@@
+
+* !A || (A && B)@p
+
+@depends on patch@
+expression A, B;
+@@
+
+  !A || 
+-  (A &&
+ B
+-  )
+
+@script:python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING condition !A || A && B is 
equivalent to !A || B")
+
+@script:python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING condition !A || A && B is equivalent to 
!A || B")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] expression without side effects

2020-09-02 Thread Denis Efremov



On 9/2/20 3:32 PM, Julia Lawall wrote:
> There is an isomorphism that you can disable: ptr_to_array

Thanks!

Anyway, even with ptr_to_array enabled equalizing cmd->dmap[0] and
cmd->dmap[1] looks incorrect to me.


Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] expression without side effects

2020-09-02 Thread Denis Efremov
Hi,

I'm trying to write a pattern to match expression without side-effects, 
i.e expression E but not i++, --i, function call.

While trying to write it I faced that this expression matches different
array indices. Actually, it's quite unexpected for me:

@@
expression E;
identifier A;
@@

* E->A || E->A

Actually, I would expect it not to match the file at all:

$ spatch --cocci-file ./test.cocci ./drivers/md/dm-clone-metadata.c
init_defs_builtins: /usr/lib64/coccinelle/standard.h
HANDLING: ./drivers/md/dm-clone-metadata.c
diff =
--- ./drivers/md/dm-clone-metadata.c
+++ /tmp/cocci-output-11041-66b4fb-dm-clone-metadata.c
@@ -947,7 +947,6 @@ bool dm_clone_changed_this_transaction(s
unsigned long flags;

spin_lock_irqsave(>bitmap_lock, flags);
-   r = cmd->dmap[0].changed || cmd->dmap[1].changed;
spin_unlock_irqrestore(>bitmap_lock, flags);

return r;

Thanks,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] checkpatch? (was: Re: [PATCH v3] coccinelle: misc: add uninitialized_var.cocci script)

2020-09-01 Thread Denis Efremov



On 9/1/20 5:37 PM, Joe Perches wrote:
> On Tue, 2020-09-01 at 12:48 +0300, Denis Efremov wrote:
>> uninitialized_var() macro was removed from the sources [1] and
>> other warning-silencing tricks were deprecated [2]. The purpose of this
>> cocci script is to prevent new occurrences of uninitialized_var()
>> open-coded variants.
> 
>> +(
>> +* T var =@p var;
>> +|
>> +* T var =@p *(&(var));
>> +|
>> +* var =@p var
>> +|
>> +* var =@p *(&(var))
>> +)
> 
> Adding a checkpatch test might be a good thing too.
> 
> ---
>  scripts/checkpatch.pl | 11 +++
>  1 file changed, 11 insertions(+)
> 
> diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
> index 149518d2a6a7..300b2659aab3 100755
> --- a/scripts/checkpatch.pl
> +++ b/scripts/checkpatch.pl
> @@ -3901,6 +3901,17 @@ sub process {
>  #ignore lines not being added
>   next if ($line =~ /^[^\+]/);
>  
> +# check for self assigments used to avoid compiler warnings
> +# e.g.:  int foo = foo, *bar = NULL;
> +#struct foo bar = *(&(bar));
> + if ($line =~ /^\+\s*(?:$Declare)?([A-Za-z_][A-Za-z\d_]*)\s*=/) {
> + my $var = $1;
> + if ($line =~ 
> /^\+\s*(?:$Declare)?$var\s*=\s*(?:$var|\*\s*\(?\s*&\s*\(?\s*$var\s*\)?\s*\)?)\s*[;,]/)
>  {
> + WARN("SELF_ASSIGNMENT",
> +  "Do not use self-assignments to avoid 
> compiler warnings\n" . $herecurr);
> + }
> + }
> +
>  # check for dereferences that span multiple lines
>   if ($prevline =~ /^\+.*$Lval\s*(?:\.|->)\s*$/ &&
>   $line =~ /^\+\s*(?!\#\s*(?!define\s+|if))\s*$Lval/) {

Looks good. I also faced this kind of assignments after declarations.
https://lkml.org/lkml/2020/8/31/85

I'm not sure if they are used to suppress compiler warnings, through.

Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH] coccinelle: ifnullfree: add vfree(), kvfree*() functions

2020-09-01 Thread Denis Efremov
Extend the list of free functions with kvfree(), kvfree_sensitive(),
vfree().

Signed-off-by: Denis Efremov 
---
 scripts/coccinelle/free/ifnullfree.cocci | 11 +--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/scripts/coccinelle/free/ifnullfree.cocci 
b/scripts/coccinelle/free/ifnullfree.cocci
index 2045391e36a0..285b92d5c665 100644
--- a/scripts/coccinelle/free/ifnullfree.cocci
+++ b/scripts/coccinelle/free/ifnullfree.cocci
@@ -20,8 +20,14 @@ expression E;
 - if (E != NULL)
 (
   kfree(E);
+|
+  kvfree(E);
 |
   kfree_sensitive(E);
+|
+  kvfree_sensitive(E, ...);
+|
+  vfree(E);
 |
   debugfs_remove(E);
 |
@@ -42,9 +48,10 @@ position p;
 @@
 
 * if (E != NULL)
-*  
\(kfree@p\|kfree_sensitive@p\|debugfs_remove@p\|debugfs_remove_recursive@p\|
+*  \(kfree@p\|kvfree@p\|kfree_sensitive@p\|kvfree_sensitive@p\|vfree@p\|
+* debugfs_remove@p\|debugfs_remove_recursive@p\|
 * usb_free_urb@p\|kmem_cache_destroy@p\|mempool_destroy@p\|
-* dma_pool_destroy@p\)(E);
+* dma_pool_destroy@p\)(E, ...);
 
 @script:python depends on org@
 p << r.p;
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v3] coccinelle: misc: add uninitialized_var.cocci script

2020-09-01 Thread Denis Efremov
uninitialized_var() macro was removed from the sources [1] and
other warning-silencing tricks were deprecated [2]. The purpose of this
cocci script is to prevent new occurrences of uninitialized_var()
open-coded variants.

[1] commit 63a0895d960a ("compiler: Remove uninitialized_var() macro")
[2] commit 4b19bec97c88 ("docs: deprecated.rst: Add uninitialized_var()")

Cc: Kees Cook 
Cc: Gustavo A. R. Silva 
Signed-off-by: Denis Efremov 
---
Changes in v2:
 - Documentation cited in the script's description
 - kernel.org link added to the diagnostics messages
 - "T *var = " pattern removed
 - "var =@p var", "var =@p *(&(var))" patterns added
Changes in v3:
 - commit's description changed

 .../coccinelle/misc/uninitialized_var.cocci   | 51 +++
 1 file changed, 51 insertions(+)
 create mode 100644 scripts/coccinelle/misc/uninitialized_var.cocci

diff --git a/scripts/coccinelle/misc/uninitialized_var.cocci 
b/scripts/coccinelle/misc/uninitialized_var.cocci
new file mode 100644
index ..8fa845cefe11
--- /dev/null
+++ b/scripts/coccinelle/misc/uninitialized_var.cocci
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Please, don't reintroduce uninitialized_var().
+/// From Documentation/process/deprecated.rst:
+///  For any compiler warnings about uninitialized variables, just add
+///  an initializer. Using warning-silencing tricks is dangerous as it
+///  papers over real bugs (or can in the future), and suppresses unrelated
+///  compiler warnings (e.g. "unused variable"). If the compiler thinks it
+///  is uninitialized, either simply initialize the variable or make compiler
+///  changes. Keep in mind that in most cases, if an initialization is
+///  obviously redundant, the compiler's dead-store elimination pass will make
+///  sure there are no needless variable writes.
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+
+virtual context
+virtual report
+virtual org
+
+@r@
+identifier var;
+type T;
+position p;
+@@
+
+(
+* T var =@p var;
+|
+* T var =@p *(&(var));
+|
+* var =@p var
+|
+* var =@p *(&(var))
+)
+
+@script:python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0],
+  "WARNING this kind of initialization is deprecated 
(https://www.kernel.org/doc/html/latest/process/deprecated.html#uninitialized-var)")
+
+@script:python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0],
+  "WARNING this kind of initialization is deprecated 
(https://www.kernel.org/doc/html/latest/process/deprecated.html#uninitialized-var)")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH] coccinelle: api: kobj_to_dev: don't warn about kobj_to_dev()

2020-09-01 Thread Denis Efremov
Exclude kobj_to_dev() definition from warnings.

Signed-off-by: Denis Efremov 
---
No changes in performance. This patch can be squashed to the
original patch with kobj_to_dev.cocci script.

 scripts/coccinelle/api/kobj_to_dev.cocci | 13 +++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/scripts/coccinelle/api/kobj_to_dev.cocci 
b/scripts/coccinelle/api/kobj_to_dev.cocci
index cd5d31c6fe76..d0b3b9647c19 100644
--- a/scripts/coccinelle/api/kobj_to_dev.cocci
+++ b/scripts/coccinelle/api/kobj_to_dev.cocci
@@ -15,10 +15,18 @@ virtual org
 virtual patch
 
 
+@initialize:python@
+@@
+filter = frozenset(['kobj_to_dev'])
+
+def relevant(p):
+return not (filter & {el.current_element for el in p})
+
+
 @r depends on !patch@
 expression ptr;
 symbol kobj;
-position p;
+position p : script:python() { relevant(p) };
 @@
 
 * container_of(ptr, struct device, kobj)@p
@@ -26,9 +34,10 @@ position p;
 
 @depends on patch@
 expression ptr;
+position p : script:python() { relevant(p) };
 @@
 
-- container_of(ptr, struct device, kobj)
+- container_of(ptr, struct device, kobj)@p
 + kobj_to_dev(ptr)
 
 
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v2] coccinelle: misc: add uninitialized_var.cocci script

2020-09-01 Thread Denis Efremov
Commit 63a0895d960a ("compiler: Remove uninitialized_var() macro") and
commit 4b19bec97c88 ("docs: deprecated.rst: Add uninitialized_var()")
removed uninitialized_var() and deprecated it.

The purpose of this script is to prevent new occurrences of open-coded
variants of uninitialized_var().

Cc: Kees Cook 
Cc: Gustavo A. R. Silva 
Signed-off-by: Denis Efremov 
---
Changes in v2:
 - Documentation cited in the script's description
 - kernel.org link added to the diagnostics messages
 - "T *var = " pattern removed
 - "var =@p var", "var =@p *(&(var))" patterns added

 .../coccinelle/misc/uninitialized_var.cocci   | 51 +++
 1 file changed, 51 insertions(+)
 create mode 100644 scripts/coccinelle/misc/uninitialized_var.cocci

diff --git a/scripts/coccinelle/misc/uninitialized_var.cocci 
b/scripts/coccinelle/misc/uninitialized_var.cocci
new file mode 100644
index ..8fa845cefe11
--- /dev/null
+++ b/scripts/coccinelle/misc/uninitialized_var.cocci
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Please, don't reintroduce uninitialized_var().
+/// From Documentation/process/deprecated.rst:
+///  For any compiler warnings about uninitialized variables, just add
+///  an initializer. Using warning-silencing tricks is dangerous as it
+///  papers over real bugs (or can in the future), and suppresses unrelated
+///  compiler warnings (e.g. "unused variable"). If the compiler thinks it
+///  is uninitialized, either simply initialize the variable or make compiler
+///  changes. Keep in mind that in most cases, if an initialization is
+///  obviously redundant, the compiler's dead-store elimination pass will make
+///  sure there are no needless variable writes.
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+
+virtual context
+virtual report
+virtual org
+
+@r@
+identifier var;
+type T;
+position p;
+@@
+
+(
+* T var =@p var;
+|
+* T var =@p *(&(var));
+|
+* var =@p var
+|
+* var =@p *(&(var))
+)
+
+@script:python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0],
+  "WARNING this kind of initialization is deprecated 
(https://www.kernel.org/doc/html/latest/process/deprecated.html#uninitialized-var)")
+
+@script:python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0],
+  "WARNING this kind of initialization is deprecated 
(https://www.kernel.org/doc/html/latest/process/deprecated.html#uninitialized-var)")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [RFC PATCH] coccinelle: misc: add uninitialized_var.cocci script

2020-08-29 Thread Denis Efremov



On 8/29/20 10:48 PM, Julia Lawall wrote:
> 
> 
> On Sat, 29 Aug 2020, Joe Perches wrote:
> 
>> On Sat, 2020-08-29 at 21:36 +0200, Julia Lawall wrote:
>>>
>>> On Wed, 12 Aug 2020, Denis Efremov wrote:
>>>
>>>> Commit 63a0895d960a ("compiler: Remove uninitialized_var() macro") and
>>>> commit 4b19bec97c88 ("docs: deprecated.rst: Add uninitialized_var()")
>>>> removed uninitialized_var() and deprecated it.
>>>>
>>>> The purpose of this script is to prevent new occurrences of open-coded
>>>> variants of uninitialized_var().
>>
>>>> Cc: Kees Cook 
>>>> Cc: Gustavo A. R. Silva 
>>>> Signed-off-by: Denis Efremov 
>>>
>>> Applied, without the commented out part.
>>>
>>> I only got three warnings, though.  Perhaps the others have been fixed?
>>
>> uninitialized_var does not exist in -next

Yes, and this rule checks for not introducing these initializations once again.

i.e, checks for: 

int a = a;

int a = *();

> 
> OK, if it seems better, I can remove it.  Out of the threee reported, one
> was a completely unnecessary initialization.
> 

I would like send v2 with better description and link to the documentation 
because it's
now available online:
https://www.kernel.org/doc/html/latest/process/deprecated.html#uninitialized-var

Thanks,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


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

2020-08-28 Thread Denis Efremov
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 
Cc: Kees Cook 
Signed-off-by: Denis Efremov 
---
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 ..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

Re: [Cocci] [PATCH] usb: atm: don't use snprintf() for sysfs attrs

2020-08-27 Thread Denis Efremov
> 
> I tried:
> @@
> identifier f_show =~ "^.*_show$";


This will miss this kind of functions:
./drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:1953:static 
DEVICE_ATTR(vbios_version, 0444, amdgpu_atombios_get_vbios_version,
./drivers/gpu/drm/amd/amdgpu/df_v3_6.c:266:static DEVICE_ATTR(df_cntr_avail, 
S_IRUGO, df_v3_6_get_df_cntr_avail, NULL);
./drivers/input/touchscreen/melfas_mip4.c:1348:static DEVICE_ATTR(fw_version, 
S_IRUGO, mip4_sysfs_read_fw_version, NULL);
./drivers/input/touchscreen/melfas_mip4.c:1373:static DEVICE_ATTR(hw_version, 
S_IRUGO, mip4_sysfs_read_hw_version, NULL);
./drivers/input/touchscreen/melfas_mip4.c:1392:static DEVICE_ATTR(product_id, 
S_IRUGO, mip4_sysfs_read_product_id, NULL);
...

> identifier dev, attr, buf;
> const char *chr;
> @@
> ssize_t f_show(struct device *dev, struct device_attribute *attr, char
> *buf)
> {
>   <...
> (
> - sprintf
> + sysfs_sprintf
>   (...);
> |
> - snprintf(buf, PAGE_SIZE,
> + sysfs_sprintf(buf,
>   ...);
> |
> - scnprintf(buf, PAGE_SIZE,
> + sysfs_sprintf(buf,
>   ...);
> |
>   strcpy(buf, chr);
>   sysfs_strcpy(buf, chr);
> )
>   ...>
> }
> 
> which finds direct statements without an assign
> but that doesn't find
> 
> arch/arm/common/dmabounce.c:static ssize_t dmabounce_show(struct device *dev, 
> struct device_attribute *attr, char *buf)
> arch/arm/common/dmabounce.c-{
> arch/arm/common/dmabounce.c-struct dmabounce_device_info *device_info = 
> dev->archdata.dmabounce;
> arch/arm/common/dmabounce.c-return sprintf(buf, "%lu %lu %lu %lu %lu 
> %lu\n",
> arch/arm/common/dmabounce.c-device_info->small.allocs,
> arch/arm/common/dmabounce.c-device_info->large.allocs,
> arch/arm/common/dmabounce.c-device_info->total_allocs - 
> device_info->small.allocs -
> arch/arm/common/dmabounce.c-device_info->large.allocs,
> arch/arm/common/dmabounce.c-device_info->total_allocs,
> arch/arm/common/dmabounce.c-device_info->map_op_count,
> arch/arm/common/dmabounce.c-device_info->bounce_count);
> arch/arm/common/dmabounce.c-}
>

This will match it (the difference is in the ';'):
@@
identifier f_show =~ "^.*_show$";
identifier dev, attr, buf;
@@

ssize_t f_show(struct device *dev, struct device_attribute *attr, char *buf)

{

<...
-   sprintf
+   sysfs_sprintf
(...)
...>
}

Regards,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [PATCH] usb: atm: don't use snprintf() for sysfs attrs

2020-08-27 Thread Denis Efremov
Hi all,

On 8/27/20 10:42 PM, Julia Lawall wrote:
> 
> 
> On Thu, 27 Aug 2020, Joe Perches wrote:
> 
>> On Thu, 2020-08-27 at 15:48 +0100, Alex Dewar wrote:
>>> On Thu, Aug 27, 2020 at 03:41:06PM +0200, Rasmus Villemoes wrote:
 On 27/08/2020 15.18, Alex Dewar wrote:
> On Thu, Aug 27, 2020 at 09:15:37AM +0200, Greg Kroah-Hartman wrote:
>> On Thu, Aug 27, 2020 at 08:42:06AM +0200, Rasmus Villemoes wrote:
>>> On 25/08/2020 00.23, Alex Dewar wrote:
 kernel/cpu.c: don't use snprintf() for sysfs attrs

 As per the documentation (Documentation/filesystems/sysfs.rst),
 snprintf() should not be used for formatting values returned by sysfs.

Just FYI, I've send an addition to the device_attr_show.cocci script[1] to turn
simple cases of snprintf (e.g. "%i") to sprintf. Looks like many developers 
would
like it more than changing snprintf to scnprintf. As for me, I don't like the 
idea
of automated altering of the original logic from bounded snprint to unbouded one
with sprintf.

[1] https://lkml.org/lkml/2020/8/13/786

Regarding current device_attr_show.cocci implementation, it detects the 
functions
by declaration:
ssize_t any_name(struct device *dev, struct device_attribute *attr, char *buf)

and I limited the check to:
"return snprintf"
pattern because there are already too many warnings.

Actually, it looks more correct to check for:
ssize_t show(struct device *dev, struct device_attribute *attr, char *buf)
{
<...
*   snprintf@p(...);
...>
}

This pattern should also highlight the snprintf calls there we save returned
value in a var, e.g.:

ret += snprintf(...);
...
ret += snprintf(...);
...
ret += snprintf(...);

return ret;

> 
> Something like
> 
> identifier f;
> fresh identifier = "sysfs" ## f;
> 
> may be useful.  Let me know if further help is needed.

Initially, I wrote the rule to search for DEVICE_ATTR(..., ..., func_name, ...)
functions. However, it looks like matching function prototype is enough. At 
least,
I failed to find false positives. I rejected the initial DEVICE_ATTR() searching
because I thought that it's impossible to handle 
DEVICE_ATTR_RO()/DEVICE_ATTR_RW()
macroses with coccinelle as they "generate" function names internally with
"##". "fresh identifier" should really help here, but now I doubt it's required 
in
device_attr_show.cocci, function prototype is enough.

Thanks,
Denis

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [PATCH] coccinelle: api: update kzfree script to kfree_sensitive

2020-08-26 Thread Denis Efremov
Ping?

On 8/11/20 10:49 AM, Denis Efremov wrote:
> Commit 453431a54934 ("mm, treewide: rename kzfree() to kfree_sensitive()")
> renames kzfree to kfree_sensitive and uses memzero_explicit(...) instead of
> memset(..., 0, ...) internally. Update cocci script to reflect these
> changes.
> 
> Signed-off-by: Denis Efremov 
> ---
> Julia, I think you can squash this commit with original script, or I can
> resend the whole script since it's not merged to the mainline.
> 
>  .../{kzfree.cocci => kfree_sensitive.cocci}   | 29 +--
>  1 file changed, 13 insertions(+), 16 deletions(-)
>  rename scripts/coccinelle/api/{kzfree.cocci => kfree_sensitive.cocci} (70%)
> 
> diff --git a/scripts/coccinelle/api/kzfree.cocci 
> b/scripts/coccinelle/api/kfree_sensitive.cocci
> similarity index 70%
> rename from scripts/coccinelle/api/kzfree.cocci
> rename to scripts/coccinelle/api/kfree_sensitive.cocci
> index 33625bd7cec9..e4a066a0b77d 100644
> --- a/scripts/coccinelle/api/kzfree.cocci
> +++ b/scripts/coccinelle/api/kfree_sensitive.cocci
> @@ -1,13 +1,13 @@
>  // SPDX-License-Identifier: GPL-2.0-only
>  ///
> -/// Use kzfree, kvfree_sensitive rather than memset or
> -/// memzero_explicit followed by kfree
> +/// Use kfree_sensitive, kvfree_sensitive rather than memset or
> +/// memzero_explicit followed by kfree.
>  ///
>  // Confidence: High
>  // Copyright: (C) 2020 Denis Efremov ISPRAS
>  // Options: --no-includes --include-headers
>  //
> -// Keywords: kzfree, kvfree_sensitive
> +// Keywords: kfree_sensitive, kvfree_sensitive
>  //
>  
>  virtual context
> @@ -18,7 +18,8 @@ virtual report
>  @initialize:python@
>  @@
>  # kmalloc_oob_in_memset uses memset to explicitly trigger out-of-bounds 
> access
> -filter = frozenset(['kmalloc_oob_in_memset', 'kzfree', 'kvfree_sensitive'])
> +filter = frozenset(['kmalloc_oob_in_memset',
> + 'kfree_sensitive', 'kvfree_sensitive'])
>  
>  def relevant(p):
>  return not (filter & {el.current_element for el in p})
> @@ -56,17 +57,13 @@ type T;
>  - memzero_explicit@m((T)E, size);
>... when != E
>when strict
> -// TODO: uncomment when kfree_sensitive will be merged.
> -// Only this case is commented out because developers
> -// may not like patches like this since kzfree uses memset
> -// internally (not memzero_explicit).
> -//(
> -//- kfree(E)@p;
> -//+ kfree_sensitive(E);
> -//|
> +(
> +- kfree(E)@p;
> ++ kfree_sensitive(E);
> +|
>  - \(vfree\|kvfree\)(E)@p;
>  + kvfree_sensitive(E, size);
> -//)
> +)
>  
>  @rp_memset depends on patch@
>  expression E, size;
> @@ -80,7 +77,7 @@ type T;
>when strict
>  (
>  - kfree(E)@p;
> -+ kzfree(E);
> ++ kfree_sensitive(E);
>  |
>  - \(vfree\|kvfree\)(E)@p;
>  + kvfree_sensitive(E, size);
> @@ -91,11 +88,11 @@ p << r.p;
>  @@
>  
>  coccilib.report.print_report(p[0],
> -  "WARNING: opportunity for kzfree/kvfree_sensitive")
> +  "WARNING: opportunity for kfree_sensitive/kvfree_sensitive")
>  
>  @script:python depends on org@
>  p << r.p;
>  @@
>  
>  coccilib.org.print_todo(p[0],
> -  "WARNING: opportunity for kzfree/kvfree_sensitive")
> +  "WARNING: opportunity for kfree_sensitive/kvfree_sensitive")
> 
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v2] coccinelle: api: add kobj_to_dev.cocci script

2020-08-21 Thread Denis Efremov
Use kobj_to_dev() instead of container_of().

Signed-off-by: Denis Efremov 
---
Changes in v2:
 - "symbol kobj;" added to the rule r

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

diff --git a/scripts/coccinelle/api/kobj_to_dev.cocci 
b/scripts/coccinelle/api/kobj_to_dev.cocci
new file mode 100644
index ..cd5d31c6fe76
--- /dev/null
+++ b/scripts/coccinelle/api/kobj_to_dev.cocci
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Use kobj_to_dev() instead of container_of()
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+// Keywords: kobj_to_dev, container_of
+//
+
+virtual context
+virtual report
+virtual org
+virtual patch
+
+
+@r depends on !patch@
+expression ptr;
+symbol kobj;
+position p;
+@@
+
+* container_of(ptr, struct device, kobj)@p
+
+
+@depends on patch@
+expression ptr;
+@@
+
+- container_of(ptr, struct device, kobj)
++ kobj_to_dev(ptr)
+
+
+@script:python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for kobj_to_dev()")
+
+@script:python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for kobj_to_dev()")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH] coccinelle: api: add kobj_to_dev.cocci script

2020-08-21 Thread Denis Efremov
Use kobj_to_dev() instead of container_of().

Signed-off-by: Denis Efremov 
---
Examples of such patches:
893c3d82b425 watchdog: Use kobj_to_dev() API
23fd63a44460 hwmon: (nct6683) Replace container_of() with  kobj_to_dev()
224941c9424f power: supply: use kobj_to_dev
a9b9b2af40c7 backlight: lm3533_bl: Use kobj_to_dev() instead
0acb47a3a093 qlcnic: Use kobj_to_dev() instead
97cd738c44c8 gpiolib: sysfs: use kobj_to_dev
d06f9e6c8960 hwmon: (nct7802) Replace container_of() API
036855a4c3b3 hwmon : (nct6775) Use kobj_to_dev() API
baf1d9c18293 driver/base/soc: Use kobj_to_dev() API
ae243ef0afbc rtc: sysfs: use kobj_to_dev
6b060d8a09e9 i2c: use kobj_to_dev() API
9e7bd945b9a9 scsi: core: use kobj_to_dev
0d730b57b95f s390/cio: use kobj_to_dev() API
0616ca73fd35 usb: use kobj_to_dev() API
8c9b839c0b80 alpha: use kobj_to_dev()
016c0bbae1d1 netxen: Use kobj_to_dev()
6908b45eafc4 GenWQE: use kobj_to_dev()
85f4f39c80e9 pch_phub: use kobj_to_dev()
47679cde604d misc: c2port: use kobj_to_dev()
85016ff33f35 misc: cxl: use kobj_to_dev()
092462c2b522 misc: eeprom: use kobj_to_dev()
a9c9d9aca4e7 zorro: Use kobj_to_dev()
a253f1eee6c4 rapidio: use kobj_to_dev()
e3837b00b6bb drm/radeon: use kobj_to_dev()
cc29ec874b37 drm/amdgpu: use kobj_to_dev()
d122cbf1a310 drm/sysfs: use kobj_to_dev()
657fb5fbadb3 drm/i915: use kobj_to_dev()
554a60379aaa PCI: Use kobj_to_dev() instead of open-coding it
2cf83833fc9c HID: use kobj_to_dev()
aeb7ed14fe5d bridge: use kobj_to_dev instead of to_dev
8e3829c61b48 staging:iio:adis16220: Use kobj_to_dev instead of open-coding it
b0d1f807f340 driver-core: Use kobj_to_dev instead of re-implementing it

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

diff --git a/scripts/coccinelle/api/kobj_to_dev.cocci 
b/scripts/coccinelle/api/kobj_to_dev.cocci
new file mode 100644
index ..e2cdd424aeca
--- /dev/null
+++ b/scripts/coccinelle/api/kobj_to_dev.cocci
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Use kobj_to_dev() instead of container_of()
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+// Keywords: kobj_to_dev, container_of
+//
+
+virtual context
+virtual report
+virtual org
+virtual patch
+
+
+@r depends on !patch@
+expression ptr;
+position p;
+@@
+
+* container_of(ptr, struct device, kobj)@p
+
+
+@depends on patch@
+expression ptr;
+@@
+
+- container_of(ptr, struct device, kobj)
++ kobj_to_dev(ptr)
+
+
+@script:python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for kobj_to_dev()")
+
+@script:python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for kobj_to_dev()")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [PATCH] coccinelle: api: add sprintf() support to device_attr_show

2020-08-14 Thread Denis Efremov


On 8/14/20 3:30 PM, Markus Elfring wrote:
>>> You propose to use a nested SmPL disjunction for desired adjustments.
>>> I suggest to start a corresponding case distinction behind
>>> the key word “return” instead of repeating it three times.
>>
>> It doesn't work.
> 
> How do you think about to apply a SmPL rule variant like the following?
> 
> @rp depends on patch@
> identifier show, dev, attr, buf;
> constant str;
> @@
> 
> ssize_t show(struct device *dev, struct device_attribute *attr, char *buf)
> {
>   <...
>   return
> (
> - snprintf
> + sprintf
>   (
>   buf,
> - \(PAGE_SIZE\|PAGE_SIZE - 1\),
> ( str
> |
> ( "%i"\|"%i\n"\|"%li"\|"%li\n"\|"%lli"\|"%lli\n"\|
>   "%d"\|"%d\n"\|"%ld"\|"%ld\n"\|"%lld"\|"%lld\n"\|
>   "%u"\|"%u\n"\|"%lu"\|"%lu\n"\|"%llu"\|"%llu\n"\|
>   "%x"\|"%x\n"\|"%lx"\|"%lx\n"\|"%llx"\|"%llx\n"\|
>   "%X"\|"%X\n"\|"%lX"\|"%lX\n"\|"%llX"\|"%llX\n"\|
>   
> "0x%x"\|"0x%x\n"\|"0x%lx"\|"0x%lx\n"\|"0x%llx"\|"0x%llx\n"\|
>   
> "0x%X"\|"0x%X\n"\|"0x%lX"\|"0x%lX\n"\|"0x%llX"\|"0x%llX\n"\|
>   "%02x\n"\|"%03x\n"\|"%04x\n"\|"%08x\n"\|
>   "%02X\n"\|"%03X\n"\|"%04X\n"\|"%08X\n"\|
>   "0x%02x\n"\|"0x%03x\n"\|"0x%04x\n"\|"0x%08x\n"\|
>   "0x%02X\n"\|"0x%03X\n"\|"0x%04X\n"\|"0x%08X\n"\|
>   "%zd"\|"%zd\n"\|"%zu"\|"%zu\n"\|"%zx"\|"%zx\n"\|
>   "%c"\|"%c\n"\|"%p"\|"%p\n"\|"%pU\n"\|"%pUl\n"\|"%hu\n"
> ) ,
>   ...
> )
>   )
> |
> - snprintf
> + scnprintf
>   (...)
> );
>   ...>
> }
> 

3 levels of nested disjunctions makes this pattern completely unreadable
and gives no comparable benefits. I don't think we should care much about
number of characters in the kernel sources, gzip will do a better job
anyway.


Thanks,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [PATCH] coccinelle: api: add sprintf() support to device_attr_show

2020-08-14 Thread Denis Efremov
Hi,

Markus, I think that CCing new people and spam them with mails they
are obviously not interested in doesn't bring an additional value to
the discussion. linux-kernel and cocci mailing lists are enough
in my opinion. This also will allow us to keep "threaded" mail
order.

On 8/14/20 11:30 AM, Markus Elfring wrote:
>> Interesting enough that with this patch coccinelle starts to skip
>> patch generation in some cases. For example, it skips patch for
>> drivers/base/core.c This is an unexpected result for me.
> 
> Would you like to point questionable differences for such patch hunks out?

Without this patch the script generates:
$ spatch -D patch --no-includes --include-headers --cocci-file 
scripts/coccinelle/api/device_attr_show.cocci drivers/base/core.c
--- drivers/base/core.c
+++ /tmp/cocci-output-63510-2f17ff-core.c
@@ -1713,7 +1713,7 @@ ssize_t device_show_ulong(struct device
char *buf)
{
struct dev_ext_attribute *ea = to_ext_attr(attr);
-   return snprintf(buf, PAGE_SIZE, "%lx\n", *(unsigned long *)(ea->var));
+   return scnprintf(buf, PAGE_SIZE, "%lx\n", *(unsigned long *)(ea->var));
}
EXPORT_SYMBOL_GPL(device_show_ulong);

@@ -1743,7 +1743,7 @@ ssize_t device_show_int(struct device *d
{
struct dev_ext_attribute *ea = to_ext_attr(attr);

-   return snprintf(buf, PAGE_SIZE, "%d\n", *(int *)(ea->var));
+   return scnprintf(buf, PAGE_SIZE, "%d\n", *(int *)(ea->var));
}
EXPORT_SYMBOL_GPL(device_show_int);

@@ -1764,7 +1764,7 @@ ssize_t device_show_bool(struct device *
{
struct dev_ext_attribute *ea = to_ext_attr(attr);

-   return snprintf(buf, PAGE_SIZE, "%d\n", *(bool *)(ea->var));
+   return scnprintf(buf, PAGE_SIZE, "%d\n", *(bool *)(ea->var));
}
EXPORT_SYMBOL_GPL(device_show_bool);

With this patch it generates nothing. I would expect spatch to generate
a different patch with sprintf instead of scnprintf, because I think 
... is enough to match "*(int *)(ea->var)". Even if it can't match sprintf
pattern it should fallback to scnprintf pattern.

> You propose to use a nested SmPL disjunction for desired adjustments.
> I suggest to start a corresponding case distinction behind
> the key word “return” instead of repeating it three times.

It doesn't work.

Thanks,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH] coccinelle: api: add sprintf() support to device_attr_show

2020-08-13 Thread Denis Efremov
It's safe to use sprintf() for simple cases in device_attr_show
type of functions. Add support for sprintf() in patch mode to
the device_attr_show.cocci script to print numbers and pointers.

Signed-off-by: Denis Efremov 
---
Interesting enough that with this patch coccinelle starts to skip
patch generation in some cases. For example, it skips patch for
drivers/base/core.c This is an unexpected result for me.

 scripts/coccinelle/api/device_attr_show.cocci | 30 +++
 1 file changed, 30 insertions(+)

diff --git a/scripts/coccinelle/api/device_attr_show.cocci 
b/scripts/coccinelle/api/device_attr_show.cocci
index d8ec4bb8ac41..1248b8c76cfe 100644
--- a/scripts/coccinelle/api/device_attr_show.cocci
+++ b/scripts/coccinelle/api/device_attr_show.cocci
@@ -30,15 +30,45 @@ ssize_t show(struct device *dev, struct device_attribute 
*attr, char *buf)
 
 @rp depends on patch@
 identifier show, dev, attr, buf;
+constant str;
 @@
 
 ssize_t show(struct device *dev, struct device_attribute *attr, char *buf)
 {
<...
+(
+   return
+-  snprintf
++  sprintf
+   (buf,
+-  \(PAGE_SIZE\|PAGE_SIZE - 1\),
+   str);
+|
+   return
+-  snprintf
++  sprintf
+   (buf,
+-  \(PAGE_SIZE\|PAGE_SIZE - 1\),
+   \("%i"\|"%i\n"\|"%li"\|"%li\n"\|"%lli"\|"%lli\n"\|
+ "%d"\|"%d\n"\|"%ld"\|"%ld\n"\|"%lld"\|"%lld\n"\|
+ "%u"\|"%u\n"\|"%lu"\|"%lu\n"\|"%llu"\|"%llu\n"\|
+ "%x"\|"%x\n"\|"%lx"\|"%lx\n"\|"%llx"\|"%llx\n"\|
+ "%X"\|"%X\n"\|"%lX"\|"%lX\n"\|"%llX"\|"%llX\n"\|
+ 
"0x%x"\|"0x%x\n"\|"0x%lx"\|"0x%lx\n"\|"0x%llx"\|"0x%llx\n"\|
+ 
"0x%X"\|"0x%X\n"\|"0x%lX"\|"0x%lX\n"\|"0x%llX"\|"0x%llX\n"\|
+ "%02x\n"\|"%03x\n"\|"%04x\n"\|"%08x\n"\|
+ "%02X\n"\|"%03X\n"\|"%04X\n"\|"%08X\n"\|
+ "0x%02x\n"\|"0x%03x\n"\|"0x%04x\n"\|"0x%08x\n"\|
+ "0x%02X\n"\|"0x%03X\n"\|"0x%04X\n"\|"0x%08X\n"\|
+ "%zd"\|"%zd\n"\|"%zu"\|"%zu\n"\|"%zx"\|"%zx\n"\|
+ 
"%c"\|"%c\n"\|"%p"\|"%p\n"\|"%pU\n"\|"%pUl\n"\|"%hu\n"\),
+   ...);
+|
return
 -  snprintf
 +  scnprintf
(...);
+)
...>
 }
 
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [RFC PATCH] coccinelle: misc: add uninitialized_var.cocci script

2020-08-11 Thread Denis Efremov
Commit 63a0895d960a ("compiler: Remove uninitialized_var() macro") and
commit 4b19bec97c88 ("docs: deprecated.rst: Add uninitialized_var()")
removed uninitialized_var() and deprecated it.

The purpose of this script is to prevent new occurrences of open-coded
variants of uninitialized_var().

Cc: Kees Cook 
Cc: Gustavo A. R. Silva 
Signed-off-by: Denis Efremov 
---
List of warnings:
./lib/glob.c:48:31-39: WARNING: this kind of initialization is deprecated
./tools/testing/selftests/vm/userfaultfd.c:349:15-22: WARNING: this kind of 
initialization is deprecated
./drivers/block/drbd/drbd_vli.h:330:5-9: WARNING: this kind of initialization 
is deprecated
./drivers/char/hw_random/intel-rng.c:333:15-18: WARNING: this kind of 
initialization is deprecated
./drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c:316:7-10: WARNING: this 
kind of initialization is deprecated
./arch/x86/include/asm/paravirt_types.h:455:15-20: WARNING: this kind of 
initialization is deprecated
./arch/x86/include/asm/paravirt_types.h:455:30-35: WARNING: this kind of 
initialization is deprecated
./arch/x86/include/asm/paravirt_types.h:455:45-50: WARNING: this kind of 
initialization is deprecated
./arch/x86/include/asm/paravirt_types.h:475:15-20: WARNING: this kind of 
initialization is deprecated
./arch/x86/include/asm/paravirt_types.h:475:30-35: WARNING: this kind of 
initialization is deprecated
./arch/x86/include/asm/paravirt_types.h:476:2-7: WARNING: this kind of 
initialization isdeprecated
./arch/x86/include/asm/paravirt_types.h:476:17-22: WARNING: this kind of 
initialization is deprecated
./arch/x86/include/asm/paravirt_types.h:476:32-37: WARNING: this kind of 
initialization is deprecated

 .../coccinelle/misc/uninitialized_var.cocci   | 51 +++
 1 file changed, 51 insertions(+)
 create mode 100644 scripts/coccinelle/misc/uninitialized_var.cocci

diff --git a/scripts/coccinelle/misc/uninitialized_var.cocci 
b/scripts/coccinelle/misc/uninitialized_var.cocci
new file mode 100644
index ..e4787bc6ab9c
--- /dev/null
+++ b/scripts/coccinelle/misc/uninitialized_var.cocci
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// uninitialized_var() and its open-coded variations are
+/// deprecated. For details, see:
+/// Documentation/process/deprecated.rst
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+
+virtual context
+virtual report
+virtual org
+
+@r@
+identifier var;
+type T;
+position p;
+@@
+
+(
+* T var@p = var;
+|
+* T var@p = *(&(var));
+//|
+// TODO: Actually, I'm not sure about this pattern.
+// Looks like it's used in wireless drivers to determine
+// whether data belongs to the driver or not.
+// Here are all matches:
+// https://elixir.bootlin.com/linux/latest/source/net/mac802154/util.c#L14
+// 
https://elixir.bootlin.com/linux/latest/source/drivers/staging/wlan-ng/cfg80211.c#L48
+// 
https://elixir.bootlin.com/linux/latest/source/drivers/net/wireless/intersil/orinoco/cfg.c#L21
+// https://elixir.bootlin.com/linux/latest/source/net/mac80211/util.c#L37
+// 
https://elixir.bootlin.com/linux/latest/source/drivers/net/wireless/rndis_wlan.c#L544
+// * T *var@p = 
+)
+
+@script:python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0],
+  "WARNING: this kind of initialization is deprecated")
+
+@script:python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0],
+  "WARNING: this kind of initialization is deprecated")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH] coccinelle: api: update kzfree script to kfree_sensitive

2020-08-11 Thread Denis Efremov
Commit 453431a54934 ("mm, treewide: rename kzfree() to kfree_sensitive()")
renames kzfree to kfree_sensitive and uses memzero_explicit(...) instead of
memset(..., 0, ...) internally. Update cocci script to reflect these
changes.

Signed-off-by: Denis Efremov 
---
Julia, I think you can squash this commit with original script, or I can
resend the whole script since it's not merged to the mainline.

 .../{kzfree.cocci => kfree_sensitive.cocci}   | 29 +--
 1 file changed, 13 insertions(+), 16 deletions(-)
 rename scripts/coccinelle/api/{kzfree.cocci => kfree_sensitive.cocci} (70%)

diff --git a/scripts/coccinelle/api/kzfree.cocci 
b/scripts/coccinelle/api/kfree_sensitive.cocci
similarity index 70%
rename from scripts/coccinelle/api/kzfree.cocci
rename to scripts/coccinelle/api/kfree_sensitive.cocci
index 33625bd7cec9..e4a066a0b77d 100644
--- a/scripts/coccinelle/api/kzfree.cocci
+++ b/scripts/coccinelle/api/kfree_sensitive.cocci
@@ -1,13 +1,13 @@
 // SPDX-License-Identifier: GPL-2.0-only
 ///
-/// Use kzfree, kvfree_sensitive rather than memset or
-/// memzero_explicit followed by kfree
+/// Use kfree_sensitive, kvfree_sensitive rather than memset or
+/// memzero_explicit followed by kfree.
 ///
 // Confidence: High
 // Copyright: (C) 2020 Denis Efremov ISPRAS
 // Options: --no-includes --include-headers
 //
-// Keywords: kzfree, kvfree_sensitive
+// Keywords: kfree_sensitive, kvfree_sensitive
 //
 
 virtual context
@@ -18,7 +18,8 @@ virtual report
 @initialize:python@
 @@
 # kmalloc_oob_in_memset uses memset to explicitly trigger out-of-bounds access
-filter = frozenset(['kmalloc_oob_in_memset', 'kzfree', 'kvfree_sensitive'])
+filter = frozenset(['kmalloc_oob_in_memset',
+   'kfree_sensitive', 'kvfree_sensitive'])
 
 def relevant(p):
 return not (filter & {el.current_element for el in p})
@@ -56,17 +57,13 @@ type T;
 - memzero_explicit@m((T)E, size);
   ... when != E
   when strict
-// TODO: uncomment when kfree_sensitive will be merged.
-// Only this case is commented out because developers
-// may not like patches like this since kzfree uses memset
-// internally (not memzero_explicit).
-//(
-//- kfree(E)@p;
-//+ kfree_sensitive(E);
-//|
+(
+- kfree(E)@p;
++ kfree_sensitive(E);
+|
 - \(vfree\|kvfree\)(E)@p;
 + kvfree_sensitive(E, size);
-//)
+)
 
 @rp_memset depends on patch@
 expression E, size;
@@ -80,7 +77,7 @@ type T;
   when strict
 (
 - kfree(E)@p;
-+ kzfree(E);
++ kfree_sensitive(E);
 |
 - \(vfree\|kvfree\)(E)@p;
 + kvfree_sensitive(E, size);
@@ -91,11 +88,11 @@ p << r.p;
 @@
 
 coccilib.report.print_report(p[0],
-  "WARNING: opportunity for kzfree/kvfree_sensitive")
+  "WARNING: opportunity for kfree_sensitive/kvfree_sensitive")
 
 @script:python depends on org@
 p << r.p;
 @@
 
 coccilib.org.print_todo(p[0],
-  "WARNING: opportunity for kzfree/kvfree_sensitive")
+  "WARNING: opportunity for kfree_sensitive/kvfree_sensitive")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [PATCH v4] coccinelle: api: add kzfree script

2020-08-11 Thread Denis Efremov



On 8/11/20 2:45 AM, Eric Biggers wrote:
> On Fri, Jul 17, 2020 at 10:39:20PM +0200, Julia Lawall wrote:
>>
>>
>> On Fri, 17 Jul 2020, Denis Efremov wrote:
>>
>>> Check for memset()/memzero_explicit() followed by kfree()/vfree()/kvfree().
>>>
>>> Signed-off-by: Denis Efremov 
>>
>> Applied.
> 
> FYI, this new script is already outdated, since kzfree() has been renamed to
> kfree_sensitive().
> 

Ok, I will send an update.

Thanks,Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v2] coccinelle: misc: add flexible_array.cocci script

2020-08-09 Thread Denis Efremov
Commit 68e4cd17e218 ("docs: deprecated.rst: Add zero-length and one-element
arrays") marks one-element and zero-length arrays as deprecated. Kernel
code should always use "flexible array members" instead.

The script warns about one-element and zero-length arrays in structs.

Cc: Kees Cook 
Cc: Gustavo A. R. Silva 
Signed-off-by: Denis Efremov 
---
Changes in v2:
 - all uapi headers are now filtered-out. Unfortunately, coccinelle
   doesn't provide structure names in Location.current_element.
   For structures the field is always "something_else". Thus, there is
   no easy way to create a list of existing structures in uapi headers
   and suppress the warning only for them, but not for the newly added
   uapi structures.
 - The pattern doesn't require 2+ fields in a structure/union anymore.
   Now it also checks single field structures/unions.
 - The pattern simplified and now uses disjuction in array elements
   (Thanks, Markus)
 - Unions are removed from patch mode
 - one-element arrays are removed from patch mode. Correct patch may
   involve turning the array to a simple field instead of a flexible
   array.

On the current master branch, the rule generates:
 - context: https://gist.github.com/evdenis/e2b4323491f9eff35376372df07f723c
 - patch: https://gist.github.com/evdenis/46081da9d68ecefd07edc3769cebcf32

 scripts/coccinelle/misc/flexible_array.cocci | 88 
 1 file changed, 88 insertions(+)
 create mode 100644 scripts/coccinelle/misc/flexible_array.cocci

diff --git a/scripts/coccinelle/misc/flexible_array.cocci 
b/scripts/coccinelle/misc/flexible_array.cocci
new file mode 100644
index ..bf6dcda1783e
--- /dev/null
+++ b/scripts/coccinelle/misc/flexible_array.cocci
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Zero-length and one-element arrays are deprecated, see
+/// Documentation/process/deprecated.rst
+/// Flexible-array members should be used instead.
+///
+//
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS.
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual context
+virtual report
+virtual org
+virtual patch
+
+@initialize:python@
+@@
+def relevant(positions):
+for p in positions:
+if "uapi" in p.file:
+ return False
+return True
+
+@r depends on !patch@
+identifier name, array;
+type T;
+position p : script:python() { relevant(p) };
+@@
+
+(
+  struct name {
+...
+*   T array@p[\(0\|1\)];
+  };
+|
+  struct {
+...
+*   T array@p[\(0\|1\)];
+  };
+|
+  union name {
+...
+*   T array@p[\(0\|1\)];
+  };
+|
+  union {
+...
+*   T array@p[\(0\|1\)];
+  };
+)
+
+@depends on patch exists@
+identifier name, array;
+type T;
+position p : script:python() { relevant(p) };
+@@
+
+(
+  struct name {
+...
+T array@p[
+-   0
+];
+  };
+|
+  struct {
+...
+T array@p[
+-   0
+];
+  };
+)
+
+@script: python depends on report@
+p << r.p;
+@@
+
+msg = "WARNING: use flexible-array member instead"
+coccilib.report.print_report(p[0], msg)
+
+@script: python depends on org@
+p << r.p;
+@@
+
+msg = "WARNING: use flexible-array member instead"
+coccilib.org.print_todo(p, msg)
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [RFC PATCH] coccinelle: misc: add flexible_array.cocci script

2020-08-06 Thread Denis Efremov
Commit 68e4cd17e218 ("docs: deprecated.rst: Add zero-length and one-element
arrays") marks one-element and zero-length arrays as deprecated. Kernel
code should always use "flexible array members" instead.

The script warns about one-element and zero-length arrays in structs.

Cc: Kees Cook 
Cc: Gustavo A. R. Silva 
Signed-off-by: Denis Efremov 
---

Currently, it's just a draft. I've placed a number of questions in the
script and marked them as TODO. Kees, Gustavo, if you could help me with
my questions I think that this rule will be enough to close:
https://github.com/KSPP/linux/issues/76

BTW, I it's possible to not warn about files in uapi folder if
this is relevant. Do I need to do it in the script?

 scripts/coccinelle/misc/flexible_array.cocci | 158 +++
 1 file changed, 158 insertions(+)
 create mode 100644 scripts/coccinelle/misc/flexible_array.cocci

diff --git a/scripts/coccinelle/misc/flexible_array.cocci 
b/scripts/coccinelle/misc/flexible_array.cocci
new file mode 100644
index ..1e7165c79e60
--- /dev/null
+++ b/scripts/coccinelle/misc/flexible_array.cocci
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Zero-length and one-element arrays are deprecated, see
+/// Documentation/process/deprecated.rst
+/// Flexible-array members should be used instead.
+///
+//
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS.
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual context
+virtual report
+virtual org
+virtual patch
+
+@r depends on !patch@
+identifier name, size, array;
+// TODO: We can additionally restrict size and array to:
+// identifier size =~ ".*(num|len|count|size|ncpus).*";
+// identifier array !~ ".*(pad|reserved).*";
+// Do we need it?
+type TS, TA;
+position p;
+@@
+
+(
+  // This will also match: typedef struct name { ...
+  // However nested structs are not matched, i.e.:
+  //   struct name1 { struct name2 { int s; int a[0]; } st; int i; }
+  // will not be matched. Do we need to handle it?
+  struct name {
+...  // TODO: Maybe simple ... is enough? It will match structs with a
+TS size; // single field, e.g.
+...  // 
https://elixir.bootlin.com/linux/v5.8/source/arch/arm/include/uapi/asm/setup.h#L127
+(
+*TA array@p[0];
+|
+ // TODO: It seems that there are exception cases for array[1], e.g.
+ //  
https://elixir.bootlin.com/linux/v5.8/source/arch/powerpc/boot/rs6000.h#L152
+ //  
https://elixir.bootlin.com/linux/v5.8/source/include/uapi/linux/cdrom.h#L292
+ //  
https://elixir.bootlin.com/linux/v5.8/source/drivers/net/wireless/ath/ath6kl/usb.c#L108
+ // We could either drop array[1] checking from this rule or
+ // restrict array name with regexp and add, for example, an "allowlist"
+ // with struct names where we allow this code pattern.
+ // TODO: How to handle: u8 data[1][MAXLEN_PSTR6]; ?
+*TA array@p[1];
+)
+  };
+|
+  struct {
+...
+TS size;
+...
+(
+*TA array@p[0];
+|
+*TA array@p[1];
+)
+  };
+|
+  // TODO: do we need to handle unions?
+  union name {
+...
+TS size;
+...
+(
+*TA array@p[0];
+|
+*TA array@p[1];
+)
+  };
+|
+  union {
+...
+TS size;
+...
+(
+*TA array@p[0];
+|
+*TA array@p[1];
+)
+  };
+)
+
+// FIXME: Patch mode doesn't work as expected.
+// Coccinelle handles formatting incorrectly.
+// Patch mode in this rule should be disabled until
+// proper formatting will be supported.
+@depends on patch exists@
+identifier name, size, array;
+type TS, TA;
+@@
+
+(
+  struct name {
+...
+TS size;
+...
+(
+-TA array[0];
+|
+-TA array[1];
+)
++TA array[];
+  };
+|
+  struct {
+...
+TS size;
+...
+(
+-TA array[0];
+|
+-TA array[1];
+)
++TA array[];
+  };
+|
+  union name {
+...
+TS size;
+...
+(
+-TA array[0];
+|
+-TA array[1];
+)
++TA array[];
+  };
+|
+  union {
+...
+TS size;
+...
+(
+-TA array[0];
+|
+-TA array[1];
+)
++TA array[];
+  };
+)
+
+@script: python depends on report@
+p << r.p;
+@@
+
+msg = "WARNING: use flexible-array member instead"
+coccilib.report.print_report(p[0], msg)
+
+@script: python depends on org@
+p << r.p;
+@@
+
+msg = "WARNING: use flexible-array member instead"
+coccilib.org.print_todo(p, msg)
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v3] coccinelle: api: add kvmalloc script

2020-08-04 Thread Denis Efremov
Suggest kvmalloc, kvfree instead of opencoded patterns.

Signed-off-by: Denis Efremov 
---
Changes in v2:
 - binary operator cmp added
 - NULL comparisions simplified
 - "T x" case added to !patch mode
Changes in v3:
 - kvfree rules added

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

diff --git a/scripts/coccinelle/api/kvmalloc.cocci 
b/scripts/coccinelle/api/kvmalloc.cocci
new file mode 100644
index ..2cb9281cc092
--- /dev/null
+++ b/scripts/coccinelle/api/kvmalloc.cocci
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Find if/else condition with kmalloc/vmalloc calls.
+/// Suggest to use kvmalloc instead. Same for kvfree.
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+
+virtual patch
+virtual report
+virtual org
+virtual context
+
+@initialize:python@
+@@
+filter = frozenset(['kvfree'])
+
+def relevant(p):
+return not (filter & {el.current_element for el in p})
+
+@kvmalloc depends on !patch@
+expression E, E1, size;
+binary operator cmp = {<=, <, ==, >, >=};
+identifier x;
+type T;
+position p;
+@@
+
+(
+* if (size cmp E1 || ...)@p {
+...
+*E = \(kmalloc\|kzalloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+*  kmalloc_array\|kmalloc_array_node\|kcalloc_node\)(..., size, ...)
+...
+  } else {
+...
+*E = \(vmalloc\|vzalloc\|vmalloc_node\|vzalloc_node\)(..., size, ...)
+...
+  }
+|
+* E = \(kmalloc\|kzalloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+*   kmalloc_array\|kmalloc_array_node\|kcalloc_node\)(..., size, ...)
+  ... when != E = E1
+  when != size = E1
+  when any
+* if (E == NULL)@p {
+...
+*   E = \(vmalloc\|vzalloc\|vmalloc_node\|vzalloc_node\)(..., size, ...)
+...
+  }
+|
+* T x = \(kmalloc\|kzalloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+* kmalloc_array\|kmalloc_array_node\|kcalloc_node\)(..., size, ...);
+  ... when != x = E1
+  when != size = E1
+  when any
+* if (x == NULL)@p {
+...
+*   x = \(vmalloc\|vzalloc\|vmalloc_node\|vzalloc_node\)(..., size, ...)
+...
+  }
+)
+
+@kvfree depends on !patch@
+expression E;
+position p : script:python() { relevant(p) };
+@@
+
+* if (is_vmalloc_addr(E))@p {
+...
+*   vfree(E)
+...
+  } else {
+... when != krealloc(E, ...)
+when any
+*   \(kfree\|kzfree\)(E)
+...
+  }
+
+@depends on patch@
+expression E, E1, flags, size, node;
+binary operator cmp = {<=, <, ==, >, >=};
+identifier x;
+type T;
+@@
+
+(
+- if (size cmp E1)
+-E = kmalloc(size, flags);
+- else
+-E = vmalloc(size);
++ E = kvmalloc(size, flags);
+|
+- E = kmalloc(size, flags | __GFP_NOWARN);
+- if (E == NULL)
+-   E = vmalloc(size);
++ E = kvmalloc(size, flags);
+|
+- T x = kmalloc(size, flags | __GFP_NOWARN);
+- if (x == NULL)
+-   x = vmalloc(size);
++ T x = kvmalloc(size, flags);
+|
+- if (size cmp E1)
+-E = kzalloc(size, flags);
+- else
+-E = vzalloc(size);
++ E = kvzalloc(size, flags);
+|
+- E = kzalloc(size, flags | __GFP_NOWARN);
+- if (E == NULL)
+-   E = vzalloc(size);
++ E = kvzalloc(size, flags);
+|
+- T x = kzalloc(size, flags | __GFP_NOWARN);
+- if (x == NULL)
+-   x = vzalloc(size);
++ T x = kvzalloc(size, flags);
+|
+- if (size cmp E1)
+-E = kmalloc_node(size, flags, node);
+- else
+-E = vmalloc_node(size, node);
++ E = kvmalloc_node(size, flags, node);
+|
+- E = kmalloc_node(size, flags | __GFP_NOWARN, node);
+- if (E == NULL)
+-   E = vmalloc_node(size, node);
++ E = kvmalloc_node(size, flags, node);
+|
+- T x = kmalloc_node(size, flags | __GFP_NOWARN, node);
+- if (x == NULL)
+-   x = vmalloc_node(size, node);
++ T x = kvmalloc_node(size, flags, node);
+|
+- if (size cmp E1)
+-E = kvzalloc_node(size, flags, node);
+- else
+-E = vzalloc_node(size, node);
++ E = kvzalloc_node(size, flags, node);
+|
+- E = kvzalloc_node(size, flags | __GFP_NOWARN, node);
+- if (E == NULL)
+-   E = vzalloc_node(size, node);
++ E = kvzalloc_node(size, flags, node);
+|
+- T x = kvzalloc_node(size, flags | __GFP_NOWARN, node);
+- if (x == NULL)
+-   x = vzalloc_node(size, node);
++ T x = kvzalloc_node(size, flags, node);
+)
+
+@depends on patch@
+expression E;
+position p : script:python() { relevant(p) };
+@@
+
+- if (is_vmalloc_addr(E))@p
+-   vfree(E);
+- else
+-   kfree(E);
++ kvfree(E);
+
+@script: python depends on report@
+p << kvmalloc.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING: opportunity for kvmalloc")
+
+@script: python depends on org@
+p << kvmalloc.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING: opportunity for kvmalloc")
+
+@script: python depends on report@
+p << kvfree.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING: opportunity for kvfree")
+
+@script: python depends on org@
+p << 

[Cocci] [PATCH v2] coccinelle: api: add kvmalloc script

2020-08-03 Thread Denis Efremov
Suggest kvmalloc instead of opencoded kmalloc && vmalloc condition.

Signed-off-by: Denis Efremov 
---
Changes in v2:
 - binary operator cmp added
 - NULL comparisions simplified
 - "T x" case added to !patch mode

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

diff --git a/scripts/coccinelle/api/kvmalloc.cocci 
b/scripts/coccinelle/api/kvmalloc.cocci
new file mode 100644
index ..20b22e3d0f74
--- /dev/null
+++ b/scripts/coccinelle/api/kvmalloc.cocci
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Find if/else condition with kmalloc/vmalloc calls.
+/// Suggest to use kvmalloc instead.
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+
+virtual patch
+virtual report
+virtual org
+virtual context
+
+@opportunity depends on !patch@
+expression E, E1, size;
+binary operator cmp = {<=, <, ==, >, >=};
+identifier x;
+type T;
+position p;
+@@
+
+(
+* if (size cmp E1 || ...)@p {
+...
+*E = \(kmalloc\|kzalloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+*  kmalloc_array\|kmalloc_array_node\|kcalloc_node\)(..., size, ...)
+...
+  } else {
+...
+*E = \(vmalloc\|vzalloc\|vmalloc_node\|vzalloc_node\)(..., size, ...)
+...
+  }
+|
+* E = \(kmalloc\|kzalloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+*   kmalloc_array\|kmalloc_array_node\|kcalloc_node\)(..., size, ...)
+  ... when != E = E1
+  when != size = E1
+  when any
+* if (E == NULL)@p {
+...
+*   E = \(vmalloc\|vzalloc\|vmalloc_node\|vzalloc_node\)(..., size, ...)
+...
+  }
+|
+* T x = \(kmalloc\|kzalloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+* kmalloc_array\|kmalloc_array_node\|kcalloc_node\)(..., size, ...);
+  ... when != x = E1
+  when != size = E1
+  when any
+* if (x == NULL)@p {
+...
+*   x = \(vmalloc\|vzalloc\|vmalloc_node\|vzalloc_node\)(..., size, ...)
+...
+  }
+)
+
+@depends on patch@
+expression E, E1, flags, size, node;
+binary operator cmp = {<=, <, ==, >, >=};
+identifier x;
+type T;
+@@
+
+(
+- if (size cmp E1)
+-E = kmalloc(size, flags);
+- else
+-E = vmalloc(size);
++ E = kvmalloc(size, flags);
+|
+- E = kmalloc(size, flags | __GFP_NOWARN);
+- if (E == NULL)
+-   E = vmalloc(size);
++ E = kvmalloc(size, flags);
+|
+- T x = kmalloc(size, flags | __GFP_NOWARN);
+- if (x == NULL)
+-   x = vmalloc(size);
++ T x = kvmalloc(size, flags);
+|
+- if (size cmp E1)
+-E = kzalloc(size, flags);
+- else
+-E = vzalloc(size);
++ E = kvzalloc(size, flags);
+|
+- E = kzalloc(size, flags | __GFP_NOWARN);
+- if (E == NULL)
+-   E = vzalloc(size);
++ E = kvzalloc(size, flags);
+|
+- T x = kzalloc(size, flags | __GFP_NOWARN);
+- if (x == NULL)
+-   x = vzalloc(size);
++ T x = kvzalloc(size, flags);
+|
+- if (size cmp E1)
+-E = kmalloc_node(size, flags, node);
+- else
+-E = vmalloc_node(size, node);
++ E = kvmalloc_node(size, flags, node);
+|
+- E = kmalloc_node(size, flags | __GFP_NOWARN, node);
+- if (E == NULL)
+-   E = vmalloc_node(size, node);
++ E = kvmalloc_node(size, flags, node);
+|
+- T x = kmalloc_node(size, flags | __GFP_NOWARN, node);
+- if (x == NULL)
+-   x = vmalloc_node(size, node);
++ T x = kvmalloc_node(size, flags, node);
+|
+- if (size cmp E1)
+-E = kvzalloc_node(size, flags, node);
+- else
+-E = vzalloc_node(size, node);
++ E = kvzalloc_node(size, flags, node);
+|
+- E = kvzalloc_node(size, flags | __GFP_NOWARN, node);
+- if (E == NULL)
+-   E = vzalloc_node(size, node);
++ E = kvzalloc_node(size, flags, node);
+|
+- T x = kvzalloc_node(size, flags | __GFP_NOWARN, node);
+- if (x == NULL)
+-   x = vzalloc_node(size, node);
++ T x = kvzalloc_node(size, flags, node);
+)
+
+@script: python depends on report@
+p << opportunity.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING: opportunity for kvmalloc")
+
+@script: python depends on org@
+p << opportunity.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING: opportunity for kvmalloc")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v7] coccinelle: api: add kfree_mismatch script

2020-08-03 Thread Denis Efremov
Check that alloc and free types of functions match each other.

Signed-off-by: Denis Efremov 
---
Changes in v2:
 - Lines are limited to 80 characters where possible
 - Confidence changed from High to Medium because of 
   fs/btrfs/send.c:1119 false-positive
 - __vmalloc_area_node() explicitly excluded from analysis
   instead of !(file in "mm/vmalloc.c") condition
Changes in v3:
 - prints style in org && report modes changed for python2
Changes in v4:
 - missing msg argument to print_todo fixed
Changes in v5:
 - fix position p in kfree rule
 - move @kok and @v positions in choice rule after the arguments
 - remove kvmalloc suggestions
Changes in v6:
 - more asterisks added in context mode
 - second @kok added to the choice rule
Changes in v7:
 - file renamed to kfree_mismatch.cocci
 - python function relevant() removed
 - additional rule for filtering free positions added
 - btrfs false-positive fixed
 - confidence level changed to high
 - kvfree_switch rule added
 - names for position variables changed to @a (alloc) and @f (free)

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

diff --git a/scripts/coccinelle/api/kfree_mismatch.cocci 
b/scripts/coccinelle/api/kfree_mismatch.cocci
new file mode 100644
index ..9e9ef9fd7a25
--- /dev/null
+++ b/scripts/coccinelle/api/kfree_mismatch.cocci
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Check that kvmalloc'ed memory is freed by kfree functions,
+/// vmalloc'ed by vfree functions and kvmalloc'ed by kvfree
+/// functions.
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+
+virtual patch
+virtual report
+virtual org
+virtual context
+
+@alloc@
+expression E, E1;
+position kok, vok;
+@@
+
+(
+  if (...) {
+...
+E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|
+  kmalloc_node\|kzalloc_node\|kmalloc_array\|
+  kmalloc_array_node\|kcalloc_node\)(...)@kok
+...
+  } else {
+...
+E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|
+  vzalloc_node\|vmalloc_exec\|vmalloc_32\|
+  vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|
+  __vmalloc_node\)(...)@vok
+...
+  }
+|
+  E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+kmalloc_array\|kmalloc_array_node\|kcalloc_node\)(...)@kok
+  ... when != E = E1
+  when any
+  if (E == NULL) {
+...
+E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|
+  vzalloc_node\|vmalloc_exec\|vmalloc_32\|
+  vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|
+  __vmalloc_node\)(...)@vok
+...
+  }
+)
+
+@free@
+expression E;
+position fok;
+@@
+
+  E = \(kvmalloc\|kvzalloc\|kvcalloc\|kvzalloc_node\|kvmalloc_node\|
+kvmalloc_array\)(...)
+  ...
+  kvfree(E)@fok
+
+@vfree depends on !patch@
+expression E;
+position a != alloc.kok;
+position f != free.fok;
+@@
+
+* E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|
+*   kzalloc_node\|kmalloc_array\|kmalloc_array_node\|
+*   kcalloc_node\)(...)@a
+  ... when != if (...) { ... E = 
\(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|__vmalloc_node\)(...);
 ... }
+  when != is_vmalloc_addr(E)
+  when any
+* \(vfree\|vfree_atomic\|kvfree\)(E)@f
+
+@depends on patch exists@
+expression E;
+position a != alloc.kok;
+position f != free.fok;
+@@
+
+  E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|
+kzalloc_node\|kmalloc_array\|kmalloc_array_node\|
+kcalloc_node\)(...)@a
+  ... when != if (...) { ... E = 
\(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|__vmalloc_node\)(...);
 ... }
+  when != is_vmalloc_addr(E)
+  when any
+- \(vfree\|vfree_atomic\|kvfree\)(E)@f
++ kfree(E)
+
+@kfree depends on !patch@
+expression E;
+position a != alloc.vok;
+position f != free.fok;
+@@
+
+* E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|
+*   vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|
+*   __vmalloc_node_range\|__vmalloc_node\)(...)@a
+  ... when != is_vmalloc_addr(E)
+  when any
+* \(kfree\|kzfree\|kvfree\)(E)@f
+
+@depends on patch exists@
+expression E;
+position a != alloc.vok;
+position f != free.fok;
+@@
+
+  E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|
+vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|
+__vmalloc_node_range\|__vmalloc_node\)(...)@a
+  ... when != is_vmalloc_addr(E)
+  when any
+- \(kfree\|kvfree\)(E)@f
++ vfree(E)
+
+@kvfree depends on !patch@
+expression E;
+position a, f;
+@@
+
+* E = \(kvmalloc\|kvzalloc\|kvcalloc\|kvzalloc_node\|kvmalloc_node\|
+*   kvmalloc_array\)(...)@a
+  ... when !=

Re: [Cocci] [PATCH v6] coccinelle: api: add kvfree script

2020-08-03 Thread Denis Efremov
Is there a difference from cocci point of view between:

... when != !is_vmalloc_addr(E)

and 

... when != is_vmalloc_addr(E)

Should the latter one be used in most cases?

Thanks,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [PATCH v6] coccinelle: api: add kvfree script

2020-08-03 Thread Denis Efremov



On 8/2/20 11:24 PM, Julia Lawall wrote:
>> +@initialize:python@
>> +@@
>> +# low-level memory api
>> +filter = frozenset(['__vmalloc_area_node'])
>> +
>> +def relevant(p):
>> +return not (filter & {el.current_element for el in p})
> 
> Is this used?

I'll remove it in v8. Or do you want me to add iterate_dir_item() in the list?

> 
> Otherwise, I think it would be good to not warn about a use of kvfree
> if that use is reachable from a kvmalloc.  There seems to be such a false
> positive in fs/btrfs/send.c, on line 1118.

I don't know how to handle this case without position filter.
It's too complex. In iterate_dir_item() there is:
buf = kmalloc(buf_len, GFP_KERNEL);
while(...) {
if (...) {
if (is_vmalloc_addr(buf)) {
vfree(buf);
...
} else {
char *tmp = krealloc(buf, ...);

if (!tmp)
kfree(buf);
...
}
if (!buf) {
buf = kvmalloc(buf_len, GFP_KERNEL);
...
}
}
}
kvfree(buf);

Adding "when != kvfree(E)" is not enough:
* E = \(kvmalloc\|kvzalloc\|kvcalloc\|kvzalloc_node\|kvmalloc_node\|
*   kvmalloc_array\)(...)@k
... when != is_vmalloc_addr(E)
+   when != kvfree(E)
when any
* \(kfree\|kzfree\|vfree\|vfree_atomic\)(E)@p

> 
> It also seems that when there are both a kmalloc and a vmalloc, there is
> no warning if kfree or vfree is used.  Is that intentional?
> 

No, I will try to address it in v8.

Regards,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH] coccinelle: api: add kvmalloc script

2020-08-03 Thread Denis Efremov
Suggest kvmalloc instead of opencoded kmalloc && vmalloc condition.

Signed-off-by: Denis Efremov 
---

If coccinelle fails with "Segmentation fault" during analysis, then
one needs to increase stack limit, e.g. ulimit -s 32767.

Current, I've sent only one patch for this rule and will send the rest
after the merge window. https://lkml.org/lkml/2020/7/31/986

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

diff --git a/scripts/coccinelle/api/kvmalloc.cocci 
b/scripts/coccinelle/api/kvmalloc.cocci
new file mode 100644
index ..76d6aeab7c09
--- /dev/null
+++ b/scripts/coccinelle/api/kvmalloc.cocci
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Find conditions in code for kmalloc/vmalloc calls.
+/// Suggest to use kvmalloc instead.
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+
+virtual patch
+virtual report
+virtual org
+virtual context
+
+@opportunity depends on !patch@
+expression E, E1, size;
+position p;
+@@
+
+(
+* if (\(size <= E1\|size < E1\|size == E1\|size > E1\) || ...)@p {
+...
+*E = \(kmalloc\|kzalloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+*  kmalloc_array\|kmalloc_array_node\|kcalloc_node\)(..., size, ...)
+...
+  } else {
+...
+*E = \(vmalloc\|vzalloc\|vmalloc_node\|vzalloc_node\)(..., size, ...)
+...
+  }
+|
+* E = \(kmalloc\|kzalloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+*   kmalloc_array\|kmalloc_array_node\|kcalloc_node\)(..., size, ...)
+  ... when != E = E1
+  when != size = E1
+  when any
+* if (\(!E\|E == NULL\))@p {
+...
+*   E = \(vmalloc\|vzalloc\|vmalloc_node\|vzalloc_node\)(..., size, ...)
+...
+  }
+)
+
+@depends on patch@
+expression E, E1, flags, size, node;
+identifier x;
+type T;
+@@
+
+(
+- if (\(size <= E1\|size < E1\|size == E1\|size > E1\))
+-E = kmalloc(size, flags);
+- else
+-E = vmalloc(size);
++ E = kvmalloc(size, flags);
+|
+- E = kmalloc(size, flags | __GFP_NOWARN);
+- if (\(!E\|E == NULL\))
+-   E = vmalloc(size);
++ E = kvmalloc(size, flags);
+|
+- T x = kmalloc(size, flags | __GFP_NOWARN);
+- if (\(!x\|x == NULL\))
+-   x = vmalloc(size);
++ T x = kvmalloc(size, flags);
+|
+- if (\(size <= E1\|size < E1\|size == E1\|size > E1\))
+-E = kzalloc(size, flags);
+- else
+-E = vzalloc(size);
++ E = kvzalloc(size, flags);
+|
+- E = kzalloc(size, flags | __GFP_NOWARN);
+- if (\(!E\|E == NULL\))
+-   E = vzalloc(size);
++ E = kvzalloc(size, flags);
+|
+- T x = kzalloc(size, flags | __GFP_NOWARN);
+- if (\(!x\|x == NULL\))
+-   x = vzalloc(size);
++ T x = kvzalloc(size, flags);
+|
+- if (\(size <= E1\|size < E1\|size == E1\|size > E1\))
+-E = kmalloc_node(size, flags, node);
+- else
+-E = vmalloc_node(size, node);
++ E = kvmalloc_node(size, flags, node);
+|
+- E = kmalloc_node(size, flags | __GFP_NOWARN, node);
+- if (\(!E\|E == NULL\))
+-   E = vmalloc_node(size, node);
++ E = kvmalloc_node(size, flags, node);
+|
+- T x = kmalloc_node(size, flags | __GFP_NOWARN, node);
+- if (\(!x\|x == NULL\))
+-   x = vmalloc_node(size, node);
++ T x = kvmalloc_node(size, flags, node);
+|
+- if (\(size <= E1\|size < E1\|size == E1\|size > E1\))
+-E = kvzalloc_node(size, flags, node);
+- else
+-E = vzalloc_node(size, node);
++ E = kvzalloc_node(size, flags, node);
+|
+- E = kvzalloc_node(size, flags | __GFP_NOWARN, node);
+- if (\(!E\|E == NULL\))
+-   E = vzalloc_node(size, node);
++ E = kvzalloc_node(size, flags, node);
+|
+- T x = kvzalloc_node(size, flags | __GFP_NOWARN, node);
+- if (\(!x\|x == NULL\))
+-   x = vzalloc_node(size, node);
++ T x = kvzalloc_node(size, flags, node);
+)
+
+@script: python depends on report@
+p << opportunity.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING: opportunity for kvmalloc")
+
+@script: python depends on org@
+p << opportunity.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING: opportunity for kvmalloc")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v6] coccinelle: api: add kvfree script

2020-07-31 Thread Denis Efremov
Check that alloc and free types of functions match each other.

Signed-off-by: Denis Efremov 
---
Changes in v2:
 - Lines are limited to 80 characters where possible
 - Confidence changed from High to Medium because of 
   fs/btrfs/send.c:1119 false-positive
 - __vmalloc_area_node() explicitly excluded from analysis
   instead of !(file in "mm/vmalloc.c") condition
Changes in v3:
 - prints style in org && report modes changed for python2
Changes in v4:
 - missing msg argument to print_todo fixed
Changes in v5:
 - fix position p in kfree rule
 - move @kok and @v positions in choice rule after the arguments
 - remove kvmalloc suggestions
Changes in v6:
 - more asterisks added in context mode
 - second @kok added to the choice rule

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

diff --git a/scripts/coccinelle/api/kvfree.cocci 
b/scripts/coccinelle/api/kvfree.cocci
new file mode 100644
index ..f43cda5b0d5b
--- /dev/null
+++ b/scripts/coccinelle/api/kvfree.cocci
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Check that kvmalloc'ed memory is freed by kfree functions,
+/// vmalloc'ed by vfree functions and kvmalloc'ed by kvfree
+/// functions.
+///
+// Confidence: Medium
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+
+virtual patch
+virtual report
+virtual org
+virtual context
+
+@initialize:python@
+@@
+# low-level memory api
+filter = frozenset(['__vmalloc_area_node'])
+
+def relevant(p):
+return not (filter & {el.current_element for el in p})
+
+@choice@
+expression E, E1;
+position kok, vok;
+@@
+
+(
+  if (...) {
+...
+E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|
+  kmalloc_node\|kzalloc_node\|kmalloc_array\|
+  kmalloc_array_node\|kcalloc_node\)(...)@kok
+...
+  } else {
+...
+E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|
+  vzalloc_node\|vmalloc_exec\|vmalloc_32\|
+  vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|
+  __vmalloc_node\)(...)@vok
+...
+  }
+|
+  E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+kmalloc_array\|kmalloc_array_node\|kcalloc_node\)(...)@kok
+  ... when != E = E1
+  when any
+  if (\(!E\|E == NULL\)) {
+...
+E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|
+  vzalloc_node\|vmalloc_exec\|vmalloc_32\|
+  vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|
+  __vmalloc_node\)(...)@vok
+...
+  }
+)
+
+@vfree depends on !patch@
+expression E;
+position k != choice.kok;
+position p;
+@@
+
+* E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|
+*   kzalloc_node\|kmalloc_array\|kmalloc_array_node\|
+*   kcalloc_node\)(...)@k
+  ... when != if (...) { ... E = 
\(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|__vmalloc_node\)(...);
 ... }
+  when != is_vmalloc_addr(E)
+  when any
+* \(vfree\|vfree_atomic\|kvfree\)(E)@p
+
+@pvfree depends on patch exists@
+expression E;
+position k != choice.kok;
+@@
+
+  E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|
+kzalloc_node\|kmalloc_array\|kmalloc_array_node\|
+kcalloc_node\)(...)@k
+  ... when != if (...) { ... E = 
\(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|__vmalloc_node\)(...);
 ... }
+  when != is_vmalloc_addr(E)
+  when any
+- \(vfree\|vfree_atomic\|kvfree\)(E)
++ kfree(E)
+
+@kfree depends on !patch@
+expression E;
+position v != choice.vok;
+position p;
+@@
+
+* E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|
+*   vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|
+*   __vmalloc_node_range\|__vmalloc_node\)(...)@v
+  ... when != !is_vmalloc_addr(E)
+  when any
+* \(kfree\|kzfree\|kvfree\)(E)@p
+
+@pkfree depends on patch exists@
+expression E;
+position v != choice.vok;
+@@
+
+  E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|
+vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|
+__vmalloc_node_range\|__vmalloc_node\)(...)@v
+  ... when != !is_vmalloc_addr(E)
+  when any
+- \(kfree\|kvfree\)(E)
++ vfree(E)
+
+@kvfree depends on !patch@
+expression E;
+position p, k;
+@@
+
+* E = \(kvmalloc\|kvzalloc\|kvcalloc\|kvzalloc_node\|kvmalloc_node\|
+*   kvmalloc_array\)(...)@k
+  ... when != is_vmalloc_addr(E)
+  when any
+* \(kfree\|kzfree\|vfree\|vfree_atomic\)(E)@p
+
+@pkvfree depends on patch exists@
+expression E;
+@@
+
+  E = \(kvmalloc\|kvzalloc\|kvcalloc\|kvzalloc_node\|kvmalloc_node\|
+kvmalloc_array\)(...)
+  ... when != is_vmalloc_addr(E)
+  when any
+- \(kfree\|vfree\)(E)
++ kvfree(E)
+
+@script: python depends on report@
+k << vfree.

[Cocci] Match variable declaration with init expression

2020-07-31 Thread Denis Efremov
Hi,

This pattern:
- E = kzalloc(size, flags | __GFP_NOWARN);
- if (\(!E\|E == null\))@p
-   E = vzalloc(size);
+ E = kvzalloc(size, flags);

matches this code:
void *p;
p = kzalloc(size, gfp | __GFP_NOWARN);

if (!p)
p = vzalloc(size);

But not this:
void *p = kzalloc(size, gfp | __GFP_NOWARN);

if (!p)
p = vzalloc(size);

What can I do to match them both?

Thanks,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v5] coccinelle: api: add kvfree script

2020-07-31 Thread Denis Efremov
Check that alloc and free types of functions match each other.

Signed-off-by: Denis Efremov 
---
Changes in v2:
 - Lines are limited to 80 characters where possible
 - Confidence changed from High to Medium because of 
   fs/btrfs/send.c:1119 false-positive
 - __vmalloc_area_node() explicitly excluded from analysis
   instead of !(file in "mm/vmalloc.c") condition
Changes in v3:
 - prints style in org && report modes changed for python2
Changes in v4:
 - missing msg argument to print_todo fixed
Changes in v5:
 - fix position p in kfree rule
 - move @kok and @v positions in choice rule after the arguments
 - remove kvmalloc suggestions

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

diff --git a/scripts/coccinelle/api/kvfree.cocci 
b/scripts/coccinelle/api/kvfree.cocci
new file mode 100644
index ..e83b1ebbad7e
--- /dev/null
+++ b/scripts/coccinelle/api/kvfree.cocci
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Check that kvmalloc'ed memory is freed by kfree functions,
+/// vmalloc'ed by vfree functions and kvmalloc'ed by kvfree
+/// functions.
+///
+// Confidence: Medium
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+
+virtual patch
+virtual report
+virtual org
+virtual context
+
+@initialize:python@
+@@
+# low-level memory api
+filter = frozenset(['__vmalloc_area_node'])
+
+def relevant(p):
+return not (filter & {el.current_element for el in p})
+
+@choice@
+expression E, E1;
+position kok, vok;
+@@
+
+(
+  if (...) {
+...
+E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|
+  kmalloc_node\|kzalloc_node\|kmalloc_array\|
+  kmalloc_array_node\|kcalloc_node\)(...)@kok
+...
+  } else {
+...
+E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|
+  vzalloc_node\|vmalloc_exec\|vmalloc_32\|
+  vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|
+  __vmalloc_node\)(...)@vok
+...
+  }
+|
+  E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+kmalloc_array\|kmalloc_array_node\|kcalloc_node\)(...)
+  ... when != E = E1
+  when any
+  if (\(!E\|E == NULL\)) {
+...
+E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|
+  vzalloc_node\|vmalloc_exec\|vmalloc_32\|
+  vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|
+  __vmalloc_node\)(...)@vok
+...
+  }
+)
+
+@vfree depends on !patch@
+expression E;
+position k != choice.kok;
+position p;
+@@
+
+* E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|
+kzalloc_node\|kmalloc_array\|kmalloc_array_node\|
+kcalloc_node\)(...)@k
+  ... when != if (...) { ... E = 
\(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|__vmalloc_node\)(...);
 ... }
+  when != is_vmalloc_addr(E)
+  when any
+* \(vfree\|vfree_atomic\|kvfree\)(E)@p
+
+@pvfree depends on patch exists@
+expression E;
+position k != choice.kok;
+@@
+
+  E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|
+kzalloc_node\|kmalloc_array\|kmalloc_array_node\|
+kcalloc_node\)(...)@k
+  ... when != if (...) { ... E = 
\(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|__vmalloc_node\)(...);
 ... }
+  when != is_vmalloc_addr(E)
+  when any
+- \(vfree\|vfree_atomic\|kvfree\)(E)
++ kfree(E)
+
+@kfree depends on !patch@
+expression E;
+position v != choice.vok;
+position p;
+@@
+
+* E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|
+vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|
+__vmalloc_node_range\|__vmalloc_node\)(...)@v
+  ... when != !is_vmalloc_addr(E)
+  when any
+* \(kfree\|kzfree\|kvfree\)(E)@p
+
+@pkfree depends on patch exists@
+expression E;
+position v != choice.vok;
+@@
+
+  E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|
+vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|
+__vmalloc_node_range\|__vmalloc_node\)(...)@v
+  ... when != !is_vmalloc_addr(E)
+  when any
+- \(kfree\|kvfree\)(E)
++ vfree(E)
+
+@kvfree depends on !patch@
+expression E;
+position p, k;
+@@
+
+* E = \(kvmalloc\|kvzalloc\|kvcalloc\|kvzalloc_node\|kvmalloc_node\|
+kvmalloc_array\)(...)@k
+  ... when != is_vmalloc_addr(E)
+  when any
+* \(kfree\|kzfree\|vfree\|vfree_atomic\)(E)@p
+
+@pkvfree depends on patch exists@
+expression E;
+@@
+
+  E = \(kvmalloc\|kvzalloc\|kvcalloc\|kvzalloc_node\|kvmalloc_node\|
+kvmalloc_array\)(...)
+  ... when != is_vmalloc_addr(E)
+  when any
+- \(kfree\|vfree\)(E)
++ kvfree(E)
+
+@script: python depends on report@
+k << vfree.k;
+p << vfree.p;
+@@
+
+msg = "WARNING: kmalloc is used to allocat

Re: [Cocci] [PATCH v4] coccinelle: api: add kvfree script

2020-07-31 Thread Denis Efremov



> With the current patch mode, I got some changes in a recent linux-next.
> Have you sent patches for these issues?

For mellanox, I've sent these patches:
https://lkml.org/lkml/2020/6/5/901
https://lkml.org/lkml/2020/6/1/713
They were accepted.

I see two new places in mellanox driver in linux-next. It looks like this
is new code that is not yet merged to the linux master branch.

diff -u -p a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c 
b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c
@@ -228,8 +228,8 @@ static int rx_fs_create(struct mlx5e_pri
fs_prot->miss_rule = miss_rule;

out:
-   kfree(flow_group_in);
-   kfree(spec);
+   kvfree(flow_group_in);
+   kvfree(spec);
return err;
}

diff -u -p a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/fs_tcp.c 
b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/fs_tcp.c
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/fs_tcp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/fs_tcp.c
@@ -191,7 +191,7 @@ static int accel_fs_tcp_create_groups(st
ft->g = kcalloc(MLX5E_ACCEL_FS_TCP_NUM_GROUPS, sizeof(*ft->g), GFP_KERNEL);
in = kvzalloc(inlen, GFP_KERNEL);
if  (!in || !ft->g) {
-   kvfree(ft->g);
+   kfree(ft->g);
kvfree(in);
return -ENOMEM;
}

I will send the fixes when the code will be merged to the linux master branch.
Maybe it will be fixed already in net-next at that time.

> 
> Do the checks for the opportunities for kvmalloc really belong in this
> rule?  That issue is not mentioned in the commit log or the description of
> the semantic patch.

I added this at the last moment. It was easy enough to add it based on existing
patterns. I will add description for this warnings. Or do you want me to single
out this warning to a separate rule?


Regards,
Denis


___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v4] coccinelle: api: add kvfree script

2020-07-30 Thread Denis Efremov
Check that alloc and free types of functions match each other.

Signed-off-by: Denis Efremov 
---
Changes in v2:
 - Lines are limited to 80 characters where possible
 - Confidence changed from High to Medium because of 
   fs/btrfs/send.c:1119 false-positive
 - __vmalloc_area_node() explicitly excluded from analysis
   instead of !(file in "mm/vmalloc.c") condition
Changes in v3:
 - prints style in org && report modes changed for python2
Changes in v4:
 - missing msg argument to print_todo fixed

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

diff --git a/scripts/coccinelle/api/kvfree.cocci 
b/scripts/coccinelle/api/kvfree.cocci
new file mode 100644
index ..d73578c5549c
--- /dev/null
+++ b/scripts/coccinelle/api/kvfree.cocci
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Check that kvmalloc'ed memory is freed by kfree functions,
+/// vmalloc'ed by vfree functions and kvmalloc'ed by kvfree
+/// functions.
+///
+// Confidence: Medium
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+
+virtual patch
+virtual report
+virtual org
+virtual context
+
+@initialize:python@
+@@
+# low-level memory api
+filter = frozenset(['__vmalloc_area_node'])
+
+def relevant(p):
+return not (filter & {el.current_element for el in p})
+
+@choice@
+expression E, E1;
+position kok, vok;
+@@
+
+(
+  if (...) {
+...
+E = \(kmalloc@kok\|kzalloc@kok\|krealloc@kok\|kcalloc@kok\|
+  kmalloc_node@kok\|kzalloc_node@kok\|kmalloc_array@kok\|
+  kmalloc_array_node@kok\|kcalloc_node@kok\)(...)
+...
+  } else {
+...
+E = \(vmalloc@vok\|vzalloc@vok\|vmalloc_user@vok\|vmalloc_node@vok\|
+  vzalloc_node@vok\|vmalloc_exec@vok\|vmalloc_32@vok\|
+  vmalloc_32_user@vok\|__vmalloc@vok\|__vmalloc_node_range@vok\|
+  __vmalloc_node@vok\)(...)
+...
+  }
+|
+  E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+kmalloc_array\|kmalloc_array_node\|kcalloc_node\)(...)
+  ... when != E = E1
+  when any
+  if (\(!E\|E == NULL\)) {
+...
+E = \(vmalloc@vok\|vzalloc@vok\|vmalloc_user@vok\|vmalloc_node@vok\|
+  vzalloc_node@vok\|vmalloc_exec@vok\|vmalloc_32@vok\|
+  vmalloc_32_user@vok\|__vmalloc@vok\|__vmalloc_node_range@vok\|
+  __vmalloc_node@vok\)(...)
+...
+  }
+)
+
+@opportunity depends on !patch@
+expression E, E1, size;
+position p : script:python() { relevant(p) };
+@@
+
+(
+* if (\(size <= E1\|size < E1\|size = E1\|size > E1\) || ...)@p {
+...
+E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+  kmalloc_array\|kmalloc_array_node\|kcalloc_node\)(..., size, ...)
+...
+  } else {
+...
+E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|
+  vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|
+  __vmalloc_node_range\|__vmalloc_node\)(..., size, ...)
+...
+  }
+|
+  E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+kmalloc_array\|kmalloc_array_node\|kcalloc_node\)(..., size, ...)
+  ... when != E = E1
+  when != size = E1
+  when any
+* if (\(!E\|E == NULL\))@p {
+...
+E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|
+  vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|
+  __vmalloc_node_range\|__vmalloc_node\)(..., size, ...)
+...
+  }
+)
+
+@vfree depends on !patch@
+expression E;
+position k != choice.kok;
+position p;
+@@
+
+* E = \(kmalloc@k\|kzalloc@k\|krealloc@k\|kcalloc@k\|kmalloc_node@k\|
+kzalloc_node@k\|kmalloc_array@k\|kmalloc_array_node@k\|
+kcalloc_node@k\)(...)
+  ... when != if (...) { ... E = 
\(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|__vmalloc_node\)(...);
 ... }
+  when != is_vmalloc_addr(E)
+  when any
+* \(vfree\|vfree_atomic\|kvfree\)(E)@p
+
+@pvfree depends on patch exists@
+expression E;
+position k != choice.kok;
+@@
+
+  E = \(kmalloc@k\|kzalloc@k\|krealloc@k\|kcalloc@k\|kmalloc_node@k\|
+kzalloc_node@k\|kmalloc_array@k\|kmalloc_array_node@k\|
+kcalloc_node@k\)(...)
+  ... when != if (...) { ... E = 
\(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|__vmalloc_node\)(...);
 ... }
+  when != is_vmalloc_addr(E)
+  when any
+- \(vfree\|vfree_atomic\|kvfree\)(E)
++ kfree(E)
+
+@kfree depends on !patch@
+expression E;
+position v != choice.vok;
+position p;
+@@
+
+* E = \(vmalloc@v\|vzalloc@v\|vmalloc_user@v\|vmalloc_node@v\|vzalloc_node@v\|
+vmalloc_exec@v\|vmalloc_32@v\|vmalloc_32_user@v\|__vmalloc@v\|
+__vmalloc_node_range@v\|__vmalloc_node@v\)(...)
+ 

Re: [Cocci] [PATCH v3] coccinelle: api: add kvfree script

2020-07-30 Thread Denis Efremov


> +
> +@script: python depends on org@
> +v << kfree.v;
> +p << kfree.p;
> +@@
> +
> +msg = "WARNING: vmalloc is used to allocate this memory at line %s" % 
> (v[0].line)
> +coccilib.org.print_todo(p[0],

Just noticed this error. I will resend the patch in 5mins.

Regards,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v3] coccinelle: api: add kvfree script

2020-07-30 Thread Denis Efremov
Check that alloc and free types of functions match each other.

Signed-off-by: Denis Efremov 
---
Changes in v2:
 - Lines are limited to 80 characters where possible
 - Confidence changed from High to Medium because of 
   fs/btrfs/send.c:1119 false-positive
 - __vmalloc_area_node() explicitly excluded from analysis
   instead of !(file in "mm/vmalloc.c") condition
Changes in v3:
 - prints style in org && report modes changed for python2

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

diff --git a/scripts/coccinelle/api/kvfree.cocci 
b/scripts/coccinelle/api/kvfree.cocci
new file mode 100644
index ..7c396daeacad
--- /dev/null
+++ b/scripts/coccinelle/api/kvfree.cocci
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Check that kvmalloc'ed memory is freed by kfree functions,
+/// vmalloc'ed by vfree functions and kvmalloc'ed by kvfree
+/// functions.
+///
+// Confidence: Medium
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+
+virtual patch
+virtual report
+virtual org
+virtual context
+
+@initialize:python@
+@@
+# low-level memory api
+filter = frozenset(['__vmalloc_area_node'])
+
+def relevant(p):
+return not (filter & {el.current_element for el in p})
+
+@choice@
+expression E, E1;
+position kok, vok;
+@@
+
+(
+  if (...) {
+...
+E = \(kmalloc@kok\|kzalloc@kok\|krealloc@kok\|kcalloc@kok\|
+  kmalloc_node@kok\|kzalloc_node@kok\|kmalloc_array@kok\|
+  kmalloc_array_node@kok\|kcalloc_node@kok\)(...)
+...
+  } else {
+...
+E = \(vmalloc@vok\|vzalloc@vok\|vmalloc_user@vok\|vmalloc_node@vok\|
+  vzalloc_node@vok\|vmalloc_exec@vok\|vmalloc_32@vok\|
+  vmalloc_32_user@vok\|__vmalloc@vok\|__vmalloc_node_range@vok\|
+  __vmalloc_node@vok\)(...)
+...
+  }
+|
+  E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+kmalloc_array\|kmalloc_array_node\|kcalloc_node\)(...)
+  ... when != E = E1
+  when any
+  if (\(!E\|E == NULL\)) {
+...
+E = \(vmalloc@vok\|vzalloc@vok\|vmalloc_user@vok\|vmalloc_node@vok\|
+  vzalloc_node@vok\|vmalloc_exec@vok\|vmalloc_32@vok\|
+  vmalloc_32_user@vok\|__vmalloc@vok\|__vmalloc_node_range@vok\|
+  __vmalloc_node@vok\)(...)
+...
+  }
+)
+
+@opportunity depends on !patch@
+expression E, E1, size;
+position p : script:python() { relevant(p) };
+@@
+
+(
+* if (\(size <= E1\|size < E1\|size = E1\|size > E1\) || ...)@p {
+...
+E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+  kmalloc_array\|kmalloc_array_node\|kcalloc_node\)(..., size, ...)
+...
+  } else {
+...
+E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|
+  vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|
+  __vmalloc_node_range\|__vmalloc_node\)(..., size, ...)
+...
+  }
+|
+  E = \(kmalloc\|kzalloc\|krealloc\|kcalloc\|kmalloc_node\|kzalloc_node\|
+kmalloc_array\|kmalloc_array_node\|kcalloc_node\)(..., size, ...)
+  ... when != E = E1
+  when != size = E1
+  when any
+* if (\(!E\|E == NULL\))@p {
+...
+E = \(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|
+  vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|
+  __vmalloc_node_range\|__vmalloc_node\)(..., size, ...)
+...
+  }
+)
+
+@vfree depends on !patch@
+expression E;
+position k != choice.kok;
+position p;
+@@
+
+* E = \(kmalloc@k\|kzalloc@k\|krealloc@k\|kcalloc@k\|kmalloc_node@k\|
+kzalloc_node@k\|kmalloc_array@k\|kmalloc_array_node@k\|
+kcalloc_node@k\)(...)
+  ... when != if (...) { ... E = 
\(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|__vmalloc_node\)(...);
 ... }
+  when != is_vmalloc_addr(E)
+  when any
+* \(vfree\|vfree_atomic\|kvfree\)(E)@p
+
+@pvfree depends on patch exists@
+expression E;
+position k != choice.kok;
+@@
+
+  E = \(kmalloc@k\|kzalloc@k\|krealloc@k\|kcalloc@k\|kmalloc_node@k\|
+kzalloc_node@k\|kmalloc_array@k\|kmalloc_array_node@k\|
+kcalloc_node@k\)(...)
+  ... when != if (...) { ... E = 
\(vmalloc\|vzalloc\|vmalloc_user\|vmalloc_node\|vzalloc_node\|vmalloc_exec\|vmalloc_32\|vmalloc_32_user\|__vmalloc\|__vmalloc_node_range\|__vmalloc_node\)(...);
 ... }
+  when != is_vmalloc_addr(E)
+  when any
+- \(vfree\|vfree_atomic\|kvfree\)(E)
++ kfree(E)
+
+@kfree depends on !patch@
+expression E;
+position v != choice.vok;
+position p;
+@@
+
+* E = \(vmalloc@v\|vzalloc@v\|vmalloc_user@v\|vmalloc_node@v\|vzalloc_node@v\|
+vmalloc_exec@v\|vmalloc_32@v\|vmalloc_32_user@v\|__vmalloc@v\|
+__vmalloc_node_range@v\|__vmalloc_node@v\)(...)
+  ... when != !is_vmalloc_addr(E)
+  when any
+* \(kfree\|kzfree\

[Cocci] [PATCH v3 1/3] coccinelle: api: extend memdup_user transformation with GFP_USER

2020-07-20 Thread Denis Efremov
Match GFP_USER and optional __GFP_NOWARN allocations with
memdup_user.cocci rule.
Commit 6c2c97a24f09 ("memdup_user(): switch to GFP_USER") switched
memdup_user() from GFP_KERNEL to GFP_USER. In almost all cases it
is still a good idea to recommend memdup_user() for GFP_KERNEL
allocations. The motivation behind altering memdup_user() to GFP_USER:
https://lkml.org/lkml/2018/1/6/333

Signed-off-by: Denis Efremov 
---
 scripts/coccinelle/api/memdup_user.cocci | 8 ++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/scripts/coccinelle/api/memdup_user.cocci 
b/scripts/coccinelle/api/memdup_user.cocci
index c809ab10bbce..0e29d41ecab8 100644
--- a/scripts/coccinelle/api/memdup_user.cocci
+++ b/scripts/coccinelle/api/memdup_user.cocci
@@ -20,7 +20,9 @@ expression from,to,size;
 identifier l1,l2;
 @@
 
--  to = \(kmalloc\|kzalloc\)(size,GFP_KERNEL);
+-  to = \(kmalloc\|kzalloc\)
+-  (size,\(GFP_KERNEL\|GFP_USER\|
+-\(GFP_KERNEL\|GFP_USER\)|__GFP_NOWARN\));
 +  to = memdup_user(from,size);
if (
 -  to==NULL
@@ -43,7 +45,9 @@ position p;
 statement S1,S2;
 @@
 
-*  to = \(kmalloc@p\|kzalloc@p\)(size,GFP_KERNEL);
+*  to = \(kmalloc@p\|kzalloc@p\)
+   (size,\(GFP_KERNEL\|GFP_USER\|
+ \(GFP_KERNEL\|GFP_USER\)|__GFP_NOWARN\));
if (to==NULL || ...) S1
if (copy_from_user(to, from, size) != 0)
S2
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v3 3/3] coccinelle: api: filter out memdup_user definitions

2020-07-20 Thread Denis Efremov
Don't match memdup_user/vmemdup_user.

Signed-off-by: Denis Efremov 
---
 scripts/coccinelle/api/memdup_user.cocci | 17 +
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/scripts/coccinelle/api/memdup_user.cocci 
b/scripts/coccinelle/api/memdup_user.cocci
index 60027e21c5e6..e01e95108405 100644
--- a/scripts/coccinelle/api/memdup_user.cocci
+++ b/scripts/coccinelle/api/memdup_user.cocci
@@ -15,12 +15,20 @@ virtual context
 virtual org
 virtual report
 
+@initialize:python@
+@@
+filter = frozenset(['memdup_user', 'vmemdup_user'])
+
+def relevant(p):
+return not (filter & {el.current_element for el in p})
+
 @depends on patch@
 expression from,to,size;
 identifier l1,l2;
+position p : script:python() { relevant(p) };
 @@
 
--  to = \(kmalloc\|kzalloc\)
+-  to = \(kmalloc@p\|kzalloc@p\)
 -  (size,\(GFP_KERNEL\|GFP_USER\|
 -\(GFP_KERNEL\|GFP_USER\)|__GFP_NOWARN\));
 +  to = memdup_user(from,size);
@@ -42,9 +50,10 @@ identifier l1,l2;
 @depends on patch@
 expression from,to,size;
 identifier l1,l2;
+position p : script:python() { relevant(p) };
 @@
 
--  to = \(kvmalloc\|kvzalloc\)(size,\(GFP_KERNEL\|GFP_USER\));
+-  to = \(kvmalloc@p\|kvzalloc@p\)(size,\(GFP_KERNEL\|GFP_USER\));
 +  to = vmemdup_user(from,size);
if (
 -  to==NULL
@@ -63,7 +72,7 @@ identifier l1,l2;
 
 @r depends on !patch@
 expression from,to,size;
-position p;
+position p : script:python() { relevant(p) };
 statement S1,S2;
 @@
 
@@ -76,7 +85,7 @@ statement S1,S2;
 
 @rv depends on !patch@
 expression from,to,size;
-position p;
+position p : script:python() { relevant(p) };
 statement S1,S2;
 @@
 
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v3 0/3] Update memdup_user.cocci

2020-07-20 Thread Denis Efremov
Add GFP_USER to the allocation flags and handle vmemdup_user().

Changes in v2:
 - memdup_user/vmemdup_user matching suppressed
 - PoC for selfcheck virtual rule
Changes in v3:
 - add missing '-' for patch rule in kmalloc/kzalloc call args
 - selfcheck rule dropped from patchset

Denis Efremov (3):
  coccinelle: api: extend memdup_user transformation with GFP_USER
  coccinelle: api: extend memdup_user rule with vmemdup_user()
  coccinelle: api: filter out memdup_user definitions

 scripts/coccinelle/api/memdup_user.cocci | 64 ++--
 1 file changed, 61 insertions(+), 3 deletions(-)

-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v3 2/3] coccinelle: api: extend memdup_user rule with vmemdup_user()

2020-07-20 Thread Denis Efremov
Add vmemdup_user() transformations to the memdup_user.cocci rule.
Commit 50fd2f298bef ("new primitive: vmemdup_user()") introduced
vmemdup_user(). The function uses kvmalloc with GPF_USER flag.

Signed-off-by: Denis Efremov 
---
 scripts/coccinelle/api/memdup_user.cocci | 45 
 1 file changed, 45 insertions(+)

diff --git a/scripts/coccinelle/api/memdup_user.cocci 
b/scripts/coccinelle/api/memdup_user.cocci
index 0e29d41ecab8..60027e21c5e6 100644
--- a/scripts/coccinelle/api/memdup_user.cocci
+++ b/scripts/coccinelle/api/memdup_user.cocci
@@ -39,6 +39,28 @@ identifier l1,l2;
 -...+>
 -  }
 
+@depends on patch@
+expression from,to,size;
+identifier l1,l2;
+@@
+
+-  to = \(kvmalloc\|kvzalloc\)(size,\(GFP_KERNEL\|GFP_USER\));
++  to = vmemdup_user(from,size);
+   if (
+-  to==NULL
++  IS_ERR(to)
+ || ...) {
+   <+... when != goto l1;
+-  -ENOMEM
++  PTR_ERR(to)
+   ...+>
+   }
+-  if (copy_from_user(to, from, size) != 0) {
+-<+... when != goto l2;
+--EFAULT
+-...+>
+-  }
+
 @r depends on !patch@
 expression from,to,size;
 position p;
@@ -52,6 +74,17 @@ statement S1,S2;
if (copy_from_user(to, from, size) != 0)
S2
 
+@rv depends on !patch@
+expression from,to,size;
+position p;
+statement S1,S2;
+@@
+
+*  to = \(kvmalloc@p\|kvzalloc@p\)(size,\(GFP_KERNEL\|GFP_USER\));
+   if (to==NULL || ...) S1
+   if (copy_from_user(to, from, size) != 0)
+   S2
+
 @script:python depends on org@
 p << r.p;
 @@
@@ -63,3 +96,15 @@ p << r.p;
 @@
 
 coccilib.report.print_report(p[0], "WARNING opportunity for memdup_user")
+
+@script:python depends on org@
+p << rv.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING opportunity for vmemdup_user")
+
+@script:python depends on report@
+p << rv.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for vmemdup_user")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [v2 1/4] coccinelle: api: extend memdup_user transformation with GFP_USER

2020-07-18 Thread Denis Efremov
Hi,

On 7/18/20 9:45 AM, Julia Lawall wrote:
> This on is indeed a problem.  I think it was not detected in testing,
> because in the current kernel the rule never applies.  But Denis, in
> 
> -  to = \(kmalloc\|kzalloc\)
> (size,\(GFP_KERNEL\|GFP_USER\|
>   \(GFP_KERNEL\|GFP_USER\)|__GFP_NOWARN\));
> 
> you do indeed need to put - in front of the second and third lines as
> well.

Thanks, Markus, Julia. I will send v3. Julia, is it ok with you, if I will
drop the last patch with "selfcheck" this time?

Regards,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [PATCH v2] coccinelle: api: add kvfree script

2020-07-17 Thread Denis Efremov
Ping?
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [PATCH v2 0/4] Update memdup_user.cocci

2020-07-17 Thread Denis Efremov
Ping?

On 6/8/20 6:00 PM, Denis Efremov wrote:
> Add GFP_USER to the allocation flags and handle vmemdup_user().
> The third patch supresses memdup_user(), vmemdup_user() functions
> detection. Last patch is a proof of concept for the rule selfchecking.
> Gives the ability to detect that an open-coded pattern in a function
> definition that we search for in the kernel sources changed.
> 
> Denis Efremov (4):
>   coccinelle: api: extend memdup_user transformation with GFP_USER
>   coccinelle: api: extend memdup_user rule with vmemdup_user()
>   coccinelle: api: filter out memdup_user definitions
>   coccinelle: api: add selfcheck for memdup_user rule
> 
>  scripts/coccinelle/api/memdup_user.cocci | 106 ++-
>  1 file changed, 103 insertions(+), 3 deletions(-)
> 
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v4] coccinelle: api: add kzfree script

2020-07-17 Thread Denis Efremov
Check for memset()/memzero_explicit() followed by kfree()/vfree()/kvfree().

Signed-off-by: Denis Efremov 
---
Changes in v2:
 - memset_explicit() added
 - kvfree_sensitive() added
 - forall added to r1
 - ... between memset and kfree added
Changes in v3:
 - Explicit filter for definitions instead of !(file in "...") conditions
 - type T added to match casts
 - memzero_explicit() patterns fixed
 - additional rule "cond" added to filter false-positives
Changes in v4:
 - memset call fixed in rp_memset
 - @m added to rp_memset,rp_memzero rules

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

diff --git a/scripts/coccinelle/api/kzfree.cocci 
b/scripts/coccinelle/api/kzfree.cocci
new file mode 100644
index ..33625bd7cec9
--- /dev/null
+++ b/scripts/coccinelle/api/kzfree.cocci
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Use kzfree, kvfree_sensitive rather than memset or
+/// memzero_explicit followed by kfree
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+// Keywords: kzfree, kvfree_sensitive
+//
+
+virtual context
+virtual patch
+virtual org
+virtual report
+
+@initialize:python@
+@@
+# kmalloc_oob_in_memset uses memset to explicitly trigger out-of-bounds access
+filter = frozenset(['kmalloc_oob_in_memset', 'kzfree', 'kvfree_sensitive'])
+
+def relevant(p):
+return not (filter & {el.current_element for el in p})
+
+@cond@
+position ok;
+@@
+
+if (...)
+  \(memset@ok\|memzero_explicit@ok\)(...);
+
+@r depends on !patch forall@
+expression E;
+position p : script:python() { relevant(p) };
+position m != cond.ok;
+type T;
+@@
+
+(
+* memset@m((T)E, 0, ...);
+|
+* memzero_explicit@m((T)E, ...);
+)
+  ... when != E
+  when strict
+* \(kfree\|vfree\|kvfree\)(E)@p;
+
+@rp_memzero depends on patch@
+expression E, size;
+position p : script:python() { relevant(p) };
+position m != cond.ok;
+type T;
+@@
+
+- memzero_explicit@m((T)E, size);
+  ... when != E
+  when strict
+// TODO: uncomment when kfree_sensitive will be merged.
+// Only this case is commented out because developers
+// may not like patches like this since kzfree uses memset
+// internally (not memzero_explicit).
+//(
+//- kfree(E)@p;
+//+ kfree_sensitive(E);
+//|
+- \(vfree\|kvfree\)(E)@p;
++ kvfree_sensitive(E, size);
+//)
+
+@rp_memset depends on patch@
+expression E, size;
+position p : script:python() { relevant(p) };
+position m != cond.ok;
+type T;
+@@
+
+- memset@m((T)E, 0, size);
+  ... when != E
+  when strict
+(
+- kfree(E)@p;
++ kzfree(E);
+|
+- \(vfree\|kvfree\)(E)@p;
++ kvfree_sensitive(E, size);
+)
+
+@script:python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0],
+  "WARNING: opportunity for kzfree/kvfree_sensitive")
+
+@script:python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0],
+  "WARNING: opportunity for kzfree/kvfree_sensitive")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v4] coccinelle: misc: add array_size_dup script to detect missed overflow checks

2020-06-22 Thread Denis Efremov
Detect an opencoded expression that is used before or after
array_size()/array3_size()/struct_size() to compute the same size.

Signed-off-by: Denis Efremov 
---
Changes in v2:
 - python rules moved next to SmPL patterns
 - assignment operator used
 - struct_size patterns fixed to check only E3, since
   E1, E2 are sizeofs of a structure and a member
   of a structure
Changes in v3:
 - s/overlow/overflow/ typo fixed (thanks, Markus)
 - \(\|\) changed to &\(E1\|E2\)
 - print strings breaks removed
Changes in v4:
 - duplicates warning removed
 - python2 compatability in report& modes added
 - s/down the code/later/ warning changed
 - \(E1\|E2\|subE1\|subE2\) patterns simplified to \(subE1\|subE2\)

 scripts/coccinelle/misc/array_size_dup.cocci | 209 +++
 1 file changed, 209 insertions(+)
 create mode 100644 scripts/coccinelle/misc/array_size_dup.cocci

diff --git a/scripts/coccinelle/misc/array_size_dup.cocci 
b/scripts/coccinelle/misc/array_size_dup.cocci
new file mode 100644
index ..d3d635b2d4fc
--- /dev/null
+++ b/scripts/coccinelle/misc/array_size_dup.cocci
@@ -0,0 +1,209 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Check for array_size(), array3_size(), struct_size() duplicates.
+/// Three types of patterns for these functions:
+///  1. An opencoded expression is used before array_size() to compute the 
same size
+///  2. An opencoded expression is used after array_size() to compute the same 
size
+/// From security point of view only first case is relevant. These functions
+/// perform arithmetic overflow check. Thus, if we use an opencoded expression
+/// before a call to the *_size() function we can miss an overflow.
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers --no-loops
+
+virtual context
+virtual report
+virtual org
+
+@as@
+expression E1, E2;
+@@
+
+array_size(E1, E2)
+
+@as_next@
+expression subE1 <= as.E1;
+expression subE2 <= as.E2;
+expression as.E1, as.E2, E3;
+assignment operator aop;
+position p1, p2;
+@@
+
+* E1 * E2@p1
+  ... when != \(subE1\|subE2\) aop E3
+  when != &\(subE1\|subE2\)
+* array_size(E1, E2)@p2
+
+@script:python depends on report@
+p1 << as_next.p1;
+p2 << as_next.p2;
+@@
+
+msg = "WARNING: array_size is used later (line %s) to compute the same size" % 
(p2[0].line)
+coccilib.report.print_report(p1[0], msg)
+
+@script:python depends on org@
+p1 << as_next.p1;
+p2 << as_next.p2;
+@@
+
+msg = "WARNING: array_size is used later (line %s) to compute the same size" % 
(p2[0].line)
+coccilib.org.print_todo(p1[0], msg)
+
+@as_prev@
+expression subE1 <= as.E1;
+expression subE2 <= as.E2;
+expression as.E1, as.E2, E3;
+assignment operator aop;
+position p1, p2;
+@@
+
+* array_size(E1, E2)@p1
+  ... when != \(subE1\|subE2\) aop E3
+  when != &\(subE1\|subE2\)
+* E1 * E2@p2
+
+@script:python depends on report@
+p1 << as_prev.p1;
+p2 << as_prev.p2;
+@@
+
+msg = "WARNING: array_size is already used (line %s) to compute the same size" 
% (p1[0].line)
+coccilib.report.print_report(p2[0], msg)
+
+@script:python depends on org@
+p1 << as_prev.p1;
+p2 << as_prev.p2;
+@@
+
+msg = "WARNING: array_size is already used (line %s) to compute the same size" 
% (p1[0].line)
+coccilib.org.print_todo(p2[0], msg)
+
+@as3@
+expression E1, E2, E3;
+@@
+
+array3_size(E1, E2, E3)
+
+@as3_next@
+expression subE1 <= as3.E1;
+expression subE2 <= as3.E2;
+expression subE3 <= as3.E3;
+expression as3.E1, as3.E2, as3.E3, E4;
+assignment operator aop;
+position p1, p2;
+@@
+
+* E1 * E2 * E3@p1
+  ... when != \(subE1\|subE2\|subE3\) aop E4
+  when != &\(subE1\|subE2\|subE3\)
+* array3_size(E1, E2, E3)@p2
+
+@script:python depends on report@
+p1 << as3_next.p1;
+p2 << as3_next.p2;
+@@
+
+msg = "WARNING: array3_size is used later (line %s) to compute the same size" 
% (p2[0].line)
+coccilib.report.print_report(p1[0], msg)
+
+@script:python depends on org@
+p1 << as3_next.p1;
+p2 << as3_next.p2;
+@@
+
+msg = "WARNING: array3_size is used later (line %s) to compute the same size" 
% (p2[0].line)
+coccilib.org.print_todo(p1[0], msg)
+
+@as3_prev@
+expression subE1 <= as3.E1;
+expression subE2 <= as3.E2;
+expression subE3 <= as3.E3;
+expression as3.E1, as3.E2, as3.E3, E4;
+assignment operator aop;
+position p1, p2;
+@@
+
+* array3_size(E1, E2, E3)@p1
+  ... when != \(subE1\|subE2\|subE3\) aop E4
+  when != &\(subE1\|subE2\|subE3\)
+* E1 * E2 * E3@p2
+
+@script:python depends on report@
+p1 << as3_prev.p1;
+p2 << as3_prev.p2;
+@@
+
+msg = "WARNING: array3_size is already used (line %s) to compute the same 
size" % (p1[0].line)
+coccilib.report.print_report(p2[0], msg)
+
+@script:python depends on org@
+p1 << as3_prev.p1;
+p2 << as3_prev.p2;
+@@
+
+msg = "WARNING: array3_

Re: [Cocci] [PATCH v3] coccinelle: misc: add array_size_dup script to detect missed overflow checks

2020-06-22 Thread Denis Efremov
What do you think about removing duplicates warning from the rule?

I mean this kind of warnings: "WARNING: same array_size (line {p1[0].line})"

As for now, I think it's better to not disturb developers with this kind
of things.

Thanks,
Denis

>> +@as_dup@
>> +expression subE1 <= as.E1;
>> +expression subE2 <= as.E2;
>> +expression as.E1, as.E2, E3;
>> +assignment operator aop;
>> +position p1, p2;
>> +@@
>> +
>> +* array_size(E1, E2)@p1
>> +  ... when != \(E1\|E2\|subE1\|subE2\) aop E3
>> +  when != &\(E1\|E2\|subE1\|subE2\)
>> +* array_size(E1, E2)@p2
>> +
>> +@script:python depends on report@
>> +p1 << as_dup.p1;
>> +p2 << as_dup.p2;
>> +@@
>> +
>> +coccilib.report.print_report(p2[0],
>> +f"WARNING: same array_size (line {p1[0].line})")
>> +
>> +@script:python depends on org@
>> +p1 << as_dup.p1;
>> +p2 << as_dup.p2;
>> +@@
>> +
>> +coccilib.org.print_todo(p2[0],
>> +f"WARNING: same array_size (line {p1[0].line})")
>> +

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [PATCH v3] coccinelle: misc: add array_size_dup script to detect missed overflow checks

2020-06-22 Thread Denis Efremov



On 6/21/20 11:56 PM, Julia Lawall wrote:
> Is it a python 2 vs python 3 thing?

Yes, python2 is no longer supported and I
thought it would be safe to use this syntax.

Ok, I will make it portable in v4.

Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH] coccinelle: api/kstrdup: fix coccinelle position

2020-06-19 Thread Denis Efremov
There is a typo in rule r2. Position p1 should be attached to kzalloc()
call.

Fixes: 29a36d4dec6c ("scripts/coccinelle: improve the coverage of some semantic 
patches")
Signed-off-by: Denis Efremov 
---
 scripts/coccinelle/api/kstrdup.cocci | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/coccinelle/api/kstrdup.cocci 
b/scripts/coccinelle/api/kstrdup.cocci
index 19f2645e6076..3c6dc5469ee4 100644
--- a/scripts/coccinelle/api/kstrdup.cocci
+++ b/scripts/coccinelle/api/kstrdup.cocci
@@ -66,7 +66,7 @@ position p1,p2;
 
 *   x = strlen(from) + 1;
 ... when != \( x = E1 \| from = E1 \)
-*   to = \(kmalloc@p1\|kzalloc@p2\)(x,flag);
+*   to = \(kmalloc@p1\|kzalloc@p1\)(x,flag);
 ... when != \(x = E2 \| from = E2 \| to = E2 \)
 if (to==NULL || ...) S
 ... when != \(x = E3 \| from = E3 \| to = E3 \)
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v3] coccinelle: misc: add array_size_dup script to detect missed overflow checks

2020-06-19 Thread Denis Efremov
Detect an opencoded expression that is used before or after
array_size()/array3_size()/struct_size() to compute the same size.

Cc: Gustavo A. R. Silva 
Cc: Kees Cook 
Signed-off-by: Denis Efremov 
---
Changes in v2:
 - python rules moved next to SmPL patterns
 - assignment operator used
 - struct_size patterns fixed to check only E3, since
   E1, E2 are sizeofs of a structure and a member
   of a structure
Changes in v3:
 - s/overlow/overflow/ typo fixed (thanks, Markus)
 - \(\|\) changed to &\(E1\|E2\)
 - print strings breaks removed

 scripts/coccinelle/misc/array_size_dup.cocci | 297 +++
 1 file changed, 297 insertions(+)
 create mode 100644 scripts/coccinelle/misc/array_size_dup.cocci

diff --git a/scripts/coccinelle/misc/array_size_dup.cocci 
b/scripts/coccinelle/misc/array_size_dup.cocci
new file mode 100644
index ..d03740257e97
--- /dev/null
+++ b/scripts/coccinelle/misc/array_size_dup.cocci
@@ -0,0 +1,297 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Check for array_size(), array3_size(), struct_size() duplicates.
+/// Three types of patterns for these functions:
+///  1. An opencoded expression is used before array_size() to compute the 
same size
+///  2. An opencoded expression is used after array_size() to compute the same 
size
+///  3. Consecutive calls of array_size() with the same values
+/// From security point of view only first case is relevant. These functions
+/// perform arithmetic overflow check. Thus, if we use an opencoded expression
+/// before a call to the *_size() function we can miss an overflow.
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers --no-loops
+
+virtual context
+virtual report
+virtual org
+
+@as@
+expression E1, E2;
+@@
+
+array_size(E1, E2)
+
+@as_next@
+expression subE1 <= as.E1;
+expression subE2 <= as.E2;
+expression as.E1, as.E2, E3;
+assignment operator aop;
+position p1, p2;
+@@
+
+* E1 * E2@p1
+  ... when != \(E1\|E2\|subE1\|subE2\) aop E3
+  when != &\(E1\|E2\|subE1\|subE2\)
+* array_size(E1, E2)@p2
+
+@script:python depends on report@
+p1 << as_next.p1;
+p2 << as_next.p2;
+@@
+
+coccilib.report.print_report(p1[0],
+f"WARNING: array_size is used down the code (line {p2[0].line}) to compute the 
same size")
+
+@script:python depends on org@
+p1 << as_next.p1;
+p2 << as_next.p2;
+@@
+
+coccilib.org.print_todo(p1[0],
+f"WARNING: array_size is used down the code (line {p2[0].line}) to compute the 
same size")
+
+@as_prev@
+expression subE1 <= as.E1;
+expression subE2 <= as.E2;
+expression as.E1, as.E2, E3;
+assignment operator aop;
+position p1, p2;
+@@
+
+* array_size(E1, E2)@p1
+  ... when != \(E1\|E2\|subE1\|subE2\) aop E3
+  when != &\(E1\|E2\|subE1\|subE2\)
+* E1 * E2@p2
+
+@script:python depends on report@
+p1 << as_prev.p1;
+p2 << as_prev.p2;
+@@
+
+coccilib.report.print_report(p2[0],
+f"WARNING: array_size is already used (line {p1[0].line}) to compute the same 
size")
+
+@script:python depends on org@
+p1 << as_prev.p1;
+p2 << as_prev.p2;
+@@
+
+coccilib.org.print_todo(p2[0],
+f"WARNING: array_size is already used (line {p1[0].line}) to compute the same 
size")
+
+@as_dup@
+expression subE1 <= as.E1;
+expression subE2 <= as.E2;
+expression as.E1, as.E2, E3;
+assignment operator aop;
+position p1, p2;
+@@
+
+* array_size(E1, E2)@p1
+  ... when != \(E1\|E2\|subE1\|subE2\) aop E3
+  when != &\(E1\|E2\|subE1\|subE2\)
+* array_size(E1, E2)@p2
+
+@script:python depends on report@
+p1 << as_dup.p1;
+p2 << as_dup.p2;
+@@
+
+coccilib.report.print_report(p2[0],
+f"WARNING: same array_size (line {p1[0].line})")
+
+@script:python depends on org@
+p1 << as_dup.p1;
+p2 << as_dup.p2;
+@@
+
+coccilib.org.print_todo(p2[0],
+f"WARNING: same array_size (line {p1[0].line})")
+
+@as3@
+expression E1, E2, E3;
+@@
+
+array3_size(E1, E2, E3)
+
+@as3_next@
+expression subE1 <= as3.E1;
+expression subE2 <= as3.E2;
+expression subE3 <= as3.E3;
+expression as3.E1, as3.E2, as3.E3, E4;
+assignment operator aop;
+position p1, p2;
+@@
+
+* E1 * E2 * E3@p1
+  ... when != \(E1\|E2\|E3\|subE1\|subE2\|subE3\) aop E4
+  when != &\(E1\|E2\|E3\|subE1\|subE2\|subE3\)
+* array3_size(E1, E2, E3)@p2
+
+@script:python depends on report@
+p1 << as3_next.p1;
+p2 << as3_next.p2;
+@@
+
+coccilib.report.print_report(p1[0],
+f"WARNING: array3_size is used down the code (line {p2[0].line}) to compute 
the same size")
+
+@script:python depends on org@
+p1 << as3_next.p1;
+p2 << as3_next.p2;
+@@
+
+coccilib.org.print_todo(p1[0],
+f"WARNING: array3_size is used down the code (line {p2[0].line}) to compute 
the same size")
+
+@as3_prev@
+expression subE1 <= as3.E1;
+expression subE2 <= as3.E2;
+expression subE3 <= as3.E3;
+expression as3.E1, as3.E2, as3.E3

Re: [Cocci] [PATCH v2] coccinelle: misc: add array_size_dup script to detect missed overflow checks

2020-06-18 Thread Denis Efremov
Hi,

On 6/18/20 2:34 PM, Markus Elfring wrote:
> Why did you repeat a typo from the previous patch subject?

Where is the typo? I can't handle your suggestions because your mails constantly
break the threads. I just can't find them after due to missed/wrong In-Reply-To
headers. Again, this mail doesn't contain In-Reply-To header and highly likely I
will miss it when I will prepare next version of the patch.


>> +expression subE1 <= as.E1;
>> +expression subE2 <= as.E2;
>> +expression as.E1, as.E2, E3;
> 
> How do you think about to use the following SmPL code variant?
> 
> expression subE1 <= as.E1, subE2 <= as.E2, as.E1, as.E2, E3;

It's less readable and harder to review.

> 
>> +  when != \(\|\|\|\)
> 
> I suggest to move the ampersand before the disjunction in such
> SmPL code exclusion specifications.
> 
> +  when != & \(E1 \| E2 \| subE1 \| subE2\)

Ok, I will fix this if there will be next version.

> 
> 
>> +coccilib.report.print_report(p2[0],
>> +f"WARNING: array_size is already used (line {p1[0].line}) to compute \
>> +the same size")
> 
> I would prefer an other code formatting at such places.
> 
> +coccilib.report.print_report(p2[0],
> + f"WARNING: array_size is already used (line 
> {p1[0].line}) to compute the same size.")
> 

No. It's pointless to break the line to save 5 chars this way.

I can use instead:

coccilib.report.print_report(p2[0], f"WARNING: array_size is already used (line 
{p1[0].line}) to compute the same size")

or

msg = f"WARNING: array_size is already used (line {p1[0].line}) to compute the 
same size"
coccilib.report.print_report(p2[0], msg)

or

coccilib.report.print_report(p2[0],
f"WARNING: array_size is already used (line {p1[0].line}) to compute the same 
size")

And I prefer the last one if Julia will allow me to use more than 80 chars in 
print string.

Thanks,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH v2] coccinelle: misc: add array_size_dup script to detect missed overlow checks

2020-06-18 Thread Denis Efremov
Detect an opencoded expression that is used before or after
array_size()/array3_size()/struct_size() to compute the same size.

Cc: Gustavo A. R. Silva 
Cc: Kees Cook 
Signed-off-by: Denis Efremov 
---
Changes in v2:
 - python rules moved next to SmPL patterns
 - assignment operator used
 - struct_size patterns fixed to check only E3, since
   E1, E2 are sizeofs of a structure and a member
   of a structure

 scripts/coccinelle/misc/array_size_dup.cocci | 309 +++
 1 file changed, 309 insertions(+)
 create mode 100644 scripts/coccinelle/misc/array_size_dup.cocci

diff --git a/scripts/coccinelle/misc/array_size_dup.cocci 
b/scripts/coccinelle/misc/array_size_dup.cocci
new file mode 100644
index ..c5214310285c
--- /dev/null
+++ b/scripts/coccinelle/misc/array_size_dup.cocci
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Check for array_size(), array3_size(), struct_size() duplicates.
+/// Three types of patterns for these functions:
+///  1. An opencoded expression is used before array_size() to compute the 
same size
+///  2. An opencoded expression is used after array_size() to compute the same 
size
+///  3. Consecutive calls of array_size() with the same values
+/// From security point of view only first case is relevant. These functions
+/// perform arithmetic overflow check. Thus, if we use an opencoded expression
+/// before a call to the *_size() function we can miss an overflow.
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers --no-loops
+
+virtual context
+virtual report
+virtual org
+
+@as@
+expression E1, E2;
+@@
+
+array_size(E1, E2)
+
+@as_next@
+expression subE1 <= as.E1;
+expression subE2 <= as.E2;
+expression as.E1, as.E2, E3;
+assignment operator aop;
+position p1, p2;
+@@
+
+* E1 * E2@p1
+  ... when != \(E1\|E2\|subE1\|subE2\) aop E3
+  when != \(\|\|\|\)
+* array_size(E1, E2)@p2
+
+@script:python depends on report@
+p1 << as_next.p1;
+p2 << as_next.p2;
+@@
+
+coccilib.report.print_report(p1[0],
+f"WARNING: array_size is used down the code (line {p2[0].line}) to compute \
+the same size")
+
+@script:python depends on org@
+p1 << as_next.p1;
+p2 << as_next.p2;
+@@
+
+coccilib.org.print_todo(p1[0],
+f"WARNING: array_size is used down the code (line {p2[0].line}) to compute \
+the same size")
+
+@as_prev@
+expression subE1 <= as.E1;
+expression subE2 <= as.E2;
+expression as.E1, as.E2, E3;
+assignment operator aop;
+position p1, p2;
+@@
+
+* array_size(E1, E2)@p1
+  ... when != \(E1\|E2\|subE1\|subE2\) aop E3
+  when != \(\|\|\|\)
+* E1 * E2@p2
+
+@script:python depends on report@
+p1 << as_prev.p1;
+p2 << as_prev.p2;
+@@
+
+coccilib.report.print_report(p2[0],
+f"WARNING: array_size is already used (line {p1[0].line}) to compute \
+the same size")
+
+@script:python depends on org@
+p1 << as_prev.p1;
+p2 << as_prev.p2;
+@@
+
+coccilib.org.print_todo(p2[0],
+f"WARNING: array_size is already used (line {p1[0].line}) to compute \
+the same size")
+
+@as_dup@
+expression subE1 <= as.E1;
+expression subE2 <= as.E2;
+expression as.E1, as.E2, E3;
+assignment operator aop;
+position p1, p2;
+@@
+
+* array_size(E1, E2)@p1
+  ... when != \(E1\|E2\|subE1\|subE2\) aop E3
+  when != \(\|\|\|\)
+* array_size(E1, E2)@p2
+
+@script:python depends on report@
+p1 << as_dup.p1;
+p2 << as_dup.p2;
+@@
+
+coccilib.report.print_report(p2[0],
+f"WARNING: same array_size (line {p1[0].line})")
+
+@script:python depends on org@
+p1 << as_dup.p1;
+p2 << as_dup.p2;
+@@
+
+coccilib.org.print_todo(p2[0],
+f"WARNING: same array_size (line {p1[0].line})")
+
+@as3@
+expression E1, E2, E3;
+@@
+
+array3_size(E1, E2, E3)
+
+@as3_next@
+expression subE1 <= as3.E1;
+expression subE2 <= as3.E2;
+expression subE3 <= as3.E3;
+expression as3.E1, as3.E2, as3.E3, E4;
+assignment operator aop;
+position p1, p2;
+@@
+
+* E1 * E2 * E3@p1
+  ... when != \(E1\|E2\|E3\|subE1\|subE2\|subE3\) aop E4
+  when != \(\|\|\|\|\|\)
+* array3_size(E1, E2, E3)@p2
+
+@script:python depends on report@
+p1 << as3_next.p1;
+p2 << as3_next.p2;
+@@
+
+coccilib.report.print_report(p1[0],
+f"WARNING: array3_size is used down the code (line {p2[0].line}) to compute \
+the same size")
+
+@script:python depends on org@
+p1 << as3_next.p1;
+p2 << as3_next.p2;
+@@
+
+coccilib.org.print_todo(p1[0],
+f"WARNING: array3_size is used down the code (line {p2[0].line}) to compute \
+the same size")
+
+@as3_prev@
+expression subE1 <= as3.E1;
+expression subE2 <= as3.E2;
+expression subE3 <= as3.E3;
+expression as3.E1, as3.E2, as3.E3, E4;
+assignment operator aop;
+position p1, p2;
+@@
+
+* array3_size(E1, E2, E3)@p1
+  ... when != \(E1\|E2\|E3\|subE1\|subE2\|subE3\) aop E4
+  when != \(\|\|\|\|\|\)
+* E1 * E2 * E

Re: [Cocci] [PATCH v3] coccinelle: api: add kzfree script

2020-06-17 Thread Denis Efremov


>> +@rp_memset depends on patch@
>> +expression E, size;
>> +position p : script:python() { relevant(p) };
>> +type T;
>> +@@
>> +
>> +- memset((T)E, size)@p;
> 
> This is missing a 0 argument.
> 

Thanks, I will send v4.

> 
> 
>> +  ... when != E
>> +  when strict
>> +(
>> +- kfree(E);
>> ++ kzfree(E);
>> +|
>> +- \(vfree\|kvfree\)(E);
>> ++ kvfree_sensitive(E, size);
>> +)
> 
> I'm not sure why you want kzfree in the first case, but kvfree_sensitive
> in the second case.
> 

As for now in kernel:

memset(E,0,...) && kfree(E) is kzfree()

There are no vzfree or kvzfree functions.
Thus, we use kvfree_sensitive().

Maybe it's worth to wait for this patchset:
https://lkml.org/lkml/2020/6/16/1163

With it the rule will use:

(
- kfree(E);
+ kfree_sensitive(E);
|
- \(vfree\|kvfree\)(E);
+ kvfree_sensitive(E, size);
)

Thanks,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [PATCH] coccinelle: misc: add array_size_dup script to detect missed overlow checks

2020-06-17 Thread Denis Efremov



On 6/17/20 11:30 PM, Julia Lawall wrote:
> 
> 
> On Mon, 15 Jun 2020, Denis Efremov wrote:
> 
>> Detect an opencoded expression that is used before or after
>> array_size()/array3_size()/struct_size() to compute the same size.
> 
> This would benefit from the assignemnt operator metavariables as well.
> 
> Also, it could be better to put the python rules up next the SmPL pattern
> matching rules that they are associated with.
> 

Thanks, I will send v2.
Here is the KSPP ticket with patches https://github.com/KSPP/linux/issues/83 
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [PATCH] coccinelle: api: add device_attr_show script

2020-06-17 Thread Denis Efremov



On 6/17/20 11:27 PM, Julia Lawall wrote:
> 
> 
> On Mon, 15 Jun 2020, Denis Efremov wrote:
> 
>> According to the documentation[1] show() methods of device attributes
>> should return the number of bytes printed into the buffer. This is
>> the return value of scnprintf(). show() must not use snprintf()
>> when formatting the value to be returned to user space. snprintf()
>> returns the length the resulting string would be, assuming it all
>> fit into the destination array[2]. scnprintf() return the length of
>> the string actually created in buf. If one can guarantee that an
>> overflow will never happen sprintf() can be used otherwise scnprintf().
> 
> The semantic patch looks fine.  Do you have any accepted patches from
> this?

It's not my patches, but:

3f9f8daad342 cpuidle: sysfs: Fix the overlap for showing available governors
117e2cb3 sparc: use scnprintf() in show_pciobppath_attr() in vio.c
03a1b56f501e sparc: use scnprintf() in show_pciobppath_attr() in pci.c
3dee04262898 iio: tsl2772: Use scnprintf() for avoiding potential buffer 
overflow
dbdd24eaac4e edd: Use scnprintf() for avoiding potential buffer overflow
abdd9feb45ed btrfs: sysfs: Use scnprintf() instead of snprintf()
f21431f2de33 thermal: int340x_thermal: Use scnprintf() for avoiding potential 
buffer overflow
40501c70e3f0 s390/zcrypt: replace snprintf/sprintf with scnprintf
eb3e064b8dd1 s390/zcrypt: Use scnprintf() for avoiding potential buffer overflow
06b522d6de9d video: uvesafb: Use scnprintf() for avoiding potential buffer 
overflow
bf1b615ad97e video: omapfb: Use scnprintf() for avoiding potential buffer 
overflow
b40e288bfb53 platform/x86: sony-laptop: Use scnprintf() for avoiding potential 
buffer overflow
ef21e1750158 ALSA: Use scnprintf() instead of snprintf() for show

and many more

Thanks,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [PATCH] coccinelle: misc: add array_size_dup script to detect missed overlow checks

2020-06-17 Thread Denis Efremov


> 
> Awesome! I'll take a look into this. :)
> 
Here is another script for your #83 ticket.
Currently, it issues 598 warnings.

// SPDX-License-Identifier: GPL-2.0-only
///
/// Check for missing overflow checks in allocation functions.
/// Low confidence because it's pointless to check for overflow
/// relatively small allocations.
///
// Confidence: Low
// Copyright: (C) 2020 Denis Efremov ISPRAS
// Options: --no-includes --include-headers

virtual patch
virtual context
virtual org
virtual report

@depends on patch@
expression E1, E2, E3, E4, size;
@@

(
- size = E1 * E2;
+ size = array_size(E1, E2);
|
- size = E1 * E2 * E3;
+ size = array3_size(E1, E2, E3);
|
- size = E1 * E2 + E3;
+ size = struct_size(E1, E2, E3);
)
  ... when != size = E4
  when != size += E4
  when != size -= E4
  when != size *= E4
  when != 
  \(kmalloc\|krealloc\|kzalloc\|kzalloc_node\|
vmalloc\|vzalloc\|vzalloc_node\|
kvmalloc\|kvzalloc\|kvzalloc_node\|
sock_kmalloc\|
f2fs_kmalloc\|f2fs_kzalloc\|f2fs_kvmalloc\|f2fs_kvzalloc\|
devm_kmalloc\|devm_kzalloc\)
  (..., size, ...)

@r depends on !patch@
expression E1, E2, E3, E4, size;
position p;
@@

(
* size = E1 * E2;@p
|
* size = E1 * E2 * E3;@p
|
* size = E1 * E2 + E3;@p
)
  ... when != size = E4
  when != size += E4
  when != size -= E4
  when != size *= E4
  when != 
* \(kmalloc\|krealloc\|kzalloc\|kzalloc_node\|
vmalloc\|vzalloc\|vzalloc_node\|
kvmalloc\|kvzalloc\|kvzalloc_node\|
sock_kmalloc\|
f2fs_kmalloc\|f2fs_kzalloc\|f2fs_kvmalloc\|f2fs_kvzalloc\|
devm_kmalloc\|devm_kzalloc\)
  (..., size, ...)

@script:python depends on report@
p << r.p;
@@

coccilib.report.print_report(p[0], "WARNING: missing overflow check")

@script:python depends on org@
p << r.p;
@@

coccilib.org.print_todo(p[0], "WARNING: missing overflow check")
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [PATCH] coccinelle: misc: add array_size_dup script to detect missed overlow checks

2020-06-17 Thread Denis Efremov
> 
> 
> Awesome! I'll take a look into this. :)
> 

It would be helpful to get a feedback from you after.
What kind of warnings are helpful and what are not?
"duplicate calls" and "opencoded expression after array_size()" look doubtful 
to me.
I think that maintainers will not like these patches.

Thanks,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [PATCH] coccinelle: misc: add array_size_dup script to detect missed overlow checks

2020-06-15 Thread Denis Efremov



On 6/15/20 9:23 PM, Kees Cook wrote:
> On Mon, Jun 15, 2020 at 01:20:45PM +0300, Denis Efremov wrote:
>> Detect an opencoded expression that is used before or after
>> array_size()/array3_size()/struct_size() to compute the same size.
>>
>> Cc: Kees Cook 
>> Signed-off-by: Denis Efremov 
> 
> Oh, very cool! How much does this find currently?
> 

opencoded expression before the function call:
./drivers/net/ethernet/cavium/liquidio/request_manager.c:98:34-59: WARNING: 
array_size is used down the code (line 103) to compute the same size
./drivers/media/test-drivers/vivid/vivid-core.c:1120:26-34: WARNING: array_size 
is used down the code (line 1122) to compute the same size
./drivers/scsi/megaraid/megaraid_sas_fusion.c:5184:11-31: WARNING: array_size 
is used down the code (line 5191) to compute the same size
./drivers/scsi/megaraid/megaraid_sas_fusion.c:5200:2-37: WARNING: array_size is 
used down the code (line 5207) to compute the same size
./fs/cifs/misc.c:853:17-39: WARNING: array_size is used down the code (line 
858) to compute the same size
./fs/cifs/misc.c:863:17-38: WARNING: array_size is used down the code (line 
868) to compute the same size
./drivers/scsi/fnic/fnic_trace.c:562:25-48: WARNING: array_size is used down 
the code (line 566) to compute the same size

opencoded expression after the function call:
./net/ethtool/ioctl.c:1976:55-66: WARNING: array_size is already used (line 
1957) to compute the same size
./net/ethtool/ioctl.c:1921:55-66: WARNING: array_size is already used (line 
1909) to compute the same size
./drivers/net/ethernet/cavium/liquidio/request_manager.c:111:29-54: WARNING: 
array_size is already used (line 103) to compute the same size
./drivers/staging/rts5208/ms.c:2309:55-56: WARNING: array_size is already used 
(line 2305) to compute the same size
./drivers/video/fbdev/core/fbcon.c:642:52-53: WARNING: array3_size is already 
used (line 638) to compute the same size
./drivers/video/fbdev/core/fbcon.c:679:47-48: WARNING: array3_size is already 
used (line 638) to compute the same size
./drivers/usb/misc/sisusbvga/sisusb_con.c:1229:54-56: WARNING: array_size is 
already used (line 1226) to compute the same size
./fs/afs/cmservice.c:271:45-46: WARNING: array3_size is already used (line 267) 
to compute the same size
./drivers/mtd/ftl.c:270:49-65: WARNING: array_size is already used (line 266) 
to compute the same size
./drivers/scsi/qla2xxx/tcm_qla2xxx.c:1608:6-42: WARNING: array_size is already 
used (line 1605) to compute the same size
./drivers/scsi/qla2xxx/tcm_qla2xxx.c:1613:8-44: WARNING: array_size is already 
used (line 1605) to compute the same size
./drivers/net/ppp/bsd_comp.c:439:13-37: WARNING: array_size is already used 
(line 409) to compute the same size
./drivers/net/wireless/ath/ath5k/debug.c:957:20-21: WARNING: array_size is 
already used (line 934) to compute the same size
./drivers/scsi/fnic/fnic_trace.c:575:3-26: WARNING: array_size is already used 
(line 566) to compute the same size
./drivers/scsi/fnic/fnic_trace.c:592:32-53: WARNING: array_size is already used 
(line 580) to compute the same size
./drivers/scsi/fnic/fnic_trace.c:504:30-51: WARNING: array_size is already used 
(line 492) to compute the same size
./drivers/staging/rts5208/rtsx_chip.c:1475:17-18: WARNING: array_size is 
already used (line 1458) to compute the same size
./kernel/kexec_file.c:917:8-25: WARNING: array_size is already used (line 913) 
to compute the same size
./drivers/rapidio/devices/rio_mport_cdev.c:984:8-25: WARNING: array_size is 
already used (line 978) to compute the same size
./fs/reiserfs/bitmap.c:1463:22-37: WARNING: array_size is already used (line 
1459) to compute the same size

duplicate calls:
./drivers/media/test-drivers/vivid/vivid-core.c:1125:59-60: WARNING: same 
array_size (line 1122)
./drivers/media/common/v4l2-tpg/v4l2-tpg-core.c:142:36-37: WARNING: same 
array_size (line 138)
./drivers/media/common/v4l2-tpg/v4l2-tpg-core.c:129:41-42: WARNING: same 
array3_size (line 123)
./drivers/media/common/v4l2-tpg/v4l2-tpg-core.c:146:40-41: WARNING: same 
array3_size (line 123)
./drivers/media/common/v4l2-tpg/v4l2-tpg-core.c:146:40-41: WARNING: same 
array3_size (line 129)
./drivers/net/ethernet/cavium/liquidio/octeon_droq.c:289:27-28: WARNING: same 
array_size (line 284)
./drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c:857:59-60: WARNING: same 
struct_size (line 854)
./fs/f2fs/super.c:3478:34-35: WARNING: same array_size (line 3478)
./drivers/net/wireless/zydas/zd1211rw/zd_usb.c:1637:45-46: WARNING: same 
struct_size (line 1634)
./drivers/net/ethernet/netronome/nfp/flower/cmsg.c:221:49-50: WARNING: same 
struct_size (line 219)
./drivers/staging/rts5208/rtsx_chip.c:1458:36-37: WARNING: same array_size 
(line 1454)
./drivers/net/ethernet/neterion/vxge/vxge-config.c:2664:59-60: WARNING: same 
array_size (line 2654)
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


Re: [Cocci] [PATCH] coccinelle: api: add kzfree script

2020-06-15 Thread Denis Efremov



On 6/15/20 3:03 PM, Dan Carpenter wrote:
> On Sun, Jun 14, 2020 at 10:42:54PM +0300, Denis Efremov wrote:
>> On 6/4/20 7:27 PM, Joe Perches wrote:
>>> On Thu, 2020-06-04 at 17:08 +0300, Denis Efremov wrote:
>>>> Check for memset() with 0 followed by kfree().
>>>
>>> Perhaps those uses should be memzero_explicit or kvfree_sensitive.
>>>
>>
>> Is it safe to suggest to use kzfree instead of memzero_explicit && kfree?
>> Or it would be better to use kvfree_sensitive in this case.
>>
>> kzfree uses memset(0) with no barrier_data.
> 
> Yeah.  That seems buggy.  It should have a barrier.  Also I thought I
> saw somewhere that Linus doesn't like the name and so that's why we have
> the _sensitive() name?
> 

Oh, there are already patches for renaming kzfree to kfree_sensitive.

https://lkml.org/lkml/2020/4/13/729

It seems they are not accepted despite multiple acks, through.

Thanks,
Denis
___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH] coccinelle: api: add device_attr_show script

2020-06-15 Thread Denis Efremov
According to the documentation[1] show() methods of device attributes
should return the number of bytes printed into the buffer. This is
the return value of scnprintf(). show() must not use snprintf()
when formatting the value to be returned to user space. snprintf()
returns the length the resulting string would be, assuming it all
fit into the destination array[2]. scnprintf() return the length of
the string actually created in buf. If one can guarantee that an
overflow will never happen sprintf() can be used otherwise scnprintf().

[1] Documentation/filesystems/sysfs.txt
[2] "snprintf() confusion" https://lwn.net/Articles/69419/

Signed-off-by: Denis Efremov 
---
 scripts/coccinelle/api/device_attr_show.cocci | 55 +++
 1 file changed, 55 insertions(+)
 create mode 100644 scripts/coccinelle/api/device_attr_show.cocci

diff --git a/scripts/coccinelle/api/device_attr_show.cocci 
b/scripts/coccinelle/api/device_attr_show.cocci
new file mode 100644
index ..d8ec4bb8ac41
--- /dev/null
+++ b/scripts/coccinelle/api/device_attr_show.cocci
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// From Documentation/filesystems/sysfs.txt:
+///  show() must not use snprintf() when formatting the value to be
+///  returned to user space. If you can guarantee that an overflow
+///  will never happen you can use sprintf() otherwise you must use
+///  scnprintf().
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+
+virtual report
+virtual org
+virtual context
+virtual patch
+
+@r depends on !patch@
+identifier show, dev, attr, buf;
+position p;
+@@
+
+ssize_t show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+   <...
+*  return snprintf@p(...);
+   ...>
+}
+
+@rp depends on patch@
+identifier show, dev, attr, buf;
+@@
+
+ssize_t show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+   <...
+   return
+-  snprintf
++  scnprintf
+   (...);
+   ...>
+}
+
+@script: python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING: use scnprintf or sprintf")
+
+@script: python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0], "WARNING: use scnprintf or sprintf")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


[Cocci] [PATCH] coccinelle: misc: add array_size_dup script to detect missed overlow checks

2020-06-15 Thread Denis Efremov
Detect an opencoded expression that is used before or after
array_size()/array3_size()/struct_size() to compute the same size.

Cc: Kees Cook 
Signed-off-by: Denis Efremov 
---
 scripts/coccinelle/misc/array_size_dup.cocci | 347 +++
 1 file changed, 347 insertions(+)
 create mode 100644 scripts/coccinelle/misc/array_size_dup.cocci

diff --git a/scripts/coccinelle/misc/array_size_dup.cocci 
b/scripts/coccinelle/misc/array_size_dup.cocci
new file mode 100644
index ..08919a938754
--- /dev/null
+++ b/scripts/coccinelle/misc/array_size_dup.cocci
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Check for array_size(), array3_size(), struct_size() duplicates.
+/// Three types of patterns for these functions:
+///  1. An opencoded expression is used before array_size() to compute the 
same size
+///  2. An opencoded expression is used after array_size() to compute the same 
size
+///  3. Consecutive calls of array_size() with the same values
+/// From security point of view only first case is relevant. These functions
+/// perform arithmetic overflow check. Thus, if we use an opencoded expression
+/// before a call to the *_size() function we can miss an overflow.
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers --no-loops
+
+virtual context
+virtual report
+virtual org
+
+@as@
+expression E1, E2;
+@@
+
+array_size(E1, E2)
+
+@as_next@
+expression subE1 <= as.E1;
+expression as.E1;
+expression subE2 <= as.E2;
+expression as.E2;
+expression E3;
+position p1, p2;
+@@
+
+* E1 * E2@p1
+  ... when != \(E1\|E2\|subE1\|subE2\)=E3
+  when != \(E1\|E2\|subE1\|subE2\)+=E3
+  when != \(E1\|E2\|subE1\|subE2\)-=E3
+  when != \(E1\|E2\|subE1\|subE2\)*=E3
+  when != \(\|\|\|\)
+* array_size(E1, E2)@p2
+
+@as_prev@
+expression subE1 <= as.E1;
+expression as.E1;
+expression subE2 <= as.E2;
+expression as.E2;
+expression E3;
+position p1, p2;
+@@
+
+* array_size(E1, E2)@p1
+  ... when != \(E1\|E2\|subE1\|subE2\)=E3
+  when != \(E1\|E2\|subE1\|subE2\)+=E3
+  when != \(E1\|E2\|subE1\|subE2\)-=E3
+  when != \(E1\|E2\|subE1\|subE2\)*=E3
+  when != \(\|\|\|\)
+* E1 * E2@p2
+
+@as_dup@
+expression subE1 <= as.E1;
+expression as.E1;
+expression subE2 <= as.E2;
+expression as.E2;
+expression E3;
+position p1, p2;
+@@
+
+* array_size(E1, E2)@p1
+  ... when != \(E1\|E2\|subE1\|subE2\)=E3
+  when != \(E1\|E2\|subE1\|subE2\)+=E3
+  when != \(E1\|E2\|subE1\|subE2\)-=E3
+  when != \(E1\|E2\|subE1\|subE2\)*=E3
+  when != \(\|\|\|\)
+* array_size(E1, E2)@p2
+
+@as3@
+expression E1, E2, E3;
+@@
+
+array3_size(E1, E2, E3)
+
+@as3_next@
+expression subE1 <= as3.E1;
+expression as3.E1;
+expression subE2 <= as3.E2;
+expression as3.E2;
+expression subE3 <= as3.E3;
+expression as3.E3;
+expression E4;
+position p1, p2;
+@@
+
+* E1 * E2 * E3@p1
+  ... when != \(E1\|E2\|E3\|subE1\|subE2\|subE3\)=E4
+  when != \(E1\|E2\|E3\|subE1\|subE2\|subE3\)+=E4
+  when != \(E1\|E2\|E3\|subE1\|subE2\|subE3\)-=E4
+  when != \(E1\|E2\|E3\|subE1\|subE2\|subE3\)*=E4
+  when != \(\|\|\|\|\|\)
+* array3_size(E1, E2, E3)@p2
+
+@as3_prev@
+expression subE1 <= as3.E1;
+expression as3.E1;
+expression subE2 <= as3.E2;
+expression as3.E2;
+expression subE3 <= as3.E3;
+expression as3.E3;
+expression E4;
+position p1, p2;
+@@
+
+* array3_size(E1, E2, E3)@p1
+  ... when != \(E1\|E2\|E3\|subE1\|subE2\|subE3\)=E4
+  when != \(E1\|E2\|E3\|subE1\|subE2\|subE3\)+=E4
+  when != \(E1\|E2\|E3\|subE1\|subE2\|subE3\)-=E4
+  when != \(E1\|E2\|E3\|subE1\|subE2\|subE3\)*=E4
+  when != \(\|\|\|\|\|\)
+* E1 * E2 * E3@p2
+
+@as3_dup@
+expression subE1 <= as3.E1;
+expression as3.E1;
+expression subE2 <= as3.E2;
+expression as3.E2;
+expression subE3 <= as3.E3;
+expression as3.E3;
+expression E4;
+position p1, p2;
+@@
+
+* array3_size(E1, E2, E3)@p1
+  ... when != \(E1\|E2\|E3\|subE1\|subE2\|subE3\)=E4
+  when != \(E1\|E2\|E3\|subE1\|subE2\|subE3\)+=E4
+  when != \(E1\|E2\|E3\|subE1\|subE2\|subE3\)-=E4
+  when != \(E1\|E2\|E3\|subE1\|subE2\|subE3\)*=E4
+  when != \(\|\|\|\|\|\)
+* array3_size(E1, E2, E3)@p2
+
+@ss@
+expression E1, E2, E3;
+@@
+
+struct_size(E1, E2, E3)
+
+@ss_next@
+expression subE1 <= ss.E1;
+expression ss.E1;
+expression subE2 <= ss.E2;
+expression ss.E2;
+expression subE3 <= ss.E3;
+expression ss.E3;
+expression E4;
+position p1, p2;
+@@
+
+* E1 * E2 + E3@p1
+  ... when != \(E1\|E2\|E3\|subE1\|subE2\|subE3\)=E4
+  when != \(E1\|E2\|E3\|subE1\|subE2\|subE3\)+=E4
+  when != \(E1\|E2\|E3\|subE1\|subE2\|subE3\)-=E4
+  when != \(E1\|E2\|E3\|subE1\|subE2\|subE3\)*=E4
+  when != \(\|\|\|\|\|\)
+* struct_size(E1, E2, E3)@p2
+
+@ss_prev@
+expression subE1 <= ss.E1;
+expression ss.E1;
+expression subE2 <= ss.E2;
+expression ss.E2;
+expression subE3 <= ss.E3;
+expression ss.E3;
+expression E4;
+position p1, 

[Cocci] [PATCH v3] coccinelle: api: add kzfree script

2020-06-14 Thread Denis Efremov
Check for memset()/memzero_explicit() followed by kfree()/vfree()/kvfree().

Signed-off-by: Denis Efremov 
---
Changes in v2:
 - memset_explicit() added
 - kvfree_sensitive() added
 - forall added to r1
 - ... between memset and kfree added
Changes in v3:
 - Explicit filter for definitions instead of !(file in "...") conditions
 - type T added to match casts
 - memzero_explicit() patterns fixed
 - additional rule "cond" added to filter false-positives

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

diff --git a/scripts/coccinelle/api/kzfree.cocci 
b/scripts/coccinelle/api/kzfree.cocci
new file mode 100644
index ..4758ca5a781e
--- /dev/null
+++ b/scripts/coccinelle/api/kzfree.cocci
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Use kzfree, kvfree_sensitive rather than memset or
+/// memzero_explicit followed by kfree
+///
+// Confidence: High
+// Copyright: (C) 2020 Denis Efremov ISPRAS
+// Options: --no-includes --include-headers
+//
+// Keywords: kzfree, kvfree_sensitive
+//
+
+virtual context
+virtual patch
+virtual org
+virtual report
+
+@initialize:python@
+@@
+# kmalloc_oob_in_memset uses memset to explicitly trigger out-of-bounds access
+filter = frozenset(['kmalloc_oob_in_memset', 'kzfree', 'kvfree_sensitive'])
+
+def relevant(p):
+return not (filter & {el.current_element for el in p})
+
+@cond@
+position ok;
+@@
+
+if (...)
+  \(memset@ok\|memzero_explicit@ok\)(...);
+
+@r depends on !patch forall@
+expression E;
+position p : script:python() { relevant(p) };
+position m != cond.ok;
+type T;
+@@
+
+(
+* memset@m((T)E, 0, ...);
+|
+* memzero_explicit@m((T)E, ...);
+)
+  ... when != E
+  when strict
+* \(kfree\|vfree\|kvfree\)(E)@p;
+
+@rp_memzero depends on patch@
+expression E, size;
+position p : script:python() { relevant(p) };
+type T;
+@@
+
+- memzero_explicit((T)E, size)@p;
+  ... when != E
+  when strict
+- \(kfree\|vfree\|kvfree\)(E);
++ kvfree_sensitive(E, size);
+
+@rp_memset depends on patch@
+expression E, size;
+position p : script:python() { relevant(p) };
+type T;
+@@
+
+- memset((T)E, size)@p;
+  ... when != E
+  when strict
+(
+- kfree(E);
++ kzfree(E);
+|
+- \(vfree\|kvfree\)(E);
++ kvfree_sensitive(E, size);
+)
+
+@script:python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0],
+  "WARNING: opportunity for kzfree/kvfree_sensitive")
+
+@script:python depends on org@
+p << r.p;
+@@
+
+coccilib.org.print_todo(p[0],
+  "WARNING: opportunity for kzfree/kvfree_sensitive")
-- 
2.26.2

___
Cocci mailing list
Cocci@systeme.lip6.fr
https://systeme.lip6.fr/mailman/listinfo/cocci


  1   2   >