Merge: boolean value-analysis (completes assume_safe_booleans1)
ober
0045080c062358663f283204061750ef0aaeb6f6
--- a/lib/semgrep/scan.sls +++ b/lib/semgrep/scan.sls @@ -32166,6 +32166,27 @@ (and val before (java-value-numeric? val source-text before 0)))) + (def (java-boolean-value-expr? text) + (let ([t (string-trim text)]) + (or (text-contains-comparison? t) + (string-find-substring t "Boolean.valueOf(") + (string-find-substring t "Boolean.parseBoolean(") + (string-find-substring t ".equals(") + (string-find-substring t ".equalsIgnoreCase(") + (string-find-substring t ".contains(") + (string-find-substring t ".containsKey(") + (string-find-substring t ".isEmpty(") + (string-find-substring t ".startsWith(") + (string-find-substring t ".endsWith(") + (string-find-substring t ".matches(") + (string-find-substring t ".isPresent(") + (string-find-substring t " instanceof ")))) + (def (sink-value-boolean? 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-boolean-value-expr? val)))) (def (taint-assume-safe-indexes? rule) (rule-option-enabled? rule "taint_assume_safe_indexes")) (def (taint-assume-safe-functions? rule) @@ -33256,16 +33277,22 @@ (let* ([requires (alist-ref/default sink-spec 'requires #f)] [reaching0 (source-states-reaching-sink rule sink-spec sources sanitizers assignment-kills source-text)] - [reaching (if (taint-assume-safe-numbers? rule) - (if (sink-value-numeric? sink-spec source-text) - '() - (sg-filter - (lambda (ss) - (not (source-state-numeric-typed-param? - ss - source-text))) - reaching0)) - reaching0)] + [reaching (cond + [(taint-assume-safe-numbers? rule) + (if (sink-value-numeric? sink-spec source-text) + '() + (sg-filter + (lambda (ss) + (not (source-state-numeric-typed-param? + ss + source-text))) + reaching0))] + [(and (taint-assume-safe-booleans? rule) + (sink-value-boolean? + sink-spec + source-text)) + '()] + [else reaching0])] [labels (label-set-for-source-states reaching)]) (if (and (not (null? labels)) (requires-satisfied? labels requires)) --- a/src/semgrep/scan.ss +++ b/src/semgrep/scan.ss @@ -32086,6 +32086,35 @@ (and val before (java-value-numeric? val source-text before 0)))) +;; --- assume_safe_booleans: a value of boolean type carries no taint. A +;; comparison is already handled by the assume_safe_comparisons gate (which +;; taint-assume-safe-booleans? subsumes); this adds boolean-returning calls +;; (`Boolean.valueOf`/`parseBoolean`, `.equals`/`.contains`/`.isEmpty`/...), +;; `instanceof`, so `sink(Boolean.valueOf(x))` is safe while `sink("a" + x)` +;; (a String concat) still flags. +(def (java-boolean-value-expr? text) + (let ([t (string-trim text)]) + (or (text-contains-comparison? t) + (string-find-substring t "Boolean.valueOf(") + (string-find-substring t "Boolean.parseBoolean(") + (string-find-substring t ".equals(") + (string-find-substring t ".equalsIgnoreCase(") + (string-find-substring t ".contains(") + (string-find-substring t ".containsKey(") + (string-find-substring t ".isEmpty(") + (string-find-substring t ".startsWith(") + (string-find-substring t ".endsWith(") + (string-find-substring t ".matches(") + (string-find-substring t ".isPresent(") + (string-find-substring t " instanceof ")))) + +(def (sink-value-boolean? 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-boolean-value-expr? val)))) + (def (taint-assume-safe-indexes? rule) (rule-option-enabled? rule "taint_assume_safe_indexes")) @@ -33150,14 +33179,18 @@ assignment-kills source-text)] [reaching - (if (taint-assume-safe-numbers? rule) - (if (sink-value-numeric? sink-spec source-text) - '() - (sg-filter - (lambda (ss) - (not (source-state-numeric-typed-param? ss source-text))) - reaching0)) - reaching0)] + (cond + [(taint-assume-safe-numbers? rule) + (if (sink-value-numeric? sink-spec source-text) + '() + (sg-filter + (lambda (ss) + (not (source-state-numeric-typed-param? ss source-text))) + reaching0))] + [(and (taint-assume-safe-booleans? rule) + (sink-value-boolean? sink-spec source-text)) + '()] + [else reaching0])] [labels (label-set-for-source-states reaching)]) (if (and (not (null? labels)) (requires-satisfied? labels requires))