Skip to content

Commit 0cd01cb

Browse files
committed
JS: Use node1,state1,node2,state2 naming convention in tainted path
1 parent 0802107 commit 0cd01cb

File tree

1 file changed

+89
-87
lines changed

1 file changed

+89
-87
lines changed

javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll

Lines changed: 89 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -876,39 +876,39 @@ module TaintedPath {
876876
}
877877

878878
/**
879-
* Holds if there is a step `src -> dst` mapping `srclabel` to `dstlabel` relevant for path traversal vulnerabilities.
879+
* Holds if there is a step `node1 -> node2` mapping `state1` to `state2` relevant for path traversal vulnerabilities.
880880
*/
881881
predicate isAdditionalFlowStep(
882-
DataFlow::Node src, FlowState srclabel, DataFlow::Node dst, FlowState dstlabel
882+
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
883883
) {
884-
isPosixPathStep(src, srclabel, dst, dstlabel)
884+
isPosixPathStep(node1, state1, node2, state2)
885885
or
886886
// Ignore all preliminary sanitization after decoding URI components
887-
srclabel instanceof FlowState::PosixPath and
888-
dstlabel instanceof FlowState::PosixPath and
887+
state1 instanceof FlowState::PosixPath and
888+
state2 instanceof FlowState::PosixPath and
889889
(
890-
TaintTracking::uriStep(src, dst)
890+
TaintTracking::uriStep(node1, node2)
891891
or
892892
exists(DataFlow::CallNode decode |
893893
decode.getCalleeName() = "decodeURIComponent" or decode.getCalleeName() = "decodeURI"
894894
|
895-
src = decode.getArgument(0) and
896-
dst = decode
895+
node1 = decode.getArgument(0) and
896+
node2 = decode
897897
)
898898
)
899899
or
900-
TaintTracking::persistentStorageStep(src, dst) and srclabel = dstlabel
900+
TaintTracking::persistentStorageStep(node1, node2) and state1 = state2
901901
or
902-
exists(DataFlow::PropRead read | read = dst |
903-
src = read.getBase() and
902+
exists(DataFlow::PropRead read | read = node2 |
903+
node1 = read.getBase() and
904904
read.getPropertyName() != "length" and
905-
srclabel = dstlabel and
905+
state1 = state2 and
906906
not AccessPath::DominatingPaths::hasDominatingWrite(read)
907907
)
908908
or
909909
// string method calls of interest
910910
exists(DataFlow::MethodCallNode mcn, string name |
911-
srclabel = dstlabel and dst = mcn and mcn.calls(src, name)
911+
state1 = state2 and node2 = mcn and mcn.calls(node1, name)
912912
|
913913
name = StringOps::substringMethodName() and
914914
// to avoid very dynamic transformations, require at least one fixed index
@@ -926,49 +926,49 @@ module TaintedPath {
926926
)
927927
or
928928
// A `str.split()` call can either split into path elements (`str.split("/")`) or split by some other string.
929-
exists(StringSplitCall mcn | dst = mcn and mcn.getBaseString() = src |
929+
exists(StringSplitCall mcn | node2 = mcn and mcn.getBaseString() = node1 |
930930
if mcn.getSeparator() = "/"
931931
then
932-
srclabel.(FlowState::PosixPath).canContainDotDotSlash() and
933-
dstlabel instanceof FlowState::SplitPath
934-
else srclabel = dstlabel
932+
state1.(FlowState::PosixPath).canContainDotDotSlash() and
933+
state2 instanceof FlowState::SplitPath
934+
else state1 = state2
935935
)
936936
or
937937
// array method calls of interest
938-
exists(DataFlow::MethodCallNode mcn, string name | dst = mcn and mcn.calls(src, name) |
938+
exists(DataFlow::MethodCallNode mcn, string name | node2 = mcn and mcn.calls(node1, name) |
939939
(
940940
name = "pop" or
941941
name = "shift"
942942
) and
943-
srclabel instanceof FlowState::SplitPath and
944-
dstlabel.(FlowState::PosixPath).canContainDotDotSlash()
943+
state1 instanceof FlowState::SplitPath and
944+
state2.(FlowState::PosixPath).canContainDotDotSlash()
945945
or
946946
(
947947
name = "slice" or
948948
name = "splice" or
949949
name = "concat"
950950
) and
951-
dstlabel instanceof FlowState::SplitPath and
952-
srclabel instanceof FlowState::SplitPath
951+
state2 instanceof FlowState::SplitPath and
952+
state1 instanceof FlowState::SplitPath
953953
or
954954
name = "join" and
955955
mcn.getArgument(0).mayHaveStringValue("/") and
956-
srclabel instanceof FlowState::SplitPath and
957-
dstlabel.(FlowState::PosixPath).canContainDotDotSlash()
956+
state1 instanceof FlowState::SplitPath and
957+
state2.(FlowState::PosixPath).canContainDotDotSlash()
958958
)
959959
or
960960
// prefix.concat(path)
961961
exists(DataFlow::MethodCallNode mcn |
962-
mcn.getMethodName() = "concat" and mcn.getAnArgument() = src
962+
mcn.getMethodName() = "concat" and mcn.getAnArgument() = node1
963963
|
964-
dst = mcn and
965-
dstlabel instanceof FlowState::SplitPath and
966-
srclabel instanceof FlowState::SplitPath
964+
node2 = mcn and
965+
state2 instanceof FlowState::SplitPath and
966+
state1 instanceof FlowState::SplitPath
967967
)
968968
or
969969
// reading unknown property of split path
970-
exists(DataFlow::PropRead read | read = dst |
971-
src = read.getBase() and
970+
exists(DataFlow::PropRead read | read = node2 |
971+
node1 = read.getBase() and
972972
not read.getPropertyName() = "length" and
973973
not exists(read.getPropertyNameExpr().getIntValue()) and
974974
// split[split.length - 1]
@@ -977,135 +977,137 @@ module TaintedPath {
977977
binop.getAnOperand().getIntValue() = 1 and
978978
binop.getAnOperand().(PropAccess).getPropertyName() = "length"
979979
) and
980-
srclabel instanceof FlowState::SplitPath and
981-
dstlabel.(FlowState::PosixPath).canContainDotDotSlash()
980+
state1 instanceof FlowState::SplitPath and
981+
state2.(FlowState::PosixPath).canContainDotDotSlash()
982982
)
983983
or
984984
exists(API::CallNode call | call = API::moduleImport("slash").getACall() |
985-
src = call.getArgument(0) and
986-
dst = call and
987-
srclabel = dstlabel
985+
node1 = call.getArgument(0) and
986+
node2 = call and
987+
state1 = state2
988988
)
989989
or
990990
exists(HtmlSanitizerCall call |
991-
src = call.getInput() and
992-
dst = call and
993-
srclabel = dstlabel
991+
node1 = call.getInput() and
992+
node2 = call and
993+
state1 = state2
994994
)
995995
or
996996
exists(DataFlow::CallNode join |
997997
// path.join() with spread argument
998998
join = NodeJSLib::Path::moduleMember("join").getACall() and
999-
src = join.getASpreadArgument() and
1000-
dst = join and
999+
node1 = join.getASpreadArgument() and
1000+
node2 = join and
10011001
(
1002-
srclabel.(FlowState::PosixPath).canContainDotDotSlash()
1002+
state1.(FlowState::PosixPath).canContainDotDotSlash()
10031003
or
1004-
srclabel instanceof FlowState::SplitPath
1004+
state1 instanceof FlowState::SplitPath
10051005
) and
1006-
dstlabel.(FlowState::PosixPath).isNormalized() and
1006+
state2.(FlowState::PosixPath).isNormalized() and
10071007
if isRelative(join.getArgument(0).getStringValue())
1008-
then dstlabel.(FlowState::PosixPath).isRelative()
1009-
else dstlabel.(FlowState::PosixPath).isAbsolute()
1008+
then state2.(FlowState::PosixPath).isRelative()
1009+
else state2.(FlowState::PosixPath).isAbsolute()
10101010
)
10111011
}
10121012

10131013
/**
1014-
* Holds if we should include a step from `src -> dst` with labels `srclabel -> dstlabel`, and the
1015-
* standard taint step `src -> dst` should be suppressed.
1014+
* Holds if we should include a step from `node1 -> node2` with labels `state1 -> state2`, and the
1015+
* standard taint step `node1 -> node2` should be suppressed.
10161016
*/
10171017
private predicate isPosixPathStep(
1018-
DataFlow::Node src, FlowState::PosixPath srclabel, DataFlow::Node dst,
1019-
FlowState::PosixPath dstlabel
1018+
DataFlow::Node node1, FlowState::PosixPath state1, DataFlow::Node node2,
1019+
FlowState::PosixPath state2
10201020
) {
10211021
// path.normalize() and similar
10221022
exists(NormalizingPathCall call |
1023-
src = call.getInput() and
1024-
dst = call.getOutput() and
1025-
dstlabel = srclabel.toNormalized()
1023+
node1 = call.getInput() and
1024+
node2 = call.getOutput() and
1025+
state2 = state1.toNormalized()
10261026
)
10271027
or
10281028
// path.resolve() and similar
10291029
exists(ResolvingPathCall call |
1030-
src = call.getInput() and
1031-
dst = call.getOutput() and
1032-
dstlabel.isAbsolute() and
1033-
dstlabel.isNormalized()
1030+
node1 = call.getInput() and
1031+
node2 = call.getOutput() and
1032+
state2.isAbsolute() and
1033+
state2.isNormalized()
10341034
)
10351035
or
10361036
// path.relative() and similar
10371037
exists(NormalizingRelativePathCall call |
1038-
src = call.getInput() and
1039-
dst = call.getOutput() and
1040-
dstlabel.isRelative() and
1041-
dstlabel.isNormalized()
1038+
node1 = call.getInput() and
1039+
node2 = call.getOutput() and
1040+
state2.isRelative() and
1041+
state2.isNormalized()
10421042
)
10431043
or
10441044
// path.dirname() and similar
10451045
exists(PreservingPathCall call |
1046-
src = call.getInput() and
1047-
dst = call.getOutput() and
1048-
srclabel = dstlabel
1046+
node1 = call.getInput() and
1047+
node2 = call.getOutput() and
1048+
state1 = state2
10491049
)
10501050
or
10511051
// foo.replace(/\./, "") and similar
10521052
exists(DotRemovingReplaceCall call |
1053-
src = call.getInput() and
1054-
dst = call.getOutput() and
1055-
srclabel.isAbsolute() and
1056-
dstlabel.isAbsolute() and
1057-
dstlabel.isNormalized()
1053+
node1 = call.getInput() and
1054+
node2 = call.getOutput() and
1055+
state1.isAbsolute() and
1056+
state2.isAbsolute() and
1057+
state2.isNormalized()
10581058
)
10591059
or
10601060
// foo.replace(/(\.\.\/)*/, "") and similar
10611061
exists(DotDotSlashPrefixRemovingReplace call |
1062-
src = call.getInput() and
1063-
dst = call.getOutput()
1062+
node1 = call.getInput() and
1063+
node2 = call.getOutput()
10641064
|
1065-
// the 4 possible combinations of normalized + relative for `srclabel`, and the possible values for `dstlabel` in each case.
1066-
srclabel.isNonNormalized() and srclabel.isRelative() // raw + relative -> any()
1065+
// the 4 possible combinations of normalized + relative for `state1`, and the possible values for `state2` in each case.
1066+
state1.isNonNormalized() and state1.isRelative() // raw + relative -> any()
10671067
or
1068-
srclabel.isNormalized() and srclabel.isAbsolute() and srclabel = dstlabel // normalized + absolute -> normalized + absolute
1068+
state1.isNormalized() and state1.isAbsolute() and state1 = state2 // normalized + absolute -> normalized + absolute
10691069
or
1070-
srclabel.isNonNormalized() and srclabel.isAbsolute() and dstlabel.isAbsolute() // raw + absolute -> raw/normalized + absolute
1070+
state1.isNonNormalized() and state1.isAbsolute() and state2.isAbsolute() // raw + absolute -> raw/normalized + absolute
10711071
// normalized + relative -> none()
10721072
)
10731073
or
10741074
// path.join()
10751075
exists(DataFlow::CallNode join, int n |
10761076
join = NodeJSLib::Path::moduleMember("join").getACall()
10771077
|
1078-
src = join.getArgument(n) and
1079-
dst = join and
1078+
node1 = join.getArgument(n) and
1079+
node2 = join and
10801080
(
10811081
// If the initial argument is tainted, just normalize it. It can be relative or absolute.
10821082
n = 0 and
1083-
dstlabel = srclabel.toNormalized()
1083+
state2 = state1.toNormalized()
10841084
or
10851085
// For later arguments, the flow label depends on whether the first argument is absolute or relative.
10861086
// If in doubt, we assume it is absolute.
10871087
n > 0 and
1088-
srclabel.canContainDotDotSlash() and
1089-
dstlabel.isNormalized() and
1088+
state1.canContainDotDotSlash() and
1089+
state2.isNormalized() and
10901090
if isRelative(join.getArgument(0).getStringValue())
1091-
then dstlabel.isRelative()
1092-
else dstlabel.isAbsolute()
1091+
then state2.isRelative()
1092+
else state2.isAbsolute()
10931093
)
10941094
)
10951095
or
10961096
// String concatenation - behaves like path.join() except without normalization
1097-
exists(DataFlow::Node operator, int n | StringConcatenation::taintStep(src, dst, operator, n) |
1097+
exists(DataFlow::Node operator, int n |
1098+
StringConcatenation::taintStep(node1, node2, operator, n)
1099+
|
10981100
// use ordinary taint flow for the first operand
10991101
n = 0 and
1100-
srclabel = dstlabel
1102+
state1 = state2
11011103
or
11021104
n > 0 and
1103-
srclabel.canContainDotDotSlash() and
1104-
dstlabel.isNonNormalized() and // The ../ is no longer at the beginning of the string.
1105+
state1.canContainDotDotSlash() and
1106+
state2.isNonNormalized() and // The ../ is no longer at the beginning of the string.
11051107
(
11061108
if isRelative(StringConcatenation::getOperand(operator, 0).getStringValue())
1107-
then dstlabel.isRelative()
1108-
else dstlabel.isAbsolute()
1109+
then state2.isRelative()
1110+
else state2.isAbsolute()
11091111
)
11101112
)
11111113
}

0 commit comments

Comments
 (0)