зеркало из https://github.com/github/codeql.git
Merge branch 'main' into impropnullfp
This commit is contained in:
Коммит
2c64fa50d2
|
@ -6,6 +6,8 @@ on:
|
|||
- '.github/workflows/csv-coverage-pr-comment.yml'
|
||||
- '*/ql/src/**/*.ql'
|
||||
- '*/ql/src/**/*.qll'
|
||||
- '*/ql/lib/**/*.ql'
|
||||
- '*/ql/lib/**/*.qll'
|
||||
- 'misc/scripts/library-coverage/*.py'
|
||||
# input data files
|
||||
- '*/documentation/library-coverage/cwe-sink.csv'
|
||||
|
|
|
@ -4,8 +4,8 @@ This open source repository contains the standard CodeQL libraries and queries t
|
|||
|
||||
## How do I learn CodeQL and run queries?
|
||||
|
||||
There is [extensive documentation](https://help.semmle.com/QL/learn-ql/) on getting started with writing CodeQL.
|
||||
You can use the [interactive query console](https://lgtm.com/help/lgtm/using-query-console) on LGTM.com or the [CodeQL for Visual Studio Code](https://help.semmle.com/codeql/codeql-for-vscode.html) extension to try out your queries on any open source project that's currently being analyzed.
|
||||
There is [extensive documentation](https://codeql.github.com/docs/) on getting started with writing CodeQL.
|
||||
You can use the [interactive query console](https://lgtm.com/help/lgtm/using-query-console) on LGTM.com or the [CodeQL for Visual Studio Code](https://codeql.github.com/docs/codeql-for-visual-studio-code/) extension to try out your queries on any open source project that's currently being analyzed.
|
||||
|
||||
## Contributing
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
lgtm,codescanning
|
||||
* A new query (`cpp/cleartext-transmission`) has been added. This is similar to the `cpp/cleartext-storage-file`, `cpp/cleartext-storage-buffer` and `cpp/cleartext-storage-database` queries but looks for cases where sensitive information is most likely transmitted over a network.
|
|
@ -0,0 +1,2 @@
|
|||
lgtm,codescanning
|
||||
* The "Uncontrolled data used in OS command" (`cpp/command-line-injection`) query has been enhanced to reduce false positive results and its `@precision` increased to `high`
|
|
@ -0,0 +1,3 @@
|
|||
lgtm,codescanning
|
||||
* Increase precision to high for the "Static buffer overflow" query
|
||||
(`cpp/static-buffer-overflow`). This means the query is run and displayed by default on Code Scanning and LGTM.
|
|
@ -38,7 +38,7 @@ class Container extends Locatable, @container {
|
|||
* DEPRECATED: Use `getLocation` instead.
|
||||
* Gets a URL representing the location of this container.
|
||||
*
|
||||
* For more information see [Providing URLs](https://help.semmle.com/QL/learn-ql/ql/locations.html#providing-urls).
|
||||
* For more information see [Providing URLs](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls).
|
||||
*/
|
||||
deprecated string getURL() { none() } // overridden by subclasses
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ class Location extends @location {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -24,7 +24,7 @@ class XMLLocatable extends @xmllocatable, TXMLLocatable {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -10,44 +10,11 @@ import semmle.code.cpp.dataflow.DataFlow
|
|||
* 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, 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))
|
||||
* ```
|
||||
* but not if it only ever occurs as
|
||||
* ```
|
||||
* malloc(sizeof(c))
|
||||
* ```
|
||||
* This requires that `v` is an array of size 0 or 1.
|
||||
*/
|
||||
predicate memberMayBeVarSize(Class c, MemberVariable v) {
|
||||
exists(int i |
|
||||
// `v` is the last field in `c`
|
||||
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 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 |
|
||||
so.(SizeofTypeOperator).getTypeOperand().getUnspecifiedType() = c or
|
||||
so.(SizeofExprOperator).getExprOperand().getUnspecifiedType() = c
|
||||
|
|
||||
// and arithmetic is performed on the result
|
||||
so.getParent*() instanceof AddExpr
|
||||
)
|
||||
)
|
||||
c = v.getDeclaringType() and
|
||||
v.getUnspecifiedType().(ArrayType).getArraySize() <= 1
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -60,10 +27,6 @@ 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.
|
||||
|
@ -85,13 +48,6 @@ 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
|
||||
|
|
|
@ -100,6 +100,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 |
|
||||
|
|
|
@ -253,6 +253,21 @@ class FormattingFunctionCall extends Expr {
|
|||
// format arguments must be known
|
||||
exists(getTarget().(FormattingFunction).getFirstFormatArgumentIndex())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the argument, if any, to which the output is written. If `isStream` is
|
||||
* `true`, the output argument is a stream (that is, this call behaves like
|
||||
* `fprintf`). If `isStream` is `false`, the output argument is a buffer (that
|
||||
* is, this call behaves like `sprintf`)
|
||||
*/
|
||||
Expr getOutputArgument(boolean isStream) {
|
||||
result =
|
||||
this.(Call)
|
||||
.getArgument(this.(Call)
|
||||
.getTarget()
|
||||
.(FormattingFunction)
|
||||
.getOutputParameterIndex(isStream))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -194,7 +194,7 @@ class BasicBlock extends ControlFlowNodeBase {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*
|
||||
* Yields no result if this basic block spans multiple source files.
|
||||
*/
|
||||
|
|
|
@ -3248,7 +3248,7 @@ class PathNode extends TPathNode {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
@ -4033,7 +4033,7 @@ private module FlowExploration {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -3248,7 +3248,7 @@ class PathNode extends TPathNode {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
@ -4033,7 +4033,7 @@ private module FlowExploration {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -3248,7 +3248,7 @@ class PathNode extends TPathNode {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
@ -4033,7 +4033,7 @@ private module FlowExploration {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -3248,7 +3248,7 @@ class PathNode extends TPathNode {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
@ -4033,7 +4033,7 @@ private module FlowExploration {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -3248,7 +3248,7 @@ class PathNode extends TPathNode {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
@ -4033,7 +4033,7 @@ private module FlowExploration {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -101,7 +101,7 @@ class Node extends TNode {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -4,7 +4,7 @@ private import semmle.code.cpp.ir.dataflow.DataFlow
|
|||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow3
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowDispatch as Dispatch
|
||||
private import semmle.code.cpp.ir.dataflow.ResolveCall
|
||||
private import semmle.code.cpp.controlflow.IRGuards
|
||||
private import semmle.code.cpp.models.interfaces.Taint
|
||||
private import semmle.code.cpp.models.interfaces.DataFlow
|
||||
|
@ -355,20 +355,6 @@ predicate taintedIncludingGlobalVars(Expr source, Element tainted, string global
|
|||
*/
|
||||
GlobalOrNamespaceVariable globalVarFromId(string id) { id = result.getQualifiedName() }
|
||||
|
||||
/**
|
||||
* Resolve potential target function(s) for `call`.
|
||||
*
|
||||
* If `call` is a call through a function pointer (`ExprCall`) or
|
||||
* targets a virtual method, simple data flow analysis is performed
|
||||
* in order to identify target(s).
|
||||
*/
|
||||
Function resolveCall(Call call) {
|
||||
exists(CallInstruction callInstruction |
|
||||
callInstruction.getAST() = call and
|
||||
result = Dispatch::viableCallable(callInstruction)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides definitions for augmenting source/sink pairs with data-flow paths
|
||||
* between them. From a `@kind path-problem` query, import this module in the
|
||||
|
@ -479,7 +465,7 @@ module TaintedWithPath {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* Provides a predicate for non-contextual virtual dispatch and function
|
||||
* pointer resolution.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
private import semmle.code.cpp.ir.ValueNumbering
|
||||
private import internal.DataFlowDispatch
|
||||
private import semmle.code.cpp.ir.IR
|
||||
|
||||
/**
|
||||
* Resolve potential target function(s) for `call`.
|
||||
*
|
||||
* If `call` is a call through a function pointer (`ExprCall`) or its target is
|
||||
* a virtual member function, simple data flow analysis is performed in order
|
||||
* to identify the possible target(s).
|
||||
*/
|
||||
Function resolveCall(Call call) {
|
||||
exists(CallInstruction callInstruction |
|
||||
callInstruction.getAST() = call and
|
||||
result = viableCallable(callInstruction)
|
||||
)
|
||||
}
|
|
@ -3248,7 +3248,7 @@ class PathNode extends TPathNode {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
@ -4033,7 +4033,7 @@ private module FlowExploration {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -3248,7 +3248,7 @@ class PathNode extends TPathNode {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
@ -4033,7 +4033,7 @@ private module FlowExploration {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -3248,7 +3248,7 @@ class PathNode extends TPathNode {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
@ -4033,7 +4033,7 @@ private module FlowExploration {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -3248,7 +3248,7 @@ class PathNode extends TPathNode {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
@ -4033,7 +4033,7 @@ private module FlowExploration {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -120,7 +120,7 @@ class Node extends TIRDataFlowNode {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -38,5 +38,8 @@ Instruction callOutput(CallInstruction call, FunctionOutput output) {
|
|||
effect.getPrimaryInstruction() = call and
|
||||
output.isParameterDerefOrQualifierObject(effect.getIndex())
|
||||
)
|
||||
// TODO: return value dereference
|
||||
or
|
||||
// TODO: modify this when we get return value dereferences
|
||||
result = call and
|
||||
output.isReturnValueDeref()
|
||||
}
|
||||
|
|
|
@ -36,3 +36,4 @@ private import implementations.Select
|
|||
private import implementations.MySql
|
||||
private import implementations.SqLite3
|
||||
private import implementations.PostgreSql
|
||||
private import implementations.System
|
||||
|
|
|
@ -85,4 +85,6 @@ private class Recv extends AliasFunction, ArrayFunction, SideEffectFunction,
|
|||
) and
|
||||
description = "Buffer read by " + this.getName()
|
||||
}
|
||||
|
||||
override predicate hasSocketInput(FunctionInput input) { input.isParameter(0) }
|
||||
}
|
||||
|
|
|
@ -60,4 +60,6 @@ private class Send extends AliasFunction, ArrayFunction, SideEffectFunction, Rem
|
|||
override predicate hasRemoteFlowSink(FunctionInput input, string description) {
|
||||
input.isParameterDeref(1) and description = "Buffer sent by " + this.getName()
|
||||
}
|
||||
|
||||
override predicate hasSocketInput(FunctionInput input) { input.isParameter(0) }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
import cpp
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.CommandExecution
|
||||
|
||||
/**
|
||||
* A function for running a command using a command interpreter.
|
||||
*/
|
||||
private class SystemFunction extends CommandExecutionFunction, ArrayFunction, AliasFunction,
|
||||
SideEffectFunction {
|
||||
SystemFunction() {
|
||||
hasGlobalOrStdName("system") or // system(command)
|
||||
hasGlobalName("popen") or // popen(command, mode)
|
||||
// Windows variants
|
||||
hasGlobalName("_popen") or // _popen(command, mode)
|
||||
hasGlobalName("_wpopen") or // _wpopen(command, mode)
|
||||
hasGlobalName("_wsystem") // _wsystem(command)
|
||||
}
|
||||
|
||||
override predicate hasCommandArgument(FunctionInput input) { input.isParameterDeref(0) }
|
||||
|
||||
override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 0 or bufParam = 1 }
|
||||
|
||||
override predicate hasArrayInput(int bufParam) { bufParam = 0 or bufParam = 1 }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = 0 or index = 1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate parameterIsAlwaysReturned(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() {
|
||||
hasGlobalOrStdName("system") or
|
||||
hasGlobalName("_wsystem")
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
(i = 0 or i = 1) and
|
||||
buffer = true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* Provides classes for modeling functions that execute new programs by
|
||||
* interpreting string data as shell commands. To use this QL library, create
|
||||
* a QL class extending `CommandExecutionFunction` with a characteristic
|
||||
* predicate that selects the function or set of functions you are modeling.
|
||||
* Within that class, override the `hasCommandArgument` predicate to indicate
|
||||
* which parameters are interpreted as shell commands.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import FunctionInputsAndOutputs
|
||||
import semmle.code.cpp.models.Models
|
||||
|
||||
/**
|
||||
* A function, such as `exec` or `popen` that starts a new process by
|
||||
* interpreting a string as a shell command.
|
||||
*/
|
||||
abstract class CommandExecutionFunction extends Function {
|
||||
/**
|
||||
* Holds if `input` is interpreted as a shell command.
|
||||
*/
|
||||
abstract predicate hasCommandArgument(FunctionInput input);
|
||||
}
|
|
@ -18,6 +18,12 @@ abstract class RemoteFlowSourceFunction extends Function {
|
|||
* Holds if remote data described by `description` flows from `output` of a call to this function.
|
||||
*/
|
||||
abstract predicate hasRemoteFlowSource(FunctionOutput output, string description);
|
||||
|
||||
/**
|
||||
* Holds if remote data from this source comes from a socket described by
|
||||
* `input`. There is no result if a socket is not specified.
|
||||
*/
|
||||
predicate hasSocketInput(FunctionInput input) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -51,4 +57,10 @@ abstract class RemoteFlowSinkFunction extends Function {
|
|||
* send over a network connection.
|
||||
*/
|
||||
abstract predicate hasRemoteFlowSink(FunctionInput input, string description);
|
||||
|
||||
/**
|
||||
* Holds if data put into this sink is transmitted through a socket described
|
||||
* by `input`. There is no result if a socket is not specified.
|
||||
*/
|
||||
predicate hasSocketInput(FunctionInput input) { none() }
|
||||
}
|
||||
|
|
|
@ -29,8 +29,7 @@ predicate nanExcludingComparison(ComparisonOperation guard, boolean polarity) {
|
|||
*/
|
||||
private predicate excludesNan(RangeSsaDefinition def, VariableAccess v) {
|
||||
exists(VariableAccess inCond, ComparisonOperation guard, boolean branch, StackVariable lsv |
|
||||
def.isGuardPhi(inCond, guard, branch) and
|
||||
inCond.getTarget() = lsv and
|
||||
def.isGuardPhi(lsv, inCond, guard, branch) and
|
||||
v = def.getAUse(lsv) and
|
||||
guard.getAnOperand() = inCond and
|
||||
nanExcludingComparison(guard, branch)
|
||||
|
|
|
@ -94,10 +94,11 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
|
|||
predicate isPhiNode(StackVariable v) { exists(RangeSSA x | x.phi_node(v, this.(BasicBlock))) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use isGuardPhi/4 instead
|
||||
* If this definition is a phi node corresponding to a guard,
|
||||
* then return the variable access and the guard.
|
||||
*/
|
||||
predicate isGuardPhi(VariableAccess va, Expr guard, boolean branch) {
|
||||
deprecated predicate isGuardPhi(VariableAccess va, Expr guard, boolean branch) {
|
||||
guard_defn(va, guard, this, branch)
|
||||
}
|
||||
|
||||
|
@ -142,9 +143,8 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
|
|||
// below excludes definitions which can only reach guard phi
|
||||
// nodes by going through the corresponding guard.
|
||||
not exists(VariableAccess access |
|
||||
v = access.getTarget() and
|
||||
pred.contains(access) and
|
||||
this.isGuardPhi(access, _, _)
|
||||
this.isGuardPhi(v, access, _, _)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -433,10 +433,7 @@ private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, StackVaria
|
|||
private predicate phiDependsOnDef(
|
||||
RangeSsaDefinition phi, StackVariable v, RangeSsaDefinition srcDef, StackVariable srcVar
|
||||
) {
|
||||
exists(VariableAccess access, Expr guard |
|
||||
access = v.getAnAccess() and
|
||||
phi.isGuardPhi(access, guard, _)
|
||||
|
|
||||
exists(VariableAccess access, Expr guard | phi.isGuardPhi(v, access, guard, _) |
|
||||
exprDependsOnDef(guard.(ComparisonOperation).getAnOperand(), srcDef, srcVar) or
|
||||
exprDependsOnDef(access, srcDef, srcVar)
|
||||
)
|
||||
|
@ -1204,8 +1201,7 @@ private float boolConversionUpperBound(Expr expr) {
|
|||
*/
|
||||
private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) {
|
||||
exists(VariableAccess access, Expr guard, boolean branch, float defLB, float guardLB |
|
||||
access = v.getAnAccess() and
|
||||
phi.isGuardPhi(access, guard, branch) and
|
||||
phi.isGuardPhi(v, access, guard, branch) and
|
||||
lowerBoundFromGuard(guard, access, guardLB, branch) and
|
||||
defLB = getFullyConvertedLowerBounds(access)
|
||||
|
|
||||
|
@ -1230,8 +1226,7 @@ private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) {
|
|||
/** See comment for `getPhiLowerBounds`, above. */
|
||||
private float getPhiUpperBounds(StackVariable v, RangeSsaDefinition phi) {
|
||||
exists(VariableAccess access, Expr guard, boolean branch, float defUB, float guardUB |
|
||||
access = v.getAnAccess() and
|
||||
phi.isGuardPhi(access, guard, branch) and
|
||||
phi.isGuardPhi(v, access, guard, branch) and
|
||||
upperBoundFromGuard(guard, access, guardUB, branch) and
|
||||
defUB = getFullyConvertedUpperBounds(access)
|
||||
|
|
||||
|
@ -1493,8 +1488,7 @@ private predicate isNEPhi(
|
|||
exists(
|
||||
ComparisonOperation cmp, boolean branch, Expr linearExpr, Expr rExpr, float p, float q, float r
|
||||
|
|
||||
access.getTarget() = v and
|
||||
phi.isGuardPhi(access, cmp, branch) and
|
||||
phi.isGuardPhi(v, access, cmp, branch) and
|
||||
eqOpWithSwapAndNegate(cmp, linearExpr, rExpr, false, branch) and
|
||||
v.getUnspecifiedType() instanceof IntegralOrEnumType and // Float `!=` is too imprecise
|
||||
r = getValue(rExpr).toFloat() and
|
||||
|
@ -1503,8 +1497,7 @@ private predicate isNEPhi(
|
|||
)
|
||||
or
|
||||
exists(Expr op, boolean branch, Expr linearExpr, float p, float q |
|
||||
access.getTarget() = v and
|
||||
phi.isGuardPhi(access, op, branch) and
|
||||
phi.isGuardPhi(v, access, op, branch) and
|
||||
eqZeroWithNegate(op, linearExpr, false, branch) and
|
||||
v.getUnspecifiedType() instanceof IntegralOrEnumType and // Float `!` is too imprecise
|
||||
linearAccess(linearExpr, access, p, q) and
|
||||
|
@ -1524,8 +1517,7 @@ private predicate isUnsupportedGuardPhi(Variable v, RangeSsaDefinition phi, Vari
|
|||
or
|
||||
eqZeroWithNegate(cmp, _, false, branch)
|
||||
|
|
||||
access.getTarget() = v and
|
||||
phi.isGuardPhi(access, cmp, branch) and
|
||||
phi.isGuardPhi(v, access, cmp, branch) and
|
||||
not isNEPhi(v, phi, access, _)
|
||||
)
|
||||
}
|
||||
|
@ -1594,6 +1586,15 @@ private module SimpleRangeAnalysisCached {
|
|||
result = min([max(getTruncatedUpperBounds(expr)), getGuardedUpperBound(expr)])
|
||||
}
|
||||
|
||||
/** Holds if the upper bound of `expr` may have been widened. This means the the upper bound is in practice likely to be overly wide. */
|
||||
cached
|
||||
predicate upperBoundMayBeWidened(Expr e) {
|
||||
isRecursiveExpr(e) and
|
||||
// Widening is not a problem if the post-analysis in `getGuardedUpperBound` has overridden the widening.
|
||||
// Note that the RHS of `<` may be multi-valued.
|
||||
not getGuardedUpperBound(e) < getTruncatedUpperBounds(e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `expr` has a provably empty range. For example:
|
||||
*
|
||||
|
|
|
@ -4,42 +4,20 @@ import cpp
|
|||
import semmle.code.cpp.security.FunctionWithWrappers
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.CommandExecution
|
||||
|
||||
/**
|
||||
* A function for running a command using a command interpreter.
|
||||
*/
|
||||
class SystemFunction extends FunctionWithWrappers, ArrayFunction, AliasFunction, SideEffectFunction {
|
||||
SystemFunction() {
|
||||
hasGlobalOrStdName("system") or // system(command)
|
||||
hasGlobalName("popen") or // popen(command, mode)
|
||||
// Windows variants
|
||||
hasGlobalName("_popen") or // _popen(command, mode)
|
||||
hasGlobalName("_wpopen") or // _wpopen(command, mode)
|
||||
hasGlobalName("_wsystem") // _wsystem(command)
|
||||
}
|
||||
|
||||
override predicate interestingArg(int arg) { arg = 0 }
|
||||
|
||||
override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 0 or bufParam = 1 }
|
||||
|
||||
override predicate hasArrayInput(int bufParam) { bufParam = 0 or bufParam = 1 }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = 0 or index = 1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate parameterIsAlwaysReturned(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() {
|
||||
hasGlobalOrStdName("system") or
|
||||
hasGlobalName("_wsystem")
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
(i = 0 or i = 1) and
|
||||
buffer = true
|
||||
class SystemFunction extends FunctionWithWrappers instanceof CommandExecutionFunction {
|
||||
override predicate interestingArg(int arg) {
|
||||
exists(FunctionInput input |
|
||||
this.(CommandExecutionFunction).hasCommandArgument(input) and
|
||||
(
|
||||
input.isParameterDerefOrQualifierObject(arg) or
|
||||
input.isParameterOrQualifierAddress(arg)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
import cpp
|
||||
import PrintfLike
|
||||
private import TaintTracking
|
||||
private import semmle.code.cpp.ir.dataflow.ResolveCall
|
||||
|
||||
bindingset[index]
|
||||
private string toCause(Function func, int index) {
|
||||
|
|
|
@ -245,7 +245,7 @@ svnchurn(
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `file`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
locations_default(
|
||||
/** The location of an element that is not an expression or a statement. */
|
||||
|
@ -262,7 +262,7 @@ locations_default(
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `file`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
locations_stmt(
|
||||
/** The location of a statement. */
|
||||
|
@ -279,7 +279,7 @@ locations_stmt(
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `file`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
locations_expr(
|
||||
/** The location of an expression. */
|
||||
|
|
|
@ -68,7 +68,7 @@ class SuppressionScope extends ElementBase {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 9.3
|
||||
* @precision medium
|
||||
* @precision high
|
||||
* @id cpp/static-buffer-overflow
|
||||
* @tags reliability
|
||||
* security
|
||||
|
@ -55,6 +55,8 @@ predicate overflowOffsetInLoop(BufferAccess bufaccess, string msg) {
|
|||
loop.counter().getAnAccess() = bufaccess.getArrayOffset() and
|
||||
// Ensure that we don't have an upper bound on the array index that's less than the buffer size.
|
||||
not upperBound(bufaccess.getArrayOffset().getFullyConverted()) < bufaccess.bufferSize() and
|
||||
// The upper bounds analysis must not have been widended
|
||||
not upperBoundMayBeWidened(bufaccess.getArrayOffset().getFullyConverted()) and
|
||||
msg =
|
||||
"Potential buffer-overflow: counter '" + loop.counter().toString() + "' <= " +
|
||||
loop.limit().toString() + " but '" + bufaccess.buffer().getName() + "' has " +
|
||||
|
@ -130,11 +132,13 @@ predicate outOfBounds(BufferAccess bufaccess, string msg) {
|
|||
(
|
||||
access > size
|
||||
or
|
||||
access = size and not exists(AddressOfExpr addof | bufaccess = addof.getOperand())
|
||||
access = size and
|
||||
not exists(AddressOfExpr addof | bufaccess = addof.getOperand()) and
|
||||
not exists(BuiltInOperationBuiltInOffsetOf offsetof | offsetof.getAChild() = bufaccess)
|
||||
) and
|
||||
msg =
|
||||
"Potential buffer-overflow: '" + buf + "' has size " + size.toString() + " but '" + buf + "[" +
|
||||
access.toString() + "]' is accessed here."
|
||||
access.toString() + "]' may be accessed here."
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -198,7 +198,7 @@ class CommentBlock extends Comment {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -18,7 +18,7 @@ class RangeFunction extends Function {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
super.getLocation().hasLocationInfo(path, sl, sc, _, _) and
|
||||
|
|
|
@ -9,7 +9,7 @@ int main(int argc, char** argv) {
|
|||
system(command1);
|
||||
}
|
||||
|
||||
{
|
||||
{
|
||||
// GOOD: the user string is encoded by a library routine.
|
||||
char userNameQuoted[1000] = {0};
|
||||
encodeShellString(userNameQuoted, 1000, userName);
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
* @description Using user-supplied data in an OS command, without
|
||||
* neutralizing special elements, can make code vulnerable
|
||||
* to command injection.
|
||||
* @kind problem
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 9.8
|
||||
* @precision low
|
||||
* @precision high
|
||||
* @id cpp/command-line-injection
|
||||
* @tags security
|
||||
* external/cwe/cwe-078
|
||||
|
@ -16,13 +16,204 @@
|
|||
import cpp
|
||||
import semmle.code.cpp.security.CommandExecution
|
||||
import semmle.code.cpp.security.Security
|
||||
import semmle.code.cpp.security.TaintTracking
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking2
|
||||
import semmle.code.cpp.security.FlowSources
|
||||
import semmle.code.cpp.models.implementations.Strcat
|
||||
|
||||
from Expr taintedArg, Expr taintSource, string taintCause, string callChain
|
||||
Expr sinkAsArgumentIndirection(DataFlow::Node sink) {
|
||||
result =
|
||||
sink.asOperand()
|
||||
.(SideEffectOperand)
|
||||
.getAddressOperand()
|
||||
.getAnyDef()
|
||||
.getUnconvertedResultExpression()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `fst` is a string that is used in a format or concatenation function resulting in `snd`,
|
||||
* and is *not* placed at the start of the resulting string. This indicates that the author did not
|
||||
* expect `fst` to control what program is run if the resulting string is eventually interpreted as
|
||||
* a command line, for example as an argument to `system`.
|
||||
*/
|
||||
predicate interestingConcatenation(DataFlow::Node fst, DataFlow::Node snd) {
|
||||
exists(FormattingFunctionCall call, int index, FormatLiteral literal |
|
||||
sinkAsArgumentIndirection(fst) = call.getConversionArgument(index) and
|
||||
snd.asDefiningArgument() = call.getOutputArgument(false) and
|
||||
literal = call.getFormat() and
|
||||
not literal.getConvSpecOffset(index) = 0 and
|
||||
literal.getConversionChar(index) = ["s", "S"]
|
||||
)
|
||||
or
|
||||
// strcat and friends
|
||||
exists(StrcatFunction strcatFunc, CallInstruction call, ReadSideEffectInstruction rse |
|
||||
call.getStaticCallTarget() = strcatFunc and
|
||||
rse.getArgumentDef() = call.getArgument(strcatFunc.getParamSrc()) and
|
||||
fst.asOperand() = rse.getSideEffectOperand() and
|
||||
snd.asInstruction().(WriteSideEffectInstruction).getDestinationAddress() =
|
||||
call.getArgument(strcatFunc.getParamDest())
|
||||
)
|
||||
or
|
||||
exists(CallInstruction call, Operator op, ReadSideEffectInstruction rse |
|
||||
call.getStaticCallTarget() = op and
|
||||
op.hasQualifiedName("std", "operator+") and
|
||||
op.getType().(UserType).hasQualifiedName("std", "basic_string") and
|
||||
call.getArgument(1) = rse.getArgumentOperand().getAnyDef() and // left operand
|
||||
fst.asOperand() = rse.getSideEffectOperand() and
|
||||
call = snd.asInstruction()
|
||||
)
|
||||
}
|
||||
|
||||
class TaintToConcatenationConfiguration extends TaintTracking::Configuration {
|
||||
TaintToConcatenationConfiguration() { this = "TaintToConcatenationConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof FlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { interestingConcatenation(sink, _) }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
node.asInstruction().getResultType() instanceof IntegralType
|
||||
or
|
||||
node.asInstruction().getResultType() instanceof FloatingPointType
|
||||
}
|
||||
}
|
||||
|
||||
class ExecTaintConfiguration extends TaintTracking2::Configuration {
|
||||
ExecTaintConfiguration() { this = "ExecTaintConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
exists(DataFlow::Node prevSink, TaintToConcatenationConfiguration conf |
|
||||
conf.hasFlow(_, prevSink) and
|
||||
interestingConcatenation(prevSink, source)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
shellCommand(sinkAsArgumentIndirection(sink), _)
|
||||
}
|
||||
|
||||
override predicate isSanitizerOut(DataFlow::Node node) {
|
||||
isSink(node) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
|
||||
}
|
||||
}
|
||||
|
||||
module StitchedPathGraph {
|
||||
// There's a different PathNode class for each DataFlowImplN.qll, so we can't simply combine the
|
||||
// PathGraph predicates directly. Instead, we use a newtype so there's a single type that
|
||||
// contains both sets of PathNodes.
|
||||
newtype TMergedPathNode =
|
||||
TPathNode1(DataFlow::PathNode node) or
|
||||
TPathNode2(DataFlow2::PathNode node)
|
||||
|
||||
// this wraps the toString and location predicates so we can use the merged node type in a
|
||||
// selection
|
||||
class MergedPathNode extends TMergedPathNode {
|
||||
string toString() {
|
||||
exists(DataFlow::PathNode n |
|
||||
this = TPathNode1(n) and
|
||||
result = n.toString()
|
||||
)
|
||||
or
|
||||
exists(DataFlow2::PathNode n |
|
||||
this = TPathNode2(n) and
|
||||
result = n.toString()
|
||||
)
|
||||
}
|
||||
|
||||
DataFlow::Node getNode() {
|
||||
exists(DataFlow::PathNode n |
|
||||
this = TPathNode1(n) and
|
||||
result = n.getNode()
|
||||
)
|
||||
or
|
||||
exists(DataFlow2::PathNode n |
|
||||
this = TPathNode2(n) and
|
||||
result = n.getNode()
|
||||
)
|
||||
}
|
||||
|
||||
DataFlow::PathNode getPathNode1() { this = TPathNode1(result) }
|
||||
|
||||
DataFlow2::PathNode getPathNode2() { this = TPathNode2(result) }
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
exists(DataFlow::PathNode n |
|
||||
this = TPathNode1(n) and
|
||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
)
|
||||
or
|
||||
exists(DataFlow2::PathNode n |
|
||||
this = TPathNode2(n) and
|
||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
query predicate edges(MergedPathNode a, MergedPathNode b) {
|
||||
exists(DataFlow::PathNode an, DataFlow::PathNode bn |
|
||||
a = TPathNode1(an) and
|
||||
b = TPathNode1(bn) and
|
||||
DataFlow::PathGraph::edges(an, bn)
|
||||
)
|
||||
or
|
||||
exists(DataFlow2::PathNode an, DataFlow2::PathNode bn |
|
||||
a = TPathNode2(an) and
|
||||
b = TPathNode2(bn) and
|
||||
DataFlow2::PathGraph::edges(an, bn)
|
||||
)
|
||||
or
|
||||
// This is where paths from the two configurations are connected. `interestingConcatenation`
|
||||
// is the only thing in this module that's actually specific to the query - everything else is
|
||||
// just using types and predicates from the DataFlow library.
|
||||
interestingConcatenation(a.getNode(), b.getNode()) and
|
||||
a instanceof TPathNode1 and
|
||||
b instanceof TPathNode2
|
||||
}
|
||||
|
||||
query predicate nodes(MergedPathNode mpn, string key, string val) {
|
||||
// here we just need the union of the underlying `nodes` predicates
|
||||
exists(DataFlow::PathNode n |
|
||||
mpn = TPathNode1(n) and
|
||||
DataFlow::PathGraph::nodes(n, key, val)
|
||||
)
|
||||
or
|
||||
exists(DataFlow2::PathNode n |
|
||||
mpn = TPathNode2(n) and
|
||||
DataFlow2::PathGraph::nodes(n, key, val)
|
||||
)
|
||||
}
|
||||
|
||||
query predicate subpaths(
|
||||
MergedPathNode arg, MergedPathNode par, MergedPathNode ret, MergedPathNode out
|
||||
) {
|
||||
// just forward subpaths from the underlying libraries. This might be slightly awkward when
|
||||
// the concatenation is deep in a call chain.
|
||||
DataFlow::PathGraph::subpaths(arg.getPathNode1(), par.getPathNode1(), ret.getPathNode1(),
|
||||
out.getPathNode1())
|
||||
or
|
||||
DataFlow2::PathGraph::subpaths(arg.getPathNode2(), par.getPathNode2(), ret.getPathNode2(),
|
||||
out.getPathNode2())
|
||||
}
|
||||
}
|
||||
|
||||
import StitchedPathGraph
|
||||
|
||||
from
|
||||
DataFlow::PathNode sourceNode, DataFlow::PathNode concatSink, DataFlow2::PathNode concatSource,
|
||||
DataFlow2::PathNode sinkNode, string taintCause, string callChain,
|
||||
TaintToConcatenationConfiguration conf1, ExecTaintConfiguration conf2
|
||||
where
|
||||
shellCommand(taintedArg, callChain) and
|
||||
tainted(taintSource, taintedArg) and
|
||||
isUserInput(taintSource, taintCause)
|
||||
select taintedArg,
|
||||
"This argument to an OS command is derived from $@ and then passed to " + callChain, taintSource,
|
||||
"user input (" + taintCause + ")"
|
||||
taintCause = sourceNode.getNode().(FlowSource).getSourceType() and
|
||||
conf1.hasFlowPath(sourceNode, concatSink) and
|
||||
interestingConcatenation(concatSink.getNode(), concatSource.getNode()) and // this loses call context
|
||||
conf2.hasFlowPath(concatSource, sinkNode) and
|
||||
shellCommand(sinkAsArgumentIndirection(sinkNode.getNode()), callChain)
|
||||
select sinkAsArgumentIndirection(sinkNode.getNode()), TPathNode1(sourceNode).(MergedPathNode),
|
||||
TPathNode2(sinkNode).(MergedPathNode),
|
||||
"This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to "
|
||||
+ callChain, sourceNode, "user input (" + taintCause + ")", concatSource,
|
||||
concatSource.toString()
|
||||
|
|
|
@ -9,7 +9,7 @@ storage.</p>
|
|||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>Ensure that sensitive information is always encrypted before being stored, especially before writing to a file.
|
||||
<p>Ensure that sensitive information is always encrypted before being stored to a file or transmitted over the network.
|
||||
It may be wise to encrypt information before it is put into a buffer that may be readable in memory.</p>
|
||||
|
||||
<p>In general, decrypt sensitive information only at the point where it is necessary for it to be used in
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<include src="CleartextStorage.inc.qhelp" /></qhelp>
|
|
@ -0,0 +1,124 @@
|
|||
/**
|
||||
* @name Cleartext transmission of sensitive information
|
||||
* @description Transmitting sensitive information across a network in
|
||||
* cleartext can expose it to an attacker.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 7.5
|
||||
* @precision medium
|
||||
* @id cpp/cleartext-transmission
|
||||
* @tags security
|
||||
* external/cwe/cwe-319
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.security.SensitiveExprs
|
||||
import semmle.code.cpp.dataflow.TaintTracking
|
||||
import semmle.code.cpp.models.interfaces.FlowSource
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/**
|
||||
* A function call that sends or receives data over a network.
|
||||
*/
|
||||
abstract class NetworkSendRecv extends FunctionCall {
|
||||
/**
|
||||
* Gets the expression for the socket or similar object used for sending or
|
||||
* receiving data (if any).
|
||||
*/
|
||||
abstract Expr getSocketExpr();
|
||||
|
||||
/**
|
||||
* Gets the expression for the buffer to be sent from / received into.
|
||||
*/
|
||||
abstract Expr getDataExpr();
|
||||
}
|
||||
|
||||
/**
|
||||
* A function call that sends data over a network.
|
||||
*
|
||||
* note: functions such as `write` may be writing to a network source or a file. We could attempt to determine which, and sort results into `cpp/cleartext-transmission` and perhaps `cpp/cleartext-storage-file`. In practice it usually isn't very important which query reports a result as long as its reported exactly once.
|
||||
*/
|
||||
class NetworkSend extends NetworkSendRecv {
|
||||
RemoteFlowSinkFunction target;
|
||||
|
||||
NetworkSend() { target = this.getTarget() }
|
||||
|
||||
override Expr getSocketExpr() {
|
||||
exists(FunctionInput input, int arg |
|
||||
target.hasSocketInput(input) and
|
||||
input.isParameter(arg) and
|
||||
result = this.getArgument(arg)
|
||||
)
|
||||
}
|
||||
|
||||
override Expr getDataExpr() {
|
||||
exists(FunctionInput input, int arg |
|
||||
target.hasRemoteFlowSink(input, _) and
|
||||
input.isParameterDeref(arg) and
|
||||
result = this.getArgument(arg)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A function call that receives data over a network.
|
||||
*/
|
||||
class NetworkRecv extends NetworkSendRecv {
|
||||
RemoteFlowSourceFunction target;
|
||||
|
||||
NetworkRecv() { target = this.getTarget() }
|
||||
|
||||
override Expr getSocketExpr() {
|
||||
exists(FunctionInput input, int arg |
|
||||
target.hasSocketInput(input) and
|
||||
input.isParameter(arg) and
|
||||
result = this.getArgument(arg)
|
||||
)
|
||||
}
|
||||
|
||||
override Expr getDataExpr() {
|
||||
exists(FunctionOutput output, int arg |
|
||||
target.hasRemoteFlowSource(output, _) and
|
||||
output.isParameterDeref(arg) and
|
||||
result = this.getArgument(arg)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint flow from a sensitive expression to a network operation with data
|
||||
* tainted by that expression.
|
||||
*/
|
||||
class SensitiveSendRecvConfiguration extends TaintTracking::Configuration {
|
||||
SensitiveSendRecvConfiguration() { this = "SensitiveSendRecvConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof SensitiveExpr }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(NetworkSendRecv transmission |
|
||||
sink.asExpr() = transmission.getDataExpr() and
|
||||
// a zero socket descriptor is standard input, which is not interesting for this query.
|
||||
not exists(Zero zero |
|
||||
DataFlow::localFlow(DataFlow::exprNode(zero),
|
||||
DataFlow::exprNode(transmission.getSocketExpr()))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from
|
||||
SensitiveSendRecvConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink,
|
||||
NetworkSendRecv transmission, string msg
|
||||
where
|
||||
config.hasFlowPath(source, sink) and
|
||||
sink.getNode().asExpr() = transmission.getDataExpr() and
|
||||
if transmission instanceof NetworkSend
|
||||
then
|
||||
msg =
|
||||
"This operation transmits '" + sink.toString() +
|
||||
"', which may contain unencrypted sensitive data from $@"
|
||||
else
|
||||
msg =
|
||||
"This operation receives into '" + sink.toString() +
|
||||
"', which may put unencrypted sensitive data into $@"
|
||||
select transmission, source, sink, msg, source, source.getNode().asExpr().toString()
|
|
@ -4,10 +4,13 @@
|
|||
* @kind problem
|
||||
* @id cpp/incorrect-allocation-error-handling
|
||||
* @problem.severity warning
|
||||
* @security-severity 7.5
|
||||
* @precision medium
|
||||
* @tags correctness
|
||||
* security
|
||||
* external/cwe/cwe-570
|
||||
* external/cwe/cwe-252
|
||||
* external/cwe/cwe-755
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
|
|
@ -24,7 +24,7 @@ class Top extends Element {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
pragma[noopt]
|
||||
final predicate hasLocationInfo(
|
||||
|
|
|
@ -61,7 +61,7 @@ class Copy extends @duplication_or_similarity {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -8,7 +8,7 @@ import cpp
|
|||
* column `startcolumn` of line `startline` to column `endcolumn` of line `endline`
|
||||
* in file `filepath`.
|
||||
*
|
||||
* For more information, see [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* For more information, see [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
external predicate defectResults(
|
||||
int id, string queryPath, string file, int startline, int startcol, int endline, int endcol,
|
||||
|
|
|
@ -8,7 +8,7 @@ import cpp
|
|||
* column `startcolumn` of line `startline` to column `endcolumn` of line `endline`
|
||||
* in file `filepath`.
|
||||
*
|
||||
* For more information, see [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* For more information, see [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
external predicate metricResults(
|
||||
int id, string queryPath, string file, int startline, int startcol, int endline, int endcol,
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
#if !defined(CODEQL_ITERATOR_H)
|
||||
#define CODEQL_ITERATOR_H
|
||||
|
||||
typedef unsigned long size_t;
|
||||
|
||||
#include "type_traits.h"
|
||||
|
||||
namespace std {
|
||||
struct ptrdiff_t;
|
||||
|
||||
template<class I> struct iterator_traits;
|
||||
|
||||
template <class Category,
|
||||
class value_type,
|
||||
class difference_type = ptrdiff_t,
|
||||
class pointer_type = value_type*,
|
||||
class reference_type = value_type&>
|
||||
struct iterator {
|
||||
typedef Category iterator_category;
|
||||
|
||||
iterator();
|
||||
iterator(iterator<Category, remove_const_t<value_type> > const &other); // non-const -> const conversion constructor
|
||||
|
||||
iterator &operator++();
|
||||
iterator operator++(int);
|
||||
iterator &operator--();
|
||||
iterator operator--(int);
|
||||
bool operator==(iterator other) const;
|
||||
bool operator!=(iterator other) const;
|
||||
reference_type operator*() const;
|
||||
pointer_type operator->() const;
|
||||
iterator operator+(int);
|
||||
iterator operator-(int);
|
||||
iterator &operator+=(int);
|
||||
iterator &operator-=(int);
|
||||
int operator-(iterator);
|
||||
reference_type operator[](int);
|
||||
};
|
||||
|
||||
struct input_iterator_tag {};
|
||||
struct forward_iterator_tag : public input_iterator_tag {};
|
||||
struct bidirectional_iterator_tag : public forward_iterator_tag {};
|
||||
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
|
||||
|
||||
struct output_iterator_tag {};
|
||||
|
||||
template<class Container>
|
||||
class back_insert_iterator {
|
||||
protected:
|
||||
Container* container = nullptr;
|
||||
public:
|
||||
using iterator_category = output_iterator_tag;
|
||||
using value_type = void;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = void;
|
||||
using reference = void;
|
||||
using container_type = Container;
|
||||
constexpr back_insert_iterator() noexcept = default;
|
||||
constexpr explicit back_insert_iterator(Container& x);
|
||||
back_insert_iterator& operator=(const typename Container::value_type& value);
|
||||
back_insert_iterator& operator=(typename Container::value_type&& value);
|
||||
back_insert_iterator& operator*();
|
||||
back_insert_iterator& operator++();
|
||||
back_insert_iterator operator++(int);
|
||||
};
|
||||
|
||||
template<class Container>
|
||||
constexpr back_insert_iterator<Container> back_inserter(Container& x) {
|
||||
return back_insert_iterator<Container>(x);
|
||||
}
|
||||
|
||||
template<class Container>
|
||||
class front_insert_iterator {
|
||||
protected:
|
||||
Container* container = nullptr;
|
||||
public:
|
||||
using iterator_category = output_iterator_tag;
|
||||
using value_type = void;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = void;
|
||||
using reference = void;
|
||||
using container_type = Container;
|
||||
constexpr front_insert_iterator() noexcept = default;
|
||||
constexpr explicit front_insert_iterator(Container& x);
|
||||
constexpr front_insert_iterator& operator=(const typename Container::value_type& value);
|
||||
constexpr front_insert_iterator& operator=(typename Container::value_type&& value);
|
||||
constexpr front_insert_iterator& operator*();
|
||||
constexpr front_insert_iterator& operator++();
|
||||
constexpr front_insert_iterator operator++(int);
|
||||
};
|
||||
template<class Container>
|
||||
constexpr front_insert_iterator<Container> front_inserter(Container& x) {
|
||||
return front_insert_iterator<Container>(x);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,85 @@
|
|||
#if !defined(CODEQL_STRING_H)
|
||||
#define CODEQL_STRING_H
|
||||
|
||||
#include "iterator.h"
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<class charT> struct char_traits;
|
||||
|
||||
typedef size_t streamsize;
|
||||
|
||||
template <class T> class allocator {
|
||||
public:
|
||||
allocator() throw();
|
||||
typedef size_t size_type;
|
||||
};
|
||||
|
||||
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> >
|
||||
class basic_string {
|
||||
public:
|
||||
using value_type = charT;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
typedef typename Allocator::size_type size_type;
|
||||
static const size_type npos = -1;
|
||||
|
||||
explicit basic_string(const Allocator& a = Allocator());
|
||||
basic_string(const charT* s, const Allocator& a = Allocator());
|
||||
template<class InputIterator> basic_string(InputIterator begin, InputIterator end, const Allocator& a = Allocator());
|
||||
|
||||
const charT* c_str() const;
|
||||
charT* data() noexcept;
|
||||
size_t length() const;
|
||||
|
||||
typedef std::iterator<random_access_iterator_tag, charT> iterator;
|
||||
typedef std::iterator<random_access_iterator_tag, const charT> const_iterator;
|
||||
|
||||
iterator begin();
|
||||
iterator end();
|
||||
const_iterator begin() const;
|
||||
const_iterator end() const;
|
||||
const_iterator cbegin() const;
|
||||
const_iterator cend() const;
|
||||
|
||||
void push_back(charT c);
|
||||
|
||||
const charT& front() const;
|
||||
charT& front();
|
||||
const charT& back() const;
|
||||
charT& back();
|
||||
|
||||
const_reference operator[](size_type pos) const;
|
||||
reference operator[](size_type pos);
|
||||
const_reference at(size_type n) const;
|
||||
reference at(size_type n);
|
||||
template<class T> basic_string& operator+=(const T& t);
|
||||
basic_string& operator+=(const charT* s);
|
||||
basic_string& append(const basic_string& str);
|
||||
basic_string& append(const charT* s);
|
||||
basic_string& append(size_type n, charT c);
|
||||
template<class InputIterator> basic_string& append(InputIterator first, InputIterator last);
|
||||
basic_string& assign(const basic_string& str);
|
||||
basic_string& assign(size_type n, charT c);
|
||||
template<class InputIterator> basic_string& assign(InputIterator first, InputIterator last);
|
||||
basic_string& insert(size_type pos, const basic_string& str);
|
||||
basic_string& insert(size_type pos, size_type n, charT c);
|
||||
basic_string& insert(size_type pos, const charT* s);
|
||||
iterator insert(const_iterator p, size_type n, charT c);
|
||||
template<class InputIterator> iterator insert(const_iterator p, InputIterator first, InputIterator last);
|
||||
basic_string& replace(size_type pos1, size_type n1, const basic_string& str);
|
||||
basic_string& replace(size_type pos1, size_type n1, size_type n2, charT c);
|
||||
size_type copy(charT* s, size_type n, size_type pos = 0) const;
|
||||
void clear() noexcept;
|
||||
basic_string substr(size_type pos = 0, size_type n = npos) const;
|
||||
void swap(basic_string& s) noexcept/*(allocator_traits<Allocator>::propagate_on_container_swap::value || allocator_traits<Allocator>::is_always_equal::value)*/;
|
||||
};
|
||||
|
||||
template<class charT, class traits, class Allocator> basic_string<charT, traits, Allocator> operator+(const basic_string<charT, traits, Allocator>& lhs, const basic_string<charT, traits, Allocator>& rhs);
|
||||
template<class charT, class traits, class Allocator> basic_string<charT, traits, Allocator> operator+(const basic_string<charT, traits, Allocator>& lhs, const charT* rhs);
|
||||
template<class charT, class traits, class Allocator> basic_string<charT, traits, Allocator> operator+(const charT* lhs, const basic_string<charT, traits, Allocator>& rhs);
|
||||
|
||||
typedef basic_string<char> string;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,21 +1,44 @@
|
|||
#if !defined(CODEQL_TYPE_TRAITS_H)
|
||||
#define CODEQL_TYPE_TRAITS_H
|
||||
|
||||
typedef unsigned long size_t;
|
||||
|
||||
namespace std {
|
||||
template<typename T>
|
||||
struct remove_reference {
|
||||
template<class T>
|
||||
struct remove_const { typedef T type; };
|
||||
|
||||
template<class T>
|
||||
struct remove_const<const T> { typedef T type; };
|
||||
|
||||
// `remove_const_t<T>` removes any `const` specifier from `T`
|
||||
template<class T>
|
||||
using remove_const_t = typename remove_const<T>::type;
|
||||
|
||||
template<class T>
|
||||
struct remove_reference { typedef T type; };
|
||||
|
||||
template<class T>
|
||||
struct remove_reference<T &> { typedef T type; };
|
||||
|
||||
template<class T>
|
||||
struct remove_reference<T &&> { typedef T type; };
|
||||
|
||||
// `remove_reference_t<T>` removes any `&` from `T`
|
||||
template<class T>
|
||||
using remove_reference_t = typename remove_reference<T>::type;
|
||||
|
||||
template<class T>
|
||||
struct decay_impl {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct remove_reference<T&> {
|
||||
typedef T type;
|
||||
template<class T, size_t t_size>
|
||||
struct decay_impl<T[t_size]> {
|
||||
typedef T* type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct remove_reference<T&&> {
|
||||
typedef T type;
|
||||
};
|
||||
template<class T>
|
||||
using decay_t = typename decay_impl<remove_reference_t<T>>::type;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -64,6 +64,6 @@ void test_copyableclass_declonly()
|
|||
|
||||
sink(s1); // $ ast,ir
|
||||
sink(s2); // $ ast,ir
|
||||
sink(s3 = source()); // $ ast MISSING: ir
|
||||
sink(s3 = source()); // $ ast,ir
|
||||
}
|
||||
}
|
||||
|
|
|
@ -415,10 +415,10 @@ void test_unordered_map()
|
|||
sink(m30["abc"]);
|
||||
sink(m31.try_emplace("abc", source(), 2)); // $ ast,ir
|
||||
sink(m31); // $ ast,ir
|
||||
sink(m31["abc"]); // $ ast MISSING: ir
|
||||
sink(m31["abc"]); // $ ast,ir
|
||||
sink(m32.try_emplace("abc", 1, source())); // $ ast,ir
|
||||
sink(m32); // $ ast,ir
|
||||
sink(m32["abc"]); // $ ast MISSING: ir
|
||||
sink(m32["abc"]); // $ ast,ir
|
||||
|
||||
// additional emplace test cases
|
||||
std::unordered_map<char *, char *> m33;
|
||||
|
|
|
@ -30,20 +30,20 @@ void test_string()
|
|||
sink(b);
|
||||
sink(c); // $ ast,ir
|
||||
sink(b.c_str());
|
||||
sink(c.c_str()); // $ ast MISSING: ir
|
||||
sink(c.c_str()); // $ ast,ir
|
||||
}
|
||||
|
||||
void test_strings2()
|
||||
{
|
||||
string path1 = user_input();
|
||||
sink(path1.c_str(), "r"); // $ ast MISSING: ir
|
||||
sink(path1.c_str(), "r"); // $ ast,ir
|
||||
|
||||
string path2;
|
||||
path2 = user_input();
|
||||
sink(path2.c_str(), "r"); // $ ast MISSING: ir
|
||||
sink(path2.c_str(), "r"); // $ ast,ir
|
||||
|
||||
string path3(user_input());
|
||||
sink(path3.c_str(), "r"); // $ ast MISSING: ir
|
||||
sink(path3.c_str(), "r"); // $ ast,ir
|
||||
}
|
||||
|
||||
void test_string3()
|
||||
|
@ -67,7 +67,7 @@ void test_string4()
|
|||
// convert back std::string -> char *
|
||||
cs = ss.c_str();
|
||||
|
||||
sink(cs); // $ ast MISSING: ir
|
||||
sink(cs); // $ ast,ir
|
||||
sink(ss); // $ ast,ir
|
||||
}
|
||||
|
||||
|
@ -159,12 +159,12 @@ void test_string_append() {
|
|||
sink(s5); // $ ast,ir
|
||||
|
||||
s6 = s3;
|
||||
sink(s6 += s4); // $ ast MISSING: ir
|
||||
sink(s6 += s4); // $ ast,ir
|
||||
sink(s6); // $ ast,ir
|
||||
|
||||
s7 = s3;
|
||||
sink(s7 += source()); // $ ast MISSING: ir
|
||||
sink(s7 += " "); // $ ast MISSING: ir
|
||||
sink(s7 += source()); // $ ast,ir
|
||||
sink(s7 += " "); // $ ast,ir
|
||||
sink(s7); // $ ast,ir
|
||||
|
||||
s8 = s3;
|
||||
|
@ -196,10 +196,10 @@ void test_string_assign() {
|
|||
sink(s3.assign(s1));
|
||||
sink(s3);
|
||||
|
||||
sink(s4.assign(s2)); // $ ast MISSING: ir
|
||||
sink(s4.assign(s2)); // $ ast,ir
|
||||
sink(s4); // $ ast,ir
|
||||
|
||||
sink(s5.assign(10, c)); // $ ast MISSING: ir
|
||||
sink(s5.assign(10, c)); // $ ast,ir
|
||||
sink(s5); // $ ast,ir
|
||||
|
||||
sink(s6.assign(s1));
|
||||
|
@ -217,15 +217,15 @@ void test_string_insert() {
|
|||
sink(s3);
|
||||
|
||||
s4 = s2;
|
||||
sink(s4.insert(0, s1)); // $ ast MISSING: ir
|
||||
sink(s4.insert(0, s1)); // $ ast,ir
|
||||
sink(s4); // $ ast,ir
|
||||
|
||||
s5 = s1;
|
||||
sink(s5.insert(0, s2)); // $ ast MISSING: ir
|
||||
sink(s5.insert(0, s2)); // $ ast,ir
|
||||
sink(s5); // $ ast,ir
|
||||
|
||||
s6 = s1;
|
||||
sink(s6.insert(0, 10, c)); // $ ast MISSING: ir
|
||||
sink(s6.insert(0, 10, c)); // $ ast,ir
|
||||
sink(s6); // $ ast,ir
|
||||
}
|
||||
|
||||
|
@ -240,15 +240,15 @@ void test_string_replace() {
|
|||
sink(s3);
|
||||
|
||||
s4 = s2;
|
||||
sink(s4.replace(1, 2, s1)); // $ ast MISSING: ir
|
||||
sink(s4.replace(1, 2, s1)); // $ ast,ir
|
||||
sink(s4); // $ ast,ir
|
||||
|
||||
s5 = s1;
|
||||
sink(s5.replace(1, 2, s2)); // $ ast MISSING: ir
|
||||
sink(s5.replace(1, 2, s2)); // $ ast,ir
|
||||
sink(s5); // $ ast,ir
|
||||
|
||||
s6 = s1;
|
||||
sink(s6.replace(1, 2, 10, c)); // $ ast MISSING: ir
|
||||
sink(s6.replace(1, 2, 10, c)); // $ ast,ir
|
||||
sink(s6); // $ ast,ir
|
||||
}
|
||||
|
||||
|
@ -309,7 +309,7 @@ void test_string_data()
|
|||
std::string b(source());
|
||||
|
||||
sink(a.data());
|
||||
sink(b.data()); // $ ast MISSING: ir
|
||||
sink(b.data()); // $ ast,ir
|
||||
sink(a.length());
|
||||
sink(b.length());
|
||||
}
|
||||
|
@ -360,7 +360,7 @@ void test_string_iterators() {
|
|||
std::string s4("world");
|
||||
|
||||
sink(s1);
|
||||
sink(s1.append(s2.begin(), s2.end())); // $ ast MISSING: ir
|
||||
sink(s1.append(s2.begin(), s2.end())); // $ ast,ir
|
||||
sink(s1); // $ ast,ir
|
||||
|
||||
sink(s3);
|
||||
|
@ -433,7 +433,7 @@ void test_string_insert_more()
|
|||
sink(s1.insert(0, cs1));
|
||||
sink(s1);
|
||||
|
||||
sink(s2.insert(0, cs2)); // $ ast MISSING: ir
|
||||
sink(s2.insert(0, cs2)); // $ ast,ir
|
||||
sink(s2); // $ ast,ir
|
||||
}
|
||||
|
||||
|
@ -446,7 +446,7 @@ void test_string_iterator_methods()
|
|||
sink(a.insert(a.begin(), 10, 'x'));
|
||||
sink(a);
|
||||
|
||||
sink(b.insert(b.begin(), 10, ns_char::source())); // $ ast MISSING: ir
|
||||
sink(b.insert(b.begin(), 10, ns_char::source())); // $ ast,ir
|
||||
sink(b); // $ ast,ir
|
||||
}
|
||||
|
||||
|
@ -459,10 +459,10 @@ void test_string_iterator_methods()
|
|||
sink(c.insert(c.end(), s1.begin(), s1.end()));
|
||||
sink(c);
|
||||
|
||||
sink(d.insert(d.end(), s2.begin(), s2.end())); // $ ast MISSING: ir
|
||||
sink(d.insert(d.end(), s2.begin(), s2.end())); // $ ast,ir
|
||||
sink(d); // $ ast,ir
|
||||
|
||||
sink(s2.insert(s2.end(), s1.begin(), s1.end())); // $ ast MISSING: ir
|
||||
sink(s2.insert(s2.end(), s1.begin(), s1.end())); // $ ast,ir
|
||||
sink(s2); // $ ast,ir
|
||||
}
|
||||
|
||||
|
@ -475,10 +475,10 @@ void test_string_iterator_methods()
|
|||
sink(e.append(s3.begin(), s3.end()));
|
||||
sink(e);
|
||||
|
||||
sink(f.append(s4.begin(), s4.end())); // $ ast MISSING: ir
|
||||
sink(f.append(s4.begin(), s4.end())); // $ ast,ir
|
||||
sink(f); // $ ast,ir
|
||||
|
||||
sink(s4.append(s3.begin(), s3.end())); // $ ast MISSING: ir
|
||||
sink(s4.append(s3.begin(), s3.end())); // $ ast,ir
|
||||
sink(s4); // $ ast,ir
|
||||
}
|
||||
|
||||
|
@ -491,7 +491,7 @@ void test_string_iterator_methods()
|
|||
sink(g.assign(s5.cbegin(), s5.cend()));
|
||||
sink(g);
|
||||
|
||||
sink(h.assign(s6.cbegin(), s6.cend())); // $ ast MISSING: ir
|
||||
sink(h.assign(s6.cbegin(), s6.cend())); // $ ast,ir
|
||||
sink(h); // $ ast,ir
|
||||
|
||||
sink(s6.assign(s5.cbegin(), s5.cend()));
|
||||
|
@ -519,8 +519,8 @@ void test_string_front_back() {
|
|||
sink(a.front());
|
||||
sink(a.back());
|
||||
a.push_back(ns_char::source());
|
||||
sink(a.front()); // $ SPURIOUS: ast
|
||||
sink(a.back()); // $ ast MISSING: ir
|
||||
sink(a.front()); // $ SPURIOUS: ast,ir
|
||||
sink(a.back()); // $ ast,ir
|
||||
}
|
||||
|
||||
void test_string_return_assign() {
|
||||
|
@ -533,12 +533,12 @@ void test_string_return_assign() {
|
|||
std::string f("ff");
|
||||
|
||||
sink( a += (b += "bb") );
|
||||
sink( c += (d += source()) ); // $ ast MISSING: ir
|
||||
sink( (e += "ee") += source() ); // $ ast MISSING: ir
|
||||
sink( (f += source()) += "ff" ); // $ ast MISSING: ir
|
||||
sink( c += (d += source()) ); // $ ast,ir
|
||||
sink( (e += "ee") += source() ); // $ ast,ir
|
||||
sink( (f += source()) += "ff" ); // $ ast,ir
|
||||
sink(a);
|
||||
sink(b);
|
||||
sink(c); // $ ast MISSING: ir
|
||||
sink(c); // $ ast,ir
|
||||
sink(d); // $ ast,ir
|
||||
sink(e); // $ ast MISSING: ir
|
||||
sink(f); // $ ast,ir
|
||||
|
@ -553,12 +553,12 @@ void test_string_return_assign() {
|
|||
std::string f("ff");
|
||||
|
||||
sink( a.assign(b.assign("bb")) );
|
||||
sink( c.assign(d.assign(source())) ); // $ ast MISSING: ir
|
||||
sink( e.assign("ee").assign(source()) ); // $ ast MISSING: ir
|
||||
sink( c.assign(d.assign(source())) ); // $ ast,ir
|
||||
sink( e.assign("ee").assign(source()) ); // $ ast,ir
|
||||
sink( f.assign(source()).assign("ff") );
|
||||
sink(a);
|
||||
sink(b);
|
||||
sink(c); // $ ast MISSING: ir
|
||||
sink(c); // $ ast,ir
|
||||
sink(d); // $ ast,ir
|
||||
sink(e); // $ ast MISSING: ir
|
||||
sink(f); // $ SPURIOUS: ast,ir
|
||||
|
|
|
@ -53,15 +53,15 @@ void test_stringstream_string(int amount)
|
|||
sink(ss7); // $ SPURIOUS: ast,ir
|
||||
|
||||
sink(ss8.put('a'));
|
||||
sink(ss9.put(ns_char::source())); // $ ast MISSING: ir
|
||||
sink(ss10.put('a').put(ns_char::source()).put('z')); // $ ast MISSING: ir
|
||||
sink(ss9.put(ns_char::source())); // $ ast,ir
|
||||
sink(ss10.put('a').put(ns_char::source()).put('z')); // $ ast,ir
|
||||
sink(ss8);
|
||||
sink(ss9); // $ ast,ir
|
||||
sink(ss10); // $ ast MISSING: ir
|
||||
|
||||
sink(ss11.write("begin", 5));
|
||||
sink(ss12.write(source(), 5)); // $ ast MISSING: ir
|
||||
sink(ss13.write("begin", 5).write(source(), amount).write("end", 3)); // $ ast MISSING: ir
|
||||
sink(ss12.write(source(), 5)); // $ ast,ir
|
||||
sink(ss13.write("begin", 5).write(source(), amount).write("end", 3)); // $ ast,ir
|
||||
sink(ss11);
|
||||
sink(ss12); // $ ast,ir
|
||||
sink(ss13); // $ ast MISSING: ir
|
||||
|
@ -73,7 +73,7 @@ void test_stringstream_int(int source)
|
|||
int v1 = 0, v2 = 0;
|
||||
|
||||
sink(ss1 << 1234);
|
||||
sink(ss2 << source); // $ ast MISSING: ir
|
||||
sink(ss2 << source); // $ ast,ir
|
||||
sink(ss1 >> v1);
|
||||
sink(ss2 >> v2); // $ ast,ir
|
||||
|
||||
|
@ -97,7 +97,7 @@ void test_stringstream_constructors()
|
|||
std::stringstream ss6;
|
||||
|
||||
sink(ss5 = std::stringstream("abc"));
|
||||
sink(ss6 = std::stringstream(source())); // $ ast MISSING: ir
|
||||
sink(ss6 = std::stringstream(source())); // $ ast,ir
|
||||
|
||||
sink(ss1);
|
||||
sink(ss2); // $ ast,ir
|
||||
|
@ -193,7 +193,7 @@ void test_stringstream_putback()
|
|||
sink(ss.get());
|
||||
sink(ss.putback('b'));
|
||||
sink(ss.get());
|
||||
sink(ss.putback(ns_char::source())); // $ ast MISSING: ir
|
||||
sink(ss.putback(ns_char::source())); // $ ast,ir
|
||||
sink(ss.get()); // $ ast,ir
|
||||
}
|
||||
|
||||
|
@ -263,6 +263,6 @@ void test_chaining()
|
|||
sink(b1); // $ ast,ir
|
||||
sink(b2); // $ ast,ir
|
||||
|
||||
sink(ss2.write("abc", 3).flush().write(source(), 3).flush().write("xyz", 3)); // $ ast MISSING: ir
|
||||
sink(ss2.write("abc", 3).flush().write(source(), 3).flush().write("xyz", 3)); // $ ast,ir
|
||||
sink(ss2); // $ ast MISSING: ir
|
||||
}
|
||||
|
|
|
@ -466,7 +466,7 @@ void test_qualifiers()
|
|||
sink(d.getString());
|
||||
d.setString(strings::source());
|
||||
sink(d); // $ ast,ir
|
||||
sink(d.getString()); // $ ast MISSING: ir
|
||||
sink(d.getString()); // $ ast,ir
|
||||
}
|
||||
|
||||
// --- non-standard swap ---
|
||||
|
|
|
@ -68,8 +68,8 @@ void test_element_taint(int x) {
|
|||
|
||||
v5.push_back(source());
|
||||
sink(v5); // $ ast,ir
|
||||
sink(v5.front()); // $ SPURIOUS: ast
|
||||
sink(v5.back()); // $ ast MISSING: ir
|
||||
sink(v5.front()); // $ SPURIOUS: ast,ir
|
||||
sink(v5.back()); // $ ast,ir
|
||||
|
||||
v6.data()[2] = source();
|
||||
sink(v6); // $ ast MISSING: ir
|
||||
|
@ -81,8 +81,8 @@ void test_element_taint(int x) {
|
|||
v7.insert(it, source());
|
||||
}
|
||||
sink(v7); // $ ast,ir
|
||||
sink(v7.front()); // $ ast MISSING: ir
|
||||
sink(v7.back()); // $ SPURIOUS: ast
|
||||
sink(v7.front()); // $ ast,ir
|
||||
sink(v7.back()); // $ SPURIOUS: ast,ir
|
||||
|
||||
{
|
||||
const std::vector<int> &v8c = v8;
|
||||
|
@ -283,8 +283,8 @@ void test_data_more() {
|
|||
|
||||
v1.push_back(source());
|
||||
sink(v1); // $ ast,ir
|
||||
sink(v1.data()); // $ ast MISSING: ir
|
||||
sink(v1.data()[2]); // $ ast MISSING: ir
|
||||
sink(v1.data()); // $ ast,ir
|
||||
sink(v1.data()[2]); // $ ast,ir
|
||||
|
||||
*(v2.data()) = ns_int::source();
|
||||
sink(v2); // $ ast MISSING: ir
|
||||
|
@ -305,10 +305,10 @@ void test_vector_insert() {
|
|||
sink(a.insert(a.end(), b.begin(), b.end()));
|
||||
sink(a);
|
||||
|
||||
sink(c.insert(c.end(), d.begin(), d.end())); // $ ast MISSING: ir
|
||||
sink(c.insert(c.end(), d.begin(), d.end())); // $ ast,ir
|
||||
sink(c); // $ ast,ir
|
||||
|
||||
sink(d.insert(d.end(), a.begin(), a.end())); // $ ast MISSING: ir
|
||||
sink(d.insert(d.end(), a.begin(), a.end())); // $ ast,ir
|
||||
sink(d); // $ ast,ir
|
||||
}
|
||||
|
||||
|
|
|
@ -5,14 +5,10 @@
|
|||
| test2.c:33:26:33:27 | 46 | Potential buffer-overflow: 'buffer' has size 40 not 46. |
|
||||
| test2.c:34:22:34:23 | 47 | Potential buffer-overflow: 'buffer' has size 40 not 47. |
|
||||
| test2.c:35:23:35:24 | 48 | Potential buffer-overflow: 'buffer' has size 40 not 48. |
|
||||
| test.c:14:9:14:13 | access to array | Potential buffer-overflow: 'xs' has size 5 but 'xs[5]' is accessed here. |
|
||||
| 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.c:14:9:14:13 | access to array | Potential buffer-overflow: 'xs' has size 5 but 'xs[5]' may be accessed here. |
|
||||
| test.c:15:9:15:13 | access to array | Potential buffer-overflow: 'xs' has size 5 but 'xs[6]' may be accessed here. |
|
||||
| test.c:20:9:20:18 | access to array | Potential buffer-overflow: 'ys' has size 5 but 'ys[5]' may be accessed here. |
|
||||
| test.c:21:9:21:18 | access to array | Potential buffer-overflow: 'ys' has size 5 but 'ys[6]' may be 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. |
|
||||
|
|
|
@ -44,21 +44,21 @@ void union_test() {
|
|||
union u u;
|
||||
u.ptr[0] = 0; // GOOD
|
||||
u.ptr[sizeof(u)-1] = 0; // GOOD
|
||||
u.ptr[sizeof(u)] = 0; // BAD
|
||||
u.ptr[sizeof(u)] = 0; // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
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
|
||||
v.u.ptr[sizeof(union u)] = 0; // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
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
|
||||
u.ptr[sizeof(u)] = 0; // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
|
@ -69,5 +69,5 @@ typedef struct {
|
|||
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
|
||||
b->buf[1] = 0; // BAD [NOT DETECTED]
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
| test.cpp:285:10:285:15 | buffer | Variable $@ may not be null terminated. | test.cpp:282:8:282:13 | buffer | buffer |
|
||||
| test.cpp:302:10:302:16 | buffer2 | Variable $@ may not be null terminated. | test.cpp:297:8:297:14 | buffer2 | buffer2 |
|
||||
| test.cpp:314:10:314:15 | buffer | Variable $@ may not be null terminated. | test.cpp:310:8:310:13 | buffer | buffer |
|
||||
| test.cpp:328:10:328:15 | buffer | Variable $@ may not be null terminated. | test.cpp:325:8:325:13 | buffer | buffer |
|
||||
| test.cpp:336:18:336:23 | buffer | Variable $@ may not be null terminated. | test.cpp:335:8:335:13 | buffer | buffer |
|
||||
| test.cpp:355:11:355:16 | buffer | Variable $@ may not be null terminated. | test.cpp:350:8:350:13 | buffer | buffer |
|
||||
| test.cpp:364:11:364:16 | buffer | Variable $@ may not be null terminated. | test.cpp:359:8:359:13 | buffer | buffer |
|
||||
|
@ -25,3 +26,4 @@
|
|||
| test.cpp:421:19:421:25 | buffer2 | Variable $@ may not be null terminated. | test.cpp:419:8:419:14 | buffer2 | buffer2 |
|
||||
| test.cpp:448:17:448:22 | buffer | Variable $@ may not be null terminated. | test.cpp:446:8:446:13 | buffer | buffer |
|
||||
| test.cpp:454:18:454:23 | buffer | Variable $@ may not be null terminated. | test.cpp:452:8:452:13 | buffer | buffer |
|
||||
| test.cpp:513:10:513:15 | buffer | Variable $@ may not be null terminated. | test.cpp:511:8:511:13 | buffer | buffer |
|
||||
|
|
|
@ -502,3 +502,37 @@ void test_strtol()
|
|||
strlen(after_ptr); // 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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1,17 @@
|
|||
| 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) |
|
||||
edges
|
||||
| tests.cpp:33:34:33:39 | call to getenv | tests.cpp:38:39:38:49 | environment indirection |
|
||||
| tests.cpp:38:25:38:36 | strncat output argument | tests.cpp:42:5:42:16 | Phi |
|
||||
| tests.cpp:38:39:38:49 | environment indirection | tests.cpp:38:25:38:36 | strncat output argument |
|
||||
| tests.cpp:38:39:38:49 | environment indirection | tests.cpp:38:25:38:36 | strncat output argument |
|
||||
| tests.cpp:42:5:42:16 | Phi | tests.cpp:51:22:51:25 | badSource output argument |
|
||||
| tests.cpp:51:22:51:25 | badSource output argument | tests.cpp:53:16:53:19 | data indirection |
|
||||
nodes
|
||||
| tests.cpp:33:34:33:39 | call to getenv | semmle.label | call to getenv |
|
||||
| tests.cpp:38:25:38:36 | strncat output argument | semmle.label | strncat output argument |
|
||||
| tests.cpp:38:39:38:49 | environment indirection | semmle.label | environment indirection |
|
||||
| tests.cpp:42:5:42:16 | Phi | semmle.label | Phi |
|
||||
| tests.cpp:51:22:51:25 | badSource output argument | semmle.label | badSource output argument |
|
||||
| tests.cpp:53:16:53:19 | data indirection | semmle.label | data indirection |
|
||||
subpaths
|
||||
#select
|
||||
| tests.cpp:53:16:53:19 | data | tests.cpp:33:34:33:39 | call to getenv | tests.cpp:53:16:53:19 | data indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string) | tests.cpp:33:34:33:39 | call to getenv | user input (an environment variable) | tests.cpp:38:25:38:36 | strncat output argument | strncat output argument |
|
||||
|
|
|
@ -1 +1,85 @@
|
|||
| test.c:21:12:21:19 | command1 | This argument to an OS command is derived from $@ and then passed to system(string) | test.c:14:20:14:23 | argv | user input (argv) |
|
||||
edges
|
||||
| test.cpp:16:20:16:23 | argv | test.cpp:22:45:22:52 | userName indirection |
|
||||
| test.cpp:22:13:22:20 | sprintf output argument | test.cpp:23:12:23:19 | command1 indirection |
|
||||
| test.cpp:22:45:22:52 | userName indirection | test.cpp:22:13:22:20 | sprintf output argument |
|
||||
| test.cpp:22:45:22:52 | userName indirection | test.cpp:22:13:22:20 | sprintf output argument |
|
||||
| test.cpp:47:21:47:26 | call to getenv | test.cpp:50:35:50:43 | envCflags indirection |
|
||||
| test.cpp:50:11:50:17 | sprintf output argument | test.cpp:51:10:51:16 | command indirection |
|
||||
| test.cpp:50:35:50:43 | envCflags indirection | test.cpp:50:11:50:17 | sprintf output argument |
|
||||
| test.cpp:50:35:50:43 | envCflags indirection | test.cpp:50:11:50:17 | sprintf output argument |
|
||||
| test.cpp:62:9:62:16 | fread output argument | test.cpp:64:20:64:27 | filename indirection |
|
||||
| test.cpp:64:11:64:17 | strncat output argument | test.cpp:65:10:65:16 | command indirection |
|
||||
| test.cpp:64:20:64:27 | filename indirection | test.cpp:64:11:64:17 | strncat output argument |
|
||||
| test.cpp:64:20:64:27 | filename indirection | test.cpp:64:11:64:17 | strncat output argument |
|
||||
| test.cpp:82:9:82:16 | fread output argument | test.cpp:84:20:84:27 | filename indirection |
|
||||
| test.cpp:84:11:84:17 | strncat output argument | test.cpp:85:32:85:38 | command indirection |
|
||||
| test.cpp:84:20:84:27 | filename indirection | test.cpp:84:11:84:17 | strncat output argument |
|
||||
| test.cpp:84:20:84:27 | filename indirection | test.cpp:84:11:84:17 | strncat output argument |
|
||||
| test.cpp:91:9:91:16 | fread output argument | test.cpp:93:17:93:24 | filename indirection |
|
||||
| test.cpp:93:11:93:14 | strncat output argument | test.cpp:94:45:94:48 | path indirection |
|
||||
| test.cpp:93:17:93:24 | filename indirection | test.cpp:93:11:93:14 | strncat output argument |
|
||||
| test.cpp:93:17:93:24 | filename indirection | test.cpp:93:11:93:14 | strncat output argument |
|
||||
| test.cpp:106:20:106:25 | call to getenv | test.cpp:107:33:107:36 | path indirection |
|
||||
| test.cpp:107:31:107:31 | call to operator+ | test.cpp:108:18:108:22 | call to c_str indirection |
|
||||
| test.cpp:107:33:107:36 | path indirection | test.cpp:107:31:107:31 | call to operator+ |
|
||||
| test.cpp:107:33:107:36 | path indirection | test.cpp:107:31:107:31 | call to operator+ |
|
||||
| test.cpp:113:20:113:25 | call to getenv | test.cpp:114:19:114:22 | path indirection |
|
||||
| test.cpp:114:17:114:17 | Call | test.cpp:114:25:114:29 | call to c_str indirection |
|
||||
| test.cpp:114:19:114:22 | path indirection | test.cpp:114:17:114:17 | Call |
|
||||
| test.cpp:114:19:114:22 | path indirection | test.cpp:114:17:114:17 | Call |
|
||||
| test.cpp:119:20:119:25 | call to getenv | test.cpp:120:19:120:22 | path indirection |
|
||||
| test.cpp:120:17:120:17 | Call | test.cpp:120:10:120:30 | call to data indirection |
|
||||
| test.cpp:120:19:120:22 | path indirection | test.cpp:120:17:120:17 | Call |
|
||||
| test.cpp:120:19:120:22 | path indirection | test.cpp:120:17:120:17 | Call |
|
||||
| test.cpp:140:9:140:11 | fread output argument | test.cpp:142:31:142:33 | str indirection |
|
||||
| test.cpp:142:11:142:17 | sprintf output argument | test.cpp:143:10:143:16 | command indirection |
|
||||
| test.cpp:142:31:142:33 | str indirection | test.cpp:142:11:142:17 | sprintf output argument |
|
||||
| test.cpp:142:31:142:33 | str indirection | test.cpp:142:11:142:17 | sprintf output argument |
|
||||
nodes
|
||||
| test.cpp:16:20:16:23 | argv | semmle.label | argv |
|
||||
| test.cpp:22:13:22:20 | sprintf output argument | semmle.label | sprintf output argument |
|
||||
| test.cpp:22:45:22:52 | userName indirection | semmle.label | userName indirection |
|
||||
| test.cpp:23:12:23:19 | command1 indirection | semmle.label | command1 indirection |
|
||||
| test.cpp:47:21:47:26 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:50:11:50:17 | sprintf output argument | semmle.label | sprintf output argument |
|
||||
| test.cpp:50:35:50:43 | envCflags indirection | semmle.label | envCflags indirection |
|
||||
| test.cpp:51:10:51:16 | command indirection | semmle.label | command indirection |
|
||||
| test.cpp:62:9:62:16 | fread output argument | semmle.label | fread output argument |
|
||||
| test.cpp:64:11:64:17 | strncat output argument | semmle.label | strncat output argument |
|
||||
| test.cpp:64:20:64:27 | filename indirection | semmle.label | filename indirection |
|
||||
| test.cpp:65:10:65:16 | command indirection | semmle.label | command indirection |
|
||||
| test.cpp:82:9:82:16 | fread output argument | semmle.label | fread output argument |
|
||||
| test.cpp:84:11:84:17 | strncat output argument | semmle.label | strncat output argument |
|
||||
| test.cpp:84:20:84:27 | filename indirection | semmle.label | filename indirection |
|
||||
| test.cpp:85:32:85:38 | command indirection | semmle.label | command indirection |
|
||||
| test.cpp:91:9:91:16 | fread output argument | semmle.label | fread output argument |
|
||||
| test.cpp:93:11:93:14 | strncat output argument | semmle.label | strncat output argument |
|
||||
| test.cpp:93:17:93:24 | filename indirection | semmle.label | filename indirection |
|
||||
| test.cpp:94:45:94:48 | path indirection | semmle.label | path indirection |
|
||||
| test.cpp:106:20:106:25 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:107:31:107:31 | call to operator+ | semmle.label | call to operator+ |
|
||||
| test.cpp:107:33:107:36 | path indirection | semmle.label | path indirection |
|
||||
| test.cpp:108:18:108:22 | call to c_str indirection | semmle.label | call to c_str indirection |
|
||||
| test.cpp:113:20:113:25 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:114:17:114:17 | Call | semmle.label | Call |
|
||||
| test.cpp:114:19:114:22 | path indirection | semmle.label | path indirection |
|
||||
| test.cpp:114:25:114:29 | call to c_str indirection | semmle.label | call to c_str indirection |
|
||||
| test.cpp:119:20:119:25 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:120:10:120:30 | call to data indirection | semmle.label | call to data indirection |
|
||||
| test.cpp:120:17:120:17 | Call | semmle.label | Call |
|
||||
| test.cpp:120:19:120:22 | path indirection | semmle.label | path indirection |
|
||||
| test.cpp:140:9:140:11 | fread output argument | semmle.label | fread output argument |
|
||||
| test.cpp:142:11:142:17 | sprintf output argument | semmle.label | sprintf output argument |
|
||||
| test.cpp:142:31:142:33 | str indirection | semmle.label | str indirection |
|
||||
| test.cpp:143:10:143:16 | command indirection | semmle.label | command indirection |
|
||||
subpaths
|
||||
#select
|
||||
| test.cpp:23:12:23:19 | command1 | test.cpp:16:20:16:23 | argv | test.cpp:23:12:23:19 | command1 indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string) | test.cpp:16:20:16:23 | argv | user input (a command-line argument) | test.cpp:22:13:22:20 | sprintf output argument | sprintf output argument |
|
||||
| test.cpp:51:10:51:16 | command | test.cpp:47:21:47:26 | call to getenv | test.cpp:51:10:51:16 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string) | test.cpp:47:21:47:26 | call to getenv | user input (an environment variable) | test.cpp:50:11:50:17 | sprintf output argument | sprintf output argument |
|
||||
| test.cpp:65:10:65:16 | command | test.cpp:62:9:62:16 | fread output argument | test.cpp:65:10:65:16 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string) | test.cpp:62:9:62:16 | fread output argument | user input (String read by fread) | test.cpp:64:11:64:17 | strncat output argument | strncat output argument |
|
||||
| test.cpp:85:32:85:38 | command | test.cpp:82:9:82:16 | fread output argument | test.cpp:85:32:85:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:82:9:82:16 | fread output argument | user input (String read by fread) | test.cpp:84:11:84:17 | strncat output argument | strncat output argument |
|
||||
| test.cpp:94:45:94:48 | path | test.cpp:91:9:91:16 | fread output argument | test.cpp:94:45:94:48 | path indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:91:9:91:16 | fread output argument | user input (String read by fread) | test.cpp:93:11:93:14 | strncat output argument | strncat output argument |
|
||||
| test.cpp:108:18:108:22 | call to c_str | test.cpp:106:20:106:25 | call to getenv | test.cpp:108:18:108:22 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string) | test.cpp:106:20:106:25 | call to getenv | user input (an environment variable) | test.cpp:107:31:107:31 | call to operator+ | call to operator+ |
|
||||
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:25 | call to getenv | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string) | test.cpp:113:20:113:25 | call to getenv | user input (an environment variable) | test.cpp:114:17:114:17 | Call | Call |
|
||||
| test.cpp:120:25:120:28 | call to data | test.cpp:119:20:119:25 | call to getenv | test.cpp:120:10:120:30 | call to data indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string) | test.cpp:119:20:119:25 | call to getenv | user input (an environment variable) | test.cpp:120:17:120:17 | Call | Call |
|
||||
| test.cpp:143:10:143:16 | command | test.cpp:140:9:140:11 | fread output argument | test.cpp:143:10:143:16 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string) | test.cpp:140:9:140:11 | fread output argument | user input (String read by fread) | test.cpp:142:11:142:17 | sprintf output argument | sprintf output argument |
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
// Semmle test case for rule ExecTainted.ql (Uncontrolled data used in OS command)
|
||||
// Associated with CWE-078: OS Command Injection. http://cwe.mitre.org/data/definitions/78.html
|
||||
|
||||
///// Library routines /////
|
||||
|
||||
int sprintf(char *s, const char *format, ...);
|
||||
int system(const char *string);
|
||||
|
||||
extern void encodeShellString(char *shellStr, int maxChars, const char* cStr);
|
||||
|
||||
///// Test code /////
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
char *userName = argv[2];
|
||||
|
||||
{
|
||||
// BAD: a string from the user is injected directly into
|
||||
// a command.
|
||||
char command1[1000] = {0};
|
||||
sprintf(command1, "userinfo -v \"%s\"", userName);
|
||||
system(command1);
|
||||
}
|
||||
|
||||
{
|
||||
// GOOD: the user string is encoded by a library routine.
|
||||
char userNameQuoted[1000] = {0};
|
||||
encodeShellString(userNameQuoted, 1000, userName);
|
||||
char command2[1000] = {0};
|
||||
sprintf(command2, "userinfo -v %s", userNameQuoted);
|
||||
system(command2);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
// Semmle test case for rule ExecTainted.ql (Uncontrolled data used in OS command)
|
||||
// Associated with CWE-078: OS Command Injection. http://cwe.mitre.org/data/definitions/78.html
|
||||
|
||||
///// Library routines /////
|
||||
|
||||
int sprintf(char *s, const char *format, ...);
|
||||
int system(const char *string);
|
||||
|
||||
char *getenv(char *var);
|
||||
|
||||
extern void encodeShellString(char *shellStr, int maxChars, const char* cStr);
|
||||
#include "../../../../../../include/string.h"
|
||||
///// Test code /////
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
char *userName = argv[2];
|
||||
|
||||
{
|
||||
// BAD: a string from the user is injected directly into
|
||||
// a command.
|
||||
char command1[1000] = {0};
|
||||
sprintf(command1, "userinfo -v \"%s\"", userName);
|
||||
system(command1);
|
||||
}
|
||||
|
||||
{
|
||||
// GOOD: the user string is encoded by a library routine.
|
||||
char userNameQuoted[1000] = {0};
|
||||
encodeShellString(userNameQuoted, 1000, userName);
|
||||
char command2[1000] = {0};
|
||||
sprintf(command2, "userinfo -v %s", userNameQuoted);
|
||||
system(command2);
|
||||
}
|
||||
}
|
||||
|
||||
void test2(char* arg2) {
|
||||
// GOOD?: the user string is the *first* part of the command, like $CC in many environments
|
||||
char *envCC = getenv("CC");
|
||||
|
||||
char command[1000];
|
||||
sprintf("%s %s", envCC, arg2);
|
||||
system(command);
|
||||
}
|
||||
|
||||
void test3(char* arg1) {
|
||||
// GOOD?: the user string is a `$CFLAGS` environment variable
|
||||
char *envCflags = getenv("CFLAGS");
|
||||
|
||||
char command[1000];
|
||||
sprintf(command, "%s %s", arg1, envCflags);
|
||||
system(command);
|
||||
}
|
||||
|
||||
typedef unsigned long size_t;
|
||||
typedef void FILE;
|
||||
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
|
||||
char *strncat(char *s1, const char *s2, size_t n);
|
||||
|
||||
void test4(FILE *f) {
|
||||
// BAD: the user string is injected directly into a command
|
||||
char command[1000] = "mv ", filename[1000];
|
||||
fread(filename, 1, 1000, f);
|
||||
|
||||
strncat(command, filename, 1000);
|
||||
system(command);
|
||||
}
|
||||
|
||||
void test5(FILE *f) {
|
||||
// GOOD?: the user string is the start of a command
|
||||
char command[1000], filename[1000] = " test.txt";
|
||||
fread(command, 1, 1000, f);
|
||||
|
||||
strncat(command, filename, 1000);
|
||||
system(command);
|
||||
}
|
||||
|
||||
int execl(char *path, char *arg1, ...);
|
||||
|
||||
void test6(FILE *f) {
|
||||
// BAD: the user string is injected directly into a command
|
||||
char command[1000] = "mv ", filename[1000];
|
||||
fread(filename, 1, 1000, f);
|
||||
|
||||
strncat(command, filename, 1000);
|
||||
execl("/bin/sh", "sh", "-c", command);
|
||||
}
|
||||
|
||||
void test7(FILE *f) {
|
||||
// GOOD [FALSE POSITIVE]: the user string is a positional argument to a shell script
|
||||
char path[1000] = "/home/me/", filename[1000];
|
||||
fread(filename, 1, 1000, f);
|
||||
|
||||
strncat(path, filename, 1000);
|
||||
execl("/bin/sh", "sh", "-c", "script.sh", path);
|
||||
}
|
||||
|
||||
void test8(char *arg2) {
|
||||
// GOOD?: the user string is the *first* part of the command, like $CC in many environments
|
||||
std::string envCC(getenv("CC"));
|
||||
std::string command = envCC + arg2;
|
||||
system(command.c_str());
|
||||
}
|
||||
|
||||
void test9(FILE *f) {
|
||||
// BAD: the user string is injected directly into a command
|
||||
std::string path(getenv("something"));
|
||||
std::string command = "mv " + path;
|
||||
system(command.c_str());
|
||||
}
|
||||
|
||||
void test10(FILE *f) {
|
||||
// BAD: the user string is injected directly into a command
|
||||
std::string path(getenv("something"));
|
||||
system(("mv " + path).c_str());
|
||||
}
|
||||
|
||||
void test11(FILE *f) {
|
||||
// BAD: the user string is injected directly into a command
|
||||
std::string path(getenv("something"));
|
||||
system(("mv " + path).data());
|
||||
}
|
||||
|
||||
int atoi(char *);
|
||||
|
||||
void test12(FILE *f) {
|
||||
char temp[10];
|
||||
char command[1000];
|
||||
|
||||
fread(temp, 1, 10, f);
|
||||
|
||||
int x = atoi(temp);
|
||||
sprintf(command, "tail -n %d foo.log", x);
|
||||
system(command); // GOOD: the user string was converted to an integer and back
|
||||
}
|
||||
|
||||
void test13(FILE *f) {
|
||||
char str[1000];
|
||||
char command[1000];
|
||||
|
||||
fread(str, 1, 1000, f);
|
||||
|
||||
sprintf(command, "echo %s", str);
|
||||
system(command); // BAD: the user string was printed into the command with the %s specifier
|
||||
}
|
||||
|
||||
void test14(FILE *f) {
|
||||
char str[1000];
|
||||
char command[1000];
|
||||
|
||||
fread(str, 1, 1000, f);
|
||||
|
||||
sprintf(command, "echo %p", str);
|
||||
system(command); // GOOD: the user string's address was printed into the command with the %p specifier
|
||||
}
|
||||
|
||||
void test15(FILE *f) {
|
||||
char temp[10];
|
||||
char command[1000];
|
||||
|
||||
fread(temp, 1, 10, f);
|
||||
|
||||
int x = atoi(temp);
|
||||
|
||||
char temp2[10];
|
||||
sprintf(temp2, "%d", x);
|
||||
sprintf(command, "tail -n %s foo.log", temp2);
|
||||
|
||||
system(command); // GOOD: the user string was converted to an integer and back
|
||||
}
|
||||
|
||||
|
||||
// TODO: test for call context sensitivity at concatenation site
|
||||
|
||||
// open question: do we want to report certain sources even when they're the start of the string?
|
|
@ -72,12 +72,9 @@
|
|||
| unions.cpp:30:2:30:7 | call to memset | This 'memset' operation accesses 200 bytes but the $@ is only 100 bytes. | unions.cpp:15:7:15:11 | small | destination buffer |
|
||||
| unions.cpp:34:2:34:7 | call to memset | This 'memset' operation accesses 200 bytes but the $@ is only 100 bytes. | unions.cpp:16:7:16:11 | large | destination buffer |
|
||||
| unions.cpp:34:2:34:7 | call to memset | This 'memset' operation accesses 200 bytes but the $@ is only 100 bytes. | unions.cpp:34:14:34:18 | large | destination buffer |
|
||||
| var_size_struct.cpp:54:5:54:14 | access to array | This array indexing operation accesses byte offset 1 but the $@ is only 1 byte. | var_size_struct.cpp:32:8:32:10 | str | array |
|
||||
| var_size_struct.cpp:55:5:55:14 | access to array | This array indexing operation accesses byte offset 1 but the $@ is only 1 byte. | var_size_struct.cpp:38:8:38:10 | str | array |
|
||||
| var_size_struct.cpp:71:3:71:8 | call to memset | This 'memset' operation accesses 1025 bytes but the $@ is only 1024 bytes. | var_size_struct.cpp:63:8:63:11 | data | destination buffer |
|
||||
| var_size_struct.cpp:73:3:73:9 | call to strncpy | This 'strncpy' operation may access 1025 bytes but the $@ is only 1024 bytes. | var_size_struct.cpp:63:8:63:11 | data | destination buffer |
|
||||
| var_size_struct.cpp:87:3:87:19 | access to array | This array indexing operation accesses byte offset 67 but the $@ is only 64 bytes. | var_size_struct.cpp:78:7:78:14 | elements | array |
|
||||
| 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: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 |
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
| tests.cpp:163:3:163:11 | access to array | Potential buffer-overflow: counter 'k' <= 100 but 'buffer' has 100 elements. |
|
||||
| tests.cpp:164:8:164:16 | access to array | Potential buffer-overflow: counter 'k' <= 100 but 'buffer' has 100 elements. |
|
||||
| tests.cpp:245:42:245:42 | 6 | Potential buffer-overflow: 'global_array_5' has size 5 not 6. |
|
||||
| tests.cpp:349:2:349:14 | access to array | Potential buffer-overflow: 'charArray' has size 10 but 'charArray[10]' is accessed here. |
|
||||
| tests.cpp:350:17:350:29 | access to array | Potential buffer-overflow: 'charArray' has size 10 but 'charArray[10]' is accessed here. |
|
||||
| var_size_struct.cpp:54:5:54:14 | access to array | Potential buffer-overflow: 'str' has size 1 but 'str[1]' is accessed here. |
|
||||
| var_size_struct.cpp:55:5:55:14 | access to array | Potential buffer-overflow: 'str' has size 1 but 'str[1]' is accessed here. |
|
||||
| tests.cpp:349:2:349:14 | access to array | Potential buffer-overflow: 'charArray' has size 10 but 'charArray[10]' may be accessed here. |
|
||||
| tests.cpp:350:17:350:29 | access to array | Potential buffer-overflow: 'charArray' has size 10 but 'charArray[10]' may be accessed here. |
|
||||
| var_size_struct.cpp:103:39:103:41 | 129 | Potential buffer-overflow: 'str' has size 128 not 129. |
|
||||
|
|
|
@ -51,8 +51,8 @@ void testVarString(int n) {
|
|||
s1->str[1] = '?'; // GOOD
|
||||
s2->str[1] = '?'; // GOOD
|
||||
s3->str[1] = '?'; // GOOD
|
||||
s4->str[1] = '?'; // BAD
|
||||
s5->str[1] = '?'; // BAD
|
||||
s4->str[1] = '?'; // BAD [NOT DETECTED]
|
||||
s5->str[1] = '?'; // BAD [NOT DETECTED]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,7 +166,7 @@ void useVarStruct34(varStruct5 *vs5) {
|
|||
|
||||
void testVarStruct34(varStruct3 *vs3, varStruct4 *vs4, varStruct5 *vs5, varStruct6 *vs6, varStruct7 *vs7, varStruct8 *vs8, varStruct9 *vs9) {
|
||||
memset(vs3->arr, 'x', 100); // GOOD: it's variable size, we don't know how big so shouldn't flag
|
||||
memset(vs4->arr, 'x', 100); // BAD: it's not variable size, so this is a buffer overflow
|
||||
memset(vs4->arr, 'x', 100); // BAD: [NOT DETECTED] it's not variable size, so this is a buffer overflow
|
||||
memset(vs5->arr, 'x', 100); // GOOD: it's variable size, we don't know how big so shouldn't flag
|
||||
memset(vs6->arr, 'x', 100); // GOOD: it's variable size, we don't know how big so shouldn't flag
|
||||
memset(vs7->arr, 'x', 100); // GOOD: it's variable size, we don't know how big so shouldn't flag
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
| var_size_struct.cpp:13:8:13:17 | VarString1 | var_size_struct.cpp:15:8:15:10 | str |
|
||||
| var_size_struct.cpp:18:8:18:17 | VarString2 | var_size_struct.cpp:20:8:20:10 | str |
|
||||
| var_size_struct.cpp:24:8:24:17 | VarString3 | var_size_struct.cpp:26:8:26:10 | str |
|
||||
| var_size_struct.cpp:30:8:30:17 | VarString4 | var_size_struct.cpp:32:8:32:10 | str |
|
||||
| var_size_struct.cpp:36:8:36:17 | VarString5 | var_size_struct.cpp:38:8:38:10 | str |
|
||||
| var_size_struct.cpp:36:8:36:17 | VarString5 | var_size_struct.cpp:39:8:39:11 | str2 |
|
||||
| var_size_struct.cpp:61:8:61:17 | varStruct1 | var_size_struct.cpp:63:8:63:11 | data |
|
||||
| var_size_struct.cpp:76:8:76:17 | varStruct2 | var_size_struct.cpp:78:7:78:14 | elements |
|
||||
| var_size_struct.cpp:106:8:106:20 | notVarStruct2 | var_size_struct.cpp:107:8:107:10 | str |
|
||||
| var_size_struct.cpp:119:8:119:17 | varStruct3 | var_size_struct.cpp:121:17:121:19 | arr |
|
||||
| var_size_struct.cpp:123:8:123:17 | varStruct4 | var_size_struct.cpp:125:17:125:19 | arr |
|
||||
| var_size_struct.cpp:127:8:127:17 | varStruct5 | var_size_struct.cpp:129:17:129:19 | arr |
|
||||
| var_size_struct.cpp:131:8:131:17 | varStruct6 | var_size_struct.cpp:133:17:133:19 | arr |
|
||||
| var_size_struct.cpp:135:8:135:17 | varStruct7 | var_size_struct.cpp:137:17:137:19 | arr |
|
||||
| var_size_struct.cpp:139:8:139:17 | varStruct8 | var_size_struct.cpp:141:9:141:11 | arr |
|
||||
| var_size_struct.cpp:143:8:143:17 | varStruct9 | var_size_struct.cpp:145:17:145:19 | arr |
|
||||
| var_size_struct.cpp:181:8:181:18 | PseudoUnion | var_size_struct.cpp:183:7:183:10 | data |
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
edges
|
||||
| test3.cpp:68:21:68:29 | password1 | test3.cpp:70:15:70:17 | ptr |
|
||||
| test3.cpp:75:15:75:22 | password | test3.cpp:77:15:77:17 | ptr |
|
||||
| test3.cpp:106:20:106:25 | buffer | test3.cpp:108:14:108:19 | buffer |
|
||||
| test3.cpp:111:28:111:33 | buffer | test3.cpp:113:9:113:14 | buffer |
|
||||
| test3.cpp:120:9:120:23 | global_password | test3.cpp:138:16:138:29 | call to get_global_str |
|
||||
| test3.cpp:128:11:128:18 | password | test3.cpp:106:20:106:25 | buffer |
|
||||
| test3.cpp:132:21:132:22 | call to id | test3.cpp:134:15:134:17 | ptr |
|
||||
| test3.cpp:132:24:132:32 | password1 | test3.cpp:111:28:111:33 | buffer |
|
||||
| test3.cpp:132:24:132:32 | password1 | test3.cpp:132:21:132:22 | call to id |
|
||||
| test3.cpp:138:16:138:29 | call to get_global_str | test3.cpp:140:15:140:18 | data |
|
||||
| test3.cpp:151:19:151:26 | password | test3.cpp:153:15:153:20 | buffer |
|
||||
nodes
|
||||
| test3.cpp:20:15:20:23 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:24:15:24:23 | password2 | semmle.label | password2 |
|
||||
| test3.cpp:41:15:41:22 | password | semmle.label | password |
|
||||
| test3.cpp:49:15:49:22 | password | semmle.label | password |
|
||||
| test3.cpp:68:21:68:29 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:70:15:70:17 | ptr | semmle.label | ptr |
|
||||
| test3.cpp:75:15:75:22 | password | semmle.label | password |
|
||||
| test3.cpp:77:15:77:17 | ptr | semmle.label | ptr |
|
||||
| test3.cpp:95:12:95:19 | password | semmle.label | password |
|
||||
| test3.cpp:106:20:106:25 | buffer | semmle.label | buffer |
|
||||
| test3.cpp:108:14:108:19 | buffer | semmle.label | buffer |
|
||||
| test3.cpp:111:28:111:33 | buffer | semmle.label | buffer |
|
||||
| test3.cpp:113:9:113:14 | buffer | semmle.label | buffer |
|
||||
| test3.cpp:120:9:120:23 | global_password | semmle.label | global_password |
|
||||
| test3.cpp:128:11:128:18 | password | semmle.label | password |
|
||||
| test3.cpp:132:21:132:22 | call to id | semmle.label | call to id |
|
||||
| test3.cpp:132:24:132:32 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:134:15:134:17 | ptr | semmle.label | ptr |
|
||||
| test3.cpp:138:16:138:29 | call to get_global_str | semmle.label | call to get_global_str |
|
||||
| test3.cpp:140:15:140:18 | data | semmle.label | data |
|
||||
| test3.cpp:151:19:151:26 | password | semmle.label | password |
|
||||
| test3.cpp:153:15:153:20 | buffer | semmle.label | buffer |
|
||||
subpaths
|
||||
| test3.cpp:132:24:132:32 | password1 | test3.cpp:111:28:111:33 | buffer | test3.cpp:113:9:113:14 | buffer | test3.cpp:132:21:132:22 | call to id |
|
||||
#select
|
||||
| test3.cpp:20:3:20:6 | call to send | test3.cpp:20:15:20:23 | password1 | test3.cpp:20:15:20:23 | password1 | This operation transmits 'password1', which may contain unencrypted sensitive data from $@ | test3.cpp:20:15:20:23 | password1 | password1 |
|
||||
| test3.cpp:24:3:24:6 | call to send | test3.cpp:24:15:24:23 | password2 | test3.cpp:24:15:24:23 | password2 | This operation transmits 'password2', which may contain unencrypted sensitive data from $@ | test3.cpp:24:15:24:23 | password2 | password2 |
|
||||
| test3.cpp:41:3:41:6 | call to recv | test3.cpp:41:15:41:22 | password | test3.cpp:41:15:41:22 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:41:15:41:22 | password | password |
|
||||
| test3.cpp:49:3:49:6 | call to recv | test3.cpp:49:15:49:22 | password | test3.cpp:49:15:49:22 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:49:15:49:22 | password | password |
|
||||
| test3.cpp:70:3:70:6 | call to send | test3.cpp:68:21:68:29 | password1 | test3.cpp:70:15:70:17 | ptr | This operation transmits 'ptr', which may contain unencrypted sensitive data from $@ | test3.cpp:68:21:68:29 | password1 | password1 |
|
||||
| test3.cpp:77:3:77:6 | call to recv | test3.cpp:75:15:75:22 | password | test3.cpp:77:15:77:17 | ptr | This operation receives into 'ptr', which may put unencrypted sensitive data into $@ | test3.cpp:75:15:75:22 | password | password |
|
||||
| test3.cpp:95:3:95:6 | call to read | test3.cpp:95:12:95:19 | password | test3.cpp:95:12:95:19 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:95:12:95:19 | password | password |
|
||||
| test3.cpp:108:2:108:5 | call to recv | test3.cpp:128:11:128:18 | password | test3.cpp:108:14:108:19 | buffer | This operation receives into 'buffer', which may put unencrypted sensitive data into $@ | test3.cpp:128:11:128:18 | password | password |
|
||||
| test3.cpp:134:3:134:6 | call to send | test3.cpp:132:24:132:32 | password1 | test3.cpp:134:15:134:17 | ptr | This operation transmits 'ptr', which may contain unencrypted sensitive data from $@ | test3.cpp:132:24:132:32 | password1 | password1 |
|
||||
| test3.cpp:140:3:140:6 | call to send | test3.cpp:120:9:120:23 | global_password | test3.cpp:140:15:140:18 | data | This operation transmits 'data', which may contain unencrypted sensitive data from $@ | test3.cpp:120:9:120:23 | global_password | global_password |
|
||||
| test3.cpp:153:3:153:6 | call to send | test3.cpp:151:19:151:26 | password | test3.cpp:153:15:153:20 | buffer | This operation transmits 'buffer', which may contain unencrypted sensitive data from $@ | test3.cpp:151:19:151:26 | password | password |
|
|
@ -0,0 +1 @@
|
|||
Security/CWE/CWE-311/CleartextTransmission.ql
|
|
@ -0,0 +1,155 @@
|
|||
|
||||
typedef unsigned long size_t;
|
||||
#define STDIN_FILENO (0)
|
||||
|
||||
size_t strlen(const char *s);
|
||||
|
||||
void send(int fd, const void *buf, size_t bufLen, int d);
|
||||
void recv(int fd, void *buf, size_t bufLen, int d);
|
||||
void read(int fd, void *buf, size_t bufLen);
|
||||
|
||||
void LogonUserA(int a, int b, const char *password, int d, int e, int f);
|
||||
|
||||
int val();
|
||||
|
||||
void test_send(const char *password1, const char *password2, const char *password_hash, const char *message)
|
||||
{
|
||||
{
|
||||
LogonUserA(val(), val(), password1, val(), val(), val()); // proof `password1` is plaintext
|
||||
|
||||
send(val(), password1, strlen(password1), val()); // BAD: `password1` is sent plaintext (certainly)
|
||||
}
|
||||
|
||||
{
|
||||
send(val(), password2, strlen(password2), val()); // BAD: `password2` is sent plaintext (probably)
|
||||
}
|
||||
|
||||
{
|
||||
send(val(), password_hash, strlen(password_hash), val()); // GOOD: `password_hash` is sent encrypted
|
||||
}
|
||||
|
||||
{
|
||||
send(val(), message, strlen(message), val()); // GOOD: `message` is not a password
|
||||
}
|
||||
}
|
||||
|
||||
void test_receive()
|
||||
{
|
||||
{
|
||||
char password[256];
|
||||
|
||||
recv(val(), password, 256, val()); // BAD: `password` is received plaintext (certainly)
|
||||
|
||||
LogonUserA(val(), val(), password, val(), val(), val()); // (proof `password` is plaintext)
|
||||
}
|
||||
|
||||
{
|
||||
char password[256];
|
||||
|
||||
recv(val(), password, 256, val()); // BAD: `password` is received plaintext (probably)
|
||||
}
|
||||
|
||||
{
|
||||
char password_hash[256];
|
||||
|
||||
recv(val(), password_hash, 256, val()); // GOOD: `password` is received encrypted
|
||||
}
|
||||
|
||||
{
|
||||
char message[256];
|
||||
|
||||
recv(val(), message, 256, val()); // GOOD: `message` is not a password
|
||||
}
|
||||
}
|
||||
|
||||
void test_dataflow(const char *password1)
|
||||
{
|
||||
{
|
||||
const char *ptr = password1;
|
||||
|
||||
send(val(), ptr, strlen(ptr), val()); // BAD: `password` is sent plaintext
|
||||
}
|
||||
|
||||
{
|
||||
char password[256];
|
||||
char *ptr = password;
|
||||
|
||||
recv(val(), ptr, 256, val()); // BAD: `password` is received plaintext
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[256];
|
||||
|
||||
recv(val(), buffer, 256, val()); // BAD: `password` is received plaintext [NOT DETECTED]
|
||||
|
||||
char *password = buffer;
|
||||
}
|
||||
}
|
||||
|
||||
void test_read()
|
||||
{
|
||||
{
|
||||
char password[256];
|
||||
int fd = val();
|
||||
|
||||
read(fd, password, 256); // BAD: `password` is received plaintext
|
||||
}
|
||||
|
||||
{
|
||||
char password[256];
|
||||
int fd = STDIN_FILENO;
|
||||
|
||||
read(fd, password, 256); // GOOD: `password` is received from stdin, not a network socket
|
||||
}
|
||||
}
|
||||
|
||||
void my_recv(char *buffer, size_t bufferSize)
|
||||
{
|
||||
recv(val(), buffer, bufferSize, val());
|
||||
}
|
||||
|
||||
const char *id(const char *buffer)
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char *global_password;
|
||||
|
||||
char *get_global_str()
|
||||
{
|
||||
return global_password;
|
||||
}
|
||||
|
||||
void test_interprocedural(const char *password1)
|
||||
{
|
||||
{
|
||||
char password[256];
|
||||
|
||||
my_recv(password, 256); // BAD: `password` is received plaintext [detected on line 108]
|
||||
}
|
||||
|
||||
{
|
||||
const char *ptr = id(password1);
|
||||
|
||||
send(val(), ptr, strlen(ptr), val()); // BAD: `password1` is sent plaintext
|
||||
}
|
||||
|
||||
{
|
||||
char *data = get_global_str();
|
||||
|
||||
send(val(), data, strlen(data), val()); // BAD: `global_password` is sent plaintext
|
||||
}
|
||||
}
|
||||
|
||||
char *strncpy(char *s1, const char *s2, size_t n);
|
||||
|
||||
void test_taint(const char *password)
|
||||
{
|
||||
{
|
||||
char buffer[16];
|
||||
|
||||
strncpy(buffer, password, 16);
|
||||
buffer[15] = 0;
|
||||
send(val(), buffer, 16, val()); // BAD: `password` is (partially) sent plaintext
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,2 @@
|
|||
description: Non-functional change to dbscheme comments
|
||||
compatibility: full
|
|
@ -0,0 +1,2 @@
|
|||
lgtm,codescanning
|
||||
* Discards in tuple patterns, for example `(_, string s)`, are no longer flagged by the query "Constant condition".
|
|
@ -0,0 +1,2 @@
|
|||
lgtm,codescanning
|
||||
* `using` declarations are no longer flagged by the query "Useless assignment to local variable".
|
|
@ -59,8 +59,15 @@ namespace Semmle.Extraction.CSharp.Populators
|
|||
return;
|
||||
}
|
||||
|
||||
var entryPoint = Cx.Compilation.GetEntryPoint(System.Threading.CancellationToken.None)!;
|
||||
var entryPoint = Cx.Compilation.GetEntryPoint(System.Threading.CancellationToken.None);
|
||||
var entryMethod = Method.Create(Cx, entryPoint);
|
||||
if (entryMethod is null)
|
||||
{
|
||||
Cx.ExtractionError("No entry method found. Skipping the extraction of global statements.",
|
||||
null, Cx.CreateLocation(globalStatements[0].GetLocation()), null, Severity.Info);
|
||||
return;
|
||||
}
|
||||
|
||||
var block = GlobalStatementsBlock.Create(Cx, entryMethod);
|
||||
|
||||
for (var i = 0; i < globalStatements.Count; i++)
|
||||
|
|
|
@ -25,7 +25,7 @@ class Attributable extends @attributable {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -33,7 +33,7 @@ class Container extends @container {
|
|||
/**
|
||||
* Gets a URL representing the location of this container.
|
||||
*
|
||||
* For more information see [Providing URLs](https://help.semmle.com/QL/learn-ql/ql/locations.html#providing-urls).
|
||||
* For more information see [Providing URLs](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls).
|
||||
*/
|
||||
string getURL() { none() }
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ class Location extends @location {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -24,7 +24,7 @@ class XMLLocatable extends @xmllocatable, TXMLLocatable {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -30,7 +30,7 @@ abstract class Bound extends TBound {
|
|||
* The location spans column `sc` of line `sl` to
|
||||
* column `ec` of line `el` in file `path`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0
|
||||
|
|
|
@ -3248,7 +3248,7 @@ class PathNode extends TPathNode {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
@ -4033,7 +4033,7 @@ private module FlowExploration {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -3248,7 +3248,7 @@ class PathNode extends TPathNode {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
@ -4033,7 +4033,7 @@ private module FlowExploration {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -3248,7 +3248,7 @@ class PathNode extends TPathNode {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
@ -4033,7 +4033,7 @@ private module FlowExploration {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -3248,7 +3248,7 @@ class PathNode extends TPathNode {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
@ -4033,7 +4033,7 @@ private module FlowExploration {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -3248,7 +3248,7 @@ class PathNode extends TPathNode {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
@ -4033,7 +4033,7 @@ private module FlowExploration {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -58,7 +58,7 @@ class Node extends TNode {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -186,10 +186,17 @@ module Private {
|
|||
TArgumentSummaryComponent(int i) { parameterPosition(i) } or
|
||||
TReturnSummaryComponent(ReturnKind rk)
|
||||
|
||||
private TSummaryComponent thisParam() {
|
||||
result = TParameterSummaryComponent(instanceParameterPosition())
|
||||
}
|
||||
|
||||
newtype TSummaryComponentStack =
|
||||
TSingletonSummaryComponentStack(SummaryComponent c) or
|
||||
TConsSummaryComponentStack(SummaryComponent head, SummaryComponentStack tail) {
|
||||
tail.(RequiredSummaryComponentStack).required(head)
|
||||
or
|
||||
tail.(RequiredSummaryComponentStack).required(TParameterSummaryComponent(_)) and
|
||||
head = thisParam()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
|
@ -198,21 +205,63 @@ module Private {
|
|||
boolean preservesValue
|
||||
) {
|
||||
c.propagatesFlow(input, output, preservesValue)
|
||||
or
|
||||
// observe side effects of callbacks on input arguments
|
||||
c.propagatesFlow(output, input, preservesValue) and
|
||||
preservesValue = true and
|
||||
isCallbackParameter(input) and
|
||||
isContentOfArgument(output)
|
||||
or
|
||||
// flow from the receiver of a callback into the instance-parameter
|
||||
exists(SummaryComponentStack s, SummaryComponentStack callbackRef |
|
||||
c.propagatesFlow(s, _, _) or c.propagatesFlow(_, s, _)
|
||||
|
|
||||
callbackRef = s.drop(_) and
|
||||
(isCallbackParameter(callbackRef) or callbackRef.head() = TReturnSummaryComponent(_)) and
|
||||
input = callbackRef.tail() and
|
||||
output = TConsSummaryComponentStack(thisParam(), input) and
|
||||
preservesValue = true
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isCallbackParameter(SummaryComponentStack s) {
|
||||
s.head() = TParameterSummaryComponent(_) and exists(s.tail())
|
||||
}
|
||||
|
||||
private predicate isContentOfArgument(SummaryComponentStack s) {
|
||||
s.head() = TContentSummaryComponent(_) and isContentOfArgument(s.tail())
|
||||
or
|
||||
s = TSingletonSummaryComponentStack(TArgumentSummaryComponent(_))
|
||||
}
|
||||
|
||||
private predicate outputState(SummarizedCallable c, SummaryComponentStack s) {
|
||||
summary(c, _, s, _)
|
||||
or
|
||||
exists(SummaryComponentStack out |
|
||||
outputState(c, out) and
|
||||
out.head() = TContentSummaryComponent(_) and
|
||||
s = out.tail()
|
||||
)
|
||||
or
|
||||
// Add the argument node corresponding to the requested post-update node
|
||||
inputState(c, s) and isCallbackParameter(s)
|
||||
}
|
||||
|
||||
private predicate inputState(SummarizedCallable c, SummaryComponentStack s) {
|
||||
summary(c, s, _, _)
|
||||
or
|
||||
exists(SummaryComponentStack inp | inputState(c, inp) and s = inp.tail())
|
||||
or
|
||||
exists(SummaryComponentStack out |
|
||||
outputState(c, out) and
|
||||
out.head() = TParameterSummaryComponent(_) and
|
||||
s = out.tail()
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TSummaryNodeState =
|
||||
TSummaryNodeInputState(SummaryComponentStack s) {
|
||||
exists(SummaryComponentStack input |
|
||||
summary(_, input, _, _) and
|
||||
s = input.drop(_)
|
||||
)
|
||||
} or
|
||||
TSummaryNodeOutputState(SummaryComponentStack s) {
|
||||
exists(SummaryComponentStack output |
|
||||
summary(_, _, output, _) and
|
||||
s = output.drop(_)
|
||||
)
|
||||
}
|
||||
TSummaryNodeInputState(SummaryComponentStack s) { inputState(_, s) } or
|
||||
TSummaryNodeOutputState(SummaryComponentStack s) { outputState(_, s) }
|
||||
|
||||
/**
|
||||
* A state used to break up (complex) flow summaries into atomic flow steps.
|
||||
|
@ -238,20 +287,14 @@ module Private {
|
|||
pragma[nomagic]
|
||||
predicate isInputState(SummarizedCallable c, SummaryComponentStack s) {
|
||||
this = TSummaryNodeInputState(s) and
|
||||
exists(SummaryComponentStack input |
|
||||
summary(c, input, _, _) and
|
||||
s = input.drop(_)
|
||||
)
|
||||
inputState(c, s)
|
||||
}
|
||||
|
||||
/** Holds if this state is a valid output state for `c`. */
|
||||
pragma[nomagic]
|
||||
predicate isOutputState(SummarizedCallable c, SummaryComponentStack s) {
|
||||
this = TSummaryNodeOutputState(s) and
|
||||
exists(SummaryComponentStack output |
|
||||
summary(c, _, output, _) and
|
||||
s = output.drop(_)
|
||||
)
|
||||
outputState(c, s)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this state. */
|
||||
|
@ -331,19 +374,12 @@ module Private {
|
|||
receiver = summaryNodeInputState(c, s.drop(1))
|
||||
}
|
||||
|
||||
private Node pre(Node post) {
|
||||
summaryPostUpdateNode(post, result)
|
||||
or
|
||||
not summaryPostUpdateNode(post, _) and
|
||||
result = post
|
||||
}
|
||||
|
||||
private predicate callbackInput(
|
||||
SummarizedCallable c, SummaryComponentStack s, Node receiver, int i
|
||||
) {
|
||||
any(SummaryNodeState state).isOutputState(c, s) and
|
||||
s.head() = TParameterSummaryComponent(i) and
|
||||
receiver = pre(summaryNodeOutputState(c, s.drop(1)))
|
||||
receiver = summaryNodeInputState(c, s.drop(1))
|
||||
}
|
||||
|
||||
/** Holds if a call targeting `receiver` should be synthesized inside `c`. */
|
||||
|
@ -395,7 +431,7 @@ module Private {
|
|||
or
|
||||
exists(int i | head = TParameterSummaryComponent(i) |
|
||||
result =
|
||||
getCallbackParameterType(getNodeType(summaryNodeOutputState(pragma[only_bind_out](c),
|
||||
getCallbackParameterType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
|
||||
s.drop(1))), i)
|
||||
)
|
||||
)
|
||||
|
@ -421,10 +457,16 @@ module Private {
|
|||
}
|
||||
|
||||
/** Holds if summary node `post` is a post-update node with pre-update node `pre`. */
|
||||
predicate summaryPostUpdateNode(Node post, ParamNode pre) {
|
||||
predicate summaryPostUpdateNode(Node post, Node pre) {
|
||||
exists(SummarizedCallable c, int i |
|
||||
isParameterPostUpdate(post, c, i) and
|
||||
pre.isParameterOf(c, i)
|
||||
pre.(ParamNode).isParameterOf(c, i)
|
||||
)
|
||||
or
|
||||
exists(SummarizedCallable callable, SummaryComponentStack s |
|
||||
callbackInput(callable, s, _, _) and
|
||||
pre = summaryNodeOutputState(callable, s) and
|
||||
post = summaryNodeInputState(callable, s)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -462,7 +504,11 @@ module Private {
|
|||
// for `StringBuilder.append(x)` with a specified value flow from qualifier to
|
||||
// return value and taint flow from argument 0 to the qualifier, then this
|
||||
// allows us to infer taint flow from argument 0 to the return value.
|
||||
summaryPostUpdateNode(pred, succ) and preservesValue = true
|
||||
succ instanceof ParamNode and summaryPostUpdateNode(pred, succ) and preservesValue = true
|
||||
or
|
||||
// Similarly we would like to chain together summaries where values get passed
|
||||
// into callbacks along the way.
|
||||
pred instanceof ArgNode and summaryPostUpdateNode(succ, pred) and preservesValue = true
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,6 +16,9 @@ private import semmle.code.csharp.dataflow.ExternalFlow
|
|||
/** Holds is `i` is a valid parameter position. */
|
||||
predicate parameterPosition(int i) { i in [-1 .. any(Parameter p).getPosition()] }
|
||||
|
||||
/** Gets the parameter position of the instance parameter. */
|
||||
int instanceParameterPosition() { none() } // disables implicit summary flow to `this` for callbacks
|
||||
|
||||
/** Gets the synthesized summary data-flow node for the given values. */
|
||||
Node summaryNode(SummarizedCallable c, SummaryNodeState state) { result = TSummaryNode(c, state) }
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ class SuppressionScope extends @commentline {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -123,6 +123,8 @@ class ConstantMatchingCondition extends ConstantCondition {
|
|||
se.getCase(i).getPattern() = this.(DiscardExpr) and
|
||||
i > 0
|
||||
)
|
||||
or
|
||||
this = any(PositionalPatternExpr ppe).getPattern(_)
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
|
|
|
@ -72,7 +72,8 @@ predicate mayEscape(LocalVariable v) {
|
|||
|
||||
class RelevantDefinition extends AssignableDefinition {
|
||||
RelevantDefinition() {
|
||||
this instanceof AssignableDefinitions::AssignmentDefinition
|
||||
this.(AssignableDefinitions::AssignmentDefinition).getAssignment() =
|
||||
any(Assignment a | not a = any(UsingDeclStmt uds).getAVariableDeclExpr())
|
||||
or
|
||||
this instanceof AssignableDefinitions::MutationDefinition
|
||||
or
|
||||
|
|
|
@ -13,7 +13,7 @@ abstract class Use extends @type_mention_parent {
|
|||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
|
|
|
@ -45,6 +45,9 @@ edges
|
|||
| ExternalFlow.cs:91:30:91:30 | SSA def(i) : Int32 | ExternalFlow.cs:92:18:92:18 | (...) ... |
|
||||
| ExternalFlow.cs:121:46:121:46 | s : Object | ExternalFlow.cs:60:35:60:35 | o : Object |
|
||||
| ExternalFlow.cs:123:34:123:41 | elements [element] : Object | ExternalFlow.cs:72:23:72:23 | o : Object |
|
||||
| ExternalFlow.cs:123:34:123:41 | elements [element] : Object | ExternalFlow.cs:72:23:72:23 | o : Object |
|
||||
| ExternalFlow.cs:123:34:123:41 | elements [element] : Object | ExternalFlow.cs:123:34:123:41 | elements [element] : Object |
|
||||
| ExternalFlow.cs:123:34:123:41 | elements [element] : Object | ExternalFlow.cs:123:34:123:41 | elements [element] : Object |
|
||||
nodes
|
||||
| ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
|
||||
| ExternalFlow.cs:10:18:10:33 | call to method StepArgRes | semmle.label | call to method StepArgRes |
|
||||
|
@ -106,6 +109,7 @@ nodes
|
|||
| ExternalFlow.cs:92:18:92:18 | (...) ... | semmle.label | (...) ... |
|
||||
| ExternalFlow.cs:121:46:121:46 | s : Object | semmle.label | s : Object |
|
||||
| ExternalFlow.cs:123:34:123:41 | elements [element] : Object | semmle.label | elements [element] : Object |
|
||||
| ExternalFlow.cs:123:34:123:41 | elements [element] : Object | semmle.label | elements [element] : Object |
|
||||
subpaths
|
||||
invalidModelRow
|
||||
#select
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче