mirror of
https://github.com/github/codeql.git
synced 2026-07-20 18:58:36 +02:00
Merge remote-tracking branch 'upstream/main' into refactor_use_of_isGuardPhi
This commit is contained in:
2
.github/workflows/csv-coverage-update.yml
vendored
2
.github/workflows/csv-coverage-update.yml
vendored
@@ -8,7 +8,7 @@ on:
|
||||
jobs:
|
||||
update:
|
||||
name: Update framework coverage report
|
||||
if: github.event.repository.fork == false
|
||||
if: github.repository == 'github/codeql'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
2
cpp/change-notes/2021-06-22-sql-tainted.md
Normal file
2
cpp/change-notes/2021-06-22-sql-tainted.md
Normal file
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* The 'Uncontrolled data in SQL query' (cpp/sql-injection) query now supports the `libpqxx` library.
|
||||
4
cpp/change-notes/2021-09-13-overflow-static.md
Normal file
4
cpp/change-notes/2021-09-13-overflow-static.md
Normal file
@@ -0,0 +1,4 @@
|
||||
lgtm,codescanning
|
||||
* The `memberMayBeVarSize` predicate considers more fields to be variable size.
|
||||
As a result, the "Static buffer overflow" query (cpp/static-buffer-overflow)
|
||||
produces fewer false positives.
|
||||
@@ -171,7 +171,7 @@ class Container extends Locatable, @container {
|
||||
* To get the full path, use `getAbsolutePath`.
|
||||
*/
|
||||
class Folder extends Container, @folder {
|
||||
override string getAbsolutePath() { folders(underlyingElement(this), result, _) }
|
||||
override string getAbsolutePath() { folders(underlyingElement(this), result) }
|
||||
|
||||
override Location getLocation() {
|
||||
result.getContainer() = this and
|
||||
@@ -190,7 +190,7 @@ class Folder extends Container, @folder {
|
||||
* DEPRECATED: use `getAbsolutePath` instead.
|
||||
* Gets the name of this folder.
|
||||
*/
|
||||
deprecated string getName() { folders(underlyingElement(this), result, _) }
|
||||
deprecated string getName() { folders(underlyingElement(this), result) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `getAbsolutePath` instead.
|
||||
@@ -208,17 +208,7 @@ class Folder extends Container, @folder {
|
||||
* DEPRECATED: use `getBaseName` instead.
|
||||
* Gets the last part of the folder name.
|
||||
*/
|
||||
deprecated string getShortName() {
|
||||
exists(string longnameRaw, string longname |
|
||||
folders(underlyingElement(this), _, longnameRaw) and
|
||||
longname = longnameRaw.replaceAll("\\", "/")
|
||||
|
|
||||
exists(int index |
|
||||
result = longname.splitAt("/", index) and
|
||||
not exists(longname.splitAt("/", index + 1))
|
||||
)
|
||||
)
|
||||
}
|
||||
deprecated string getShortName() { result = this.getBaseName() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `getParentContainer` instead.
|
||||
@@ -242,7 +232,7 @@ class Folder extends Container, @folder {
|
||||
* `getStem` and `getExtension`. To get the full path, use `getAbsolutePath`.
|
||||
*/
|
||||
class File extends Container, @file {
|
||||
override string getAbsolutePath() { files(underlyingElement(this), result, _, _, _) }
|
||||
override string getAbsolutePath() { files(underlyingElement(this), result) }
|
||||
|
||||
override string toString() { result = Container.super.toString() }
|
||||
|
||||
@@ -336,7 +326,13 @@ class File extends Container, @file {
|
||||
* for example, for "file.tar.gz", this predicate will have the result
|
||||
* "tar.gz", while `getExtension` will have the result "gz".
|
||||
*/
|
||||
string getExtensions() { files(underlyingElement(this), _, _, result, _) }
|
||||
string getExtensions() {
|
||||
exists(string name, int firstDotPos |
|
||||
name = this.getBaseName() and
|
||||
firstDotPos = min([name.indexOf("."), name.length() - 1]) and
|
||||
result = name.suffix(firstDotPos + 1)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the short name of this file, that is, the prefix of its base name up
|
||||
@@ -351,7 +347,16 @@ class File extends Container, @file {
|
||||
* for example, for "file.tar.gz", this predicate will have the result
|
||||
* "file", while `getStem` will have the result "file.tar".
|
||||
*/
|
||||
string getShortName() { files(underlyingElement(this), _, result, _, _) }
|
||||
string getShortName() {
|
||||
exists(string name, int firstDotPos |
|
||||
name = this.getBaseName() and
|
||||
firstDotPos = min([name.indexOf("."), name.length()]) and
|
||||
result = name.prefix(firstDotPos)
|
||||
)
|
||||
or
|
||||
this.getAbsolutePath() = "" and
|
||||
result = ""
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,17 +2,18 @@ import cpp
|
||||
import semmle.code.cpp.dataflow.DataFlow
|
||||
|
||||
/**
|
||||
* Holds if `v` is a member variable of `c` that looks like it might be variable sized in practice. For
|
||||
* example:
|
||||
* Holds if `v` is a member variable of `c` that looks like it might be variable sized
|
||||
* in practice. For example:
|
||||
* ```
|
||||
* struct myStruct { // c
|
||||
* int amount;
|
||||
* char data[1]; // v
|
||||
* };
|
||||
* ```
|
||||
* This requires that `v` is an array of size 0 or 1, and `v` is the last member of `c`. In addition,
|
||||
* there must be at least one instance where a `c` pointer is allocated with additional space. For
|
||||
* example, holds for `c` if it occurs as
|
||||
* This requires that `v` is an array of size 0 or 1, and `v` is the last member of `c`.
|
||||
* In addition, if the size of the structure is taken, there must be at least one instance
|
||||
* where a `c` pointer is allocated with additional space.
|
||||
* For example, holds for `c` if it occurs as
|
||||
* ```
|
||||
* malloc(sizeof(c) + 100 * sizeof(char))
|
||||
* ```
|
||||
@@ -27,27 +28,25 @@ predicate memberMayBeVarSize(Class c, MemberVariable v) {
|
||||
i = max(int j | c.getCanonicalMember(j) instanceof Field | j) and
|
||||
v = c.getCanonicalMember(i) and
|
||||
// v is an array of size at most 1
|
||||
v.getUnspecifiedType().(ArrayType).getArraySize() <= 1
|
||||
v.getUnspecifiedType().(ArrayType).getArraySize() <= 1 and
|
||||
not c instanceof Union
|
||||
) and
|
||||
// If the size is taken, then arithmetic is performed on the result at least once
|
||||
(
|
||||
// `sizeof(c)` is not taken
|
||||
not exists(SizeofOperator so |
|
||||
so.(SizeofTypeOperator).getTypeOperand().getUnspecifiedType() = c or
|
||||
so.(SizeofExprOperator).getExprOperand().getUnspecifiedType() = c
|
||||
)
|
||||
or
|
||||
// or `sizeof(c)` is taken
|
||||
exists(SizeofOperator so |
|
||||
// `sizeof(c)` is taken
|
||||
so.(SizeofTypeOperator).getTypeOperand().getUnspecifiedType() = c or
|
||||
so.(SizeofExprOperator).getExprOperand().getUnspecifiedType() = c
|
||||
|
|
||||
// arithmetic is performed on the result
|
||||
// and arithmetic is performed on the result
|
||||
so.getParent*() instanceof AddExpr
|
||||
)
|
||||
or
|
||||
exists(AddressOfExpr aoe |
|
||||
// `&(c.v)` is taken
|
||||
aoe.getAddressable() = v
|
||||
)
|
||||
or
|
||||
exists(BuiltInOperationBuiltInOffsetOf oo |
|
||||
// `offsetof(c, v)` using a builtin
|
||||
oo.getAChild().(VariableAccess).getTarget() = v
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -61,6 +60,10 @@ int getBufferSize(Expr bufferExpr, Element why) {
|
||||
result = bufferVar.getUnspecifiedType().(ArrayType).getSize() and
|
||||
why = bufferVar and
|
||||
not memberMayBeVarSize(_, bufferVar) and
|
||||
not exists(Union bufferType |
|
||||
bufferType.getAMemberVariable() = why and
|
||||
bufferVar.getUnspecifiedType().(ArrayType).getSize() <= 1
|
||||
) and
|
||||
not result = 0 // zero sized arrays are likely to have special usage, for example
|
||||
or
|
||||
// behaving a bit like a 'union' overlapping other fields.
|
||||
@@ -82,6 +85,13 @@ int getBufferSize(Expr bufferExpr, Element why) {
|
||||
parentPtr.getTarget().getUnspecifiedType().(PointerType).getBaseType() = parentClass and
|
||||
result = getBufferSize(parentPtr, _) + bufferVar.getType().getSize() - parentClass.getSize()
|
||||
)
|
||||
or
|
||||
exists(Union bufferType |
|
||||
bufferType.getAMemberVariable() = why and
|
||||
why = bufferVar and
|
||||
bufferVar.getUnspecifiedType().(ArrayType).getSize() <= 1 and
|
||||
result = bufferType.getSize()
|
||||
)
|
||||
)
|
||||
or
|
||||
// buffer is a fixed size dynamic allocation
|
||||
|
||||
@@ -93,6 +93,15 @@ predicate variableMustBeNullTerminated(VariableAccess va) {
|
||||
fc.getArgument(i) = va
|
||||
)
|
||||
or
|
||||
// String argument to a formatting function (such as `printf`)
|
||||
exists(int n, FormatLiteral fl |
|
||||
fc.(FormattingFunctionCall).getConversionArgument(n) = va and
|
||||
fl = fc.(FormattingFunctionCall).getFormat() and
|
||||
fl.getConversionType(n) instanceof PointerType and // `%s`, `%ws` etc
|
||||
not fl.getConversionType(n) instanceof VoidPointerType and // exclude: `%p`
|
||||
not fl.hasPrecision(n) // exclude: `%.*s`
|
||||
)
|
||||
or
|
||||
// Call to a wrapper function that requires null termination
|
||||
// (not itself adding a null terminator)
|
||||
exists(Function wrapper, int i, Parameter p, VariableAccess use |
|
||||
|
||||
@@ -923,28 +923,29 @@ private module Stage2 {
|
||||
|
||||
ApOption apSome(Ap ap) { result = TBooleanSome(ap) }
|
||||
|
||||
class Cc = boolean;
|
||||
class Cc = CallContext;
|
||||
|
||||
class CcCall extends Cc {
|
||||
CcCall() { this = true }
|
||||
class CcCall = CallContextCall;
|
||||
|
||||
/** Holds if this call context may be `call`. */
|
||||
predicate matchesCall(DataFlowCall call) { any() }
|
||||
}
|
||||
class CcNoCall = CallContextNoCall;
|
||||
|
||||
class CcNoCall extends Cc {
|
||||
CcNoCall() { this = false }
|
||||
}
|
||||
|
||||
Cc ccNone() { result = false }
|
||||
Cc ccNone() { result instanceof CallContextAny }
|
||||
|
||||
private class LocalCc = Unit;
|
||||
|
||||
bindingset[call, c, outercc]
|
||||
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
|
||||
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
|
||||
checkCallContextCall(outercc, call, c) and
|
||||
if recordDataFlowCallSiteDispatch(call, c)
|
||||
then result = TSpecificCall(call)
|
||||
else result = TSomeCall()
|
||||
}
|
||||
|
||||
bindingset[call, c, innercc]
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
|
||||
checkCallContextReturn(innercc, c, call) and
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
@@ -1172,7 +1173,8 @@ private module Stage2 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -1860,7 +1862,8 @@ private module Stage3 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -2117,7 +2120,7 @@ private module Stage3 {
|
||||
private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
|
||||
exists(AccessPathFront apf |
|
||||
Stage3::revFlow(node, true, _, apf, config) and
|
||||
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
|
||||
Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2618,7 +2621,8 @@ private module Stage4 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3639,9 +3643,10 @@ private module Subpaths {
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _,
|
||||
unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3686,8 +3691,8 @@ private module Subpaths {
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
||||
pragma[only_bind_into](arg).getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
|
||||
@@ -923,28 +923,29 @@ private module Stage2 {
|
||||
|
||||
ApOption apSome(Ap ap) { result = TBooleanSome(ap) }
|
||||
|
||||
class Cc = boolean;
|
||||
class Cc = CallContext;
|
||||
|
||||
class CcCall extends Cc {
|
||||
CcCall() { this = true }
|
||||
class CcCall = CallContextCall;
|
||||
|
||||
/** Holds if this call context may be `call`. */
|
||||
predicate matchesCall(DataFlowCall call) { any() }
|
||||
}
|
||||
class CcNoCall = CallContextNoCall;
|
||||
|
||||
class CcNoCall extends Cc {
|
||||
CcNoCall() { this = false }
|
||||
}
|
||||
|
||||
Cc ccNone() { result = false }
|
||||
Cc ccNone() { result instanceof CallContextAny }
|
||||
|
||||
private class LocalCc = Unit;
|
||||
|
||||
bindingset[call, c, outercc]
|
||||
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
|
||||
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
|
||||
checkCallContextCall(outercc, call, c) and
|
||||
if recordDataFlowCallSiteDispatch(call, c)
|
||||
then result = TSpecificCall(call)
|
||||
else result = TSomeCall()
|
||||
}
|
||||
|
||||
bindingset[call, c, innercc]
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
|
||||
checkCallContextReturn(innercc, c, call) and
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
@@ -1172,7 +1173,8 @@ private module Stage2 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -1860,7 +1862,8 @@ private module Stage3 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -2117,7 +2120,7 @@ private module Stage3 {
|
||||
private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
|
||||
exists(AccessPathFront apf |
|
||||
Stage3::revFlow(node, true, _, apf, config) and
|
||||
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
|
||||
Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2618,7 +2621,8 @@ private module Stage4 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3639,9 +3643,10 @@ private module Subpaths {
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _,
|
||||
unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3686,8 +3691,8 @@ private module Subpaths {
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
||||
pragma[only_bind_into](arg).getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
|
||||
@@ -923,28 +923,29 @@ private module Stage2 {
|
||||
|
||||
ApOption apSome(Ap ap) { result = TBooleanSome(ap) }
|
||||
|
||||
class Cc = boolean;
|
||||
class Cc = CallContext;
|
||||
|
||||
class CcCall extends Cc {
|
||||
CcCall() { this = true }
|
||||
class CcCall = CallContextCall;
|
||||
|
||||
/** Holds if this call context may be `call`. */
|
||||
predicate matchesCall(DataFlowCall call) { any() }
|
||||
}
|
||||
class CcNoCall = CallContextNoCall;
|
||||
|
||||
class CcNoCall extends Cc {
|
||||
CcNoCall() { this = false }
|
||||
}
|
||||
|
||||
Cc ccNone() { result = false }
|
||||
Cc ccNone() { result instanceof CallContextAny }
|
||||
|
||||
private class LocalCc = Unit;
|
||||
|
||||
bindingset[call, c, outercc]
|
||||
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
|
||||
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
|
||||
checkCallContextCall(outercc, call, c) and
|
||||
if recordDataFlowCallSiteDispatch(call, c)
|
||||
then result = TSpecificCall(call)
|
||||
else result = TSomeCall()
|
||||
}
|
||||
|
||||
bindingset[call, c, innercc]
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
|
||||
checkCallContextReturn(innercc, c, call) and
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
@@ -1172,7 +1173,8 @@ private module Stage2 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -1860,7 +1862,8 @@ private module Stage3 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -2117,7 +2120,7 @@ private module Stage3 {
|
||||
private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
|
||||
exists(AccessPathFront apf |
|
||||
Stage3::revFlow(node, true, _, apf, config) and
|
||||
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
|
||||
Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2618,7 +2621,8 @@ private module Stage4 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3639,9 +3643,10 @@ private module Subpaths {
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _,
|
||||
unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3686,8 +3691,8 @@ private module Subpaths {
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
||||
pragma[only_bind_into](arg).getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
|
||||
@@ -923,28 +923,29 @@ private module Stage2 {
|
||||
|
||||
ApOption apSome(Ap ap) { result = TBooleanSome(ap) }
|
||||
|
||||
class Cc = boolean;
|
||||
class Cc = CallContext;
|
||||
|
||||
class CcCall extends Cc {
|
||||
CcCall() { this = true }
|
||||
class CcCall = CallContextCall;
|
||||
|
||||
/** Holds if this call context may be `call`. */
|
||||
predicate matchesCall(DataFlowCall call) { any() }
|
||||
}
|
||||
class CcNoCall = CallContextNoCall;
|
||||
|
||||
class CcNoCall extends Cc {
|
||||
CcNoCall() { this = false }
|
||||
}
|
||||
|
||||
Cc ccNone() { result = false }
|
||||
Cc ccNone() { result instanceof CallContextAny }
|
||||
|
||||
private class LocalCc = Unit;
|
||||
|
||||
bindingset[call, c, outercc]
|
||||
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
|
||||
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
|
||||
checkCallContextCall(outercc, call, c) and
|
||||
if recordDataFlowCallSiteDispatch(call, c)
|
||||
then result = TSpecificCall(call)
|
||||
else result = TSomeCall()
|
||||
}
|
||||
|
||||
bindingset[call, c, innercc]
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
|
||||
checkCallContextReturn(innercc, c, call) and
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
@@ -1172,7 +1173,8 @@ private module Stage2 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -1860,7 +1862,8 @@ private module Stage3 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -2117,7 +2120,7 @@ private module Stage3 {
|
||||
private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
|
||||
exists(AccessPathFront apf |
|
||||
Stage3::revFlow(node, true, _, apf, config) and
|
||||
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
|
||||
Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2618,7 +2621,8 @@ private module Stage4 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3639,9 +3643,10 @@ private module Subpaths {
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _,
|
||||
unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3686,8 +3691,8 @@ private module Subpaths {
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
||||
pragma[only_bind_into](arg).getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
|
||||
@@ -786,13 +786,18 @@ private module Cached {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call context `call` either improves virtual dispatch in
|
||||
* `callable` or if it allows us to prune unreachable nodes in `callable`.
|
||||
* Holds if the call context `call` improves virtual dispatch in `callable`.
|
||||
*/
|
||||
cached
|
||||
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
|
||||
predicate recordDataFlowCallSiteDispatch(DataFlowCall call, DataFlowCallable callable) {
|
||||
reducedViableImplInCallContext(_, callable, call)
|
||||
or
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call context `call` allows us to prune unreachable nodes in `callable`.
|
||||
*/
|
||||
cached
|
||||
predicate recordDataFlowCallSiteUnreachable(DataFlowCall call, DataFlowCallable callable) {
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call))
|
||||
}
|
||||
|
||||
@@ -846,6 +851,15 @@ private module Cached {
|
||||
TAccessPathFrontSome(AccessPathFront apf)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call context `call` either improves virtual dispatch in
|
||||
* `callable` or if it allows us to prune unreachable nodes in `callable`.
|
||||
*/
|
||||
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
|
||||
recordDataFlowCallSiteDispatch(call, callable) or
|
||||
recordDataFlowCallSiteUnreachable(call, callable)
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Node` at which a cast can occur such that the type should be checked.
|
||||
*/
|
||||
|
||||
@@ -923,28 +923,29 @@ private module Stage2 {
|
||||
|
||||
ApOption apSome(Ap ap) { result = TBooleanSome(ap) }
|
||||
|
||||
class Cc = boolean;
|
||||
class Cc = CallContext;
|
||||
|
||||
class CcCall extends Cc {
|
||||
CcCall() { this = true }
|
||||
class CcCall = CallContextCall;
|
||||
|
||||
/** Holds if this call context may be `call`. */
|
||||
predicate matchesCall(DataFlowCall call) { any() }
|
||||
}
|
||||
class CcNoCall = CallContextNoCall;
|
||||
|
||||
class CcNoCall extends Cc {
|
||||
CcNoCall() { this = false }
|
||||
}
|
||||
|
||||
Cc ccNone() { result = false }
|
||||
Cc ccNone() { result instanceof CallContextAny }
|
||||
|
||||
private class LocalCc = Unit;
|
||||
|
||||
bindingset[call, c, outercc]
|
||||
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
|
||||
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
|
||||
checkCallContextCall(outercc, call, c) and
|
||||
if recordDataFlowCallSiteDispatch(call, c)
|
||||
then result = TSpecificCall(call)
|
||||
else result = TSomeCall()
|
||||
}
|
||||
|
||||
bindingset[call, c, innercc]
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
|
||||
checkCallContextReturn(innercc, c, call) and
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
@@ -1172,7 +1173,8 @@ private module Stage2 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -1860,7 +1862,8 @@ private module Stage3 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -2117,7 +2120,7 @@ private module Stage3 {
|
||||
private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
|
||||
exists(AccessPathFront apf |
|
||||
Stage3::revFlow(node, true, _, apf, config) and
|
||||
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
|
||||
Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2618,7 +2621,8 @@ private module Stage4 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3639,9 +3643,10 @@ private module Subpaths {
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _,
|
||||
unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3686,8 +3691,8 @@ private module Subpaths {
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
||||
pragma[only_bind_into](arg).getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
|
||||
@@ -550,6 +550,39 @@ module TaintedWithPath {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is flow from `arg` to `out` across a call that can by summarized by the flow
|
||||
* from `par` to `ret` within it, in the graph of data flow path explanations.
|
||||
*/
|
||||
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
|
||||
DataFlow3::PathGraph::subpaths(arg.(WrapPathNode).inner(), par.(WrapPathNode).inner(),
|
||||
ret.(WrapPathNode).inner(), out.(WrapPathNode).inner())
|
||||
or
|
||||
// To avoid showing trivial-looking steps, we _replace_ the last node instead
|
||||
// of adding an edge out of it.
|
||||
exists(WrapPathNode sinkNode |
|
||||
DataFlow3::PathGraph::subpaths(arg.(WrapPathNode).inner(), par.(WrapPathNode).inner(),
|
||||
ret.(WrapPathNode).inner(), sinkNode.inner()) and
|
||||
out.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode())
|
||||
)
|
||||
or
|
||||
// Same for the first node
|
||||
exists(WrapPathNode sourceNode |
|
||||
DataFlow3::PathGraph::subpaths(sourceNode.inner(), par.(WrapPathNode).inner(),
|
||||
ret.(WrapPathNode).inner(), out.(WrapPathNode).inner()) and
|
||||
sourceNode.inner().getNode() = getNodeForExpr(arg.(InitialPathNode).inner())
|
||||
)
|
||||
or
|
||||
// Finally, handle the case where the path goes directly from a source to a
|
||||
// sink, meaning that they both need to be translated.
|
||||
exists(WrapPathNode sinkNode, WrapPathNode sourceNode |
|
||||
DataFlow3::PathGraph::subpaths(sourceNode.inner(), par.(WrapPathNode).inner(),
|
||||
ret.(WrapPathNode).inner(), sinkNode.inner()) and
|
||||
sourceNode.inner().getNode() = getNodeForExpr(arg.(InitialPathNode).inner()) and
|
||||
out.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode())
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
key = "semmle.label" and val = n.toString()
|
||||
|
||||
@@ -923,28 +923,29 @@ private module Stage2 {
|
||||
|
||||
ApOption apSome(Ap ap) { result = TBooleanSome(ap) }
|
||||
|
||||
class Cc = boolean;
|
||||
class Cc = CallContext;
|
||||
|
||||
class CcCall extends Cc {
|
||||
CcCall() { this = true }
|
||||
class CcCall = CallContextCall;
|
||||
|
||||
/** Holds if this call context may be `call`. */
|
||||
predicate matchesCall(DataFlowCall call) { any() }
|
||||
}
|
||||
class CcNoCall = CallContextNoCall;
|
||||
|
||||
class CcNoCall extends Cc {
|
||||
CcNoCall() { this = false }
|
||||
}
|
||||
|
||||
Cc ccNone() { result = false }
|
||||
Cc ccNone() { result instanceof CallContextAny }
|
||||
|
||||
private class LocalCc = Unit;
|
||||
|
||||
bindingset[call, c, outercc]
|
||||
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
|
||||
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
|
||||
checkCallContextCall(outercc, call, c) and
|
||||
if recordDataFlowCallSiteDispatch(call, c)
|
||||
then result = TSpecificCall(call)
|
||||
else result = TSomeCall()
|
||||
}
|
||||
|
||||
bindingset[call, c, innercc]
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
|
||||
checkCallContextReturn(innercc, c, call) and
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
@@ -1172,7 +1173,8 @@ private module Stage2 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -1860,7 +1862,8 @@ private module Stage3 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -2117,7 +2120,7 @@ private module Stage3 {
|
||||
private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
|
||||
exists(AccessPathFront apf |
|
||||
Stage3::revFlow(node, true, _, apf, config) and
|
||||
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
|
||||
Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2618,7 +2621,8 @@ private module Stage4 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3639,9 +3643,10 @@ private module Subpaths {
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _,
|
||||
unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3686,8 +3691,8 @@ private module Subpaths {
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
||||
pragma[only_bind_into](arg).getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
|
||||
@@ -923,28 +923,29 @@ private module Stage2 {
|
||||
|
||||
ApOption apSome(Ap ap) { result = TBooleanSome(ap) }
|
||||
|
||||
class Cc = boolean;
|
||||
class Cc = CallContext;
|
||||
|
||||
class CcCall extends Cc {
|
||||
CcCall() { this = true }
|
||||
class CcCall = CallContextCall;
|
||||
|
||||
/** Holds if this call context may be `call`. */
|
||||
predicate matchesCall(DataFlowCall call) { any() }
|
||||
}
|
||||
class CcNoCall = CallContextNoCall;
|
||||
|
||||
class CcNoCall extends Cc {
|
||||
CcNoCall() { this = false }
|
||||
}
|
||||
|
||||
Cc ccNone() { result = false }
|
||||
Cc ccNone() { result instanceof CallContextAny }
|
||||
|
||||
private class LocalCc = Unit;
|
||||
|
||||
bindingset[call, c, outercc]
|
||||
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
|
||||
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
|
||||
checkCallContextCall(outercc, call, c) and
|
||||
if recordDataFlowCallSiteDispatch(call, c)
|
||||
then result = TSpecificCall(call)
|
||||
else result = TSomeCall()
|
||||
}
|
||||
|
||||
bindingset[call, c, innercc]
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
|
||||
checkCallContextReturn(innercc, c, call) and
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
@@ -1172,7 +1173,8 @@ private module Stage2 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -1860,7 +1862,8 @@ private module Stage3 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -2117,7 +2120,7 @@ private module Stage3 {
|
||||
private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
|
||||
exists(AccessPathFront apf |
|
||||
Stage3::revFlow(node, true, _, apf, config) and
|
||||
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
|
||||
Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2618,7 +2621,8 @@ private module Stage4 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3639,9 +3643,10 @@ private module Subpaths {
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _,
|
||||
unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3686,8 +3691,8 @@ private module Subpaths {
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
||||
pragma[only_bind_into](arg).getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
|
||||
@@ -923,28 +923,29 @@ private module Stage2 {
|
||||
|
||||
ApOption apSome(Ap ap) { result = TBooleanSome(ap) }
|
||||
|
||||
class Cc = boolean;
|
||||
class Cc = CallContext;
|
||||
|
||||
class CcCall extends Cc {
|
||||
CcCall() { this = true }
|
||||
class CcCall = CallContextCall;
|
||||
|
||||
/** Holds if this call context may be `call`. */
|
||||
predicate matchesCall(DataFlowCall call) { any() }
|
||||
}
|
||||
class CcNoCall = CallContextNoCall;
|
||||
|
||||
class CcNoCall extends Cc {
|
||||
CcNoCall() { this = false }
|
||||
}
|
||||
|
||||
Cc ccNone() { result = false }
|
||||
Cc ccNone() { result instanceof CallContextAny }
|
||||
|
||||
private class LocalCc = Unit;
|
||||
|
||||
bindingset[call, c, outercc]
|
||||
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
|
||||
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
|
||||
checkCallContextCall(outercc, call, c) and
|
||||
if recordDataFlowCallSiteDispatch(call, c)
|
||||
then result = TSpecificCall(call)
|
||||
else result = TSomeCall()
|
||||
}
|
||||
|
||||
bindingset[call, c, innercc]
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
|
||||
checkCallContextReturn(innercc, c, call) and
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
@@ -1172,7 +1173,8 @@ private module Stage2 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -1860,7 +1862,8 @@ private module Stage3 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -2117,7 +2120,7 @@ private module Stage3 {
|
||||
private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
|
||||
exists(AccessPathFront apf |
|
||||
Stage3::revFlow(node, true, _, apf, config) and
|
||||
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
|
||||
Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2618,7 +2621,8 @@ private module Stage4 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3639,9 +3643,10 @@ private module Subpaths {
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _,
|
||||
unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3686,8 +3691,8 @@ private module Subpaths {
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
||||
pragma[only_bind_into](arg).getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
|
||||
@@ -923,28 +923,29 @@ private module Stage2 {
|
||||
|
||||
ApOption apSome(Ap ap) { result = TBooleanSome(ap) }
|
||||
|
||||
class Cc = boolean;
|
||||
class Cc = CallContext;
|
||||
|
||||
class CcCall extends Cc {
|
||||
CcCall() { this = true }
|
||||
class CcCall = CallContextCall;
|
||||
|
||||
/** Holds if this call context may be `call`. */
|
||||
predicate matchesCall(DataFlowCall call) { any() }
|
||||
}
|
||||
class CcNoCall = CallContextNoCall;
|
||||
|
||||
class CcNoCall extends Cc {
|
||||
CcNoCall() { this = false }
|
||||
}
|
||||
|
||||
Cc ccNone() { result = false }
|
||||
Cc ccNone() { result instanceof CallContextAny }
|
||||
|
||||
private class LocalCc = Unit;
|
||||
|
||||
bindingset[call, c, outercc]
|
||||
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
|
||||
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
|
||||
checkCallContextCall(outercc, call, c) and
|
||||
if recordDataFlowCallSiteDispatch(call, c)
|
||||
then result = TSpecificCall(call)
|
||||
else result = TSomeCall()
|
||||
}
|
||||
|
||||
bindingset[call, c, innercc]
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
|
||||
checkCallContextReturn(innercc, c, call) and
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
@@ -1172,7 +1173,8 @@ private module Stage2 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -1860,7 +1862,8 @@ private module Stage3 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -2117,7 +2120,7 @@ private module Stage3 {
|
||||
private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
|
||||
exists(AccessPathFront apf |
|
||||
Stage3::revFlow(node, true, _, apf, config) and
|
||||
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
|
||||
Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2618,7 +2621,8 @@ private module Stage4 {
|
||||
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
|
||||
pragma[only_bind_into](config)) and
|
||||
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
|
||||
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
|
||||
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
|
||||
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3639,9 +3643,10 @@ private module Subpaths {
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, AccessPath apout
|
||||
) {
|
||||
pathThroughCallable(arg, out, _, apout) and
|
||||
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
|
||||
pathIntoCallable(arg, par, _, innercc, sc, _) and
|
||||
paramFlowsThrough(kind, innercc, sc, apout, _, unbindConf(arg.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _,
|
||||
unbindConf(arg.getConfiguration()))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3686,8 +3691,8 @@ private module Subpaths {
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
|
||||
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
|
||||
arg.getASuccessor() = par and
|
||||
arg.getASuccessor() = out and
|
||||
pragma[only_bind_into](arg).getASuccessor() = par and
|
||||
pragma[only_bind_into](arg).getASuccessor() = out and
|
||||
subpaths03(arg, p, ret, o, apout) and
|
||||
par.getNodeEx() = p and
|
||||
out.getNodeEx() = o and
|
||||
|
||||
@@ -786,13 +786,18 @@ private module Cached {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call context `call` either improves virtual dispatch in
|
||||
* `callable` or if it allows us to prune unreachable nodes in `callable`.
|
||||
* Holds if the call context `call` improves virtual dispatch in `callable`.
|
||||
*/
|
||||
cached
|
||||
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
|
||||
predicate recordDataFlowCallSiteDispatch(DataFlowCall call, DataFlowCallable callable) {
|
||||
reducedViableImplInCallContext(_, callable, call)
|
||||
or
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call context `call` allows us to prune unreachable nodes in `callable`.
|
||||
*/
|
||||
cached
|
||||
predicate recordDataFlowCallSiteUnreachable(DataFlowCall call, DataFlowCallable callable) {
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call))
|
||||
}
|
||||
|
||||
@@ -846,6 +851,15 @@ private module Cached {
|
||||
TAccessPathFrontSome(AccessPathFront apf)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call context `call` either improves virtual dispatch in
|
||||
* `callable` or if it allows us to prune unreachable nodes in `callable`.
|
||||
*/
|
||||
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
|
||||
recordDataFlowCallSiteDispatch(call, callable) or
|
||||
recordDataFlowCallSiteUnreachable(call, callable)
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Node` at which a cast can occur such that the type should be checked.
|
||||
*/
|
||||
|
||||
@@ -1856,12 +1856,12 @@ class InitializeDynamicAllocationInstruction extends SideEffectInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the address of the allocation this instruction is initializing.
|
||||
* Gets the operand that represents the address of the allocation this instruction is initializing.
|
||||
*/
|
||||
final AddressOperand getAllocationAddressOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the operand for the allocation this instruction is initializing.
|
||||
* Gets the address for the allocation this instruction is initializing.
|
||||
*/
|
||||
final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() }
|
||||
}
|
||||
|
||||
@@ -1856,12 +1856,12 @@ class InitializeDynamicAllocationInstruction extends SideEffectInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the address of the allocation this instruction is initializing.
|
||||
* Gets the operand that represents the address of the allocation this instruction is initializing.
|
||||
*/
|
||||
final AddressOperand getAllocationAddressOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the operand for the allocation this instruction is initializing.
|
||||
* Gets the address for the allocation this instruction is initializing.
|
||||
*/
|
||||
final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() }
|
||||
}
|
||||
|
||||
@@ -1856,12 +1856,12 @@ class InitializeDynamicAllocationInstruction extends SideEffectInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the address of the allocation this instruction is initializing.
|
||||
* Gets the operand that represents the address of the allocation this instruction is initializing.
|
||||
*/
|
||||
final AddressOperand getAllocationAddressOperand() { result = getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets the operand for the allocation this instruction is initializing.
|
||||
* Gets the address for the allocation this instruction is initializing.
|
||||
*/
|
||||
final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() }
|
||||
}
|
||||
|
||||
@@ -33,3 +33,6 @@ private import implementations.Recv
|
||||
private import implementations.Accept
|
||||
private import implementations.Poll
|
||||
private import implementations.Select
|
||||
private import implementations.MySql
|
||||
private import implementations.SqLite3
|
||||
private import implementations.PostgreSql
|
||||
|
||||
32
cpp/ql/lib/semmle/code/cpp/models/implementations/MySql.qll
Normal file
32
cpp/ql/lib/semmle/code/cpp/models/implementations/MySql.qll
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Provides implementation classes modeling the MySql C API.
|
||||
* See `semmle.code.cpp.models.Models` for usage information.
|
||||
*/
|
||||
|
||||
private import semmle.code.cpp.models.interfaces.Sql
|
||||
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
|
||||
|
||||
/**
|
||||
* The `mysql_query` family of functions from the MySQL C API.
|
||||
*/
|
||||
private class MySqlExecutionFunction extends SqlExecutionFunction {
|
||||
MySqlExecutionFunction() {
|
||||
this.hasName(["mysql_query", "mysql_real_query", "mysql_real_query_nonblocking"])
|
||||
}
|
||||
|
||||
override predicate hasSqlArgument(FunctionInput input) { input.isParameterDeref(1) }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `mysql_real_escape_string` family of functions from the MySQL C API.
|
||||
*/
|
||||
private class MySqlBarrierFunction extends SqlBarrierFunction {
|
||||
MySqlBarrierFunction() {
|
||||
this.hasName(["mysql_real_escape_string", "mysql_real_escape_string_quote"])
|
||||
}
|
||||
|
||||
override predicate barrierSqlArgument(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameterDeref(2) and
|
||||
output.isParameterDeref(1)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
private import semmle.code.cpp.models.interfaces.Sql
|
||||
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
|
||||
|
||||
private predicate pqxxTransactionSqlArgument(string function, int arg) {
|
||||
function = "exec" and arg = 0
|
||||
or
|
||||
function = "exec0" and arg = 0
|
||||
or
|
||||
function = "exec1" and arg = 0
|
||||
or
|
||||
function = "exec_n" and arg = 1
|
||||
or
|
||||
function = "exec_params" and arg = 0
|
||||
or
|
||||
function = "exec_params0" and arg = 0
|
||||
or
|
||||
function = "exec_params1" and arg = 0
|
||||
or
|
||||
function = "exec_params_n" and arg = 1
|
||||
or
|
||||
function = "query_value" and arg = 0
|
||||
or
|
||||
function = "stream" and arg = 0
|
||||
}
|
||||
|
||||
private predicate pqxxConnectionSqlArgument(string function, int arg) {
|
||||
function = "prepare" and arg = 1
|
||||
}
|
||||
|
||||
private predicate pqxxTransationClassNames(string className, string namespace) {
|
||||
namespace = "pqxx" and
|
||||
className in [
|
||||
"dbtransaction", "nontransaction", "basic_robusttransaction", "robusttransaction",
|
||||
"subtransaction", "transaction", "basic_transaction", "transaction_base", "work"
|
||||
]
|
||||
}
|
||||
|
||||
private predicate pqxxConnectionClassNames(string className, string namespace) {
|
||||
namespace = "pqxx" and
|
||||
className in ["connection_base", "basic_connection", "connection"]
|
||||
}
|
||||
|
||||
private predicate pqxxEscapeArgument(string function, int arg) {
|
||||
arg = 0 and
|
||||
function in ["esc", "esc_raw", "quote", "quote_raw", "quote_name", "quote_table", "esc_like"]
|
||||
}
|
||||
|
||||
private class PostgreSqlExecutionFunction extends SqlExecutionFunction {
|
||||
PostgreSqlExecutionFunction() {
|
||||
exists(Class c |
|
||||
this.getDeclaringType() = c and
|
||||
// transaction exec and connection prepare variations
|
||||
(
|
||||
pqxxTransationClassNames(c.getName(), c.getNamespace().getName()) and
|
||||
pqxxTransactionSqlArgument(this.getName(), _)
|
||||
or
|
||||
pqxxConnectionSqlArgument(this.getName(), _) and
|
||||
pqxxConnectionClassNames(c.getName(), c.getNamespace().getName())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasSqlArgument(FunctionInput input) {
|
||||
exists(int argIndex |
|
||||
pqxxTransactionSqlArgument(this.getName(), argIndex)
|
||||
or
|
||||
pqxxConnectionSqlArgument(this.getName(), argIndex)
|
||||
|
|
||||
input.isParameterDeref(argIndex)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class PostgreSqlBarrierFunction extends SqlBarrierFunction {
|
||||
PostgreSqlBarrierFunction() {
|
||||
exists(Class c |
|
||||
this.getDeclaringType() = c and
|
||||
// transaction and connection escape functions
|
||||
(
|
||||
pqxxTransationClassNames(c.getName(), c.getNamespace().getName()) or
|
||||
pqxxConnectionClassNames(c.getName(), c.getNamespace().getName())
|
||||
) and
|
||||
pqxxEscapeArgument(this.getName(), _)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate barrierSqlArgument(FunctionInput input, FunctionOutput output) {
|
||||
exists(int argIndex |
|
||||
input.isParameterDeref(argIndex) and
|
||||
output.isReturnValueDeref() and
|
||||
pqxxEscapeArgument(this.getName(), argIndex)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Provides implementation classes modeling the SQLite C API.
|
||||
* See `semmle.code.cpp.models.Models` for usage information.
|
||||
*/
|
||||
|
||||
private import semmle.code.cpp.models.interfaces.Sql
|
||||
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
|
||||
|
||||
/**
|
||||
* The `sqlite3_exec` and `sqlite3_prepare` families of functions from the SQLite C API.
|
||||
*/
|
||||
private class SqLite3ExecutionFunction extends SqlExecutionFunction {
|
||||
SqLite3ExecutionFunction() {
|
||||
this.hasName([
|
||||
"sqlite3_exec", "sqlite3_prepare", "sqlite3_prepare_v2", "sqlite3_prepare_v3",
|
||||
"sqlite3_prepare16", "sqlite3_prepare16_v2", "sqlite3_prepare16_v3"
|
||||
])
|
||||
}
|
||||
|
||||
override predicate hasSqlArgument(FunctionInput input) { input.isParameterDeref(1) }
|
||||
}
|
||||
30
cpp/ql/lib/semmle/code/cpp/models/interfaces/Sql.qll
Normal file
30
cpp/ql/lib/semmle/code/cpp/models/interfaces/Sql.qll
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Provides abstract classes for modeling functions that execute and escape SQL query strings.
|
||||
* To extend this QL library, create a QL class extending `SqlExecutionFunction` or `SqlEscapeFunction`
|
||||
* with a characteristic predicate that selects the function or set of functions you are modeling.
|
||||
* Within that class, override the predicates provided by the class to match the way a
|
||||
* parameter flows into the function and, in the case of `SqlEscapeFunction`, out of the function.
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
|
||||
/**
|
||||
* An abstract class that represents a function that executes an SQL query.
|
||||
*/
|
||||
abstract class SqlExecutionFunction extends Function {
|
||||
/**
|
||||
* Holds if `input` to this function represents SQL code to be executed.
|
||||
*/
|
||||
abstract predicate hasSqlArgument(FunctionInput input);
|
||||
}
|
||||
|
||||
/**
|
||||
* An abstract class that represents a function that is a barrier to an SQL query string.
|
||||
*/
|
||||
abstract class SqlBarrierFunction extends Function {
|
||||
/**
|
||||
* Holds if the `output` is a barrier to the SQL input `input` such that is it safe to pass to
|
||||
* an `SqlExecutionFunction`.
|
||||
*/
|
||||
abstract predicate barrierSqlArgument(FunctionInput input, FunctionOutput output);
|
||||
}
|
||||
@@ -1541,7 +1541,8 @@ private float getGuardedUpperBound(VariableAccess guardedAccess) {
|
||||
// that there is one predecessor, albeit somewhat conservative.
|
||||
exists(unique(BasicBlock b | b = def.(BasicBlock).getAPredecessor())) and
|
||||
guardedAccess = def.getAUse(v) and
|
||||
result = max(float ub | upperBoundFromGuard(guard, guardVa, ub, branch))
|
||||
result = max(float ub | upperBoundFromGuard(guard, guardVa, ub, branch)) and
|
||||
not convertedExprMightOverflow(guard.getAChild+())
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import semmle.code.cpp.exprs.Expr
|
||||
import semmle.code.cpp.commons.Environment
|
||||
import semmle.code.cpp.security.SecurityOptions
|
||||
import semmle.code.cpp.models.interfaces.FlowSource
|
||||
import semmle.code.cpp.models.interfaces.Sql
|
||||
|
||||
/**
|
||||
* Extend this class to customize the security queries for
|
||||
@@ -34,13 +35,11 @@ class SecurityOptions extends string {
|
||||
* An argument to a function that is passed to a SQL server.
|
||||
*/
|
||||
predicate sqlArgument(string function, int arg) {
|
||||
// MySQL C API
|
||||
function = "mysql_query" and arg = 1
|
||||
or
|
||||
function = "mysql_real_query" and arg = 1
|
||||
or
|
||||
// SQLite3 C API
|
||||
function = "sqlite3_exec" and arg = 1
|
||||
exists(FunctionInput input, SqlExecutionFunction sql |
|
||||
sql.hasName(function) and
|
||||
input.isParameterDeref(arg) and
|
||||
sql.hasSqlArgument(input)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -310,23 +310,14 @@ diagnostics(
|
||||
int location: @location_default ref
|
||||
);
|
||||
|
||||
/*
|
||||
fromSource(0) = unknown,
|
||||
fromSource(1) = from source,
|
||||
fromSource(2) = from library
|
||||
*/
|
||||
files(
|
||||
unique int id: @file,
|
||||
string name: string ref,
|
||||
string simple: string ref,
|
||||
string ext: string ref,
|
||||
int fromSource: int ref
|
||||
string name: string ref
|
||||
);
|
||||
|
||||
folders(
|
||||
unique int id: @folder,
|
||||
string name: string ref,
|
||||
string simple: string ref
|
||||
string name: string ref
|
||||
);
|
||||
|
||||
@container = @folder | @file
|
||||
|
||||
@@ -12875,18 +12875,6 @@
|
||||
<k>name</k>
|
||||
<v>59320</v>
|
||||
</e>
|
||||
<e>
|
||||
<k>simple</k>
|
||||
<v>40580</v>
|
||||
</e>
|
||||
<e>
|
||||
<k>ext</k>
|
||||
<v>97</v>
|
||||
</e>
|
||||
<e>
|
||||
<k>fromSource</k>
|
||||
<v>10</v>
|
||||
</e>
|
||||
</columnsizes>
|
||||
<dependencies>
|
||||
<dep>
|
||||
@@ -12906,54 +12894,6 @@
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>id</src>
|
||||
<trg>simple</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>1</a>
|
||||
<b>2</b>
|
||||
<v>59320</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>id</src>
|
||||
<trg>ext</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>1</a>
|
||||
<b>2</b>
|
||||
<v>59320</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>id</src>
|
||||
<trg>fromSource</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>1</a>
|
||||
<b>2</b>
|
||||
<v>59320</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>name</src>
|
||||
<trg>id</trg>
|
||||
<val>
|
||||
@@ -12969,406 +12909,6 @@
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>name</src>
|
||||
<trg>simple</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>1</a>
|
||||
<b>2</b>
|
||||
<v>59320</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>name</src>
|
||||
<trg>ext</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>1</a>
|
||||
<b>2</b>
|
||||
<v>59320</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>name</src>
|
||||
<trg>fromSource</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>1</a>
|
||||
<b>2</b>
|
||||
<v>59320</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>simple</src>
|
||||
<trg>id</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>1</a>
|
||||
<b>2</b>
|
||||
<v>30814</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>2</a>
|
||||
<b>3</b>
|
||||
<v>6123</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>3</a>
|
||||
<b>7</b>
|
||||
<v>3197</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>7</a>
|
||||
<b>42</b>
|
||||
<v>444</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>simple</src>
|
||||
<trg>name</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>1</a>
|
||||
<b>2</b>
|
||||
<v>30814</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>2</a>
|
||||
<b>3</b>
|
||||
<v>6123</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>3</a>
|
||||
<b>7</b>
|
||||
<v>3197</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>7</a>
|
||||
<b>42</b>
|
||||
<v>444</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>simple</src>
|
||||
<trg>ext</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>1</a>
|
||||
<b>2</b>
|
||||
<v>36277</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>2</a>
|
||||
<b>3</b>
|
||||
<v>3739</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>3</a>
|
||||
<b>6</b>
|
||||
<v>563</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>simple</src>
|
||||
<trg>fromSource</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>1</a>
|
||||
<b>2</b>
|
||||
<v>40580</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>ext</src>
|
||||
<trg>id</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>1</a>
|
||||
<b>2</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>3</a>
|
||||
<b>4</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>15</a>
|
||||
<b>16</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>38</a>
|
||||
<b>39</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>80</a>
|
||||
<b>81</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>114</a>
|
||||
<b>115</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>441</a>
|
||||
<b>442</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>768</a>
|
||||
<b>769</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>4013</a>
|
||||
<b>4014</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>ext</src>
|
||||
<trg>name</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>1</a>
|
||||
<b>2</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>3</a>
|
||||
<b>4</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>15</a>
|
||||
<b>16</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>38</a>
|
||||
<b>39</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>80</a>
|
||||
<b>81</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>114</a>
|
||||
<b>115</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>441</a>
|
||||
<b>442</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>768</a>
|
||||
<b>769</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>4013</a>
|
||||
<b>4014</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>ext</src>
|
||||
<trg>simple</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>1</a>
|
||||
<b>2</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>3</a>
|
||||
<b>4</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>15</a>
|
||||
<b>16</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>38</a>
|
||||
<b>39</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>75</a>
|
||||
<b>76</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>112</a>
|
||||
<b>113</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>428</a>
|
||||
<b>429</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>688</a>
|
||||
<b>689</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>2838</a>
|
||||
<b>2839</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>ext</src>
|
||||
<trg>fromSource</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>1</a>
|
||||
<b>2</b>
|
||||
<v>97</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>fromSource</src>
|
||||
<trg>id</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>5473</a>
|
||||
<b>5474</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>fromSource</src>
|
||||
<trg>name</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>5473</a>
|
||||
<b>5474</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>fromSource</src>
|
||||
<trg>simple</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>3744</a>
|
||||
<b>3745</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>fromSource</src>
|
||||
<trg>ext</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>9</a>
|
||||
<b>10</b>
|
||||
<v>10</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
</dependencies>
|
||||
</relation>
|
||||
<relation>
|
||||
@@ -13383,10 +12923,6 @@
|
||||
<k>name</k>
|
||||
<v>10817</v>
|
||||
</e>
|
||||
<e>
|
||||
<k>simple</k>
|
||||
<v>3099</v>
|
||||
</e>
|
||||
</columnsizes>
|
||||
<dependencies>
|
||||
<dep>
|
||||
@@ -13406,22 +12942,6 @@
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>id</src>
|
||||
<trg>simple</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>1</a>
|
||||
<b>2</b>
|
||||
<v>10817</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>name</src>
|
||||
<trg>id</trg>
|
||||
<val>
|
||||
@@ -13437,94 +12957,6 @@
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>name</src>
|
||||
<trg>simple</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>1</a>
|
||||
<b>2</b>
|
||||
<v>10817</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>simple</src>
|
||||
<trg>id</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>1</a>
|
||||
<b>2</b>
|
||||
<v>1669</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>2</a>
|
||||
<b>3</b>
|
||||
<v>661</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>3</a>
|
||||
<b>4</b>
|
||||
<v>433</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>4</a>
|
||||
<b>17</b>
|
||||
<v>238</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>27</a>
|
||||
<b>121</b>
|
||||
<v>97</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
<dep>
|
||||
<src>simple</src>
|
||||
<trg>name</trg>
|
||||
<val>
|
||||
<hist>
|
||||
<budget>12</budget>
|
||||
<bs>
|
||||
<b>
|
||||
<a>1</a>
|
||||
<b>2</b>
|
||||
<v>1669</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>2</a>
|
||||
<b>3</b>
|
||||
<v>661</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>3</a>
|
||||
<b>4</b>
|
||||
<v>433</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>4</a>
|
||||
<b>17</b>
|
||||
<v>238</v>
|
||||
</b>
|
||||
<b>
|
||||
<a>27</a>
|
||||
<b>121</b>
|
||||
<v>97</v>
|
||||
</b>
|
||||
</bs>
|
||||
</hist>
|
||||
</val>
|
||||
</dep>
|
||||
</dependencies>
|
||||
</relation>
|
||||
<relation>
|
||||
|
||||
12
cpp/ql/src/Metrics/Internal/DiagnosticsSumElapsedTimes.ql
Normal file
12
cpp/ql/src/Metrics/Internal/DiagnosticsSumElapsedTimes.ql
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @name Sum of frontend and extractor time
|
||||
* @description The sum of elapsed frontend time, and the sum of elapsed extractor time.
|
||||
* This query is for internal use only and may change without notice.
|
||||
* @kind table
|
||||
* @id cpp/frontend-and-extractor-time
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
select sum(Compilation c, float seconds | compilation_time(c, _, 2, seconds) | seconds) as sum_frontend_elapsed_seconds,
|
||||
sum(Compilation c, float seconds | compilation_time(c, _, 4, seconds) | seconds) as sum_extractor_elapsed_seconds
|
||||
@@ -30,7 +30,15 @@ class Configuration extends TaintTrackingConfiguration {
|
||||
}
|
||||
|
||||
override predicate isBarrier(Expr e) {
|
||||
super.isBarrier(e) or e.getUnspecifiedType() instanceof IntegralType
|
||||
super.isBarrier(e)
|
||||
or
|
||||
e.getUnspecifiedType() instanceof IntegralType
|
||||
or
|
||||
exists(SqlBarrierFunction sql, int arg, FunctionInput input |
|
||||
e = sql.getACallToThisFunction().getArgument(arg) and
|
||||
input.isParameterDeref(arg) and
|
||||
sql.barrierSqlArgument(input, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <pqxx/pqxx>
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
|
||||
if (argc != 2) {
|
||||
throw std::runtime_error("Give me a string!");
|
||||
}
|
||||
|
||||
pqxx::connection c;
|
||||
pqxx::work w(c);
|
||||
|
||||
// BAD
|
||||
char *userName = argv[1];
|
||||
char query1[1000] = {0};
|
||||
sprintf(query1, "SELECT UID FROM USERS where name = \"%s\"", userName);
|
||||
pqxx::row r = w.exec1(query1);
|
||||
w.commit();
|
||||
std::cout << r[0].as<int>() << std::endl;
|
||||
|
||||
// GOOD
|
||||
pqxx::result r2 = w.exec("SELECT " + w.quote(argv[1]));
|
||||
w.commit();
|
||||
std::cout << r2[0][0].c_str() << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>The code passes user input as part of a SQL query without escaping special elements.
|
||||
It generates a SQL query to Postgres using <code>sprintf</code>,
|
||||
with the user-supplied data directly passed as an argument
|
||||
to <code>sprintf</code>. This leaves the code vulnerable to attack by SQL Injection.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>Use a library routine to escape characters in the user-supplied
|
||||
string before converting it to SQL. Use <code>esc</code> and <code>quote</code> pqxx library functions.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
<sample src="SqlPqxxTainted.cpp" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>MSDN Library: <a href="https://docs.microsoft.com/en-us/sql/relational-databases/security/sql-injection">SQL Injection</a>.</li>
|
||||
|
||||
|
||||
<!-- LocalWords: SQL CWE
|
||||
-->
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -1,113 +0,0 @@
|
||||
/**
|
||||
* @name Uncontrolled data in SQL query to Postgres
|
||||
* @description Including user-supplied data in a SQL query to Postgres
|
||||
* without neutralizing special elements can make code
|
||||
* vulnerable to SQL Injection.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @id cpp/sql-injection-via-pqxx
|
||||
* @tags security
|
||||
* external/cwe/cwe-089
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.security.Security
|
||||
import semmle.code.cpp.dataflow.TaintTracking
|
||||
import DataFlow::PathGraph
|
||||
|
||||
predicate pqxxTransationClassNames(string className, string namespace) {
|
||||
namespace = "pqxx" and
|
||||
className in [
|
||||
"dbtransaction", "nontransaction", "basic_robusttransaction", "robusttransaction",
|
||||
"subtransaction", "transaction", "basic_transaction", "transaction_base", "work"
|
||||
]
|
||||
}
|
||||
|
||||
predicate pqxxConnectionClassNames(string className, string namespace) {
|
||||
namespace = "pqxx" and
|
||||
className in ["connection_base", "basic_connection", "connection"]
|
||||
}
|
||||
|
||||
predicate pqxxTransactionSqlArgument(string function, int arg) {
|
||||
function = "exec" and arg = 0
|
||||
or
|
||||
function = "exec0" and arg = 0
|
||||
or
|
||||
function = "exec1" and arg = 0
|
||||
or
|
||||
function = "exec_n" and arg = 1
|
||||
or
|
||||
function = "exec_params" and arg = 0
|
||||
or
|
||||
function = "exec_params0" and arg = 0
|
||||
or
|
||||
function = "exec_params1" and arg = 0
|
||||
or
|
||||
function = "exec_params_n" and arg = 1
|
||||
or
|
||||
function = "query_value" and arg = 0
|
||||
or
|
||||
function = "stream" and arg = 0
|
||||
}
|
||||
|
||||
predicate pqxxConnectionSqlArgument(string function, int arg) { function = "prepare" and arg = 1 }
|
||||
|
||||
Expr getPqxxSqlArgument() {
|
||||
exists(FunctionCall fc, Expr e, int argIndex, UserType t |
|
||||
// examples: 'work' for 'work.exec(...)'; '->' for 'tx->exec()'.
|
||||
e = fc.getQualifier() and
|
||||
// to find ConnectionHandle/TransationHandle and similar classes which override '->' operator behavior
|
||||
// and return pointer to a connection/transation object
|
||||
e.getType().refersTo(t) and
|
||||
// transaction exec and connection prepare variations
|
||||
(
|
||||
pqxxTransationClassNames(t.getName(), t.getNamespace().getName()) and
|
||||
pqxxTransactionSqlArgument(fc.getTarget().getName(), argIndex)
|
||||
or
|
||||
pqxxConnectionClassNames(t.getName(), t.getNamespace().getName()) and
|
||||
pqxxConnectionSqlArgument(fc.getTarget().getName(), argIndex)
|
||||
) and
|
||||
result = fc.getArgument(argIndex)
|
||||
)
|
||||
}
|
||||
|
||||
predicate pqxxEscapeArgument(string function, int arg) {
|
||||
arg = 0 and
|
||||
function in ["esc", "esc_raw", "quote", "quote_raw", "quote_name", "quote_table", "esc_like"]
|
||||
}
|
||||
|
||||
predicate isEscapedPqxxArgument(Expr argExpr) {
|
||||
exists(FunctionCall fc, Expr e, int argIndex, UserType t |
|
||||
// examples: 'work' for 'work.exec(...)'; '->' for 'tx->exec()'.
|
||||
e = fc.getQualifier() and
|
||||
// to find ConnectionHandle/TransationHandle and similar classes which override '->' operator behavior
|
||||
// and return pointer to a connection/transation object
|
||||
e.getType().refersTo(t) and
|
||||
// transaction and connection escape functions
|
||||
(
|
||||
pqxxTransationClassNames(t.getName(), t.getNamespace().getName()) or
|
||||
pqxxConnectionClassNames(t.getName(), t.getNamespace().getName())
|
||||
) and
|
||||
pqxxEscapeArgument(fc.getTarget().getName(), argIndex) and
|
||||
// is escaped arg == argExpr
|
||||
argExpr = fc.getArgument(argIndex)
|
||||
)
|
||||
}
|
||||
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "SqlPqxxTainted" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { isUserInput(source.asExpr(), _) }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink.asExpr() = getPqxxSqlArgument() }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) { isEscapedPqxxArgument(node.asExpr()) }
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, Configuration config, string taintCause
|
||||
where
|
||||
config.hasFlowPath(source, sink) and
|
||||
isUserInput(source.getNode().asExpr(), taintCause)
|
||||
select sink, source, sink, "This argument to a SQL query function is derived from $@", source,
|
||||
"user input (" + taintCause + ")"
|
||||
13
cpp/ql/src/experimental/Security/CWE/CWE-675/DoubleRelease.c
Normal file
13
cpp/ql/src/experimental/Security/CWE/CWE-675/DoubleRelease.c
Normal file
@@ -0,0 +1,13 @@
|
||||
...
|
||||
fs = socket(AF_UNIX, SOCK_STREAM, 0)
|
||||
...
|
||||
close(fs);
|
||||
fs = -1; // GOOD
|
||||
...
|
||||
|
||||
...
|
||||
fs = socket(AF_UNIX, SOCK_STREAM, 0)
|
||||
...
|
||||
close(fs);
|
||||
if(fs) close(fs); // BAD
|
||||
...
|
||||
@@ -0,0 +1,26 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>Double release of the descriptor can lead to a crash of the program. Requires the attention of developers.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>We recommend that you exclude situations of possible double release.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
<p>The following example demonstrates an erroneous and corrected use of descriptor deallocation.</p>
|
||||
<sample src="DoubleRelease.c" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
CERT C Coding Standard:
|
||||
<a href="https://wiki.sei.cmu.edu/confluence/display/c/FIO46-C.+Do+not+access+a+closed+file">FIO46-C. Do not access a closed file</a>.
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
142
cpp/ql/src/experimental/Security/CWE/CWE-675/DoubleRelease.ql
Normal file
142
cpp/ql/src/experimental/Security/CWE/CWE-675/DoubleRelease.ql
Normal file
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* @name Errors When Double Release
|
||||
* @description Double release of the descriptor can lead to a crash of the program.
|
||||
* @kind problem
|
||||
* @id cpp/double-release
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @tags security
|
||||
* external/cwe/cwe-675
|
||||
* external/cwe/cwe-666
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.commons.File
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
import semmle.code.cpp.valuenumbering.HashCons
|
||||
|
||||
/**
|
||||
* A function call that potentially does not return (such as `exit`).
|
||||
*/
|
||||
class CallMayNotReturn extends FunctionCall {
|
||||
CallMayNotReturn() {
|
||||
// call that is known to not return
|
||||
not exists(this.(ControlFlowNode).getASuccessor())
|
||||
or
|
||||
// call to another function that may not return
|
||||
exists(CallMayNotReturn exit | getTarget() = exit.getEnclosingFunction())
|
||||
or
|
||||
exists(ThrowExpr tex | tex = this.(ControlFlowNode).getASuccessor())
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if there are no assignment expressions to the function argument. */
|
||||
pragma[inline]
|
||||
predicate checkChangeVariable(FunctionCall fc0, ControlFlowNode fc1, ControlFlowNode fc2) {
|
||||
not exists(Expr exptmp |
|
||||
(
|
||||
exptmp = fc0.getArgument(0).(VariableAccess).getTarget().getAnAssignedValue() or
|
||||
exptmp.(AddressOfExpr).getOperand() =
|
||||
fc0.getArgument(0).(VariableAccess).getTarget().getAnAccess()
|
||||
) and
|
||||
exptmp = fc1.getASuccessor*() and
|
||||
exptmp = fc2.getAPredecessor*()
|
||||
) and
|
||||
(
|
||||
(
|
||||
not fc0.getArgument(0) instanceof PointerFieldAccess and
|
||||
not fc0.getArgument(0) instanceof ValueFieldAccess
|
||||
or
|
||||
fc0.getArgument(0).(VariableAccess).getQualifier() instanceof ThisExpr
|
||||
)
|
||||
or
|
||||
not exists(Expr exptmp |
|
||||
(
|
||||
exptmp =
|
||||
fc0.getArgument(0)
|
||||
.(VariableAccess)
|
||||
.getQualifier()
|
||||
.(VariableAccess)
|
||||
.getTarget()
|
||||
.getAnAssignedValue() or
|
||||
exptmp.(AddressOfExpr).getOperand() =
|
||||
fc0.getArgument(0)
|
||||
.(VariableAccess)
|
||||
.getQualifier()
|
||||
.(VariableAccess)
|
||||
.getTarget()
|
||||
.getAnAccess()
|
||||
) and
|
||||
exptmp = fc1.getASuccessor*() and
|
||||
exptmp = fc2.getAPredecessor*()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if the underlying expression is a call to the close function. Provided that the function parameter does not change after the call. */
|
||||
predicate closeReturn(FunctionCall fc) {
|
||||
fcloseCall(fc, _) and
|
||||
checkChangeVariable(fc, fc, fc.getEnclosingFunction())
|
||||
}
|
||||
|
||||
/** Holds if the underlying expression is a call to the close function. Provided that the function parameter does not change before the call. */
|
||||
predicate closeWithoutChangeBefore(FunctionCall fc) {
|
||||
fcloseCall(fc, _) and
|
||||
checkChangeVariable(fc, fc.getEnclosingFunction().getEntryPoint(), fc)
|
||||
}
|
||||
|
||||
/** Holds, if a sequential call of the specified functions is possible, via a higher-level function call. */
|
||||
predicate callInOtherFunctions(FunctionCall fc, FunctionCall fc1) {
|
||||
exists(FunctionCall fec1, FunctionCall fec2 |
|
||||
fc.getEnclosingFunction() != fc1.getEnclosingFunction() and
|
||||
fec1 = fc.getEnclosingFunction().getACallToThisFunction() and
|
||||
fec2 = fc1.getEnclosingFunction().getACallToThisFunction() and
|
||||
fec1.getASuccessor*() = fec2 and
|
||||
checkChangeVariable(fc, fec1, fec2)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if successive calls to close functions are possible. */
|
||||
predicate interDoubleCloseFunctions(FunctionCall fc, FunctionCall fc1) {
|
||||
fcloseCall(fc, _) and
|
||||
fcloseCall(fc1, _) and
|
||||
fc != fc1 and
|
||||
fc.getASuccessor*() = fc1 and
|
||||
checkChangeVariable(fc, fc, fc1)
|
||||
}
|
||||
|
||||
/** Holds if the first arguments of the two functions are similar. */
|
||||
predicate similarArguments(FunctionCall fc, FunctionCall fc1) {
|
||||
globalValueNumber(fc.getArgument(0)) = globalValueNumber(fc1.getArgument(0))
|
||||
or
|
||||
fc.getArgument(0).(VariableAccess).getTarget() = fc1.getArgument(0).(VariableAccess).getTarget() and
|
||||
(
|
||||
not fc.getArgument(0) instanceof PointerFieldAccess and
|
||||
not fc.getArgument(0) instanceof ValueFieldAccess
|
||||
or
|
||||
fc.getArgument(0).(VariableAccess).getQualifier() instanceof ThisExpr
|
||||
)
|
||||
or
|
||||
fc.getArgument(0).(VariableAccess).getTarget() = fc1.getArgument(0).(VariableAccess).getTarget() and
|
||||
(
|
||||
fc.getArgument(0) instanceof PointerFieldAccess or
|
||||
fc.getArgument(0) instanceof ValueFieldAccess
|
||||
) and
|
||||
hashCons(fc.getArgument(0)) = hashCons(fc1.getArgument(0))
|
||||
}
|
||||
|
||||
from FunctionCall fc, FunctionCall fc1
|
||||
where
|
||||
not exists(CallMayNotReturn fctmp | fctmp = fc.getASuccessor*()) and
|
||||
not exists(IfStmt ifs | ifs.getCondition().getAChild*() = fc) and
|
||||
(
|
||||
// detecting a repeated call situation within one function
|
||||
closeReturn(fc) and
|
||||
closeWithoutChangeBefore(fc1) and
|
||||
callInOtherFunctions(fc, fc1)
|
||||
or
|
||||
// detection of repeated call in different functions
|
||||
interDoubleCloseFunctions(fc, fc1)
|
||||
) and
|
||||
similarArguments(fc, fc1)
|
||||
select fc, "Second call to the $@ function is possible.", fc1, fc1.getTarget().getName()
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @name unsigned to signed used in pointer arithmetic
|
||||
* @description finds unsigned to signed conversions used in pointer arithmetic, potentially causing an out-of-bound access
|
||||
* @id cpp/sign-conversion-pointer-arithmetic
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @tags reliability
|
||||
* security
|
||||
* external/cwe/cwe-787
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.DataFlow
|
||||
import semmle.code.cpp.security.Overflow
|
||||
|
||||
from FunctionCall call, Function f, Parameter p, DataFlow::Node sink, PointerArithmeticOperation pao
|
||||
where
|
||||
f = call.getTarget() and
|
||||
p = f.getAParameter() and
|
||||
p.getUnspecifiedType().(IntegralType).isSigned() and
|
||||
call.getArgument(p.getIndex()).getUnspecifiedType().(IntegralType).isUnsigned() and
|
||||
pao.getAnOperand() = sink.asExpr() and
|
||||
not exists(Operation a | guardedLesser(a, sink.asExpr())) and
|
||||
not exists(Operation b | guardedGreater(b, call.getArgument(p.getIndex()))) and
|
||||
not call.getArgument(p.getIndex()).isConstant() and
|
||||
DataFlow::localFlow(DataFlow::parameterNode(p), sink) and
|
||||
p.getUnspecifiedType().getSize() < 8
|
||||
select call,
|
||||
"This call: $@ passes an unsigned int to a function that requires a signed int: $@. And then used in pointer arithmetic: $@",
|
||||
call, call.toString(), f, f.toString(), sink, sink.toString()
|
||||
@@ -63,6 +63,7 @@ where
|
||||
functionsMissingReturnStmt(f, blame) and
|
||||
reachable(blame) and
|
||||
not functionImperfectlyExtracted(f) and
|
||||
not f.isFromUninstantiatedTemplate(_) and
|
||||
(blame = stmt or blame.(Expr).getEnclosingStmt() = stmt) and
|
||||
msg =
|
||||
"Function " + f.getName() + " should return a value of type " + f.getType().getName() +
|
||||
|
||||
@@ -599,6 +599,10 @@
|
||||
| test.c:675:7:675:7 | y | -2147483648 |
|
||||
| test.c:684:7:684:7 | x | -2147483648 |
|
||||
| test.c:689:7:689:7 | x | -2147483648 |
|
||||
| test.c:696:8:696:8 | x | 2147483647 |
|
||||
| test.c:696:12:696:12 | y | 256 |
|
||||
| test.c:697:9:697:9 | x | 2147483647 |
|
||||
| test.c:698:9:698:9 | y | 256 |
|
||||
| test.cpp:10:7:10:7 | b | -2147483648 |
|
||||
| test.cpp:11:5:11:5 | x | -2147483648 |
|
||||
| test.cpp:13:10:13:10 | x | -2147483648 |
|
||||
|
||||
@@ -689,3 +689,12 @@ label:
|
||||
out(x);
|
||||
goto label;
|
||||
}
|
||||
|
||||
void test_overflow() {
|
||||
const int x = 2147483647; // 2^31-1
|
||||
const int y = 256;
|
||||
if ((x + y) <= 512) {
|
||||
out(x);
|
||||
out(y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -599,6 +599,10 @@
|
||||
| test.c:675:7:675:7 | y | 2147483647 |
|
||||
| test.c:684:7:684:7 | x | 2147483647 |
|
||||
| test.c:689:7:689:7 | x | 15 |
|
||||
| test.c:696:8:696:8 | x | 2147483647 |
|
||||
| test.c:696:12:696:12 | y | 256 |
|
||||
| test.c:697:9:697:9 | x | 2147483647 |
|
||||
| test.c:698:9:698:9 | y | 256 |
|
||||
| test.cpp:10:7:10:7 | b | 2147483647 |
|
||||
| test.cpp:11:5:11:5 | x | 2147483647 |
|
||||
| test.cpp:13:10:13:10 | x | 2147483647 |
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
| test.c:15:9:15:13 | access to array | Potential buffer-overflow: 'xs' has size 5 but 'xs[6]' is accessed here. |
|
||||
| test.c:20:9:20:18 | access to array | Potential buffer-overflow: 'ys' has size 5 but 'ys[5]' is accessed here. |
|
||||
| test.c:21:9:21:18 | access to array | Potential buffer-overflow: 'ys' has size 5 but 'ys[6]' is accessed here. |
|
||||
| test.c:47:3:47:18 | access to array | Potential buffer-overflow: 'ptr' has size 8 but 'ptr[8]' is accessed here. |
|
||||
| test.c:54:3:54:26 | access to array | Potential buffer-overflow: 'ptr' has size 8 but 'ptr[8]' is accessed here. |
|
||||
| test.c:61:3:61:18 | access to array | Potential buffer-overflow: 'ptr' has size 8 but 'ptr[8]' is accessed here. |
|
||||
| test.c:72:3:72:11 | access to array | Potential buffer-overflow: 'buf' has size 1 but 'buf[1]' is accessed here. |
|
||||
| test.cpp:19:3:19:12 | access to array | Potential buffer-overflow: counter 'i' <= 3 but 'buffer1' has 3 elements. |
|
||||
| test.cpp:20:3:20:12 | access to array | Potential buffer-overflow: counter 'i' <= 3 but 'buffer2' has 3 elements. |
|
||||
| test.cpp:24:27:24:27 | 4 | Potential buffer-overflow: 'buffer1' has size 3 not 4. |
|
||||
|
||||
@@ -27,3 +27,47 @@ void f(void) {
|
||||
c = stru.zs[6]; // GOOD (zs is variable size)
|
||||
}
|
||||
|
||||
void* malloc(long unsigned int);
|
||||
void test_buffer_sentinal() {
|
||||
struct { char len; char buf[1]; } *b = malloc(10); // len(buf.buffer) effectively 8
|
||||
b->buf[0] = 0; // GOOD
|
||||
b->buf[7] = 0; // GOOD
|
||||
b->buf[8] = 0; // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
union u {
|
||||
unsigned long value;
|
||||
char ptr[1];
|
||||
};
|
||||
|
||||
void union_test() {
|
||||
union u u;
|
||||
u.ptr[0] = 0; // GOOD
|
||||
u.ptr[sizeof(u)-1] = 0; // GOOD
|
||||
u.ptr[sizeof(u)] = 0; // BAD
|
||||
}
|
||||
|
||||
void test_struct_union() {
|
||||
struct { union u u; } v;
|
||||
v.u.ptr[0] = 0; // GOOD
|
||||
v.u.ptr[sizeof(union u)-1] = 0; // GOOD
|
||||
v.u.ptr[sizeof(union u)] = 0; // BAD
|
||||
}
|
||||
|
||||
void union_test2() {
|
||||
union { char ptr[1]; unsigned long value; } u;
|
||||
u.ptr[0] = 0; // GOOD
|
||||
u.ptr[sizeof(u)-1] = 0; // GOOD
|
||||
u.ptr[sizeof(u)] = 0; // BAD
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char len;
|
||||
char buf[1];
|
||||
} var_buf;
|
||||
|
||||
void test_alloc() {
|
||||
// Special case of taking sizeof without any addition or multiplications
|
||||
var_buf *b = malloc(sizeof(var_buf));
|
||||
b->buf[1] = 0; // BAD
|
||||
}
|
||||
|
||||
@@ -23,3 +23,5 @@
|
||||
| test.cpp:365:19:365:25 | buffer2 | Variable $@ may not be null terminated. | test.cpp:363:8:363:14 | buffer2 | buffer2 |
|
||||
| test.cpp:392:17:392:22 | buffer | Variable $@ may not be null terminated. | test.cpp:390:8:390:13 | buffer | buffer |
|
||||
| test.cpp:398:18:398:23 | buffer | Variable $@ may not be null terminated. | test.cpp:396:8:396:13 | buffer | buffer |
|
||||
| test.cpp:444:10:444:15 | buffer | Variable $@ may not be null terminated. | test.cpp:442:8:442:13 | buffer | buffer |
|
||||
| test.cpp:450:16:450:21 | buffer | Variable $@ may not be null terminated. | test.cpp:448:8:448:13 | buffer | buffer |
|
||||
|
||||
@@ -433,3 +433,36 @@ void test_read_fread(int read_src, FILE *s)
|
||||
strlen(buffer); // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
int printf(const char *format, ...);
|
||||
|
||||
void test_printf(char *str)
|
||||
{
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
printf(buffer, ""); // BAD
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
printf("%s", buffer); // BAD
|
||||
}
|
||||
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
char *copied_str = (char *)malloc(len);
|
||||
|
||||
memcpy(copied_str, str, len);
|
||||
printf("%s", copied_str); // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
char *copied_str = (char *)malloc(len + 1);
|
||||
|
||||
memcpy(copied_str, str, len + 1);
|
||||
printf("%s", copied_str); // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* This test case is closely based on CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp
|
||||
* from the SAMATE Juliet test suite.
|
||||
*/
|
||||
|
||||
#define NULL (0)
|
||||
|
||||
typedef unsigned long size_t;
|
||||
typedef size_t time_t;
|
||||
time_t time(time_t *timer);
|
||||
|
||||
typedef struct {} FILE;
|
||||
extern FILE *stdin;
|
||||
FILE *fopen(const char *filename, const char *mode);
|
||||
int fclose(FILE *stream);
|
||||
#define FILENAME_MAX (4096)
|
||||
|
||||
typedef unsigned long size_t;
|
||||
size_t strlen(const char *s);
|
||||
char *strcat(char *s1, const char *s2);
|
||||
char *fgets(char *s, int n, FILE *stream);
|
||||
|
||||
int globalReturnsTrue()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int globalReturnsFalse()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void printLine(const char *str);
|
||||
|
||||
#define BASEPATH "c:\\temp\\"
|
||||
#define FOPEN fopen
|
||||
|
||||
namespace CWE23_Relative_Path_Traversal__char_console_fopen_11
|
||||
{
|
||||
|
||||
void bad()
|
||||
{
|
||||
char * data;
|
||||
char dataBuffer[FILENAME_MAX] = BASEPATH;
|
||||
data = dataBuffer;
|
||||
if(globalReturnsTrue())
|
||||
{
|
||||
{
|
||||
/* Read input from the console */
|
||||
size_t dataLen = strlen(data);
|
||||
/* if there is room in data, read into it from the console */
|
||||
if (FILENAME_MAX-dataLen > 1)
|
||||
{
|
||||
/* POTENTIAL FLAW: Read data from the console */
|
||||
if (fgets(data+dataLen, (int)(FILENAME_MAX-dataLen), stdin) != NULL)
|
||||
{
|
||||
/* The next few lines remove the carriage return from the string that is
|
||||
* inserted by fgets() */
|
||||
dataLen = strlen(data);
|
||||
if (dataLen > 0 && data[dataLen-1] == '\n')
|
||||
{
|
||||
data[dataLen-1] = '\0';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printLine("fgets() failed");
|
||||
/* Restore NUL terminator if fgets fails */
|
||||
data[dataLen] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
FILE *pFile = NULL;
|
||||
/* POTENTIAL FLAW: Possibly opening a file without validating the file name or path */
|
||||
pFile = FOPEN(data, "wb+");
|
||||
if (pFile != NULL)
|
||||
{
|
||||
fclose(pFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* goodG2B1() - use goodsource and badsink by changing the globalReturnsTrue() to globalReturnsFalse() */
|
||||
static void goodG2B1()
|
||||
{
|
||||
char * data;
|
||||
char dataBuffer[FILENAME_MAX] = BASEPATH;
|
||||
data = dataBuffer;
|
||||
if(globalReturnsFalse())
|
||||
{
|
||||
/* INCIDENTAL: CWE 561 Dead Code, the code below will never run */
|
||||
printLine("Benign, fixed string");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIX: Use a fixed file name */
|
||||
strcat(data, "file.txt");
|
||||
}
|
||||
{
|
||||
FILE *pFile = NULL;
|
||||
/* POTENTIAL FLAW: Possibly opening a file without validating the file name or path */
|
||||
pFile = FOPEN(data, "wb+");
|
||||
if (pFile != NULL)
|
||||
{
|
||||
fclose(pFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* goodG2B2() - use goodsource and badsink by reversing the blocks in the if statement */
|
||||
static void goodG2B2()
|
||||
{
|
||||
char * data;
|
||||
char dataBuffer[FILENAME_MAX] = BASEPATH;
|
||||
data = dataBuffer;
|
||||
if(globalReturnsTrue())
|
||||
{
|
||||
/* FIX: Use a fixed file name */
|
||||
strcat(data, "file.txt");
|
||||
}
|
||||
{
|
||||
FILE *pFile = NULL;
|
||||
/* POTENTIAL FLAW: Possibly opening a file without validating the file name or path */
|
||||
pFile = FOPEN(data, "wb+");
|
||||
if (pFile != NULL)
|
||||
{
|
||||
fclose(pFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
edges
|
||||
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | (const char *)... |
|
||||
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data |
|
||||
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection |
|
||||
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | fgets output argument | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | (const char *)... |
|
||||
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | fgets output argument | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data |
|
||||
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | fgets output argument | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection |
|
||||
subpaths
|
||||
nodes
|
||||
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | semmle.label | ... + ... |
|
||||
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | fgets output argument | semmle.label | fgets output argument |
|
||||
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | (const char *)... | semmle.label | (const char *)... |
|
||||
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | (const char *)... | semmle.label | (const char *)... |
|
||||
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | semmle.label | data |
|
||||
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection | semmle.label | data indirection |
|
||||
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection | semmle.label | data indirection |
|
||||
#select
|
||||
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | This argument to a file access function is derived from $@ and then passed to fopen(filename) | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | user input (fgets) |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-022/TaintedPath.ql
|
||||
@@ -5,6 +5,7 @@ edges
|
||||
| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName |
|
||||
| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName indirection |
|
||||
| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName indirection |
|
||||
subpaths
|
||||
nodes
|
||||
| test.c:9:23:9:26 | argv | semmle.label | argv |
|
||||
| test.c:9:23:9:26 | argv | semmle.label | argv |
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
| tests.cpp:53:16:53:19 | data | This argument to an OS command is derived from $@ and then passed to system(string) | tests.cpp:33:34:33:39 | call to getenv | user input (getenv) |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-078/ExecTainted.ql
|
||||
@@ -0,0 +1,58 @@
|
||||
//semmle-extractor-options: --edg --target --edg win64
|
||||
|
||||
// A selection of tests from the SAMATE Juliet framework for rule CWE-78.
|
||||
|
||||
// library types, functions etc
|
||||
#define NULL (0)
|
||||
typedef unsigned long size_t;
|
||||
size_t strlen(const char *s);
|
||||
char *strncat(char *s1, const char *s2, size_t n);
|
||||
char *getenv(const char *name);
|
||||
int system(const char *string);
|
||||
void exit(int status);
|
||||
|
||||
#define FULL_COMMAND "dir "
|
||||
#define ENV_VARIABLE "ADD"
|
||||
#define GETENV getenv
|
||||
#define SYSTEM system
|
||||
|
||||
void printLine(const char *str);
|
||||
|
||||
// ----------
|
||||
|
||||
/* The static variable below is used to drive control flow in the source function */
|
||||
static int badStatic = 0;
|
||||
|
||||
static char * badSource(char * data)
|
||||
{
|
||||
if(badStatic)
|
||||
{
|
||||
{
|
||||
/* Append input from an environment variable to data */
|
||||
size_t dataLen = strlen(data);
|
||||
char * environment = GETENV(ENV_VARIABLE);
|
||||
/* If there is data in the environment variable */
|
||||
if (environment != NULL)
|
||||
{
|
||||
/* POTENTIAL FLAW: Read data from an environment variable */
|
||||
strncat(data+dataLen, environment, 100-dataLen-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void CWE78_OS_Command_Injection__char_environment_system_21_bad()
|
||||
{
|
||||
char * data;
|
||||
char data_buf[100] = FULL_COMMAND;
|
||||
data = data_buf;
|
||||
badStatic = 1; /* true */
|
||||
data = badSource(data);
|
||||
/* POTENTIAL FLAW: Execute command in data possibly leading to command injection [NOT DETECTED] */
|
||||
if (SYSTEM(data) != 0)
|
||||
{
|
||||
printLine("command execution failed!");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ edges
|
||||
| search.c:55:17:55:25 | raw_query indirection | search.c:14:24:14:28 | *query |
|
||||
| search.c:57:5:57:15 | raw_query | search.c:22:24:22:28 | query |
|
||||
| search.c:57:17:57:25 | raw_query indirection | search.c:22:24:22:28 | *query |
|
||||
subpaths
|
||||
nodes
|
||||
| search.c:14:24:14:28 | *query | semmle.label | *query |
|
||||
| search.c:14:24:14:28 | query | semmle.label | query |
|
||||
|
||||
@@ -5,6 +5,15 @@ edges
|
||||
| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 |
|
||||
| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 indirection |
|
||||
| test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 indirection |
|
||||
| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | (const char *)... |
|
||||
| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | (const char *)... |
|
||||
| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | access to array |
|
||||
| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | access to array |
|
||||
| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | access to array |
|
||||
| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | access to array |
|
||||
| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | access to array indirection |
|
||||
| test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | access to array indirection |
|
||||
subpaths
|
||||
nodes
|
||||
| test.c:15:20:15:23 | argv | semmle.label | argv |
|
||||
| test.c:15:20:15:23 | argv | semmle.label | argv |
|
||||
@@ -13,5 +22,15 @@ nodes
|
||||
| test.c:21:18:21:23 | query1 | semmle.label | query1 |
|
||||
| test.c:21:18:21:23 | query1 indirection | semmle.label | query1 indirection |
|
||||
| test.c:21:18:21:23 | query1 indirection | semmle.label | query1 indirection |
|
||||
| test.cpp:43:27:43:30 | argv | semmle.label | argv |
|
||||
| test.cpp:43:27:43:30 | argv | semmle.label | argv |
|
||||
| test.cpp:43:27:43:33 | (const char *)... | semmle.label | (const char *)... |
|
||||
| test.cpp:43:27:43:33 | (const char *)... | semmle.label | (const char *)... |
|
||||
| test.cpp:43:27:43:33 | access to array | semmle.label | access to array |
|
||||
| test.cpp:43:27:43:33 | access to array | semmle.label | access to array |
|
||||
| test.cpp:43:27:43:33 | access to array | semmle.label | access to array |
|
||||
| test.cpp:43:27:43:33 | access to array indirection | semmle.label | access to array indirection |
|
||||
| test.cpp:43:27:43:33 | access to array indirection | semmle.label | access to array indirection |
|
||||
#select
|
||||
| test.c:21:18:21:23 | query1 | test.c:15:20:15:23 | argv | test.c:21:18:21:23 | query1 | This argument to a SQL query function is derived from $@ and then passed to mysql_query(sqlArg) | test.c:15:20:15:23 | argv | user input (argv) |
|
||||
| test.cpp:43:27:43:33 | access to array | test.cpp:43:27:43:30 | argv | test.cpp:43:27:43:33 | access to array | This argument to a SQL query function is derived from $@ and then passed to pqxx::work::exec1((unnamed parameter 0)) | test.cpp:43:27:43:30 | argv | user input (argv) |
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
int sprintf(char* str, const char* format, ...);
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<class charT> struct char_traits;
|
||||
|
||||
template <class T> class allocator {
|
||||
public:
|
||||
allocator() throw();
|
||||
};
|
||||
|
||||
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> >
|
||||
class basic_string {
|
||||
public:
|
||||
explicit basic_string(const Allocator& a = Allocator());
|
||||
basic_string(const charT* s, const Allocator& a = Allocator());
|
||||
|
||||
const charT* c_str() const;
|
||||
};
|
||||
|
||||
typedef basic_string<char> string;
|
||||
}
|
||||
|
||||
namespace pqxx {
|
||||
struct connection {};
|
||||
|
||||
struct row {};
|
||||
struct result {};
|
||||
|
||||
struct work {
|
||||
work(connection&);
|
||||
|
||||
row exec1(const char*);
|
||||
result exec(const std::string&);
|
||||
std::string quote(const char*);
|
||||
};
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
pqxx::connection c;
|
||||
pqxx::work w(c);
|
||||
|
||||
pqxx::row r = w.exec1(argv[1]); // BAD
|
||||
|
||||
pqxx::result r2 = w.exec(w.quote(argv[1])); // GOOD
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
edges
|
||||
| test.cpp:37:73:37:76 | *data | test.cpp:43:32:43:35 | (LPCSTR)... |
|
||||
| test.cpp:37:73:37:76 | *data | test.cpp:43:32:43:35 | data |
|
||||
| test.cpp:37:73:37:76 | *data | test.cpp:43:32:43:35 | data indirection |
|
||||
| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | (LPCSTR)... |
|
||||
| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | data |
|
||||
| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | data |
|
||||
| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | data indirection |
|
||||
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:17:73:22 | data |
|
||||
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:17:73:22 | data |
|
||||
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data indirection |
|
||||
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data indirection |
|
||||
| test.cpp:73:17:73:22 | data | test.cpp:37:73:37:76 | data |
|
||||
| test.cpp:73:24:73:27 | data indirection | test.cpp:37:73:37:76 | *data |
|
||||
subpaths
|
||||
nodes
|
||||
| test.cpp:37:73:37:76 | *data | semmle.label | *data |
|
||||
| test.cpp:37:73:37:76 | data | semmle.label | data |
|
||||
| test.cpp:43:32:43:35 | (LPCSTR)... | semmle.label | (LPCSTR)... |
|
||||
| test.cpp:43:32:43:35 | (LPCSTR)... | semmle.label | (LPCSTR)... |
|
||||
| test.cpp:43:32:43:35 | data | semmle.label | data |
|
||||
| test.cpp:43:32:43:35 | data | semmle.label | data |
|
||||
| test.cpp:43:32:43:35 | data | semmle.label | data |
|
||||
| test.cpp:43:32:43:35 | data indirection | semmle.label | data indirection |
|
||||
| test.cpp:43:32:43:35 | data indirection | semmle.label | data indirection |
|
||||
| test.cpp:64:30:64:35 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:64:30:64:35 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:73:17:73:22 | data | semmle.label | data |
|
||||
| test.cpp:73:24:73:27 | data indirection | semmle.label | data indirection |
|
||||
#select
|
||||
| test.cpp:43:32:43:35 | data | test.cpp:64:30:64:35 | call to getenv | test.cpp:43:32:43:35 | data | The value of this argument may come from $@ and is being passed to LoadLibraryA | test.cpp:64:30:64:35 | call to getenv | call to getenv |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-114/UncontrolledProcessOperation.ql
|
||||
@@ -0,0 +1,132 @@
|
||||
// Some SAMATE Juliet test cases for CWE-114.
|
||||
|
||||
typedef unsigned long size_t;
|
||||
typedef unsigned int BOOL;
|
||||
typedef const char *LPCSTR;
|
||||
typedef void *HMODULE;
|
||||
#define NULL (0)
|
||||
|
||||
size_t strlen(const char *s);
|
||||
char *strncat(char *s1, const char *s2, size_t n);
|
||||
|
||||
HMODULE LoadLibraryA(LPCSTR libname);
|
||||
BOOL FreeLibrary(HMODULE hModule);
|
||||
|
||||
char *getenv(const char *name);
|
||||
|
||||
#define GETENV getenv
|
||||
#define ENV_VARIABLE "ADD"
|
||||
|
||||
void printLine(const char *msg);
|
||||
|
||||
// --- CWE114_Process_Control__w32_char_environment_82 ---
|
||||
|
||||
class CWE114_Process_Control__w32_char_environment_82_base
|
||||
{
|
||||
public:
|
||||
/* pure virtual function */
|
||||
virtual void action(char * data) = 0;
|
||||
};
|
||||
|
||||
class CWE114_Process_Control__w32_char_environment_82_bad : public CWE114_Process_Control__w32_char_environment_82_base
|
||||
{
|
||||
public:
|
||||
void action(char * data);
|
||||
};
|
||||
|
||||
void CWE114_Process_Control__w32_char_environment_82_bad::action(char * data)
|
||||
{
|
||||
{
|
||||
HMODULE hModule;
|
||||
/* POTENTIAL FLAW: If the path to the library is not specified, an attacker may be able to
|
||||
* replace his own file with the intended library */
|
||||
hModule = LoadLibraryA(data);
|
||||
if (hModule != NULL)
|
||||
{
|
||||
FreeLibrary(hModule);
|
||||
printLine("Library loaded and freed successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
printLine("Unable to load library");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bad()
|
||||
{
|
||||
char * data;
|
||||
char dataBuffer[100] = "";
|
||||
data = dataBuffer;
|
||||
{
|
||||
/* Append input from an environment variable to data */
|
||||
size_t dataLen = strlen(data);
|
||||
char * environment = GETENV(ENV_VARIABLE);
|
||||
/* If there is data in the environment variable */
|
||||
if (environment != NULL)
|
||||
{
|
||||
/* POTENTIAL FLAW: Read data from an environment variable */
|
||||
strncat(data+dataLen, environment, 100-dataLen-1);
|
||||
}
|
||||
}
|
||||
CWE114_Process_Control__w32_char_environment_82_base* baseObject = new CWE114_Process_Control__w32_char_environment_82_bad;
|
||||
baseObject->action(data);
|
||||
delete baseObject;
|
||||
}
|
||||
|
||||
// --- CWE114_Process_Control__w32_char_console_33 ---
|
||||
|
||||
typedef struct {} FILE;
|
||||
char *fgets(char *s, int n, FILE *stream);
|
||||
FILE *stdin;
|
||||
|
||||
void CWE114_Process_Control__w32_char_console_33_bad()
|
||||
{
|
||||
char * data;
|
||||
char * &dataRef = data;
|
||||
char dataBuffer[100] = "";
|
||||
data = dataBuffer;
|
||||
{
|
||||
/* Read input from the console */
|
||||
size_t dataLen = strlen(data);
|
||||
/* if there is room in data, read into it from the console */
|
||||
if (100-dataLen > 1)
|
||||
{
|
||||
/* POTENTIAL FLAW: Read data from the console [NOT DETECTED] */
|
||||
if (fgets(data+dataLen, (int)(100-dataLen), stdin) != NULL)
|
||||
{
|
||||
/* The next few lines remove the carriage return from the string that is
|
||||
* inserted by fgets() */
|
||||
dataLen = strlen(data);
|
||||
if (dataLen > 0 && data[dataLen-1] == '\n')
|
||||
{
|
||||
data[dataLen-1] = '\0';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printLine("fgets() failed");
|
||||
/* Restore NUL terminator if fgets fails */
|
||||
data[dataLen] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
char * data = dataRef;
|
||||
{
|
||||
HMODULE hModule;
|
||||
/* POTENTIAL FLAW: If the path to the library is not specified, an attacker may be able to
|
||||
* replace his own file with the intended library */
|
||||
hModule = LoadLibraryA(data);
|
||||
if (hModule != NULL)
|
||||
{
|
||||
FreeLibrary(hModule);
|
||||
printLine("Library loaded and freed successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
printLine("Unable to load library");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,7 @@ edges
|
||||
| test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | (const char *)... |
|
||||
| test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | buffer |
|
||||
| test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | buffer indirection |
|
||||
subpaths
|
||||
nodes
|
||||
| test.cpp:24:30:24:36 | *command | semmle.label | *command |
|
||||
| test.cpp:24:30:24:36 | command | semmle.label | command |
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
| tests.cpp:350:13:350:19 | call to strncat | This 'call to strncat' operation is limited to 100 bytes but the destination is only 50 bytes. |
|
||||
| tests.cpp:452:9:452:15 | call to wcsncpy | This 'call to wcsncpy' operation is limited to 396 bytes but the destination is only 200 bytes. |
|
||||
| tests.cpp:481:9:481:16 | call to swprintf | This 'call to swprintf' operation is limited to 400 bytes but the destination is only 200 bytes. |
|
||||
| tests.cpp:630:13:630:20 | call to swprintf | This 'call to swprintf' operation is limited to 400 bytes but the destination is only 200 bytes. |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-120/BadlyBoundedWrite.ql
|
||||
@@ -0,0 +1 @@
|
||||
Best Practices/Likely Errors/OffsetUseBeforeRangeCheck.ql
|
||||
@@ -0,0 +1,19 @@
|
||||
| tests.cpp:45:9:45:14 | call to memcpy | This 'memcpy' operation accesses 32 bytes but the $@ is only 16 bytes. | tests.cpp:32:10:32:18 | charFirst | destination buffer |
|
||||
| tests.cpp:60:9:60:14 | call to memcpy | This 'memcpy' operation accesses 32 bytes but the $@ is only 16 bytes. | tests.cpp:32:10:32:18 | charFirst | destination buffer |
|
||||
| tests.cpp:171:9:171:14 | call to memcpy | This 'memcpy' operation accesses 100 bytes but the $@ is only 50 bytes. | tests.cpp:164:20:164:25 | call to malloc | destination buffer |
|
||||
| tests.cpp:172:9:172:19 | access to array | This array indexing operation accesses byte offset 99 but the $@ is only 50 bytes. | tests.cpp:164:20:164:25 | call to malloc | array |
|
||||
| tests.cpp:192:9:192:14 | call to memcpy | This 'memcpy' operation accesses 100 bytes but the $@ is only 50 bytes. | tests.cpp:181:10:181:22 | dataBadBuffer | destination buffer |
|
||||
| tests.cpp:192:9:192:14 | call to memcpy | This 'memcpy' operation accesses 100 bytes but the $@ is only 50 bytes. | tests.cpp:185:12:185:24 | dataBadBuffer | destination buffer |
|
||||
| tests.cpp:193:9:193:19 | access to array | This array indexing operation accesses byte offset 99 but the $@ is only 50 bytes. | tests.cpp:181:10:181:22 | dataBadBuffer | array |
|
||||
| tests.cpp:193:9:193:19 | access to array | This array indexing operation accesses byte offset 99 but the $@ is only 50 bytes. | tests.cpp:185:12:185:24 | dataBadBuffer | array |
|
||||
| tests.cpp:212:9:212:14 | call to memcpy | This 'memcpy' operation accesses 100 bytes but the $@ is only 50 bytes. | tests.cpp:201:36:201:41 | call to alloca | destination buffer |
|
||||
| tests.cpp:212:9:212:14 | call to memcpy | This 'memcpy' operation accesses 100 bytes but the $@ is only 50 bytes. | tests.cpp:205:12:205:24 | dataBadBuffer | destination buffer |
|
||||
| tests.cpp:213:9:213:19 | access to array | This array indexing operation accesses byte offset 99 but the $@ is only 50 bytes. | tests.cpp:201:36:201:41 | call to alloca | array |
|
||||
| tests.cpp:213:9:213:19 | access to array | This array indexing operation accesses byte offset 99 but the $@ is only 50 bytes. | tests.cpp:205:12:205:24 | dataBadBuffer | array |
|
||||
| tests.cpp:237:9:237:19 | access to array | This array indexing operation accesses byte offset 99 but the $@ is only 50 bytes. | tests.cpp:221:36:221:41 | call to alloca | array |
|
||||
| tests.cpp:237:9:237:19 | access to array | This array indexing operation accesses byte offset 99 but the $@ is only 50 bytes. | tests.cpp:225:12:225:24 | dataBadBuffer | array |
|
||||
| tests.cpp:261:9:261:19 | access to array | This array indexing operation accesses byte offset 99 but the $@ is only 50 bytes. | tests.cpp:245:10:245:22 | dataBadBuffer | array |
|
||||
| tests.cpp:261:9:261:19 | access to array | This array indexing operation accesses byte offset 99 but the $@ is only 50 bytes. | tests.cpp:249:12:249:24 | dataBadBuffer | array |
|
||||
| tests.cpp:384:9:384:14 | call to memcpy | This 'memcpy' operation accesses 40 bytes but the $@ is only 10 bytes. | tests.cpp:380:19:380:24 | call to alloca | destination buffer |
|
||||
| tests.cpp:434:9:434:19 | access to array | This array indexing operation accesses byte offset 399 but the $@ is only 200 bytes. | tests.cpp:422:12:422:26 | new[] | array |
|
||||
| tests.cpp:453:9:453:19 | access to array | This array indexing operation accesses byte offset 399 but the $@ is only 200 bytes. | tests.cpp:445:12:445:26 | new[] | array |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-119/OverflowBuffer.ql
|
||||
@@ -0,0 +1 @@
|
||||
Critical/OverflowDestination.ql
|
||||
@@ -0,0 +1,2 @@
|
||||
| tests.cpp:45:51:45:72 | sizeof(<expr>) | Potential buffer-overflow: 'charFirst' has size 16 not 32. |
|
||||
| tests.cpp:60:52:60:74 | sizeof(<expr>) | Potential buffer-overflow: 'charFirst' has size 16 not 32. |
|
||||
@@ -0,0 +1 @@
|
||||
Critical/OverflowStatic.ql
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-120/OverrunWrite.ql
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-120/OverrunWriteFloat.ql
|
||||
@@ -0,0 +1,3 @@
|
||||
| tests.cpp:290:13:290:19 | call to wcsncpy | Potentially unsafe call to wcsncpy; third argument should be size of destination. |
|
||||
| tests.cpp:306:4:306:10 | call to wcsncpy | Potentially unsafe call to wcsncpy; third argument should be size of destination. |
|
||||
| tests.cpp:452:9:452:15 | call to wcsncpy | Potentially unsafe call to wcsncpy; third argument should be size of destination. |
|
||||
@@ -0,0 +1 @@
|
||||
Likely Bugs/Memory Management/StrncpyFlippedArgs.ql
|
||||
@@ -0,0 +1,4 @@
|
||||
edges
|
||||
subpaths
|
||||
nodes
|
||||
#select
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-120/UnboundedWrite.ql
|
||||
671
cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/tests.cpp
Normal file
671
cpp/ql/test/query-tests/Security/CWE/CWE-119/SAMATE/tests.cpp
Normal file
@@ -0,0 +1,671 @@
|
||||
// A sample of tests from the SAMATE Juliet framework for rule CWE-119.
|
||||
|
||||
// library types, functions etc
|
||||
typedef unsigned long size_t;
|
||||
void *malloc(size_t size);
|
||||
void *alloca(size_t size);
|
||||
void free(void *ptr);
|
||||
#define ALLOCA alloca
|
||||
|
||||
void *memcpy(void *s1, const void *s2, size_t n);
|
||||
void *memset(void *s, int c, size_t n);
|
||||
char *strcpy(char *s1, const char *s2);
|
||||
size_t strlen(const char *s);
|
||||
|
||||
void exit(int status);
|
||||
|
||||
typedef unsigned int DWORD;
|
||||
DWORD GetCurrentDirectoryA(DWORD bufferLength, char *buffer);
|
||||
bool PathAppendA(char *path, const char *more);
|
||||
#define MAX_PATH 4096
|
||||
|
||||
void printLine(const char *str);
|
||||
void printSizeTLine(size_t val);
|
||||
void printIntLine(int val);
|
||||
|
||||
// ----------
|
||||
|
||||
#define SRC_STR "0123456789abcde0123"
|
||||
|
||||
typedef struct _charVoid
|
||||
{
|
||||
char charFirst[16];
|
||||
void * voidSecond;
|
||||
void * voidThird;
|
||||
} charVoid;
|
||||
|
||||
void CWE121_Stack_Based_Buffer_Overflow__char_type_overrun_memcpy_01_bad()
|
||||
{
|
||||
{
|
||||
charVoid structCharVoid;
|
||||
structCharVoid.voidSecond = (void *)SRC_STR;
|
||||
/* Print the initial block pointed to by structCharVoid.voidSecond */
|
||||
printLine((char *)structCharVoid.voidSecond);
|
||||
/* FLAW: Use the sizeof(structCharVoid) which will overwrite the pointer voidSecond */
|
||||
memcpy(structCharVoid.charFirst, SRC_STR, sizeof(structCharVoid));
|
||||
structCharVoid.charFirst[(sizeof(structCharVoid.charFirst)/sizeof(char))-1] = '\0'; /* null terminate the string */
|
||||
printLine((char *)structCharVoid.charFirst);
|
||||
printLine((char *)structCharVoid.voidSecond);
|
||||
}
|
||||
}
|
||||
|
||||
void CWE122_Heap_Based_Buffer_Overflow__char_type_overrun_memcpy_01_bad()
|
||||
{
|
||||
{
|
||||
charVoid * structCharVoid = (charVoid *)malloc(sizeof(charVoid));
|
||||
structCharVoid->voidSecond = (void *)SRC_STR;
|
||||
/* Print the initial block pointed to by structCharVoid->voidSecond */
|
||||
printLine((char *)structCharVoid->voidSecond);
|
||||
/* FLAW: Use the sizeof(*structCharVoid) which will overwrite the pointer y */
|
||||
memcpy(structCharVoid->charFirst, SRC_STR, sizeof(*structCharVoid));
|
||||
structCharVoid->charFirst[(sizeof(structCharVoid->charFirst)/sizeof(char))-1] = '\0'; /* null terminate the string */
|
||||
printLine((char *)structCharVoid->charFirst);
|
||||
printLine((char *)structCharVoid->voidSecond);
|
||||
free(structCharVoid);
|
||||
}
|
||||
}
|
||||
|
||||
void CWE124_Buffer_Underwrite__char_alloca_cpy_01_bad()
|
||||
{
|
||||
char * data;
|
||||
char * dataBuffer = (char *)ALLOCA(100*sizeof(char));
|
||||
memset(dataBuffer, 'A', 100-1);
|
||||
dataBuffer[100-1] = '\0';
|
||||
/* FLAW: Set data pointer to before the allocated memory buffer */
|
||||
data = dataBuffer - 8;
|
||||
{
|
||||
char source[100];
|
||||
memset(source, 'C', 100-1); /* fill with 'C's */
|
||||
source[100-1] = '\0'; /* null terminate */
|
||||
/* POTENTIAL FLAW: Possibly copying data to memory before the destination buffer */
|
||||
strcpy(data, source); // [NOT DETECTED]
|
||||
printLine(data);
|
||||
}
|
||||
}
|
||||
|
||||
void CWE126_Buffer_Overread__char_alloca_loop_01_bad()
|
||||
{
|
||||
char * data;
|
||||
char * dataBadBuffer = (char *)ALLOCA(50*sizeof(char));
|
||||
char * dataGoodBuffer = (char *)ALLOCA(100*sizeof(char));
|
||||
memset(dataBadBuffer, 'A', 50-1); /* fill with 'A's */
|
||||
dataBadBuffer[50-1] = '\0'; /* null terminate */
|
||||
memset(dataGoodBuffer, 'A', 100-1); /* fill with 'A's */
|
||||
dataGoodBuffer[100-1] = '\0'; /* null terminate */
|
||||
/* FLAW: Set data pointer to a small buffer */
|
||||
data = dataBadBuffer;
|
||||
{
|
||||
size_t i, destLen;
|
||||
char dest[100];
|
||||
memset(dest, 'C', 100-1);
|
||||
dest[100-1] = '\0'; /* null terminate */
|
||||
destLen = strlen(dest);
|
||||
/* POTENTIAL FLAW: using length of the dest where data
|
||||
* could be smaller than dest causing buffer overread */
|
||||
for (i = 0; i < destLen; i++)
|
||||
{
|
||||
dest[i] = data[i]; // [NOT DETECTED]
|
||||
}
|
||||
dest[100-1] = '\0';
|
||||
printLine(dest);
|
||||
}
|
||||
}
|
||||
|
||||
void CWE127_Buffer_Underread__char_alloca_cpy_01_bad()
|
||||
{
|
||||
char * data;
|
||||
char * dataBuffer = (char *)ALLOCA(100*sizeof(char));
|
||||
memset(dataBuffer, 'A', 100-1);
|
||||
dataBuffer[100-1] = '\0';
|
||||
/* FLAW: Set data pointer to before the allocated memory buffer */
|
||||
data = dataBuffer - 8;
|
||||
{
|
||||
char dest[100*2];
|
||||
memset(dest, 'C', 100*2-1); /* fill with 'C's */
|
||||
dest[100*2-1] = '\0'; /* null terminate */
|
||||
/* POTENTIAL FLAW: Possibly copy from a memory location located before the source buffer */
|
||||
strcpy(dest, data); // [NOT DETECTED]
|
||||
printLine(dest);
|
||||
}
|
||||
}
|
||||
|
||||
#define BAD_PATH_SIZE (MAX_PATH / 2) /* maintenance note: must be < MAX_PATH in order for 'bad' to be 'bad' */
|
||||
|
||||
void CWE785_Path_Manipulation_Function_Without_Max_Sized_Buffer__w32_01_bad()
|
||||
{
|
||||
{
|
||||
char path[BAD_PATH_SIZE];
|
||||
DWORD length;
|
||||
length = GetCurrentDirectoryA(BAD_PATH_SIZE, path);
|
||||
if (length == 0 || length >= BAD_PATH_SIZE) /* failure conditions for this API call */
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
/* FLAW: PathAppend assumes the 'path' parameter is MAX_PATH */
|
||||
/* INCIDENTAL: CWE 121 stack based buffer overflow, which is intrinsic to
|
||||
* this example identified on the CWE webpage */
|
||||
if (!PathAppendA(path, "AAAAAAAAAAAA")) // [NOT DETECTED]
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
printSizeTLine(strlen(path));
|
||||
printIntLine(BAD_PATH_SIZE);
|
||||
printLine(path);
|
||||
}
|
||||
}
|
||||
|
||||
#define NULL (0)
|
||||
|
||||
void CWE122_Heap_Based_Buffer_Overflow__c_CWE805_char_memcpy_01_bad()
|
||||
{
|
||||
char * data;
|
||||
data = NULL;
|
||||
/* FLAW: Allocate and point data to a small buffer that is smaller than the large buffer used in the sinks */
|
||||
data = (char *)malloc(50*sizeof(char));
|
||||
data[0] = '\0'; /* null terminate */
|
||||
{
|
||||
char source[100];
|
||||
memset(source, 'C', 100-1); /* fill with 'C's */
|
||||
source[100-1] = '\0'; /* null terminate */
|
||||
/* POTENTIAL FLAW: Possible buffer overflow if source is larger than data */
|
||||
memcpy(data, source, 100*sizeof(char));
|
||||
data[100-1] = '\0'; /* Ensure the destination buffer is null terminated */
|
||||
printLine(data);
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
||||
void CWE121_Stack_Based_Buffer_Overflow__CWE805_char_declare_memcpy_01_bad()
|
||||
{
|
||||
char * data;
|
||||
char dataBadBuffer[50];
|
||||
char dataGoodBuffer[100];
|
||||
/* FLAW: Set a pointer to a "small" buffer. This buffer will be used in the sinks as a destination
|
||||
* buffer in various memory copying functions using a "large" source buffer. */
|
||||
data = dataBadBuffer;
|
||||
data[0] = '\0'; /* null terminate */
|
||||
{
|
||||
char source[100];
|
||||
memset(source, 'C', 100-1); /* fill with 'C's */
|
||||
source[100-1] = '\0'; /* null terminate */
|
||||
/* POTENTIAL FLAW: Possible buffer overflow if the size of data is less than the length of source */
|
||||
memcpy(data, source, 100*sizeof(char));
|
||||
data[100-1] = '\0'; /* Ensure the destination buffer is null terminated */
|
||||
printLine(data);
|
||||
}
|
||||
}
|
||||
|
||||
void CWE121_Stack_Based_Buffer_Overflow__CWE805_char_alloca_memcpy_01_bad()
|
||||
{
|
||||
char * data;
|
||||
char * dataBadBuffer = (char *)ALLOCA(50*sizeof(char));
|
||||
char * dataGoodBuffer = (char *)ALLOCA(100*sizeof(char));
|
||||
/* FLAW: Set a pointer to a "small" buffer. This buffer will be used in the sinks as a destination
|
||||
* buffer in various memory copying functions using a "large" source buffer. */
|
||||
data = dataBadBuffer;
|
||||
data[0] = '\0'; /* null terminate */
|
||||
{
|
||||
char source[100];
|
||||
memset(source, 'C', 100-1); /* fill with 'C's */
|
||||
source[100-1] = '\0'; /* null terminate */
|
||||
/* POTENTIAL FLAW: Possible buffer overflow if the size of data is less than the length of source */
|
||||
memcpy(data, source, 100*sizeof(char));
|
||||
data[100-1] = '\0'; /* Ensure the destination buffer is null terminated */
|
||||
printLine(data);
|
||||
}
|
||||
}
|
||||
|
||||
void CWE121_Stack_Based_Buffer_Overflow__CWE805_char_alloca_loop_01_bad()
|
||||
{
|
||||
char * data;
|
||||
char * dataBadBuffer = (char *)ALLOCA(50*sizeof(char));
|
||||
char * dataGoodBuffer = (char *)ALLOCA(100*sizeof(char));
|
||||
/* FLAW: Set a pointer to a "small" buffer. This buffer will be used in the sinks as a destination
|
||||
* buffer in various memory copying functions using a "large" source buffer. */
|
||||
data = dataBadBuffer;
|
||||
data[0] = '\0'; /* null terminate */
|
||||
{
|
||||
size_t i;
|
||||
char source[100];
|
||||
memset(source, 'C', 100-1); /* fill with 'C's */
|
||||
source[100-1] = '\0'; /* null terminate */
|
||||
/* POTENTIAL FLAW: Possible buffer overflow if the size of data is less than the length of source */
|
||||
for (i = 0; i < 100; i++)
|
||||
{
|
||||
data[i] = source[i];
|
||||
}
|
||||
data[100-1] = '\0'; /* Ensure the destination buffer is null terminated */
|
||||
printLine(data);
|
||||
}
|
||||
}
|
||||
|
||||
void CWE121_Stack_Based_Buffer_Overflow__CWE805_char_declare_loop_01_bad()
|
||||
{
|
||||
char * data;
|
||||
char dataBadBuffer[50];
|
||||
char dataGoodBuffer[100];
|
||||
/* FLAW: Set a pointer to a "small" buffer. This buffer will be used in the sinks as a destination
|
||||
* buffer in various memory copying functions using a "large" source buffer. */
|
||||
data = dataBadBuffer;
|
||||
data[0] = '\0'; /* null terminate */
|
||||
{
|
||||
size_t i;
|
||||
char source[100];
|
||||
memset(source, 'C', 100-1); /* fill with 'C's */
|
||||
source[100-1] = '\0'; /* null terminate */
|
||||
/* POTENTIAL FLAW: Possible buffer overflow if the size of data is less than the length of source */
|
||||
for (i = 0; i < 100; i++)
|
||||
{
|
||||
data[i] = source[i];
|
||||
}
|
||||
data[100-1] = '\0'; /* Ensure the destination buffer is null terminated */
|
||||
printLine(data);
|
||||
}
|
||||
}
|
||||
|
||||
wchar_t *wcsncpy(wchar_t *destination, const wchar_t *source, size_t num);
|
||||
size_t wcslen(const wchar_t *str);
|
||||
char *strcat(char *destination, const char *source);
|
||||
char *strncat(char *destination, const char *source, size_t num);
|
||||
|
||||
void *memmove(void *destination, const void *source, size_t num);
|
||||
|
||||
void printWLine(const wchar_t *line);
|
||||
|
||||
/* MAINTENANCE NOTE: The length of this string should equal the 10 */
|
||||
#define SRC_STRING L"AAAAAAAAAA"
|
||||
|
||||
namespace CWE122_Heap_Based_Buffer_Overflow__cpp_CWE193_wchar_t_ncpy_01
|
||||
{
|
||||
void bad()
|
||||
{
|
||||
wchar_t * data;
|
||||
data = NULL;
|
||||
/* FLAW: Did not leave space for a null terminator */
|
||||
data = new wchar_t[10];
|
||||
{
|
||||
wchar_t source[10+1] = SRC_STRING;
|
||||
/* Copy length + 1 to include NUL terminator from source */
|
||||
/* POTENTIAL FLAW: data may not have enough space to hold source */
|
||||
wcsncpy(data, source, wcslen(source) + 1);
|
||||
printWLine(data);
|
||||
delete [] data;
|
||||
}
|
||||
}
|
||||
|
||||
static void goodG2B()
|
||||
{
|
||||
wchar_t * data;
|
||||
data = NULL;
|
||||
/* FIX: Allocate space for a null terminator */
|
||||
data = new wchar_t[10+1];
|
||||
{
|
||||
wchar_t source[10+1] = SRC_STRING;
|
||||
/* Copy length + 1 to include NUL terminator from source */
|
||||
/* POTENTIAL FLAW: data may not have enough space to hold source */
|
||||
wcsncpy(data, source, wcslen(source) + 1); // [FALSE POSITIVE RESULT] (debatable)
|
||||
printWLine(data);
|
||||
delete [] data;
|
||||
}
|
||||
}
|
||||
} /* close namespace */
|
||||
|
||||
namespace CWE122_Heap_Based_Buffer_Overflow__cpp_CWE193_wchar_t_memmove_31
|
||||
{
|
||||
void bad()
|
||||
{
|
||||
wchar_t * data;
|
||||
data = NULL;
|
||||
/* FLAW: Did not leave space for a null terminator */
|
||||
data = new wchar_t[10];
|
||||
{
|
||||
wchar_t * dataCopy = data;
|
||||
wchar_t * data = dataCopy;
|
||||
{
|
||||
wchar_t source[10+1] = SRC_STRING;
|
||||
/* Copy length + 1 to include NUL terminator from source */
|
||||
/* POTENTIAL FLAW: data may not have enough space to hold source */
|
||||
memmove(data, source, (wcslen(source) + 1) * sizeof(wchar_t)); // [NOT DETECTED]
|
||||
printWLine(data);
|
||||
delete [] data;
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* close namespace */
|
||||
|
||||
namespace CWE122_Heap_Based_Buffer_Overflow__cpp_CWE805_char_ncat_01
|
||||
{
|
||||
void bad()
|
||||
{
|
||||
char * data;
|
||||
data = NULL;
|
||||
/* FLAW: Allocate using new[] and point data to a small buffer that is smaller than the large buffer used in the sinks */
|
||||
data = new char[50];
|
||||
data[0] = '\0'; /* null terminate */
|
||||
{
|
||||
char source[100];
|
||||
memset(source, 'C', 100-1); /* fill with 'C's */
|
||||
source[100-1] = '\0'; /* null terminate */
|
||||
/* POTENTIAL FLAW: Possible buffer overflow if source is larger than sizeof(data)-strlen(data) */
|
||||
strncat(data, source, 100);
|
||||
printLine(data);
|
||||
delete [] data;
|
||||
}
|
||||
}
|
||||
} /* close namespace */
|
||||
|
||||
void CWE122_Heap_Based_Buffer_Overflow__c_dest_char_cat_01_bad()
|
||||
{
|
||||
char * data;
|
||||
data = NULL;
|
||||
/* FLAW: Allocate and point data to a small buffer that is smaller than the large buffer used in the sinks */
|
||||
data = (char *)malloc(50*sizeof(char));
|
||||
data[0] = '\0'; /* null terminate */
|
||||
{
|
||||
char source[100];
|
||||
memset(source, 'C', 100-1); /* fill with 'C's */
|
||||
source[100-1] = '\0'; /* null terminate */
|
||||
/* POTENTIAL FLAW: Possible buffer overflow if source is larger than sizeof(data)-strlen(data) */
|
||||
strcat(data, source); // [NOT DETECTED]
|
||||
printLine(data);
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
||||
void CWE121_Stack_Based_Buffer_Overflow__CWE131_memcpy_01_bad()
|
||||
{
|
||||
int * data;
|
||||
data = NULL;
|
||||
/* FLAW: Allocate memory without using sizeof(int) */
|
||||
data = (int *)ALLOCA(10);
|
||||
{
|
||||
int source[10] = {0};
|
||||
/* POTENTIAL FLAW: Possible buffer overflow if data was not allocated correctly in the source */
|
||||
memcpy(data, source, 10*sizeof(int));
|
||||
printIntLine(data[0]);
|
||||
}
|
||||
}
|
||||
|
||||
typedef long long int64_t;
|
||||
wchar_t *wmemset(wchar_t *dest, wchar_t c, size_t count);
|
||||
void* calloc(size_t num, size_t size);
|
||||
|
||||
void printLongLongLine(int64_t longLongIntNumber);
|
||||
void printDoubleLine(double doubleNumber);
|
||||
|
||||
void CWE122_Heap_Based_Buffer_Overflow__cpp_CWE805_int64_t_loop_01_bad()
|
||||
{
|
||||
int64_t * data;
|
||||
data = NULL;
|
||||
/* FLAW: Allocate using new[] and point data to a small buffer that is smaller than the large buffer used in the sinks */
|
||||
data = new int64_t[50];
|
||||
{
|
||||
int64_t source[100] = {0}; /* fill with 0's */
|
||||
{
|
||||
size_t i;
|
||||
/* POTENTIAL FLAW: Possible buffer overflow if data < 100 */
|
||||
for (i = 0; i < 100; i++)
|
||||
{
|
||||
data[i] = source[i]; // [NOT DETECTED]
|
||||
}
|
||||
printLongLongLine(data[0]);
|
||||
delete [] data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CWE122_Heap_Based_Buffer_Overflow__cpp_CWE805_wchar_t_loop_01_bad()
|
||||
{
|
||||
wchar_t * data;
|
||||
data = NULL;
|
||||
/* FLAW: Allocate using new[] and point data to a small buffer that is smaller than the large buffer used in the sinks */
|
||||
data = new wchar_t[50];
|
||||
data[0] = L'\0'; /* null terminate */
|
||||
{
|
||||
size_t i;
|
||||
wchar_t source[100];
|
||||
wmemset(source, L'C', 100-1); /* fill with L'C's */
|
||||
source[100-1] = L'\0'; /* null terminate */
|
||||
/* POTENTIAL FLAW: Possible buffer overflow if source is larger than data */
|
||||
for (i = 0; i < 100; i++)
|
||||
{
|
||||
data[i] = source[i];
|
||||
}
|
||||
data[100-1] = L'\0'; /* Ensure the destination buffer is null terminated */
|
||||
printWLine(data);
|
||||
delete [] data;
|
||||
}
|
||||
}
|
||||
|
||||
void CWE122_Heap_Based_Buffer_Overflow__cpp_CWE805_wchar_t_ncpy_01_bad()
|
||||
{
|
||||
wchar_t * data;
|
||||
data = NULL;
|
||||
/* FLAW: Allocate using new[] and point data to a small buffer that is smaller than the large buffer used in the sinks */
|
||||
data = new wchar_t[50];
|
||||
data[0] = L'\0'; /* null terminate */
|
||||
{
|
||||
wchar_t source[100];
|
||||
wmemset(source, L'C', 100-1); /* fill with L'C's */
|
||||
source[100-1] = L'\0'; /* null terminate */
|
||||
/* POTENTIAL FLAW: Possible buffer overflow if source is larger than data */
|
||||
wcsncpy(data, source, 100-1);
|
||||
data[100-1] = L'\0'; /* Ensure the destination buffer is null terminated */
|
||||
printWLine(data);
|
||||
delete [] data;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
int _snwprintf(wchar_t *buffer, size_t count, const wchar_t *format, ...);
|
||||
#define SNPRINTF _snwprintf
|
||||
#else
|
||||
int snprintf(char *s, size_t n, const char *format, ...);
|
||||
int swprintf(wchar_t *wcs, size_t maxlen, const wchar_t *format, ...);
|
||||
//#define SNPRINTF snprintf --- original code; using snprintf appears to be a mistake in samate?
|
||||
#define SNPRINTF swprintf
|
||||
#endif
|
||||
|
||||
void CWE122_Heap_Based_Buffer_Overflow__cpp_CWE805_wchar_t_snprintf_01_bad()
|
||||
{
|
||||
wchar_t * data;
|
||||
data = NULL;
|
||||
/* FLAW: Allocate using new[] and point data to a small buffer that is smaller than the large buffer used in the sinks */
|
||||
data = new wchar_t[50];
|
||||
data[0] = L'\0'; /* null terminate */
|
||||
{
|
||||
wchar_t source[100];
|
||||
wmemset(source, L'C', 100-1); /* fill with L'C's */
|
||||
source[100-1] = L'\0'; /* null terminate */
|
||||
/* POTENTIAL FLAW: Possible buffer overflow if source is larger than data */
|
||||
SNPRINTF(data, 100, L"%s", source);
|
||||
printWLine(data);
|
||||
delete [] data;
|
||||
}
|
||||
}
|
||||
|
||||
/* classes used in some test cases as a custom type */
|
||||
class TwoIntsClass
|
||||
{
|
||||
public: // Needed to access variables from label files
|
||||
int intOne;
|
||||
int intTwo;
|
||||
};
|
||||
|
||||
class OneIntClass
|
||||
{
|
||||
public: // Needed to access variables from label files
|
||||
int intOne;
|
||||
};
|
||||
|
||||
void *operator new(size_t size, void *ptr) throw(); // placement new (from #include <new>)
|
||||
|
||||
void CWE122_Heap_Based_Buffer_Overflow__placement_new_01_bad()
|
||||
{
|
||||
char * data;
|
||||
char * dataBadBuffer = (char *)malloc(sizeof(OneIntClass));
|
||||
char * dataGoodBuffer = (char *)malloc(sizeof(TwoIntsClass));
|
||||
/* POTENTIAL FLAW: Initialize data to a buffer small than the sizeof(TwoIntsClass) */
|
||||
data = dataBadBuffer;
|
||||
{
|
||||
/* The Visual C++ compiler generates a warning if you initialize the class with ().
|
||||
* This will cause the compile to default-initialize the object.
|
||||
* See http://msdn.microsoft.com/en-us/library/wewb47ee%28v=VS.100%29.aspx
|
||||
*/
|
||||
/* POTENTIAL FLAW: data may not be large enough to hold a TwoIntsClass */
|
||||
TwoIntsClass * classTwo = new(data) TwoIntsClass; // [NOT DETECTED]
|
||||
/* Initialize and make use of the class */
|
||||
classTwo->intOne = 5;
|
||||
classTwo->intTwo = 10; /* POTENTIAL FLAW: If sizeof(data) < sizeof(TwoIntsClass) then this line will be a buffer overflow */
|
||||
printIntLine(classTwo->intOne);
|
||||
/* skip printing classTwo->intTwo since that could be a buffer overread */
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
||||
void CWE122_Heap_Based_Buffer_Overflow__sizeof_double_01_bad()
|
||||
{
|
||||
double * data;
|
||||
/* Initialize data */
|
||||
data = NULL;
|
||||
/* INCIDENTAL: CWE-467 (Use of sizeof() on a pointer type) */
|
||||
/* FLAW: Using sizeof the pointer and not the data type in malloc() */
|
||||
data = (double *)malloc(sizeof(data)); // [NOT DETECTED]
|
||||
*data = 1.7E300;
|
||||
/* POTENTIAL FLAW: Attempt to use data, which may not have enough memory allocated */
|
||||
printDoubleLine(*data);
|
||||
free(data);
|
||||
}
|
||||
|
||||
int rand(void);
|
||||
#define RAND32() ((rand()<<30) ^ (rand()<<15) ^ rand())
|
||||
|
||||
void CWE122_Heap_Based_Buffer_Overflow__c_CWE129_rand_01_bad()
|
||||
{
|
||||
int data;
|
||||
/* Initialize data */
|
||||
data = -1;
|
||||
/* POTENTIAL FLAW: Set data to a random value */
|
||||
data = RAND32();
|
||||
{
|
||||
int i;
|
||||
int * buffer = (int *)malloc(10 * sizeof(int));
|
||||
/* initialize buffer */
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
buffer[i] = 0;
|
||||
}
|
||||
/* POTENTIAL FLAW: Attempt to write to an index of the array that is above the upper bound
|
||||
* This code does check to see if the array index is negative */
|
||||
if (data >= 0)
|
||||
{
|
||||
buffer[data] = 1; // [NOT DETECTED]
|
||||
/* Print the array values */
|
||||
for(i = 0; i < 10; i++)
|
||||
{
|
||||
printIntLine(buffer[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printLine("ERROR: Array index is negative.");
|
||||
}
|
||||
free(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct FILE;
|
||||
int fscanf(FILE *stream, const char *format, ...);
|
||||
FILE *stdin;
|
||||
|
||||
void CWE122_Heap_Based_Buffer_Overflow__c_CWE129_fscanf_01_bad()
|
||||
{
|
||||
int data;
|
||||
/* Initialize data */
|
||||
data = -1;
|
||||
/* POTENTIAL FLAW: Read data from the console using fscanf() */
|
||||
fscanf(stdin, "%d", &data);
|
||||
{
|
||||
int i;
|
||||
int * buffer = (int *)malloc(10 * sizeof(int));
|
||||
/* initialize buffer */
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
buffer[i] = 0;
|
||||
}
|
||||
/* POTENTIAL FLAW: Attempt to write to an index of the array that is above the upper bound
|
||||
* This code does check to see if the array index is negative */
|
||||
if (data >= 0)
|
||||
{
|
||||
buffer[data] = 1; // [NOT DETECTED]
|
||||
/* Print the array values */
|
||||
for(i = 0; i < 10; i++)
|
||||
{
|
||||
printIntLine(buffer[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printLine("ERROR: Array index is negative.");
|
||||
}
|
||||
free(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void CWE122_Heap_Based_Buffer_Overflow__cpp_CWE805_wchar_t_snprintf_31_bad()
|
||||
{
|
||||
wchar_t * data;
|
||||
data = NULL;
|
||||
/* FLAW: Allocate using new[] and point data to a small buffer that is smaller than the large buffer used in the sinks */
|
||||
data = new wchar_t[50];
|
||||
data[0] = L'\0'; /* null terminate */
|
||||
{
|
||||
wchar_t * dataCopy = data;
|
||||
wchar_t * data = dataCopy;
|
||||
{
|
||||
wchar_t source[100];
|
||||
wmemset(source, L'C', 100-1); /* fill with L'C's */
|
||||
source[100-1] = L'\0'; /* null terminate */
|
||||
/* POTENTIAL FLAW: Possible buffer overflow if source is larger than data */
|
||||
SNPRINTF(data, 100, L"%s", source);
|
||||
printWLine(data);
|
||||
delete [] data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int rand(void);
|
||||
|
||||
int globalReturnsTrueOrFalse()
|
||||
{
|
||||
return (rand() % 2);
|
||||
}
|
||||
|
||||
#define SRC_STRING "AAAAAAAAAA"
|
||||
|
||||
void CWE121_Stack_Based_Buffer_Overflow__CWE193_char_declare_cpy_12_bad()
|
||||
{
|
||||
char * data;
|
||||
char dataBadBuffer[10];
|
||||
char dataGoodBuffer[10+1];
|
||||
if(globalReturnsTrueOrFalse())
|
||||
{
|
||||
/* FLAW: Set a pointer to a buffer that does not leave room for a NULL terminator when performing
|
||||
* string copies in the sinks */
|
||||
data = dataBadBuffer;
|
||||
data[0] = '\0'; /* null terminate */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIX: Set a pointer to a buffer that leaves room for a NULL terminator when performing
|
||||
* string copies in the sinks */
|
||||
data = dataGoodBuffer;
|
||||
data[0] = '\0'; /* null terminate */
|
||||
}
|
||||
{
|
||||
char source[10+1] = SRC_STRING;
|
||||
/* POTENTIAL FLAW: data may not have enough space to hold source */ // [NOT DETECTED]
|
||||
strcpy(data, source);
|
||||
printLine(data);
|
||||
}
|
||||
}
|
||||
@@ -80,4 +80,4 @@
|
||||
| var_size_struct.cpp:99:3:99:8 | call to memset | This 'memset' operation accesses 129 bytes but the $@ is only 128 bytes. | var_size_struct.cpp:92:8:92:10 | str | destination buffer |
|
||||
| var_size_struct.cpp:101:3:101:8 | call to memset | This 'memset' operation accesses 129 bytes but the $@ is only 128 bytes. | var_size_struct.cpp:92:8:92:10 | str | destination buffer |
|
||||
| var_size_struct.cpp:103:3:103:9 | call to strncpy | This 'strncpy' operation may access 129 bytes but the $@ is only 128 bytes. | var_size_struct.cpp:92:8:92:10 | str | destination buffer |
|
||||
| var_size_struct.cpp:171:3:171:8 | call to memset | This 'memset' operation accesses 100 bytes but the $@ is only 1 byte. | var_size_struct.cpp:125:17:125:19 | arr | destination buffer |
|
||||
| var_size_struct.cpp:169:3:169:8 | call to memset | This 'memset' operation accesses 100 bytes but the $@ is only 1 byte. | var_size_struct.cpp:125:17:125:19 | arr | destination buffer |
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
edges
|
||||
subpaths
|
||||
nodes
|
||||
#select
|
||||
|
||||
@@ -161,8 +161,6 @@ void useVarStruct34(varStruct5 *vs5) {
|
||||
varStruct5 *vs5b = (varStruct5 *)malloc(sizeof(*vs5));
|
||||
varStruct6 *vs6 = (varStruct6 *)malloc(offsetof(varStruct6, arr) + 9); // establish varStruct6 as variable size
|
||||
varStruct7 *vs7 = (varStruct7 *)malloc(sizeForVarStruct7(9)); // establish varStruct7 as variable size
|
||||
varStruct8 *vs8a = (varStruct8 *)malloc(sizeof(varStruct8) + 9); // establish varStruct8 as variable size
|
||||
varStruct8 *vs8b = (varStruct8 *)malloc(sizeof(varStruct8));
|
||||
varStruct9 *vs9 = (varStruct9 *)malloc(__builtin_offsetof(varStruct9, arr) + 9); // establish varStruct9 as variable size
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ edges
|
||||
| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array |
|
||||
| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array indirection |
|
||||
| tests.c:34:10:34:13 | argv | tests.c:34:10:34:16 | access to array indirection |
|
||||
subpaths
|
||||
nodes
|
||||
| tests.c:28:22:28:25 | argv | semmle.label | argv |
|
||||
| tests.c:28:22:28:25 | argv | semmle.label | argv |
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
// Snippet from a SAMATE Juliet test case for rule CWE-122 / CWE-129
|
||||
// CWE122_Heap_Based_Buffer_Overflow__c_CWE129_fgets_01.c
|
||||
|
||||
typedef unsigned long size_t;
|
||||
void *malloc(size_t size);
|
||||
void free(void *ptr);
|
||||
#define NULL (0)
|
||||
|
||||
typedef struct {} FILE;
|
||||
FILE *stdin;
|
||||
char *fgets(char *s, int n, FILE *stream);
|
||||
|
||||
int atoi(const char *nptr);
|
||||
|
||||
void printLine(const char *str);
|
||||
void printIntLine(int val);
|
||||
|
||||
// ---
|
||||
|
||||
#define CHAR_ARRAY_SIZE (64)
|
||||
|
||||
void CWE122_Heap_Based_Buffer_Overflow__c_CWE129_fgets_01_bad()
|
||||
{
|
||||
int data;
|
||||
/* Initialize data */
|
||||
data = -1;
|
||||
{
|
||||
char inputBuffer[CHAR_ARRAY_SIZE] = "";
|
||||
/* POTENTIAL FLAW: Read data from the console using fgets() */
|
||||
if (fgets(inputBuffer, CHAR_ARRAY_SIZE, stdin) != NULL)
|
||||
{
|
||||
/* Convert to int */
|
||||
data = atoi(inputBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
printLine("fgets() failed.");
|
||||
}
|
||||
}
|
||||
{
|
||||
int i;
|
||||
int * buffer = (int *)malloc(10 * sizeof(int));
|
||||
/* initialize buffer */
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
buffer[i] = 0;
|
||||
}
|
||||
/* POTENTIAL FLAW: Attempt to write to an index of the array that is above the upper bound
|
||||
* This code does check to see if the array index is negative */
|
||||
if (data >= 0)
|
||||
{
|
||||
buffer[data] = 1;
|
||||
/* Print the array values */
|
||||
for(i = 0; i < 10; i++)
|
||||
{
|
||||
printIntLine(buffer[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printLine("ERROR: Array index is negative.");
|
||||
}
|
||||
free(buffer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
| CWE122_Heap_Based_Buffer_Overflow__c_CWE129_fgets_01.c:52:20:52:23 | data | $@ flows to here and is used in an array indexing expression, potentially causing an invalid access. | CWE122_Heap_Based_Buffer_Overflow__c_CWE129_fgets_01.c:30:19:30:29 | inputBuffer | User-provided value |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-129/ImproperArrayIndexValidation.ql
|
||||
@@ -0,0 +1,46 @@
|
||||
edges
|
||||
| char_connect_socket_w32_vsnprintf_01_bad.c:94:46:94:69 | recv output argument | char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data |
|
||||
| char_connect_socket_w32_vsnprintf_01_bad.c:94:46:94:69 | recv output argument | char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data |
|
||||
| char_connect_socket_w32_vsnprintf_01_bad.c:94:46:94:69 | recv output argument | char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data indirection |
|
||||
| char_connect_socket_w32_vsnprintf_01_bad.c:94:55:94:68 | ... + ... | char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data |
|
||||
| char_connect_socket_w32_vsnprintf_01_bad.c:94:55:94:68 | ... + ... | char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data |
|
||||
| char_connect_socket_w32_vsnprintf_01_bad.c:94:55:94:68 | ... + ... | char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data indirection |
|
||||
| char_console_fprintf_01_bad.c:30:23:30:35 | ... + ... | char_console_fprintf_01_bad.c:49:21:49:24 | (const char *)... |
|
||||
| char_console_fprintf_01_bad.c:30:23:30:35 | ... + ... | char_console_fprintf_01_bad.c:49:21:49:24 | data |
|
||||
| char_console_fprintf_01_bad.c:30:23:30:35 | ... + ... | char_console_fprintf_01_bad.c:49:21:49:24 | data indirection |
|
||||
| char_console_fprintf_01_bad.c:30:23:30:35 | fgets output argument | char_console_fprintf_01_bad.c:49:21:49:24 | (const char *)... |
|
||||
| char_console_fprintf_01_bad.c:30:23:30:35 | fgets output argument | char_console_fprintf_01_bad.c:49:21:49:24 | data |
|
||||
| char_console_fprintf_01_bad.c:30:23:30:35 | fgets output argument | char_console_fprintf_01_bad.c:49:21:49:24 | data indirection |
|
||||
| char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | char_environment_fprintf_01_bad.c:36:21:36:24 | (const char *)... |
|
||||
| char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | char_environment_fprintf_01_bad.c:36:21:36:24 | (const char *)... |
|
||||
| char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | char_environment_fprintf_01_bad.c:36:21:36:24 | data |
|
||||
| char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | char_environment_fprintf_01_bad.c:36:21:36:24 | data |
|
||||
| char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | char_environment_fprintf_01_bad.c:36:21:36:24 | data indirection |
|
||||
| char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | char_environment_fprintf_01_bad.c:36:21:36:24 | data indirection |
|
||||
subpaths
|
||||
nodes
|
||||
| char_connect_socket_w32_vsnprintf_01_bad.c:94:46:94:69 | recv output argument | semmle.label | recv output argument |
|
||||
| char_connect_socket_w32_vsnprintf_01_bad.c:94:55:94:68 | ... + ... | semmle.label | ... + ... |
|
||||
| char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | semmle.label | data |
|
||||
| char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | semmle.label | data |
|
||||
| char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | semmle.label | data |
|
||||
| char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data indirection | semmle.label | data indirection |
|
||||
| char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data indirection | semmle.label | data indirection |
|
||||
| char_console_fprintf_01_bad.c:30:23:30:35 | ... + ... | semmle.label | ... + ... |
|
||||
| char_console_fprintf_01_bad.c:30:23:30:35 | fgets output argument | semmle.label | fgets output argument |
|
||||
| char_console_fprintf_01_bad.c:49:21:49:24 | (const char *)... | semmle.label | (const char *)... |
|
||||
| char_console_fprintf_01_bad.c:49:21:49:24 | (const char *)... | semmle.label | (const char *)... |
|
||||
| char_console_fprintf_01_bad.c:49:21:49:24 | data | semmle.label | data |
|
||||
| char_console_fprintf_01_bad.c:49:21:49:24 | data indirection | semmle.label | data indirection |
|
||||
| char_console_fprintf_01_bad.c:49:21:49:24 | data indirection | semmle.label | data indirection |
|
||||
| char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | semmle.label | call to getenv |
|
||||
| char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | semmle.label | call to getenv |
|
||||
| char_environment_fprintf_01_bad.c:36:21:36:24 | (const char *)... | semmle.label | (const char *)... |
|
||||
| char_environment_fprintf_01_bad.c:36:21:36:24 | (const char *)... | semmle.label | (const char *)... |
|
||||
| char_environment_fprintf_01_bad.c:36:21:36:24 | data | semmle.label | data |
|
||||
| char_environment_fprintf_01_bad.c:36:21:36:24 | data indirection | semmle.label | data indirection |
|
||||
| char_environment_fprintf_01_bad.c:36:21:36:24 | data indirection | semmle.label | data indirection |
|
||||
#select
|
||||
| char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | char_connect_socket_w32_vsnprintf_01_bad.c:94:55:94:68 | ... + ... | char_connect_socket_w32_vsnprintf_01_bad.c:125:15:125:18 | data | The value of this argument may come from $@ and is being used as a formatting argument to badVaSink(data), which calls vsnprintf(format) | char_connect_socket_w32_vsnprintf_01_bad.c:94:55:94:68 | ... + ... | recv |
|
||||
| char_console_fprintf_01_bad.c:49:21:49:24 | data | char_console_fprintf_01_bad.c:30:23:30:35 | ... + ... | char_console_fprintf_01_bad.c:49:21:49:24 | data | The value of this argument may come from $@ and is being used as a formatting argument to fprintf(format) | char_console_fprintf_01_bad.c:30:23:30:35 | ... + ... | fgets |
|
||||
| char_environment_fprintf_01_bad.c:36:21:36:24 | data | char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | char_environment_fprintf_01_bad.c:36:21:36:24 | data | The value of this argument may come from $@ and is being used as a formatting argument to fprintf(format) | char_environment_fprintf_01_bad.c:27:30:27:35 | call to getenv | getenv |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-134/UncontrolledFormatString.ql
|
||||
@@ -0,0 +1,126 @@
|
||||
// External test case from SAMATE's Juliet Test Suite for C/C++
|
||||
// (http://samate.nist.gov/SRD/testsuite.php)
|
||||
// Associated with CWE-134: Uncontrolled format string. http://cwe.mitre.org/data/definitions/134.html
|
||||
// This is a snippet with added declarations, not the entire test case.
|
||||
|
||||
typedef unsigned long size_t;
|
||||
|
||||
typedef void *va_list;
|
||||
#define va_start(ap, parmN)
|
||||
#define va_end(ap)
|
||||
#define va_arg(ap, type) ((type)0)
|
||||
|
||||
int vsnprintf(char *s, size_t n, const char *format, va_list arg);
|
||||
|
||||
size_t strlen(const char *s);
|
||||
|
||||
#define SOCKET int
|
||||
#define INVALID_SOCKET (0)
|
||||
#define SOCKET_ERROR (1)
|
||||
#define AF_INET (2)
|
||||
#define SOCK_STREAM (3)
|
||||
#define IPPROTO_TCP (4)
|
||||
#define IP_ADDRESS (5)
|
||||
#define TCP_PORT (6)
|
||||
typedef int in_addr_t;
|
||||
struct in_addr {
|
||||
in_addr_t s_addr;
|
||||
};
|
||||
struct sockaddr_in {
|
||||
int sin_family;
|
||||
int sin_port;
|
||||
struct in_addr sin_addr;
|
||||
};
|
||||
in_addr_t inet_addr(const char *cp);
|
||||
|
||||
#define IP_ADDRESS "0.0.0.0"
|
||||
|
||||
void printLine(char *);
|
||||
|
||||
static void badVaSink(char * data, ...)
|
||||
{
|
||||
{
|
||||
char dest[100] = "";
|
||||
va_list args;
|
||||
va_start(args, data);
|
||||
/* POTENTIAL FLAW: Do not specify the format allowing a possible format string vulnerability */
|
||||
vsnprintf(dest, 100-1, data, args);
|
||||
va_end(args);
|
||||
printLine(dest);
|
||||
}
|
||||
}
|
||||
|
||||
void CWE134_Uncontrolled_Format_String__char_connect_socket_w32_vsnprintf_01_bad()
|
||||
{
|
||||
char * data;
|
||||
char dataBuffer[100] = "";
|
||||
data = dataBuffer;
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
int wsaDataInit = 0;
|
||||
#endif
|
||||
int recvResult;
|
||||
struct sockaddr_in service;
|
||||
char *replace;
|
||||
SOCKET connectSocket = INVALID_SOCKET;
|
||||
size_t dataLen = strlen(data);
|
||||
do
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (WSAStartup(MAKEWORD(2,2), &wsaData) != NO_ERROR)
|
||||
{
|
||||
break;
|
||||
}
|
||||
wsaDataInit = 1;
|
||||
#endif
|
||||
/* POTENTIAL FLAW: Read data using a connect socket */
|
||||
connectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (connectSocket == INVALID_SOCKET)
|
||||
{
|
||||
break;
|
||||
}
|
||||
memset(&service, 0, sizeof(service));
|
||||
service.sin_family = AF_INET;
|
||||
service.sin_addr.s_addr = inet_addr(IP_ADDRESS);
|
||||
service.sin_port = htons(TCP_PORT);
|
||||
if (connect(connectSocket, (struct sockaddr*)&service, sizeof(service)) == SOCKET_ERROR)
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* Abort on error or the connection was closed, make sure to recv one
|
||||
* less char than is in the recv_buf in order to append a terminator */
|
||||
/* Abort on error or the connection was closed */
|
||||
recvResult = recv(connectSocket, (char *)(data + dataLen), sizeof(char) * (100 - dataLen - 1), 0);
|
||||
if (recvResult == SOCKET_ERROR || recvResult == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* Append null terminator */
|
||||
data[dataLen + recvResult / sizeof(char)] = '\0';
|
||||
/* Eliminate CRLF */
|
||||
replace = strchr(data, '\r');
|
||||
if (replace)
|
||||
{
|
||||
*replace = '\0';
|
||||
}
|
||||
replace = strchr(data, '\n');
|
||||
if (replace)
|
||||
{
|
||||
*replace = '\0';
|
||||
}
|
||||
}
|
||||
while (0);
|
||||
if (connectSocket != INVALID_SOCKET)
|
||||
{
|
||||
CLOSE_SOCKET(connectSocket);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
if (wsaDataInit)
|
||||
{
|
||||
WSACleanup();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
badVaSink(data, data);
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
// External test case from SAMATE's Juliet Test Suite for C/C++
|
||||
// (http://samate.nist.gov/SRD/testsuite.php)
|
||||
// Associated with CWE-134: Uncontrolled format string. http://cwe.mitre.org/data/definitions/134.html
|
||||
// Examples amended to have all function declarations inlined.
|
||||
|
||||
#define NULL 0
|
||||
typedef unsigned long size_t;
|
||||
typedef struct {} FILE;
|
||||
extern FILE * stdin;
|
||||
extern FILE * stdout;
|
||||
size_t strlen(const char *s);
|
||||
char *fgets(char *s, int n, FILE *stream);
|
||||
int fprintf(FILE *stream, const char *format, ...);
|
||||
char *strcpy(char *s1, const char *s2);
|
||||
|
||||
void printLine(char *);
|
||||
|
||||
void CWE134_Uncontrolled_Format_String__char_console_fprintf_01_bad()
|
||||
{
|
||||
char * data;
|
||||
char data_buf[100] = "";
|
||||
data = data_buf;
|
||||
{
|
||||
/* Read input from the console */
|
||||
size_t data_len = strlen(data);
|
||||
/* if there is room in data, read into it from the console */
|
||||
/* POTENTIAL FLAW: Read data from the console */
|
||||
if(100-data_len > 1)
|
||||
{
|
||||
if (fgets(data+data_len, (int)(100-data_len), stdin) != NULL)
|
||||
{
|
||||
/* The next 3 lines remove the carriage return from the string that is
|
||||
* inserted by fgets() */
|
||||
data_len = strlen(data);
|
||||
if (data_len > 0 && data[data_len-1] == '\n')
|
||||
{
|
||||
data[data_len-1] = '\0';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printLine("fgets() failed");
|
||||
/* Restore NUL terminator if fgets fails */
|
||||
data[data_len] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
/* POTENTIAL FLAW: Do not specify the format allowing a possible format string vulnerability */
|
||||
fprintf(stdout, data);
|
||||
}
|
||||
|
||||
/* goodG2B uses the GoodSource with the BadSink */
|
||||
static void goodG2B()
|
||||
{
|
||||
char * data;
|
||||
char data_buf[100] = "";
|
||||
data = data_buf;
|
||||
/* FIX: Use a fixed string that does not contain a format specifier */
|
||||
strcpy(data, "fixedstringtest");
|
||||
/* POTENTIAL FLAW: Do not specify the format allowing a possible format string vulnerability */
|
||||
fprintf(stdout, data);
|
||||
}
|
||||
|
||||
/* goodB2G uses the BadSource with the GoodSink */
|
||||
static void goodB2G()
|
||||
{
|
||||
char * data;
|
||||
char data_buf[100] = "";
|
||||
data = data_buf;
|
||||
{
|
||||
/* Read input from the console */
|
||||
size_t data_len = strlen(data);
|
||||
/* if there is room in data, read into it from the console */
|
||||
/* POTENTIAL FLAW: Read data from the console */
|
||||
if(100-data_len > 1)
|
||||
{
|
||||
if (fgets(data+data_len, (int)(100-data_len), stdin) != NULL)
|
||||
{
|
||||
/* The next 3 lines remove the carriage return from the string that is
|
||||
* inserted by fgets() */
|
||||
data_len = strlen(data);
|
||||
if (data_len > 0 && data[data_len-1] == '\n')
|
||||
{
|
||||
data[data_len-1] = '\0';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printLine("fgets() failed");
|
||||
/* Restore NUL terminator if fgets fails */
|
||||
data[data_len] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
/* FIX: Specify the format disallowing a format string vulnerability */
|
||||
fprintf(stdout, "%s\n", data);
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
// External test case from SAMATE's Juliet Test Suite for C/C++
|
||||
// (http://samate.nist.gov/SRD/testsuite.php)
|
||||
// Associated with CWE-134: Uncontrolled format string. http://cwe.mitre.org/data/definitions/134.html
|
||||
// Examples amended to have all function declarations inlined.
|
||||
|
||||
#define NULL 0
|
||||
typedef struct {} FILE;
|
||||
typedef unsigned long size_t;
|
||||
extern FILE * stdout;
|
||||
size_t strlen(const char *s);
|
||||
char *getenv(const char *name);
|
||||
char *strcpy(char *s1, const char *s2);
|
||||
char *strncat(char *s1, const char *s2, size_t n);
|
||||
int fprintf(FILE *stream, const char *format, ...);
|
||||
|
||||
#define ENV_VARIABLE "ADD"
|
||||
#define GETENV getenv
|
||||
|
||||
void CWE134_Uncontrolled_Format_String__char_environment_fprintf_01_bad()
|
||||
{
|
||||
char * data;
|
||||
char data_buf[100] = "";
|
||||
data = data_buf;
|
||||
{
|
||||
/* Append input from an environment variable to data */
|
||||
size_t data_len = strlen(data);
|
||||
char * environment = GETENV(ENV_VARIABLE);
|
||||
/* If there is data in the environment variable */
|
||||
if (environment != NULL)
|
||||
{
|
||||
/* POTENTIAL FLAW: Read data from an environment variable */
|
||||
strncat(data+data_len, environment, 100-data_len-1);
|
||||
}
|
||||
}
|
||||
/* POTENTIAL FLAW: Do not specify the format allowing a possible format string vulnerability */
|
||||
fprintf(stdout, data);
|
||||
}
|
||||
|
||||
/* goodG2B uses the GoodSource with the BadSink */
|
||||
static void goodG2B()
|
||||
{
|
||||
char * data;
|
||||
char data_buf[100] = "";
|
||||
data = data_buf;
|
||||
/* FIX: Use a fixed string that does not contain a format specifier */
|
||||
strcpy(data, "fixedstringtest");
|
||||
/* POTENTIAL FLAW: Do not specify the format allowing a possible format string vulnerability */
|
||||
fprintf(stdout, data);
|
||||
}
|
||||
|
||||
/* goodB2G uses the BadSource with the GoodSink */
|
||||
static void goodB2G()
|
||||
{
|
||||
char * data;
|
||||
char data_buf[100] = "";
|
||||
data = data_buf;
|
||||
{
|
||||
/* Append input from an environment variable to data */
|
||||
size_t data_len = strlen(data);
|
||||
char * environment = GETENV(ENV_VARIABLE);
|
||||
/* If there is data in the environment variable */
|
||||
if (environment != NULL)
|
||||
{
|
||||
/* POTENTIAL FLAW: Read data from an environment variable */
|
||||
strncat(data+data_len, environment, 100-data_len-1);
|
||||
}
|
||||
}
|
||||
/* FIX: Specify the format disallowing a format string vulnerability */
|
||||
fprintf(stdout, "%s\n", data);
|
||||
}
|
||||
@@ -247,6 +247,13 @@ edges
|
||||
| argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 |
|
||||
| argvLocal.c:168:18:168:21 | argv | argvLocal.c:170:24:170:26 | i10 |
|
||||
| argvLocal.c:170:15:170:26 | i10 indirection | argvLocal.c:9:25:9:31 | *correct |
|
||||
subpaths
|
||||
| argvLocal.c:117:2:117:13 | i3 | argvLocal.c:9:25:9:31 | correct | argvLocal.c:9:25:9:31 | *correct | argvLocal.c:117:15:117:16 | printWrapper output argument |
|
||||
| argvLocal.c:117:15:117:16 | i3 indirection | argvLocal.c:9:25:9:31 | *correct | argvLocal.c:9:25:9:31 | *correct | argvLocal.c:117:15:117:16 | printWrapper output argument |
|
||||
| argvLocal.c:122:2:122:13 | i4 | argvLocal.c:9:25:9:31 | correct | argvLocal.c:9:25:9:31 | *correct | argvLocal.c:122:15:122:16 | printWrapper output argument |
|
||||
| argvLocal.c:122:15:122:16 | i4 indirection | argvLocal.c:9:25:9:31 | *correct | argvLocal.c:9:25:9:31 | *correct | argvLocal.c:122:15:122:16 | printWrapper output argument |
|
||||
| argvLocal.c:128:2:128:13 | i5 | argvLocal.c:9:25:9:31 | correct | argvLocal.c:9:25:9:31 | *correct | argvLocal.c:128:15:128:16 | printWrapper output argument |
|
||||
| argvLocal.c:128:15:128:16 | i5 indirection | argvLocal.c:9:25:9:31 | *correct | argvLocal.c:9:25:9:31 | *correct | argvLocal.c:128:15:128:16 | printWrapper output argument |
|
||||
nodes
|
||||
| argvLocal.c:9:25:9:31 | *correct | semmle.label | *correct |
|
||||
| argvLocal.c:9:25:9:31 | *correct | semmle.label | *correct |
|
||||
|
||||
@@ -51,6 +51,7 @@ edges
|
||||
| funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | (const char *)... |
|
||||
| funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | i6 |
|
||||
| funcsLocal.c:41:18:41:20 | i61 | funcsLocal.c:42:9:42:10 | i6 indirection |
|
||||
subpaths
|
||||
nodes
|
||||
| funcsLocal.c:16:8:16:9 | fread output argument | semmle.label | fread output argument |
|
||||
| funcsLocal.c:16:8:16:9 | i1 | semmle.label | i1 |
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
edges
|
||||
subpaths
|
||||
nodes
|
||||
#select
|
||||
|
||||
@@ -46,6 +46,7 @@ edges
|
||||
| globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | (const char *)... |
|
||||
| globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | copy2 |
|
||||
| globalVars.c:50:9:50:13 | copy2 | globalVars.c:50:9:50:13 | copy2 indirection |
|
||||
subpaths
|
||||
nodes
|
||||
| globalVars.c:8:7:8:10 | copy | semmle.label | copy |
|
||||
| globalVars.c:9:7:9:11 | copy2 | semmle.label | copy2 |
|
||||
|
||||
@@ -71,6 +71,7 @@ edges
|
||||
| ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | i9 |
|
||||
| ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | i9 indirection |
|
||||
| ifs.c:123:8:123:11 | argv | ifs.c:124:9:124:10 | i9 indirection |
|
||||
subpaths
|
||||
nodes
|
||||
| ifs.c:61:8:61:11 | argv | semmle.label | argv |
|
||||
| ifs.c:61:8:61:11 | argv | semmle.label | argv |
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
edges
|
||||
| examples.cpp:63:26:63:30 | & ... | examples.cpp:66:11:66:14 | data |
|
||||
| examples.cpp:63:26:63:30 | & ... | examples.cpp:66:11:66:14 | data |
|
||||
| examples.cpp:63:26:63:30 | fscanf output argument | examples.cpp:66:11:66:14 | data |
|
||||
| examples.cpp:63:26:63:30 | fscanf output argument | examples.cpp:66:11:66:14 | data |
|
||||
subpaths
|
||||
nodes
|
||||
| examples.cpp:63:26:63:30 | & ... | semmle.label | & ... |
|
||||
| examples.cpp:63:26:63:30 | fscanf output argument | semmle.label | fscanf output argument |
|
||||
| examples.cpp:66:11:66:14 | data | semmle.label | data |
|
||||
| examples.cpp:66:11:66:14 | data | semmle.label | data |
|
||||
| examples.cpp:66:11:66:14 | data | semmle.label | data |
|
||||
#select
|
||||
| examples.cpp:66:11:66:14 | data | examples.cpp:63:26:63:30 | & ... | examples.cpp:66:11:66:14 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:63:26:63:30 | & ... | User-provided value |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-190/ArithmeticTainted.ql
|
||||
@@ -0,0 +1,78 @@
|
||||
edges
|
||||
| examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data |
|
||||
| examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data |
|
||||
| examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data |
|
||||
| examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data |
|
||||
| examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data |
|
||||
| examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data |
|
||||
| examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data |
|
||||
| examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data |
|
||||
| examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data |
|
||||
| examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data |
|
||||
| examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data |
|
||||
| examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data |
|
||||
| examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data |
|
||||
| examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data |
|
||||
| examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data |
|
||||
| examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data |
|
||||
| examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data |
|
||||
| examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data |
|
||||
| examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data |
|
||||
| examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data |
|
||||
| examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data |
|
||||
| examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data |
|
||||
| examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data |
|
||||
| examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data |
|
||||
nodes
|
||||
| examples.cpp:22:26:22:33 | (unsigned int)... | semmle.label | (unsigned int)... |
|
||||
| examples.cpp:22:26:22:33 | (unsigned int)... | semmle.label | (unsigned int)... |
|
||||
| examples.cpp:22:26:22:33 | (unsigned int)... | semmle.label | (unsigned int)... |
|
||||
| examples.cpp:22:26:22:33 | (unsigned int)... | semmle.label | (unsigned int)... |
|
||||
| examples.cpp:22:26:22:33 | (unsigned int)... | semmle.label | (unsigned int)... |
|
||||
| examples.cpp:22:26:22:33 | (unsigned int)... | semmle.label | (unsigned int)... |
|
||||
| examples.cpp:22:26:22:33 | call to rand | semmle.label | call to rand |
|
||||
| examples.cpp:22:26:22:33 | call to rand | semmle.label | call to rand |
|
||||
| examples.cpp:22:26:22:33 | call to rand | semmle.label | call to rand |
|
||||
| examples.cpp:22:26:22:33 | call to rand | semmle.label | call to rand |
|
||||
| examples.cpp:22:26:22:33 | call to rand | semmle.label | call to rand |
|
||||
| examples.cpp:22:26:22:33 | call to rand | semmle.label | call to rand |
|
||||
| examples.cpp:25:31:25:34 | data | semmle.label | data |
|
||||
| examples.cpp:35:26:35:33 | (unsigned int)... | semmle.label | (unsigned int)... |
|
||||
| examples.cpp:35:26:35:33 | (unsigned int)... | semmle.label | (unsigned int)... |
|
||||
| examples.cpp:35:26:35:33 | (unsigned int)... | semmle.label | (unsigned int)... |
|
||||
| examples.cpp:35:26:35:33 | (unsigned int)... | semmle.label | (unsigned int)... |
|
||||
| examples.cpp:35:26:35:33 | (unsigned int)... | semmle.label | (unsigned int)... |
|
||||
| examples.cpp:35:26:35:33 | (unsigned int)... | semmle.label | (unsigned int)... |
|
||||
| examples.cpp:35:26:35:33 | call to rand | semmle.label | call to rand |
|
||||
| examples.cpp:35:26:35:33 | call to rand | semmle.label | call to rand |
|
||||
| examples.cpp:35:26:35:33 | call to rand | semmle.label | call to rand |
|
||||
| examples.cpp:35:26:35:33 | call to rand | semmle.label | call to rand |
|
||||
| examples.cpp:35:26:35:33 | call to rand | semmle.label | call to rand |
|
||||
| examples.cpp:35:26:35:33 | call to rand | semmle.label | call to rand |
|
||||
| examples.cpp:38:9:38:12 | data | semmle.label | data |
|
||||
subpaths
|
||||
#select
|
||||
| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | (unsigned int)... | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:25:31:25:34 | data | examples.cpp:22:26:22:33 | call to rand | examples.cpp:25:31:25:34 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:22:26:22:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | (unsigned int)... | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value |
|
||||
| examples.cpp:38:9:38:12 | data | examples.cpp:35:26:35:33 | call to rand | examples.cpp:38:9:38:12 | data | $@ flows to here and is used in arithmetic, potentially causing an underflow. | examples.cpp:35:26:35:33 | call to rand | Uncontrolled value |
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user