Merge: numeric value-analysis (assume-safe step 3)
ober
0e959ffbac921d2f9af0e42d4e4f657c6eb2f42b
--- a/lib/semgrep/scan.sls +++ b/lib/semgrep/scan.sls @@ -31982,6 +31982,38 @@ (param-type-before-name source-text (finding-start-offset finding)))))) + (def (java-numeric-value-expr? text) + (let ([t (string-trim text)]) + (or (sg-string-suffix? ".length" t) + (text-contains-numeric-cast? t) + (string-find-substring t "(long)") + (string-find-substring t "(short)") + (string-find-substring t "(byte)") + (string-find-substring t "(char)") + (string-find-substring t ".length()") + (string-find-substring t ".size()") + (string-find-substring t ".hashCode()") + (string-find-substring t ".ordinal()") + (string-find-substring t ".intValue()") + (string-find-substring t ".longValue()") + (string-find-substring t ".compareTo(") + (string-find-substring t ".compareToIgnoreCase(") + (string-find-substring t ".indexOf(") + (string-find-substring t ".lastIndexOf(") + (string-find-substring t "Integer.parseInt(") + (string-find-substring t "Integer.valueOf(") + (string-find-substring t "Long.parseLong(") + (string-find-substring t "Long.valueOf(") + (string-find-substring t "Short.parseShort(") + (string-find-substring t "Byte.parseByte(") + (string-find-substring t "Double.parseDouble(") + (string-find-substring t "Float.parseFloat(")))) + (def (sink-value-numeric? sink-spec source-text) + (let* ([sink (sink-finding sink-spec)] + [val (and sink + (or (direct-call-argument-text sink source-text) + (finding-text sink source-text)))]) + (and val (java-numeric-value-expr? val)))) (def (taint-assume-safe-indexes? rule) (rule-option-enabled? rule "taint_assume_safe_indexes")) (def (taint-assume-safe-functions? rule) @@ -33072,12 +33104,14 @@ [reaching0 (source-states-reaching-sink rule sink-spec sources sanitizers assignment-kills source-text)] [reaching (if (taint-assume-safe-numbers? rule) - (sg-filter - (lambda (ss) - (not (source-state-numeric-typed-param? - ss - source-text))) - reaching0) + (if (sink-value-numeric? sink-spec source-text) + '() + (sg-filter + (lambda (ss) + (not (source-state-numeric-typed-param? + ss + source-text))) + reaching0)) reaching0)] [labels (label-set-for-source-states reaching)]) (if (and (not (null? labels)) --- a/src/semgrep/scan.ss +++ b/src/semgrep/scan.ss @@ -31920,6 +31920,44 @@ (java-numeric-type-name? (param-type-before-name source-text (finding-start-offset finding)))))) +;; --- assume_safe_numbers: a value whose Java static type is numeric carries no +;; taint, even if derived from a tainted receiver. Recognizes array `.length`, +;; a numeric cast, and numeric-returning library calls (`compareTo`, `size`, +;; `Integer.parseInt`, ...). Used to drop a sink whose argument is such a value. +(def (java-numeric-value-expr? text) + (let ([t (string-trim text)]) + (or (sg-string-suffix? ".length" t) + (text-contains-numeric-cast? t) + (string-find-substring t "(long)") + (string-find-substring t "(short)") + (string-find-substring t "(byte)") + (string-find-substring t "(char)") + (string-find-substring t ".length()") + (string-find-substring t ".size()") + (string-find-substring t ".hashCode()") + (string-find-substring t ".ordinal()") + (string-find-substring t ".intValue()") + (string-find-substring t ".longValue()") + (string-find-substring t ".compareTo(") + (string-find-substring t ".compareToIgnoreCase(") + (string-find-substring t ".indexOf(") + (string-find-substring t ".lastIndexOf(") + (string-find-substring t "Integer.parseInt(") + (string-find-substring t "Integer.valueOf(") + (string-find-substring t "Long.parseLong(") + (string-find-substring t "Long.valueOf(") + (string-find-substring t "Short.parseShort(") + (string-find-substring t "Byte.parseByte(") + (string-find-substring t "Double.parseDouble(") + (string-find-substring t "Float.parseFloat(")))) + +(def (sink-value-numeric? sink-spec source-text) + (let* ([sink (sink-finding sink-spec)] + [val (and sink + (or (direct-call-argument-text sink source-text) + (finding-text sink source-text)))]) + (and val (java-numeric-value-expr? val)))) + (def (taint-assume-safe-indexes? rule) (rule-option-enabled? rule "taint_assume_safe_indexes")) @@ -32984,10 +33022,12 @@ source-text)] [reaching (if (taint-assume-safe-numbers? rule) - (sg-filter - (lambda (ss) - (not (source-state-numeric-typed-param? ss source-text))) - reaching0) + (if (sink-value-numeric? sink-spec source-text) + '() + (sg-filter + (lambda (ss) + (not (source-state-numeric-typed-param? ss source-text))) + reaching0)) reaching0)] [labels (label-set-for-source-states reaching)]) (if (and (not (null? labels))