mirror of
https://github.com/github/codeql.git
synced 2026-05-18 21:27:08 +02:00
Compare commits
222 Commits
criemen/cs
...
codeql-cli
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff65ffafb0 | ||
|
|
97402fdf36 | ||
|
|
2662a4c651 | ||
|
|
dce03569e5 | ||
|
|
6ec9b95072 | ||
|
|
641646ac08 | ||
|
|
75f42f4614 | ||
|
|
0c1fb8c881 | ||
|
|
4f9303eb02 | ||
|
|
2c23dacca1 | ||
|
|
de83929a60 | ||
|
|
f1001374fd | ||
|
|
25d3af9236 | ||
|
|
1f3f1b5ec4 | ||
|
|
5c0fb2030d | ||
|
|
71ef98584d | ||
|
|
6bba191407 | ||
|
|
df144f3a1e | ||
|
|
a46dc55e84 | ||
|
|
14268f3c63 | ||
|
|
408ba517e5 | ||
|
|
4d4ca6b948 | ||
|
|
d443354651 | ||
|
|
57f6859ddc | ||
|
|
5f087f0084 | ||
|
|
f66f7ce8d7 | ||
|
|
f22979f4b6 | ||
|
|
46e6e72593 | ||
|
|
92c18960c5 | ||
|
|
e349891cff | ||
|
|
e02c32f3d4 | ||
|
|
0f1dc9b2d9 | ||
|
|
ae6c95ff95 | ||
|
|
bae7e10e46 | ||
|
|
ec63099c54 | ||
|
|
2b8b5cf1b8 | ||
|
|
6730f57d5c | ||
|
|
118d50236f | ||
|
|
7a001f4905 | ||
|
|
803ed20962 | ||
|
|
4256fbf11a | ||
|
|
f3dd002ba9 | ||
|
|
f9e9ae91f7 | ||
|
|
23419ee634 | ||
|
|
b8f0f85840 | ||
|
|
69453aa144 | ||
|
|
55f5b26ba6 | ||
|
|
721bde1ce8 | ||
|
|
2e9d548083 | ||
|
|
83d1fc33e1 | ||
|
|
14e51627c5 | ||
|
|
52540b42fc | ||
|
|
6bd7047e41 | ||
|
|
57f1f5b829 | ||
|
|
bff93c4484 | ||
|
|
0342b3eba2 | ||
|
|
d28e7920b3 | ||
|
|
331ca61be9 | ||
|
|
559b965e74 | ||
|
|
6299b844f8 | ||
|
|
4385b316c0 | ||
|
|
b1dc6099ff | ||
|
|
15099b3db0 | ||
|
|
8334c6db91 | ||
|
|
1c75e5b2a6 | ||
|
|
1623bba18a | ||
|
|
475d8da342 | ||
|
|
ae09499905 | ||
|
|
c950e26b3e | ||
|
|
f75c062949 | ||
|
|
f22d87b7c7 | ||
|
|
e11a68803e | ||
|
|
45faed057c | ||
|
|
f1b67ade9b | ||
|
|
f9ae7c5454 | ||
|
|
296dee90dd | ||
|
|
967bbbc1a7 | ||
|
|
28a5a1d507 | ||
|
|
5b38ba87df | ||
|
|
db42b60015 | ||
|
|
f8c8d59cb5 | ||
|
|
c8779d0d0b | ||
|
|
28160e418c | ||
|
|
ed349f7d6b | ||
|
|
fa569dcef4 | ||
|
|
040d971588 | ||
|
|
e95bfc816e | ||
|
|
44935cef63 | ||
|
|
190050f577 | ||
|
|
458baeff32 | ||
|
|
c14d4042e0 | ||
|
|
5a451e964d | ||
|
|
b157d73c10 | ||
|
|
985d1990eb | ||
|
|
463096e4be | ||
|
|
892beeab6d | ||
|
|
9ec2f9204b | ||
|
|
c73e6f1fa8 | ||
|
|
9aafbfce13 | ||
|
|
cc6268339b | ||
|
|
834b07e6ad | ||
|
|
8be6aeda3e | ||
|
|
359dcf37e9 | ||
|
|
eb263e747f | ||
|
|
bc576f658e | ||
|
|
6f56a656e4 | ||
|
|
031f453af8 | ||
|
|
002f2a0985 | ||
|
|
d21e27c717 | ||
|
|
30e4822fb7 | ||
|
|
d931ade182 | ||
|
|
ed9a0ea155 | ||
|
|
c3577b34d3 | ||
|
|
e4da8da5d9 | ||
|
|
b455b2c1a6 | ||
|
|
dc4dda1dbc | ||
|
|
098ea50068 | ||
|
|
6e291711ac | ||
|
|
fca6ccd2f1 | ||
|
|
291bb2210c | ||
|
|
4bf717c3e4 | ||
|
|
d15c46836b | ||
|
|
c0fce80b7d | ||
|
|
1b7e3814b0 | ||
|
|
bf6cfd3bef | ||
|
|
30aefabb2a | ||
|
|
f05b75e04f | ||
|
|
c28f54a78b | ||
|
|
66b03bfb12 | ||
|
|
71e25521cf | ||
|
|
27e6173bb7 | ||
|
|
3a73faf061 | ||
|
|
352ec91a08 | ||
|
|
00549e36ed | ||
|
|
b385ddbab1 | ||
|
|
f599c6d8a9 | ||
|
|
df967ce43f | ||
|
|
6e533c6284 | ||
|
|
2b1b4cd85d | ||
|
|
5280d69500 | ||
|
|
39ed7876c3 | ||
|
|
882280309f | ||
|
|
01a074c146 | ||
|
|
d56625cb8b | ||
|
|
8f10667ee1 | ||
|
|
837cdc8301 | ||
|
|
3a62628938 | ||
|
|
9062fb666a | ||
|
|
b48d483eba | ||
|
|
c327f0f0a7 | ||
|
|
393aad5935 | ||
|
|
8f141cb157 | ||
|
|
5a09a325f2 | ||
|
|
5fc8a00487 | ||
|
|
b3feb4d7e9 | ||
|
|
0d8986cfad | ||
|
|
617d950a25 | ||
|
|
1c87875049 | ||
|
|
5e21a5d284 | ||
|
|
0fb439b54d | ||
|
|
e865c3cbd3 | ||
|
|
e4c8406365 | ||
|
|
2d387a98ce | ||
|
|
78a65a7787 | ||
|
|
6d7598115e | ||
|
|
a7264c2b5c | ||
|
|
dc265e7542 | ||
|
|
657c29f409 | ||
|
|
ebf7231be7 | ||
|
|
9b5556e245 | ||
|
|
2d313ef4c7 | ||
|
|
a051a57e00 | ||
|
|
0b91310357 | ||
|
|
b8e7e1d15e | ||
|
|
daffae020b | ||
|
|
cd147038cd | ||
|
|
a86862d578 | ||
|
|
04016ebd20 | ||
|
|
f99df55e94 | ||
|
|
3dcb039c76 | ||
|
|
9b0ad8295e | ||
|
|
9d5cf0b331 | ||
|
|
f12310cb86 | ||
|
|
137403f649 | ||
|
|
5433907c33 | ||
|
|
5bee44dcfe | ||
|
|
6568332e3d | ||
|
|
6c50c2bfe6 | ||
|
|
e8eff78799 | ||
|
|
ad756d59c8 | ||
|
|
315bdc2b48 | ||
|
|
637c52d10a | ||
|
|
92b13c4259 | ||
|
|
3d8a7e0ee3 | ||
|
|
57c645bd24 | ||
|
|
1f2e8d898d | ||
|
|
225c96ec9f | ||
|
|
37361d9f79 | ||
|
|
3697ef72c4 | ||
|
|
5cab25662c | ||
|
|
8ed10317bd | ||
|
|
dd9a2db137 | ||
|
|
020b4becfd | ||
|
|
5385cc3aaa | ||
|
|
9087259b1b | ||
|
|
968127eaa3 | ||
|
|
e0782683eb | ||
|
|
dafcd5ec98 | ||
|
|
a1e38c3444 | ||
|
|
eccde3f4f1 | ||
|
|
a0e2e1ef21 | ||
|
|
1fe565a46f | ||
|
|
20bf3c7f67 | ||
|
|
76e56cdac7 | ||
|
|
ad2631202d | ||
|
|
6c8cc79b4d | ||
|
|
52007fb9a2 | ||
|
|
08c54767f2 | ||
|
|
d654e98650 | ||
|
|
1a9bfb38aa | ||
|
|
bf9d0b93d7 | ||
|
|
1a51c015b4 |
@@ -1,3 +1,17 @@
|
||||
## 0.12.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The expressions `AssignPointerAddExpr` and `AssignPointerSubExpr` are no longer subtypes of `AssignBitwiseOperation`.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The "Returning stack-allocated memory" (`cpp/return-stack-allocated-memory`) query now also detects returning stack-allocated memory allocated by calls to `alloca`, `strdupa`, and `strndupa`.
|
||||
* Added models for `strlcpy` and `strlcat`.
|
||||
* Added models for the `sprintf` variants from the `StrSafe.h` header.
|
||||
* Added SQL API models for `ODBC`.
|
||||
* Added taint models for `realloc` and related functions.
|
||||
|
||||
## 0.11.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added taint models for `realloc` and related functions.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: breaking
|
||||
---
|
||||
* The expressions `AssignPointerAddExpr` and `AssignPointerSubExpr` are no longer subtypes of `AssignBitwiseOperation`.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added models for the `sprintf` variants from the `StrSafe.h` header.
|
||||
13
cpp/ql/lib/change-notes/released/0.12.0.md
Normal file
13
cpp/ql/lib/change-notes/released/0.12.0.md
Normal file
@@ -0,0 +1,13 @@
|
||||
## 0.12.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The expressions `AssignPointerAddExpr` and `AssignPointerSubExpr` are no longer subtypes of `AssignBitwiseOperation`.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The "Returning stack-allocated memory" (`cpp/return-stack-allocated-memory`) query now also detects returning stack-allocated memory allocated by calls to `alloca`, `strdupa`, and `strndupa`.
|
||||
* Added models for `strlcpy` and `strlcat`.
|
||||
* Added models for the `sprintf` variants from the `StrSafe.h` header.
|
||||
* Added SQL API models for `ODBC`.
|
||||
* Added taint models for `realloc` and related functions.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.11.0
|
||||
lastReleaseVersion: 0.12.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.11.1-dev
|
||||
version: 0.12.0
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -81,6 +81,14 @@ class Node0Impl extends TIRDataFlowNode0 {
|
||||
/** Gets the operands corresponding to this node, if any. */
|
||||
Operand asOperand() { result = this.(OperandNode0).getOperand() }
|
||||
|
||||
/** Gets the location of this node. */
|
||||
final Location getLocation() { result = this.getLocationImpl() }
|
||||
|
||||
/** INTERNAL: Do not use. */
|
||||
Location getLocationImpl() {
|
||||
none() // overridden by subclasses
|
||||
}
|
||||
|
||||
/** INTERNAL: Do not use. */
|
||||
string toStringImpl() {
|
||||
none() // overridden by subclasses
|
||||
@@ -131,9 +139,15 @@ abstract class InstructionNode0 extends Node0Impl {
|
||||
override DataFlowType getType() { result = getInstructionType(instr, _) }
|
||||
|
||||
override string toStringImpl() {
|
||||
// This predicate is overridden in subclasses. This default implementation
|
||||
// does not use `Instruction.toString` because that's expensive to compute.
|
||||
result = instr.getOpcode().toString()
|
||||
if instr.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
|
||||
then result = "this"
|
||||
else result = instr.getAst().toString()
|
||||
}
|
||||
|
||||
override Location getLocationImpl() {
|
||||
if exists(instr.getAst().getLocation())
|
||||
then result = instr.getAst().getLocation()
|
||||
else result instanceof UnknownDefaultLocation
|
||||
}
|
||||
|
||||
final override predicate isGLValue() { exists(getInstructionType(instr, true)) }
|
||||
@@ -173,7 +187,17 @@ abstract class OperandNode0 extends Node0Impl {
|
||||
|
||||
override DataFlowType getType() { result = getOperandType(op, _) }
|
||||
|
||||
override string toStringImpl() { result = op.toString() }
|
||||
override string toStringImpl() {
|
||||
if op.getDef().(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
|
||||
then result = "this"
|
||||
else result = op.getDef().getAst().toString()
|
||||
}
|
||||
|
||||
override Location getLocationImpl() {
|
||||
if exists(op.getDef().getAst().getLocation())
|
||||
then result = op.getDef().getAst().getLocation()
|
||||
else result instanceof UnknownDefaultLocation
|
||||
}
|
||||
|
||||
final override predicate isGLValue() { exists(getOperandType(op, true)) }
|
||||
}
|
||||
|
||||
@@ -432,6 +432,10 @@ private class Node0 extends Node, TNode0 {
|
||||
|
||||
override Declaration getFunction() { result = node.getFunction() }
|
||||
|
||||
override Location getLocationImpl() { result = node.getLocation() }
|
||||
|
||||
override string toStringImpl() { result = node.toString() }
|
||||
|
||||
override DataFlowType getType() { result = node.getType() }
|
||||
|
||||
override predicate isGLValue() { node.isGLValue() }
|
||||
@@ -448,18 +452,6 @@ class InstructionNode extends Node0 {
|
||||
|
||||
/** Gets the instruction corresponding to this node. */
|
||||
Instruction getInstruction() { result = instr }
|
||||
|
||||
override Location getLocationImpl() {
|
||||
if exists(instr.getAst().getLocation())
|
||||
then result = instr.getAst().getLocation()
|
||||
else result instanceof UnknownDefaultLocation
|
||||
}
|
||||
|
||||
override string toStringImpl() {
|
||||
if instr.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
|
||||
then result = "this"
|
||||
else result = instr.getAst().toString()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -473,18 +465,6 @@ class OperandNode extends Node, Node0 {
|
||||
|
||||
/** Gets the operand corresponding to this node. */
|
||||
Operand getOperand() { result = op }
|
||||
|
||||
override Location getLocationImpl() {
|
||||
if exists(op.getDef().getAst().getLocation())
|
||||
then result = op.getDef().getAst().getLocation()
|
||||
else result instanceof UnknownDefaultLocation
|
||||
}
|
||||
|
||||
override string toStringImpl() {
|
||||
if op.getDef().(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
|
||||
then result = "this"
|
||||
else result = op.getDef().getAst().toString()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,6 +10,8 @@ import semmle.code.cpp.models.interfaces.SideEffect
|
||||
|
||||
/**
|
||||
* The standard function `strcat` and its wide, sized, and Microsoft variants.
|
||||
*
|
||||
* Does not include `strlcat`, which is covered by `StrlcatFunction`
|
||||
*/
|
||||
class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, SideEffectFunction {
|
||||
StrcatFunction() {
|
||||
@@ -90,3 +92,64 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid
|
||||
buffer = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `strlcat` function.
|
||||
*/
|
||||
class StrlcatFunction extends TaintFunction, ArrayFunction, SideEffectFunction {
|
||||
StrlcatFunction() {
|
||||
this.hasGlobalName("strlcat") // strlcat(dst, src, dst_size)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of the parameter that is the size of the copy (in characters).
|
||||
*/
|
||||
int getParamSize() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets the index of the parameter that is the source of the copy.
|
||||
*/
|
||||
int getParamSrc() { result = 1 }
|
||||
|
||||
/**
|
||||
* Gets the index of the parameter that is the destination to be appended to.
|
||||
*/
|
||||
int getParamDest() { result = 0 }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
(
|
||||
input.isParameter(2)
|
||||
or
|
||||
input.isParameterDeref(0)
|
||||
or
|
||||
input.isParameterDeref(1)
|
||||
) and
|
||||
output.isParameterDeref(0)
|
||||
}
|
||||
|
||||
override predicate hasArrayInput(int param) {
|
||||
param = 0 or
|
||||
param = 1
|
||||
}
|
||||
|
||||
override predicate hasArrayOutput(int param) { param = 0 }
|
||||
|
||||
override predicate hasArrayWithNullTerminator(int param) { param = 1 }
|
||||
|
||||
override predicate hasArrayWithUnknownSize(int param) { param = 0 }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = 0 and
|
||||
buffer = true and
|
||||
mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
(i = 0 or i = 1) and
|
||||
buffer = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,8 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
|
||||
"wcsxfrm_l", // _strxfrm_l(dest, src, max_amount, locale)
|
||||
"_mbsnbcpy", // _mbsnbcpy(dest, src, max_amount)
|
||||
"stpcpy", // stpcpy(dest, src)
|
||||
"stpncpy" // stpcpy(dest, src, max_amount)
|
||||
"stpncpy", // stpncpy(dest, src, max_amount)
|
||||
"strlcpy" // strlcpy(dst, src, dst_size)
|
||||
])
|
||||
or
|
||||
(
|
||||
@@ -53,6 +54,11 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
|
||||
*/
|
||||
private predicate isSVariant() { this.getName().matches("%\\_s") }
|
||||
|
||||
/**
|
||||
* Holds if the function returns the total length the string would have had if the size was unlimited.
|
||||
*/
|
||||
private predicate returnsTotalLength() { this.getName() = "strlcpy" }
|
||||
|
||||
/**
|
||||
* Gets the index of the parameter that is the maximum size of the copy (in characters).
|
||||
*/
|
||||
@@ -60,7 +66,7 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
|
||||
if this.isSVariant()
|
||||
then result = 1
|
||||
else (
|
||||
this.getName().matches(["%ncpy%", "%nbcpy%", "%xfrm%"]) and
|
||||
this.getName().matches(["%ncpy%", "%nbcpy%", "%xfrm%", "strlcpy"]) and
|
||||
result = 2
|
||||
)
|
||||
}
|
||||
@@ -100,6 +106,7 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
|
||||
input.isParameterDeref(this.getParamSrc()) and
|
||||
output.isReturnValueDeref()
|
||||
or
|
||||
not this.returnsTotalLength() and
|
||||
input.isParameter(this.getParamDest()) and
|
||||
output.isReturnValue()
|
||||
}
|
||||
@@ -110,8 +117,9 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
|
||||
exists(this.getParamSize()) and
|
||||
input.isParameterDeref(this.getParamSrc()) and
|
||||
(
|
||||
output.isParameterDeref(this.getParamDest()) or
|
||||
output.isReturnValueDeref()
|
||||
output.isParameterDeref(this.getParamDest())
|
||||
or
|
||||
not this.returnsTotalLength() and output.isReturnValueDeref()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@ class SemSsaExplicitUpdate extends SemSsaVariable {
|
||||
|
||||
SemSsaExplicitUpdate() { Specific::explicitUpdate(this, sourceExpr) }
|
||||
|
||||
final SemExpr getSourceExpr() { result = sourceExpr }
|
||||
|
||||
final SemExpr getDefiningExpr() { result = sourceExpr }
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ private predicate constantIntegerExpr(SemExpr e, int val) {
|
||||
// Copy of another constant
|
||||
exists(SemSsaExplicitUpdate v, SemExpr src |
|
||||
e = v.getAUse() and
|
||||
src = v.getSourceExpr() and
|
||||
src = v.getDefiningExpr() and
|
||||
constantIntegerExpr(src, val)
|
||||
)
|
||||
or
|
||||
|
||||
@@ -22,30 +22,7 @@ module CppLangImplConstant implements LangSig<Sem, FloatDelta> {
|
||||
predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
|
||||
* Holds if `e2 >= e1 + delta` (if `upper = false`) or `e2 <= e1 + delta` (if `upper = true`).
|
||||
*/
|
||||
predicate hasBound(SemExpr e, SemExpr bound, float delta, boolean upper) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the value of `dest` is known to be `src + delta`.
|
||||
*/
|
||||
predicate additionalValueFlowStep(SemExpr dest, SemExpr src, float delta) { none() }
|
||||
|
||||
/**
|
||||
* Gets the type that range analysis should use to track the result of the specified expression,
|
||||
* if a type other than the original type of the expression is to be used.
|
||||
*
|
||||
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
||||
* actually references but whose values can be tracked as the type contained in the box.
|
||||
*/
|
||||
SemType getAlternateType(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Gets the type that range analysis should use to track the result of the specified source
|
||||
* variable, if a type other than the original type of the expression is to be used.
|
||||
*
|
||||
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
||||
* actually references but whose values can be tracked as the type contained in the box.
|
||||
*/
|
||||
SemType getAlternateTypeForSsaVariable(SemSsaVariable var) { none() }
|
||||
predicate additionalBoundFlowStep(SemExpr e2, SemExpr e1, float delta, boolean upper) { none() }
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
private import RangeAnalysisConstantSpecific
|
||||
private import RangeAnalysisRelativeSpecific
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||
private import RangeUtils
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExpr
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticCFG
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticGuard
|
||||
@@ -88,12 +87,18 @@ module Sem implements Semantic {
|
||||
|
||||
class AddressType = SemAddressType;
|
||||
|
||||
SemType getExprType(SemExpr e) { result = e.getSemType() }
|
||||
|
||||
SemType getSsaType(SemSsaVariable var) { result = var.getType() }
|
||||
|
||||
class SsaVariable = SemSsaVariable;
|
||||
|
||||
class SsaPhiNode = SemSsaPhiNode;
|
||||
|
||||
class SsaExplicitUpdate = SemSsaExplicitUpdate;
|
||||
|
||||
predicate additionalValueFlowStep(SemExpr dest, SemExpr src, int delta) { none() }
|
||||
|
||||
predicate conversionCannotOverflow(Type fromType, Type toType) {
|
||||
SemanticType::conversionCannotOverflow(fromType, toType)
|
||||
}
|
||||
@@ -101,7 +106,7 @@ module Sem implements Semantic {
|
||||
|
||||
module SignAnalysis implements SignAnalysisSig<Sem> {
|
||||
private import SignAnalysisCommon as SA
|
||||
import SA::SignAnalysis<FloatDelta, Util>
|
||||
import SA::SignAnalysis<FloatDelta>
|
||||
}
|
||||
|
||||
module ConstantBounds implements BoundSig<SemLocation, Sem, FloatDelta> {
|
||||
@@ -164,18 +169,16 @@ private module ModulusAnalysisInstantiated implements ModulusAnalysisSig<Sem> {
|
||||
class ModBound = AllBounds::SemBound;
|
||||
|
||||
private import codeql.rangeanalysis.ModulusAnalysis as MA
|
||||
import MA::ModulusAnalysis<SemLocation, Sem, FloatDelta, AllBounds, Util>
|
||||
import MA::ModulusAnalysis<SemLocation, Sem, FloatDelta, AllBounds>
|
||||
}
|
||||
|
||||
module Util = RangeUtil<FloatDelta, CppLangImplConstant>;
|
||||
|
||||
module ConstantStage =
|
||||
RangeStage<SemLocation, Sem, FloatDelta, ConstantBounds, FloatOverflow, CppLangImplConstant,
|
||||
SignAnalysis, ModulusAnalysisInstantiated, Util>;
|
||||
SignAnalysis, ModulusAnalysisInstantiated>;
|
||||
|
||||
module RelativeStage =
|
||||
RangeStage<SemLocation, Sem, FloatDelta, RelativeBounds, FloatOverflow, CppLangImplRelative,
|
||||
SignAnalysis, ModulusAnalysisInstantiated, Util>;
|
||||
SignAnalysis, ModulusAnalysisInstantiated>;
|
||||
|
||||
private newtype TSemReason =
|
||||
TSemNoReason() or
|
||||
|
||||
@@ -54,30 +54,7 @@ module CppLangImplRelative implements LangSig<Sem, FloatDelta> {
|
||||
predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
|
||||
* Holds if `e2 >= e1 + delta` (if `upper = false`) or `e2 <= e1 + delta` (if `upper = true`).
|
||||
*/
|
||||
predicate hasBound(SemExpr e, SemExpr bound, float delta, boolean upper) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the value of `dest` is known to be `src + delta`.
|
||||
*/
|
||||
predicate additionalValueFlowStep(SemExpr dest, SemExpr src, float delta) { none() }
|
||||
|
||||
/**
|
||||
* Gets the type that range analysis should use to track the result of the specified expression,
|
||||
* if a type other than the original type of the expression is to be used.
|
||||
*
|
||||
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
||||
* actually references but whose values can be tracked as the type contained in the box.
|
||||
*/
|
||||
SemType getAlternateType(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Gets the type that range analysis should use to track the result of the specified source
|
||||
* variable, if a type other than the original type of the expression is to be used.
|
||||
*
|
||||
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
||||
* actually references but whose values can be tracked as the type contained in the box.
|
||||
*/
|
||||
SemType getAlternateTypeForSsaVariable(SemSsaVariable var) { none() }
|
||||
predicate additionalBoundFlowStep(SemExpr e2, SemExpr e1, float delta, boolean upper) { none() }
|
||||
}
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
/**
|
||||
* Provides utility predicates for range analysis.
|
||||
*/
|
||||
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
private import RangeAnalysisRelativeSpecific
|
||||
private import codeql.rangeanalysis.RangeAnalysis
|
||||
private import RangeAnalysisImpl
|
||||
private import ConstantAnalysis
|
||||
|
||||
module RangeUtil<DeltaSig D, LangSig<Sem, D> Lang> implements UtilSig<Sem, D> {
|
||||
/**
|
||||
* Gets an expression that equals `v - d`.
|
||||
*/
|
||||
private SemExpr semSsaRead(SemSsaVariable v, D::Delta delta) {
|
||||
// There are various language-specific extension points that can be removed once we no longer
|
||||
// expect to match the original Java implementation's results exactly.
|
||||
result = v.getAUse() and delta = D::fromInt(0)
|
||||
or
|
||||
exists(D::Delta d1, SemConstantIntegerExpr c |
|
||||
result.(SemAddExpr).hasOperands(semSsaRead(v, d1), c) and
|
||||
delta = D::fromFloat(D::toFloat(d1) - c.getIntValue())
|
||||
)
|
||||
or
|
||||
exists(SemSubExpr sub, D::Delta d1, SemConstantIntegerExpr c |
|
||||
result = sub and
|
||||
sub.getLeftOperand() = semSsaRead(v, d1) and
|
||||
sub.getRightOperand() = c and
|
||||
delta = D::fromFloat(D::toFloat(d1) + c.getIntValue())
|
||||
)
|
||||
or
|
||||
result = v.(SemSsaExplicitUpdate).getSourceExpr() and
|
||||
delta = D::fromFloat(0)
|
||||
or
|
||||
result.(SemCopyValueExpr).getOperand() = semSsaRead(v, delta)
|
||||
or
|
||||
result.(SemStoreExpr).getOperand() = semSsaRead(v, delta)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a condition that tests whether `v` equals `e + delta`.
|
||||
*
|
||||
* If the condition evaluates to `testIsTrue`:
|
||||
* - `isEq = true` : `v == e + delta`
|
||||
* - `isEq = false` : `v != e + delta`
|
||||
*/
|
||||
pragma[nomagic]
|
||||
SemGuard semEqFlowCond(
|
||||
SemSsaVariable v, SemExpr e, D::Delta delta, boolean isEq, boolean testIsTrue
|
||||
) {
|
||||
exists(boolean eqpolarity |
|
||||
result.isEquality(semSsaRead(v, delta), e, eqpolarity) and
|
||||
(testIsTrue = true or testIsTrue = false) and
|
||||
eqpolarity.booleanXor(testIsTrue).booleanNot() = isEq
|
||||
)
|
||||
or
|
||||
exists(boolean testIsTrue0 |
|
||||
semImplies_v2(result, testIsTrue, semEqFlowCond(v, e, delta, isEq, testIsTrue0), testIsTrue0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is an `SsaExplicitUpdate` that equals `e + delta`.
|
||||
*/
|
||||
predicate semSsaUpdateStep(SemSsaExplicitUpdate v, SemExpr e, D::Delta delta) {
|
||||
exists(SemExpr defExpr | defExpr = v.getSourceExpr() |
|
||||
defExpr.(SemCopyValueExpr).getOperand() = e and delta = D::fromFloat(0)
|
||||
or
|
||||
defExpr.(SemStoreExpr).getOperand() = e and delta = D::fromFloat(0)
|
||||
or
|
||||
defExpr.(SemAddOneExpr).getOperand() = e and delta = D::fromFloat(1)
|
||||
or
|
||||
defExpr.(SemSubOneExpr).getOperand() = e and delta = D::fromFloat(-1)
|
||||
or
|
||||
e = defExpr and
|
||||
not (
|
||||
defExpr instanceof SemCopyValueExpr or
|
||||
defExpr instanceof SemStoreExpr or
|
||||
defExpr instanceof SemAddOneExpr or
|
||||
defExpr instanceof SemSubOneExpr
|
||||
) and
|
||||
delta = D::fromFloat(0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e1 + delta` equals `e2`.
|
||||
*/
|
||||
predicate semValueFlowStep(SemExpr e2, SemExpr e1, D::Delta delta) {
|
||||
e2.(SemCopyValueExpr).getOperand() = e1 and delta = D::fromFloat(0)
|
||||
or
|
||||
e2.(SemStoreExpr).getOperand() = e1 and delta = D::fromFloat(0)
|
||||
or
|
||||
e2.(SemAddOneExpr).getOperand() = e1 and delta = D::fromFloat(1)
|
||||
or
|
||||
e2.(SemSubOneExpr).getOperand() = e1 and delta = D::fromFloat(-1)
|
||||
or
|
||||
Lang::additionalValueFlowStep(e2, e1, delta)
|
||||
or
|
||||
exists(SemExpr x | e2.(SemAddExpr).hasOperands(e1, x) |
|
||||
D::fromInt(x.(SemConstantIntegerExpr).getIntValue()) = delta
|
||||
)
|
||||
or
|
||||
exists(SemExpr x, SemSubExpr sub |
|
||||
e2 = sub and
|
||||
sub.getLeftOperand() = e1 and
|
||||
sub.getRightOperand() = x
|
||||
|
|
||||
D::fromInt(-x.(SemConstantIntegerExpr).getIntValue()) = delta
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type used to track the specified expression's range information.
|
||||
*
|
||||
* Usually, this just `e.getSemType()`, but the language can override this to track immutable boxed
|
||||
* primitive types as the underlying primitive type.
|
||||
*/
|
||||
SemType getTrackedType(SemExpr e) {
|
||||
result = Lang::getAlternateType(e)
|
||||
or
|
||||
not exists(Lang::getAlternateType(e)) and result = e.getSemType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type used to track the specified source variable's range information.
|
||||
*
|
||||
* Usually, this just `e.getType()`, but the language can override this to track immutable boxed
|
||||
* primitive types as the underlying primitive type.
|
||||
*/
|
||||
SemType getTrackedTypeForSsaVariable(SemSsaVariable var) {
|
||||
result = Lang::getAlternateTypeForSsaVariable(var)
|
||||
or
|
||||
not exists(Lang::getAlternateTypeForSsaVariable(var)) and result = var.getType()
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,9 @@ private import RangeAnalysisImpl
|
||||
private import SignAnalysisSpecific as Specific
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
private import ConstantAnalysis
|
||||
private import RangeUtils
|
||||
private import Sign
|
||||
|
||||
module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
module SignAnalysis<DeltaSig D> {
|
||||
private import codeql.rangeanalysis.internal.RangeUtils::MakeUtils<Sem, D>
|
||||
|
||||
/**
|
||||
@@ -39,7 +38,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
|
||||
/** An SSA definition whose sign is determined by the sign of that definitions source expression. */
|
||||
private class ExplicitSignDef extends FlowSignDef instanceof SemSsaExplicitUpdate {
|
||||
final override Sign getSign() { result = semExprSign(super.getSourceExpr()) }
|
||||
final override Sign getSign() { result = semExprSign(super.getDefiningExpr()) }
|
||||
}
|
||||
|
||||
/** An SSA Phi definition, whose sign is the union of the signs of its inputs. */
|
||||
@@ -148,7 +147,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
not this instanceof ConstantSignExpr and
|
||||
(
|
||||
// Only track numeric types.
|
||||
Utils::getTrackedType(this) instanceof SemNumericType
|
||||
Sem::getExprType(this) instanceof SemNumericType
|
||||
or
|
||||
// Unless the language says to track this expression anyway.
|
||||
Specific::trackUnknownNonNumericExpr(this)
|
||||
@@ -203,7 +202,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
|
||||
/** An expression of an unsigned type. */
|
||||
private class UnsignedExpr extends FlowSignExpr {
|
||||
UnsignedExpr() { Utils::getTrackedType(this) instanceof SemUnsignedIntegerType }
|
||||
UnsignedExpr() { Sem::getExprType(this) instanceof SemUnsignedIntegerType }
|
||||
|
||||
override Sign getSignRestriction() {
|
||||
result = TPos() or
|
||||
@@ -276,7 +275,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
override SemUnboxExpr cast;
|
||||
|
||||
UnboxSignExpr() {
|
||||
exists(SemType fromType | fromType = Utils::getTrackedType(cast.getOperand()) |
|
||||
exists(SemType fromType | fromType = Sem::getExprType(cast.getOperand()) |
|
||||
// Only numeric source types are handled here.
|
||||
fromType instanceof SemNumericType
|
||||
)
|
||||
@@ -471,7 +470,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
||||
Sign semExprSign(SemExpr e) {
|
||||
exists(Sign s | s = e.(SignExpr).getSign() |
|
||||
if
|
||||
Utils::getTrackedType(e) instanceof SemUnsignedIntegerType and
|
||||
Sem::getExprType(e) instanceof SemUnsignedIntegerType and
|
||||
s = TNeg() and
|
||||
not Specific::ignoreTypeRestrictions(e)
|
||||
then result = TPos()
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
## 0.8.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/uninitialized-local` query has been improved to produce fewer false positives.
|
||||
|
||||
## 0.8.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -27,16 +27,26 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
|
||||
ReturnStackAllocatedMemoryConfig() { this = "ReturnStackAllocatedMemoryConfig" }
|
||||
|
||||
override predicate isSource(Instruction source) {
|
||||
// Holds if `source` is a node that represents the use of a stack variable
|
||||
exists(VariableAddressInstruction var, Function func |
|
||||
var = source and
|
||||
func = source.getEnclosingFunction() and
|
||||
var.getAstVariable() instanceof StackVariable and
|
||||
// Pointer-to-member types aren't properly handled in the dbscheme.
|
||||
not var.getResultType() instanceof PointerToMemberType and
|
||||
exists(Function func |
|
||||
// Rule out FPs caused by extraction errors.
|
||||
not any(ErrorExpr e).getEnclosingFunction() = func and
|
||||
not intentionallyReturnsStackPointer(func)
|
||||
not intentionallyReturnsStackPointer(func) and
|
||||
func = source.getEnclosingFunction()
|
||||
|
|
||||
// `source` is an instruction that represents the use of a stack variable
|
||||
exists(VariableAddressInstruction var |
|
||||
var = source and
|
||||
var.getAstVariable() instanceof StackVariable and
|
||||
// Pointer-to-member types aren't properly handled in the dbscheme.
|
||||
not var.getResultType() instanceof PointerToMemberType
|
||||
)
|
||||
or
|
||||
// `source` is an instruction that represents the return value of a
|
||||
// function that is known to return stack-allocated memory.
|
||||
exists(Call call |
|
||||
call.getTarget().hasGlobalName(["alloca", "strdupa", "strndupa", "_alloca", "_malloca"]) and
|
||||
source.getUnconvertedResultExpression() = call
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -85,10 +95,10 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
|
||||
}
|
||||
|
||||
from
|
||||
MustFlowPathNode source, MustFlowPathNode sink, VariableAddressInstruction var,
|
||||
MustFlowPathNode source, MustFlowPathNode sink, Instruction instr,
|
||||
ReturnStackAllocatedMemoryConfig conf
|
||||
where
|
||||
conf.hasFlowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and
|
||||
source.getInstruction() = var
|
||||
source.getInstruction() = instr
|
||||
select sink.getInstruction(), source, sink, "May return stack-allocated memory from $@.",
|
||||
var.getAst(), var.getAst().toString()
|
||||
instr.getAst(), instr.getAst().toString()
|
||||
|
||||
@@ -14,25 +14,47 @@
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.security.Security
|
||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
||||
import TaintedWithPath
|
||||
import semmle.code.cpp.security.FlowSources
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
import semmle.code.cpp.ir.IR
|
||||
import Flow::PathGraph
|
||||
|
||||
predicate isProcessOperationExplanation(Expr arg, string processOperation) {
|
||||
predicate isProcessOperationExplanation(DataFlow::Node arg, string processOperation) {
|
||||
exists(int processOperationArg, FunctionCall call |
|
||||
isProcessOperationArgument(processOperation, processOperationArg) and
|
||||
call.getTarget().getName() = processOperation and
|
||||
call.getArgument(processOperationArg) = arg
|
||||
call.getArgument(processOperationArg) = [arg.asExpr(), arg.asIndirectExpr()]
|
||||
)
|
||||
}
|
||||
|
||||
class Configuration extends TaintTrackingConfiguration {
|
||||
override predicate isSink(Element arg) { isProcessOperationExplanation(arg, _) }
|
||||
predicate isSource(FlowSource source, string sourceType) {
|
||||
not source instanceof DataFlow::ExprNode and
|
||||
sourceType = source.getSourceType()
|
||||
}
|
||||
|
||||
from string processOperation, Expr arg, Expr source, PathNode sourceNode, PathNode sinkNode
|
||||
module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node node) { isSource(node, _) }
|
||||
|
||||
predicate isSink(DataFlow::Node node) { isProcessOperationExplanation(node, _) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
isSink(node) and node.asExpr().getUnspecifiedType() instanceof ArithmeticType
|
||||
or
|
||||
node.asInstruction().(StoreInstruction).getResultType() instanceof ArithmeticType
|
||||
}
|
||||
}
|
||||
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
|
||||
from
|
||||
string processOperation, string sourceType, DataFlow::Node source, DataFlow::Node sink,
|
||||
Flow::PathNode sourceNode, Flow::PathNode sinkNode
|
||||
where
|
||||
isProcessOperationExplanation(arg, processOperation) and
|
||||
taintedWithPath(source, arg, sourceNode, sinkNode)
|
||||
select arg, sourceNode, sinkNode,
|
||||
source = sourceNode.getNode() and
|
||||
sink = sinkNode.getNode() and
|
||||
isSource(source, sourceType) and
|
||||
isProcessOperationExplanation(sink, processOperation) and
|
||||
Flow::flowPath(sourceNode, sinkNode)
|
||||
select sink, sourceNode, sinkNode,
|
||||
"The value of this argument may come from $@ and is being passed to " + processOperation + ".",
|
||||
source, source.toString()
|
||||
source, sourceType
|
||||
|
||||
@@ -52,16 +52,17 @@ predicate isUnboundedWrite(BufferWrite bw) {
|
||||
* Holds if `e` is a source buffer going into an unbounded write `bw` or a
|
||||
* qualifier of (a qualifier of ...) such a source.
|
||||
*/
|
||||
predicate unboundedWriteSource(Expr e, BufferWrite bw) {
|
||||
isUnboundedWrite(bw) and e = bw.getASource()
|
||||
predicate unboundedWriteSource(Expr e, BufferWrite bw, boolean qualifier) {
|
||||
isUnboundedWrite(bw) and e = bw.getASource() and qualifier = false
|
||||
or
|
||||
exists(FieldAccess fa | unboundedWriteSource(fa, bw) and e = fa.getQualifier())
|
||||
exists(FieldAccess fa | unboundedWriteSource(fa, bw, _) and e = fa.getQualifier()) and
|
||||
qualifier = true
|
||||
}
|
||||
|
||||
predicate isSource(FS::FlowSource source, string sourceType) { source.getSourceType() = sourceType }
|
||||
|
||||
predicate isSink(DataFlow::Node sink, BufferWrite bw) {
|
||||
unboundedWriteSource(sink.asIndirectExpr(), bw)
|
||||
predicate isSink(DataFlow::Node sink, BufferWrite bw, boolean qualifier) {
|
||||
unboundedWriteSource(sink.asIndirectExpr(), bw, qualifier)
|
||||
or
|
||||
// `gets` and `scanf` reads from stdin so there's no real input.
|
||||
// The `BufferWrite` library models this as the call itself being
|
||||
@@ -69,7 +70,7 @@ predicate isSink(DataFlow::Node sink, BufferWrite bw) {
|
||||
// the sink so that we report a path where source = sink (because
|
||||
// the same output argument is also included in `isSource`).
|
||||
bw.getASource() = bw and
|
||||
unboundedWriteSource(sink.asDefiningArgument(), bw)
|
||||
unboundedWriteSource(sink.asDefiningArgument(), bw, qualifier)
|
||||
}
|
||||
|
||||
predicate lessThanOrEqual(IRGuardCondition g, Expr e, boolean branch) {
|
||||
@@ -84,9 +85,9 @@ predicate lessThanOrEqual(IRGuardCondition g, Expr e, boolean branch) {
|
||||
module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { isSource(source, _) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { isSink(sink, _) }
|
||||
predicate isSink(DataFlow::Node sink) { isSink(sink, _, _) }
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) { isSink(node) }
|
||||
predicate isBarrierOut(DataFlow::Node node) { isSink(node, _, false) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
// Block flow if the node is guarded by any <, <= or = operations.
|
||||
@@ -116,7 +117,7 @@ from BufferWrite bw, Flow::PathNode source, Flow::PathNode sink, string sourceTy
|
||||
where
|
||||
Flow::flowPath(source, sink) and
|
||||
isSource(source.getNode(), sourceType) and
|
||||
isSink(sink.getNode(), bw)
|
||||
isSink(sink.getNode(), bw, _)
|
||||
select bw, source, sink,
|
||||
"This '" + bw.getBWDesc() + "' with input from $@ may overflow the destination.",
|
||||
source.getNode(), sourceType
|
||||
|
||||
@@ -14,10 +14,13 @@
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.security.Overflow
|
||||
import semmle.code.cpp.security.Security
|
||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
||||
import TaintedWithPath
|
||||
import semmle.code.cpp.dataflow.new.TaintTracking
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.controlflow.IRGuards as IRGuards
|
||||
import semmle.code.cpp.security.FlowSources as FS
|
||||
import Bounded
|
||||
import Flow::PathGraph
|
||||
|
||||
bindingset[op]
|
||||
predicate missingGuard(Operation op, Expr e, string effect) {
|
||||
@@ -28,28 +31,90 @@ predicate missingGuard(Operation op, Expr e, string effect) {
|
||||
not e instanceof VariableAccess and effect = "overflow"
|
||||
}
|
||||
|
||||
class Configuration extends TaintTrackingConfiguration {
|
||||
override predicate isSink(Element e) {
|
||||
exists(Operation op |
|
||||
missingGuard(op, e, _) and
|
||||
op.getAnOperand() = e
|
||||
|
|
||||
op instanceof UnaryArithmeticOperation or
|
||||
op instanceof BinaryArithmeticOperation or
|
||||
op instanceof AssignArithmeticOperation
|
||||
)
|
||||
}
|
||||
predicate isSource(FS::FlowSource source, string sourceType) { sourceType = source.getSourceType() }
|
||||
|
||||
override predicate isBarrier(Expr e) {
|
||||
super.isBarrier(e) or bounded(e) or e.getUnspecifiedType().(IntegralType).getSize() <= 1
|
||||
predicate isSink(DataFlow::Node sink, Operation op, Expr e) {
|
||||
e = sink.asExpr() and
|
||||
missingGuard(op, e, _) and
|
||||
op.getAnOperand() = e and
|
||||
(
|
||||
op instanceof UnaryArithmeticOperation or
|
||||
op instanceof BinaryArithmeticOperation or
|
||||
op instanceof AssignArithmeticOperation
|
||||
)
|
||||
}
|
||||
|
||||
predicate hasUpperBoundsCheck(Variable var) {
|
||||
exists(RelationalOperation oper, VariableAccess access |
|
||||
oper.getAnOperand() = access and
|
||||
access.getTarget() = var and
|
||||
// Comparing to 0 is not an upper bound check
|
||||
not oper.getAnOperand().getValue() = "0"
|
||||
)
|
||||
}
|
||||
|
||||
predicate constantInstruction(Instruction instr) {
|
||||
instr instanceof ConstantInstruction or
|
||||
constantInstruction(instr.(UnaryInstruction).getUnary())
|
||||
}
|
||||
|
||||
predicate readsVariable(LoadInstruction load, Variable var) {
|
||||
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
|
||||
}
|
||||
|
||||
predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Variable checkedVar) {
|
||||
exists(Instruction instr | instr = node.asInstruction() |
|
||||
readsVariable(instr, checkedVar) and
|
||||
any(IRGuards::IRGuardCondition guard).ensuresEq(access, _, _, instr.getBlock(), true)
|
||||
)
|
||||
}
|
||||
|
||||
module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { isSource(source, _) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { isSink(sink, _, _) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
exists(StoreInstruction store | store = node.asInstruction() |
|
||||
// Block flow to "likely small expressions"
|
||||
bounded(store.getSourceValue().getUnconvertedResultExpression())
|
||||
or
|
||||
// Block flow to "small types"
|
||||
store.getResultType().getUnspecifiedType().(IntegralType).getSize() <= 1
|
||||
)
|
||||
or
|
||||
// Block flow if there's an upper bound check of the variable anywhere in the program
|
||||
exists(Variable checkedVar, Instruction instr | instr = node.asInstruction() |
|
||||
readsVariable(instr, checkedVar) and
|
||||
hasUpperBoundsCheck(checkedVar)
|
||||
)
|
||||
or
|
||||
// Block flow if the node is guarded by an equality check
|
||||
exists(Variable checkedVar, Operand access |
|
||||
nodeIsBarrierEqualityCandidate(node, access, checkedVar) and
|
||||
readsVariable(access.getDef(), checkedVar)
|
||||
)
|
||||
or
|
||||
// Block flow to any binary instruction whose operands are both non-constants.
|
||||
exists(BinaryInstruction iTo |
|
||||
iTo = node.asInstruction() and
|
||||
not constantInstruction(iTo.getLeft()) and
|
||||
not constantInstruction(iTo.getRight()) and
|
||||
// propagate taint from either the pointer or the offset, regardless of constantness
|
||||
not iTo instanceof PointerArithmeticInstruction
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from Expr origin, Expr e, string effect, PathNode sourceNode, PathNode sinkNode, Operation op
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
|
||||
from
|
||||
Expr e, string effect, Flow::PathNode source, Flow::PathNode sink, Operation op, string sourceType
|
||||
where
|
||||
taintedWithPath(origin, e, sourceNode, sinkNode) and
|
||||
op.getAnOperand() = e and
|
||||
Flow::flowPath(source, sink) and
|
||||
isSource(source.getNode(), sourceType) and
|
||||
isSink(sink.getNode(), op, e) and
|
||||
missingGuard(op, e, effect)
|
||||
select e, sourceNode, sinkNode,
|
||||
select e, source, sink,
|
||||
"$@ flows to an operand of an arithmetic expression, potentially causing an " + effect + ".",
|
||||
origin, "User-provided value"
|
||||
source, sourceType
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* @description The total number of lines of C/C++ code across all files, including system headers, libraries, and auto-generated files. This is a useful metric of the size of a database. For all files that were seen during the build, this query counts the lines of code, excluding whitespace or comments.
|
||||
* @kind metric
|
||||
* @tags summary
|
||||
* telemetry
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added SQL API models for `ODBC`.
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
## 0.8.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/uninitialized-local` query has been improved to produce fewer false positives.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.8.2
|
||||
lastReleaseVersion: 0.8.3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 0.8.3-dev
|
||||
version: 0.8.3
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -2,7 +2,6 @@ import cpp
|
||||
import codeql.rangeanalysis.ModulusAnalysis
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticLocation
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeUtils
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisRelativeSpecific
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisImpl
|
||||
@@ -10,9 +9,7 @@ import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
module ModulusAnalysisInstantiated =
|
||||
ModulusAnalysis<SemLocation, Sem, FloatDelta, ConstantBounds,
|
||||
RangeUtil<FloatDelta, CppLangImplRelative>>;
|
||||
module ModulusAnalysisInstantiated = ModulusAnalysis<SemLocation, Sem, FloatDelta, ConstantBounds>;
|
||||
|
||||
module ModulusAnalysisTest implements TestSig {
|
||||
string getARelevantTag() { result = "mod" }
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.SignAnalysisCommon
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeUtils
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisRelativeSpecific
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
module SignAnalysisInstantiated =
|
||||
SignAnalysis<FloatDelta, RangeUtil<FloatDelta, CppLangImplRelative>>;
|
||||
module SignAnalysisInstantiated = SignAnalysis<FloatDelta>;
|
||||
|
||||
module SignAnalysisTest implements TestSig {
|
||||
string getARelevantTag() { result = "sign" }
|
||||
|
||||
@@ -43,6 +43,11 @@ edges
|
||||
| test.cpp:189:16:189:16 | p | test.cpp:189:16:189:16 | (reference to) |
|
||||
| test.cpp:190:10:190:13 | (reference dereference) | test.cpp:190:10:190:13 | (reference to) |
|
||||
| test.cpp:190:10:190:13 | pRef | test.cpp:190:10:190:13 | (reference dereference) |
|
||||
| test.cpp:237:12:237:17 | call to alloca | test.cpp:237:12:237:17 | call to alloca |
|
||||
| test.cpp:237:12:237:17 | call to alloca | test.cpp:238:9:238:9 | p |
|
||||
| test.cpp:249:13:249:20 | call to strndupa | test.cpp:249:13:249:20 | call to strndupa |
|
||||
| test.cpp:249:13:249:20 | call to strndupa | test.cpp:250:9:250:10 | s2 |
|
||||
| test.cpp:250:9:250:10 | s2 | test.cpp:250:9:250:10 | (void *)... |
|
||||
nodes
|
||||
| test.cpp:17:9:17:11 | & ... | semmle.label | & ... |
|
||||
| test.cpp:17:10:17:11 | mc | semmle.label | mc |
|
||||
@@ -101,6 +106,14 @@ nodes
|
||||
| test.cpp:190:10:190:13 | (reference dereference) | semmle.label | (reference dereference) |
|
||||
| test.cpp:190:10:190:13 | (reference to) | semmle.label | (reference to) |
|
||||
| test.cpp:190:10:190:13 | pRef | semmle.label | pRef |
|
||||
| test.cpp:237:12:237:17 | call to alloca | semmle.label | call to alloca |
|
||||
| test.cpp:237:12:237:17 | call to alloca | semmle.label | call to alloca |
|
||||
| test.cpp:238:9:238:9 | p | semmle.label | p |
|
||||
| test.cpp:245:9:245:15 | call to strdupa | semmle.label | call to strdupa |
|
||||
| test.cpp:249:13:249:20 | call to strndupa | semmle.label | call to strndupa |
|
||||
| test.cpp:249:13:249:20 | call to strndupa | semmle.label | call to strndupa |
|
||||
| test.cpp:250:9:250:10 | (void *)... | semmle.label | (void *)... |
|
||||
| test.cpp:250:9:250:10 | s2 | semmle.label | s2 |
|
||||
#select
|
||||
| test.cpp:17:9:17:11 | CopyValue: & ... | test.cpp:17:10:17:11 | mc | test.cpp:17:9:17:11 | & ... | May return stack-allocated memory from $@. | test.cpp:17:10:17:11 | mc | mc |
|
||||
| test.cpp:25:9:25:11 | Load: ptr | test.cpp:23:18:23:19 | mc | test.cpp:25:9:25:11 | ptr | May return stack-allocated memory from $@. | test.cpp:23:18:23:19 | mc | mc |
|
||||
@@ -115,3 +128,6 @@ nodes
|
||||
| test.cpp:177:10:177:23 | Convert: (void *)... | test.cpp:176:25:176:34 | localArray | test.cpp:177:10:177:23 | (void *)... | May return stack-allocated memory from $@. | test.cpp:176:25:176:34 | localArray | localArray |
|
||||
| test.cpp:183:10:183:19 | CopyValue: (reference to) | test.cpp:182:21:182:27 | myLocal | test.cpp:183:10:183:19 | (reference to) | May return stack-allocated memory from $@. | test.cpp:182:21:182:27 | myLocal | myLocal |
|
||||
| test.cpp:190:10:190:13 | CopyValue: (reference to) | test.cpp:189:16:189:16 | p | test.cpp:190:10:190:13 | (reference to) | May return stack-allocated memory from $@. | test.cpp:189:16:189:16 | p | p |
|
||||
| test.cpp:238:9:238:9 | Load: p | test.cpp:237:12:237:17 | call to alloca | test.cpp:238:9:238:9 | p | May return stack-allocated memory from $@. | test.cpp:237:12:237:17 | call to alloca | call to alloca |
|
||||
| test.cpp:245:9:245:15 | Call: call to strdupa | test.cpp:245:9:245:15 | call to strdupa | test.cpp:245:9:245:15 | call to strdupa | May return stack-allocated memory from $@. | test.cpp:245:9:245:15 | call to strdupa | call to strdupa |
|
||||
| test.cpp:250:9:250:10 | Convert: (void *)... | test.cpp:249:13:249:20 | call to strndupa | test.cpp:250:9:250:10 | (void *)... | May return stack-allocated memory from $@. | test.cpp:249:13:249:20 | call to strndupa | call to strndupa |
|
||||
|
||||
@@ -229,4 +229,23 @@ int* id(int* px) {
|
||||
void f() {
|
||||
int x;
|
||||
int* px = id(&x); // GOOD
|
||||
}
|
||||
|
||||
void *alloca(size_t);
|
||||
|
||||
void* test_alloca() {
|
||||
void* p = alloca(10);
|
||||
return p; // BAD
|
||||
}
|
||||
|
||||
char *strdupa(const char *);
|
||||
char *strndupa(const char *, size_t);
|
||||
|
||||
char* test_strdupa(const char* s) {
|
||||
return strdupa(s); // BAD
|
||||
}
|
||||
|
||||
void* test_strndupa(const char* s, size_t size) {
|
||||
char* s2 = strndupa(s, size);
|
||||
return s2; // BAD
|
||||
}
|
||||
@@ -1,23 +1,12 @@
|
||||
edges
|
||||
| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | data |
|
||||
| test.cpp:37:73:37:76 | data | test.cpp:43:32:43:35 | data |
|
||||
| test.cpp:37:73:37:76 | data indirection | test.cpp:43:32:43:35 | data |
|
||||
| test.cpp:37:73:37:76 | data indirection | test.cpp:43:32:43:35 | data |
|
||||
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data |
|
||||
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data |
|
||||
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data indirection |
|
||||
| test.cpp:64:30:64:35 | call to getenv | test.cpp:73:24:73:27 | data indirection |
|
||||
| test.cpp:73:24:73:27 | data | test.cpp:37:73:37:76 | data |
|
||||
| test.cpp:37:73:37:76 | data indirection | test.cpp:43:32:43:35 | data indirection |
|
||||
| test.cpp:64:30:64:35 | call to getenv indirection | test.cpp:73:24:73:27 | data indirection |
|
||||
| test.cpp:73:24:73:27 | data indirection | test.cpp:37:73:37:76 | data indirection |
|
||||
subpaths
|
||||
nodes
|
||||
| test.cpp:37:73:37:76 | data | semmle.label | data |
|
||||
| test.cpp:37:73:37:76 | data indirection | semmle.label | data indirection |
|
||||
| test.cpp:43:32:43:35 | data | semmle.label | data |
|
||||
| test.cpp:43:32:43:35 | data | semmle.label | data |
|
||||
| test.cpp:64:30:64:35 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:64:30:64:35 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:73:24:73:27 | data | semmle.label | data |
|
||||
| test.cpp:43:32:43:35 | data indirection | semmle.label | data indirection |
|
||||
| test.cpp:64:30:64:35 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| test.cpp:73:24:73:27 | data indirection | semmle.label | data indirection |
|
||||
subpaths
|
||||
#select
|
||||
| test.cpp:43:32:43:35 | data | test.cpp:64:30:64:35 | call to getenv | test.cpp:43:32:43:35 | data | The value of this argument may come from $@ and is being passed to LoadLibraryA. | test.cpp:64:30:64:35 | call to getenv | call to getenv |
|
||||
| test.cpp:43:32:43:35 | data indirection | test.cpp:64:30:64:35 | call to getenv indirection | test.cpp:43:32:43:35 | data indirection | The value of this argument may come from $@ and is being passed to LoadLibraryA. | test.cpp:64:30:64:35 | call to getenv indirection | an environment variable |
|
||||
|
||||
@@ -1,112 +1,48 @@
|
||||
edges
|
||||
| test.cpp:24:30:24:36 | command | test.cpp:26:10:26:16 | command |
|
||||
| test.cpp:24:30:24:36 | command | test.cpp:26:10:26:16 | command |
|
||||
| test.cpp:29:30:29:36 | command | test.cpp:31:10:31:16 | command |
|
||||
| test.cpp:29:30:29:36 | command | test.cpp:31:10:31:16 | command |
|
||||
| test.cpp:42:18:42:23 | call to getenv | test.cpp:24:30:24:36 | command |
|
||||
| test.cpp:42:18:42:34 | call to getenv | test.cpp:24:30:24:36 | command |
|
||||
| test.cpp:43:18:43:23 | call to getenv | test.cpp:29:30:29:36 | command |
|
||||
| test.cpp:43:18:43:34 | call to getenv | test.cpp:29:30:29:36 | command |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:64:10:64:16 | dataref |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:64:10:64:16 | dataref |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:64:10:64:16 | dataref |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:64:10:64:16 | dataref |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:64:10:64:16 | dataref |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:64:10:64:16 | dataref |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:65:10:65:14 | data2 |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:65:10:65:14 | data2 |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:65:10:65:14 | data2 |
|
||||
| test.cpp:56:12:56:17 | buffer | test.cpp:65:10:65:14 | data2 |
|
||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | buffer |
|
||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | buffer |
|
||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | data |
|
||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | data |
|
||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:64:10:64:16 | dataref |
|
||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:64:10:64:16 | dataref |
|
||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:64:10:64:16 | dataref |
|
||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:65:10:65:14 | data2 |
|
||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:65:10:65:14 | data2 |
|
||||
| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer |
|
||||
| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer |
|
||||
| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer |
|
||||
| test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer |
|
||||
| test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | buffer |
|
||||
| test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | buffer |
|
||||
| test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer |
|
||||
| test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer |
|
||||
| test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer |
|
||||
| test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer |
|
||||
| test.cpp:98:17:98:22 | recv output argument | test.cpp:99:15:99:20 | buffer |
|
||||
| test.cpp:98:17:98:22 | recv output argument | test.cpp:99:15:99:20 | buffer |
|
||||
| test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | buffer |
|
||||
| test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | buffer |
|
||||
| test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | buffer |
|
||||
| test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | buffer |
|
||||
| test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | buffer |
|
||||
| test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | buffer |
|
||||
| test.cpp:113:8:113:12 | call to fgets | test.cpp:114:9:114:11 | ptr |
|
||||
| test.cpp:113:8:113:12 | call to fgets | test.cpp:114:9:114:11 | ptr |
|
||||
| test.cpp:113:8:113:12 | call to fgets | test.cpp:114:9:114:11 | ptr |
|
||||
| test.cpp:113:8:113:12 | call to fgets | test.cpp:114:9:114:11 | ptr |
|
||||
subpaths
|
||||
| test.cpp:24:30:24:36 | command indirection | test.cpp:26:10:26:16 | command indirection |
|
||||
| test.cpp:29:30:29:36 | command indirection | test.cpp:31:10:31:16 | command indirection |
|
||||
| test.cpp:42:18:42:34 | call to getenv indirection | test.cpp:24:30:24:36 | command indirection |
|
||||
| test.cpp:43:18:43:34 | call to getenv indirection | test.cpp:29:30:29:36 | command indirection |
|
||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | buffer indirection |
|
||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | data indirection |
|
||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:64:10:64:16 | (reference dereference) indirection |
|
||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:64:10:64:16 | dataref indirection |
|
||||
| test.cpp:56:12:56:17 | fgets output argument | test.cpp:65:10:65:14 | data2 indirection |
|
||||
| test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | buffer indirection |
|
||||
| test.cpp:98:17:98:22 | recv output argument | test.cpp:99:15:99:20 | buffer indirection |
|
||||
| test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | buffer indirection |
|
||||
| test.cpp:113:8:113:12 | call to fgets indirection | test.cpp:114:9:114:11 | ptr indirection |
|
||||
nodes
|
||||
| test.cpp:24:30:24:36 | command | semmle.label | command |
|
||||
| test.cpp:26:10:26:16 | command | semmle.label | command |
|
||||
| test.cpp:26:10:26:16 | command | semmle.label | command |
|
||||
| test.cpp:29:30:29:36 | command | semmle.label | command |
|
||||
| test.cpp:31:10:31:16 | command | semmle.label | command |
|
||||
| test.cpp:31:10:31:16 | command | semmle.label | command |
|
||||
| test.cpp:42:18:42:23 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:42:18:42:34 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:43:18:43:23 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:43:18:43:34 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:56:12:56:17 | buffer | semmle.label | buffer |
|
||||
| test.cpp:56:12:56:17 | buffer | semmle.label | buffer |
|
||||
| test.cpp:24:30:24:36 | command indirection | semmle.label | command indirection |
|
||||
| test.cpp:26:10:26:16 | command indirection | semmle.label | command indirection |
|
||||
| test.cpp:29:30:29:36 | command indirection | semmle.label | command indirection |
|
||||
| test.cpp:31:10:31:16 | command indirection | semmle.label | command indirection |
|
||||
| test.cpp:42:18:42:34 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| test.cpp:43:18:43:34 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| test.cpp:56:12:56:17 | fgets output argument | semmle.label | fgets output argument |
|
||||
| test.cpp:62:10:62:15 | buffer | semmle.label | buffer |
|
||||
| test.cpp:62:10:62:15 | buffer | semmle.label | buffer |
|
||||
| test.cpp:63:10:63:13 | data | semmle.label | data |
|
||||
| test.cpp:63:10:63:13 | data | semmle.label | data |
|
||||
| test.cpp:64:10:64:16 | dataref | semmle.label | dataref |
|
||||
| test.cpp:64:10:64:16 | dataref | semmle.label | dataref |
|
||||
| test.cpp:64:10:64:16 | dataref | semmle.label | dataref |
|
||||
| test.cpp:65:10:65:14 | data2 | semmle.label | data2 |
|
||||
| test.cpp:65:10:65:14 | data2 | semmle.label | data2 |
|
||||
| test.cpp:76:12:76:17 | buffer | semmle.label | buffer |
|
||||
| test.cpp:76:12:76:17 | buffer | semmle.label | buffer |
|
||||
| test.cpp:62:10:62:15 | buffer indirection | semmle.label | buffer indirection |
|
||||
| test.cpp:63:10:63:13 | data indirection | semmle.label | data indirection |
|
||||
| test.cpp:64:10:64:16 | (reference dereference) indirection | semmle.label | (reference dereference) indirection |
|
||||
| test.cpp:64:10:64:16 | dataref indirection | semmle.label | dataref indirection |
|
||||
| test.cpp:65:10:65:14 | data2 indirection | semmle.label | data2 indirection |
|
||||
| test.cpp:76:12:76:17 | fgets output argument | semmle.label | fgets output argument |
|
||||
| test.cpp:78:10:78:15 | buffer | semmle.label | buffer |
|
||||
| test.cpp:78:10:78:15 | buffer | semmle.label | buffer |
|
||||
| test.cpp:98:17:98:22 | buffer | semmle.label | buffer |
|
||||
| test.cpp:98:17:98:22 | buffer | semmle.label | buffer |
|
||||
| test.cpp:78:10:78:15 | buffer indirection | semmle.label | buffer indirection |
|
||||
| test.cpp:98:17:98:22 | recv output argument | semmle.label | recv output argument |
|
||||
| test.cpp:99:15:99:20 | buffer | semmle.label | buffer |
|
||||
| test.cpp:99:15:99:20 | buffer | semmle.label | buffer |
|
||||
| test.cpp:106:17:106:22 | buffer | semmle.label | buffer |
|
||||
| test.cpp:106:17:106:22 | buffer | semmle.label | buffer |
|
||||
| test.cpp:99:15:99:20 | buffer indirection | semmle.label | buffer indirection |
|
||||
| test.cpp:106:17:106:22 | recv output argument | semmle.label | recv output argument |
|
||||
| test.cpp:107:15:107:20 | buffer | semmle.label | buffer |
|
||||
| test.cpp:107:15:107:20 | buffer | semmle.label | buffer |
|
||||
| test.cpp:113:8:113:12 | call to fgets | semmle.label | call to fgets |
|
||||
| test.cpp:113:8:113:12 | call to fgets | semmle.label | call to fgets |
|
||||
| test.cpp:114:9:114:11 | ptr | semmle.label | ptr |
|
||||
| test.cpp:114:9:114:11 | ptr | semmle.label | ptr |
|
||||
| test.cpp:107:15:107:20 | buffer indirection | semmle.label | buffer indirection |
|
||||
| test.cpp:113:8:113:12 | call to fgets indirection | semmle.label | call to fgets indirection |
|
||||
| test.cpp:114:9:114:11 | ptr indirection | semmle.label | ptr indirection |
|
||||
subpaths
|
||||
#select
|
||||
| test.cpp:26:10:26:16 | command | test.cpp:42:18:42:23 | call to getenv | test.cpp:26:10:26:16 | command | The value of this argument may come from $@ and is being passed to system. | test.cpp:42:18:42:23 | call to getenv | call to getenv |
|
||||
| test.cpp:31:10:31:16 | command | test.cpp:43:18:43:23 | call to getenv | test.cpp:31:10:31:16 | command | The value of this argument may come from $@ and is being passed to system. | test.cpp:43:18:43:23 | call to getenv | call to getenv |
|
||||
| test.cpp:62:10:62:15 | buffer | test.cpp:56:12:56:17 | buffer | test.cpp:62:10:62:15 | buffer | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | buffer | buffer |
|
||||
| test.cpp:63:10:63:13 | data | test.cpp:56:12:56:17 | buffer | test.cpp:63:10:63:13 | data | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | buffer | buffer |
|
||||
| test.cpp:64:10:64:16 | dataref | test.cpp:56:12:56:17 | buffer | test.cpp:64:10:64:16 | dataref | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | buffer | buffer |
|
||||
| test.cpp:65:10:65:14 | data2 | test.cpp:56:12:56:17 | buffer | test.cpp:65:10:65:14 | data2 | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | buffer | buffer |
|
||||
| test.cpp:78:10:78:15 | buffer | test.cpp:76:12:76:17 | buffer | test.cpp:78:10:78:15 | buffer | The value of this argument may come from $@ and is being passed to system. | test.cpp:76:12:76:17 | buffer | buffer |
|
||||
| test.cpp:99:15:99:20 | buffer | test.cpp:98:17:98:22 | buffer | test.cpp:99:15:99:20 | buffer | The value of this argument may come from $@ and is being passed to LoadLibrary. | test.cpp:98:17:98:22 | buffer | buffer |
|
||||
| test.cpp:107:15:107:20 | buffer | test.cpp:106:17:106:22 | buffer | test.cpp:107:15:107:20 | buffer | The value of this argument may come from $@ and is being passed to LoadLibrary. | test.cpp:106:17:106:22 | buffer | buffer |
|
||||
| test.cpp:114:9:114:11 | ptr | test.cpp:113:8:113:12 | call to fgets | test.cpp:114:9:114:11 | ptr | The value of this argument may come from $@ and is being passed to system. | test.cpp:113:8:113:12 | call to fgets | call to fgets |
|
||||
| test.cpp:26:10:26:16 | command indirection | test.cpp:42:18:42:34 | call to getenv indirection | test.cpp:26:10:26:16 | command indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:42:18:42:34 | call to getenv indirection | an environment variable |
|
||||
| test.cpp:31:10:31:16 | command indirection | test.cpp:43:18:43:34 | call to getenv indirection | test.cpp:31:10:31:16 | command indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:43:18:43:34 | call to getenv indirection | an environment variable |
|
||||
| test.cpp:62:10:62:15 | buffer indirection | test.cpp:56:12:56:17 | fgets output argument | test.cpp:62:10:62:15 | buffer indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | fgets output argument | string read by fgets |
|
||||
| test.cpp:63:10:63:13 | data indirection | test.cpp:56:12:56:17 | fgets output argument | test.cpp:63:10:63:13 | data indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | fgets output argument | string read by fgets |
|
||||
| test.cpp:64:10:64:16 | (reference dereference) indirection | test.cpp:56:12:56:17 | fgets output argument | test.cpp:64:10:64:16 | (reference dereference) indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | fgets output argument | string read by fgets |
|
||||
| test.cpp:64:10:64:16 | dataref indirection | test.cpp:56:12:56:17 | fgets output argument | test.cpp:64:10:64:16 | dataref indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | fgets output argument | string read by fgets |
|
||||
| test.cpp:65:10:65:14 | data2 indirection | test.cpp:56:12:56:17 | fgets output argument | test.cpp:65:10:65:14 | data2 indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:56:12:56:17 | fgets output argument | string read by fgets |
|
||||
| test.cpp:78:10:78:15 | buffer indirection | test.cpp:76:12:76:17 | fgets output argument | test.cpp:78:10:78:15 | buffer indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:76:12:76:17 | fgets output argument | string read by fgets |
|
||||
| test.cpp:99:15:99:20 | buffer indirection | test.cpp:98:17:98:22 | recv output argument | test.cpp:99:15:99:20 | buffer indirection | The value of this argument may come from $@ and is being passed to LoadLibrary. | test.cpp:98:17:98:22 | recv output argument | buffer read by recv |
|
||||
| test.cpp:107:15:107:20 | buffer indirection | test.cpp:106:17:106:22 | recv output argument | test.cpp:107:15:107:20 | buffer indirection | The value of this argument may come from $@ and is being passed to LoadLibrary. | test.cpp:106:17:106:22 | recv output argument | buffer read by recv |
|
||||
| test.cpp:114:9:114:11 | ptr indirection | test.cpp:113:8:113:12 | call to fgets indirection | test.cpp:114:9:114:11 | ptr indirection | The value of this argument may come from $@ and is being passed to system. | test.cpp:113:8:113:12 | call to fgets indirection | string read by fgets |
|
||||
|
||||
@@ -1,4 +1,32 @@
|
||||
edges
|
||||
subpaths
|
||||
| main.cpp:6:27:6:30 | argv indirection | main.cpp:10:20:10:23 | argv indirection |
|
||||
| main.cpp:10:20:10:23 | argv indirection | tests.cpp:631:32:631:35 | argv indirection |
|
||||
| tests.cpp:613:19:613:24 | source indirection | tests.cpp:615:17:615:22 | source indirection |
|
||||
| tests.cpp:622:19:622:24 | source indirection | tests.cpp:625:2:625:16 | ... = ... indirection |
|
||||
| tests.cpp:625:2:625:16 | ... = ... indirection | tests.cpp:625:4:625:7 | s indirection [post update] [home indirection] |
|
||||
| tests.cpp:625:4:625:7 | s indirection [post update] [home indirection] | tests.cpp:628:14:628:14 | s indirection [home indirection] |
|
||||
| tests.cpp:628:14:628:14 | s indirection [home indirection] | tests.cpp:628:14:628:19 | home indirection |
|
||||
| tests.cpp:628:14:628:14 | s indirection [home indirection] | tests.cpp:628:16:628:19 | home indirection |
|
||||
| tests.cpp:628:16:628:19 | home indirection | tests.cpp:628:14:628:19 | home indirection |
|
||||
| tests.cpp:631:32:631:35 | argv indirection | tests.cpp:656:9:656:15 | access to array indirection |
|
||||
| tests.cpp:631:32:631:35 | argv indirection | tests.cpp:657:9:657:15 | access to array indirection |
|
||||
| tests.cpp:656:9:656:15 | access to array indirection | tests.cpp:613:19:613:24 | source indirection |
|
||||
| tests.cpp:657:9:657:15 | access to array indirection | tests.cpp:622:19:622:24 | source indirection |
|
||||
nodes
|
||||
| main.cpp:6:27:6:30 | argv indirection | semmle.label | argv indirection |
|
||||
| main.cpp:10:20:10:23 | argv indirection | semmle.label | argv indirection |
|
||||
| tests.cpp:613:19:613:24 | source indirection | semmle.label | source indirection |
|
||||
| tests.cpp:615:17:615:22 | source indirection | semmle.label | source indirection |
|
||||
| tests.cpp:622:19:622:24 | source indirection | semmle.label | source indirection |
|
||||
| tests.cpp:625:2:625:16 | ... = ... indirection | semmle.label | ... = ... indirection |
|
||||
| tests.cpp:625:4:625:7 | s indirection [post update] [home indirection] | semmle.label | s indirection [post update] [home indirection] |
|
||||
| tests.cpp:628:14:628:14 | s indirection [home indirection] | semmle.label | s indirection [home indirection] |
|
||||
| tests.cpp:628:14:628:19 | home indirection | semmle.label | home indirection |
|
||||
| tests.cpp:628:16:628:19 | home indirection | semmle.label | home indirection |
|
||||
| tests.cpp:631:32:631:35 | argv indirection | semmle.label | argv indirection |
|
||||
| tests.cpp:656:9:656:15 | access to array indirection | semmle.label | access to array indirection |
|
||||
| tests.cpp:657:9:657:15 | access to array indirection | semmle.label | access to array indirection |
|
||||
subpaths
|
||||
#select
|
||||
| tests.cpp:615:2:615:7 | call to strcpy | main.cpp:6:27:6:30 | argv indirection | tests.cpp:615:17:615:22 | source indirection | This 'call to strcpy' with input from $@ may overflow the destination. | main.cpp:6:27:6:30 | argv indirection | a command-line argument |
|
||||
| tests.cpp:628:2:628:7 | call to strcpy | main.cpp:6:27:6:30 | argv indirection | tests.cpp:628:14:628:19 | home indirection | This 'call to strcpy' with input from $@ may overflow the destination. | main.cpp:6:27:6:30 | argv indirection | a command-line argument |
|
||||
|
||||
@@ -407,7 +407,7 @@ void test15()
|
||||
{
|
||||
if (ptr[5] == ' ') // GOOD
|
||||
{
|
||||
// ...
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -608,6 +608,26 @@ int test23() {
|
||||
return sizeof(buffer) / sizeof(buffer[101]); // GOOD
|
||||
}
|
||||
|
||||
char* strcpy(char *, const char *);
|
||||
|
||||
void test24(char* source) {
|
||||
char buffer[100];
|
||||
strcpy(buffer, source); // BAD
|
||||
}
|
||||
|
||||
struct my_struct {
|
||||
char* home;
|
||||
};
|
||||
|
||||
void test25(char* source) {
|
||||
my_struct s;
|
||||
|
||||
s.home = source;
|
||||
|
||||
char buf[100];
|
||||
strcpy(buf, s.home); // BAD
|
||||
}
|
||||
|
||||
int tests_main(int argc, char *argv[])
|
||||
{
|
||||
long long arr17[19];
|
||||
@@ -633,6 +653,8 @@ int tests_main(int argc, char *argv[])
|
||||
test21(argc == 0);
|
||||
test22(argc == 0, argv[0]);
|
||||
test23();
|
||||
test24(argv[0]);
|
||||
test25(argv[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
edges
|
||||
| examples.cpp:63:26:63:30 | & ... | examples.cpp:66:11:66:14 | data |
|
||||
| examples.cpp:63:26:63:30 | & ... | examples.cpp:66:11:66:14 | data |
|
||||
| examples.cpp:63:26:63:30 | fscanf output argument | examples.cpp:66:11:66:14 | data |
|
||||
| examples.cpp:63:26:63:30 | fscanf output argument | examples.cpp:66:11:66:14 | data |
|
||||
subpaths
|
||||
nodes
|
||||
| examples.cpp:63:26:63:30 | & ... | semmle.label | & ... |
|
||||
| examples.cpp:63:26:63:30 | fscanf output argument | semmle.label | fscanf output argument |
|
||||
| examples.cpp:66:11:66:14 | data | semmle.label | data |
|
||||
| examples.cpp:66:11:66:14 | data | semmle.label | data |
|
||||
subpaths
|
||||
#select
|
||||
| examples.cpp:66:11:66:14 | data | examples.cpp:63:26:63:30 | & ... | examples.cpp:66:11:66:14 | data | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | examples.cpp:63:26:63:30 | & ... | User-provided value |
|
||||
| examples.cpp:66:11:66:14 | data | examples.cpp:63:26:63:30 | fscanf output argument | examples.cpp:66:11:66:14 | data | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | examples.cpp:63:26:63:30 | fscanf output argument | value read by fscanf |
|
||||
|
||||
@@ -1,86 +1,59 @@
|
||||
edges
|
||||
| test2.cpp:12:21:12:21 | v | test2.cpp:14:11:14:11 | v |
|
||||
| test2.cpp:12:21:12:21 | v | test2.cpp:14:11:14:11 | v |
|
||||
| test2.cpp:25:22:25:23 | & ... | test2.cpp:27:13:27:13 | v |
|
||||
| test2.cpp:25:22:25:23 | fscanf output argument | test2.cpp:27:13:27:13 | v |
|
||||
| test2.cpp:27:13:27:13 | v | test2.cpp:12:21:12:21 | v |
|
||||
| test2.cpp:36:9:36:14 | buffer | test2.cpp:39:9:39:11 | num |
|
||||
| test2.cpp:36:9:36:14 | buffer | test2.cpp:39:9:39:11 | num |
|
||||
| test2.cpp:36:9:36:14 | buffer | test2.cpp:39:9:39:11 | num |
|
||||
| test2.cpp:36:9:36:14 | buffer | test2.cpp:39:9:39:11 | num |
|
||||
| test2.cpp:36:9:36:14 | buffer | test2.cpp:40:3:40:5 | num |
|
||||
| test2.cpp:36:9:36:14 | buffer | test2.cpp:40:3:40:5 | num |
|
||||
| test2.cpp:36:9:36:14 | buffer | test2.cpp:40:3:40:5 | num |
|
||||
| test2.cpp:36:9:36:14 | buffer | test2.cpp:40:3:40:5 | num |
|
||||
| test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:39:9:39:11 | num |
|
||||
| test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:39:9:39:11 | num |
|
||||
| test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:40:3:40:5 | num |
|
||||
| test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:40:3:40:5 | num |
|
||||
| test5.cpp:5:5:5:17 | getTaintedInt indirection | test5.cpp:17:6:17:18 | call to getTaintedInt |
|
||||
| test3.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections |
|
||||
| test3.c:10:27:10:30 | argv indirection | test.c:44:7:44:10 | len2 |
|
||||
| test3.c:10:27:10:30 | argv indirection | test.c:54:7:54:10 | len3 |
|
||||
| test5.cpp:5:5:5:17 | getTaintedInt indirection | test5.cpp:17:6:17:18 | call to getTaintedInt |
|
||||
| test5.cpp:5:5:5:17 | getTaintedInt indirection | test5.cpp:18:6:18:18 | call to getTaintedInt |
|
||||
| test5.cpp:9:7:9:9 | buf | test5.cpp:5:5:5:17 | getTaintedInt indirection |
|
||||
| test5.cpp:9:7:9:9 | buf | test5.cpp:5:5:5:17 | getTaintedInt indirection |
|
||||
| test5.cpp:9:7:9:9 | gets output argument | test5.cpp:5:5:5:17 | getTaintedInt indirection |
|
||||
| test5.cpp:18:6:18:18 | call to getTaintedInt | test5.cpp:19:6:19:6 | y |
|
||||
| test5.cpp:18:6:18:18 | call to getTaintedInt | test5.cpp:19:6:19:6 | y |
|
||||
| test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections |
|
||||
| test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections |
|
||||
| test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections |
|
||||
| test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections |
|
||||
| test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 |
|
||||
| test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 |
|
||||
| test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 |
|
||||
| test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 |
|
||||
| test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 |
|
||||
| test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 |
|
||||
| test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 |
|
||||
| test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 |
|
||||
subpaths
|
||||
| test.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections |
|
||||
| test.c:10:27:10:30 | argv indirection | test.c:44:7:44:10 | len2 |
|
||||
| test.c:10:27:10:30 | argv indirection | test.c:54:7:54:10 | len3 |
|
||||
nodes
|
||||
| test2.cpp:12:21:12:21 | v | semmle.label | v |
|
||||
| test2.cpp:14:11:14:11 | v | semmle.label | v |
|
||||
| test2.cpp:14:11:14:11 | v | semmle.label | v |
|
||||
| test2.cpp:25:22:25:23 | & ... | semmle.label | & ... |
|
||||
| test2.cpp:25:22:25:23 | fscanf output argument | semmle.label | fscanf output argument |
|
||||
| test2.cpp:27:13:27:13 | v | semmle.label | v |
|
||||
| test2.cpp:36:9:36:14 | buffer | semmle.label | buffer |
|
||||
| test2.cpp:36:9:36:14 | buffer | semmle.label | buffer |
|
||||
| test2.cpp:36:9:36:14 | fgets output argument | semmle.label | fgets output argument |
|
||||
| test2.cpp:39:9:39:11 | num | semmle.label | num |
|
||||
| test2.cpp:39:9:39:11 | num | semmle.label | num |
|
||||
| test2.cpp:40:3:40:5 | num | semmle.label | num |
|
||||
| test2.cpp:40:3:40:5 | num | semmle.label | num |
|
||||
| test3.c:10:27:10:30 | argv indirection | semmle.label | argv indirection |
|
||||
| test5.cpp:5:5:5:17 | getTaintedInt indirection | semmle.label | getTaintedInt indirection |
|
||||
| test5.cpp:9:7:9:9 | buf | semmle.label | buf |
|
||||
| test5.cpp:9:7:9:9 | buf | semmle.label | buf |
|
||||
| test5.cpp:9:7:9:9 | gets output argument | semmle.label | gets output argument |
|
||||
| test5.cpp:17:6:17:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
|
||||
| test5.cpp:17:6:17:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
|
||||
| test5.cpp:18:6:18:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
|
||||
| test5.cpp:19:6:19:6 | y | semmle.label | y |
|
||||
| test5.cpp:19:6:19:6 | y | semmle.label | y |
|
||||
| test.c:11:29:11:32 | argv | semmle.label | argv |
|
||||
| test.c:11:29:11:32 | argv | semmle.label | argv |
|
||||
| test.c:10:27:10:30 | argv indirection | semmle.label | argv indirection |
|
||||
| test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections |
|
||||
| test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections |
|
||||
| test.c:41:17:41:20 | argv | semmle.label | argv |
|
||||
| test.c:41:17:41:20 | argv | semmle.label | argv |
|
||||
| test.c:44:7:44:10 | len2 | semmle.label | len2 |
|
||||
| test.c:44:7:44:10 | len2 | semmle.label | len2 |
|
||||
| test.c:51:17:51:20 | argv | semmle.label | argv |
|
||||
| test.c:51:17:51:20 | argv | semmle.label | argv |
|
||||
| test.c:54:7:54:10 | len3 | semmle.label | len3 |
|
||||
| test.c:54:7:54:10 | len3 | semmle.label | len3 |
|
||||
subpaths
|
||||
#select
|
||||
| test2.cpp:14:11:14:11 | v | test2.cpp:25:22:25:23 | & ... | test2.cpp:14:11:14:11 | v | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test2.cpp:25:22:25:23 | & ... | User-provided value |
|
||||
| test2.cpp:14:11:14:11 | v | test2.cpp:25:22:25:23 | & ... | test2.cpp:14:11:14:11 | v | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test2.cpp:25:22:25:23 | & ... | User-provided value |
|
||||
| test2.cpp:39:9:39:11 | num | test2.cpp:36:9:36:14 | buffer | test2.cpp:39:9:39:11 | num | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test2.cpp:36:9:36:14 | buffer | User-provided value |
|
||||
| test2.cpp:40:3:40:5 | num | test2.cpp:36:9:36:14 | buffer | test2.cpp:40:3:40:5 | num | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test2.cpp:36:9:36:14 | buffer | User-provided value |
|
||||
| test5.cpp:17:6:17:18 | call to getTaintedInt | test5.cpp:9:7:9:9 | buf | test5.cpp:17:6:17:18 | call to getTaintedInt | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
|
||||
| test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | buf | test5.cpp:19:6:19:6 | y | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
|
||||
| test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | buf | test5.cpp:19:6:19:6 | y | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
|
||||
| test.c:14:15:14:28 | maxConnections | test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test.c:11:29:11:32 | argv | User-provided value |
|
||||
| test.c:14:15:14:28 | maxConnections | test.c:11:29:11:32 | argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:11:29:11:32 | argv | User-provided value |
|
||||
| test.c:44:7:44:10 | len2 | test.c:41:17:41:20 | argv | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:41:17:41:20 | argv | User-provided value |
|
||||
| test.c:54:7:54:10 | len3 | test.c:51:17:51:20 | argv | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:51:17:51:20 | argv | User-provided value |
|
||||
| test2.cpp:14:11:14:11 | v | test2.cpp:25:22:25:23 | fscanf output argument | test2.cpp:14:11:14:11 | v | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test2.cpp:25:22:25:23 | fscanf output argument | value read by fscanf |
|
||||
| test2.cpp:14:11:14:11 | v | test2.cpp:25:22:25:23 | fscanf output argument | test2.cpp:14:11:14:11 | v | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test2.cpp:25:22:25:23 | fscanf output argument | value read by fscanf |
|
||||
| test2.cpp:39:9:39:11 | num | test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:39:9:39:11 | num | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test2.cpp:36:9:36:14 | fgets output argument | string read by fgets |
|
||||
| test2.cpp:40:3:40:5 | num | test2.cpp:36:9:36:14 | fgets output argument | test2.cpp:40:3:40:5 | num | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test2.cpp:36:9:36:14 | fgets output argument | string read by fgets |
|
||||
| test5.cpp:17:6:17:18 | call to getTaintedInt | test5.cpp:9:7:9:9 | gets output argument | test5.cpp:17:6:17:18 | call to getTaintedInt | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
|
||||
| test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | gets output argument | test5.cpp:19:6:19:6 | y | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
|
||||
| test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | gets output argument | test5.cpp:19:6:19:6 | y | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
|
||||
| test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | argv indirection | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||
| test.c:44:7:44:10 | len2 | test3.c:10:27:10:30 | argv indirection | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||
| test.c:44:7:44:10 | len2 | test3.c:10:27:10:30 | argv indirection | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||
| test.c:44:7:44:10 | len2 | test.c:10:27:10:30 | argv indirection | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||
| test.c:44:7:44:10 | len2 | test.c:10:27:10:30 | argv indirection | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||
| test.c:54:7:54:10 | len3 | test3.c:10:27:10:30 | argv indirection | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||
| test.c:54:7:54:10 | len3 | test3.c:10:27:10:30 | argv indirection | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||
| test.c:54:7:54:10 | len3 | test.c:10:27:10:30 | argv indirection | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||
| test.c:54:7:54:10 | len3 | test.c:10:27:10:30 | argv indirection | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | argv indirection | a command-line argument |
|
||||
|
||||
@@ -252,7 +252,7 @@ namespace Semmle.Autobuild.Shared
|
||||
|
||||
try
|
||||
{
|
||||
var res = thisBuildActions.RunProcess("sysctl", "machdep.cpu.brand_string", workingDirectory: null, env: null, out var stdOut);
|
||||
thisBuildActions.RunProcess("sysctl", "machdep.cpu.brand_string", workingDirectory: null, env: null, out var stdOut);
|
||||
return stdOut?.Any(s => s?.ToLowerInvariant().Contains("apple") == true) ?? false;
|
||||
}
|
||||
catch (Exception)
|
||||
|
||||
@@ -15,14 +15,12 @@ namespace Semmle.Autobuild.Shared
|
||||
/// <returns></returns>
|
||||
public static CommandBuilder MsBuildCommand(this CommandBuilder cmdBuilder, IAutobuilder<AutobuildOptionsShared> builder)
|
||||
{
|
||||
var IsRunningOnAppleSiliconMac = builder.Actions.IsMacOs() && builder.Actions.IsRunningOnAppleSilicon();
|
||||
|
||||
// mono doesn't ship with `msbuild` on Arm-based Macs, but we can fall back to
|
||||
// msbuild that ships with `dotnet` which can be invoked with `dotnet msbuild`
|
||||
// perhaps we should do this on all platforms?
|
||||
return IsRunningOnAppleSiliconMac ?
|
||||
cmdBuilder.RunCommand("dotnet").Argument("msbuild") :
|
||||
cmdBuilder.RunCommand("msbuild");
|
||||
return builder.Actions.IsRunningOnAppleSilicon()
|
||||
? cmdBuilder.RunCommand("dotnet").Argument("msbuild")
|
||||
: cmdBuilder.RunCommand("msbuild");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +82,12 @@ namespace Semmle.Autobuild.Shared
|
||||
Argument("/t:restore").
|
||||
QuoteArgument(projectOrSolution.FullPath);
|
||||
|
||||
if (nugetDownloaded)
|
||||
if (builder.Actions.IsRunningOnAppleSilicon())
|
||||
{
|
||||
// On Apple Silicon, only try package restore with `dotnet msbuild /t:restore`
|
||||
ret &= BuildScript.Try(msbuildRestoreCommand.Script);
|
||||
}
|
||||
else if (nugetDownloaded)
|
||||
{
|
||||
ret &= BuildScript.Try(nugetRestore | msbuildRestoreCommand.Script);
|
||||
}
|
||||
|
||||
@@ -89,8 +89,10 @@ namespace Semmle.Extraction.CSharp.Populators
|
||||
SyntaxKind.ModuleKeyword => Entities.AttributeKind.Module,
|
||||
_ => throw new InternalError(node, "Unhandled global target")
|
||||
};
|
||||
foreach (var attribute in node.Attributes)
|
||||
var attributes = node.Attributes;
|
||||
for (var i = 0; i < attributes.Count; i++)
|
||||
{
|
||||
var attribute = attributes[i];
|
||||
if (attributeLookup.Value(attribute) is AttributeData attributeData)
|
||||
{
|
||||
var ae = Entities.Attribute.Create(Cx, attributeData, outputAssembly, kind);
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.7.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.7.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.7.3
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.7.2
|
||||
lastReleaseVersion: 1.7.3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-all
|
||||
version: 1.7.3-dev
|
||||
version: 1.7.3
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.7.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.7.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.7.3
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.7.2
|
||||
lastReleaseVersion: 1.7.3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-queries
|
||||
version: 1.7.3-dev
|
||||
version: 1.7.3
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -2,10 +2,10 @@ import os
|
||||
from create_database_utils import *
|
||||
from diagnostics_test_utils import *
|
||||
|
||||
run_codeql_database_create(['dotnet pack'], db=None, lang="csharp")
|
||||
run_codeql_database_create(['dotnet pack -o nugetpackage'], db=None, lang="csharp")
|
||||
|
||||
## Check that the NuGet package is created.
|
||||
if not os.path.isfile("bin/Debug/dotnet_pack.1.0.0.nupkg"):
|
||||
if not os.path.isfile("nugetpackage/dotnet_pack.1.0.0.nupkg"):
|
||||
raise Exception("The NuGet package was not created.")
|
||||
|
||||
check_diagnostics()
|
||||
|
||||
@@ -1,24 +1,6 @@
|
||||
import os
|
||||
|
||||
from create_database_utils import *
|
||||
from diagnostics_test_utils import *
|
||||
|
||||
def is_running_on_apple_silicon():
|
||||
arch = subprocess.Popen(['sysctl', 'machdep.cpu.brand_string'], stdout=subprocess.PIPE)
|
||||
output, errors = arch.communicate()
|
||||
if b'apple' in output.lower():
|
||||
return True
|
||||
return False
|
||||
|
||||
# if on ARM runners, remove Mono from the path, so we're using
|
||||
# dotnet restore instead of nuget.exe restore - on ARM machines
|
||||
# we run dotner msbuild (instead of the mono-provided msbuild.exe)
|
||||
# so we need to match the restore command, too.
|
||||
|
||||
platform_name = sys.platform.lower()
|
||||
if platform_name.startswith("darwin") and is_running_on_apple_silicon():
|
||||
os.environ["PATH"] = os.environ["PATH"].replace("/Library/Frameworks/Mono.framework/Versions/Current/Commands:", "")
|
||||
|
||||
# force CodeQL to use MSBuild by setting `LGTM_INDEX_MSBUILD_TARGET`
|
||||
run_codeql_database_create([], db=None, lang="csharp", extra_env={ 'LGTM_INDEX_MSBUILD_TARGET': 'Build' })
|
||||
check_diagnostics()
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<OutputType>Exe</OutputType>
|
||||
<SelfContained>false</SelfContained>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Skipping the test on the ARM runners, as we're running into trouble with Mono and nuget.
|
||||
@@ -1,3 +1,49 @@
|
||||
## 0.8.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The predicate `UnboundGeneric::getName` now prints the number of type parameters as a `` `N`` suffix, instead of a `<,...,>` suffix. For example, the unbound generic type
|
||||
`System.Collections.Generic.IList<T>` is printed as ``IList`1`` instead of `IList<>`.
|
||||
* The predicates `hasQualifiedName`, `getQualifiedName`, and `getQualifiedNameWithTypes` have been deprecated, and are instead replaced by `hasFullyQualifiedName`, `getFullyQualifiedName`, and `getFullyQualifiedNameWithTypes`, respectively. The new predicates use the same format for unbound generic types as mentioned above.
|
||||
* These changes also affect models-as-data rows that refer to a field or a property belonging to a generic type. For example, instead of writing
|
||||
```yml
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/csharp-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["System.Collections.Generic", "Dictionary<TKey,TValue>", False, "Add", "(System.Collections.Generic.KeyValuePair<TKey,TValue>)", "", "Argument[0].Property[System.Collections.Generic.KeyValuePair<,>.Key]", "Argument[this].Element.Property[System.Collections.Generic.KeyValuePair<,>.Key]", "value", "manual"]
|
||||
```
|
||||
one now writes
|
||||
```yml
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/csharp-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["System.Collections.Generic", "Dictionary<TKey,TValue>", False, "Add", "(System.Collections.Generic.KeyValuePair<TKey,TValue>)", "", "Argument[0].Property[System.Collections.Generic.KeyValuePair`2.Key]", "Argument[this].Element.Property[System.Collections.Generic.KeyValuePair`2.Key]", "value", "manual"]
|
||||
```
|
||||
* The models-as-data format for types and methods with type parameters has been changed to include the names of the type parameters. For example, instead of writing
|
||||
```yml
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/csharp-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["System.Collections.Generic", "IList<>", True, "Insert", "(System.Int32,T)", "", "Argument[1]", "Argument[this].Element", "value", "manual"]
|
||||
- ["System.Linq", "Enumerable", False, "Select<,>", "(System.Collections.Generic.IEnumerable<TSource>,System.Func<TSource,System.Int32,TResult>)", "", "Argument[0].Element", "Argument[1].Parameter[0]", "value", "manual"]
|
||||
```
|
||||
one now writes
|
||||
```yml
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/csharp-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["System.Collections.Generic", "IList<T>", True, "Insert", "(System.Int32,T)", "", "Argument[1]", "Argument[this].Element", "value", "manual"]
|
||||
- ["System.Linq", "Enumerable", False, "Select<TSource,TResult>", "(System.Collections.Generic.IEnumerable<TSource>,System.Func<TSource,System.Int32,TResult>)", "", "Argument[0].Element", "Argument[1].Parameter[0]", "value", "manual"]
|
||||
```
|
||||
|
||||
## 0.8.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
|
||||
* The models-as-data format for types and methods with type parameters has been changed to include the names of the type parameters. For example, instead of writing
|
||||
```yml
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/csharp-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["System.Collections.Generic", "IList<>", True, "Insert", "(System.Int32,T)", "", "Argument[1]", "Argument[this].Element", "value", "manual"]
|
||||
- ["System.Linq", "Enumerable", False, "Select<,>", "(System.Collections.Generic.IEnumerable<TSource>,System.Func<TSource,System.Int32,TResult>)", "", "Argument[0].Element", "Argument[1].Parameter[0]", "value", "manual"]
|
||||
```
|
||||
one now writes
|
||||
```yml
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/csharp-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["System.Collections.Generic", "IList<T>", True, "Insert", "(System.Int32,T)", "", "Argument[1]", "Argument[this].Element", "value", "manual"]
|
||||
- ["System.Linq", "Enumerable", False, "Select<TSource,TResult>", "(System.Collections.Generic.IEnumerable<TSource>,System.Func<TSource,System.Int32,TResult>)", "", "Argument[0].Element", "Argument[1].Parameter[0]", "value", "manual"]
|
||||
```
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
## 0.8.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The predicate `UnboundGeneric::getName` now prints the number of type parameters as a `` `N`` suffix, instead of a `<,...,>` suffix. For example, the unbound generic type
|
||||
`System.Collections.Generic.IList<T>` is printed as ``IList`1`` instead of `IList<>`.
|
||||
@@ -23,3 +23,23 @@ extensions:
|
||||
data:
|
||||
- ["System.Collections.Generic", "Dictionary<TKey,TValue>", False, "Add", "(System.Collections.Generic.KeyValuePair<TKey,TValue>)", "", "Argument[0].Property[System.Collections.Generic.KeyValuePair`2.Key]", "Argument[this].Element.Property[System.Collections.Generic.KeyValuePair`2.Key]", "value", "manual"]
|
||||
```
|
||||
* The models-as-data format for types and methods with type parameters has been changed to include the names of the type parameters. For example, instead of writing
|
||||
```yml
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/csharp-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["System.Collections.Generic", "IList<>", True, "Insert", "(System.Int32,T)", "", "Argument[1]", "Argument[this].Element", "value", "manual"]
|
||||
- ["System.Linq", "Enumerable", False, "Select<,>", "(System.Collections.Generic.IEnumerable<TSource>,System.Func<TSource,System.Int32,TResult>)", "", "Argument[0].Element", "Argument[1].Parameter[0]", "value", "manual"]
|
||||
```
|
||||
one now writes
|
||||
```yml
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/csharp-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["System.Collections.Generic", "IList<T>", True, "Insert", "(System.Int32,T)", "", "Argument[1]", "Argument[this].Element", "value", "manual"]
|
||||
- ["System.Linq", "Enumerable", False, "Select<TSource,TResult>", "(System.Collections.Generic.IEnumerable<TSource>,System.Func<TSource,System.Int32,TResult>)", "", "Argument[0].Element", "Argument[1].Parameter[0]", "value", "manual"]
|
||||
```
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.8.2
|
||||
lastReleaseVersion: 0.8.3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-all
|
||||
version: 0.8.3-dev
|
||||
version: 0.8.3
|
||||
groups: csharp
|
||||
dbscheme: semmlecode.csharp.dbscheme
|
||||
extractor: csharp
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
## 0.8.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* CIL extraction is now disabled by default. It is still possible to turn on CIL extraction by setting the `cil` extractor option to `true` or by setting the environment variable `$CODEQL_EXTRACTOR_CSHARP_OPTION_CIL` to `true`. This is the first step towards sun-setting the CIL extractor entirely.
|
||||
|
||||
## 0.8.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* CIL extraction is now disabled by default. It is still possible to turn on CIL extraction by setting the `cil` extractor option to `true` or by setting the environment variable `$CODEQL_EXTRACTOR_CSHARP_OPTION_CIL` to `true`. This is the first step towards sun-setting the CIL extractor entirely.
|
||||
## 0.8.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* CIL extraction is now disabled by default. It is still possible to turn on CIL extraction by setting the `cil` extractor option to `true` or by setting the environment variable `$CODEQL_EXTRACTOR_CSHARP_OPTION_CIL` to `true`. This is the first step towards sun-setting the CIL extractor entirely.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.8.2
|
||||
lastReleaseVersion: 0.8.3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-queries
|
||||
version: 0.8.3-dev
|
||||
version: 0.8.3
|
||||
groups:
|
||||
- csharp
|
||||
- queries
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
| standalone.cs:3:12:3:29 | [assembly: Attribute1(...)] |
|
||||
| standalone.cs:9:2:9:11 | [Attribute1(...)] |
|
||||
@@ -0,0 +1,5 @@
|
||||
import csharp
|
||||
|
||||
from Attribute a
|
||||
where a.getType().getName() = "Attribute1Attribute"
|
||||
select a
|
||||
@@ -0,0 +1 @@
|
||||
semmle-extractor-options: --standalone
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
[assembly: global::Attribute1]
|
||||
|
||||
class Attribute1Attribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[Attribute1]
|
||||
class A
|
||||
{
|
||||
}
|
||||
@@ -42,14 +42,47 @@ Downloading a database from GitHub
|
||||
|
||||
.. include:: ../reusables/download-github-database.rst
|
||||
|
||||
.. _filtering-databases-and-queries-by-language:
|
||||
|
||||
Filtering databases and queries by language
|
||||
-------------------------------------------
|
||||
|
||||
Optionally, to see databases containing a specific language and queries written for that language, you can apply a language filter using the language selector.
|
||||
|
||||
#. To see available language filters, in the sidebar, click the **Language** title bar.
|
||||
#. Hover over the language filter you would like to apply, then click **Select**.
|
||||
|
||||
.. image:: ../images/codeql-for-visual-studio-code/choose-language-filter.png
|
||||
:width: 350
|
||||
:alt: Screenshot of the language selector. The "Select" button for a language filter is outlined in dark orange.
|
||||
|
||||
Creating a custom query
|
||||
------------------------
|
||||
|
||||
You can generate a query template for a specific language from the queries panel, then write your own code to quickly create a custom query.
|
||||
|
||||
#. Optionally, to create a custom query in an existing directory, in the sidebar, click the **Queries** title bar to expand the queries panel, then select the desired directory.
|
||||
#. In the sidebar, hover over the **Queries** title bar, then click the **Create query** icon.
|
||||
|
||||
.. image:: ../images/codeql-for-visual-studio-code/create-query-icon.png
|
||||
:width: 350
|
||||
:alt: Screenshot of the queries panel. The "Create query" icon is outlined in dark orange.
|
||||
|
||||
#. In the Command Palette, select the target language for your query. If you've chosen not to create your custom query in an existing directory, selecting a language will autogenerate a directory labeled ``codeql-custom-queries-<language>``, where ``<language>`` is the name of the selected language. A query template labeled ``example.ql`` will then be added to the existing or autogenerated directory.
|
||||
#. In the template, write your custom query, then save the file. Once your query is finished, you can run it from the queries panel.
|
||||
|
||||
Running a query
|
||||
------------------------
|
||||
|
||||
The `CodeQL repository <https://github.com/github/codeql>`__ on GitHub contains lots of example queries.
|
||||
If you have that folder (or a different CodeQL pack) available in your workspace, you can access existing queries under ``<language>/ql/src/<category>``, for example ``java/ql/src/Likely Bugs``.
|
||||
You can access any existing queries in your workspace through the queries panel.
|
||||
|
||||
#. Open a query (``.ql``) file. It is displayed in the editor, with IntelliSense features such as syntax highlighting and autocomplete suggestions.
|
||||
#. Right-click in the query window and select **CodeQL: Run Query on Selected Database**. (Alternatively, run the command from the Command Palette.)
|
||||
#. In the sidebar, to expand the queries panel, click the **Queries** title bar.
|
||||
#. To run a query against the selected database, hover over the desired query, then click the **Run local query** icon.
|
||||
|
||||
.. image:: ../images/codeql-for-visual-studio-code/run-local-query-icon.png
|
||||
:width: 350
|
||||
:alt: Screenshot of the mouse pointer hovering over a query in the queries panel. The "Run local query" icon is outlined in dark orange.
|
||||
|
||||
The CodeQL extension runs the query on the current database and reports progress in the bottom right corner of the application.
|
||||
When the results are ready, they're displayed in the Results view.
|
||||
@@ -61,6 +94,23 @@ For more information, see ":doc:`Troubleshooting CodeQL for Visual Studio Code <
|
||||
Running multiple queries
|
||||
--------------------------
|
||||
|
||||
You can quickly run multiple queries against the database you've selected using the queries panel or a single command.
|
||||
|
||||
Running all queries in a directory
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can easily run every query in a directory using the queries panel.
|
||||
|
||||
#. In the sidebar, to expand the queries panel, click the **Queries** title bar.
|
||||
#. Hover over the desired directory of queries, then click the **Run local queries** icon.
|
||||
|
||||
.. image:: ../images/codeql-for-visual-studio-code/run-local-queries-icon.png
|
||||
:width: 350
|
||||
:alt: Screenshot of the mouse pointer hovering over a directory of queries in the queries panel. The "Run local queries" icon is outlined in dark orange.
|
||||
|
||||
Running a selection of queries
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can run multiple queries with a single command.
|
||||
|
||||
#. Go to the File Explorer.
|
||||
@@ -122,6 +172,7 @@ To see the queries that you have run in the current session, open the Query Hist
|
||||
|
||||
The Query History contains information including the date and time when the query was run, the name of the query, the database on which it was run, and how long it took to run the query.
|
||||
To customize the information that is displayed, right-click an entry and select **Rename**.
|
||||
You can also filter the Query History view by language using the language selector. For more information, see ":ref:`Filtering databases and queries by language <filtering-databases-and-queries-by-language>`."
|
||||
|
||||
Click an entry to display the corresponding results in the Query Results view, and double-click
|
||||
to display the query itself in the editor (or right-click and select **View Query**).
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 69 KiB |
@@ -49,7 +49,7 @@ The following properties are supported by all query files:
|
||||
| | | ``warning`` | |
|
||||
| | | ``recommendation`` | |
|
||||
+-----------------------+---------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| ``@security-severity``| ``<score>`` | Defines the level of severity, between 0.0 and 10.0, for queries with ``@tags security``. For more information about calculating ``@security-severity``, see the `GitHub changelog <https://github.blog/changelog/2021-07-19-codeql-code-scanning-new-severity-levels-for-security-alerts/>`__. |
|
||||
| ``@security-severity``| ``<score>`` | Defines the level of severity, between 0.0 and 10.0, for queries with ``@tags security``. For more information about calculating ``@security-severity``, see the `GitHub changelog <https://gh.io/2021-07-19-codeql-security-severity>`__. |
|
||||
+-----------------------+---------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
Example
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 0.0.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.0.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
go/ql/consistency-queries/change-notes/released/0.0.2.md
Normal file
3
go/ql/consistency-queries/change-notes/released/0.0.2.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.0.2
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.0.1
|
||||
lastReleaseVersion: 0.0.2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql-go-consistency-queries
|
||||
version: 0.0.2-dev
|
||||
version: 0.0.2
|
||||
groups:
|
||||
- go
|
||||
- queries
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
## 0.7.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added the [gin cors](https://github.com/gin-contrib/cors) library to the CorsMisconfiguration.ql query
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* A bug has been fixed that meant that value flow through an array was not tracked correctly in some circumstances. Taint flow was tracked correctly.
|
||||
|
||||
## 0.7.2
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
9
go/ql/lib/change-notes/released/0.7.3.md
Normal file
9
go/ql/lib/change-notes/released/0.7.3.md
Normal file
@@ -0,0 +1,9 @@
|
||||
## 0.7.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added the [gin cors](https://github.com/gin-contrib/cors) library to the CorsMisconfiguration.ql query
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* A bug has been fixed that meant that value flow through an array was not tracked correctly in some circumstances. Taint flow was tracked correctly.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.7.2
|
||||
lastReleaseVersion: 0.7.3
|
||||
|
||||
@@ -41,6 +41,7 @@ import semmle.go.frameworks.Email
|
||||
import semmle.go.frameworks.Encoding
|
||||
import semmle.go.frameworks.Fiber
|
||||
import semmle.go.frameworks.Gin
|
||||
import semmle.go.frameworks.GinCors
|
||||
import semmle.go.frameworks.Glog
|
||||
import semmle.go.frameworks.GoKit
|
||||
import semmle.go.frameworks.GoMicro
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/go-all
|
||||
version: 0.7.3-dev
|
||||
version: 0.7.3
|
||||
groups: go
|
||||
dbscheme: go.dbscheme
|
||||
extractor: go
|
||||
|
||||
@@ -724,16 +724,19 @@ class GenericTypeInstantiationExpr extends Expr {
|
||||
* ```go
|
||||
* a[1:3]
|
||||
* a[1:3:5]
|
||||
* a[1:]
|
||||
* a[:3]
|
||||
* a[:]
|
||||
* ```
|
||||
*/
|
||||
class SliceExpr extends @sliceexpr, Expr {
|
||||
/** Gets the base of this slice expression. */
|
||||
Expr getBase() { result = this.getChildExpr(0) }
|
||||
|
||||
/** Gets the lower bound of this slice expression. */
|
||||
/** Gets the lower bound of this slice expression, if any. */
|
||||
Expr getLow() { result = this.getChildExpr(1) }
|
||||
|
||||
/** Gets the upper bound of this slice expression. */
|
||||
/** Gets the upper bound of this slice expression, if any. */
|
||||
Expr getHigh() { result = this.getChildExpr(2) }
|
||||
|
||||
/** Gets the maximum of this slice expression, if any. */
|
||||
|
||||
@@ -21,7 +21,7 @@ predicate containerStoreStep(Node node1, Node node2, Content c) {
|
||||
node2.getType() instanceof SliceType
|
||||
) and
|
||||
(
|
||||
exists(Write w | w.writesElement(node2, _, node1))
|
||||
exists(Write w | w.writesElement(node2.(PostUpdateNode).getPreUpdateNode(), _, node1))
|
||||
or
|
||||
node1 = node2.(ImplicitVarargsSlice).getCallNode().getAnImplicitVarargsArgument()
|
||||
)
|
||||
|
||||
139
go/ql/lib/semmle/go/frameworks/GinCors.qll
Normal file
139
go/ql/lib/semmle/go/frameworks/GinCors.qll
Normal file
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* Provides classes for modeling the `github.com/gin-contrib/cors` package.
|
||||
*/
|
||||
|
||||
import go
|
||||
|
||||
/**
|
||||
* Provides classes for modeling the `github.com/gin-contrib/cors` package.
|
||||
*/
|
||||
module GinCors {
|
||||
/** Gets the package name `github.com/gin-gonic/gin`. */
|
||||
string packagePath() { result = package("github.com/gin-contrib/cors", "") }
|
||||
|
||||
/**
|
||||
* A new function create a new gin Handler that passed to gin as middleware
|
||||
*/
|
||||
class New extends Function {
|
||||
New() { exists(Function f | f.hasQualifiedName(packagePath(), "New") | this = f) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A write to the value of Access-Control-Allow-Credentials header
|
||||
*/
|
||||
class AllowCredentialsWrite extends DataFlow::ExprNode {
|
||||
DataFlow::Node base;
|
||||
|
||||
AllowCredentialsWrite() {
|
||||
exists(Field f, Write w |
|
||||
f.hasQualifiedName(packagePath(), "Config", "AllowCredentials") and
|
||||
w.writesField(base, f, this) and
|
||||
this.getType() instanceof BoolType
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get config struct holding header values
|
||||
*/
|
||||
DataFlow::Node getBase() { result = base }
|
||||
|
||||
/**
|
||||
* Get config variable holding header values
|
||||
*/
|
||||
GinConfig getConfig() {
|
||||
exists(GinConfig gc |
|
||||
(
|
||||
gc.getV().getBaseVariable().getDefinition().(SsaExplicitDefinition).getRhs() =
|
||||
base.asInstruction() or
|
||||
gc.getV().getAUse() = base
|
||||
) and
|
||||
result = gc
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A write to the value of Access-Control-Allow-Origins header
|
||||
*/
|
||||
class AllowOriginsWrite extends DataFlow::ExprNode {
|
||||
DataFlow::Node base;
|
||||
|
||||
AllowOriginsWrite() {
|
||||
exists(Field f, Write w |
|
||||
f.hasQualifiedName(packagePath(), "Config", "AllowOrigins") and
|
||||
w.writesField(base, f, this) and
|
||||
this.asExpr() instanceof SliceLit
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get config struct holding header values
|
||||
*/
|
||||
DataFlow::Node getBase() { result = base }
|
||||
|
||||
/**
|
||||
* Get config variable holding header values
|
||||
*/
|
||||
GinConfig getConfig() {
|
||||
exists(GinConfig gc |
|
||||
(
|
||||
gc.getV().getBaseVariable().getDefinition().(SsaExplicitDefinition).getRhs() =
|
||||
base.asInstruction() or
|
||||
gc.getV().getAUse() = base
|
||||
) and
|
||||
result = gc
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A write to the value of Access-Control-Allow-Origins of value "*", overriding AllowOrigins
|
||||
*/
|
||||
class AllowAllOriginsWrite extends DataFlow::ExprNode {
|
||||
DataFlow::Node base;
|
||||
|
||||
AllowAllOriginsWrite() {
|
||||
exists(Field f, Write w |
|
||||
f.hasQualifiedName(packagePath(), "Config", "AllowAllOrigins") and
|
||||
w.writesField(base, f, this) and
|
||||
this.getType() instanceof BoolType
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get config struct holding header values
|
||||
*/
|
||||
DataFlow::Node getBase() { result = base }
|
||||
|
||||
/**
|
||||
* Get config variable holding header values
|
||||
*/
|
||||
GinConfig getConfig() {
|
||||
exists(GinConfig gc |
|
||||
(
|
||||
gc.getV().getBaseVariable().getDefinition().(SsaExplicitDefinition).getRhs() =
|
||||
base.asInstruction() or
|
||||
gc.getV().getAUse() = base
|
||||
) and
|
||||
result = gc
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable of type Config that holds the headers to be set.
|
||||
*/
|
||||
class GinConfig extends Variable {
|
||||
SsaWithFields v;
|
||||
|
||||
GinConfig() {
|
||||
this = v.getBaseVariable().getSourceVariable() and
|
||||
exists(Type t | t.hasQualifiedName(packagePath(), "Config") | v.getType() = t)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get variable declaration of GinConfig
|
||||
*/
|
||||
SsaWithFields getV() { result = v }
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,7 @@
|
||||
## 0.7.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.7.2
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
3
go/ql/src/change-notes/released/0.7.3.md
Normal file
3
go/ql/src/change-notes/released/0.7.3.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.7.3
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.7.2
|
||||
lastReleaseVersion: 0.7.3
|
||||
|
||||
31
go/ql/src/experimental/CWE-287/ImproperLdapAuth.qhelp
Normal file
31
go/ql/src/experimental/CWE-287/ImproperLdapAuth.qhelp
Normal file
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>
|
||||
If an LDAP connection uses user-supplied data as password, anonymous bind could be caused using an empty password
|
||||
to result in a successful authentication.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>Don't use user-supplied data as password while establishing an LDAP connection.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>In the following examples, the code accepts a bind password via a HTTP request in variable <code>
|
||||
bindPassword</code>. The code builds a LDAP query whose authentication depends on user supplied data.</p>
|
||||
|
||||
|
||||
<sample src="examples/LdapAuthBad.go" />
|
||||
|
||||
<p>In the following examples, the code accepts a bind password via a HTTP request in variable <code>
|
||||
bindPassword</code>. The function ensures that the password provided is not empty before binding. </p>
|
||||
|
||||
<sample src="examples/LdapAuthGood.go" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>MITRE: <a href="https://cwe.mitre.org/data/definitions/287.html">CWE-287: Improper Authentication</a>.</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
19
go/ql/src/experimental/CWE-287/ImproperLdapAuth.ql
Normal file
19
go/ql/src/experimental/CWE-287/ImproperLdapAuth.ql
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @name Improper LDAP Authentication
|
||||
* @description A user-controlled query carries no authentication
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @id go/improper-ldap-auth
|
||||
* @tags security
|
||||
* experimental
|
||||
* external/cwe/cwe-287
|
||||
*/
|
||||
|
||||
import go
|
||||
import ImproperLdapAuthCustomizations
|
||||
import ImproperLdapAuth::Flow::PathGraph
|
||||
|
||||
from ImproperLdapAuth::Flow::PathNode source, ImproperLdapAuth::Flow::PathNode sink
|
||||
where ImproperLdapAuth::Flow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "LDAP binding password depends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
@@ -0,0 +1,84 @@
|
||||
import go
|
||||
import semmle.go.dataflow.barrierguardutil.RegexpCheck
|
||||
|
||||
module ImproperLdapAuth {
|
||||
/**
|
||||
* A sink that is vulnerable to improper LDAP Authentication vulnerabilities.
|
||||
*/
|
||||
abstract class LdapAuthSink extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A sanitizer function that prevents improper LDAP Authentication attacks.
|
||||
*/
|
||||
abstract class LdapSanitizer extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A vulnerable argument to `go-ldap` or `ldap`'s `bind` function (Only v2).
|
||||
*/
|
||||
private class GoLdapBindSink extends LdapAuthSink {
|
||||
GoLdapBindSink() {
|
||||
exists(Method meth |
|
||||
meth.hasQualifiedName("gopkg.in/ldap.v2", "Conn", "Bind") and
|
||||
this = meth.getACall().getArgument(1)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a regexp match function, considered as a barrier guard for sanitizing untrusted URLs.
|
||||
*
|
||||
* This is overapproximate: we do not attempt to reason about the correctness of the regexp.
|
||||
*/
|
||||
class RegexpCheckAsBarrierGuard extends RegexpCheckBarrier, LdapSanitizer { }
|
||||
|
||||
/**
|
||||
* An empty string.
|
||||
*/
|
||||
class EmptyString extends DataFlow::Node {
|
||||
EmptyString() { this.asExpr().getStringValue() = "" }
|
||||
}
|
||||
|
||||
private predicate equalityAsSanitizerGuard(DataFlow::Node g, Expr e, boolean outcome) {
|
||||
exists(DataFlow::Node nonConstNode, DataFlow::Node constNode, DataFlow::EqualityTestNode eq |
|
||||
g = eq and
|
||||
nonConstNode = eq.getAnOperand() and
|
||||
not nonConstNode.isConst() and
|
||||
constNode = eq.getAnOperand() and
|
||||
constNode.isConst() and
|
||||
e = nonConstNode.asExpr() and
|
||||
(
|
||||
// If `constNode` is not an empty string a comparison is considered a sanitizer
|
||||
not constNode instanceof EmptyString and outcome = eq.getPolarity()
|
||||
or
|
||||
// If `constNode` is an empty string a not comparison is considered a sanitizer
|
||||
constNode instanceof EmptyString and outcome = eq.getPolarity().booleanNot()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* An equality check comparing a data-flow node against a constant string, considered as
|
||||
* a barrier guard for sanitizing untrusted user input.
|
||||
*/
|
||||
class EqualityAsSanitizerGuard extends LdapSanitizer {
|
||||
EqualityAsSanitizerGuard() {
|
||||
this = DataFlow::BarrierGuard<equalityAsSanitizerGuard/3>::getABarrierNode()
|
||||
}
|
||||
}
|
||||
|
||||
private module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source instanceof UntrustedFlowSource or source instanceof EmptyString
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof LdapAuthSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof LdapSanitizer }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow for reasoning about improper ldap auth vulnerabilities
|
||||
* with sinks which are not sanitized by string comparisons.
|
||||
*/
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
}
|
||||
22
go/ql/src/experimental/CWE-287/examples/LdapAuthBad.go
Normal file
22
go/ql/src/experimental/CWE-287/examples/LdapAuthBad.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
func bad() interface{} {
|
||||
bindPassword := req.URL.Query()["password"][0]
|
||||
|
||||
// Connect to the LDAP server
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to connect to LDAP server: %v", err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
err = l.Bind("cn=admin,dc=example,dc=com", bindPassword)
|
||||
if err != nil {
|
||||
log.Fatalf("LDAP bind failed: %v", err)
|
||||
}
|
||||
}
|
||||
24
go/ql/src/experimental/CWE-287/examples/LdapAuthGood.go
Normal file
24
go/ql/src/experimental/CWE-287/examples/LdapAuthGood.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
func good() interface{} {
|
||||
bindPassword := req.URL.Query()["password"][0]
|
||||
|
||||
// Connect to the LDAP server
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to connect to LDAP server: %v", err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
if bindPassword != "" {
|
||||
err = l.Bind("cn=admin,dc=example,dc=com", bindPassword)
|
||||
if err != nil {
|
||||
log.Fatalf("LDAP bind failed: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,22 +69,53 @@ module UntrustedToAllowOriginHeaderConfig implements DataFlow::ConfigSig {
|
||||
predicate isSink(DataFlow::Node sink) { isSinkHW(sink, _) }
|
||||
}
|
||||
|
||||
module UntrustedToAllowOriginConfigConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
|
||||
|
||||
additional predicate isSinkWrite(DataFlow::Node sink, GinCors::AllowOriginsWrite w) { sink = w }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { isSinkWrite(sink, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flowfor reasoning about when an `UntrustedFlowSource` flows to
|
||||
* a `HeaderWrite` that writes an `Access-Control-Allow-Origin` header's value.
|
||||
*/
|
||||
module UntrustedToAllowOriginHeaderFlow = TaintTracking::Global<UntrustedToAllowOriginHeaderConfig>;
|
||||
|
||||
/**
|
||||
* Tracks taint flowfor reasoning about when an `UntrustedFlowSource` flows to
|
||||
* a `AllowOriginsWrite` that writes an `Access-Control-Allow-Origin` header's value.
|
||||
*/
|
||||
module UntrustedToAllowOriginConfigFlow = TaintTracking::Global<UntrustedToAllowOriginConfigConfig>;
|
||||
|
||||
/**
|
||||
* Holds if the provided `allowOriginHW` HeaderWrite's parent ResponseWriter
|
||||
* also has another HeaderWrite that sets a `Access-Control-Allow-Credentials`
|
||||
* header to `true`.
|
||||
*/
|
||||
predicate allowCredentialsIsSetToTrue(AllowOriginHeaderWrite allowOriginHW) {
|
||||
predicate allowCredentialsIsSetToTrue(DataFlow::ExprNode allowOriginHW) {
|
||||
exists(AllowCredentialsHeaderWrite allowCredentialsHW |
|
||||
allowCredentialsHW.getHeaderValue().toLowerCase() = "true"
|
||||
|
|
||||
allowOriginHW.getResponseWriter() = allowCredentialsHW.getResponseWriter()
|
||||
allowOriginHW.(AllowOriginHeaderWrite).getResponseWriter() =
|
||||
allowCredentialsHW.getResponseWriter()
|
||||
)
|
||||
or
|
||||
exists(GinCors::AllowCredentialsWrite allowCredentialsGin |
|
||||
allowCredentialsGin.getExpr().getBoolValue() = true
|
||||
|
|
||||
allowCredentialsGin.getConfig() = allowOriginHW.(GinCors::AllowOriginsWrite).getConfig() and
|
||||
not exists(GinCors::AllowAllOriginsWrite allowAllOrigins |
|
||||
allowAllOrigins.getExpr().getBoolValue() = true and
|
||||
allowCredentialsGin.getConfig() = allowAllOrigins.getConfig()
|
||||
)
|
||||
or
|
||||
allowCredentialsGin.getBase() = allowOriginHW.(GinCors::AllowOriginsWrite).getBase() and
|
||||
not exists(GinCors::AllowAllOriginsWrite allowAllOrigins |
|
||||
allowAllOrigins.getExpr().getBoolValue() = true and
|
||||
allowCredentialsGin.getBase() = allowAllOrigins.getBase()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -93,10 +124,13 @@ predicate allowCredentialsIsSetToTrue(AllowOriginHeaderWrite allowOriginHW) {
|
||||
* UntrustedFlowSource.
|
||||
* The `message` parameter is populated with the warning message to be returned by the query.
|
||||
*/
|
||||
predicate flowsFromUntrustedToAllowOrigin(AllowOriginHeaderWrite allowOriginHW, string message) {
|
||||
predicate flowsFromUntrustedToAllowOrigin(DataFlow::ExprNode allowOriginHW, string message) {
|
||||
exists(DataFlow::Node sink |
|
||||
UntrustedToAllowOriginHeaderFlow::flowTo(sink) and
|
||||
UntrustedToAllowOriginHeaderConfig::isSinkHW(sink, allowOriginHW)
|
||||
or
|
||||
UntrustedToAllowOriginConfigFlow::flowTo(sink) and
|
||||
UntrustedToAllowOriginConfigConfig::isSinkWrite(sink, allowOriginHW)
|
||||
|
|
||||
message =
|
||||
headerAllowOrigin() + " header is set to a user-defined value, and " +
|
||||
@@ -108,11 +142,23 @@ predicate flowsFromUntrustedToAllowOrigin(AllowOriginHeaderWrite allowOriginHW,
|
||||
* Holds if the provided `allowOriginHW` HeaderWrite is for a `Access-Control-Allow-Origin`
|
||||
* header and the value is set to `null`.
|
||||
*/
|
||||
predicate allowOriginIsNull(AllowOriginHeaderWrite allowOriginHW, string message) {
|
||||
allowOriginHW.getHeaderValue().toLowerCase() = "null" and
|
||||
predicate allowOriginIsNull(DataFlow::ExprNode allowOriginHW, string message) {
|
||||
allowOriginHW.(AllowOriginHeaderWrite).getHeaderValue().toLowerCase() = "null" and
|
||||
message =
|
||||
headerAllowOrigin() + " header is set to `" + allowOriginHW.getHeaderValue() + "`, and " +
|
||||
headerAllowCredentials() + " is set to `true`"
|
||||
headerAllowOrigin() + " header is set to `" +
|
||||
allowOriginHW.(AllowOriginHeaderWrite).getHeaderValue() + "`, and " + headerAllowCredentials()
|
||||
+ " is set to `true`"
|
||||
or
|
||||
allowOriginHW
|
||||
.(GinCors::AllowOriginsWrite)
|
||||
.asExpr()
|
||||
.(SliceLit)
|
||||
.getAnElement()
|
||||
.getStringValue()
|
||||
.toLowerCase() = "null" and
|
||||
message =
|
||||
headerAllowOrigin() + " header is set to `" + "null" + "`, and " + headerAllowCredentials() +
|
||||
" is set to `true`"
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,7 +216,7 @@ module FromUntrustedFlow = TaintTracking::Global<FromUntrustedConfig>;
|
||||
/**
|
||||
* Holds if the provided `allowOriginHW` is also destination of a `UntrustedFlowSource`.
|
||||
*/
|
||||
predicate flowsToGuardedByCheckOnUntrusted(AllowOriginHeaderWrite allowOriginHW) {
|
||||
predicate flowsToGuardedByCheckOnUntrusted(DataFlow::ExprNode allowOriginHW) {
|
||||
exists(DataFlow::Node sink, ControlFlow::ConditionGuardNode cgn |
|
||||
FromUntrustedFlow::flowTo(sink) and FromUntrustedConfig::isSinkCgn(sink, cgn)
|
||||
|
|
||||
@@ -178,7 +224,7 @@ predicate flowsToGuardedByCheckOnUntrusted(AllowOriginHeaderWrite allowOriginHW)
|
||||
)
|
||||
}
|
||||
|
||||
from AllowOriginHeaderWrite allowOriginHW, string message
|
||||
from DataFlow::ExprNode allowOriginHW, string message
|
||||
where
|
||||
allowCredentialsIsSetToTrue(allowOriginHW) and
|
||||
(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/go-queries
|
||||
version: 0.7.3-dev
|
||||
version: 0.7.3
|
||||
groups:
|
||||
- go
|
||||
- queries
|
||||
|
||||
14
go/ql/test/experimental/CWE-287/ImproperLdapAuth.expected
Normal file
14
go/ql/test/experimental/CWE-287/ImproperLdapAuth.expected
Normal file
@@ -0,0 +1,14 @@
|
||||
edges
|
||||
| ImproperLdapAuth.go:18:18:18:24 | selection of URL | ImproperLdapAuth.go:18:18:18:32 | call to Query |
|
||||
| ImproperLdapAuth.go:18:18:18:32 | call to Query | ImproperLdapAuth.go:28:23:28:34 | bindPassword |
|
||||
| ImproperLdapAuth.go:87:18:87:19 | "" | ImproperLdapAuth.go:97:23:97:34 | bindPassword |
|
||||
nodes
|
||||
| ImproperLdapAuth.go:18:18:18:24 | selection of URL | semmle.label | selection of URL |
|
||||
| ImproperLdapAuth.go:18:18:18:32 | call to Query | semmle.label | call to Query |
|
||||
| ImproperLdapAuth.go:28:23:28:34 | bindPassword | semmle.label | bindPassword |
|
||||
| ImproperLdapAuth.go:87:18:87:19 | "" | semmle.label | "" |
|
||||
| ImproperLdapAuth.go:97:23:97:34 | bindPassword | semmle.label | bindPassword |
|
||||
subpaths
|
||||
#select
|
||||
| ImproperLdapAuth.go:28:23:28:34 | bindPassword | ImproperLdapAuth.go:18:18:18:24 | selection of URL | ImproperLdapAuth.go:28:23:28:34 | bindPassword | LDAP binding password depends on a $@. | ImproperLdapAuth.go:18:18:18:24 | selection of URL | user-provided value |
|
||||
| ImproperLdapAuth.go:97:23:97:34 | bindPassword | ImproperLdapAuth.go:87:18:87:19 | "" | ImproperLdapAuth.go:97:23:97:34 | bindPassword | LDAP binding password depends on a $@. | ImproperLdapAuth.go:87:18:87:19 | "" | user-provided value |
|
||||
108
go/ql/test/experimental/CWE-287/ImproperLdapAuth.go
Normal file
108
go/ql/test/experimental/CWE-287/ImproperLdapAuth.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package main
|
||||
|
||||
//go:generate depstubber -vendor gopkg.in/ldap.v2 Conn Dial
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"regexp"
|
||||
|
||||
ldap "gopkg.in/ldap.v2"
|
||||
)
|
||||
|
||||
func bad(w http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||
ldapServer := "ldap.example.com"
|
||||
ldapPort := 389
|
||||
bindDN := "cn=admin,dc=example,dc=com"
|
||||
bindPassword := req.URL.Query()["password"][0]
|
||||
|
||||
// Connect to the LDAP server
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to connect to LDAP server: %v", err), err
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
// BAD: user input is not sanetized
|
||||
err = l.Bind(bindDN, bindPassword)
|
||||
if err != nil {
|
||||
return fmt.Errorf("LDAP bind failed: %v", err), err
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func good1(w http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||
ldapServer := "ldap.example.com"
|
||||
ldapPort := 389
|
||||
bindDN := "cn=admin,dc=example,dc=com"
|
||||
bindPassword := req.URL.Query()["password"][0]
|
||||
|
||||
// Connect to the LDAP server
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to connect to LDAP server: %v", err), err
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
hasEmptyInput, _ := regexp.MatchString("^\\s*$", bindPassword)
|
||||
|
||||
// GOOD : bindPassword is not empty
|
||||
if !hasEmptyInput {
|
||||
l.Bind(bindDN, bindPassword)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("LDAP bind failed: %v", err), err
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func good2(w http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||
ldapServer := "ldap.example.com"
|
||||
ldapPort := 389
|
||||
bindDN := "cn=admin,dc=example,dc=com"
|
||||
bindPassword := req.URL.Query()["password"][0]
|
||||
|
||||
// Connect to the LDAP server
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to connect to LDAP server: %v", err), err
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
// GOOD : bindPassword is not empty
|
||||
if bindPassword != "" {
|
||||
l.Bind(bindDN, bindPassword)
|
||||
return nil, err
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func bad2(req *http.Request) {
|
||||
// LDAP server details
|
||||
ldapServer := "ldap.example.com"
|
||||
ldapPort := 389
|
||||
bindDN := "cn=admin,dc=example,dc=com"
|
||||
// BAD : empty password
|
||||
bindPassword := ""
|
||||
|
||||
// Connect to the LDAP server
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to connect to LDAP server: %v", err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
// BAD : bindPassword is empty
|
||||
err = l.Bind(bindDN, bindPassword)
|
||||
if err != nil {
|
||||
log.Fatalf("LDAP bind failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
bad(nil, nil)
|
||||
good1(nil, nil)
|
||||
good2(nil, nil)
|
||||
bad2(nil)
|
||||
}
|
||||
1
go/ql/test/experimental/CWE-287/ImproperLdapAuth.qlref
Normal file
1
go/ql/test/experimental/CWE-287/ImproperLdapAuth.qlref
Normal file
@@ -0,0 +1 @@
|
||||
experimental/CWE-287/ImproperLdapAuth.ql
|
||||
7
go/ql/test/experimental/CWE-287/go.mod
Normal file
7
go/ql/test/experimental/CWE-287/go.mod
Normal file
@@ -0,0 +1,7 @@
|
||||
module main
|
||||
|
||||
go 1.19
|
||||
|
||||
require gopkg.in/ldap.v2 v2.5.1
|
||||
|
||||
require gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
|
||||
185
go/ql/test/experimental/CWE-287/vendor/gopkg.in/ldap.v2/stub.go
generated
vendored
Normal file
185
go/ql/test/experimental/CWE-287/vendor/gopkg.in/ldap.v2/stub.go
generated
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
// Code generated by depstubber. DO NOT EDIT.
|
||||
// This is a simple stub for gopkg.in/ldap.v2, strictly for use in testing.
|
||||
|
||||
// See the LICENSE file for information about the licensing of the original library.
|
||||
// Source: gopkg.in/ldap.v2 (exports: Conn; functions: Dial)
|
||||
|
||||
// Package ldap is a stub of gopkg.in/ldap.v2, generated by depstubber.
|
||||
package ldap
|
||||
|
||||
import (
|
||||
tls "crypto/tls"
|
||||
time "time"
|
||||
)
|
||||
|
||||
type AddRequest struct {
|
||||
DN string
|
||||
Attributes []Attribute
|
||||
}
|
||||
|
||||
func (_ *AddRequest) Attribute(_ string, _ []string) {}
|
||||
|
||||
type Attribute struct {
|
||||
Type string
|
||||
Vals []string
|
||||
}
|
||||
|
||||
type Conn struct {
|
||||
Debug interface{}
|
||||
}
|
||||
|
||||
func (_ *Conn) Add(_ *AddRequest) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Conn) Bind(_ string, _ string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Conn) Close() {}
|
||||
|
||||
func (_ *Conn) Compare(_ string, _ string, _ string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (_ *Conn) Del(_ *DelRequest) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Conn) Modify(_ *ModifyRequest) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Conn) PasswordModify(_ *PasswordModifyRequest) (*PasswordModifyResult, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (_ *Conn) Search(_ *SearchRequest) (*SearchResult, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (_ *Conn) SearchWithPaging(_ *SearchRequest, _ uint32) (*SearchResult, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (_ *Conn) SetTimeout(_ time.Duration) {}
|
||||
|
||||
func (_ *Conn) SimpleBind(_ *SimpleBindRequest) (*SimpleBindResult, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (_ *Conn) Start() {}
|
||||
|
||||
func (_ *Conn) StartTLS(_ *tls.Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type Control interface {
|
||||
Encode() interface{}
|
||||
GetControlType() string
|
||||
String() string
|
||||
}
|
||||
|
||||
type DelRequest struct {
|
||||
DN string
|
||||
Controls []Control
|
||||
}
|
||||
|
||||
func Dial(_ string, _ string) (*Conn, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type Entry struct {
|
||||
DN string
|
||||
Attributes []*EntryAttribute
|
||||
}
|
||||
|
||||
func (_ *Entry) GetAttributeValue(_ string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ *Entry) GetAttributeValues(_ string) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Entry) GetRawAttributeValue(_ string) []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Entry) GetRawAttributeValues(_ string) [][]byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Entry) PrettyPrint(_ int) {}
|
||||
|
||||
func (_ *Entry) Print() {}
|
||||
|
||||
type EntryAttribute struct {
|
||||
Name string
|
||||
Values []string
|
||||
ByteValues [][]byte
|
||||
}
|
||||
|
||||
func (_ *EntryAttribute) PrettyPrint(_ int) {}
|
||||
|
||||
func (_ *EntryAttribute) Print() {}
|
||||
|
||||
type ModifyRequest struct {
|
||||
DN string
|
||||
AddAttributes []PartialAttribute
|
||||
DeleteAttributes []PartialAttribute
|
||||
ReplaceAttributes []PartialAttribute
|
||||
}
|
||||
|
||||
func (_ *ModifyRequest) Add(_ string, _ []string) {}
|
||||
|
||||
func (_ *ModifyRequest) Delete(_ string, _ []string) {}
|
||||
|
||||
func (_ *ModifyRequest) Replace(_ string, _ []string) {}
|
||||
|
||||
type PartialAttribute struct {
|
||||
Type string
|
||||
Vals []string
|
||||
}
|
||||
|
||||
type PasswordModifyRequest struct {
|
||||
UserIdentity string
|
||||
OldPassword string
|
||||
NewPassword string
|
||||
}
|
||||
|
||||
type PasswordModifyResult struct {
|
||||
GeneratedPassword string
|
||||
}
|
||||
|
||||
type SearchRequest struct {
|
||||
BaseDN string
|
||||
Scope int
|
||||
DerefAliases int
|
||||
SizeLimit int
|
||||
TimeLimit int
|
||||
TypesOnly bool
|
||||
Filter string
|
||||
Attributes []string
|
||||
Controls []Control
|
||||
}
|
||||
|
||||
type SearchResult struct {
|
||||
Entries []*Entry
|
||||
Referrals []string
|
||||
Controls []Control
|
||||
}
|
||||
|
||||
func (_ *SearchResult) PrettyPrint(_ int) {}
|
||||
|
||||
func (_ *SearchResult) Print() {}
|
||||
|
||||
type SimpleBindRequest struct {
|
||||
Username string
|
||||
Password string
|
||||
Controls []Control
|
||||
}
|
||||
|
||||
type SimpleBindResult struct {
|
||||
Controls []Control
|
||||
}
|
||||
6
go/ql/test/experimental/CWE-287/vendor/modules.txt
vendored
Normal file
6
go/ql/test/experimental/CWE-287/vendor/modules.txt
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
# gopkg.in/ldap.v2 v2.5.1
|
||||
## explicit
|
||||
gopkg.in/ldap.v2
|
||||
# gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d
|
||||
## explicit
|
||||
gopkg.in/asn1-ber.v1
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user