Skip to content

Commit e9c369c

Browse files
Update comments.
1 parent 0fd5529 commit e9c369c

6 files changed

Lines changed: 57 additions & 22 deletions

File tree

ql_demos/cpp/libssh2_eating_error_codes/00_error_codes.ql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44

55
import cpp
66

7+
// Look for return statements that return a negative integer constant.
8+
// For example:
9+
//
10+
// return -1;
11+
//
12+
// The negative return value might be an error code.
713
from ReturnStmt ret
814
where ret.getExpr().getValue().toInt() < 0
915
select ret

ql_demos/cpp/libssh2_eating_error_codes/01_error_codes_call.ql

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44

55
import cpp
66

7+
// Extend the previous query to also find calls to functions that sometimes
8+
// return a negative integer constant.
79
from Function f, FunctionCall call, ReturnStmt ret
8-
where call.getTarget() = f
9-
and ret.getEnclosingFunction() = f
10-
and ret.getExpr().getValue().toInt() < 0
10+
where
11+
call.getTarget() = f and
12+
ret.getEnclosingFunction() = f and
13+
ret.getExpr().getValue().toInt() < 0
1114
select ret, call

ql_demos/cpp/libssh2_eating_error_codes/02_eating_error_codes.ql

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44

55
import cpp
66

7+
// Look for calls that are cast to unsigned, which means that the error
8+
// code might be accidentally ignored.
79
from Function f, FunctionCall call, ReturnStmt ret
8-
where call.getTarget() = f
9-
and ret.getEnclosingFunction() = f
10-
and ret.getExpr().getValue().toInt() < 0
11-
and call.getFullyConverted().getType().getUnderlyingType().(IntegralType).isUnsigned()
10+
where
11+
call.getTarget() = f and
12+
ret.getEnclosingFunction() = f and
13+
ret.getExpr().getValue().toInt() < 0 and
14+
call.getFullyConverted().getType().getUnderlyingType().(IntegralType).isUnsigned()
1215
select call, ret

ql_demos/cpp/libssh2_eating_error_codes/03_eating_error_codes_localflow.ql

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,15 @@
55
import cpp
66
import semmle.code.cpp.dataflow.DataFlow
77

8-
// int r = f();
9-
// unsigned int x = r;
10-
8+
// The previous query only handled cases where the result of the function
9+
// call is immediately cast to unsigned. So it will fail to detect examples
10+
// like this, where the cast doesn't happen immediately:
11+
//
12+
// int r = f();
13+
// unsigned int x = r;
14+
//
15+
// In this query, we add local dataflow so that we can also handle such
16+
// cases.
1117
from Function f, FunctionCall call, ReturnStmt ret, DataFlow::Node source, DataFlow::Node sink
1218
where call.getTarget() = f
1319
and ret.getEnclosingFunction() = f

ql_demos/cpp/libssh2_eating_error_codes/04_eating_error_codes_localflow_rangeanalysis.ql

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,25 @@ import cpp
66
import semmle.code.cpp.dataflow.DataFlow
77
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
88

9-
// int r = f();
10-
// if (r < 0) return -1;
11-
// unsigned int x = r;
12-
9+
// The previous query produced some weird results. The problem is that it
10+
// treats any expression with an unsigned type as a potential sink. What we
11+
// really want is to find where the cast from signed to unsigned happens,
12+
// because that's where the integer overflow occurs. So we want the sink to
13+
// be a potentially negative expression that gets cast to unsigned.
14+
//
15+
// Note that by using range analysis, we can avoid producing false positive
16+
// results for examples like this:
17+
//
18+
// int r = f();
19+
// if (r < 0) return -1;
20+
// unsigned int x = r;
1321
from Function f, FunctionCall call, ReturnStmt ret, DataFlow::Node source, DataFlow::Node sink
14-
where call.getTarget() = f
15-
and ret.getEnclosingFunction() = f
16-
and ret.getExpr().getValue().toInt() < 0
17-
and source.asExpr() = call
18-
and DataFlow::localFlow(source, sink)
19-
and sink.asExpr().getFullyConverted().getType().getUnderlyingType().(IntegralType).isUnsigned()
20-
and lowerBound(sink.asExpr()) < 0
22+
where
23+
call.getTarget() = f and
24+
ret.getEnclosingFunction() = f and
25+
ret.getExpr().getValue().toInt() < 0 and
26+
source.asExpr() = call and
27+
DataFlow::localFlow(source, sink) and
28+
sink.asExpr().getFullyConverted().getType().getUnderlyingType().(IntegralType).isUnsigned() and
29+
lowerBound(sink.asExpr()) < 0
2130
select source, sink
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
1-
[Snapshot](https://downloads.lgtm.com/snapshots/cpp/libssh2/libssh2_libssh2_C_C++_38bf7ce.zip)
1+
# Eating error codes in libssh2
2+
3+
Use this [Snapshot](https://downloads.lgtm.com/snapshots/cpp/libssh2/libssh2_libssh2_C_C++_38bf7ce.zip) for the demo.
4+
5+
This demo shows how to develop, step-by-step, the query from the [blog post](https://blog.semmle.com/libssh2-integer-overflow/) about libssh2 CVE-2019-13115. This query did not find the bug that caused the CVE. It is instead about doing variant analysis on a bug which we noticed on the development branch of libssh2. We sent the query results to the libssh2 development team and they were able to fix all the variants before the next version of libssh2 was released.
6+
7+
[This](https://lgtm.com/projects/g/libssh2/libssh2/snapshot/6e2f5563c80521b3cde72a6fcdb675c2e085f9cf/files/src/hostkey.c?sort=name&dir=ASC&mode=heatmap&__hstc=70225743.5fa8704c8874c6eafaef219923a26734.1534954774206.1564532078978.1564925733575.72&__hssc=70225743.2.1565139962633&__hsfp=997709570#L677) is an example of the bug. The problem is that `_libssh2_get_c_string` returns an negative integer as an error code, but the type of `r_len` is `unsigned int`, so the error code is accidentally ignored.
8+
9+
For a shorter demo, stop at step 02. Steps 03 and 04 make the query more sophisticated by adding local dataflow and range analysis.

0 commit comments

Comments
 (0)