Compare commits

..

1 Commits

Author SHA1 Message Date
Calum Grant
2b4935cd41 C++: Add test for implicit this 2023-10-10 09:42:02 +01:00
452 changed files with 1751 additions and 26656 deletions

View File

@@ -17,10 +17,3 @@ updates:
ignore:
- dependency-name: '*'
update-types: ['version-update:semver-patch', 'version-update:semver-minor']
- package-ecosystem: "gomod"
directory: "go/extractor"
schedule:
interval: "daily"
reviewers:
- "github/codeql-go"

View File

@@ -29,9 +29,9 @@ jobs:
# run with --check-only if running in a PR (github.sha != main)
if : ${{ github.event_name == 'pull_request' }}
shell: bash
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
- name: compile queries - full
# do full compile if running on main - this populates the cache
if : ${{ github.event_name != 'pull_request' }}
shell: bash
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"

View File

@@ -498,6 +498,22 @@
"ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModelsExtensions.qll",
"python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModelsExtensions.qll"
],
"TaintedFormatStringQuery Ruby/JS": [
"javascript/ql/lib/semmle/javascript/security/dataflow/TaintedFormatStringQuery.qll",
"ruby/ql/lib/codeql/ruby/security/TaintedFormatStringQuery.qll"
],
"TaintedFormatStringCustomizations Ruby/JS": [
"javascript/ql/lib/semmle/javascript/security/dataflow/TaintedFormatStringCustomizations.qll",
"ruby/ql/lib/codeql/ruby/security/TaintedFormatStringCustomizations.qll"
],
"HttpToFileAccessQuery JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessQuery.qll",
"ruby/ql/lib/codeql/ruby/security/HttpToFileAccessQuery.qll"
],
"HttpToFileAccessCustomizations JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessCustomizations.qll",
"ruby/ql/lib/codeql/ruby/security/HttpToFileAccessCustomizations.qll"
],
"Typo database": [
"javascript/ql/src/Expressions/TypoDatabase.qll",
"ql/ql/src/codeql_ql/style/TypoDatabase.qll"

View File

@@ -1,13 +1,3 @@
## 0.10.0
### Minor Analysis Improvements
* Functions that do not return due to calling functions that don't return (e.g. `exit`) are now detected as
non-returning in the IR and dataflow.
* Treat functions that reach the end of the function as returning in the IR.
They used to be treated as unreachable but it is allowed in C.
* The `DataFlow::asDefiningArgument` predicate now takes its argument from the range starting at `1` instead of `2`. Queries that depend on the single-parameter version of `DataFlow::asDefiningArgument` should have their arguments updated accordingly.
## 0.9.3
No user-facing changes.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The `DataFlow::asDefiningArgument` predicate now takes its argument from the range starting at `1` instead of `2`. Queries that depend on the single-parameter version of `DataFlow::asDefiningArgument` should have their arguments updated accordingly.

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* Treat functions that reach the end of the function as returning in the IR.
They used to be treated as unreachable but it is allowed in C.

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* Functions that do not return due to calling functions that don't return (e.g. `exit`) are now detected as
non-returning in the IR and dataflow.

View File

@@ -1,9 +0,0 @@
## 0.10.0
### Minor Analysis Improvements
* Functions that do not return due to calling functions that don't return (e.g. `exit`) are now detected as
non-returning in the IR and dataflow.
* Treat functions that reach the end of the function as returning in the IR.
They used to be treated as unreachable but it is allowed in C.
* The `DataFlow::asDefiningArgument` predicate now takes its argument from the range starting at `1` instead of `2`. Queries that depend on the single-parameter version of `DataFlow::asDefiningArgument` should have their arguments updated accordingly.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.10.0
lastReleaseVersion: 0.9.3

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 0.10.1-dev
version: 0.10.0-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp

View File

@@ -73,10 +73,6 @@ private int isSource(Expr bufferExpr, Element why) {
)
}
/** Same as `getBufferSize`, but with the `why` column projected away to prevent large duplications. */
pragma[nomagic]
int getBufferSizeProj(Expr bufferExpr) { result = getBufferSize(bufferExpr, _) }
/**
* Get the size in bytes of the buffer pointed to by an expression (if this can be determined).
*/
@@ -91,7 +87,7 @@ int getBufferSize(Expr bufferExpr, Element why) {
why = bufferVar and
parentPtr = bufferExpr.(VariableAccess).getQualifier() and
parentPtr.getTarget().getUnspecifiedType().(PointerType).getBaseType() = parentClass and
result = getBufferSizeProj(parentPtr) + bufferSize - parentClass.getSize()
result = getBufferSize(parentPtr, _) + bufferSize - parentClass.getSize()
|
if exists(bufferVar.getType().getSize())
then bufferSize = bufferVar.getType().getSize()
@@ -99,6 +95,7 @@ int getBufferSize(Expr bufferExpr, Element why) {
)
or
// dataflow (all sources must be the same size)
result = unique(Expr def | DataFlow::localExprFlowStep(def, bufferExpr) | getBufferSizeProj(def)) and
result = unique(Expr def | DataFlow::localExprFlowStep(def, bufferExpr) | getBufferSize(def, _)) and
// find reason
exists(Expr def | DataFlow::localExprFlowStep(def, bufferExpr) | exists(getBufferSize(def, why)))
}

View File

