From: David Malcolm Date: Thu, 7 Dec 2023 00:25:26 +0000 (-0500) Subject: analyzer: fix taint false positives with UNKNOWN [PR112850] X-Git-Tag: basepoints/gcc-15~3900 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=08b7462d3ad8e5acd941b7c777c5b26b4064d686;p=thirdparty%2Fgcc.git analyzer: fix taint false positives with UNKNOWN [PR112850] PR analyzer/112850 reports a false positive from -Wanalyzer-tainted-allocation-size on the Linux kernel [1] where -fanalyzer complains that an allocation size is attacker-controlled despite the value being correctly sanitized against upper and lower limits. The root cause is that the expression is sufficiently complex to exceed the -param=analyzer-max-svalue-depth= threshold, currently at 12, with depth 13, and so it is treated as UNKNOWN. Hence the sanitizations are seen as comparisons of an UNKNOWN symbolic value against constants, and these were being ignored by the taint state machine. The expression in question is relatively typical for those seen in Linux kernel ioctl handlers, and I was surprised that it had exceeded the analyzer's default expression complexity limit. This patch addresses this problem in three ways: (a) the default value of the threshold parameter is increased, from 12 to 18, so that such expressions are precisely handled (b) adding a new -Wanalyzer-symbol-too-complex to warn when the symbol complexity limit is reached. This is off by default for users, and on by default in the test suite. (c) the taint state machine handles comparisons against UNKNOWN svalues by dropping all taint information on that execution path, so that if the complexity limit has been exceeded we don't generate false positives As well as fixing the taint false positive (PR analyzer/112850), the patch also fixes a couple of leak false positives seen on flex-generated scanners (PR analyzer/103546). [1] specifically, in sound/core/rawmidi.c's handler for SNDRV_RAWMIDI_STREAM_OUTPUT. gcc/ChangeLog: PR analyzer/103546 PR analyzer/112850 * doc/invoke.texi: Add -Wanalyzer-symbol-too-complex. gcc/analyzer/ChangeLog: PR analyzer/103546 PR analyzer/112850 * analyzer.opt (-param=analyzer-max-svalue-depth=): Increase from 12 to 18. (Wanalyzer-symbol-too-complex): New. * diagnostic-manager.cc (null_assignment_sm_context::clear_all_per_svalue_state): New. * engine.cc (impl_sm_context::clear_all_per_svalue_state): New. * program-state.cc (sm_state_map::clear_all_per_svalue_state): New. * program-state.h (sm_state_map::clear_all_per_svalue_state): New decl. * region-model-manager.cc (region_model_manager::reject_if_too_complex): Add -Wanalyzer-symbol-too-complex. * sm-taint.cc (taint_state_machine::on_condition): Handle comparisons against UNKNOWN. * sm.h (sm_context::clear_all_per_svalue_state): New. gcc/testsuite/ChangeLog: PR analyzer/103546 PR analyzer/112850 * c-c++-common/analyzer/call-summaries-pr107158-2.c: Add -Wno-analyzer-symbol-too-complex. * c-c++-common/analyzer/call-summaries-pr107158.c: Likewise. * c-c++-common/analyzer/deref-before-check-pr109060-haproxy-cfgparse.c: Likewise. * c-c++-common/analyzer/feasibility-3.c: Add -Wno-analyzer-too-complex and -Wno-analyzer-symbol-too-complex. * c-c++-common/analyzer/flex-with-call-summaries.c: Add -Wno-analyzer-symbol-too-complex. Remove fail for PR analyzer/103546 leak false positive. * c-c++-common/analyzer/flex-without-call-summaries.c: Remove xfail for PR analyzer/103546 leak false positive. * c-c++-common/analyzer/infinite-recursion-3.c: Add -Wno-analyzer-symbol-too-complex. * c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early-O2.c: Likewise. * c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early.c: Likewise. * c-c++-common/analyzer/null-deref-pr108400-SoftEtherVPN-WebUi.c: Likewise. * c-c++-common/analyzer/null-deref-pr108806-qemu.c: Likewise. * c-c++-common/analyzer/null-deref-pr108830.c: Likewise. * c-c++-common/analyzer/pr94596.c: Likewise. * c-c++-common/analyzer/strtok-2.c: Likewise. * c-c++-common/analyzer/strtok-4.c: Add -Wno-analyzer-too-complex and -Wno-analyzer-symbol-too-complex. * c-c++-common/analyzer/strtok-cppreference.c: Likewise. * gcc.dg/analyzer/analyzer.exp: Add -Wanalyzer-symbol-too-complex to DEFAULT_CFLAGS. * gcc.dg/analyzer/attr-const-3.c: Add -Wno-analyzer-symbol-too-complex. * gcc.dg/analyzer/call-summaries-pr107072.c: Likewise. * gcc.dg/analyzer/doom-s_sound-pr108867.c: Likewise. * gcc.dg/analyzer/explode-4.c: Likewise. * gcc.dg/analyzer/null-deref-pr102671-1.c: Likewise. * gcc.dg/analyzer/null-deref-pr105755.c: Likewise. * gcc.dg/analyzer/out-of-bounds-curl.c: Likewise. * gcc.dg/analyzer/pr101503.c: Likewise. * gcc.dg/analyzer/pr103892.c: Add -Wno-analyzer-too-complex and -Wno-analyzer-symbol-too-complex. * gcc.dg/analyzer/pr94851-4.c: Add -Wno-analyzer-symbol-too-complex. * gcc.dg/analyzer/pr96860-1.c: Likewise. * gcc.dg/analyzer/pr96860-2.c: Likewise. * gcc.dg/analyzer/pr98918.c: Likewise. * gcc.dg/analyzer/pr99044-2.c: Likewise. * gcc.dg/analyzer/uninit-pr108806-qemu.c: Likewise. * gcc.dg/analyzer/use-after-free.c: Add -Wno-analyzer-too-complex and -Wno-analyzer-symbol-too-complex. * gcc.dg/plugin/plugin.exp: Add new tests for analyzer_kernel_plugin.c. * gcc.dg/plugin/taint-CVE-2011-0521-4.c: Update expected results. * gcc.dg/plugin/taint-CVE-2011-0521-5.c: Likewise. * gcc.dg/plugin/taint-CVE-2011-0521-6.c: Likewise. * gcc.dg/plugin/taint-CVE-2011-0521-5-fixed.c: Remove xfail. * gcc.dg/plugin/taint-pr112850-precise.c: New test. * gcc.dg/plugin/taint-pr112850-too-complex.c: New test. * gcc.dg/plugin/taint-pr112850-unsanitized.c: New test. * gcc.dg/plugin/taint-pr112850.c: New test. Signed-off-by: David Malcolm --- diff --git a/gcc/analyzer/analyzer.opt b/gcc/analyzer/analyzer.opt index a3c30caf2abe..d0fe5a437880 100644 --- a/gcc/analyzer/analyzer.opt +++ b/gcc/analyzer/analyzer.opt @@ -43,7 +43,7 @@ Common Joined UInteger Var(param_analyzer_max_recursion_depth) Init(2) Param The maximum number of times a callsite can appear in a call stack within the analyzer, before terminating analysis of a call that would recurse deeper. -param=analyzer-max-svalue-depth= -Common Joined UInteger Var(param_analyzer_max_svalue_depth) Init(12) Param +Common Joined UInteger Var(param_analyzer_max_svalue_depth) Init(18) Param The maximum depth of a symbolic value, before approximating the value as unknown. -param=analyzer-min-snodes-for-call-summary= @@ -262,6 +262,10 @@ Wanalyzer-use-of-uninitialized-value Common Var(warn_analyzer_use_of_uninitialized_value) Init(1) Warning Warn about code paths in which an uninitialized value is used. +Wanalyzer-symbol-too-complex +Common Var(warn_analyzer_symbol_too_complex) Init(0) Warning +Warn if expressions are too complicated for the analyzer to fully track. + Wanalyzer-too-complex Common Var(warn_analyzer_too_complex) Init(0) Warning Warn if the code is too complicated for the analyzer to fully explore. diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc index ecd57376b549..38bd308a9a48 100644 --- a/gcc/analyzer/diagnostic-manager.cc +++ b/gcc/analyzer/diagnostic-manager.cc @@ -2043,6 +2043,11 @@ struct null_assignment_sm_context : public sm_context /* No-op. */ } + void clear_all_per_svalue_state () final override + { + /* No-op. */ + } + void on_custom_transition (custom_transition *) final override { } diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 825b3af43fce..d2524e34f586 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -474,6 +474,11 @@ public: m_new_state->m_checker_states[m_sm_idx]->set_global_state (state); } + void clear_all_per_svalue_state () final override + { + m_new_state->m_checker_states[m_sm_idx]->clear_all_per_svalue_state (); + } + void on_custom_transition (custom_transition *transition) final override { transition->impl_transition (&m_eg, diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc index 9bb81e6ddddc..78f739ef5efa 100644 --- a/gcc/analyzer/program-state.cc +++ b/gcc/analyzer/program-state.cc @@ -526,6 +526,14 @@ sm_state_map::clear_any_state (const svalue *sval) m_map.remove (sval); } +/* Clear all per-svalue state within this state map. */ + +void +sm_state_map::clear_all_per_svalue_state () +{ + m_map.empty (); +} + /* Set the "global" state within this state map to STATE. */ void diff --git a/gcc/analyzer/program-state.h b/gcc/analyzer/program-state.h index c9b3aa0cbfce..ef1a2ad54a98 100644 --- a/gcc/analyzer/program-state.h +++ b/gcc/analyzer/program-state.h @@ -146,6 +146,7 @@ public: const svalue *origin, const extrinsic_state &ext_state); void clear_any_state (const svalue *sval); + void clear_all_per_svalue_state (); void set_global_state (state_machine::state_t state); state_machine::state_t get_global_state () const; diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc index 921edc558681..b631bcb04d04 100644 --- a/gcc/analyzer/region-model-manager.cc +++ b/gcc/analyzer/region-model-manager.cc @@ -185,6 +185,16 @@ region_model_manager::reject_if_too_complex (svalue *sval) return false; } + pretty_printer pp; + pp_format_decoder (&pp) = default_tree_printer; + sval->dump_to_pp (&pp, true); + if (warning_at (input_location, OPT_Wanalyzer_symbol_too_complex, + "symbol too complicated: %qs", + pp_formatted_text (&pp))) + inform (input_location, + "max_depth %i exceeds --param=analyzer-max-svalue-depth=%i", + c.m_max_depth, param_analyzer_max_svalue_depth); + delete sval; return true; } diff --git a/gcc/analyzer/sm-taint.cc b/gcc/analyzer/sm-taint.cc index d01e3f03951d..6b5d51c62af9 100644 --- a/gcc/analyzer/sm-taint.cc +++ b/gcc/analyzer/sm-taint.cc @@ -1038,6 +1038,20 @@ taint_state_machine::on_condition (sm_context *sm_ctxt, if (stmt == NULL) return; + if (lhs->get_kind () == SK_UNKNOWN + || rhs->get_kind () == SK_UNKNOWN) + { + /* If we have a comparison against UNKNOWN, then + we've presumably hit the svalue complexity limit, + and we don't know what is being sanitized. + Give up on any taint already found on this execution path. */ + // TODO: warn about this + if (get_logger ()) + get_logger ()->log ("comparison against UNKNOWN; removing all taint"); + sm_ctxt->clear_all_per_svalue_state (); + return; + } + // TODO switch (op) { diff --git a/gcc/analyzer/sm.h b/gcc/analyzer/sm.h index 3ff9c2607807..ef63d73a5415 100644 --- a/gcc/analyzer/sm.h +++ b/gcc/analyzer/sm.h @@ -299,6 +299,8 @@ public: virtual state_machine::state_t get_global_state () const = 0; virtual void set_global_state (state_machine::state_t) = 0; + virtual void clear_all_per_svalue_state () = 0; + /* A vfunc for handling custom transitions, such as when registering a signal handler. */ virtual void on_custom_transition (custom_transition *transition) = 0; diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index bff3645eedcf..f8d6f799e11a 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -491,6 +491,7 @@ Objective-C and Objective-C++ Dialects}. -Wno-analyzer-tainted-divisor -Wno-analyzer-tainted-offset -Wno-analyzer-tainted-size +-Wanalyzer-symbol-too-complex -Wanalyzer-too-complex -Wno-analyzer-undefined-behavior-strtok -Wno-analyzer-unsafe-call-within-signal-handler @@ -10562,6 +10563,19 @@ Enabling this option effectively enables the following warnings: This option is only available if GCC was configured with analyzer support enabled. +@opindex Wanalyzer-symbol-too-complex +@opindex Wno-analyzer-symbol-too-complex +@item -Wanalyzer-symbol-too-complex +If @option{-fanalyzer} is enabled, the analyzer uses various heuristics +to attempt to track the state of memory, but these can be defeated by +sufficiently complicated code. + +By default, the analysis silently stops tracking values of expressions +if they exceed the threshold defined by +@option{--param analyzer-max-svalue-depth=@var{value}}, and falls back +to an imprecise representation for such expressions. +The @option{-Wanalyzer-symbol-too-complex} option warns if this occurs. + @opindex Wanalyzer-too-complex @opindex Wno-analyzer-too-complex @item -Wanalyzer-too-complex diff --git a/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158-2.c b/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158-2.c index 4561e10cafd0..b395623cccac 100644 --- a/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158-2.c @@ -1,4 +1,4 @@ -/* { dg-additional-options "-fanalyzer-call-summaries -Wno-analyzer-too-complex" } */ +/* { dg-additional-options "-fanalyzer-call-summaries -Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */ /* { dg-skip-if "c++98 has no noreturn attribute" { c++98_only } } */ #ifdef __cplusplus diff --git a/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158.c b/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158.c index d4cf079cef84..de7058362491 100644 --- a/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158.c +++ b/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158.c @@ -1,4 +1,4 @@ -/* { dg-additional-options "-fanalyzer-call-summaries" } */ +/* { dg-additional-options "-fanalyzer-call-summaries -Wno-analyzer-symbol-too-complex" } */ typedef __SIZE_TYPE__ size_t; enum { _ISspace = ((5) < 8 ? ((1 << (5)) << 8) : ((1 << (5)) >> 8)) }; diff --git a/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr109060-haproxy-cfgparse.c b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr109060-haproxy-cfgparse.c index 1d28e10747cd..c4561fcd8a7e 100644 --- a/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr109060-haproxy-cfgparse.c +++ b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr109060-haproxy-cfgparse.c @@ -1,5 +1,7 @@ /* Reduced from haproxy-2.7.1's cfgparse.c. */ +/* { dg-additional-options "-Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */ + typedef __SIZE_TYPE__ size_t; extern int diff --git a/gcc/testsuite/c-c++-common/analyzer/feasibility-3.c b/gcc/testsuite/c-c++-common/analyzer/feasibility-3.c index 2fcd064e801f..06194f85069c 100644 --- a/gcc/testsuite/c-c++-common/analyzer/feasibility-3.c +++ b/gcc/testsuite/c-c++-common/analyzer/feasibility-3.c @@ -1,6 +1,8 @@ /* Reduced and adapted from Linux: fs/proc/inode.c: proc_reg_open (GPL v2.0). */ +/* { dg-additional-options "-Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */ + /* Types. */ typedef unsigned char u8; diff --git a/gcc/testsuite/c-c++-common/analyzer/flex-with-call-summaries.c b/gcc/testsuite/c-c++-common/analyzer/flex-with-call-summaries.c index 45edacf0e53d..963a84bc9ab8 100644 --- a/gcc/testsuite/c-c++-common/analyzer/flex-with-call-summaries.c +++ b/gcc/testsuite/c-c++-common/analyzer/flex-with-call-summaries.c @@ -5,6 +5,7 @@ /* { dg-skip-if "" { "avr-*-*" } } */ /* { dg-additional-options "-fanalyzer-call-summaries" } */ /* { dg-additional-options "-Wno-analyzer-too-complex" } */ +/* { dg-additional-options "-Wno-analyzer-symbol-too-complex" } */ /* A lexical scanner generated by flex */ @@ -885,8 +886,7 @@ static int yy_get_next_buffer (void) } else /* Can't grow it, we don't own it. */ - b->yy_ch_buf = NULL; /* { dg-bogus "leak" "" { xfail *-*-* } } */ - /* TODO: leak false positive: PR analyzer/103546. */ + b->yy_ch_buf = NULL; /* { dg-bogus "leak" "PR analyzer/103546" } */ if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( diff --git a/gcc/testsuite/c-c++-common/analyzer/flex-without-call-summaries.c b/gcc/testsuite/c-c++-common/analyzer/flex-without-call-summaries.c index 5369f7685c28..b1c233121378 100644 --- a/gcc/testsuite/c-c++-common/analyzer/flex-without-call-summaries.c +++ b/gcc/testsuite/c-c++-common/analyzer/flex-without-call-summaries.c @@ -886,8 +886,7 @@ static int yy_get_next_buffer (void) } else /* Can't grow it, we don't own it. */ - b->yy_ch_buf = NULL; /* { dg-bogus "leak" "" { xfail *-*-* } } */ - /* TODO: leak false positive: PR analyzer/103546. */ + b->yy_ch_buf = NULL; /* { dg-bogus "leak" "PR analyzer/103546" */ if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( diff --git a/gcc/testsuite/c-c++-common/analyzer/infinite-recursion-3.c b/gcc/testsuite/c-c++-common/analyzer/infinite-recursion-3.c index 68c4fa396caa..2ae20a1108a7 100644 --- a/gcc/testsuite/c-c++-common/analyzer/infinite-recursion-3.c +++ b/gcc/testsuite/c-c++-common/analyzer/infinite-recursion-3.c @@ -1,4 +1,4 @@ -/* { dg-additional-options "-fno-analyzer-call-summaries -Wno-analyzer-too-complex" } */ +/* { dg-additional-options "-fno-analyzer-call-summaries -Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */ struct node { diff --git a/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early-O2.c b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early-O2.c index c46ffe91a6b4..c1c8e6f6a39a 100644 --- a/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early-O2.c +++ b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early-O2.c @@ -1,7 +1,7 @@ /* Reduced from haproxy's src/ssl_sample.c */ /* { dg-require-effective-target ptr_eq_long } */ -/* { dg-additional-options "-O2" } */ +/* { dg-additional-options "-O2 -Wno-analyzer-symbol-too-complex" } */ union sample_value { long long int sint; diff --git a/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early.c b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early.c index ef34a76c50d6..c5f1fa42e6f1 100644 --- a/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early.c +++ b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early.c @@ -1,6 +1,7 @@ /* Reduced from haproxy's src/ssl_sample.c */ /* { dg-require-effective-target ptr_eq_long } */ +/* { dg-additional-options "-Wno-analyzer-symbol-too-complex" } */ union sample_value { long long int sint; diff --git a/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108400-SoftEtherVPN-WebUi.c b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108400-SoftEtherVPN-WebUi.c index 1151d622519b..9dcf7aa31f10 100644 --- a/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108400-SoftEtherVPN-WebUi.c +++ b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108400-SoftEtherVPN-WebUi.c @@ -1,4 +1,6 @@ /* Reduced from SoftEtherVPN's src/Cedar/WebUI.c. */ +/* { dg-additional-options "-Wno-analyzer-symbol-too-complex" } */ + #include "../../gcc.dg/analyzer/analyzer-decls.h" typedef int (COMPARE)(void *p1, void *p2); typedef unsigned int UINT; diff --git a/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108806-qemu.c b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108806-qemu.c index f7f6923927fc..16ef6574d2f4 100644 --- a/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108806-qemu.c +++ b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108806-qemu.c @@ -1,5 +1,7 @@ /* Reduced from qemu-7.2.0's hw/intc/omap_intc.c */ +/* { dg-additional-options "-Wno-analyzer-symbol-too-complex" } */ + #include "../../gcc.dg/analyzer/analyzer-decls.h" typedef unsigned char __uint8_t; diff --git a/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108830.c b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108830.c index 0c95148ebd57..1cb1ebe65f96 100644 --- a/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108830.c +++ b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108830.c @@ -1,6 +1,6 @@ /* Reduced from apr-1.7.0/tables/apr_hash.c: 'apr_hash_merge' */ -/* { dg-additional-options "-Wno-analyzer-too-complex" } */ +/* { dg-additional-options "-Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */ #include "../../gcc.dg/analyzer/analyzer-decls.h" diff --git a/gcc/testsuite/c-c++-common/analyzer/pr94596.c b/gcc/testsuite/c-c++-common/analyzer/pr94596.c index 10ea549924e0..0d6240941d7b 100644 --- a/gcc/testsuite/c-c++-common/analyzer/pr94596.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr94596.c @@ -17,6 +17,9 @@ */ #include "../../gcc.dg/analyzer/analyzer-decls.h" + +/* { dg-additional-options "-Wno-analyzer-symbol-too-complex" } */ + typedef __SIZE_TYPE__ size_t; #ifndef __cplusplus diff --git a/gcc/testsuite/c-c++-common/analyzer/strtok-2.c b/gcc/testsuite/c-c++-common/analyzer/strtok-2.c index 0336bf0cfe9d..f34b4a7198a8 100644 --- a/gcc/testsuite/c-c++-common/analyzer/strtok-2.c +++ b/gcc/testsuite/c-c++-common/analyzer/strtok-2.c @@ -1,3 +1,5 @@ +/* { dg-additional-options "-Wno-analyzer-symbol-too-complex" } */ + #include "../../gcc.dg/analyzer/analyzer-decls.h" extern char *strtok (char *str, const char *delim) diff --git a/gcc/testsuite/c-c++-common/analyzer/strtok-4.c b/gcc/testsuite/c-c++-common/analyzer/strtok-4.c index b6b7d49e3c3c..793c7fcb7f40 100644 --- a/gcc/testsuite/c-c++-common/analyzer/strtok-4.c +++ b/gcc/testsuite/c-c++-common/analyzer/strtok-4.c @@ -1,3 +1,5 @@ +/* { dg-additional-options "-Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */ + #include "../../gcc.dg/analyzer/analyzer-decls.h" extern char *strtok (char *str, const char *delim); diff --git a/gcc/testsuite/c-c++-common/analyzer/strtok-cppreference.c b/gcc/testsuite/c-c++-common/analyzer/strtok-cppreference.c index a2e912341d68..a396c643f116 100644 --- a/gcc/testsuite/c-c++-common/analyzer/strtok-cppreference.c +++ b/gcc/testsuite/c-c++-common/analyzer/strtok-cppreference.c @@ -11,6 +11,8 @@ should be released under an equivalent license so that everyone could benefit from the modified versions. " */ +/* { dg-additional-options " -Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */ + #define __STDC_WANT_LIB_EXT1__ 0 #include #include diff --git a/gcc/testsuite/gcc.dg/analyzer/analyzer.exp b/gcc/testsuite/gcc.dg/analyzer/analyzer.exp index cedf3c0466fd..ba5aa680fc7a 100644 --- a/gcc/testsuite/gcc.dg/analyzer/analyzer.exp +++ b/gcc/testsuite/gcc.dg/analyzer/analyzer.exp @@ -30,7 +30,7 @@ if [info exists DEFAULT_CFLAGS] then { } # If a testcase doesn't have special options, use these. -set DEFAULT_CFLAGS "-fanalyzer -Wanalyzer-too-complex -fanalyzer-call-summaries" +set DEFAULT_CFLAGS "-fanalyzer -Wanalyzer-too-complex -Wanalyzer-symbol-too-complex -fanalyzer-call-summaries" if { [istarget "*-*-darwin*" ] } { # On macOS, system headers redefine by default some macros (memcpy, diff --git a/gcc/testsuite/gcc.dg/analyzer/attr-const-3.c b/gcc/testsuite/gcc.dg/analyzer/attr-const-3.c index fc8527a5d0e7..11238a77a658 100644 --- a/gcc/testsuite/gcc.dg/analyzer/attr-const-3.c +++ b/gcc/testsuite/gcc.dg/analyzer/attr-const-3.c @@ -1,7 +1,7 @@ /* Verify that we handle unknown values passed to __attribute__ ((const)) (by imposing a complexity limit). */ -/* { dg-additional-options "--param analyzer-max-svalue-depth=4" } */ +/* { dg-additional-options "--param analyzer-max-svalue-depth=4 -Wno-analyzer-symbol-too-complex" } */ #include "analyzer-decls.h" diff --git a/gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107072.c b/gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107072.c index 6e583d0228ff..f59318b428f4 100644 --- a/gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107072.c +++ b/gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107072.c @@ -1,5 +1,5 @@ /* { dg-require-effective-target int32plus } */ -/* { dg-additional-options "-fanalyzer-call-summaries --param analyzer-min-snodes-for-call-summary=0" } */ +/* { dg-additional-options "-fanalyzer-call-summaries --param analyzer-min-snodes-for-call-summary=0 -Wno-analyzer-symbol-too-complex" } */ /* There need to be at least two calls to a function for the call-summarization code to be used. diff --git a/gcc/testsuite/gcc.dg/analyzer/doom-s_sound-pr108867.c b/gcc/testsuite/gcc.dg/analyzer/doom-s_sound-pr108867.c index ae58f03d3b32..fdc21a2bec3d 100644 --- a/gcc/testsuite/gcc.dg/analyzer/doom-s_sound-pr108867.c +++ b/gcc/testsuite/gcc.dg/analyzer/doom-s_sound-pr108867.c @@ -1,6 +1,6 @@ /* Reduced from Doom's linuxdoom-1.10/s_sound.c, which is GPLv2 or later. */ -/* { dg-additional-options "-fno-analyzer-call-summaries -Wno-analyzer-too-complex" } */ +/* { dg-additional-options "-fno-analyzer-call-summaries -Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */ /* { dg-require-effective-target size32plus } */ typedef struct _IO_FILE FILE; diff --git a/gcc/testsuite/gcc.dg/analyzer/explode-4.c b/gcc/testsuite/gcc.dg/analyzer/explode-4.c index 874b1e9c3008..a98dfb56bf50 100644 --- a/gcc/testsuite/gcc.dg/analyzer/explode-4.c +++ b/gcc/testsuite/gcc.dg/analyzer/explode-4.c @@ -3,7 +3,7 @@ conjured_svalues whilst handling a long chain of external function calls. */ -/* { dg-additional-options "-Wno-implicit-function-declaration -Wno-int-conversion -Wno-analyzer-too-complex" } */ +/* { dg-additional-options "-Wno-implicit-function-declaration -Wno-int-conversion -Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */ #define NULL ((void *)0) typedef unsigned char uint8_t; diff --git a/gcc/testsuite/gcc.dg/analyzer/null-deref-pr102671-1.c b/gcc/testsuite/gcc.dg/analyzer/null-deref-pr102671-1.c index 3fe061bdbd88..65c7bac1f7e9 100644 --- a/gcc/testsuite/gcc.dg/analyzer/null-deref-pr102671-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/null-deref-pr102671-1.c @@ -1,5 +1,5 @@ /* { dg-require-effective-target ptr_eq_long } */ -/* { dg-additional-options "-O2 -Wno-shift-count-overflow" } */ +/* { dg-additional-options "-O2 -Wno-shift-count-overflow -Wno-analyzer-symbol-too-complex" } */ struct lisp; union vectorlike_header { long size; }; diff --git a/gcc/testsuite/gcc.dg/analyzer/null-deref-pr105755.c b/gcc/testsuite/gcc.dg/analyzer/null-deref-pr105755.c index 2b0ba292e00c..5375b4dd6f6f 100644 --- a/gcc/testsuite/gcc.dg/analyzer/null-deref-pr105755.c +++ b/gcc/testsuite/gcc.dg/analyzer/null-deref-pr105755.c @@ -1,5 +1,5 @@ /* { dg-require-effective-target int32plus } */ -/* { dg-additional-options "-Wno-analyzer-too-complex -O2" } */ +/* { dg-additional-options "-Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex -O2" } */ typedef long int ptrdiff_t; typedef long int EMACS_INT; diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-curl.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-curl.c index e34b572966e2..d14661cbc6ae 100644 --- a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-curl.c +++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-curl.c @@ -1,4 +1,4 @@ -/* { dg-additional-options "-O2" } */ +/* { dg-additional-options "-O2 -Wno-analyzer-symbol-too-complex" } */ #include /* Reduced from curl lib/smb.c. */ diff --git a/gcc/testsuite/gcc.dg/analyzer/pr101503.c b/gcc/testsuite/gcc.dg/analyzer/pr101503.c index 16faf6eac2f7..cc4d801d8a6c 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr101503.c +++ b/gcc/testsuite/gcc.dg/analyzer/pr101503.c @@ -1,4 +1,4 @@ -/* { dg-additional-options "--param analyzer-max-svalue-depth=0" } */ +/* { dg-additional-options "--param analyzer-max-svalue-depth=0 -Wno-analyzer-symbol-too-complex" } */ int val; diff --git a/gcc/testsuite/gcc.dg/analyzer/pr103892.c b/gcc/testsuite/gcc.dg/analyzer/pr103892.c index d16cd83c472f..a17c3b7e119e 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr103892.c +++ b/gcc/testsuite/gcc.dg/analyzer/pr103892.c @@ -1,4 +1,4 @@ -/* { dg-additional-options "-O2" } */ +/* { dg-additional-options "-O2 -Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */ /* C only: C++ FE optimizes argstr_get_word completely away and therefore the number of SN diminishes compared to C, diff --git a/gcc/testsuite/gcc.dg/analyzer/pr94851-4.c b/gcc/testsuite/gcc.dg/analyzer/pr94851-4.c index 2a15a5d7f5bf..a5130c59cb00 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr94851-4.c +++ b/gcc/testsuite/gcc.dg/analyzer/pr94851-4.c @@ -1,4 +1,4 @@ -/* { dg-additional-options "-O2" } */ +/* { dg-additional-options "-O2 -Wno-analyzer-symbol-too-complex" } */ #include diff --git a/gcc/testsuite/gcc.dg/analyzer/pr96860-1.c b/gcc/testsuite/gcc.dg/analyzer/pr96860-1.c index 8f298ec04e71..8be30b3a6dad 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr96860-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/pr96860-1.c @@ -1,5 +1,5 @@ /* { dg-require-effective-target int128 } */ -/* { dg-additional-options "--param analyzer-max-svalue-depth=0" } */ +/* { dg-additional-options "--param analyzer-max-svalue-depth=0 -Wno-analyzer-symbol-too-complex" } */ void x7 (void) { diff --git a/gcc/testsuite/gcc.dg/analyzer/pr96860-2.c b/gcc/testsuite/gcc.dg/analyzer/pr96860-2.c index 90a818cb2836..d12b9a1e1fa6 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr96860-2.c +++ b/gcc/testsuite/gcc.dg/analyzer/pr96860-2.c @@ -1,4 +1,4 @@ -/* { dg-additional-options "--param analyzer-max-svalue-depth=0" } */ +/* { dg-additional-options "--param analyzer-max-svalue-depth=0 -Wno-analyzer-symbol-too-complex" } */ void x7 (void) { diff --git a/gcc/testsuite/gcc.dg/analyzer/pr98918.c b/gcc/testsuite/gcc.dg/analyzer/pr98918.c index ac626ba1f308..c3bbce3e6ec1 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr98918.c +++ b/gcc/testsuite/gcc.dg/analyzer/pr98918.c @@ -1,3 +1,5 @@ +/* { dg-additional-options "-Wno-analyzer-symbol-too-complex" } */ + #include struct marker { diff --git a/gcc/testsuite/gcc.dg/analyzer/pr99044-2.c b/gcc/testsuite/gcc.dg/analyzer/pr99044-2.c index fd71d35d7e4e..f7badb92f448 100644 --- a/gcc/testsuite/gcc.dg/analyzer/pr99044-2.c +++ b/gcc/testsuite/gcc.dg/analyzer/pr99044-2.c @@ -1,3 +1,5 @@ +/* { dg-additional-options "-Wno-analyzer-symbol-too-complex" } */ + struct node { struct node *next; diff --git a/gcc/testsuite/gcc.dg/analyzer/uninit-pr108806-qemu.c b/gcc/testsuite/gcc.dg/analyzer/uninit-pr108806-qemu.c index 34fe802f4952..092720111286 100644 --- a/gcc/testsuite/gcc.dg/analyzer/uninit-pr108806-qemu.c +++ b/gcc/testsuite/gcc.dg/analyzer/uninit-pr108806-qemu.c @@ -5,6 +5,8 @@ struct omap_intr_handler_bank_s* bank; */ +/* { dg-additional-options "-Wno-analyzer-symbol-too-complex" } */ + typedef unsigned char __uint8_t; typedef unsigned int __uint32_t; typedef unsigned long int __uint64_t; diff --git a/gcc/testsuite/gcc.dg/analyzer/use-after-free.c b/gcc/testsuite/gcc.dg/analyzer/use-after-free.c index d7e4bc2c6cac..76a85f563350 100644 --- a/gcc/testsuite/gcc.dg/analyzer/use-after-free.c +++ b/gcc/testsuite/gcc.dg/analyzer/use-after-free.c @@ -1,3 +1,5 @@ +/* { dg-additional-options "-Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */ + #include #include "analyzer-decls.h" diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp index f098a327d319..f0b4bb7a051f 100644 --- a/gcc/testsuite/gcc.dg/plugin/plugin.exp +++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp @@ -162,7 +162,11 @@ set plugin_test_list [list \ taint-CVE-2011-0521-5.c \ taint-CVE-2011-0521-5-fixed.c \ taint-CVE-2011-0521-6.c \ - taint-antipatterns-1.c } \ + taint-antipatterns-1.c \ + taint-pr112850.c \ + taint-pr112850-precise.c \ + taint-pr112850-too-complex.c \ + taint-pr112850-unsanitized.c } \ { analyzer_cpython_plugin.c \ cpython-plugin-test-no-Python-h.c \ cpython-plugin-test-PyList_Append.c \ diff --git a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-4.c b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-4.c index 06b3468fca58..e268a8eab8fc 100644 --- a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-4.c +++ b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-4.c @@ -32,9 +32,9 @@ int test_1(struct file *file, unsigned int cmd, unsigned long arg) if (info->num > 1) return -EINVAL; av7110->ci_slot[info->num].num = info->num; /* { dg-warning "attacker-controlled value" } */ - av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ? /* { dg-warning "attacker-controlled value" } */ + av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ? CA_CI_LINK : CA_CI; - memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t)); /* { dg-warning "attacker-controlled value" } */ + memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t)); } copy_to_user((void __user *)arg, parg, sizeof(sbuf)); diff --git a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5-fixed.c b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5-fixed.c index 076ada3a20a8..b39e693da632 100644 --- a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5-fixed.c +++ b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5-fixed.c @@ -39,8 +39,7 @@ int test_1(struct file *file, unsigned int cmd, unsigned long arg) av7110->ci_slot[info->num].num = info->num; av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ? CA_CI_LINK : CA_CI; - memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t)); /* { dg-bogus "use of attacker-controlled value in array lookup without bounds checking" "" { xfail *-*-* } } */ - // FIXME: why the above false +ve? + memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t)); /* { dg-bogus "use of attacker-controlled value in array lookup without bounds checking" } */ } copy_to_user((void __user *)arg, &sbuf, sizeof(sbuf)); diff --git a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5.c b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5.c index e27ee469df8f..fe216c0a3c44 100644 --- a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5.c +++ b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5.c @@ -37,9 +37,9 @@ int test_1(struct file *file, unsigned int cmd, unsigned long arg) __analyzer_dump_state ("taint", info->num); /* { dg-warning "has_ub" } */ av7110->ci_slot[info->num].num = info->num; /* { dg-warning "use of attacker-controlled value '\\*info\\.num' in array lookup without checking for negative" } */ - av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ? /* { dg-warning "use of attacker-controlled value '\\*info\\.num' in array lookup without checking for negative" } */ + av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ? CA_CI_LINK : CA_CI; - memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t)); /* { dg-warning "use of attacker-controlled value in array lookup without bounds checking" } */ + memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t)); } copy_to_user((void __user *)arg, &sbuf, sizeof(sbuf)); diff --git a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-6.c b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-6.c index fea70ee57617..5b68de324708 100644 --- a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-6.c +++ b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-6.c @@ -34,9 +34,9 @@ int test_1(struct file *file, unsigned int cmd, unsigned long arg) //__analyzer_break (); av7110->ci_slot[info->num].num = info->num; /* { dg-warning "use of attacker-controlled value '\\*info\\.num' in array lookup without bounds checking" } */ - av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ? /* { dg-warning "use of attacker-controlled value '\\*info\\.num' in array lookup without bounds checking" } */ + av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ? CA_CI_LINK : CA_CI; - memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t)); /* { dg-warning "use of attacker-controlled value in array lookup without bounds checking" } */ + memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t)); } copy_to_user((void __user *)arg, &sbuf, sizeof(sbuf)); diff --git a/gcc/testsuite/gcc.dg/plugin/taint-pr112850-precise.c b/gcc/testsuite/gcc.dg/plugin/taint-pr112850-precise.c new file mode 100644 index 000000000000..558f0fb1a8ae --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/taint-pr112850-precise.c @@ -0,0 +1,50 @@ +/* Reduced from false positive in Linux kernel in sound/core/rawmidi.c. + + Use a value of --param=analyzer-max-svalue-depth= high enough to avoid + UNKNOWN svalues; make sure we don't get false positives with this case. */ + +/* { dg-do compile } */ +/* { dg-options "-fanalyzer -O2 -Wanalyzer-symbol-too-complex --param=analyzer-max-svalue-depth=13" } */ +/* { dg-require-effective-target analyzer } */ + +typedef unsigned long __kernel_ulong_t; +typedef __kernel_ulong_t __kernel_size_t; +typedef __kernel_size_t size_t; +typedef unsigned int gfp_t; + +extern unsigned long copy_from_user(void* to, const void* from, unsigned long n); + +extern +__attribute__((__alloc_size__(1))) +__attribute__((__malloc__)) void* +kvzalloc(size_t size, gfp_t flags); + +struct snd_rawmidi_params +{ + int stream; + size_t buffer_size; +}; + +char *newbuf; + +static int +resize_runtime_buffer(struct snd_rawmidi_params* params) +{ + if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) /* { dg-bogus "symbol too complicated" } */ + return -22; + newbuf = kvzalloc(params->buffer_size, /* { dg-bogus "use of attacker-controlled value '\\*params.buffer_size' as allocation size without upper-bounds checking" "PR analyzer/112850" } */ + (((gfp_t)(0x400u | 0x800u)) | ((gfp_t)0x40u) | ((gfp_t)0x80u))); + if (!newbuf) + return -12; + return 0; +} + +long +snd_rawmidi_ioctl(unsigned long arg) +{ + void* argp = (void*)arg; + struct snd_rawmidi_params params; + if (copy_from_user(¶ms, argp, sizeof(struct snd_rawmidi_params))) + return -14; + return resize_runtime_buffer(¶ms); +} diff --git a/gcc/testsuite/gcc.dg/plugin/taint-pr112850-too-complex.c b/gcc/testsuite/gcc.dg/plugin/taint-pr112850-too-complex.c new file mode 100644 index 000000000000..2a4ee8197c38 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/taint-pr112850-too-complex.c @@ -0,0 +1,51 @@ +/* Reduced from false positive in Linux kernel in sound/core/rawmidi.c. + + With --param=analyzer-max-svalue-depth=12, the value being compared + at the sanitization is too complex and becomes UNKNOWN; make sure + this doesn't lead to a false positive. */ + +/* { dg-do compile } */ +/* { dg-options "-fanalyzer -O2 -Wanalyzer-symbol-too-complex --param=analyzer-max-svalue-depth=12" } */ +/* { dg-require-effective-target analyzer } */ + +typedef unsigned long __kernel_ulong_t; +typedef __kernel_ulong_t __kernel_size_t; +typedef __kernel_size_t size_t; +typedef unsigned int gfp_t; + +extern unsigned long copy_from_user(void* to, const void* from, unsigned long n); + +extern +__attribute__((__alloc_size__(1))) +__attribute__((__malloc__)) void* +kvzalloc(size_t size, gfp_t flags); + +struct snd_rawmidi_params +{ + int stream; + size_t buffer_size; +}; + +char *newbuf; + +static int +resize_runtime_buffer(struct snd_rawmidi_params* params) +{ + if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) /* { dg-warning "symbol too complicated" } */ + return -22; + newbuf = kvzalloc(params->buffer_size, /* { dg-bogus "use of attacker-controlled value '\\*params.buffer_size' as allocation size without upper-bounds checking" "PR analyzer/112850" } */ + (((gfp_t)(0x400u | 0x800u)) | ((gfp_t)0x40u) | ((gfp_t)0x80u))); + if (!newbuf) + return -12; + return 0; +} + +long +snd_rawmidi_ioctl(unsigned long arg) +{ + void* argp = (void*)arg; + struct snd_rawmidi_params params; + if (copy_from_user(¶ms, argp, sizeof(struct snd_rawmidi_params))) + return -14; + return resize_runtime_buffer(¶ms); +} diff --git a/gcc/testsuite/gcc.dg/plugin/taint-pr112850-unsanitized.c b/gcc/testsuite/gcc.dg/plugin/taint-pr112850-unsanitized.c new file mode 100644 index 000000000000..e46fcb6c8a10 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/taint-pr112850-unsanitized.c @@ -0,0 +1,50 @@ +/* Reduced from false positive in Linux kernel in sound/core/rawmidi.c, + with sanitization removed to make it a true positive. + + Verify that we detect this (with default params). */ + +/* { dg-do compile } */ +/* { dg-options "-fanalyzer -O2 -Wanalyzer-too-complex" } */ +/* { dg-require-effective-target analyzer } */ + +typedef unsigned long __kernel_ulong_t; +typedef __kernel_ulong_t __kernel_size_t; +typedef __kernel_size_t size_t; +typedef unsigned int gfp_t; + +extern unsigned long copy_from_user(void* to, const void* from, unsigned long n); + +extern +__attribute__((__alloc_size__(1))) +__attribute__((__malloc__)) void* +kvzalloc(size_t size, gfp_t flags); + +struct snd_rawmidi_params +{ + int stream; + size_t buffer_size; +}; + +char *newbuf; + +static int +resize_runtime_buffer(struct snd_rawmidi_params* params) +{ + /* No sanitization, so we should complain. */ + + newbuf = kvzalloc(params->buffer_size, /* { dg-warning "use of attacker-controlled value '\\*params.buffer_size' as allocation size without upper-bounds checking" "PR analyzer/112850" } */ + (((gfp_t)(0x400u | 0x800u)) | ((gfp_t)0x40u) | ((gfp_t)0x80u))); + if (!newbuf) + return -12; + return 0; +} + +long +snd_rawmidi_ioctl(unsigned long arg) +{ + void* argp = (void*)arg; + struct snd_rawmidi_params params; + if (copy_from_user(¶ms, argp, sizeof(struct snd_rawmidi_params))) + return -14; + return resize_runtime_buffer(¶ms); +} diff --git a/gcc/testsuite/gcc.dg/plugin/taint-pr112850.c b/gcc/testsuite/gcc.dg/plugin/taint-pr112850.c new file mode 100644 index 000000000000..6fa1d0f9bd4b --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/taint-pr112850.c @@ -0,0 +1,47 @@ +/* Reduced from false positive in Linux kernel in sound/core/rawmidi.c. */ + +/* { dg-do compile } */ +/* { dg-options "-fanalyzer -O2 -Wanalyzer-symbol-too-complex" } */ +/* { dg-require-effective-target analyzer } */ + +typedef unsigned long __kernel_ulong_t; +typedef __kernel_ulong_t __kernel_size_t; +typedef __kernel_size_t size_t; +typedef unsigned int gfp_t; + +extern unsigned long copy_from_user(void* to, const void* from, unsigned long n); + +extern +__attribute__((__alloc_size__(1))) +__attribute__((__malloc__)) void* +kvzalloc(size_t size, gfp_t flags); + +struct snd_rawmidi_params +{ + int stream; + size_t buffer_size; +}; + +char *newbuf; + +static int +resize_runtime_buffer(struct snd_rawmidi_params* params) +{ + if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) /* { dg-bogus "symbol too complicated" } */ + return -22; + newbuf = kvzalloc(params->buffer_size, /* { dg-bogus "use of attacker-controlled value '\\*params.buffer_size' as allocation size without upper-bounds checking" "PR analyzer/112850" } */ + (((gfp_t)(0x400u | 0x800u)) | ((gfp_t)0x40u) | ((gfp_t)0x80u))); + if (!newbuf) + return -12; + return 0; +} + +long +snd_rawmidi_ioctl(unsigned long arg) +{ + void* argp = (void*)arg; + struct snd_rawmidi_params params; + if (copy_from_user(¶ms, argp, sizeof(struct snd_rawmidi_params))) + return -14; + return resize_runtime_buffer(¶ms); +}