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>