Add a script to find and replace chained capable() calls with capable_any(). Also find and replace capable_any() calls where CAP_SYS_ADMIN was passed as first argument. Signed-off-by: Christian Göttsche <cgzones@xxxxxxxxxxxxxx> --- v5: add patch --- MAINTAINERS | 1 + scripts/coccinelle/api/capable_any.cocci | 164 +++++++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 scripts/coccinelle/api/capable_any.cocci diff --git a/MAINTAINERS b/MAINTAINERS index f4d7f7cb7577..32349e4c5f56 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4731,6 +4731,7 @@ S: Supported F: include/linux/capability.h F: include/uapi/linux/capability.h F: kernel/capability.c +F: scripts/coccinelle/api/capable_any.cocci F: security/commoncap.c CAPELLA MICROSYSTEMS LIGHT SENSOR DRIVER diff --git a/scripts/coccinelle/api/capable_any.cocci b/scripts/coccinelle/api/capable_any.cocci new file mode 100644 index 000000000000..83aedd3bf81d --- /dev/null +++ b/scripts/coccinelle/api/capable_any.cocci @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0-only +/// Use capable_any rather than chaining capable and order CAP_SYS_ADMIN last +/// +// Confidence: High +// Copyright: (C) 2024 Christian Göttsche. +// URL: https://coccinelle.gitlabpages.inria.fr/website +// Options: --no-includes --include-headers +// Keywords: capable, capable_any, ns_capable, ns_capable_any, sockopt_ns_capable, sockopt_ns_capable_any + +virtual patch +virtual context +virtual org +virtual report + +//---------------------------------------------------------- +// For patch mode +//---------------------------------------------------------- + +@ depends on patch@ +binary operator op; +expression cap1,cap2,E; +expression ns; +@@ + +( +- capable(cap1) || capable(cap2) ++ capable_any(cap1, cap2) +| +- E op capable(cap1) || capable(cap2) ++ E op capable_any(cap1, cap2) +| +- !capable(cap1) && !capable(cap2) ++ !capable_any(cap1, cap2) +| +- E op !capable(cap1) && !capable(cap2) ++ E op !capable_any(cap1, cap2) +| +- ns_capable(ns, cap1) || ns_capable(ns, cap2) ++ ns_capable_any(ns, cap1, cap2) +| +- E op ns_capable(ns, cap1) || ns_capable(ns, cap2) ++ E op ns_capable_any(ns, cap1, cap2) +| +- !ns_capable(ns, cap1) && !ns_capable(ns, cap2) ++ !ns_capable_any(ns, cap1, cap2) +| +- E op !ns_capable(ns, cap1) && !ns_capable(ns, cap2) ++ E op !ns_capable_any(ns, cap1, cap2) +| +- sockopt_ns_capable(ns, cap1) || sockopt_ns_capable(ns, cap2) ++ sockopt_ns_capable_any(ns, cap1, cap2) +| +- E op sockopt_ns_capable(ns, cap1) || sockopt_ns_capable(ns, cap2) ++ E op sockopt_ns_capable_any(ns, cap1, cap2) +| +- !sockopt_ns_capable(ns, cap1) && !sockopt_ns_capable(ns, cap2) ++ !sockopt_ns_capable_any(ns, cap1, cap2) +| +- E op !sockopt_ns_capable(ns, cap1) && !sockopt_ns_capable(ns, cap2) ++ E op !sockopt_ns_capable_any(ns, cap1, cap2) +) + +@ depends on patch@ +identifier func = { capable_any, ns_capable_any, sockopt_ns_capable_any }; +expression cap; +expression ns; +@@ + +( +- func(CAP_SYS_ADMIN, cap) ++ func(cap, CAP_SYS_ADMIN) +| +- func(ns, CAP_SYS_ADMIN, cap) ++ func(ns, cap, CAP_SYS_ADMIN) +) + +//---------------------------------------------------------- +// For context mode +//---------------------------------------------------------- + +@r1 depends on !patch exists@ +binary operator op; +expression cap1,cap2,E; +expression ns; +position p1,p2; +@@ + +( +* capable@p1(cap1) || capable@p2(cap2) +| +* E op capable@p1(cap1) || capable@p2(cap2) +| +* !capable@p1(cap1) && !capable@p2(cap2) +| +* E op !capable@p1(cap1) && !capable@p2(cap2) +| +* ns_capable@p1(ns, cap1) || ns_capable@p2(ns, cap2) +| +* E op ns_capable@p1(ns, cap1) || ns_capable@p2(ns, cap2) +| +* !ns_capable@p1(ns, cap1) && !ns_capable@p2(ns, cap2) +| +* E op !ns_capable@p1(ns, cap1) && !ns_capable@p2(ns, cap2) +| +* sockopt_ns_capable@p1(ns, cap1) || sockopt_ns_capable@p2(ns, cap2) +| +* E op sockopt_ns_capable@p1(ns, cap1) || sockopt_ns_capable@p2(ns, cap2) +| +* !sockopt_ns_capable@p1(ns, cap1) && !sockopt_ns_capable@p2(ns, cap2) +| +* E op !sockopt_ns_capable@p1(ns, cap1) && !sockopt_ns_capable@p2(ns, cap2) +) + +@r2 depends on !patch exists@ +identifier func = { capable_any, ns_capable_any, sockopt_ns_capable_any }; +expression cap; +expression ns; +position p; +@@ + +( +* func@p(CAP_SYS_ADMIN, cap) +| +* func@p(ns, CAP_SYS_ADMIN, cap) +) + +//---------------------------------------------------------- +// For org mode +//---------------------------------------------------------- + +@script:python depends on org@ +p1 << r1.p1; +p2 << r1.p2; +@@ + +cocci.print_main("WARNING opportunity for capable_any",p1) +cocci.print_secs("chained capable",p2) + +@script:python depends on org@ +p << r2.p; +f << r2.func; +@@ + +cocci.print_main("WARNING " + f + " arguments should be reordered",p) + +//---------------------------------------------------------- +// For report mode +//---------------------------------------------------------- + +@script:python depends on report@ +p1 << r1.p1; +p2 << r1.p2; +@@ + +msg = "WARNING opportunity for capable_any (chained capable line %s)" % (p2[0].line) +coccilib.report.print_report(p1[0], msg) + +@script:python depends on report@ +p << r2.p; +f << r2.func; +@@ + +msg = "WARNING %s arguments should be reordered" % (f) +coccilib.report.print_report(p[0], msg) -- 2.43.0