anon.c
· 817 B · C
Raw
#pragma QUIC
typedef unsigned int uint;
struct sconn
{
uint state; /* PERSISTENT to keep state counters correct */
uint unused;
};
typedef struct sconn sconn_t;
struct container {
sconn_t* conn;
int unused;
};
typedef struct container container_t;
#define STATE0 0
#define STATE1 1
#define STATE2 2
sconn_t global = {};
container_t get_data(){
container_t e = {.conn = &global};
return e;
}
void sink(sconn_t *conn){
;;
}
void set (sconn_t *conn, uint state)
{
conn->state = state;
}
void set_and_2sched(sconn_t *conn, uint n){
set(conn, STATE0);
sink(conn);
if (n % 2)
set(conn, STATE1);
}
void easyflow(sconn_t *conn, uint n)
{
if(n%2)
set(conn, STATE2);
set_and_2sched(conn, n);
sink(conn);
}
void producer(uint n){
container_t c = get_data();
easyflow(c.conn, n);
sink(c.conn);
}
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 | } |
57 |
test.ql
· 549 B · Text
Raw
/**
* @kind path-problem
*/
import cpp
import testlib
import FlowTest::PathGraph
query predicate nodes(FlowTest::PathNode n, string key, string val) {
key = "semmle.label" and val = n.toString() + " " + n.getState().(ConnState).toString()
}
from FlowTest::PathNode source, FlowTest::PathNode sink,
ConnState sig, ConnState sig2
where FlowTest::flowPath(source, sink)
and sig = sink.getState() and sig2 = source.getState()
select sink.getNode(), source, sink, "Unsafe data from sig $@ to sig $@ ", sig2, sig2.toString(), sig, sig.toString()
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
· 3.3 KiB · Text
Raw
import cpp
import semmle.code.cpp.dataflow.new.TaintTracking
newtype ConnStateType =
STATE0() or
STATE1() or
STATE2()
predicate allStates(ConnStateType s) {
s =
STATE0() or
s = STATE1()
or s = STATE2()
}
class ConnState extends ConnStateType {
final string toString() {
this = STATE0() and result = "STATE0"
or
this = STATE1() and result = "STATE1"
or this = STATE2() and result = "STATE2"
}
Location getLocation() { result instanceof UnknownLocation }
}
predicate isSetState(Function m, int arg, ConnState sqt) {
m.getName() = "set"
and (
arg = 0 and sqt = STATE0()
or
arg = 1 and sqt = STATE1()
or
arg = 2 and sqt = STATE2()
)
}
predicate isCallSetState(FunctionCall fc, ConnState sqt) {
isSetState(fc.getTarget(), fc.getArgument(1).getValue().toInt(), sqt)
}
class ConnFlowStateTransformerNode extends DataFlow::Node {
ConnState next_state;
ConnFlowStateTransformerNode() {
exists(FunctionCall fc|
isCallSetState(fc, next_state )
and this.asIndirectArgument() = fc.getArgument(0)
)
or
exists(FunctionCall fc|
isCallSetState(fc, next_state )
and this.asExpr() = fc.getArgument(0)
)
or
exists(FunctionCall fc|
isCallSetState(fc, next_state )
and this.asDefiningArgument() = fc.getArgument(0)
)
}
ConnState transform(ConnState flowstate){
flowstate != next_state and result = next_state
}
}
predicate isAdditionalStepImpl(DataFlow::Node n1, DataFlow::Node n2){
// from event to event.conn
exists(FieldAccess fa |
n1.asIndirectExpr() = fa.getQualifier() and
n2.asExpr() = fa
and fa.getTarget().getName() = "conn"
)
or
exists(FieldAccess fa |
n1.asIndirectExpr() = fa.getQualifier() and
n2.asIndirectExpr() = fa
and fa.getTarget().getName() = "conn"
)
}
module TestConfig implements DataFlow::StateConfigSig {
class FlowState = ConnState;
predicate isSource(DataFlow::Node node, FlowState sig) {
exists(FunctionCall fc |
fc.getTarget().getName()= "get_data"
and fc = node.asExpr()
and allStates(sig)
)
}
predicate isSink(DataFlow::Node sink, FlowState state) {
exists(FunctionCall fc |
fc.getTarget().getName()= "sink"
and fc.getArgument(0) = sink.asExpr()
and allStates(state)
)
}
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
isAdditionalStepImpl(n1,n2)
}
predicate isAdditionalFlowStep(
DataFlow::Node node1, FlowState prevState, DataFlow::Node node2, FlowState succState
) {
node2.(ConnFlowStateTransformerNode).transform(prevState) = succState
and DataFlow::simpleLocalFlowStep(node1, node2, _)
}
predicate isBarrier(DataFlow::Node node, FlowState state) {
node.(ConnFlowStateTransformerNode).transform(state) != state
}
}
module FlowTest = TaintTracking::GlobalWithState<TestConfig>;
int explorationLimit() { result = 4 }
module MyPartialFlowFwd = FlowTest::FlowExplorationFwd<explorationLimit/0>;
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 | |
114 |