vaioco revised this gist 1 day ago. Go to revision
3 files changed, 187 insertions
anon.c(file created)
@@ -0,0 +1,56 @@ | |||
1 | + | #pragma QUIC | |
2 | + | typedef unsigned int uint; | |
3 | + | ||
4 | + | struct sconn | |
5 | + | { | |
6 | + | uint state; /* PERSISTENT to keep state counters correct */ | |
7 | + | uint unused; | |
8 | + | }; | |
9 | + | typedef struct sconn sconn_t; | |
10 | + | ||
11 | + | struct container { | |
12 | + | sconn_t* conn; | |
13 | + | int unused; | |
14 | + | }; | |
15 | + | typedef struct container container_t; | |
16 | + | #define STATE0 0 | |
17 | + | #define STATE1 1 | |
18 | + | #define STATE2 2 | |
19 | + | ||
20 | + | ||
21 | + | sconn_t global = {}; | |
22 | + | ||
23 | + | container_t get_data(){ | |
24 | + | container_t e = {.conn = &global}; | |
25 | + | return e; | |
26 | + | } | |
27 | + | ||
28 | + | void sink(sconn_t *conn){ | |
29 | + | ;; | |
30 | + | } | |
31 | + | ||
32 | + | void set (sconn_t *conn, uint state) | |
33 | + | { | |
34 | + | conn->state = state; | |
35 | + | } | |
36 | + | ||
37 | + | void set_and_2sched(sconn_t *conn, uint n){ | |
38 | + | set(conn, STATE0); | |
39 | + | sink(conn); | |
40 | + | if (n % 2) | |
41 | + | set(conn, STATE1); | |
42 | + | } | |
43 | + | ||
44 | + | void easyflow(sconn_t *conn, uint n) | |
45 | + | { | |
46 | + | if(n%2) | |
47 | + | set(conn, STATE2); | |
48 | + | set_and_2sched(conn, n); | |
49 | + | sink(conn); | |
50 | + | } | |
51 | + | ||
52 | + | void producer(uint n){ | |
53 | + | container_t c = get_data(); | |
54 | + | easyflow(c.conn, n); | |
55 | + | sink(c.conn); | |
56 | + | } |
test.ql(file created)
@@ -0,0 +1,18 @@ | |||
1 | + | /** | |
2 | + | * @kind path-problem | |
3 | + | */ | |
4 | + | ||
5 | + | import cpp | |
6 | + | import testlib | |
7 | + | ||
8 | + | import FlowTest::PathGraph | |
9 | + | ||
10 | + | query predicate nodes(FlowTest::PathNode n, string key, string val) { | |
11 | + | key = "semmle.label" and val = n.toString() + " " + n.getState().(ConnState).toString() | |
12 | + | } | |
13 | + | ||
14 | + | from FlowTest::PathNode source, FlowTest::PathNode sink, | |
15 | + | ConnState sig, ConnState sig2 | |
16 | + | where FlowTest::flowPath(source, sink) | |
17 | + | and sig = sink.getState() and sig2 = source.getState() | |
18 | + | select sink.getNode(), source, sink, "Unsafe data from sig $@ to sig $@ ", sig2, sig2.toString(), sig, sig.toString() |
testlib.qll(file created)
@@ -0,0 +1,113 @@ | |||
1 | + | import cpp | |
2 | + | import semmle.code.cpp.dataflow.new.TaintTracking | |
3 | + | ||
4 | + | ||
5 | + | newtype ConnStateType = | |
6 | + | STATE0() or | |
7 | + | STATE1() or | |
8 | + | STATE2() | |
9 | + | ||
10 | + | predicate allStates(ConnStateType s) { | |
11 | + | s = | |
12 | + | STATE0() or | |
13 | + | s = STATE1() | |
14 | + | or s = STATE2() | |
15 | + | } | |
16 | + | ||
17 | + | class ConnState extends ConnStateType { | |
18 | + | final string toString() { | |
19 | + | this = STATE0() and result = "STATE0" | |
20 | + | or | |
21 | + | this = STATE1() and result = "STATE1" | |
22 | + | or this = STATE2() and result = "STATE2" | |
23 | + | } | |
24 | + | Location getLocation() { result instanceof UnknownLocation } | |
25 | + | } | |
26 | + | predicate isSetState(Function m, int arg, ConnState sqt) { | |
27 | + | m.getName() = "set" | |
28 | + | and ( | |
29 | + | arg = 0 and sqt = STATE0() | |
30 | + | or | |
31 | + | arg = 1 and sqt = STATE1() | |
32 | + | or | |
33 | + | arg = 2 and sqt = STATE2() | |
34 | + | ) | |
35 | + | } | |
36 | + | predicate isCallSetState(FunctionCall fc, ConnState sqt) { | |
37 | + | isSetState(fc.getTarget(), fc.getArgument(1).getValue().toInt(), sqt) | |
38 | + | } | |
39 | + | ||
40 | + | class ConnFlowStateTransformerNode extends DataFlow::Node { | |
41 | + | ConnState next_state; | |
42 | + | ConnFlowStateTransformerNode() { | |
43 | + | exists(FunctionCall fc| | |
44 | + | isCallSetState(fc, next_state ) | |
45 | + | and this.asIndirectArgument() = fc.getArgument(0) | |
46 | + | ) | |
47 | + | or | |
48 | + | exists(FunctionCall fc| | |
49 | + | isCallSetState(fc, next_state ) | |
50 | + | and this.asExpr() = fc.getArgument(0) | |
51 | + | ) | |
52 | + | or | |
53 | + | exists(FunctionCall fc| | |
54 | + | isCallSetState(fc, next_state ) | |
55 | + | and this.asDefiningArgument() = fc.getArgument(0) | |
56 | + | ) | |
57 | + | } | |
58 | + | ConnState transform(ConnState flowstate){ | |
59 | + | flowstate != next_state and result = next_state | |
60 | + | } | |
61 | + | } | |
62 | + | ||
63 | + | predicate isAdditionalStepImpl(DataFlow::Node n1, DataFlow::Node n2){ | |
64 | + | // from event to event.conn | |
65 | + | exists(FieldAccess fa | | |
66 | + | n1.asIndirectExpr() = fa.getQualifier() and | |
67 | + | n2.asExpr() = fa | |
68 | + | and fa.getTarget().getName() = "conn" | |
69 | + | ) | |
70 | + | or | |
71 | + | exists(FieldAccess fa | | |
72 | + | n1.asIndirectExpr() = fa.getQualifier() and | |
73 | + | n2.asIndirectExpr() = fa | |
74 | + | and fa.getTarget().getName() = "conn" | |
75 | + | ) | |
76 | + | } | |
77 | + | module TestConfig implements DataFlow::StateConfigSig { | |
78 | + | class FlowState = ConnState; | |
79 | + | predicate isSource(DataFlow::Node node, FlowState sig) { | |
80 | + | exists(FunctionCall fc | | |
81 | + | fc.getTarget().getName()= "get_data" | |
82 | + | and fc = node.asExpr() | |
83 | + | and allStates(sig) | |
84 | + | ) | |
85 | + | } | |
86 | + | ||
87 | + | predicate isSink(DataFlow::Node sink, FlowState state) { | |
88 | + | exists(FunctionCall fc | | |
89 | + | fc.getTarget().getName()= "sink" | |
90 | + | and fc.getArgument(0) = sink.asExpr() | |
91 | + | and allStates(state) | |
92 | + | ) | |
93 | + | } | |
94 | + | ||
95 | + | predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) { | |
96 | + | isAdditionalStepImpl(n1,n2) | |
97 | + | } | |
98 | + | predicate isAdditionalFlowStep( | |
99 | + | DataFlow::Node node1, FlowState prevState, DataFlow::Node node2, FlowState succState | |
100 | + | ) { | |
101 | + | node2.(ConnFlowStateTransformerNode).transform(prevState) = succState | |
102 | + | and DataFlow::simpleLocalFlowStep(node1, node2, _) | |
103 | + | } | |
104 | + | ||
105 | + | predicate isBarrier(DataFlow::Node node, FlowState state) { | |
106 | + | node.(ConnFlowStateTransformerNode).transform(state) != state | |
107 | + | } | |
108 | + | } | |
109 | + | ||
110 | + | module FlowTest = TaintTracking::GlobalWithState<TestConfig>; | |
111 | + | int explorationLimit() { result = 4 } | |
112 | + | module MyPartialFlowFwd = FlowTest::FlowExplorationFwd<explorationLimit/0>; | |
113 | + |