diff options
Diffstat (limited to 'scripts/coccinelle/free')
-rw-r--r-- | scripts/coccinelle/free/clk_put.cocci | 68 | ||||
-rw-r--r-- | scripts/coccinelle/free/devm_free.cocci | 143 | ||||
-rw-r--r-- | scripts/coccinelle/free/ifnullfree.cocci | 67 | ||||
-rw-r--r-- | scripts/coccinelle/free/iounmap.cocci | 68 | ||||
-rw-r--r-- | scripts/coccinelle/free/kfree.cocci | 134 | ||||
-rw-r--r-- | scripts/coccinelle/free/kfreeaddr.cocci | 37 | ||||
-rw-r--r-- | scripts/coccinelle/free/pci_free_consistent.cocci | 53 | ||||
-rw-r--r-- | scripts/coccinelle/free/put_device.cocci | 56 |
8 files changed, 626 insertions, 0 deletions
diff --git a/scripts/coccinelle/free/clk_put.cocci b/scripts/coccinelle/free/clk_put.cocci new file mode 100644 index 000000000..7237b4949 --- /dev/null +++ b/scripts/coccinelle/free/clk_put.cocci @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0-only +/// Find missing clk_puts. +/// +//# This only signals a missing clk_put when there is a clk_put later +//# in the same function. +//# False positives can be due to loops. +// +// Confidence: Moderate +// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. +// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: + +virtual context +virtual org +virtual report + +@clk@ +expression e; +statement S,S1; +int ret; +position p1,p2,p3; +@@ + +e = clk_get@p1(...) +... when != clk_put(e) +if (<+...e...+>) S +... when any + when != clk_put(e) + when != if (...) { ... clk_put(e); ... } +( + if (ret == 0) S1 +| +if (...) + { ... + return 0; } +| +if (...) + { ... + return <+...e...+>; } +| +*if@p2 (...) + { ... when != clk_put(e) + when forall + return@p3 ...; } +) +... when any +clk_put(e); + +@script:python depends on org@ +p1 << clk.p1; +p2 << clk.p2; +p3 << clk.p3; +@@ + +cocci.print_main("clk_get",p1) +cocci.print_secs("if",p2) +cocci.print_secs("needed clk_put",p3) + +@script:python depends on report@ +p1 << clk.p1; +p2 << clk.p2; +p3 << clk.p3; +@@ + +msg = "ERROR: missing clk_put; clk_get on line %s and execution via conditional on line %s" % (p1[0].line,p2[0].line) +coccilib.report.print_report(p3[0],msg) diff --git a/scripts/coccinelle/free/devm_free.cocci b/scripts/coccinelle/free/devm_free.cocci new file mode 100644 index 000000000..da80050b9 --- /dev/null +++ b/scripts/coccinelle/free/devm_free.cocci @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: GPL-2.0-only +/// Find uses of standard freeing functons on values allocated using devm_ +/// functions. Values allocated using the devm_functions are freed when +/// the device is detached, and thus the use of the standard freeing +/// function would cause a double free. +/// See Documentation/driver-api/driver-model/devres.rst for more information. +/// +/// A difficulty of detecting this problem is that the standard freeing +/// function might be called from a different function than the one +/// containing the allocation function. It is thus necessary to make the +/// connection between the allocation function and the freeing function. +/// Here this is done using the specific argument text, which is prone to +/// false positives. There is no rule for the request_region and +/// request_mem_region variants because this heuristic seems to be a bit +/// less reliable in these cases. +/// +// Confidence: Moderate +// Copyright: (C) 2011 Julia Lawall, INRIA/LIP6. +// Copyright: (C) 2011 Gilles Muller, INRIA/LiP6. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: --no-includes --include-headers + +virtual org +virtual report +virtual context + +@r depends on context || org || report@ +expression x; +@@ + +( + x = devm_kmalloc(...) +| + x = devm_kvasprintf(...) +| + x = devm_kasprintf(...) +| + x = devm_kzalloc(...) +| + x = devm_kmalloc_array(...) +| + x = devm_kcalloc(...) +| + x = devm_kstrdup(...) +| + x = devm_kmemdup(...) +| + x = devm_get_free_pages(...) +| + x = devm_request_irq(...) +| + x = devm_ioremap(...) +| + x = devm_ioport_map(...) +) + +@safe depends on context || org || report exists@ +expression x; +position p; +@@ + +( + x = kmalloc(...) +| + x = kvasprintf(...) +| + x = kasprintf(...) +| + x = kzalloc(...) +| + x = kmalloc_array(...) +| + x = kcalloc(...) +| + x = kstrdup(...) +| + x = kmemdup(...) +| + x = get_free_pages(...) +| + x = request_irq(...) +| + x = ioremap(...) +| + x = ioport_map(...) +) +... +( + kfree@p(x) +| + kfree_sensitive@p(x) +| + krealloc@p(x, ...) +| + free_pages@p(x, ...) +| + free_page@p(x) +| + free_irq@p(x) +| + iounmap@p(x) +| + ioport_unmap@p(x) +) + +@pb@ +expression r.x; +position p != safe.p; +@@ + +( +* kfree@p(x) +| +* kfree_sensitive@p(x) +| +* krealloc@p(x, ...) +| +* free_pages@p(x, ...) +| +* free_page@p(x) +| +* free_irq@p(x) +| +* iounmap@p(x) +| +* ioport_unmap@p(x) +) + +@script:python depends on org@ +p << pb.p; +@@ + +msg="WARNING: invalid free of devm_ allocated data" +coccilib.org.print_todo(p[0], msg) + +@script:python depends on report@ +p << pb.p; +@@ + +msg="WARNING: invalid free of devm_ allocated data" +coccilib.report.print_report(p[0], msg) + diff --git a/scripts/coccinelle/free/ifnullfree.cocci b/scripts/coccinelle/free/ifnullfree.cocci new file mode 100644 index 000000000..285b92d5c --- /dev/null +++ b/scripts/coccinelle/free/ifnullfree.cocci @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0-only +/// NULL check before some freeing functions is not needed. +/// +/// Based on checkpatch warning +/// "kfree(NULL) is safe this check is probably not required" +/// and kfreeaddr.cocci by Julia Lawall. +/// +// Copyright: (C) 2014 Fabian Frederick. +// Comments: - +// Options: --no-includes --include-headers + +virtual patch +virtual org +virtual report +virtual context + +@r2 depends on patch@ +expression E; +@@ +- if (E != NULL) +( + kfree(E); +| + kvfree(E); +| + kfree_sensitive(E); +| + kvfree_sensitive(E, ...); +| + vfree(E); +| + debugfs_remove(E); +| + debugfs_remove_recursive(E); +| + usb_free_urb(E); +| + kmem_cache_destroy(E); +| + mempool_destroy(E); +| + dma_pool_destroy(E); +) + +@r depends on context || report || org @ +expression E; +position p; +@@ + +* if (E != NULL) +* \(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, ...); + +@script:python depends on org@ +p << r.p; +@@ + +cocci.print_main("NULL check before that freeing function is not needed", p) + +@script:python depends on report@ +p << r.p; +@@ + +msg = "WARNING: NULL check before some freeing functions is not needed." +coccilib.report.print_report(p[0], msg) diff --git a/scripts/coccinelle/free/iounmap.cocci b/scripts/coccinelle/free/iounmap.cocci new file mode 100644 index 000000000..63b81d0c9 --- /dev/null +++ b/scripts/coccinelle/free/iounmap.cocci @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0-only +/// Find missing iounmaps. +/// +//# This only signals a missing iounmap when there is an iounmap later +//# in the same function. +//# False positives can be due to loops. +// +// Confidence: Moderate +// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. +// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: + +virtual context +virtual org +virtual report + +@iom@ +expression e; +statement S,S1; +int ret; +position p1,p2,p3; +@@ + +e = \(ioremap@p1\)(...) +... when != iounmap(e) +if (<+...e...+>) S +... when any + when != iounmap(e) + when != if (...) { ... iounmap(e); ... } +( + if (ret == 0) S1 +| +if (...) + { ... + return 0; } +| +if (...) + { ... + return <+...e...+>; } +| +*if@p2 (...) + { ... when != iounmap(e) + when forall + return@p3 ...; } +) +... when any +iounmap(e); + +@script:python depends on org@ +p1 << iom.p1; +p2 << iom.p2; +p3 << iom.p3; +@@ + +cocci.print_main("ioremap",p1) +cocci.print_secs("if",p2) +cocci.print_secs("needed iounmap",p3) + +@script:python depends on report@ +p1 << iom.p1; +p2 << iom.p2; +p3 << iom.p3; +@@ + +msg = "ERROR: missing iounmap; ioremap on line %s and execution via conditional on line %s" % (p1[0].line,p2[0].line) +coccilib.report.print_report(p3[0],msg) diff --git a/scripts/coccinelle/free/kfree.cocci b/scripts/coccinelle/free/kfree.cocci new file mode 100644 index 000000000..168568386 --- /dev/null +++ b/scripts/coccinelle/free/kfree.cocci @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0-only +/// Find a use after free. +//# Values of variables may imply that some +//# execution paths are not possible, resulting in false positives. +//# Another source of false positives are macros such as +//# SCTP_DBG_OBJCNT_DEC that do not actually evaluate their argument +/// +// Confidence: Moderate +// Copyright: (C) 2010-2012 Nicolas Palix. +// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. +// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: --no-includes --include-headers + +virtual org +virtual report + +@free@ +expression E; +position p1; +@@ + +( +* kfree@p1(E) +| +* kfree_sensitive@p1(E) +) + +@print expression@ +constant char [] c; +expression free.E,E2; +type T; +position p; +identifier f; +@@ + +( + f(...,c,...,(T)E@p,...) +| + E@p == E2 +| + E@p != E2 +| + E2 == E@p +| + E2 != E@p +| + !E@p +| + E@p || ... +) + +@sz@ +expression free.E; +position p; +@@ + + sizeof(<+...E@p...+>) + +@loop exists@ +expression E; +identifier l; +position ok; +@@ + +while (1) { ... +( +* kfree@ok(E) +| +* kfree_sensitive@ok(E) +) + ... when != break; + when != goto l; + when forall +} + +@r exists@ +expression free.E, subE<=free.E, E2; +expression E1; +iterator iter; +statement S; +position free.p1!=loop.ok,p2!={print.p,sz.p}; +@@ + +( +* kfree@p1(E,...) +| +* kfree_sensitive@p1(E,...) +) +... +( + iter(...,subE,...) S // no use +| + list_remove_head(E1,subE,...) +| + subE = E2 +| + subE++ +| + ++subE +| + --subE +| + subE-- +| + &subE +| + BUG(...) +| + BUG_ON(...) +| + return_VALUE(...) +| + return_ACPI_STATUS(...) +| + E@p2 // bad use +) + +@script:python depends on org@ +p1 << free.p1; +p2 << r.p2; +@@ + +cocci.print_main("kfree",p1) +cocci.print_secs("ref",p2) + +@script:python depends on report@ +p1 << free.p1; +p2 << r.p2; +@@ + +msg = "ERROR: reference preceded by free on line %s" % (p1[0].line) +coccilib.report.print_report(p2[0],msg) diff --git a/scripts/coccinelle/free/kfreeaddr.cocci b/scripts/coccinelle/free/kfreeaddr.cocci new file mode 100644 index 000000000..142af6337 --- /dev/null +++ b/scripts/coccinelle/free/kfreeaddr.cocci @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0-only +/// Free of a structure field +/// +// Confidence: High +// Copyright: (C) 2013 Julia Lawall, INRIA/LIP6. +// URL: http://coccinelle.lip6.fr/ +// Comments: +// Options: --no-includes --include-headers + +virtual org +virtual report +virtual context + +@r depends on context || report || org @ +expression e; +identifier f; +position p; +@@ + +( +* kfree@p(&e->f) +| +* kfree_sensitive@p(&e->f) +) + +@script:python depends on org@ +p << r.p; +@@ + +cocci.print_main("kfree",p) + +@script:python depends on report@ +p << r.p; +@@ + +msg = "ERROR: invalid free of structure field" +coccilib.report.print_report(p[0],msg) diff --git a/scripts/coccinelle/free/pci_free_consistent.cocci b/scripts/coccinelle/free/pci_free_consistent.cocci new file mode 100644 index 000000000..d51e92556 --- /dev/null +++ b/scripts/coccinelle/free/pci_free_consistent.cocci @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-only +/// Find missing pci_free_consistent for every pci_alloc_consistent. +/// +// Confidence: Moderate +// Copyright: (C) 2013 Petr Strnad. +// URL: http://coccinelle.lip6.fr/ +// Keywords: pci_free_consistent, pci_alloc_consistent +// Options: --no-includes --include-headers + +virtual report +virtual org + +@search@ +local idexpression id; +expression x,y,z,e; +position p1,p2; +type T; +@@ + +id = pci_alloc_consistent@p1(x,y,&z) +... when != e = id +if (id == NULL || ...) { ... return ...; } +... when != pci_free_consistent(x,y,id,z) + when != if (id) { ... pci_free_consistent(x,y,id,z) ... } + when != if (y) { ... pci_free_consistent(x,y,id,z) ... } + when != e = (T)id + when exists +( +return 0; +| +return 1; +| +return id; +| +return@p2 ...; +) + +@script:python depends on report@ +p1 << search.p1; +p2 << search.p2; +@@ + +msg = "ERROR: missing pci_free_consistent; pci_alloc_consistent on line %s and return without freeing on line %s" % (p1[0].line,p2[0].line) +coccilib.report.print_report(p2[0],msg) + +@script:python depends on org@ +p1 << search.p1; +p2 << search.p2; +@@ + +msg = "ERROR: missing pci_free_consistent; pci_alloc_consistent on line %s and return without freeing on line %s" % (p1[0].line,p2[0].line) +cocci.print_main(msg,p1) +cocci.print_secs("",p2) diff --git a/scripts/coccinelle/free/put_device.cocci b/scripts/coccinelle/free/put_device.cocci new file mode 100644 index 000000000..120921366 --- /dev/null +++ b/scripts/coccinelle/free/put_device.cocci @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0 +/// Find missing put_device for every of_find_device_by_node. +/// +// Confidence: Moderate +// Copyright: (C) 2018-2019 Wen Yang, ZTE. +// Comments: +// Options: --no-includes --include-headers + +virtual report +virtual org + +@search exists@ +local idexpression id; +expression x,e,e1; +position p1,p2; +type T,T1,T2,T3; +@@ + +id = of_find_device_by_node@p1(x) +... when != e = id +if (id == NULL || ...) { ... return ...; } +... when != put_device(&id->dev) + when != platform_device_put(id) + when != of_dev_put(id) + when != if (id) { ... put_device(&id->dev) ... } + when != e1 = (T)id + when != e1 = (T)(&id->dev) + when != e1 = get_device(&id->dev) + when != e1 = (T1)platform_get_drvdata(id) +( + return +( id +| (T2)dev_get_drvdata(&id->dev) +| (T3)platform_get_drvdata(id) +| &id->dev +); +| return@p2 ...; +) + +@script:python depends on report@ +p1 << search.p1; +p2 << search.p2; +@@ + +coccilib.report.print_report(p2[0], + "ERROR: missing put_device; call of_find_device_by_node on line " + + p1[0].line + + ", but without a corresponding object release within this function.") + +@script:python depends on org@ +p1 << search.p1; +p2 << search.p2; +@@ + +cocci.print_main("of_find_device_by_node", p1) +cocci.print_secs("needed put_device", p2) |