]> git.ipfire.org Git - thirdparty/gcc.git/commit
analyzer: implement trust boundaries via a plugin for Linux kernel
authorDavid Malcolm <dmalcolm@redhat.com>
Fri, 9 Sep 2022 21:13:04 +0000 (17:13 -0400)
committerDavid Malcolm <dmalcolm@redhat.com>
Fri, 9 Sep 2022 21:13:04 +0000 (17:13 -0400)
commitc81b60b8c6ff3d4db2e395a628e114df812cfc48
treee1e3715a12fdaf50af93746d0df9ec4c744f8321
parent07e30160beaa207f56f170900fac0d799c6af410
analyzer: implement trust boundaries via a plugin for Linux kernel

This is a less ambitious version of:
  [PATCH 0/6] RFC: adding support to GCC for detecting trust boundaries
    https://gcc.gnu.org/pipermail/gcc-patches/2021-November/584372.html

Earlier versions of this patch attempted:
(a) various ways of identifying "untrusted" memory regions
(b) providing a way to support the Linux kernel's "__user" annotation,
    either via type attributes, or via custom address spaces
(c) enough attributes to identify "copy_from_user" and "copy_to_user",
(d) wiring all of the above together to detect infoleaks and taint

This patch adds a new -Wanalyzer-exposure-through-uninit-copy, emitted
by -fanalyzer if it detects copying of uninitialized data through
a pointer to an untrusted region, but requires a plugin to tell it when
a copy crosses a trust boundary.

This patch adds a proof-of-concept gcc plugin for the analyzer for use
with the Linux kernel that special-cases calls to "copy_from_user" and
calls to "copy_to_user": calls to copy_to_user are checked for
-Wanalyzer-exposure-through-uninit-copy, and data copied via
copy_from_user is marked as tainted when -fanalyzer-checker=taint is
active.

This is very much just a proof-of-concept.  A big limitation is that the
copy_{from,to}_user special-casing only happens if these functions have
no body in the TU being analyzed, which isn't the case for a normal
kernel build.  I'd much prefer to provide a more general mechanism for
handling such behavior without resorting to plugins (e.g. via attributes
or custom address spaces), but in the interest of not "letting perfect
be the enemy of the good" this patch at least allows parts of this
"trust boundaries" code to be merged for experimentation with the idea.

The -Wanalyzer-exposure-through-uninit-copy diagnostic uses notes to
express what fields and padding within a struct have not been initialized.
For example:

infoleak-CVE-2011-1078-2.c: In function 'test_1':
infoleak-CVE-2011-1078-2.c:32:9: warning: potential exposure of sensitive
  information by copying uninitialized data from stack across trust
  boundary [CWE-200] [-Wanalyzer-exposure-through-uninit-copy]
   32 |         copy_to_user(optval, &cinfo, sizeof(cinfo));
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  'test_1': events 1-3
    |
    |   25 |         struct sco_conninfo cinfo;
    |      |                             ^~~~~
    |      |                             |
    |      |                             (1) region created on stack here
    |      |                             (2) capacity: 6 bytes
    |......
    |   32 |         copy_to_user(optval, &cinfo, sizeof(cinfo));
    |      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |         |
    |      |         (3) uninitialized data copied from stack here
    |
infoleak-CVE-2011-1078-2.c:32:9: note: 1 byte is uninitialized
   32 |         copy_to_user(optval, &cinfo, sizeof(cinfo));
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
infoleak-CVE-2011-1078-2.c:18:15: note: padding after field 'dev_class'
  is uninitialized (1 byte)
   18 |         __u8  dev_class[3];
      |               ^~~~~~~~~
infoleak-CVE-2011-1078-2.c:25:29: note: suggest forcing
  zero-initialization by providing a '{0}' initializer
   25 |         struct sco_conninfo cinfo;
      |                             ^~~~~
      |                                   = {0}

For taint-detection, the patch includes a series of reproducers for
detecting CVE-2011-0521.  Unfortunately the analyzer doesn't yet detect
the issue until the code has been significantly simplified from its
original form: currently only in -5.c and -6.c in the series of test
(see notes in the individual cases), such as:

taint-CVE-2011-0521-6.c:33:48: warning: use of attacker-controlled value
  '*info.num' in array lookup without bounds checking [CWE-129]
  [-Wanalyzer-tainted-array-index]
   33 |             av7110->ci_slot[info->num].num = info->num;
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~
  'test_1': events 1-3
    |
    |   19 |    if (copy_from_user(&sbuf, (void __user *)arg, sizeof(sbuf)) != 0)
    |      |        ^
    |      |        |
    |      |        (1) following 'false' branch...
    |......
    |   23 |             struct dvb_device *dvbdev = file->private_data;
    |      |                                ~~~~~~
    |      |                                |
    |      |                                (2) ...to here
    |......
    |   33 |             av7110->ci_slot[info->num].num = info->num;
    |      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                                            |
    |      |                                            (3) use of attacker-controlled value '*info.num' in array lookup without bounds checking
    |

The patch also includes various infoleak and taint cases from my
antipatterns.ko kernel module:
  https://github.com/davidmalcolm/antipatterns.ko

