Skip to content

Commit 68c729f

Browse files
committed
PS: Models-as-data skeleton.
1 parent 9fb5711 commit 68c729f

File tree

10 files changed

+567
-24
lines changed

10 files changed

+567
-24
lines changed

powershell/ql/lib/semmle/code/powershell/Call.qll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ private import semmle.code.powershell.controlflow.CfgNodes
66
abstract private class AbstractCall extends Ast {
77
abstract Expr getCommand();
88

9+
abstract string getName();
10+
911
/** Gets the i'th argument to this call. */
1012
abstract Expr getArgument(int i);
1113

@@ -34,6 +36,8 @@ class CmdCall extends AbstractCall instanceof Cmd {
3436

3537
final override Expr getPositionalArgument(int i) { result = Cmd.super.getPositionalArgument(i) }
3638

39+
final override string getName() { result = Cmd.super.getCommandName() }
40+
3741
final override Expr getArgument(int i) { result = Cmd.super.getArgument(i) }
3842

3943
final override Expr getNamedArgument(string name) { result = Cmd.super.getNamedArgument(name) }
@@ -68,6 +72,8 @@ class MethodCall extends AbstractCall instanceof InvokeMemberExpr {
6872
result.getBody() = getTarget(call)
6973
)
7074
}
75+
76+
final override string getName() { result = InvokeMemberExpr.super.getName() }
7177
}
7278

7379
final class Call = AbstractCall;

powershell/ql/lib/semmle/code/powershell/Frameworks.qll

Whitespace-only changes.
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/** Provides classes and predicates for defining flow summaries. */
2+
3+
import powershell
4+
private import semmle.code.powershell.controlflow.Cfg
5+
private import semmle.code.powershell.typetracking.TypeTracking
6+
import semmle.code.powershell.dataflow.DataFlow
7+
private import internal.FlowSummaryImpl as Impl
8+
private import internal.DataFlowDispatch
9+
private import internal.DataFlowImplCommon as DataFlowImplCommon
10+
private import internal.DataFlowPrivate
11+
12+
// import all instances below
13+
private module Summaries {
14+
private import semmle.code.powershell.Frameworks
15+
private import semmle.code.powershell.frameworks.data.ModelsAsData
16+
}
17+
18+
/** A callable with a flow summary, identified by a unique string. */
19+
abstract class SummarizedCallable extends LibraryCallable, Impl::Public::SummarizedCallable {
20+
bindingset[this]
21+
SummarizedCallable() { any() }
22+
23+
override predicate propagatesFlow(
24+
string input, string output, boolean preservesValue, string model
25+
) {
26+
this.propagatesFlow(input, output, preservesValue) and model = ""
27+
}
28+
29+
/**
30+
* Holds if data may flow from `input` to `output` through this callable.
31+
*
32+
* `preservesValue` indicates whether this is a value-preserving step or a taint-step.
33+
*/
34+
predicate propagatesFlow(string input, string output, boolean preservesValue) { none() }
35+
36+
/**
37+
* Gets the synthesized parameter that results from an input specification
38+
* that starts with `Argument[s]` for this library callable.
39+
*/
40+
DataFlow::ParameterNode getParameter(string s) {
41+
exists(ParameterPosition pos |
42+
DataFlowImplCommon::parameterNode(result, TLibraryCallable(this), pos) and
43+
s = Impl::Input::encodeParameterPosition(pos)
44+
)
45+
}
46+
}
47+
48+
/**
49+
* A callable with a flow summary, identified by a unique string, where all
50+
* calls to a method with the same name are considered relevant.
51+
*/
52+
abstract class SimpleSummarizedCallable extends SummarizedCallable {
53+
Call c;
54+
55+
bindingset[this]
56+
SimpleSummarizedCallable() { c.getName() = this }
57+
58+
final override MethodCall getACall() { result = c }
59+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* Provides an extension point for modeling user-controlled data.
3+
* Such data is often used as data-flow sources in security queries.
4+
*/
5+
6+
private import semmle.code.powershell.dataflow.internal.DataFlowPublic as DataFlow
7+
// Need to import since frameworks can extend `RemoteFlowSource::Range`
8+
private import semmle.code.powershell.Frameworks
9+
10+
/**
11+
* A data flow source of remote user input.
12+
*
13+
* Extend this class to refine existing API models. If you want to model new APIs,
14+
* extend `RemoteFlowSource::Range` instead.
15+
*/
16+
class RemoteFlowSource extends DataFlow::Node instanceof RemoteFlowSource::Range {
17+
/** Gets a string that describes the type of this remote flow source. */
18+
string getSourceType() { result = super.getSourceType() }
19+
}
20+
21+
/** Provides a class for modeling new sources of remote user input. */
22+
module RemoteFlowSource {
23+
/**
24+
* A data flow source of remote user input.
25+
*
26+
* Extend this class to model new APIs. If you want to refine existing API models,
27+
* extend `RemoteFlowSource` instead.
28+
*/
29+
abstract class Range extends DataFlow::Node {
30+
/** Gets a string that describes the type of this remote flow source. */
31+
abstract string getSourceType();
32+
}
33+
}

powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowDispatch.qll

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ private import semmle.code.powershell.Cfg
33
private import DataFlowPrivate
44
private import DataFlowPublic
55
private import semmle.code.powershell.typetracking.internal.TypeTrackingImpl
6+
private import FlowSummaryImpl as FlowSummaryImpl
7+
private import semmle.code.powershell.dataflow.FlowSummary
68
private import codeql.util.Boolean
79
private import codeql.util.Unit
810

@@ -108,6 +110,24 @@ abstract class DataFlowCall extends TDataFlowCall {
108110
}
109111
}
110112

