Last active 1 day ago

Revision c0425e77ebf6d25dcc000e0bd06829fc5f397760

anon.c Raw
1#pragma QUIC
2typedef unsigned int uint;
3
4struct sconn
5{
6 uint state; /* PERSISTENT to keep state counters correct */
7 uint unused;
8};
9typedef struct sconn sconn_t;
10
11struct container {
12 sconn_t* conn;
13 int unused;
14};
15typedef struct container container_t;
16#define STATE0 0
17#define STATE1 1
18#define STATE2 2
19
20
21sconn_t global = {};
22
23container_t get_data(){
24 container_t e = {.conn = &global};
25 return e;
26}
27
28void sink(sconn_t *conn){
29 ;;
30}
31
32void set (sconn_t *conn, uint state)
33{
34 conn->state = state;
35}
36
37void 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
44void 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
52void producer(uint n){
53 container_t c = get_data();
54 easyflow(c.conn, n);
55 sink(c.conn);
56}
57
test.ql Raw
1/**
2* @kind path-problem
3*/
4
5import cpp
6import testlib
7
8import FlowTest::PathGraph
9
10query predicate nodes(FlowTest::PathNode n, string key, string val) {
11 key = "semmle.label" and val = n.toString() + " " + n.getState().(ConnState).toString()
12}
13
14from FlowTest::PathNode source, FlowTest::PathNode sink,
15 ConnState sig, ConnState sig2
16where FlowTest::flowPath(source, sink)
17and sig = sink.getState() and sig2 = source.getState()
18select sink.getNode(), source, sink, "Unsafe data from sig $@ to sig $@ ", sig2, sig2.toString(), sig, sig.toString()
testlib.qll Raw
1import cpp
2import 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
40class 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
63predicate 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}
77module 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
110module FlowTest = TaintTracking::GlobalWithState<TestConfig>;
111int explorationLimit() { result = 4 }
112module MyPartialFlowFwd = FlowTest::FlowExplorationFwd<explorationLimit/0>;
113
114