gcc/analyzer/ChangeLog:
* analyzer.opt (Wanalyzer-exposure-through-uninit-copy): New.
* checker-path.cc (region_creation_event::region_creation_event):
Add "capacity" and "kind" params.
(region_creation_event::get_desc): Generalize to different kinds
of event.
(checker_path::add_region_creation_event): Convert to...
(checker_path::add_region_creation_events): ...this.
* checker-path.h (enum rce_kind): New.
(region_creation_event::region_creation_event): Add "capacity" and
"kind" params.
(region_creation_event::m_capacity): New field.
(region_creation_event::m_rce_kind): New field.
(checker_path::add_region_creation_event): Convert to...
(checker_path::add_region_creation_events): ...this.
* diagnostic-manager.cc (diagnostic_manager::build_emission_path):
Update for multiple region creation events.
(diagnostic_manager::add_event_on_final_node): Likewise.
(diagnostic_manager::add_events_for_eedge): Likewise.
* region-model-impl-calls.cc (call_details::get_logger): New.
* region-model.cc: Define INCLUDE_MEMORY before including
"system.h".  Include "gcc-rich-location.h".
(class record_layout): New.
(class exposure_through_uninit_copy): New.
(contains_uninit_p): New.
(region_model::maybe_complain_about_infoleak): New.
* region-model.h (call_details::get_logger): New decl.
(region_model::maybe_complain_about_infoleak): New decl.
(region_model::mark_as_tainted): New decl.
* sm-taint.cc (region_model::mark_as_tainted): New.

gcc/ChangeLog:
* doc/invoke.texi (Static Analyzer Options): Add
-Wanalyzer-exposure-through-uninit-copy.

gcc/testsuite/ChangeLog:
* gcc.dg/plugin/analyzer_kernel_plugin.c: New test.
* gcc.dg/plugin/copy_from_user-1.c: New test.
* gcc.dg/plugin/infoleak-1.c: New test.
* gcc.dg/plugin/infoleak-2.c: New test.
* gcc.dg/plugin/infoleak-3.c: New test.
* gcc.dg/plugin/infoleak-CVE-2011-1078-1.c: New test.
* gcc.dg/plugin/infoleak-CVE-2011-1078-2.c: New test.
* gcc.dg/plugin/infoleak-CVE-2014-1446-1.c: New test.
* gcc.dg/plugin/infoleak-CVE-2017-18549-1.c: New test.
* gcc.dg/plugin/infoleak-CVE-2017-18550-1.c: New test.
* gcc.dg/plugin/infoleak-antipatterns-1.c: New test.
* gcc.dg/plugin/infoleak-fixit-1.c: New test.
* gcc.dg/plugin/infoleak-net-ethtool-ioctl.c: New test.
* gcc.dg/plugin/infoleak-vfio_iommu_type1.c: New test.
* gcc.dg/plugin/plugin.exp (plugin_test_list): Add
analyzer_kernel_plugin.c and the new test cases.
* gcc.dg/plugin/taint-CVE-2011-0521-1-fixed.c: New test.
* gcc.dg/plugin/taint-CVE-2011-0521-1.c: New test.
* gcc.dg/plugin/taint-CVE-2011-0521-2-fixed.c: New test.
* gcc.dg/plugin/taint-CVE-2011-0521-2.c: New test.
* gcc.dg/plugin/taint-CVE-2011-0521-3-fixed.c: New test.
* gcc.dg/plugin/taint-CVE-2011-0521-3.c: New test.
* gcc.dg/plugin/taint-CVE-2011-0521-4.c: New test.
* gcc.dg/plugin/taint-CVE-2011-0521-5-fixed.c: New test.
* gcc.dg/plugin/taint-CVE-2011-0521-5.c: New test.
* gcc.dg/plugin/taint-CVE-2011-0521-6.c: New test.
* gcc.dg/plugin/taint-CVE-2011-0521.h: New test.
* gcc.dg/plugin/taint-antipatterns-1.c: New test.
* gcc.dg/plugin/test-uaccess.h: New header for tests.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
37 files changed:
gcc/analyzer/analyzer.opt
gcc/analyzer/checker-path.cc
gcc/analyzer/checker-path.h
gcc/analyzer/diagnostic-manager.cc
gcc/analyzer/region-model-impl-calls.cc
gcc/analyzer/region-model.cc
gcc/analyzer/region-model.h
gcc/analyzer/sm-taint.cc
gcc/doc/invoke.texi
gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/copy_from_user-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/infoleak-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/infoleak-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/infoleak-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/infoleak-CVE-2011-1078-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/infoleak-CVE-2011-1078-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/infoleak-CVE-2014-1446-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/infoleak-CVE-2017-18549-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/infoleak-CVE-2017-18550-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/infoleak-antipatterns-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/infoleak-fixit-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/infoleak-net-ethtool-ioctl.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/infoleak-vfio_iommu_type1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/plugin.exp
gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-1-fixed.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-2-fixed.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-3-fixed.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5-fixed.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-6.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521.h [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/taint-antipatterns-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/test-uaccess.h [new file with mode: 0644]