-
Notifications
You must be signed in to change notification settings - Fork 76
Expand file tree
/
Copy pathDoNotRelyOnIndeterminateValuesOfErrno.ql
More file actions
96 lines (88 loc) · 3 KB
/
DoNotRelyOnIndeterminateValuesOfErrno.ql
File metadata and controls
96 lines (88 loc) · 3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/**
* @id c/cert/do-not-rely-on-indeterminate-values-of-errno
* @name ERR32-C: Do not rely on indeterminate values of errno
* @description Do not rely on indeterminate values of errno. This may result in undefined behavior.
* @kind problem
* @precision high
* @problem.severity error
* @tags external/cert/id/err32-c
* correctness
* external/cert/severity/low
* external/cert/likelihood/unlikely
* external/cert/remediation-cost/low
* external/cert/priority/p3
* external/cert/level/l3
* external/cert/obligation/rule
* coding-standards/baseline/safety
*/
import cpp
import codingstandards.c.cert
import codingstandards.c.Errno
import codingstandards.c.Signal
import semmle.code.cpp.controlflow.Guards
import semmle.code.cpp.dataflow.DataFlow
/**
* A check on `signal` call return value
* `if (signal(SIGINT, handler) == SIG_ERR)`
*/
class SignalCheckOperation extends EqualityOperation instanceof GuardCondition {
BasicBlock errorSuccessor;
SignalCheckOperation() {
this.getAnOperand() = any(MacroInvocation m | m.getMacroName() = "SIG_ERR").getExpr() and
(
this.getOperator() = "==" and
super.controls(errorSuccessor, true)
or
this.getOperator() = "!=" and
super.controls(errorSuccessor, false)
)
}
BasicBlock getCheckedSuccessor() { result != errorSuccessor and result = this.getASuccessor() }
BasicBlock getErrorSuccessor() { result = errorSuccessor }
}
/**
* Models signal handlers that call signal() and return
*/
class SignalCallingHandler extends SignalHandler {
SignalCallingHandler() {
// calls signal() on the handled signal
exists(SignalCall sCall |
sCall.getEnclosingFunction() = this and
DataFlow::localFlow(DataFlow::parameterNode(this.getParameter(0)),
DataFlow::exprNode(sCall.getArgument(0))) and
// does not abort on error
not exists(SignalCheckOperation sCheck, AbortCall abort |
DataFlow::localExprFlow(sCall, sCheck.getAnOperand()) and
abort = sCheck.getErrorSuccessor().(BlockStmt).getStmt(0).(ExprStmt).getExpr()
)
)
}
}
/**
* CFG nodes preceeding `ErrnoRead`
*/
ControlFlowNode preceedErrnoRead(ErrnoRead er) {
result = er
or
exists(ControlFlowNode mid |
result = mid.getAPredecessor() and
mid = preceedErrnoRead(er) and
// stop recursion on calls to `abort` and `_Exit`
not result instanceof AbortCall and
// stop recursion on successful `SignalCheckOperation`
not result = any(SignalCheckOperation o).getCheckedSuccessor()
)
}
from ErrnoRead errno, SignalCall signal
where
not isExcluded(errno, Contracts5Package::doNotRelyOnIndeterminateValuesOfErrnoQuery()) and
exists(SignalCallingHandler handler |
// errno read after the handler returns
handler.getRegistration() = signal
or
// errno read inside the handler
signal.getEnclosingFunction() = handler
|
signal = preceedErrnoRead(errno)
)
select errno, "`errno` has indeterminate value after this $@.", signal, signal.toString()