From 0f1a40d983eaf798fa7ff12da5dc95b73454da69 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 19 Sep 2019 09:53:01 +0100 Subject: [PATCH 1/2] QL training: add first few slides for variant analysis/C++. --- .../ql-training/cpp/variant-analysis-tips.rst | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 docs/language/ql-training/cpp/variant-analysis-tips.rst diff --git a/docs/language/ql-training/cpp/variant-analysis-tips.rst b/docs/language/ql-training/cpp/variant-analysis-tips.rst new file mode 100644 index 000000000000..488911fa27c8 --- /dev/null +++ b/docs/language/ql-training/cpp/variant-analysis-tips.rst @@ -0,0 +1,58 @@ +================================ +Variant analysis tips and tricks +================================ + +QL for C/C++ + +.. container:: semmle-logo + + Semmle :sup:`TM` + +.. rst-class:: agenda + +Agenda +====== + +- Range analysis +- Guards + +Range analysis +============== + +*Range analysis* is the process of determining upper and lower bounds for arithmetic values in the program. + + .. code-block:: cpp + + void f(int x) { + if (x < -1 || x > 16) { + return; + } + val[x]; // What possible values can x hold here? + } + +Simple range analysis +===================== + +The standard libraries include the ``semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis`` QL library. This determines, where possible, fixed bounds for an arithmetic expression. + + .. code-block:: ql + + import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis + + from ArrayExpr ae + where lowerBound(ae.getArrayOffset()) < 0 + select ae + + +Simple range analysis: use cases +================================ + +This library only supports *constant* bounds - it will return a + +The Semmle C/C++ standard library includes the ``SimpleRangeAnalysis`` . + + +Guards +====== + +*Guards* are conditions which \ No newline at end of file From 936960310d26fd6d4e028a45f0660758b9339170 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 19 Sep 2019 13:31:02 +0100 Subject: [PATCH 2/2] C#: Complete first draft of variant analysis for C/C++. --- .../ql-training/cpp/variant-analysis-tips.rst | 122 +++++++++++++++--- .../guards/GuardCondition.expected | 2 + .../variant-analysis/guards/GuardCondition.ql | 6 + .../cpp/variant-analysis/guards/test.c | 9 ++ .../SimpleIndexOutOfBounds.expected | 1 + .../range-analysis/SimpleIndexOutOfBounds.ql | 6 + .../variant-analysis/range-analysis/test.c | 7 + 7 files changed, 132 insertions(+), 21 deletions(-) create mode 100644 docs/language/ql-training/query-examples/cpp/variant-analysis/guards/GuardCondition.expected create mode 100644 docs/language/ql-training/query-examples/cpp/variant-analysis/guards/GuardCondition.ql create mode 100644 docs/language/ql-training/query-examples/cpp/variant-analysis/guards/test.c create mode 100644 docs/language/ql-training/query-examples/cpp/variant-analysis/range-analysis/SimpleIndexOutOfBounds.expected create mode 100644 docs/language/ql-training/query-examples/cpp/variant-analysis/range-analysis/SimpleIndexOutOfBounds.ql create mode 100644 docs/language/ql-training/query-examples/cpp/variant-analysis/range-analysis/test.c diff --git a/docs/language/ql-training/cpp/variant-analysis-tips.rst b/docs/language/ql-training/cpp/variant-analysis-tips.rst index 488911fa27c8..9d53ee576e0c 100644 --- a/docs/language/ql-training/cpp/variant-analysis-tips.rst +++ b/docs/language/ql-training/cpp/variant-analysis-tips.rst @@ -2,7 +2,7 @@ Variant analysis tips and tricks ================================ -QL for C/C++ +C/C++ .. container:: semmle-logo @@ -13,46 +13,126 @@ QL for C/C++ Agenda ====== -- Range analysis -- Guards +- Query development process + - Sources of query ideas + - Evaluating query ideas + - Iterative query development +- Useful libraries for C/C++ + - Range analysis + - Guards + +.. rst-class:: background2 + +Query development process +========================== + +Sources of ideas +================ + +- Fix commits in revision history +- Issue reports +- Newly discovered kind of vulnerability +- Transfer from other languages/frameworks +- Chance discovery while working on another query +- Follow Twitter, Hacker News, Snyk, etc. + +Evaluating a query idea +======================= + +- It should be *specific* e.g. not "find all buffer overflows". +- ...but not too specific, only worthwhile if there are some variants to find! +- There should be a concrete test case exhibiting the problem. + +Iterative query development +=========================== + +- Start with a very specific query that just finds the original bug/test case +- Generalize to get at the essence of the problem +- This also helps forming a better understanding of the problem: “thinking in QL” +- As you generalize, vet new results and refine the query to exclude false positives. +- Ideally, the query should not flag the fixed version (if any). + +.. rst-class:: background2 + +Useful libraries for C/C++ +========================== Range analysis ============== *Range analysis* is the process of determining upper and lower bounds for arithmetic values in the program. - .. code-block:: cpp + .. literalinclude:: ../query-examples/cpp/variant-analysis/range-analysis/test.c + :language: cpp - void f(int x) { - if (x < -1 || x > 16) { - return; - } - val[x]; // What possible values can x hold here? - } +This is typically useful for determining underflow, overflow or out of bounds reads/writes. Simple range analysis ===================== -The standard libraries include the ``semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis`` QL library. This determines, where possible, fixed bounds for an arithmetic expression. +QL comes with the ``SimpleRangeAnalysis`` library, which can be used to determine, where possible, *fixed bounds* for +an arithmetic expression. For example: - .. code-block:: ql + .. literalinclude:: ../query-examples/cpp/variant-analysis/range-analysis/SimpleIndexOutOfBounds.ql + :language: ql - import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis +Would find the ``val[x]`` access from the previous slide. - from ArrayExpr ae - where lowerBound(ae.getArrayOffset()) < 0 - select ae +Simple range analysis: API +========================== +- ``lowerBound`` and ``upperBound`` predicates provide lower and upper bounds on expressions, where possible. +- ``exprWithEmptyRange`` predicate identifies expressions which have non-overlapping upper and lower bounds, indicating the expression is dead code. +- Helper predicates of the form ``..MightOverflow..`` are provided for reasoning about overflow. -Simple range analysis: use cases -================================ +Simple range analysis: restrictions +=================================== + +The library only supports *constant* bounds. -This library only supports *constant* bounds - it will return a +e.g. -The Semmle C/C++ standard library includes the ``SimpleRangeAnalysis`` . + .. code-block:: cpp + + if (x >= 1) { + val[x]; // lowerBound(x) = 1 + } + if (x >= y) { + val[x]; // no lowerBound(x) + } + +In particular, we do not deduce that ``lowerBound(x) = y``. Integer values only! + +Simple range analysis: notes +============================ +- Often used to *exclude* known safe cases e.g. a fixed size array where the index upperBound is known. +- Ranges for variables modified in loops may be over approximated (see QL doc for details). +- ``lowerBound(expr)`` reports the bounds *before* conversion. For post conversion, try ``lowerBound(expr.getFullyConverted())``. Guards ====== -*Guards* are conditions which \ No newline at end of file +A *guard* is a condition which controls whether a certain part of the program is executed. For example: + + .. literalinclude:: ../query-examples/cpp/variant-analysis/guards/test.c + :language: cpp + +This is typically useful for determining whether a certain necessary check has occurred before a potentially unsafe operation. + +Guards library +============== + +QL comes with the ``Guards`` library, which can be used to determine which ``BasicBlocks`` are guarded by certain conditions. For example: + + .. literalinclude:: ../query-examples/cpp/variant-analysis/guards/GuardCondition.ql + :language: ql + +Would report the last two ``val[x]`` accesses from the previous slide. + +Guards: API +=========== + +- ``GuardCondition`` represents an expression in the program that is a condition. +- The ``GuardCondition.controls(BasicBlock, boolean)`` predicate represents the set of basic blocks controlled by each guard + condition, and includes whether they are controlled in the true case or false case. diff --git a/docs/language/ql-training/query-examples/cpp/variant-analysis/guards/GuardCondition.expected b/docs/language/ql-training/query-examples/cpp/variant-analysis/guards/GuardCondition.expected new file mode 100644 index 000000000000..b7857a6d8962 --- /dev/null +++ b/docs/language/ql-training/query-examples/cpp/variant-analysis/guards/GuardCondition.expected @@ -0,0 +1,2 @@ +| test.c:6:9:6:14 | access to array | +| test.c:8:7:8:12 | access to array | diff --git a/docs/language/ql-training/query-examples/cpp/variant-analysis/guards/GuardCondition.ql b/docs/language/ql-training/query-examples/cpp/variant-analysis/guards/GuardCondition.ql new file mode 100644 index 000000000000..b16a5773c177 --- /dev/null +++ b/docs/language/ql-training/query-examples/cpp/variant-analysis/guards/GuardCondition.ql @@ -0,0 +1,6 @@ +import cpp +import semmle.code.cpp.controlflow.Guards + +from ArrayExpr ae +where not exists(GuardCondition gc | gc.controls(ae.getBasicBlock(), true)) +select ae \ No newline at end of file diff --git a/docs/language/ql-training/query-examples/cpp/variant-analysis/guards/test.c b/docs/language/ql-training/query-examples/cpp/variant-analysis/guards/test.c new file mode 100644 index 000000000000..16a670f59275 --- /dev/null +++ b/docs/language/ql-training/query-examples/cpp/variant-analysis/guards/test.c @@ -0,0 +1,9 @@ + int val[16]; + void f(int x) { + if (x > 0) { // `x > 0` is a guard condition + val[x]; // guarded by `x > 0`, true case + } else { + val[x]; // guarded by `x > 0`, false case + } + val[x]; // not guarded + } \ No newline at end of file diff --git a/docs/language/ql-training/query-examples/cpp/variant-analysis/range-analysis/SimpleIndexOutOfBounds.expected b/docs/language/ql-training/query-examples/cpp/variant-analysis/range-analysis/SimpleIndexOutOfBounds.expected new file mode 100644 index 000000000000..3779f2341211 --- /dev/null +++ b/docs/language/ql-training/query-examples/cpp/variant-analysis/range-analysis/SimpleIndexOutOfBounds.expected @@ -0,0 +1 @@ +| test.c:6:7:6:12 | access to array | diff --git a/docs/language/ql-training/query-examples/cpp/variant-analysis/range-analysis/SimpleIndexOutOfBounds.ql b/docs/language/ql-training/query-examples/cpp/variant-analysis/range-analysis/SimpleIndexOutOfBounds.ql new file mode 100644 index 000000000000..6272c2554961 --- /dev/null +++ b/docs/language/ql-training/query-examples/cpp/variant-analysis/range-analysis/SimpleIndexOutOfBounds.ql @@ -0,0 +1,6 @@ +import cpp +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis + +from ArrayExpr ae +where lowerBound(ae.getArrayOffset()) < 0 +select ae \ No newline at end of file diff --git a/docs/language/ql-training/query-examples/cpp/variant-analysis/range-analysis/test.c b/docs/language/ql-training/query-examples/cpp/variant-analysis/range-analysis/test.c new file mode 100644 index 000000000000..1d9cd696c348 --- /dev/null +++ b/docs/language/ql-training/query-examples/cpp/variant-analysis/range-analysis/test.c @@ -0,0 +1,7 @@ + int val[16]; + void f(int x) { + if (x < -1 || x > 15) { + return; + } + val[x]; // What possible range of values can x hold here? + } \ No newline at end of file