Merge remote-tracking branch 'upstream/main' into refactor_use_of_isGuardPhi

This commit is contained in:
Anders Fugmann
2021-09-28 09:38:16 +02:00
1096 changed files with 85719 additions and 9699 deletions

View File

@@ -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:

View File

@@ -0,0 +1,2 @@
lgtm,codescanning
* The 'Uncontrolled data in SQL query' (cpp/sql-injection) query now supports the `libpqxx` library.

View 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.

View File

@@ -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 = ""
}
}
/**

View File

@@ -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

View File

@@ -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 |

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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.
*/

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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.
*/

View File

@@ -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() }
}

View File

@@ -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() }
}

View File

@@ -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() }
}

View File

@@ -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

View 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)
}
}

View File

@@ -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)
)
}
}

View File

@@ -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) }
}

View 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);
}

View File

@@ -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+())
)
}

View File

@@ -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)
)
}
/**

View File

@@ -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

View 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>

View 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

View File

@@ -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, _)
)
}
}

View File

@@ -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;
}

View File

@@ -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>

View File

@@ -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 + ")"

View 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
...

View File

@@ -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>

View 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()

View File

@@ -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()

View File

@@ -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() +

View File

@@ -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 |

View File

@@ -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);
}
}

View File

@@ -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 |

View File

@@ -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. |

View File

@@ -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
}

View File

@@ -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 |

View File

@@ -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
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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) |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-022/TaintedPath.ql

View File

@@ -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 |

View File

@@ -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) |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-078/ExecTainted.ql

View File

@@ -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);
}
}

View File

@@ -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 |

View File

@@ -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) |

View File

@@ -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;
}

View File

@@ -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 |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-114/UncontrolledProcessOperation.ql

View File

@@ -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");
}
}
}
}

View File

@@ -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 |

View File

@@ -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. |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-120/BadlyBoundedWrite.ql

View File

@@ -0,0 +1 @@
Best Practices/Likely Errors/OffsetUseBeforeRangeCheck.ql

View File

@@ -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 |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-119/OverflowBuffer.ql

View File

@@ -0,0 +1 @@
Critical/OverflowDestination.ql

View File

@@ -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. |

View File

@@ -0,0 +1 @@
Critical/OverflowStatic.ql

View File

@@ -0,0 +1 @@
Security/CWE/CWE-120/OverrunWrite.ql

View File

@@ -0,0 +1 @@
Security/CWE/CWE-120/OverrunWriteFloat.ql

View File

@@ -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. |

View File

@@ -0,0 +1 @@
Likely Bugs/Memory Management/StrncpyFlippedArgs.ql

View File

@@ -0,0 +1,4 @@
edges
subpaths
nodes
#select

View File

@@ -0,0 +1 @@
Security/CWE/CWE-120/UnboundedWrite.ql

View 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);
}
}

View File

@@ -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 |

View File

@@ -1,3 +1,4 @@
edges
subpaths
nodes
#select

View File

@@ -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
}

View File

@@ -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 |

View File

@@ -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);
}
}

View File

@@ -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 |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-129/ImproperArrayIndexValidation.ql

View File

@@ -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 |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-134/UncontrolledFormatString.ql

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-190/ArithmeticTainted.ql

View File

@@ -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