113+
class SummaryCall extends DataFlowCall, TSummaryCall {
114+
private FlowSummaryImpl::Public::SummarizedCallable c;
115+
private FlowSummaryImpl::Private::SummaryNode receiver;
116+
117+
SummaryCall() { this = TSummaryCall(c, receiver) }
118+
119+
/** Gets the data flow node that this call targets. */
120+
FlowSummaryImpl::Private::SummaryNode getReceiver() { result = receiver }
121+
122+
override DataFlowCallable getEnclosingCallable() { result.asLibraryCallable() = c }
123+
124+
override CfgNodes::CallCfgNode asCall() { none() }
125+
126+
override string toString() { result = "[summary] call to " + receiver + " in " + c }
127+
128+
override EmptyLocation getLocation() { any() }
129+
}
130+
111131
class NormalCall extends DataFlowCall, TNormalCall {
112132
private CfgNodes::CallCfgNode c;
113133

@@ -218,7 +238,13 @@ private module Cached {
218238
TLibraryCallable(LibraryCallable callable)
219239

220240
cached
221-
newtype TDataFlowCall = TNormalCall(CfgNodes::CallCfgNode c)
241+
newtype TDataFlowCall =
242+
TNormalCall(CfgNodes::CallCfgNode c) or
243+
TSummaryCall(
244+
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
245+
) {
246+
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
247+
}
222248

223249
/** Gets a viable run-time target for the call `call`. */
224250
cached
@@ -234,12 +260,18 @@ private module Cached {
234260
cached
235261
newtype TArgumentPosition =
236262
TThisArgumentPosition() or
237-
TKeywordArgumentPosition(string name) { name = any(Argument p).getName() } or
263+
TKeywordArgumentPosition(string name) {
264+
name = any(Argument p).getName()
265+
or
266+
FlowSummaryImpl::ParsePositions::isParsedKeywordParameterPosition(_, name)
267+
} or
238268
TPositionalArgumentPosition(int pos, NamedSet ns) {
239269
exists(CfgNodes::CallCfgNode call |
240270
call = ns.getABindingCall() and
241271
exists(call.getArgument(pos))
242272
)
273+
or
274+
FlowSummaryImpl::ParsePositions::isParsedParameterPosition(_, pos)
243275
} or
244276
TPipelineArgumentPosition()
245277

0 commit comments

Comments
 (0)