Add __attribute__ ((tainted_args))
authorDavid Malcolm <dmalcolm@redhat.com>
Fri, 12 Nov 2021 15:06:23 +0000 (10:06 -0500)
committerDavid Malcolm <dmalcolm@redhat.com>
Fri, 14 Jan 2022 01:18:20 +0000 (20:18 -0500)
commitb31cec9c22b8dfa40baefd4c2dd774477e8e04c5
tree4675de9d964069a4cf3d2b6c630e440bb8e022ff
parentad3f0d0806d64ae8ceddfbde1560d4829085202b
Add __attribute__ ((tainted_args))

This patch adds a new __attribute__ ((tainted_args)) to the C/C++ frontends.

It can be used on function decls: the analyzer will treat as tainted
all parameters to the function and all buffers pointed to by parameters
to the function.  Adding this in one place to the Linux kernel's
__SYSCALL_DEFINEx macro allows the analyzer to treat all syscalls as
having tainted inputs.  This gives some coverage of system calls without
needing to "teach" the analyzer about "__user" - an example of the use
of this can be seen in CVE-2011-2210, where given:

 SYSCALL_DEFINE5(osf_getsysinfo, unsigned long, op, void __user *, buffer,
                 unsigned long, nbytes, int __user *, start, void __user *, arg)

the analyzer will treat the nbytes param as under attacker control, and
can complain accordingly:

taint-CVE-2011-2210-1.c: In function 'sys_osf_getsysinfo':
taint-CVE-2011-2210-1.c:69:21: warning: use of attacker-controlled value
  'nbytes' as size without upper-bounds checking [CWE-129] [-Wanalyzer-tainted-size]
   69 |                 if (copy_to_user(buffer, hwrpb, nbytes) != 0)
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Additionally, the patch allows the attribute to be used on field decls:
specifically function pointers.  Any function used as an initializer
for such a field gets treated as being called with tainted arguments.
An example can be seen in CVE-2020-13143, where adding
__attribute__((tainted_args)) to the "store" callback of
configfs_attribute:

  struct configfs_attribute {
    /* [...snip...] */
    ssize_t (*store)(struct config_item *, const char *, size_t)
      __attribute__((tainted_args));
    /* [...snip...] */
  };

allows the analyzer to see:

 CONFIGFS_ATTR(gadget_dev_desc_, UDC);

and treat gadget_dev_desc_UDC_store as having tainted arguments, so that
it complains:

taint-CVE-2020-13143-1.c: In function 'gadget_dev_desc_UDC_store':
taint-CVE-2020-13143-1.c:33:17: warning: use of attacker-controlled value
  'len + 18446744073709551615' as offset without upper-bounds checking [CWE-823] [-Wanalyzer-tainted-offset]
   33 |         if (name[len - 1] == '\n')
      |             ~~~~^~~~~~~~~

As before this currently still needs -fanalyzer-checker=taint (in
addition to -fanalyzer).

gcc/analyzer/ChangeLog:
* engine.cc: Include "stringpool.h", "attribs.h", and
"tree-dfa.h".
(mark_params_as_tainted): New.
(class tainted_args_function_custom_event): New.
(class tainted_args_function_info): New.
(exploded_graph::add_function_entry): Handle functions with
"tainted_args" attribute.
(class tainted_args_field_custom_event): New.
(class tainted_args_callback_custom_event): New.
(class tainted_args_call_info): New.
(add_tainted_args_callback): New.
(add_any_callbacks): New.
(exploded_graph::build_initial_worklist): Likewise.
(exploded_graph::build_initial_worklist): Find callbacks that are
reachable from global initializers, calling add_any_callbacks on
them.

gcc/c-family/ChangeLog:
* c-attribs.c (c_common_attribute_table): Add "tainted_args".
(handle_tainted_args_attribute): New.

gcc/ChangeLog:
* doc/extend.texi (Function Attributes): Note that "tainted_args" can
be used on field decls.
(Common Function Attributes): Add entry on "tainted_args" attribute.

gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/attr-tainted_args-1.c: New test.
* gcc.dg/analyzer/attr-tainted_args-misuses.c: New test.
* gcc.dg/analyzer/taint-CVE-2011-2210-1.c: New test.
* gcc.dg/analyzer/taint-CVE-2020-13143-1.c: New test.
* gcc.dg/analyzer/taint-CVE-2020-13143-2.c: New test.
* gcc.dg/analyzer/taint-CVE-2020-13143.h: New test.
* gcc.dg/analyzer/taint-alloc-3.c: New test.
* gcc.dg/analyzer/taint-alloc-4.c: New test.
* gcc.dg/analyzer/test-uaccess.h: New test.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
12 files changed:
gcc/analyzer/engine.cc
gcc/c-family/c-attribs.c
gcc/doc/extend.texi
gcc/testsuite/gcc.dg/analyzer/attr-tainted_args-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/attr-tainted_args-misuses.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/taint-CVE-2011-2210-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/taint-CVE-2020-13143-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/taint-CVE-2020-13143-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/taint-CVE-2020-13143.h [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/taint-alloc-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/taint-alloc-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/test-uaccess.h [new file with mode: 0644]