|
11 | 11 | */
|
12 | 12 |
|
13 | 13 | import cpp
|
| 14 | +import semmle.code.cpp.models.implementations.Strcat |
14 | 15 | import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
15 | 16 |
|
16 | 17 | /**
|
17 |
| - * A call to `strncat` of the form `strncat(buff, str, someExpr - strlen(buf))`, for some expression `someExpr` equal to `sizeof(buff)`. |
| 18 | + * Holds if `call` is a call to `strncat` such that `sizeArg` and `destArg` are the size and |
| 19 | + * destination arguments, respectively. |
18 | 20 | */
|
19 |
| -class WrongCallStrncat extends FunctionCall { |
20 |
| - Expr leftsomeExpr; |
21 |
| - |
22 |
| - WrongCallStrncat() { |
23 |
| - this.getTarget().hasGlobalOrStdName("strncat") and |
24 |
| - // the expression of the first argument in `strncat` and `strnlen` is identical |
25 |
| - globalValueNumber(this.getArgument(0)) = |
26 |
| - globalValueNumber(this.getArgument(2).(SubExpr).getRightOperand().(StrlenCall).getStringExpr()) and |
27 |
| - // using a string constant often speaks of manually calculating the length of the required buffer. |
28 |
| - ( |
29 |
| - not this.getArgument(1) instanceof StringLiteral and |
30 |
| - not this.getArgument(1) instanceof CharLiteral |
31 |
| - ) and |
32 |
| - // for use in predicates |
33 |
| - leftsomeExpr = this.getArgument(2).(SubExpr).getLeftOperand() |
34 |
| - } |
35 |
| - |
36 |
| - /** |
37 |
| - * Holds if the left side of the expression `someExpr` equal to `sizeof(buf)`. |
38 |
| - */ |
39 |
| - predicate isExpressionEqualSizeof() { |
40 |
| - // the left side of the expression `someExpr` is `sizeof(buf)`. |
41 |
| - globalValueNumber(this.getArgument(0)) = |
42 |
| - globalValueNumber(leftsomeExpr.(SizeofExprOperator).getExprOperand()) |
43 |
| - or |
44 |
| - // value of the left side of the expression `someExpr` equal `sizeof(buf)` value, and `buf` is array. |
45 |
| - leftsomeExpr.getValue().toInt() = this.getArgument(0).getType().getSize() |
46 |
| - } |
47 |
| - |
48 |
| - /** |
49 |
| - * Holds if the left side of the expression `someExpr` equal to variable containing the length of the memory allocated for the buffer. |
50 |
| - */ |
51 |
| - predicate isVariableEqualValueSizegBuffer() { |
52 |
| - // the left side of expression `someExpr` is the variable that was used in the function of allocating memory for the buffer`. |
53 |
| - exists(AllocationExpr alc | |
54 |
| - leftsomeExpr.(VariableAccess).getTarget() = |
55 |
| - alc.(FunctionCall).getArgument(0).(VariableAccess).getTarget() |
56 |
| - ) |
57 |
| - } |
| 21 | +predicate interestringCallWithArgs(Call call, Expr sizeArg, Expr destArg) { |
| 22 | + exists(StrcatFunction strcat | |
| 23 | + strcat = call.getTarget() and |
| 24 | + sizeArg = call.getArgument(strcat.getParamSize()) and |
| 25 | + destArg = call.getArgument(strcat.getParamDest()) |
| 26 | + ) |
58 | 27 | }
|
59 | 28 |
|
60 |
| -from WrongCallStrncat sc |
| 29 | +from FunctionCall call, Expr sizeArg, Expr destArg, SubExpr sub, int n |
61 | 30 | where
|
62 |
| - sc.isExpressionEqualSizeof() or |
63 |
| - sc.isVariableEqualValueSizegBuffer() |
64 |
| -select sc, "if the used buffer is full, writing out of the buffer is possible" |
| 31 | + interestringCallWithArgs(call, sizeArg, destArg) and |
| 32 | + // The destination buffer is an array of size n |
| 33 | + destArg.getUnspecifiedType().(ArrayType).getSize() = n and |
| 34 | + // The size argument is equivalent to a subtraction |
| 35 | + globalValueNumber(sizeArg).getAnExpr() = sub and |
| 36 | + // ... where the left side of the subtraction is the constant n |
| 37 | + globalValueNumber(sub.getLeftOperand()).getAnExpr().getValue().toInt() = n and |
| 38 | + // ... and the right side of the subtraction is a call to `strlen` where the argument is the |
| 39 | + // destination buffer. |
| 40 | + globalValueNumber(sub.getRightOperand()).getAnExpr().(StrlenCall).getStringExpr() = |
| 41 | + globalValueNumber(destArg).getAnExpr() |
| 42 | +select call, "Possible out-of-bounds write due to incorrect size argument." |
0 commit comments