@@ -555,7 +555,7 @@ predicate instructionForFullyConvertedCall(Instruction instr, CallInstruction ca
}
/** Holds if `node` represents the output node for `call`. */
predicate simpleOutNode(Node node, CallInstruction call) {
private predicate simpleOutNode(Node node, CallInstruction call) {
operandForFullyConvertedCall(node.asOperand(), call)
or
instructionForFullyConvertedCall(node.asInstruction(), call)

View File

@@ -6,7 +6,6 @@
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.DataFlow
private import DataFlowUtil
private import DataFlowPrivate
private import SsaInternals as Ssa
/**
@@ -36,7 +35,7 @@ DataFlow::Node callInput(CallInstruction call, FunctionInput input) {
*/
Node callOutput(CallInstruction call, FunctionOutput output) {
// The return value
simpleOutNode(result, call) and
result.asInstruction() = call and
output.isReturnValue()
or
// The side effect of a call on the value pointed to by an argument or qualifier
@@ -83,7 +82,7 @@ Node callOutput(CallInstruction call, FunctionOutput output, int d) {
// If there isn't an indirect out node for the call with indirection `d` then
// we conflate this with the underlying `CallInstruction`.
not exists(getIndirectReturnOutNode(call, d)) and
n = result
n.asInstruction() = result.asInstruction()
or
// The side effect of a call on the value pointed to by an argument or qualifier
exists(Operand operand, int indirectionIndex |

View File

@@ -1,16 +1,3 @@
## 0.8.0
### Query Metadata Changes
* The `cpp/double-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.
* The `cpp/use-after-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.
### Minor Analysis Improvements
* The queries `cpp/double-free` and `cpp/use-after-free` find fewer false positives
in cases where a non-returning function is called.
* The number of duplicated dataflow paths reported by queries has been significantly reduced.
## 0.7.5
No user-facing changes.

View File

@@ -82,20 +82,36 @@ module ValidState {
* library will perform, and visit all the places where the size argument is modified.
* 2. Once that dataflow traversal is done, we accumulate the offsets added at each places
* where the offset is modified (see `validStateImpl`).
*
* Because we want to guarantee that each place where we modify the offset has a `PathNode`
* we "flip" a boolean flow state in each `isAdditionalFlowStep`. This ensures that the node
* has a corresponding `PathNode`.
*/
private module ValidStateConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { hasSize(_, source, _) }
private module ValidStateConfig implements DataFlow::StateConfigSig {
class FlowState = boolean;
predicate isSink(DataFlow::Node sink) { isSinkPairImpl(_, _, sink, _, _) }
predicate isSource(DataFlow::Node source, FlowState state) {
hasSize(_, source, _) and
state = false
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
isAdditionalFlowStep2(node1, node2, _)
predicate isSink(DataFlow::Node sink, FlowState state) {
isSinkPairImpl(_, _, sink, _, _) and
state = [false, true]
}
predicate isAdditionalFlowStep(
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
) {
isAdditionalFlowStep2(node1, node2, _) and
state1 = [false, true] and
state2 = state1.booleanNot()
}
predicate includeHiddenNodes() { any() }
}
private import DataFlow::Global<ValidStateConfig>
private import DataFlow::GlobalWithState<ValidStateConfig>
private predicate inLoop(PathNode n) { n.getASuccessor+() = n }

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The number of duplicated dataflow paths reported by queries has been significantly reduced.

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* The queries `cpp/double-free` and `cpp/use-after-free` find fewer false positives
in cases where a non-returning function is called.

View File

@@ -0,0 +1,4 @@
---
category: queryMetadata
---
* The `cpp/double-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.

View File

@@ -0,0 +1,4 @@
---
category: queryMetadata
---
* The `cpp/use-after-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.

View File

@@ -1,12 +0,0 @@
## 0.8.0
### Query Metadata Changes
* The `cpp/double-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.
* The `cpp/use-after-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.
### Minor Analysis Improvements
* The queries `cpp/double-free` and `cpp/use-after-free` find fewer false positives
in cases where a non-returning function is called.
* The number of duplicated dataflow paths reported by queries has been significantly reduced.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.8.0
lastReleaseVersion: 0.7.5

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 0.8.1-dev
version: 0.8.0-dev
groups:
- cpp
- queries

View File

@@ -1,3 +1,3 @@
failures
astTypeBugs
irTypeBugs
failures

View File

@@ -0,0 +1,9 @@
class TestImplicitThis
{
public:
int field;
int get() const {
return field + this->field + get() + this->get();
}
};

View File

@@ -0,0 +1,2 @@
| this.cpp:7:16:7:20 | this |
| this.cpp:7:38:7:40 | this |

View File

@@ -0,0 +1,5 @@
import cpp
from ThisExpr te
where te.isCompilerGenerated()
select te

View File

@@ -16,18 +16,18 @@ edges
| 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:106:20:106:38 | call to getenv | test.cpp:107:33:107:36 | path indirection |
| test.cpp:106:20:106:25 | call to getenv | test.cpp:107:33:107:36 | path indirection |
| test.cpp:106:20:106:38 | call to getenv indirection | 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:113:20:113:38 | call to getenv | test.cpp:114:19:114:22 | path indirection |
| test.cpp:113:20:113:25 | call to getenv | test.cpp:114:19:114:22 | path indirection |
| test.cpp:113:20:113:38 | call to getenv indirection | test.cpp:114:19:114:22 | path indirection |
| test.cpp:114:10:114:23 | call to operator+ | test.cpp:114:25:114:29 | call to c_str indirection |
| test.cpp:114:10:114:23 | call to operator+ | test.cpp:114:25:114:29 | call to c_str indirection |
| test.cpp:114:17:114:17 | call to operator+ | test.cpp:114:10:114:23 | call to operator+ |
| test.cpp:114:19:114:22 | path indirection | test.cpp:114:10:114:23 | call to operator+ |
| test.cpp:114:19:114:22 | path indirection | test.cpp:114:17:114:17 | call to operator+ |
| test.cpp:119:20:119:38 | call to getenv | test.cpp:120:19:120:22 | path indirection |
| test.cpp:119:20:119:25 | call to getenv | test.cpp:120:19:120:22 | path indirection |
| test.cpp:119:20:119:38 | call to getenv indirection | test.cpp:120:19:120:22 | path indirection |
| test.cpp:120:17:120:17 | call to operator+ | 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 to operator+ |
@@ -91,12 +91,12 @@ nodes
| 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:38 | call to getenv | semmle.label | call to getenv |
| test.cpp:106:20:106:25 | call to getenv | semmle.label | call to getenv |
| test.cpp:106:20:106:38 | call to getenv indirection | semmle.label | call to getenv indirection |
| 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:38 | call to getenv | semmle.label | call to getenv |
| test.cpp:113:20:113:25 | call to getenv | semmle.label | call to getenv |
| test.cpp:113:20:113:38 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:114:10:114:23 | call to operator+ | semmle.label | call to operator+ |
| test.cpp:114:10:114:23 | call to operator+ | semmle.label | call to operator+ |
@@ -104,7 +104,7 @@ nodes
| 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:114:25:114:29 | call to c_str indirection | semmle.label | call to c_str indirection |
| test.cpp:119:20:119:38 | call to getenv | semmle.label | call to getenv |
| test.cpp:119:20:119:25 | call to getenv | semmle.label | call to getenv |
| test.cpp:119:20:119:38 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:120:10:120:30 | call to data indirection | semmle.label | call to data indirection |
| test.cpp:120:17:120:17 | call to operator+ | semmle.label | call to operator+ |
@@ -158,13 +158,13 @@ subpaths
| 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:38 | 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:38 | call to getenv | user input (an environment variable) | test.cpp:107:31:107:31 | call to operator+ | call to operator+ |
| 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:108:18:108:22 | call to c_str | test.cpp:106:20:106:38 | call to getenv indirection | 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:38 | call to getenv indirection | 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:38 | 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:38 | call to getenv | user input (an environment variable) | test.cpp:114:10:114:23 | call to operator+ | call to operator+ |
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:38 | 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:38 | call to getenv | user input (an environment variable) | test.cpp:114:17:114:17 | 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:10:114:23 | 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 to operator+ | call to operator+ |
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:38 | call to getenv indirection | 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:38 | call to getenv indirection | user input (an environment variable) | test.cpp:114:10:114:23 | call to operator+ | call to operator+ |
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:38 | call to getenv indirection | 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:38 | call to getenv indirection | user input (an environment variable) | test.cpp:114:17:114:17 | call to operator+ | call to operator+ |
| test.cpp:120:25:120:28 | call to data | test.cpp:119:20:119:38 | 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:38 | call to getenv | user input (an environment variable) | test.cpp:120:17:120:17 | call to operator+ | call to operator+ |
| 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 to operator+ | call to operator+ |
| test.cpp:120:25:120:28 | call to data | test.cpp:119:20:119:38 | call to getenv indirection | 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:38 | call to getenv indirection | user input (an environment variable) | test.cpp:120:17:120:17 | call to operator+ | call to operator+ |
| 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 |
| test.cpp:183:32:183:38 | command | test.cpp:174:9:174:16 | fread output argument | test.cpp:183:32:183:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:174:9:174:16 | fread output argument | user input (string read by fread) | test.cpp:177:13:177:17 | strncat output argument | strncat output argument |

View File

@@ -5,33 +5,33 @@ edges
| test.cpp:39:27:39:30 | argv indirection | test.cpp:49:32:49:35 | size |
| test.cpp:39:27:39:30 | argv indirection | test.cpp:50:17:50:30 | size |
| test.cpp:39:27:39:30 | argv indirection | test.cpp:53:35:53:60 | ... * ... |
| test.cpp:124:18:124:31 | call to getenv | test.cpp:128:24:128:41 | ... * ... |
| test.cpp:124:18:124:23 | call to getenv | test.cpp:128:24:128:41 | ... * ... |
| test.cpp:124:18:124:31 | call to getenv indirection | test.cpp:128:24:128:41 | ... * ... |
| test.cpp:133:19:133:32 | call to getenv | test.cpp:135:10:135:27 | ... * ... |
| test.cpp:133:19:133:24 | call to getenv | test.cpp:135:10:135:27 | ... * ... |
| test.cpp:133:19:133:32 | call to getenv indirection | test.cpp:135:10:135:27 | ... * ... |
| test.cpp:148:20:148:33 | call to getenv | test.cpp:152:11:152:28 | ... * ... |
| test.cpp:148:20:148:25 | call to getenv | test.cpp:152:11:152:28 | ... * ... |
| test.cpp:148:20:148:33 | call to getenv indirection | test.cpp:152:11:152:28 | ... * ... |
| test.cpp:209:8:209:23 | get_tainted_size indirection | test.cpp:241:9:241:24 | call to get_tainted_size |
| test.cpp:211:14:211:27 | call to getenv | test.cpp:209:8:209:23 | get_tainted_size indirection |
| test.cpp:211:14:211:19 | call to getenv | test.cpp:209:8:209:23 | get_tainted_size indirection |
| test.cpp:211:14:211:27 | call to getenv indirection | test.cpp:209:8:209:23 | get_tainted_size indirection |
| test.cpp:230:21:230:21 | s | test.cpp:231:21:231:21 | s |
| test.cpp:237:24:237:37 | call to getenv | test.cpp:239:9:239:18 | local_size |
| test.cpp:237:24:237:37 | call to getenv | test.cpp:245:11:245:20 | local_size |
| test.cpp:237:24:237:37 | call to getenv | test.cpp:247:10:247:19 | local_size |
| test.cpp:237:24:237:29 | call to getenv | test.cpp:239:9:239:18 | local_size |
| test.cpp:237:24:237:29 | call to getenv | test.cpp:245:11:245:20 | local_size |
| test.cpp:237:24:237:29 | call to getenv | test.cpp:247:10:247:19 | local_size |
| test.cpp:237:24:237:37 | call to getenv indirection | test.cpp:239:9:239:18 | local_size |
| test.cpp:237:24:237:37 | call to getenv indirection | test.cpp:245:11:245:20 | local_size |
| test.cpp:237:24:237:37 | call to getenv indirection | test.cpp:247:10:247:19 | local_size |
| test.cpp:247:10:247:19 | local_size | test.cpp:230:21:230:21 | s |
| test.cpp:250:20:250:27 | out_size | test.cpp:289:17:289:20 | get_size output argument |
| test.cpp:250:20:250:27 | out_size | test.cpp:305:18:305:21 | get_size output argument |
| test.cpp:251:18:251:31 | call to getenv | test.cpp:250:20:250:27 | out_size |
| test.cpp:251:18:251:23 | call to getenv | test.cpp:250:20:250:27 | out_size |
| test.cpp:251:18:251:31 | call to getenv indirection | test.cpp:250:20:250:27 | out_size |
| test.cpp:259:20:259:33 | call to getenv | test.cpp:263:11:263:29 | ... * ... |
| test.cpp:259:20:259:25 | call to getenv | test.cpp:263:11:263:29 | ... * ... |
| test.cpp:259:20:259:33 | call to getenv indirection | test.cpp:263:11:263:29 | ... * ... |
| test.cpp:289:17:289:20 | get_size output argument | test.cpp:291:11:291:28 | ... * ... |
| test.cpp:305:18:305:21 | get_size output argument | test.cpp:308:10:308:27 | ... * ... |
| test.cpp:353:18:353:31 | call to getenv | test.cpp:355:35:355:38 | size |
| test.cpp:353:18:353:31 | call to getenv | test.cpp:356:35:356:38 | size |
| test.cpp:353:18:353:23 | call to getenv | test.cpp:355:35:355:38 | size |
| test.cpp:353:18:353:23 | call to getenv | test.cpp:356:35:356:38 | size |
| test.cpp:353:18:353:31 | call to getenv indirection | test.cpp:355:35:355:38 | size |
| test.cpp:353:18:353:31 | call to getenv indirection | test.cpp:356:35:356:38 | size |
nodes
@@ -42,37 +42,37 @@ nodes
| test.cpp:49:32:49:35 | size | semmle.label | size |
| test.cpp:50:17:50:30 | size | semmle.label | size |
| test.cpp:53:35:53:60 | ... * ... | semmle.label | ... * ... |
| test.cpp:124:18:124:31 | call to getenv | semmle.label | call to getenv |
| test.cpp:124:18:124:23 | call to getenv | semmle.label | call to getenv |
| test.cpp:124:18:124:31 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:128:24:128:41 | ... * ... | semmle.label | ... * ... |
| test.cpp:133:19:133:32 | call to getenv | semmle.label | call to getenv |
| test.cpp:133:19:133:24 | call to getenv | semmle.label | call to getenv |
| test.cpp:133:19:133:32 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:135:10:135:27 | ... * ... | semmle.label | ... * ... |
| test.cpp:148:20:148:33 | call to getenv | semmle.label | call to getenv |
| test.cpp:148:20:148:25 | call to getenv | semmle.label | call to getenv |
| test.cpp:148:20:148:33 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:152:11:152:28 | ... * ... | semmle.label | ... * ... |
| test.cpp:209:8:209:23 | get_tainted_size indirection | semmle.label | get_tainted_size indirection |
| test.cpp:211:14:211:27 | call to getenv | semmle.label | call to getenv |
| test.cpp:211:14:211:19 | call to getenv | semmle.label | call to getenv |
| test.cpp:211:14:211:27 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:230:21:230:21 | s | semmle.label | s |
| test.cpp:231:21:231:21 | s | semmle.label | s |
| test.cpp:237:24:237:37 | call to getenv | semmle.label | call to getenv |
| test.cpp:237:24:237:29 | call to getenv | semmle.label | call to getenv |
| test.cpp:237:24:237:37 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:239:9:239:18 | local_size | semmle.label | local_size |
| test.cpp:241:9:241:24 | call to get_tainted_size | semmle.label | call to get_tainted_size |
| test.cpp:245:11:245:20 | local_size | semmle.label | local_size |
| test.cpp:247:10:247:19 | local_size | semmle.label | local_size |
| test.cpp:250:20:250:27 | out_size | semmle.label | out_size |
| test.cpp:251:18:251:31 | call to getenv | semmle.label | call to getenv |
| test.cpp:251:18:251:23 | call to getenv | semmle.label | call to getenv |
| test.cpp:251:18:251:31 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:259:20:259:33 | call to getenv | semmle.label | call to getenv |
| test.cpp:259:20:259:25 | call to getenv | semmle.label | call to getenv |
| test.cpp:259:20:259:33 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:263:11:263:29 | ... * ... | semmle.label | ... * ... |
| test.cpp:289:17:289:20 | get_size output argument | semmle.label | get_size output argument |
| test.cpp:291:11:291:28 | ... * ... | semmle.label | ... * ... |
| test.cpp:305:18:305:21 | get_size output argument | semmle.label | get_size output argument |
| test.cpp:308:10:308:27 | ... * ... | semmle.label | ... * ... |
| test.cpp:353:18:353:31 | call to getenv | semmle.label | call to getenv |
| test.cpp:353:18:353:23 | call to getenv | semmle.label | call to getenv |
| test.cpp:353:18:353:31 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:355:35:355:38 | size | semmle.label | size |
| test.cpp:356:35:356:38 | size | semmle.label | size |
@@ -84,27 +84,27 @@ subpaths
| test.cpp:49:25:49:30 | call to malloc | test.cpp:39:27:39:30 | argv indirection | test.cpp:49:32:49:35 | size | This allocation size is derived from $@ and might overflow. | test.cpp:39:27:39:30 | argv indirection | user input (a command-line argument) |
| test.cpp:50:17:50:30 | new[] | test.cpp:39:27:39:30 | argv indirection | test.cpp:50:17:50:30 | size | This allocation size is derived from $@ and might overflow. | test.cpp:39:27:39:30 | argv indirection | user input (a command-line argument) |
| test.cpp:53:21:53:27 | call to realloc | test.cpp:39:27:39:30 | argv indirection | test.cpp:53:35:53:60 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:39:27:39:30 | argv indirection | user input (a command-line argument) |
| test.cpp:128:17:128:22 | call to malloc | test.cpp:124:18:124:31 | call to getenv | test.cpp:128:24:128:41 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:124:18:124:31 | call to getenv | user input (an environment variable) |
| test.cpp:128:17:128:22 | call to malloc | test.cpp:124:18:124:23 | call to getenv | test.cpp:128:24:128:41 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:124:18:124:23 | call to getenv | user input (an environment variable) |
| test.cpp:128:17:128:22 | call to malloc | test.cpp:124:18:124:31 | call to getenv indirection | test.cpp:128:24:128:41 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:124:18:124:31 | call to getenv indirection | user input (an environment variable) |
| test.cpp:135:3:135:8 | call to malloc | test.cpp:133:19:133:32 | call to getenv | test.cpp:135:10:135:27 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:133:19:133:32 | call to getenv | user input (an environment variable) |
| test.cpp:135:3:135:8 | call to malloc | test.cpp:133:19:133:24 | call to getenv | test.cpp:135:10:135:27 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:133:19:133:24 | call to getenv | user input (an environment variable) |
| test.cpp:135:3:135:8 | call to malloc | test.cpp:133:19:133:32 | call to getenv indirection | test.cpp:135:10:135:27 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:133:19:133:32 | call to getenv indirection | user input (an environment variable) |
| test.cpp:152:4:152:9 | call to malloc | test.cpp:148:20:148:33 | call to getenv | test.cpp:152:11:152:28 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:148:20:148:33 | call to getenv | user input (an environment variable) |
| test.cpp:152:4:152:9 | call to malloc | test.cpp:148:20:148:25 | call to getenv | test.cpp:152:11:152:28 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:148:20:148:25 | call to getenv | user input (an environment variable) |
| test.cpp:152:4:152:9 | call to malloc | test.cpp:148:20:148:33 | call to getenv indirection | test.cpp:152:11:152:28 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:148:20:148:33 | call to getenv indirection | user input (an environment variable) |
| test.cpp:231:14:231:19 | call to malloc | test.cpp:237:24:237:37 | call to getenv | test.cpp:231:21:231:21 | s | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:37 | call to getenv | user input (an environment variable) |
| test.cpp:231:14:231:19 | call to malloc | test.cpp:237:24:237:29 | call to getenv | test.cpp:231:21:231:21 | s | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:29 | call to getenv | user input (an environment variable) |
| test.cpp:231:14:231:19 | call to malloc | test.cpp:237:24:237:37 | call to getenv indirection | test.cpp:231:21:231:21 | s | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:37 | call to getenv indirection | user input (an environment variable) |
| test.cpp:239:2:239:7 | call to malloc | test.cpp:237:24:237:37 | call to getenv | test.cpp:239:9:239:18 | local_size | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:37 | call to getenv | user input (an environment variable) |
| test.cpp:239:2:239:7 | call to malloc | test.cpp:237:24:237:29 | call to getenv | test.cpp:239:9:239:18 | local_size | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:29 | call to getenv | user input (an environment variable) |
| test.cpp:239:2:239:7 | call to malloc | test.cpp:237:24:237:37 | call to getenv indirection | test.cpp:239:9:239:18 | local_size | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:37 | call to getenv indirection | user input (an environment variable) |
| test.cpp:241:2:241:7 | call to malloc | test.cpp:211:14:211:27 | call to getenv | test.cpp:241:9:241:24 | call to get_tainted_size | This allocation size is derived from $@ and might overflow. | test.cpp:211:14:211:27 | call to getenv | user input (an environment variable) |
| test.cpp:241:2:241:7 | call to malloc | test.cpp:211:14:211:19 | call to getenv | test.cpp:241:9:241:24 | call to get_tainted_size | This allocation size is derived from $@ and might overflow. | test.cpp:211:14:211:19 | call to getenv | user input (an environment variable) |
| test.cpp:241:2:241:7 | call to malloc | test.cpp:211:14:211:27 | call to getenv indirection | test.cpp:241:9:241:24 | call to get_tainted_size | This allocation size is derived from $@ and might overflow. | test.cpp:211:14:211:27 | call to getenv indirection | user input (an environment variable) |
| test.cpp:245:2:245:9 | call to my_alloc | test.cpp:237:24:237:37 | call to getenv | test.cpp:245:11:245:20 | local_size | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:37 | call to getenv | user input (an environment variable) |
| test.cpp:245:2:245:9 | call to my_alloc | test.cpp:237:24:237:29 | call to getenv | test.cpp:245:11:245:20 | local_size | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:29 | call to getenv | user input (an environment variable) |
| test.cpp:245:2:245:9 | call to my_alloc | test.cpp:237:24:237:37 | call to getenv indirection | test.cpp:245:11:245:20 | local_size | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:37 | call to getenv indirection | user input (an environment variable) |
| test.cpp:263:4:263:9 | call to malloc | test.cpp:259:20:259:33 | call to getenv | test.cpp:263:11:263:29 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:259:20:259:33 | call to getenv | user input (an environment variable) |
| test.cpp:263:4:263:9 | call to malloc | test.cpp:259:20:259:25 | call to getenv | test.cpp:263:11:263:29 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:259:20:259:25 | call to getenv | user input (an environment variable) |
| test.cpp:263:4:263:9 | call to malloc | test.cpp:259:20:259:33 | call to getenv indirection | test.cpp:263:11:263:29 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:259:20:259:33 | call to getenv indirection | user input (an environment variable) |
| test.cpp:291:4:291:9 | call to malloc | test.cpp:251:18:251:31 | call to getenv | test.cpp:291:11:291:28 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:251:18:251:31 | call to getenv | user input (an environment variable) |
| test.cpp:291:4:291:9 | call to malloc | test.cpp:251:18:251:23 | call to getenv | test.cpp:291:11:291:28 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:251:18:251:23 | call to getenv | user input (an environment variable) |
| test.cpp:291:4:291:9 | call to malloc | test.cpp:251:18:251:31 | call to getenv indirection | test.cpp:291:11:291:28 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:251:18:251:31 | call to getenv indirection | user input (an environment variable) |
| test.cpp:308:3:308:8 | call to malloc | test.cpp:251:18:251:31 | call to getenv | test.cpp:308:10:308:27 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:251:18:251:31 | call to getenv | user input (an environment variable) |
| test.cpp:308:3:308:8 | call to malloc | test.cpp:251:18:251:23 | call to getenv | test.cpp:308:10:308:27 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:251:18:251:23 | call to getenv | user input (an environment variable) |
| test.cpp:308:3:308:8 | call to malloc | test.cpp:251:18:251:31 | call to getenv indirection | test.cpp:308:10:308:27 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:251:18:251:31 | call to getenv indirection | user input (an environment variable) |
| test.cpp:355:25:355:33 | call to MyMalloc1 | test.cpp:353:18:353:31 | call to getenv | test.cpp:355:35:355:38 | size | This allocation size is derived from $@ and might overflow. | test.cpp:353:18:353:31 | call to getenv | user input (an environment variable) |
| test.cpp:355:25:355:33 | call to MyMalloc1 | test.cpp:353:18:353:23 | call to getenv | test.cpp:355:35:355:38 | size | This allocation size is derived from $@ and might overflow. | test.cpp:353:18:353:23 | call to getenv | user input (an environment variable) |
| test.cpp:355:25:355:33 | call to MyMalloc1 | test.cpp:353:18:353:31 | call to getenv indirection | test.cpp:355:35:355:38 | size | This allocation size is derived from $@ and might overflow. | test.cpp:353:18:353:31 | call to getenv indirection | user input (an environment variable) |
| test.cpp:356:25:356:33 | call to MyMalloc2 | test.cpp:353:18:353:31 | call to getenv | test.cpp:356:35:356:38 | size | This allocation size is derived from $@ and might overflow. | test.cpp:353:18:353:31 | call to getenv | user input (an environment variable) |
| test.cpp:356:25:356:33 | call to MyMalloc2 | test.cpp:353:18:353:23 | call to getenv | test.cpp:356:35:356:38 | size | This allocation size is derived from $@ and might overflow. | test.cpp:353:18:353:23 | call to getenv | user input (an environment variable) |
| test.cpp:356:25:356:33 | call to MyMalloc2 | test.cpp:353:18:353:31 | call to getenv indirection | test.cpp:356:35:356:38 | size | This allocation size is derived from $@ and might overflow. | test.cpp:353:18:353:31 | call to getenv indirection | user input (an environment variable) |

View File

@@ -1,2 +0,0 @@
description: Exclude @void_type from @value_type
compatibility: full

View File

@@ -1,2 +0,0 @@
description: Add keyset to metadata_handle
compatibility: full

View File

@@ -70,8 +70,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
foreach (var info in assemblyInfoByFileName.Values
.OrderBy(info => info.Name)
.ThenBy(info => info.NetCoreVersion ?? emptyVersion)
.ThenBy(info => info.Version ?? emptyVersion)
.ThenBy(info => info.Filename))
.ThenBy(info => info.Version ?? emptyVersion))
{
foreach (var index in info.IndexStrings)
{

View File

@@ -322,11 +322,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
}
var emptyVersion = new Version(0, 0);
sortedReferences = sortedReferences
.OrderBy(r => r.NetCoreVersion ?? emptyVersion)
.ThenBy(r => r.Version ?? emptyVersion)
.ThenBy(r => r.Filename)
.ToList();
sortedReferences = sortedReferences.OrderBy(r => r.NetCoreVersion ?? emptyVersion).ThenBy(r => r.Version ?? emptyVersion).ToList();
var finalAssemblyList = new Dictionary<string, AssemblyInfo>();

View File

@@ -13,7 +13,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
/// </summary>
internal class NugetPackages
{
private readonly string? nugetExe;
private readonly string nugetExe;
private readonly ProgressMonitor progressMonitor;
/// <summary>
@@ -36,18 +36,10 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
this.packageDirectory = packageDirectory;
this.progressMonitor = progressMonitor;
nugetExe = ResolveNugetExe(sourceDir);
packageFiles = new DirectoryInfo(sourceDir)
.EnumerateFiles("packages.config", SearchOption.AllDirectories)
.ToArray();
if (packageFiles.Length > 0)
{
nugetExe = ResolveNugetExe(sourceDir);
}
else
{
progressMonitor.LogInfo("Found no packages.config file");
}
}
/// <summary>
@@ -119,7 +111,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
string exe, args;
if (Util.Win32.IsWindows())
{
exe = nugetExe!;
exe = nugetExe;
args = string.Format("install -OutputDirectory {0} {1}", packageDirectory, package);
}
else

View File

@@ -1,7 +1,3 @@
## 1.7.0
No user-facing changes.
## 1.6.5
No user-facing changes.

View File

@@ -1,3 +0,0 @@
## 1.7.0
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.7.0
lastReleaseVersion: 1.6.5

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-all
version: 1.7.1-dev
version: 1.7.0-dev
groups:
- csharp
- solorigate

View File

@@ -1,7 +1,3 @@
## 1.7.0
No user-facing changes.
## 1.6.5
No user-facing changes.

View File

@@ -1,3 +0,0 @@
## 1.7.0
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.7.0
lastReleaseVersion: 1.6.5

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-queries
version: 1.7.1-dev
version: 1.7.0-dev
groups:
- csharp
- solorigate

View File

@@ -1,3 +0,0 @@
| Program.cs:0:0:0:0 | Program.cs |
| obj/Debug/net5.0/.NETCoreApp,Version=v5.0.AssemblyAttributes.cs:0:0:0:0 | obj/Debug/net5.0/.NETCoreApp,Version=v5.0.AssemblyAttributes.cs |
| obj/Debug/net5.0/autobuild.AssemblyInfo.cs:0:0:0:0 | obj/Debug/net5.0/autobuild.AssemblyInfo.cs |

View File

@@ -1,5 +0,0 @@
import csharp
from File f
where f.fromSource()
select f

View File

@@ -1 +0,0 @@
var dummy = "dummy";

View File

@@ -1,14 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<Target Name="DeleteBinObjFolders" BeforeTargets="Clean">
<RemoveDir Directories=".\bin" />
<RemoveDir Directories=".\obj" />
</Target>
</Project>

View File

@@ -1,5 +0,0 @@
{
"sdk": {
"version": "5.0.408"
}
}

View File

@@ -1,3 +0,0 @@
from create_database_utils import *
run_codeql_database_create([], lang="csharp", extra_args=["--extractor-option=cil=false"])

View File

@@ -1,7 +1,3 @@
## 0.8.0
No user-facing changes.
## 0.7.5
No user-facing changes.

View File

@@ -1,3 +0,0 @@
## 0.8.0
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.8.0
lastReleaseVersion: 0.7.5

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-all
version: 0.8.1-dev
version: 0.8.0-dev
groups: csharp
dbscheme: semmlecode.csharp.dbscheme
extractor: csharp

View File

@@ -397,7 +397,7 @@ class NonNestedType extends ValueOrRefType {
/**
* The `void` type.
*/
class VoidType extends ValueOrRefType, @void_type {
class VoidType extends DotNet::ValueOrRefType, Type, @void_type {
override predicate hasQualifiedName(string qualifier, string name) {
qualifier = "System" and
name = "Void"

View File

@@ -456,7 +456,7 @@ case @type.kind of
@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type;
@floating_point_type = @float_type | @double_type;
@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type
| @uint_ptr_type | @tuple_type | @void_type;
| @uint_ptr_type | @tuple_type;
@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type
| @dynamic_type;
@value_or_ref_type = @value_type | @ref_type;
@@ -1292,7 +1292,7 @@ expr_argument_name(
lambda_expr_return_type(
unique int id: @lambda_expr ref,
int type_id: @type_or_ref ref);
/** CONTROL/DATA FLOW **/
@control_flow_element = @stmt | @expr;
@@ -2074,4 +2074,5 @@ cil_attribute_positional_argument(
@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property |
@callable | @value_or_ref_type | @void_type;
#keyset[entity, location]
metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref)

View File

@@ -1,2 +0,0 @@
description: Remove keyset from metadata_handle
compatibility: full

View File

@@ -1,2 +0,0 @@
description: Include @void_type in @value_type
compatibility: full

View File

@@ -1,9 +1,3 @@
## 0.8.0
### New Queries
* Added a new query, `cs/web/insecure-direct-object-reference`, to find instances of missing authorization checks for resources selected by an ID parameter.
## 0.7.5
No user-facing changes.

View File

@@ -1,5 +1,4 @@
## 0.8.0
### New Queries
* Added a new query, `cs/web/insecure-direct-object-reference`, to find instances of missing authorization checks for resources selected by an ID parameter.
---
category: newQuery
---
* Added a new query, `cs/web/insecure-direct-object-reference`, to find instances of missing authorization checks for resources selected by an ID parameter.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.8.0
lastReleaseVersion: 0.7.5

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-queries
version: 0.8.1-dev
version: 0.8.0-dev
groups:
- csharp
- queries

View File

@@ -135,5 +135,5 @@ There are two methods for using CodeQL model packs with code scanning:
For more information, see the following articles on the GitHub Docs site:
- Default setup of code scanning: `Extending CodeQL coverage with CodeQL model packs in default setup <https://docs.github.com/en/code-security/code-scanning/managing-your-code-scanning-configuration/editing-your-configuration-of-default-setup#extending-codeql-coverage-with-codeql-model-packs-in-default-setup>`__
- Advanced setup of code scanning: `Extending CodeQL coverage with CodeQL model packs <https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning#extending-codeql-coverage-with-codeql-model-packs>`__
- Advanced setup of code scanning: `Extending CodeQL coverage with CodeQL model packs <https://docs.github.com//en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning#extending-codeql-coverage-with-codeql-model-packs>`__
- CodeQL CLI setup in external CI system: `Using model packs to analyze calls to custom dependencies <https://docs.github.com/en/code-security/code-scanning/using-codeql-code-scanning-with-your-existing-ci-system/configuring-codeql-cli-in-your-ci-system#using-model-packs-to-analyze-calls-to-custom-dependencies>`__

View File

@@ -1993,10 +1993,6 @@ The following built-in predicates are members of type ``int``:
+-------------------------+-------------+----------------+----------------------------------------------------------------------------------------------------------------+
| ``toUnicode`` | string | | The result is the unicode character for the receiver seen as a unicode code point. |
+-------------------------+-------------+----------------+----------------------------------------------------------------------------------------------------------------+
| ``codePointAt`` | int | int | The result is the unicode code point at the index given by the argument. |
+-------------------------+-------------+----------------+----------------------------------------------------------------------------------------------------------------+
| ``codePointCount`` | int | int, int | The result is the number of unicode code points in the receiver between the given indices. |
+-------------------------+-------------+----------------+----------------------------------------------------------------------------------------------------------------+
The leftmost bit after ``bitShiftRightSigned`` depends on sign extension, whereas after ``bitShiftRight`` it is zero.

View File

@@ -51,7 +51,7 @@ tools: $(addsuffix $(EXE),$(addprefix tools/bin/,$(BINARIES))) tools/tokenizer.j
.PHONY: $(addsuffix $(EXE),$(addprefix tools/bin/,$(BINARIES)))
$(addsuffix $(EXE),$(addprefix tools/bin/,$(BINARIES))):
go build -C extractor -mod=vendor -o ../$@ ./cli/$(basename $(@F))
go build -mod=vendor -o $@ ./extractor/cli/$(basename $(@F))
tools-codeql: tools-$(CODEQL_PLATFORM)
@@ -61,19 +61,19 @@ tools-linux64: $(addprefix tools/linux64/,$(BINARIES))
.PHONY: $(addprefix tools/linux64/,$(BINARIES))
$(addprefix tools/linux64/,$(BINARIES)):
GOOS=linux GOARCH=amd64 go build -C extractor -mod=vendor -o ../$@ ./cli/$(@F)
GOOS=linux GOARCH=amd64 go build -mod=vendor -o $@ ./extractor/cli/$(@F)
tools-osx64: $(addprefix tools/osx64/,$(BINARIES))
.PHONY: $(addprefix tools/osx64/,$(BINARIES))
$(addprefix tools/osx64/,$(BINARIES)):
GOOS=darwin GOARCH=amd64 go build -C extractor -mod=vendor -o ../$@ ./cli/$(@F)
GOOS=darwin GOARCH=amd64 go build -mod=vendor -o $@ ./extractor/cli/$(@F)
tools-win64: $(addsuffix .exe,$(addprefix tools/win64/,$(BINARIES)))
.PHONY: $(addsuffix .exe,$(addprefix tools/win64/,$(BINARIES)))
$(addsuffix .exe,$(addprefix tools/win64/,$(BINARIES))):
env GOOS=windows GOARCH=amd64 go build -C extractor -mod=vendor -o ../$@ ./cli/$(basename $(@F))
env GOOS=windows GOARCH=amd64 go build -mod=vendor -o $@ ./extractor/cli/$(basename $(@F))
.PHONY: extractor-common extractor extractor-full
extractor-common: codeql-extractor.yml LICENSE ql/lib/go.dbscheme \

View File

@@ -1,10 +0,0 @@
module github.com/github/codeql-go/extractor
go 1.21
require (
golang.org/x/mod v0.13.0
golang.org/x/tools v0.14.0
)
require golang.org/x/sys v0.13.0 // indirect

View File

@@ -1,8 +0,0 @@
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=

10
go/go.mod Normal file
View File

@@ -0,0 +1,10 @@
module github.com/github/codeql-go
go 1.21
require (
golang.org/x/mod v0.12.0
golang.org/x/tools v0.13.0
)
require golang.org/x/sys v0.12.0 // indirect

8
go/go.sum Normal file
View File

@@ -0,0 +1,8 @@
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=

View File

@@ -1,9 +1,3 @@
## 0.7.0
### Minor Analysis Improvements
* Added Numeric and Boolean types to SQL injection sanitzers.
## 0.6.5
No user-facing changes.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added Numeric and Boolean types to SQL injection sanitzers.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Support has been added for file system access sinks in the following libraries: [net/http](https://pkg.go.dev/net/http), [Afero](https://github.com/spf13/afero), [beego](https://pkg.go.dev/github.com/astaxie/beego), [Echo](https://pkg.go.dev/github.com/labstack/echo), [Fiber](https://github.com/kataras/iris), [Gin](https://pkg.go.dev/github.com/gin-gonic/gin), [Iris](https://github.com/kataras/iris).

View File

@@ -1,5 +0,0 @@
## 0.7.0
### Minor Analysis Improvements
* Added Numeric and Boolean types to SQL injection sanitzers.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.7.0
lastReleaseVersion: 0.6.5

View File

@@ -30,7 +30,6 @@ import semmle.go.dataflow.GlobalValueNumbering
import semmle.go.dataflow.SSA
import semmle.go.dataflow.TaintTracking
import semmle.go.dataflow.TaintTracking2
import semmle.go.frameworks.Afero
import semmle.go.frameworks.Beego
import semmle.go.frameworks.BeegoOrm
import semmle.go.frameworks.Chi
@@ -39,13 +38,11 @@ import semmle.go.frameworks.Echo
import semmle.go.frameworks.ElazarlGoproxy
import semmle.go.frameworks.Email
import semmle.go.frameworks.Encoding
import semmle.go.frameworks.Fiber
import semmle.go.frameworks.Gin
import semmle.go.frameworks.Glog
import semmle.go.frameworks.GoMicro
import semmle.go.frameworks.GoRestfulHttp
import semmle.go.frameworks.Gqlgen
import semmle.go.frameworks.Iris
import semmle.go.frameworks.K8sIoApimachineryPkgRuntime
import semmle.go.frameworks.K8sIoApiCoreV1
import semmle.go.frameworks.K8sIoClientGo

View File

@@ -1,5 +1,5 @@
name: codeql/go-all
version: 0.7.1-dev
version: 0.7.0-dev
groups: go
dbscheme: go.dbscheme
extractor: go

View File

@@ -1,114 +0,0 @@
/**
* Provides classes for working with sinks and taint propagators
* from the `github.com/spf13/afero` package.
*/
import go
/**
* Provide File system access sinks of [afero](https://github.com/spf13/afero) framework
*/
module Afero {
/**
* Gets all versions of `github.com/spf13/afero`
*/
string aferoPackage() { result = package("github.com/spf13/afero", "") }
/**
* The File system access sinks of [afero](https://github.com/spf13/afero) framework methods
*/
class AferoSystemAccess extends FileSystemAccess::Range, DataFlow::CallNode {
AferoSystemAccess() {
exists(Method m |
m.hasQualifiedName(aferoPackage(), "HttpFs",
["Create", "Open", "OpenFile", "Remove", "RemoveAll"]) and
this = m.getACall()
or
m.hasQualifiedName(aferoPackage(), "RegexpFs",
["Create", "Open", "OpenFile", "Remove", "RemoveAll", "Mkdir", "MkdirAll"]) and
this = m.getACall()
or
m.hasQualifiedName(aferoPackage(), "ReadOnlyFs",
["Create", "Open", "OpenFile", "ReadDir", "ReadlinkIfPossible", "Mkdir", "MkdirAll"]) and
this = m.getACall()
or
m.hasQualifiedName(aferoPackage(), "OsFs",
[
"Create", "Open", "OpenFile", "ReadlinkIfPossible", "Remove", "RemoveAll", "Mkdir",
"MkdirAll"
]) and
this = m.getACall()
or
m.hasQualifiedName(aferoPackage(), "MemMapFs",
["Create", "Open", "OpenFile", "Remove", "RemoveAll", "Mkdir", "MkdirAll"]) and
this = m.getACall()
)
}
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
}
/**
* The File system access sinks of [afero](https://github.com/spf13/afero) framework utility functions
*
* Afero Type is basically is an wrapper around utility functions which make them like a method, look at [here](https://github.com/spf13/afero/blob/cf95922e71986c0116204b6eeb3b345a01ffd842/ioutil.go#L61)
*
* The Types that are not vulnerable: `afero.BasePathFs` and `afero.IOFS`
*/
class AferoUtilityFunctionSystemAccess extends FileSystemAccess::Range, DataFlow::CallNode {
int pathArg;
AferoUtilityFunctionSystemAccess() {
// utility functions
exists(Function f |
f.hasQualifiedName(aferoPackage(),
["WriteReader", "SafeWriteReader", "WriteFile", "ReadFile", "ReadDir"]) and
this = f.getACall() and
pathArg = 1 and
not aferoSanitizer(this.getArgument(0))
)
or
exists(Method m |
m.hasQualifiedName(aferoPackage(), "Afero",
["WriteReader", "SafeWriteReader", "WriteFile", "ReadFile", "ReadDir"]) and
this = m.getACall() and
pathArg = 0 and
not aferoSanitizer(this.getReceiver())
)
}
override DataFlow::Node getAPathArgument() { result = this.getArgument(pathArg) }
}
/**
* Holds if the Afero utility function has a first argument of a safe type like `NewBasePathFs`.
*
* e.g.
* ```
* basePathFs := afero.NewBasePathFs(osFS, "tmp")
* afero.ReadFile(basePathFs, filepath)
* ```
*/
predicate aferoSanitizer(DataFlow::Node n) {
exists(Function f |
f.hasQualifiedName(aferoPackage(), ["NewBasePathFs", "NewIOFS"]) and
TaintTracking::localTaint(f.getACall(), n)
)
}
/**
* Holds if there is a dataflow node from n1 to n2 when initializing the Afero instance
*
* A helper for `aferoSanitizer` for when the Afero instance is initialized with one of the safe FS types like IOFS
*
* e.g.`n2 := &afero.Afero{Fs: afero.NewBasePathFs(osFS, "./")}` n1 is `afero.NewBasePathFs(osFS, "./")`
*/
class AdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
exists(StructLit st | st.getType().hasQualifiedName(aferoPackage(), "Afero") |
n1.asExpr() = st.getAnElement().(KeyValueExpr).getAChildExpr() and
n2.asExpr() = st
)
}
}
}

View File

@@ -278,31 +278,21 @@ module Beego {
}
}
/**
* The File system access sinks
*/
private class FsOperations extends FileSystemAccess::Range, DataFlow::CallNode {
int pathArg;
FsOperations() {
this.getTarget().hasQualifiedName(packagePath(), "Walk") and pathArg = 1
this.getTarget().hasQualifiedName(packagePath(), "Walk")
or
exists(Method m | this = m.getACall() |
m.hasQualifiedName(packagePath(), "FileSystem", "Open") and pathArg = 0
or
m.hasQualifiedName(packagePath(), "Controller", "SaveToFile") and pathArg = 1
or
m.hasQualifiedName(contextPackagePath(), "BeegoOutput", "Download") and
pathArg = 0
or
// SaveToFileWithBuffer only available in v2
m.hasQualifiedName("github.com/beego/beego/v2/server/web", "Controller",
"SaveToFileWithBuffer") and
pathArg = 1
m.hasQualifiedName(packagePath(), "FileSystem", "Open") or
m.hasQualifiedName(packagePath(), "Controller", "SaveToFile")
)
}
override DataFlow::Node getAPathArgument() { result = this.getArgument(pathArg) }
override DataFlow::Node getAPathArgument() {
this.getTarget().getName() = ["Walk", "SaveToFile"] and result = this.getArgument(1)
or
this.getTarget().getName() = "Open" and result = this.getArgument(0)
}
}
private class RedirectMethods extends Http::Redirect::Range, DataFlow::CallNode {

View File

@@ -98,18 +98,4 @@ private module Echo {
override Http::ResponseWriter getResponseWriter() { none() }
}
/**
* The File system access sinks
*/
class FsOperations extends FileSystemAccess::Range, DataFlow::CallNode {
FsOperations() {
exists(Method m |
m.hasQualifiedName(packagePath(), "Context", ["Attachment", "File"]) and
this = m.getACall()
)
}
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
}
}

View File

@@ -1,38 +0,0 @@
/**
* Provides classes for working the `github.com/gofiber/fiber` package.
*/
import go
private module Fiber {
/** Gets the package name `github.com/gofiber/fiber`. */
string packagePath() { result = package("github.com/gofiber/fiber", "") }
/** Gets the v2 module path `github.com/gofiber/fiber/v2` */
string v2modulePath() { result = "github.com/gofiber/fiber/v2" }
/**
* The File system access sinks
*/
class FsOperations extends FileSystemAccess::Range, DataFlow::CallNode {
int pathArg;
FsOperations() {
exists(Method m |
(
m.hasQualifiedName(packagePath(), "Ctx", ["SendFile", "Download"]) and
pathArg = 0
or
m.hasQualifiedName(packagePath(), "Ctx", "SaveFile") and
pathArg = 1
or
m.hasQualifiedName(v2modulePath(), "Ctx", "SaveFileToStorage") and
pathArg = 1
) and
this = m.getACall()
)
}
override DataFlow::Node getAPathArgument() { result = this.getArgument(pathArg) }
}
}

View File

@@ -53,26 +53,4 @@ private module Gin {
)
}
}
/**
* The File system access sinks
*/
class FsOperations extends FileSystemAccess::Range, DataFlow::CallNode {
int pathArg;
FsOperations() {
exists(Method m |
(
m.hasQualifiedName(packagePath(), "Context", ["File", "FileAttachment"]) and
pathArg = 0
or
m.hasQualifiedName(packagePath(), "Context", "SaveUploadedFile") and
pathArg = 1
) and
this = m.getACall()
)
}
override DataFlow::Node getAPathArgument() { result = this.getArgument(pathArg) }
}
}

View File

@@ -1,49 +0,0 @@
/**
* Provides classes for working the `github.com/kataras/iris` package.
*/
import go
private module Iris {
/** Gets the v1 module path `github.com/kataras/iris`. */
string v1modulePath() { result = "github.com/kataras/iris" }
/** Gets the v12 module path `github.com/kataras/iris/v12` */
string v12modulePath() { result = "github.com/kataras/iris/v12" }
/** Gets the path for the context package of all versions of beego. */
string contextPackagePath() {
result = v12contextPackagePath()
or
result = v1contextPackagePath()
}
/** Gets the path for the context package of beego v12. */
string v12contextPackagePath() { result = v12modulePath() + "/context" }
/** Gets the path for the context package of beego v1. */
string v1contextPackagePath() { result = v1modulePath() + "/server/web/context" }
/**
* The File system access sinks
*/
class FsOperations extends FileSystemAccess::Range, DataFlow::CallNode {
int pathArg;
FsOperations() {
exists(Method m |
(
m.hasQualifiedName(contextPackagePath(), "Context",
["SendFile", "ServeFile", "SendFileWithRate", "ServeFileWithRate", "UploadFormFiles"]) and
pathArg = 0
or
m.hasQualifiedName(v12contextPackagePath(), "Context", "SaveFormFile") and
pathArg = 1
) and
this = m.getACall()
)
}
override DataFlow::Node getAPathArgument() { result = this.getArgument(pathArg) }
}
}

View File

@@ -288,18 +288,4 @@ module NetHttp {
override predicate guardedBy(DataFlow::Node check) { check = handlerReg.getArgument(0) }
}
/**
* The File system access sinks
*/
class HttpServeFile extends FileSystemAccess::Range, DataFlow::CallNode {
HttpServeFile() {
exists(Function f |
f.hasQualifiedName("net/http", "ServeFile") and
this = f.getACall()
)
}
override DataFlow::Node getAPathArgument() { result = this.getArgument(2) }
}
}

View File

@@ -195,13 +195,8 @@ private class MaxValueState extends TMaxValueState {
*/
int getBitSize() { this = TMkMaxValueState(result, _) }
private ArchitectureBitSize architectureBitSize() { this = TMkMaxValueState(_, result) }
/** Gets whether the architecture is 32 bit or 64 bit, if it is known. */
int getArchitectureBitSize() { result = this.architectureBitSize().toInt() }
/** Holds if the architecture is not known. */
predicate architectureBitSizeUnknown() { this.architectureBitSize().isUnknown() }
/** Gets whether the architecture is 32 bit or 64 bit, or if it is unknown. */
ArchitectureBitSize getArchitectureBitSize() { this = TMkMaxValueState(_, result) }
/**
* Gets the bitsize we should use for a sink.
@@ -210,16 +205,17 @@ private class MaxValueState extends TMaxValueState {
* we should use 32 bits, because that will find results that only exist on
* 32-bit architectures.
*/
int getSinkBitSize() {
if this = TMkMaxValueState(_, TMk64Bit()) then result = 64 else result = 32
bindingset[default]
int getSinkBitSize(int default) {
if this = TMkMaxValueState(_, TMk64Bit()) then result = 64 else result = default
}
/** Gets a textual representation of this element. */
string toString() {
exists(string suffix |
suffix = " (on " + this.getArchitectureBitSize() + "-bit architecture)"
suffix = " (on " + this.getArchitectureBitSize().toInt() + "-bit architecture)"
or
this.architectureBitSizeUnknown() and suffix = ""
this.getArchitectureBitSize().isUnknown() and suffix = ""
|
result = "MaxValueState(max value <= 2^(" + this.getBitSize() + ")-1" + suffix
)
@@ -340,7 +336,9 @@ class UpperBoundCheck extends BarrierFlowStateTransformer {
}
override predicate barrierFor(MaxValueState flowstate) {
g.isBoundFor(flowstate.getBitSize(), flowstate.getSinkBitSize())
// Use a default value of 32 for `MaxValueState.getSinkBitSize` because
// this will find results that only exist on 32-bit architectures.
g.isBoundFor(flowstate.getBitSize(), flowstate.getSinkBitSize(32))
}
override MaxValueState transform(MaxValueState state) {
@@ -349,13 +347,11 @@ class UpperBoundCheck extends BarrierFlowStateTransformer {
max(int bitsize |
bitsize = validBitSize() and
bitsize < state.getBitSize() and
not g.isBoundFor(bitsize, state.getSinkBitSize())
// Use a default value of 32 for `MaxValueState.getSinkBitSize` because
// this will find results that only exist on 32-bit architectures.
not g.isBoundFor(bitsize, state.getSinkBitSize(32))
) and
(
result.getArchitectureBitSize() = state.getArchitectureBitSize()
or
state.architectureBitSizeUnknown() and result.architectureBitSizeUnknown()
)
result.getArchitectureBitSize() = state.getArchitectureBitSize()
}
}
@@ -399,10 +395,10 @@ private module ConversionWithoutBoundsCheckConfig implements DataFlow::StateConf
then
exists(int b | b = [32, 64] |
state.getBitSize() = adjustBitSize(0, sourceIsSigned, b) and
state.getArchitectureBitSize() = b
state.getArchitectureBitSize().toInt() = b
)
else (
state.architectureBitSizeUnknown() and
state.getArchitectureBitSize().isUnknown() and
state.getBitSize() =
min(int bitsize |
bitsize = validBitSize() and
@@ -423,8 +419,10 @@ private module ConversionWithoutBoundsCheckConfig implements DataFlow::StateConf
additional predicate isSink2(DataFlow::TypeCastNode sink, FlowState state) {
sink.asExpr() instanceof ConversionExpr and
exists(int architectureBitSize, IntegerType integerType, int sinkBitsize, boolean sinkIsSigned |
architectureBitSize = getIntTypeBitSize(sink.getFile(), state.getSinkBitSize()) and
not (state.getArchitectureBitSize() = 32 and architectureBitSize = 64) and
// Use a default value of 32 for `MaxValueState.getSinkBitSize` because
// this will find results that only exist on 32-bit architectures.
architectureBitSize = getIntTypeBitSize(sink.getFile(), state.getSinkBitSize(32)) and
not (state.getArchitectureBitSize().toInt() = 32 and architectureBitSize = 64) and
sink.getResultType().getUnderlyingType() = integerType and
(
sinkBitsize = integerType.getSize()

View File

@@ -1,7 +1,3 @@
## 0.7.0
No user-facing changes.
## 0.6.5
No user-facing changes.

View File

@@ -1,3 +0,0 @@
## 0.7.0
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.7.0
lastReleaseVersion: 0.6.5

View File

@@ -1,28 +0,0 @@
package main
import (
"fmt"
"log"
"github.com/go-jose/go-jose/v3/jwt"
)
var JwtKey = []byte("AllYourBase")
func main() {
// BAD: usage of a harcoded Key
verifyJWT(JWTFromUser)
}
func LoadJwtKey(token *jwt.Token) (interface{}, error) {
return JwtKey, nil
}
func verifyJWT(signedToken string) {
fmt.Println("verifying JWT")
DecodedToken, err := jwt.ParseWithClaims(signedToken, &CustomerInfo{}, LoadJwtKey)
if claims, ok := DecodedToken.Claims.(*CustomerInfo); ok && DecodedToken.Valid {
fmt.Printf("NAME:%v ,ID:%v\n", claims.Name, claims.ID)
} else {
log.Fatal(err)
}
}

View File

@@ -1,41 +0,0 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
<qhelp>
<overview>
<p>
A JSON Web Token (JWT) is used for authenticating and managing users in an application.
</p>
<p>
Using a hard-coded secret key for parsing JWT tokens in open source projects
can leave the application using the token vulnerable to authentication bypasses.
</p>
<p>
A JWT token is safe for enforcing authentication and access control as long as it can't be forged by a malicious actor. However, when a project exposes this secret publicly, these seemingly unforgeable tokens can now be easily forged.
Since the authentication as well as access control is typically enforced through these JWT tokens, an attacker armed with the secret can create a valid authentication token for any user and may even gain access to other privileged parts of the application.
</p>
</overview>
<recommendation>
<p>
Generating a cryptographically secure secret key during application initialization and using this generated key for future JWT parsing requests can prevent this vulnerability.
</p>
</recommendation>
<example>
<p>
The following code uses a hard-coded string as a secret for parsing user provided JWTs. In this case, an attacker can very easily forge a token by using the hard-coded secret.
</p>
<sample src="ExampleBad.go" />
</example>
<references>
<li>
CVE-2022-0664:
<a href="https://nvd.nist.gov/vuln/detail/CVE-2022-0664">Use of Hard-coded Cryptographic Key in Go github.com/gravitl/netmaker prior to 0.8.5,0.9.4,0.10.0,0.10.1. </a>
</li>
</references>
</qhelp>

View File

@@ -1,59 +0,0 @@
/**
* @name Decoding JWT with hardcoded key
* @description Decoding JWT Secret with a Constant value lead to authentication or authorization bypass
* @kind path-problem
* @problem.severity error
* @id go/parse-jwt-with-hardcoded-key
* @tags security
* experimental
* external/cwe/cwe-321
*/
import go
import experimental.frameworks.JWT
module JwtParseWithConstantKeyConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof StringLit }
predicate isSink(DataFlow::Node sink) {
// first part is the JWT Parsing Functions that get a func type as an argument
// Find a node that has flow to a key Function argument
// then find the first result node of this Function which is the secret key
exists(FuncDef fd, DataFlow::Node n, DataFlow::ResultNode rn |
fd = n.asExpr()
or
n = fd.(FuncDecl).getFunction().getARead()
|
GolangJwtKeyFunc::flow(n, _) and
sink = rn and
rn.getRoot() = fd and
rn.getIndex() = 0
)
or
// second part is the JWT Parsing Functions that get a string or byte as an argument
sink = any(JwtParse jp).getKeyArg()
}
}
module GolangJwtKeyFuncConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source = any(Function f).getARead()
or
source.asExpr() = any(FuncDef fd)
}
predicate isSink(DataFlow::Node sink) {
sink = any(JwtParseWithKeyFunction parseJwt).getKeyFuncArg()
}
}
module JwtParseWithConstantKey = TaintTracking::Global<JwtParseWithConstantKeyConfig>;
module GolangJwtKeyFunc = TaintTracking::Global<GolangJwtKeyFuncConfig>;
import JwtParseWithConstantKey::PathGraph
from JwtParseWithConstantKey::PathNode source, JwtParseWithConstantKey::PathNode sink
where JwtParseWithConstantKey::flowPath(source, sink)
select sink.getNode(), source, sink, "This $@.", source.getNode(),
"Constant Key is used as JWT Secret key"

View File

@@ -1,39 +0,0 @@
package main
import (
"fmt"
"log"
"github.com/golang-jwt/jwt/v5"
)
func main() {
// BAD: only decode jwt without verification
notVerifyJWT(token)
// GOOD: decode with verification or verify plus decode
notVerifyJWT(token)
VerifyJWT(token)
}
func notVerifyJWT(signedToken string) {
fmt.Println("only decoding JWT")
DecodedToken, _, err := jwt.NewParser().ParseUnverified(signedToken, &CustomerInfo{})
if claims, ok := DecodedToken.Claims.(*CustomerInfo); ok {
fmt.Printf("DecodedToken:%v\n", claims)
} else {
log.Fatal("error", err)
}
}
func LoadJwtKey(token *jwt.Token) (interface{}, error) {
return ARandomJwtKey, nil
}
func verifyJWT(signedToken string) {
fmt.Println("verifying JWT")
DecodedToken, err := jwt.ParseWithClaims(signedToken, &CustomerInfo{}, LoadJwtKey)
if claims, ok := DecodedToken.Claims.(*CustomerInfo); ok && DecodedToken.Valid {
fmt.Printf("NAME:%v ,ID:%v\n", claims.Name, claims.ID)
} else {
log.Fatal(err)
}
}

View File

@@ -1,34 +0,0 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
<qhelp>
<overview>
<p>
A JSON Web Token (JWT) is used for authenticating and managing users in an application.
</p>
<p>
Only Decoding JWTs without checking if they have a valid signature or not can lead to security vulnerabilities.
</p>
</overview>
<recommendation>
<p>
Don't use methods that only decode JWT, Instead use methods that verify the signature of JWT.
</p>
</recommendation>
<example>
<p>
In the following code you can see an Example from a popular Library.
</p>
<sample src="Example.go" />
</example>
<references>
<li>
<a href="https://github.com/argoproj/argo-cd/security/advisories/GHSA-q9hr-j4rf-8fjc">JWT audience claim is not verified</a>
</li>
</references>
</qhelp>

View File

@@ -1,57 +0,0 @@
/**
* @name Use of JWT Methods that only decode user provided Token
* @description Using JWT methods without verification can cause to authorization or authentication bypass
* @kind path-problem
* @problem.severity error
* @id go/parse-jwt-without-verification
* @tags security
* experimental
* external/cwe/cwe-321
*/
import go
import experimental.frameworks.JWT
module WithValidationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
predicate isSink(DataFlow::Node sink) {
sink = any(JwtParse jwtParse).getTokenArg() or
sink = any(JwtParseWithKeyFunction jwtParseWithKeyFunction).getTokenArg()
}
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
golangJwtIsAdditionalFlowStep(nodeFrom, nodeTo)
or
goJoseIsAdditionalFlowStep(nodeFrom, nodeTo)
}
}
module NoValidationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof UntrustedFlowSource and
not WithValidation::flow(source, _)
}
predicate isSink(DataFlow::Node sink) {
sink = any(JwtUnverifiedParse parseUnverified).getTokenArg()
}
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
golangJwtIsAdditionalFlowStep(nodeFrom, nodeTo)
or
goJoseIsAdditionalFlowStep(nodeFrom, nodeTo)
}
}
module WithValidation = TaintTracking::Global<WithValidationConfig>;
module NoValidation = TaintTracking::Global<NoValidationConfig>;
import NoValidation::PathGraph
from NoValidation::PathNode source, NoValidation::PathNode sink
where NoValidation::flowPath(source, sink)
select sink.getNode(), source, sink,
"This JWT is parsed without verification and received from $@.", source.getNode(),
"this user-controlled source"

View File

@@ -1,265 +0,0 @@
import go
/**
* A abstract class which responsible for parsing a JWT token.
*/
abstract class JwtParseBase extends Function {
/**
* Gets argument number that responsible for JWT
*
* `-1` means the receiver is a argument node that responsible for JWT.
* In this case, we must declare some additional taint steps.
*/
abstract int getTokenArgNum();
/**
* Gets Argument as DataFlow node that responsible for JWT
*/
DataFlow::Node getTokenArg() {
this.getTokenArgNum() != -1 and result = this.getACall().getArgument(this.getTokenArgNum())
or
this.getTokenArgNum() = -1 and result = this.getACall().getReceiver()
}
}
/**
* A abstract class which responsible for parsing a JWT token which the key parameter is a function type.
*
* Extends this class for Jwt parsing methods that accepts a function type as key.
*/
abstract class JwtParseWithKeyFunction extends JwtParseBase {
/**
* Gets argument number that responsible for a function returning the secret key
*/
abstract int getKeyFuncArgNum();
/**
* Gets Argument as DataFlow node that responsible for a function returning the secret key
*/
DataFlow::Node getKeyFuncArg() { result = this.getACall().getArgument(this.getKeyFuncArgNum()) }
}
/**
* A abstract class which responsible for parsing a JWT token which the key parameter can be a string or byte type.
*
* Extends this class for Jwt parsing methods that accepts a non-function type as key.
*/
abstract class JwtParse extends JwtParseBase {
/**
* Gets argument number that responsible for secret key
*/
abstract int getKeyArgNum();
/**
* Gets Argument as DataFlow node that responsible for secret key
*/
DataFlow::Node getKeyArg() { result = this.getACall().getArgument(this.getKeyArgNum()) }
}
/**
* A abstract class which responsible for parsing a JWT without verifying it
*
* Extends this class for Jwt parsing methods that don't verify JWT signature
*/
abstract class JwtUnverifiedParse extends JwtParseBase { }
/**
* Gets `github.com/golang-jwt/jwt` and `github.com/dgrijalva/jwt-go`(previous name of `golang-jwt`) JWT packages
*/
string golangJwtPackage() {
result = package(["github.com/golang-jwt/jwt", "github.com/dgrijalva/jwt-go"], "")
}
/**
* A class that contains the following function and method:
*
* func (p *Parser) Parse(tokenString string, keyFunc Keyfunc)
*
* func Parse(tokenString string, keyFunc Keyfunc)
*/
class GolangJwtParse extends JwtParseWithKeyFunction {
GolangJwtParse() {
exists(Function f | f.hasQualifiedName(golangJwtPackage(), "Parse") | this = f)
or
exists(Method f | f.hasQualifiedName(golangJwtPackage(), "Parser", "Parse") | this = f)
}
override int getKeyFuncArgNum() { result = 1 }
override int getTokenArgNum() { result = 0 }
}
/**
* A class that contains the following function and method:
*
* func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc)
*
* func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc)
*/
class GolangJwtParseWithClaims extends JwtParseWithKeyFunction {
GolangJwtParseWithClaims() {
exists(Function f | f.hasQualifiedName(golangJwtPackage(), "ParseWithClaims") | this = f)
or
exists(Method f | f.hasQualifiedName(golangJwtPackage(), "Parser", "ParseWithClaims") |
this = f
)
}
override int getKeyFuncArgNum() { result = 2 }
override int getTokenArgNum() { result = 0 }
}
/**
* A class that contains the following method:
*
* func (p *Parser) ParseUnverified(tokenString string, claims Claims)
*/
class GolangJwtParseUnverified extends JwtUnverifiedParse {
GolangJwtParseUnverified() {
exists(Method f | f.hasQualifiedName(golangJwtPackage(), "Parser", "ParseUnverified") |
this = f
)
}
override int getTokenArgNum() { result = 0 }
}
/**
* Gets `github.com/golang-jwt/jwt` and `github.com/dgrijalva/jwt-go`(previous name of `golang-jwt`) JWT packages
*/
string golangJwtRequestPackage() {
result = package(["github.com/golang-jwt/jwt", "github.com/dgrijalva/jwt-go"], "request")
}
/**
* A class that contains the following function:
*
* func ParseFromRequest(req *http.Request, extractor Extractor, keyFunc jwt.Keyfunc, options ...ParseFromRequestOption)
*/
class GolangJwtParseFromRequest extends JwtParseWithKeyFunction {
GolangJwtParseFromRequest() {
exists(Function f | f.hasQualifiedName(golangJwtRequestPackage(), "ParseFromRequest") |
this = f
)
}
override int getKeyFuncArgNum() { result = 2 }
override int getTokenArgNum() { result = 0 }
}
/**
* A class that contains the following function:
*
* func ParseFromRequestWithClaims(req *http.Request, extractor Extractor, claims jwt.Claims, keyFunc jwt.Keyfunc)
*/
class GolangJwtParseFromRequestWithClaims extends JwtParseWithKeyFunction {
GolangJwtParseFromRequestWithClaims() {
exists(Function f |
f.hasQualifiedName(golangJwtRequestPackage(), "ParseFromRequestWithClaims")
|
this = f
)
}
override int getKeyFuncArgNum() { result = 3 }
override int getTokenArgNum() { result = 0 }
}
/**
* Gets `gopkg.in/square/go-jose` and `github.com/go-jose/go-jose` jwt package
*/
string goJoseJwtPackage() {
result = package(["gopkg.in/square/go-jose", "github.com/go-jose/go-jose"], "jwt")
}
/**
* A class that contains the following method:
*
* func (t *JSONWebToken) Claims(key interface{}, dest ...interface{})
*/
class GoJoseParseWithClaims extends JwtParse {
GoJoseParseWithClaims() {
exists(Method f | f.hasQualifiedName(goJoseJwtPackage(), "JSONWebToken", "Claims") | this = f)
}
override int getKeyArgNum() { result = 0 }
override int getTokenArgNum() { result = -1 }
}
/**
* A class that contains the following method:
*
* func (t *JSONWebToken) UnsafeClaimsWithoutVerification(dest ...interface{})
*/
class GoJoseUnsafeClaims extends JwtUnverifiedParse {
GoJoseUnsafeClaims() {
exists(Method f |
f.hasQualifiedName(goJoseJwtPackage(), "JSONWebToken", "UnsafeClaimsWithoutVerification")
|
this = f
)
}
override int getTokenArgNum() { result = -1 }
}
/**
* Holds for general additional steps related to parsing the secret keys in `golang-jwt/jwt`,`dgrijalva/jwt-go` packages
*/
predicate golangJwtIsAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
exists(Function f, DataFlow::CallNode call |
(
f.hasQualifiedName(package("github.com/golang-jwt/jwt", ""),
[
"ParseECPrivateKeyFromPEM", "ParseECPublicKeyFromPEM", "ParseEdPrivateKeyFromPEM",
"ParseEdPublicKeyFromPEM", "ParseRSAPrivateKeyFromPEM", "ParseRSAPublicKeyFromPEM",
"RegisterSigningMethod"
]) or
f.hasQualifiedName(package("github.com/dgrijalva/jwt-go", ""),
[
"ParseECPrivateKeyFromPEM", "ParseECPublicKeyFromPEM", "ParseRSAPrivateKeyFromPEM",
"ParseRSAPrivateKeyFromPEMWithPassword", "ParseRSAPublicKeyFromPEM"
])
) and
call = f.getACall() and
nodeFrom = call.getArgument(0) and
nodeTo = call.getResult(0)
or
(
f instanceof GolangJwtParse
or
f instanceof GolangJwtParseWithClaims
) and
call = f.getACall() and
nodeFrom = call.getArgument(0) and
nodeTo = call.getResult(0)
)
}
/**
* Holds for general additioanl steps related to parsing the secret keys in `go-jose` package
*/
predicate goJoseIsAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
exists(Function f, DataFlow::CallNode call |
f.hasQualifiedName(goJoseJwtPackage(), ["ParseEncrypted", "ParseSigned"]) and
call = f.getACall() and
nodeFrom = call.getArgument(0) and
nodeTo = call.getResult(0)
)
or
exists(Method m, DataFlow::CallNode call |
m.hasQualifiedName(goJoseJwtPackage(), "NestedJSONWebToken", "ParseSignedAndEncrypted") and
call = m.getACall() and
nodeFrom = call.getArgument(0) and
nodeTo = call.getResult(0)
or
m.hasQualifiedName(goJoseJwtPackage(), "NestedJSONWebToken", "Decrypt") and
call = m.getACall() and
nodeFrom = call.getReceiver() and
nodeTo = call.getResult(0)
)
}

View File

@@ -1,5 +1,5 @@
name: codeql/go-queries
version: 0.7.1-dev
version: 0.7.0-dev
groups:
- go
- queries

Some files were not shown because too many files have changed in this diff Show More