diff options
author | David Malcolm <dmalcolm@redhat.com> | 2021-05-26 15:47:23 -0400 |
---|---|---|
committer | David Malcolm <dmalcolm@redhat.com> | 2021-11-13 09:27:26 -0500 |
commit | b9365b93212041f14a7f71ba8da5af4d82240dc6 (patch) | |
tree | 3cc3fcc1a454a25b03b7bd62dcfb6d5e9add0058 /gcc/analyzer/program-state.cc | |
parent | e2dd12ab66d14ac76a92b4538af81f8361132ba0 (diff) | |
download | gcc-b9365b93212041f14a7f71ba8da5af4d82240dc6.zip gcc-b9365b93212041f14a7f71ba8da5af4d82240dc6.tar.gz gcc-b9365b93212041f14a7f71ba8da5af4d82240dc6.tar.bz2 |
analyzer: add four new taint-based warnings
The initial commit of the analyzer in GCC 10 had a single warning,
-Wanalyzer-tainted-array-index
and required manually enabling the taint checker with
-fanalyzer-checker=taint (due to scaling issues).
This patch extends the taint detection to add four new taint-based
warnings:
-Wanalyzer-tainted-allocation-size
for e.g. attacker-controlled malloc/alloca
-Wanalyzer-tainted-divisor
for detecting where an attacker can inject a divide-by-zero
-Wanalyzer-tainted-offset
for attacker-controlled pointer offsets
-Wanalyzer-tainted-size
for e.g. attacker-controlled memset
and rewords all the warnings to talk about "attacker-controlled" values
rather than "tainted" values.
Unfortunately I haven't yet addressed the scaling issues, so all of
these still require -fanalyzer-checker=taint (in addition to -fanalyzer).
gcc/analyzer/ChangeLog:
* analyzer.opt (Wanalyzer-tainted-allocation-size): New.
(Wanalyzer-tainted-divisor): New.
(Wanalyzer-tainted-offset): New.
(Wanalyzer-tainted-size): New.
* engine.cc (impl_region_model_context::get_taint_map): New.
* exploded-graph.h (impl_region_model_context::get_taint_map):
New decl.
* program-state.cc (sm_state_map::get_state): Call
alt_get_inherited_state.
(sm_state_map::impl_set_state): Modify states within
compound svalues.
(program_state::impl_call_analyzer_dump_state): Undo casts.
(selftest::test_program_state_1): Update for new context param of
create_region_for_heap_alloc.
(selftest::test_program_state_merging): Likewise.
* region-model-impl-calls.cc (region_model::impl_call_alloca):
Likewise.
(region_model::impl_call_calloc): Likewise.
(region_model::impl_call_malloc): Likewise.
(region_model::impl_call_operator_new): Likewise.
(region_model::impl_call_realloc): Likewise.
* region-model.cc (region_model::check_region_access): Call
check_region_for_taint.
(region_model::get_representative_path_var_1): Handle binops.
(region_model::create_region_for_heap_alloc): Add "ctxt" param and
pass it to set_dynamic_extents.
(region_model::create_region_for_alloca): Likewise.
(region_model::set_dynamic_extents): Add "ctxt" param and use it
to call check_dynamic_size_for_taint.
(selftest::test_state_merging): Update for new context param of
create_region_for_heap_alloc.
(selftest::test_malloc_constraints): Likewise.
(selftest::test_malloc): Likewise.
(selftest::test_alloca): Likewise for create_region_for_alloca.
* region-model.h (region_model::create_region_for_heap_alloc): Add
"ctxt" param.
(region_model::create_region_for_alloca): Likewise.
(region_model::set_dynamic_extents): Likewise.
(region_model::check_dynamic_size_for_taint): New decl.
(region_model::check_region_for_taint): New decl.
(region_model_context::get_taint_map): New vfunc.
(noop_region_model_context::get_taint_map): New.
* sm-taint.cc: Remove include of "diagnostic-event-id.h"; add
includes of "gimple-iterator.h", "tristate.h", "selftest.h",
"ordered-hash-map.h", "cgraph.h", "cfg.h", "digraph.h",
"analyzer/supergraph.h", "analyzer/call-string.h",
"analyzer/program-point.h", "analyzer/store.h",
"analyzer/region-model.h", and "analyzer/program-state.h".
(enum bounds): Move to top of file.
(class taint_diagnostic): New.
(class tainted_array_index): Convert to subclass of taint_diagnostic.
(tainted_array_index::emit): Add CWE-129. Reword warning to use
"attacker-controlled" rather than "tainted".
(tainted_array_index::describe_state_change): Move to
taint_diagnostic::describe_state_change.
(tainted_array_index::describe_final_event): Reword to use
"attacker-controlled" rather than "tainted".
(class tainted_offset): New.
(class tainted_size): New.
(class tainted_divisor): New.
(class tainted_allocation_size): New.
(taint_state_machine::alt_get_inherited_state): New.
(taint_state_machine::on_stmt): In assignment handling, remove
ARRAY_REF handling in favor of check_region_for_taint. Add
detection of tainted divisors.
(taint_state_machine::get_taint): New.
(taint_state_machine::combine_states): New.
(region_model::check_region_for_taint): New.
(region_model::check_dynamic_size_for_taint): New.
* sm.h (state_machine::alt_get_inherited_state): New.
gcc/ChangeLog:
* doc/invoke.texi (Static Analyzer Options): Add
-Wno-analyzer-tainted-allocation-size,
-Wno-analyzer-tainted-divisor, -Wno-analyzer-tainted-offset, and
-Wno-analyzer-tainted-size to list. Add
-Wanalyzer-tainted-allocation-size, -Wanalyzer-tainted-divisor,
-Wanalyzer-tainted-offset, and -Wanalyzer-tainted-size to list
of options effectively enabled by -fanalyzer.
(-Wanalyzer-tainted-allocation-size): New.
(-Wanalyzer-tainted-array-index): Tweak wording; add link to CWE.
(-Wanalyzer-tainted-divisor): New.
(-Wanalyzer-tainted-offset): New.
(-Wanalyzer-tainted-size): New.
gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/pr93382.c: Tweak expected wording.
* gcc.dg/analyzer/taint-alloc-1.c: New test.
* gcc.dg/analyzer/taint-alloc-2.c: New test.
* gcc.dg/analyzer/taint-divisor-1.c: New test.
* gcc.dg/analyzer/taint-1.c: Rename to...
* gcc.dg/analyzer/taint-read-index-1.c: ...this. Tweak expected
wording. Mark some events as xfail.
* gcc.dg/analyzer/taint-read-offset-1.c: New test.
* gcc.dg/analyzer/taint-size-1.c: New test.
* gcc.dg/analyzer/taint-write-index-1.c: New test.
* gcc.dg/analyzer/taint-write-offset-1.c: New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
Diffstat (limited to 'gcc/analyzer/program-state.cc')
-rw-r--r-- | gcc/analyzer/program-state.cc | 26 |
1 files changed, 24 insertions, 2 deletions
diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc index 8230140..1c87af0 100644 --- a/gcc/analyzer/program-state.cc +++ b/gcc/analyzer/program-state.cc @@ -420,6 +420,10 @@ sm_state_map::get_state (const svalue *sval, } } + if (state_machine::state_t state + = m_sm.alt_get_inherited_state (*this, sval, ext_state)) + return state; + return m_sm.get_default_state (sval); } @@ -495,6 +499,18 @@ sm_state_map::impl_set_state (const svalue *sval, gcc_assert (sval->can_have_associated_state_p ()); + if (m_sm.inherited_state_p ()) + { + if (const compound_svalue *compound_sval + = sval->dyn_cast_compound_svalue ()) + for (auto iter : *compound_sval) + { + const svalue *inner_sval = iter.second; + if (inner_sval->can_have_associated_state_p ()) + impl_set_state (inner_sval, state, origin, ext_state); + } + } + /* Special-case state 0 as the default value. */ if (state == 0) { @@ -1384,6 +1400,10 @@ program_state::impl_call_analyzer_dump_state (const gcall *call, const svalue *sval = cd.get_arg_svalue (1); + /* Strip off cast to int (due to variadic args). */ + if (const svalue *cast = sval->maybe_undo_cast ()) + sval = cast; + state_machine::state_t state = smap->get_state (sval, ext_state); warning_at (call->location, 0, "state: %qs", state->get_name ()); } @@ -1543,7 +1563,8 @@ test_program_state_1 () region_model *model = s.m_region_model; const svalue *size_in_bytes = mgr->get_or_create_unknown_svalue (size_type_node); - const region *new_reg = model->create_region_for_heap_alloc (size_in_bytes); + const region *new_reg + = model->create_region_for_heap_alloc (size_in_bytes, NULL); const svalue *ptr_sval = mgr->get_ptr_svalue (ptr_type_node, new_reg); model->set_value (model->get_lvalue (p, NULL), ptr_sval, NULL); @@ -1599,7 +1620,8 @@ test_program_state_merging () region_model *model0 = s0.m_region_model; const svalue *size_in_bytes = mgr->get_or_create_unknown_svalue (size_type_node); - const region *new_reg = model0->create_region_for_heap_alloc (size_in_bytes); + const region *new_reg + = model0->create_region_for_heap_alloc (size_in_bytes, NULL); const svalue *ptr_sval = mgr->get_ptr_svalue (ptr_type_node, new_reg); model0->set_value (model0->get_lvalue (p, &ctxt), ptr_sval, &ctxt); |