Merge branch 'main' into rust-experiment

Conflicts:
  shared/tree-sitter-extractor/src/trap.rs
This commit is contained in:
Paolo Tranquilli
2024-09-09 14:15:34 +02:00
74 changed files with 1831 additions and 101 deletions

View File

@@ -16,9 +16,9 @@ local_path_override(
bazel_dep(name = "platforms", version = "0.0.10")
bazel_dep(name = "rules_go", version = "0.50.0")
bazel_dep(name = "rules_pkg", version = "0.10.1")
bazel_dep(name = "rules_pkg", version = "1.0.1")
bazel_dep(name = "rules_nodejs", version = "6.2.0-codeql.1")
bazel_dep(name = "rules_python", version = "0.32.2")
bazel_dep(name = "rules_python", version = "0.35.0")
bazel_dep(name = "bazel_skylib", version = "1.6.1")
bazel_dep(name = "abseil-cpp", version = "20240116.0", repo_name = "absl")
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
@@ -27,7 +27,7 @@ bazel_dep(name = "rules_kotlin", version = "1.9.4-codeql.1")
bazel_dep(name = "gazelle", version = "0.38.0")
bazel_dep(name = "rules_dotnet", version = "0.15.1")
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
bazel_dep(name = "rules_rust", version = "0.49.1")
bazel_dep(name = "rules_rust", version = "0.49.3")
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)

View File

@@ -0,0 +1,26 @@
/**
* https://github.com/google/brotli
*/
import cpp
import DecompressionBomb
/**
* The `BrotliDecoderDecompress` function is used in flow sink.
* See https://www.brotli.org/decode.html.
*/
class BrotliDecoderDecompressFunction extends DecompressionFunction {
BrotliDecoderDecompressFunction() { this.hasGlobalName("BrotliDecoderDecompress") }
override int getArchiveParameterIndex() { result = 1 }
}
/**
* The `BrotliDecoderDecompressStream` function is used in flow sink.
* See https://www.brotli.org/decode.html.
*/
class BrotliDecoderDecompressStreamFunction extends DecompressionFunction {
BrotliDecoderDecompressStreamFunction() { this.hasGlobalName("BrotliDecoderDecompressStream") }
override int getArchiveParameterIndex() { result = 2 }
}

View File

@@ -0,0 +1,26 @@
import cpp
import semmle.code.cpp.ir.dataflow.TaintTracking
import MiniZip
import ZlibGzopen
import ZlibInflator
import ZlibUncompress
import LibArchive
import ZSTD
import Brotli
/**
* The Decompression Sink instances, extend this class to define new decompression sinks.
*/
abstract class DecompressionFunction extends Function {
abstract int getArchiveParameterIndex();
}
/**
* The Decompression Flow Steps, extend this class to define new decompression sinks.
*/
abstract class DecompressionFlowStep extends string {
bindingset[this]
DecompressionFlowStep() { any() }
abstract predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2);
}

View File

@@ -0,0 +1,39 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Extracting Compressed files with any compression algorithm like gzip can cause denial of service attacks.</p>
<p>Attackers can compress a huge file consisting of repeated similiar bytes into a small compressed file.</p>
</overview>
<recommendation>
<p>When you want to decompress a user-provided compressed file you must be careful about the decompression ratio or read these files within a loop byte by byte to be able to manage the decompressed size in each cycle of the loop.</p>
</recommendation>
<example>
<p>
Reading an uncompressed Gzip file within a loop and check for a threshold size in each cycle.
</p>
<sample src="example_good.cpp"/>
<p>
The following example is unsafe, as we do not check the uncompressed size.
</p>
<sample src="example_bad.cpp" />
</example>
<references>
<li>
<a href="https://zlib.net/manual.html">Zlib documentation</a>
</li>
<li>
<a href="https://www.bamsoftware.com/hacks/zipbomb/">An explanation of the attack</a>
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,40 @@
/**
* @name User-controlled file decompression
* @description User-controlled data that flows into decompression library APIs without checking the compression rate is dangerous
* @kind path-problem
* @problem.severity error
* @precision low
* @id cpp/data-decompression-bomb
* @tags security
* experimental
* external/cwe/cwe-409
*/
import cpp
import semmle.code.cpp.security.FlowSources
import DecompressionBomb
predicate isSink(FunctionCall fc, DataFlow::Node sink) {
exists(DecompressionFunction f | fc.getTarget() = f |
fc.getArgument(f.getArchiveParameterIndex()) = [sink.asExpr(), sink.asIndirectExpr()]
)
}
module DecompressionTaintConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof FlowSource }
predicate isSink(DataFlow::Node sink) { isSink(_, sink) }
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
any(DecompressionFlowStep s).isAdditionalFlowStep(node1, node2)
}
}
module DecompressionTaint = TaintTracking::Global<DecompressionTaintConfig>;
import DecompressionTaint::PathGraph
from DecompressionTaint::PathNode source, DecompressionTaint::PathNode sink, FunctionCall fc
where DecompressionTaint::flowPath(source, sink) and isSink(fc, sink.getNode())
select sink.getNode(), source, sink, "The decompression output of $@ is not limited", fc,
fc.getTarget().getName()

View File

@@ -0,0 +1,32 @@
/**
* https://github.com/libarchive/libarchive/wiki
*/
import cpp
import DecompressionBomb
/**
* The `archive_read_data*` functions are used in flow sink.
* See https://github.com/libarchive/libarchive/wiki/Examples.
*/
class Archive_read_data_block extends DecompressionFunction {
Archive_read_data_block() {
this.hasGlobalName(["archive_read_data_block", "archive_read_data", "archive_read_data_into_fd"])
}
override int getArchiveParameterIndex() { result = 0 }
}
/**
* The `archive_read_open_filename` function as a flow step.
*/
class ReadOpenFunctionStep extends DecompressionFlowStep {
ReadOpenFunctionStep() { this = "ReadOpenFunction" }
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(FunctionCall fc | fc.getTarget().hasGlobalName("archive_read_open_filename") |
node1.asIndirectExpr() = fc.getArgument(1) and
node2.asIndirectExpr() = fc.getArgument(0)
)
}
}

View File

@@ -0,0 +1,56 @@
/**
* https://github.com/zlib-ng/minizip-ng
*/
import cpp
import DecompressionBomb
/**
* The `mz_zip_entry` function is used in flow sink.
* See https://github.com/zlib-ng/minizip-ng/blob/master/doc/mz_zip.md.
*/
class Mz_zip_entry extends DecompressionFunction {
Mz_zip_entry() { this.hasGlobalName("mz_zip_entry_read") }
override int getArchiveParameterIndex() { result = 1 }
}
/**
* The `mz_zip_reader_entry_*` and `mz_zip_reader_save_all` functions are used in flow sink.
* See https://github.com/zlib-ng/minizip-ng/blob/master/doc/mz_zip_rw.md.
*/
class Mz_zip_reader_entry extends DecompressionFunction {
Mz_zip_reader_entry() {
this.hasGlobalName([
"mz_zip_reader_entry_save", "mz_zip_reader_entry_read", "mz_zip_reader_entry_save_process",
"mz_zip_reader_entry_save_file", "mz_zip_reader_entry_save_buffer", "mz_zip_reader_save_all"
])
}
override int getArchiveParameterIndex() { result = 0 }
}
/**
* The `UnzOpen*` functions are used in flow sink.
*/
class UnzOpenFunction extends DecompressionFunction {
UnzOpenFunction() { this.hasGlobalName(["UnzOpen", "unzOpen64", "unzOpen2", "unzOpen2_64"]) }
override int getArchiveParameterIndex() { result = 0 }
}
/**
* The `mz_zip_reader_open_file` and `mz_zip_reader_open_file_in_memory` functions as a flow step.
*/
class ReaderOpenFunctionStep extends DecompressionFlowStep {
ReaderOpenFunctionStep() { this = "ReaderOpenFunctionStep" }
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(FunctionCall fc |
fc.getTarget().hasGlobalName(["mz_zip_reader_open_file_in_memory", "mz_zip_reader_open_file"])
|
node1.asIndirectExpr() = fc.getArgument(1) and
node2.asIndirectExpr() = fc.getArgument(0)
)
}
}

View File

@@ -0,0 +1,88 @@
/**
* https://github.com/facebook/zstd/blob/dev/examples/streaming_decompression.c
*/
import cpp
import DecompressionBomb
/**
* The `ZSTD_decompress` function is used in flow sink.
*/
class ZstdDecompressFunction extends DecompressionFunction {
ZstdDecompressFunction() { this.hasGlobalName("ZSTD_decompress") }
override int getArchiveParameterIndex() { result = 2 }
}
/**
* The `ZSTD_decompressDCtx` function is used in flow sink.
*/
class ZstdDecompressDctxFunction extends DecompressionFunction {
ZstdDecompressDctxFunction() { this.hasGlobalName("ZSTD_decompressDCtx") }
override int getArchiveParameterIndex() { result = 3 }
}
/**
* The `ZSTD_decompressStream` function is used in flow sink.
*/
class ZstdDecompressStreamFunction extends DecompressionFunction {
ZstdDecompressStreamFunction() { this.hasGlobalName("ZSTD_decompressStream") }
override int getArchiveParameterIndex() { result = 2 }
}
/**
* The `ZSTD_decompress_usingDDict` function is used in flow sink.
*/
class ZstdDecompressUsingDdictFunction extends DecompressionFunction {
ZstdDecompressUsingDdictFunction() { this.hasGlobalName("ZSTD_decompress_usingDDict") }
override int getArchiveParameterIndex() { result = 3 }
}
/**
* The `fopen_orDie` function as a flow step.
*/
class FopenOrDieFunctionStep extends DecompressionFlowStep {
FopenOrDieFunctionStep() { this = "FopenOrDieFunctionStep" }
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(FunctionCall fc | fc.getTarget().hasGlobalName("fopen_orDie") |
node1.asIndirectExpr() = fc.getArgument(0) and
node2.asExpr() = fc
)
}
}
/**
* The `fread_orDie` function as a flow step.
*/
class FreadOrDieFunctionStep extends DecompressionFlowStep {
FreadOrDieFunctionStep() { this = "FreadOrDieFunctionStep" }
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(FunctionCall fc | fc.getTarget().hasGlobalName("fread_orDie") |
node1.asExpr() = fc.getArgument(2) and
node2.asIndirectExpr() = fc.getArgument(0)
)
}
}
/**
* The `src` member of a `ZSTD_inBuffer` variable is used in a flow steps.
*/
class SrcMember extends DecompressionFlowStep {
SrcMember() { this = "SrcMember" }
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(VariableAccess inBufferAccess, Field srcField, ClassAggregateLiteral c |
inBufferAccess.getType().hasName("ZSTD_inBuffer") and
srcField.hasName("src")
|
node2.asExpr() = inBufferAccess and
inBufferAccess.getTarget().getInitializer().getExpr() = c and
node1.asIndirectExpr() = c.getFieldExpr(srcField, _)
)
}
}

View File

@@ -0,0 +1,71 @@
/**
* https://www.zlib.net/
*/
import cpp
import DecompressionBomb
/**
* The `gzfread` function is used in flow sink.
*
* `gzfread(voidp buf, z_size_t size, z_size_t nitems, gzFile file)`
*/
class GzFreadFunction extends DecompressionFunction {
GzFreadFunction() { this.hasGlobalName("gzfread") }
override int getArchiveParameterIndex() { result = 3 }
}
/**
* The `gzgets` function is used in flow sink.
*
* `gzgets(gzFile file, char *buf, int len)`
*/
class GzGetsFunction extends DecompressionFunction {
GzGetsFunction() { this.hasGlobalName("gzgets") }
override int getArchiveParameterIndex() { result = 0 }
}
/**
* The `gzread` function is used in flow sink.
*
* `gzread(gzFile file, voidp buf, unsigned len)`
*/
class GzReadFunction extends DecompressionFunction {
GzReadFunction() { this.hasGlobalName("gzread") }
override int getArchiveParameterIndex() { result = 0 }
}
/**
* The `gzdopen` function is used in flow steps.
*
* `gzdopen(int fd, const char *mode)`
*/
class GzdopenFunctionStep extends DecompressionFlowStep {
GzdopenFunctionStep() { this = "GzdopenFunctionStep" }
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(FunctionCall fc | fc.getTarget().hasGlobalName("gzdopen") |
node1.asExpr() = fc.getArgument(0) and
node2.asExpr() = fc
)
}
}
/**
* The `gzopen` function is used in flow steps.
*
* `gzopen(const char *path, const char *mode)`
*/
class GzopenFunctionStep extends DecompressionFlowStep {
GzopenFunctionStep() { this = "GzopenFunctionStep" }
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(FunctionCall fc | fc.getTarget().hasGlobalName("gzopen") |
node1.asIndirectExpr() = fc.getArgument(0) and
node2.asExpr() = fc
)
}
}

View File

@@ -0,0 +1,37 @@
/**
* https://www.zlib.net/
*/
import cpp
import DecompressionBomb
/**
* The `inflate` and `inflateSync` functions are used in flow sink.
*
* `inflate(z_stream strm, int flush)`
*
* `inflateSync(z_stream strm)`
*/
class InflateFunction extends DecompressionFunction {
InflateFunction() { this.hasGlobalName(["inflate", "inflateSync"]) }
override int getArchiveParameterIndex() { result = 0 }
}
/**
* The `next_in` member of a `z_stream` variable is used in a flow steps.
*/
class NextInMemberStep extends DecompressionFlowStep {
NextInMemberStep() { this = "NextInMemberStep" }
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(Variable nextInVar |
nextInVar.getDeclaringType().hasName("z_stream") and
nextInVar.hasName("next_in")
|
node1.asIndirectExpr() = nextInVar.getAnAssignedValue() and
node2.asExpr() =
nextInVar.getAnAccess().getQualifier().(VariableAccess).getTarget().getAnAccess()
)
}
}

View File

@@ -0,0 +1,15 @@
/**
* https://www.zlib.net/
*/
import cpp
import DecompressionBomb
/**
* The `uncompress`/`uncompress2` function is used in flow sink.
*/
class UncompressFunction extends DecompressionFunction {
UncompressFunction() { this.hasGlobalName(["uncompress", "uncompress2"]) }
override int getArchiveParameterIndex() { result = 2 }
}

View File

@@ -0,0 +1,15 @@
#include "zlib.h"
void UnsafeGzread(gzFile inFileZ) {
const int BUFFER_SIZE = 8192;
unsigned char unzipBuffer[BUFFER_SIZE];
unsigned int unzippedBytes;
while (true) {
unzippedBytes = gzread(inFileZ, unzipBuffer, BUFFER_SIZE);
if (unzippedBytes <= 0) {
break;
}
// process buffer
}
}

View File

@@ -0,0 +1,23 @@
#include "zlib.h"
void SafeGzread(gzFile inFileZ) {
const int MAX_READ = 1024 * 1024 * 4;
const int BUFFER_SIZE = 8192;
unsigned char unzipBuffer[BUFFER_SIZE];
unsigned int unzippedBytes;
unsigned int totalRead = 0;
while (true) {
unzippedBytes = gzread(inFileZ, unzipBuffer, BUFFER_SIZE);
totalRead += unzippedBytes;
if (unzippedBytes <= 0) {
break;
}
if (totalRead > MAX_READ) {
// Possible decompression bomb, stop processing.
break;
} else {
// process buffer
}
}
}

View File

@@ -0,0 +1,239 @@
edges
| brotliTest.cpp:15:41:15:44 | **argv | brotliTest.cpp:15:41:15:44 | **argv | provenance | |
| brotliTest.cpp:15:41:15:44 | **argv | brotliTest.cpp:18:35:18:53 | *access to array | provenance | |
| brotliTest.cpp:15:41:15:44 | **argv | brotliTest.cpp:21:30:21:52 | *access to array | provenance | |
| brotliTest.cpp:21:30:21:52 | *access to array | brotliTest.cpp:24:51:24:58 | **& ... | provenance | |
| libarchiveTests.cpp:16:31:16:32 | *ar | libarchiveTests.cpp:16:31:16:32 | *ar | provenance | |
| libarchiveTests.cpp:16:31:16:32 | *ar | libarchiveTests.cpp:22:41:22:42 | *ar | provenance | |
| libarchiveTests.cpp:30:45:30:48 | **argv | libarchiveTests.cpp:30:45:30:48 | **argv | provenance | |
| libarchiveTests.cpp:30:45:30:48 | **argv | libarchiveTests.cpp:34:35:34:41 | *access to array | provenance | |
| libarchiveTests.cpp:34:32:34:32 | *a | libarchiveTests.cpp:38:27:38:27 | *a | provenance | |
| libarchiveTests.cpp:34:35:34:41 | *access to array | libarchiveTests.cpp:34:32:34:32 | *a | provenance | Config |
| libarchiveTests.cpp:38:27:38:27 | *a | libarchiveTests.cpp:16:31:16:32 | *ar | provenance | |
| libarchiveTests.cpp:38:27:38:27 | *a | libarchiveTests.cpp:38:27:38:27 | read_data output argument | provenance | |
| libarchiveTests.cpp:38:27:38:27 | read_data output argument | libarchiveTests.cpp:38:27:38:27 | *a | provenance | |
| main.cpp:7:33:7:36 | **argv | main.cpp:8:23:8:26 | **argv | provenance | |
| main.cpp:7:33:7:36 | **argv | main.cpp:9:27:9:30 | **argv | provenance | |
| main.cpp:7:33:7:36 | **argv | main.cpp:10:24:10:27 | **argv | provenance | |
| main.cpp:7:33:7:36 | **argv | main.cpp:11:21:11:24 | **argv | provenance | |
| main.cpp:7:33:7:36 | **argv | main.cpp:12:21:12:24 | **argv | provenance | |
| main.cpp:8:23:8:26 | **argv | brotliTest.cpp:15:41:15:44 | **argv | provenance | |
| main.cpp:8:23:8:26 | **argv | main.cpp:8:23:8:26 | brotli_test output argument | provenance | |
| main.cpp:8:23:8:26 | brotli_test output argument | main.cpp:9:27:9:30 | **argv | provenance | |
| main.cpp:8:23:8:26 | brotli_test output argument | main.cpp:10:24:10:27 | **argv | provenance | |
| main.cpp:8:23:8:26 | brotli_test output argument | main.cpp:11:21:11:24 | **argv | provenance | |
| main.cpp:8:23:8:26 | brotli_test output argument | main.cpp:12:21:12:24 | **argv | provenance | |
| main.cpp:9:27:9:30 | **argv | libarchiveTests.cpp:30:45:30:48 | **argv | provenance | |
| main.cpp:9:27:9:30 | **argv | main.cpp:9:27:9:30 | libarchive_test output argument | provenance | |
| main.cpp:9:27:9:30 | libarchive_test output argument | main.cpp:10:24:10:27 | **argv | provenance | |
| main.cpp:9:27:9:30 | libarchive_test output argument | main.cpp:11:21:11:24 | **argv | provenance | |
| main.cpp:9:27:9:30 | libarchive_test output argument | main.cpp:12:21:12:24 | **argv | provenance | |
| main.cpp:10:24:10:27 | **argv | main.cpp:10:24:10:27 | minizip_test output argument | provenance | |
| main.cpp:10:24:10:27 | **argv | minizipTest.cpp:12:42:12:45 | **argv | provenance | |
| main.cpp:10:24:10:27 | minizip_test output argument | main.cpp:11:21:11:24 | **argv | provenance | |
| main.cpp:10:24:10:27 | minizip_test output argument | main.cpp:12:21:12:24 | **argv | provenance | |
| main.cpp:11:21:11:24 | **argv | main.cpp:11:21:11:24 | zlib_test output argument | provenance | |
| main.cpp:11:21:11:24 | **argv | main.cpp:11:21:11:24 | zlib_test output argument | provenance | |
| main.cpp:11:21:11:24 | **argv | zlibTest.cpp:80:33:80:36 | **argv | provenance | |
| main.cpp:11:21:11:24 | zlib_test output argument | main.cpp:12:21:12:24 | **argv | provenance | |
| main.cpp:11:21:11:24 | zlib_test output argument | main.cpp:12:21:12:24 | *argv | provenance | |
| main.cpp:12:21:12:24 | **argv | zstdTest.cpp:26:39:26:42 | **argv | provenance | |
| main.cpp:12:21:12:24 | *argv | zstdTest.cpp:26:39:26:42 | **argv | provenance | |
| main.cpp:12:21:12:24 | *argv | zstdTest.cpp:26:39:26:42 | *argv | provenance | |
| minizipTest.cpp:12:42:12:45 | **argv | minizipTest.cpp:12:42:12:45 | **argv | provenance | |
| minizipTest.cpp:12:42:12:45 | **argv | minizipTest.cpp:17:52:17:67 | *access to array | provenance | |
| minizipTest.cpp:12:42:12:45 | **argv | minizipTest.cpp:24:41:24:47 | *access to array | provenance | |
| minizipTest.cpp:12:42:12:45 | **argv | minizipTest.cpp:28:13:28:19 | *access to array | provenance | |
| minizipTest.cpp:24:29:24:38 | **zip_reader | minizipTest.cpp:26:30:26:39 | **zip_reader | provenance | |
| minizipTest.cpp:24:29:24:38 | *zip_reader | minizipTest.cpp:26:30:26:39 | *zip_reader | provenance | |
| minizipTest.cpp:24:41:24:47 | *access to array | minizipTest.cpp:24:29:24:38 | **zip_reader | provenance | Config |
| minizipTest.cpp:24:41:24:47 | *access to array | minizipTest.cpp:24:29:24:38 | *zip_reader | provenance | Config |
| zlibTest.cpp:16:26:16:30 | *input | zlibTest.cpp:20:25:20:39 | *input | provenance | |
| zlibTest.cpp:20:25:20:39 | *input | zlibTest.cpp:16:26:16:30 | *input | provenance | |
| zlibTest.cpp:20:25:20:39 | *input | zlibTest.cpp:24:17:24:26 | & ... | provenance | Config |
| zlibTest.cpp:20:25:20:39 | *input | zlibTest.cpp:25:13:25:22 | & ... | provenance | Config |
| zlibTest.cpp:24:17:24:26 | & ... | zlibTest.cpp:25:13:25:22 | & ... | provenance | |
| zlibTest.cpp:37:25:37:32 | *fileName | zlibTest.cpp:38:29:38:36 | *fileName | provenance | |
| zlibTest.cpp:38:22:38:27 | call to gzopen | zlibTest.cpp:38:22:38:27 | call to gzopen | provenance | |
| zlibTest.cpp:38:22:38:27 | call to gzopen | zlibTest.cpp:41:20:41:26 | inFileZ | provenance | |
| zlibTest.cpp:38:29:38:36 | *fileName | zlibTest.cpp:37:25:37:32 | *fileName | provenance | |
| zlibTest.cpp:38:29:38:36 | *fileName | zlibTest.cpp:38:22:38:27 | call to gzopen | provenance | Config |
| zlibTest.cpp:47:26:47:33 | *fileName | zlibTest.cpp:48:29:48:36 | *fileName | provenance | |
| zlibTest.cpp:48:22:48:27 | call to gzopen | zlibTest.cpp:48:22:48:27 | call to gzopen | provenance | |
| zlibTest.cpp:48:22:48:27 | call to gzopen | zlibTest.cpp:51:38:51:44 | inFileZ | provenance | |
| zlibTest.cpp:48:29:48:36 | *fileName | zlibTest.cpp:47:26:47:33 | *fileName | provenance | |
| zlibTest.cpp:48:29:48:36 | *fileName | zlibTest.cpp:48:22:48:27 | call to gzopen | provenance | Config |
| zlibTest.cpp:57:25:57:32 | *fileName | zlibTest.cpp:58:29:58:36 | *fileName | provenance | |
| zlibTest.cpp:58:22:58:27 | call to gzopen | zlibTest.cpp:58:22:58:27 | call to gzopen | provenance | |
| zlibTest.cpp:58:22:58:27 | call to gzopen | zlibTest.cpp:62:25:62:31 | inFileZ | provenance | |
| zlibTest.cpp:58:29:58:36 | *fileName | zlibTest.cpp:57:25:57:32 | *fileName | provenance | |
| zlibTest.cpp:58:29:58:36 | *fileName | zlibTest.cpp:58:22:58:27 | call to gzopen | provenance | Config |
| zlibTest.cpp:71:26:71:30 | *input | zlibTest.cpp:71:26:71:30 | *input | provenance | |
| zlibTest.cpp:71:26:71:30 | *input | zlibTest.cpp:77:45:77:59 | *input | provenance | |
| zlibTest.cpp:80:33:80:36 | **argv | zlibTest.cpp:80:33:80:36 | **argv | provenance | |
| zlibTest.cpp:80:33:80:36 | **argv | zlibTest.cpp:81:19:81:25 | *access to array | provenance | |
| zlibTest.cpp:80:33:80:36 | **argv | zlibTest.cpp:82:18:82:24 | *access to array | provenance | |
| zlibTest.cpp:80:33:80:36 | **argv | zlibTest.cpp:83:19:83:25 | *access to array | provenance | |
| zlibTest.cpp:80:33:80:36 | **argv | zlibTest.cpp:84:18:84:24 | *access to array | provenance | |
| zlibTest.cpp:80:33:80:36 | **argv | zlibTest.cpp:85:19:85:25 | *access to array | provenance | |
| zlibTest.cpp:81:19:81:25 | *access to array | zlibTest.cpp:47:26:47:33 | *fileName | provenance | |
| zlibTest.cpp:81:19:81:25 | *access to array | zlibTest.cpp:81:19:81:25 | UnsafeGzfread output argument | provenance | |
| zlibTest.cpp:81:19:81:25 | UnsafeGzfread output argument | zlibTest.cpp:80:33:80:36 | **argv | provenance | |
| zlibTest.cpp:81:19:81:25 | UnsafeGzfread output argument | zlibTest.cpp:80:33:80:36 | **argv [Return] | provenance | |
| zlibTest.cpp:81:19:81:25 | UnsafeGzfread output argument | zlibTest.cpp:82:18:82:24 | *access to array | provenance | |
| zlibTest.cpp:81:19:81:25 | UnsafeGzfread output argument | zlibTest.cpp:83:19:83:25 | *access to array | provenance | |
| zlibTest.cpp:81:19:81:25 | UnsafeGzfread output argument | zlibTest.cpp:84:18:84:24 | *access to array | provenance | |
| zlibTest.cpp:81:19:81:25 | UnsafeGzfread output argument | zlibTest.cpp:85:19:85:25 | *access to array | provenance | |
| zlibTest.cpp:82:18:82:24 | *access to array | zlibTest.cpp:57:25:57:32 | *fileName | provenance | |
| zlibTest.cpp:82:18:82:24 | *access to array | zlibTest.cpp:82:18:82:24 | UnsafeGzgets output argument | provenance | |
| zlibTest.cpp:82:18:82:24 | UnsafeGzgets output argument | zlibTest.cpp:80:33:80:36 | **argv | provenance | |
| zlibTest.cpp:82:18:82:24 | UnsafeGzgets output argument | zlibTest.cpp:80:33:80:36 | **argv [Return] | provenance | |
| zlibTest.cpp:82:18:82:24 | UnsafeGzgets output argument | zlibTest.cpp:83:19:83:25 | *access to array | provenance | |
| zlibTest.cpp:82:18:82:24 | UnsafeGzgets output argument | zlibTest.cpp:84:18:84:24 | *access to array | provenance | |
| zlibTest.cpp:82:18:82:24 | UnsafeGzgets output argument | zlibTest.cpp:85:19:85:25 | *access to array | provenance | |
| zlibTest.cpp:83:19:83:25 | *access to array | zlibTest.cpp:16:26:16:30 | *input | provenance | |
| zlibTest.cpp:83:19:83:25 | *access to array | zlibTest.cpp:83:19:83:25 | UnsafeInflate output argument | provenance | |
| zlibTest.cpp:83:19:83:25 | UnsafeInflate output argument | zlibTest.cpp:80:33:80:36 | **argv | provenance | |
| zlibTest.cpp:83:19:83:25 | UnsafeInflate output argument | zlibTest.cpp:80:33:80:36 | **argv [Return] | provenance | |
| zlibTest.cpp:83:19:83:25 | UnsafeInflate output argument | zlibTest.cpp:84:18:84:24 | *access to array | provenance | |
| zlibTest.cpp:83:19:83:25 | UnsafeInflate output argument | zlibTest.cpp:85:19:85:25 | *access to array | provenance | |
| zlibTest.cpp:84:18:84:24 | *access to array | zlibTest.cpp:37:25:37:32 | *fileName | provenance | |
| zlibTest.cpp:84:18:84:24 | *access to array | zlibTest.cpp:84:18:84:24 | UnsafeGzread output argument | provenance | |
| zlibTest.cpp:84:18:84:24 | UnsafeGzread output argument | zlibTest.cpp:80:33:80:36 | **argv | provenance | |
| zlibTest.cpp:84:18:84:24 | UnsafeGzread output argument | zlibTest.cpp:80:33:80:36 | **argv [Return] | provenance | |
| zlibTest.cpp:84:18:84:24 | UnsafeGzread output argument | zlibTest.cpp:85:19:85:25 | *access to array | provenance | |
| zlibTest.cpp:85:19:85:25 | *access to array | zlibTest.cpp:71:26:71:30 | *input | provenance | |
| zlibTest.cpp:85:19:85:25 | *access to array | zlibTest.cpp:85:19:85:25 | InflateString output argument | provenance | |
| zlibTest.cpp:85:19:85:25 | InflateString output argument | zlibTest.cpp:80:33:80:36 | **argv | provenance | |
| zlibTest.cpp:85:19:85:25 | InflateString output argument | zlibTest.cpp:80:33:80:36 | **argv [Return] | provenance | |
| zstdTest.cpp:26:39:26:42 | **argv | zstdTest.cpp:27:35:27:41 | *access to array | provenance | |
| zstdTest.cpp:26:39:26:42 | *argv | zstdTest.cpp:27:35:27:41 | *access to array | provenance | |
| zstdTest.cpp:27:23:27:33 | call to fopen_orDie | zstdTest.cpp:27:23:27:33 | call to fopen_orDie | provenance | |
| zstdTest.cpp:27:23:27:33 | call to fopen_orDie | zstdTest.cpp:35:52:35:54 | fin | provenance | |
| zstdTest.cpp:27:35:27:41 | *access to array | zstdTest.cpp:27:23:27:33 | call to fopen_orDie | provenance | Config |
| zstdTest.cpp:35:32:35:37 | **buffIn | zstdTest.cpp:36:32:36:37 | **buffIn | provenance | |
| zstdTest.cpp:35:32:35:37 | *buffIn | zstdTest.cpp:36:32:36:37 | *buffIn | provenance | |
| zstdTest.cpp:35:52:35:54 | fin | zstdTest.cpp:35:32:35:37 | **buffIn | provenance | Config |
| zstdTest.cpp:35:52:35:54 | fin | zstdTest.cpp:35:32:35:37 | *buffIn | provenance | Config |
| zstdTest.cpp:36:32:36:37 | **buffIn | zstdTest.cpp:35:32:35:37 | **buffIn | provenance | |
| zstdTest.cpp:36:32:36:37 | **buffIn | zstdTest.cpp:39:69:39:74 | & ... | provenance | Config |
| zstdTest.cpp:36:32:36:37 | **buffIn | zstdTest.cpp:39:69:39:74 | & ... | provenance | Config |
| zstdTest.cpp:36:32:36:37 | *buffIn | zstdTest.cpp:35:32:35:37 | *buffIn | provenance | |
| zstdTest.cpp:36:32:36:37 | *buffIn | zstdTest.cpp:39:69:39:74 | & ... | provenance | Config |
| zstdTest.cpp:36:32:36:37 | *buffIn | zstdTest.cpp:39:69:39:74 | & ... | provenance | Config |
| zstdTest.cpp:39:69:39:74 | & ... | zstdTest.cpp:39:69:39:74 | & ... | provenance | |
| zstdTest.cpp:39:69:39:74 | & ... | zstdTest.cpp:39:69:39:74 | & ... | provenance | |
nodes
| brotliTest.cpp:15:41:15:44 | **argv | semmle.label | **argv |
| brotliTest.cpp:15:41:15:44 | **argv | semmle.label | **argv |
| brotliTest.cpp:18:35:18:53 | *access to array | semmle.label | *access to array |
| brotliTest.cpp:21:30:21:52 | *access to array | semmle.label | *access to array |
| brotliTest.cpp:24:51:24:58 | **& ... | semmle.label | **& ... |
| libarchiveTests.cpp:16:31:16:32 | *ar | semmle.label | *ar |
| libarchiveTests.cpp:16:31:16:32 | *ar | semmle.label | *ar |
| libarchiveTests.cpp:22:41:22:42 | *ar | semmle.label | *ar |
| libarchiveTests.cpp:30:45:30:48 | **argv | semmle.label | **argv |
| libarchiveTests.cpp:30:45:30:48 | **argv | semmle.label | **argv |
| libarchiveTests.cpp:34:32:34:32 | *a | semmle.label | *a |
| libarchiveTests.cpp:34:35:34:41 | *access to array | semmle.label | *access to array |
| libarchiveTests.cpp:38:27:38:27 | *a | semmle.label | *a |
| libarchiveTests.cpp:38:27:38:27 | read_data output argument | semmle.label | read_data output argument |
| main.cpp:7:33:7:36 | **argv | semmle.label | **argv |
| main.cpp:8:23:8:26 | **argv | semmle.label | **argv |
| main.cpp:8:23:8:26 | brotli_test output argument | semmle.label | brotli_test output argument |
| main.cpp:9:27:9:30 | **argv | semmle.label | **argv |
| main.cpp:9:27:9:30 | libarchive_test output argument | semmle.label | libarchive_test output argument |
| main.cpp:10:24:10:27 | **argv | semmle.label | **argv |
| main.cpp:10:24:10:27 | minizip_test output argument | semmle.label | minizip_test output argument |
| main.cpp:11:21:11:24 | **argv | semmle.label | **argv |
| main.cpp:11:21:11:24 | zlib_test output argument | semmle.label | zlib_test output argument |
| main.cpp:11:21:11:24 | zlib_test output argument | semmle.label | zlib_test output argument |
| main.cpp:12:21:12:24 | **argv | semmle.label | **argv |
| main.cpp:12:21:12:24 | *argv | semmle.label | *argv |
| minizipTest.cpp:12:42:12:45 | **argv | semmle.label | **argv |
| minizipTest.cpp:12:42:12:45 | **argv | semmle.label | **argv |
| minizipTest.cpp:17:52:17:67 | *access to array | semmle.label | *access to array |
| minizipTest.cpp:24:29:24:38 | **zip_reader | semmle.label | **zip_reader |
| minizipTest.cpp:24:29:24:38 | *zip_reader | semmle.label | *zip_reader |
| minizipTest.cpp:24:41:24:47 | *access to array | semmle.label | *access to array |
| minizipTest.cpp:26:30:26:39 | **zip_reader | semmle.label | **zip_reader |
| minizipTest.cpp:26:30:26:39 | *zip_reader | semmle.label | *zip_reader |
| minizipTest.cpp:28:13:28:19 | *access to array | semmle.label | *access to array |
| zlibTest.cpp:16:26:16:30 | *input | semmle.label | *input |
| zlibTest.cpp:16:26:16:30 | *input | semmle.label | *input |
| zlibTest.cpp:20:25:20:39 | *input | semmle.label | *input |
| zlibTest.cpp:24:17:24:26 | & ... | semmle.label | & ... |
| zlibTest.cpp:25:13:25:22 | & ... | semmle.label | & ... |
| zlibTest.cpp:37:25:37:32 | *fileName | semmle.label | *fileName |
| zlibTest.cpp:37:25:37:32 | *fileName | semmle.label | *fileName |
| zlibTest.cpp:38:22:38:27 | call to gzopen | semmle.label | call to gzopen |
| zlibTest.cpp:38:22:38:27 | call to gzopen | semmle.label | call to gzopen |
| zlibTest.cpp:38:29:38:36 | *fileName | semmle.label | *fileName |
| zlibTest.cpp:41:20:41:26 | inFileZ | semmle.label | inFileZ |
| zlibTest.cpp:47:26:47:33 | *fileName | semmle.label | *fileName |
| zlibTest.cpp:47:26:47:33 | *fileName | semmle.label | *fileName |
| zlibTest.cpp:48:22:48:27 | call to gzopen | semmle.label | call to gzopen |
| zlibTest.cpp:48:22:48:27 | call to gzopen | semmle.label | call to gzopen |
| zlibTest.cpp:48:29:48:36 | *fileName | semmle.label | *fileName |
| zlibTest.cpp:51:38:51:44 | inFileZ | semmle.label | inFileZ |
| zlibTest.cpp:57:25:57:32 | *fileName | semmle.label | *fileName |
| zlibTest.cpp:57:25:57:32 | *fileName | semmle.label | *fileName |
| zlibTest.cpp:58:22:58:27 | call to gzopen | semmle.label | call to gzopen |
| zlibTest.cpp:58:22:58:27 | call to gzopen | semmle.label | call to gzopen |
| zlibTest.cpp:58:29:58:36 | *fileName | semmle.label | *fileName |
| zlibTest.cpp:62:25:62:31 | inFileZ | semmle.label | inFileZ |
| zlibTest.cpp:71:26:71:30 | *input | semmle.label | *input |
| zlibTest.cpp:71:26:71:30 | *input | semmle.label | *input |
| zlibTest.cpp:77:45:77:59 | *input | semmle.label | *input |
| zlibTest.cpp:80:33:80:36 | **argv | semmle.label | **argv |
| zlibTest.cpp:80:33:80:36 | **argv | semmle.label | **argv |
| zlibTest.cpp:80:33:80:36 | **argv [Return] | semmle.label | **argv [Return] |
| zlibTest.cpp:81:19:81:25 | *access to array | semmle.label | *access to array |
| zlibTest.cpp:81:19:81:25 | UnsafeGzfread output argument | semmle.label | UnsafeGzfread output argument |
| zlibTest.cpp:82:18:82:24 | *access to array | semmle.label | *access to array |
| zlibTest.cpp:82:18:82:24 | UnsafeGzgets output argument | semmle.label | UnsafeGzgets output argument |
| zlibTest.cpp:83:19:83:25 | *access to array | semmle.label | *access to array |
| zlibTest.cpp:83:19:83:25 | UnsafeInflate output argument | semmle.label | UnsafeInflate output argument |
| zlibTest.cpp:84:18:84:24 | *access to array | semmle.label | *access to array |
| zlibTest.cpp:84:18:84:24 | UnsafeGzread output argument | semmle.label | UnsafeGzread output argument |
| zlibTest.cpp:85:19:85:25 | *access to array | semmle.label | *access to array |
| zlibTest.cpp:85:19:85:25 | InflateString output argument | semmle.label | InflateString output argument |
| zstdTest.cpp:26:39:26:42 | **argv | semmle.label | **argv |
| zstdTest.cpp:26:39:26:42 | *argv | semmle.label | *argv |
| zstdTest.cpp:27:23:27:33 | call to fopen_orDie | semmle.label | call to fopen_orDie |
| zstdTest.cpp:27:23:27:33 | call to fopen_orDie | semmle.label | call to fopen_orDie |
| zstdTest.cpp:27:35:27:41 | *access to array | semmle.label | *access to array |
| zstdTest.cpp:35:32:35:37 | **buffIn | semmle.label | **buffIn |
| zstdTest.cpp:35:32:35:37 | *buffIn | semmle.label | *buffIn |
| zstdTest.cpp:35:52:35:54 | fin | semmle.label | fin |
| zstdTest.cpp:36:32:36:37 | **buffIn | semmle.label | **buffIn |
| zstdTest.cpp:36:32:36:37 | *buffIn | semmle.label | *buffIn |
| zstdTest.cpp:39:69:39:74 | & ... | semmle.label | & ... |
| zstdTest.cpp:39:69:39:74 | & ... | semmle.label | & ... |
subpaths
| libarchiveTests.cpp:38:27:38:27 | *a | libarchiveTests.cpp:16:31:16:32 | *ar | libarchiveTests.cpp:16:31:16:32 | *ar | libarchiveTests.cpp:38:27:38:27 | read_data output argument |
| main.cpp:8:23:8:26 | **argv | brotliTest.cpp:15:41:15:44 | **argv | brotliTest.cpp:15:41:15:44 | **argv | main.cpp:8:23:8:26 | brotli_test output argument |
| main.cpp:9:27:9:30 | **argv | libarchiveTests.cpp:30:45:30:48 | **argv | libarchiveTests.cpp:30:45:30:48 | **argv | main.cpp:9:27:9:30 | libarchive_test output argument |
| main.cpp:10:24:10:27 | **argv | minizipTest.cpp:12:42:12:45 | **argv | minizipTest.cpp:12:42:12:45 | **argv | main.cpp:10:24:10:27 | minizip_test output argument |
| main.cpp:11:21:11:24 | **argv | zlibTest.cpp:80:33:80:36 | **argv | zlibTest.cpp:80:33:80:36 | **argv | main.cpp:11:21:11:24 | zlib_test output argument |
| main.cpp:11:21:11:24 | **argv | zlibTest.cpp:80:33:80:36 | **argv | zlibTest.cpp:80:33:80:36 | **argv [Return] | main.cpp:11:21:11:24 | zlib_test output argument |
| main.cpp:11:21:11:24 | **argv | zlibTest.cpp:80:33:80:36 | **argv | zlibTest.cpp:80:33:80:36 | **argv [Return] | main.cpp:11:21:11:24 | zlib_test output argument |
| zlibTest.cpp:81:19:81:25 | *access to array | zlibTest.cpp:47:26:47:33 | *fileName | zlibTest.cpp:47:26:47:33 | *fileName | zlibTest.cpp:81:19:81:25 | UnsafeGzfread output argument |
| zlibTest.cpp:82:18:82:24 | *access to array | zlibTest.cpp:57:25:57:32 | *fileName | zlibTest.cpp:57:25:57:32 | *fileName | zlibTest.cpp:82:18:82:24 | UnsafeGzgets output argument |
| zlibTest.cpp:83:19:83:25 | *access to array | zlibTest.cpp:16:26:16:30 | *input | zlibTest.cpp:16:26:16:30 | *input | zlibTest.cpp:83:19:83:25 | UnsafeInflate output argument |
| zlibTest.cpp:84:18:84:24 | *access to array | zlibTest.cpp:37:25:37:32 | *fileName | zlibTest.cpp:37:25:37:32 | *fileName | zlibTest.cpp:84:18:84:24 | UnsafeGzread output argument |
| zlibTest.cpp:85:19:85:25 | *access to array | zlibTest.cpp:71:26:71:30 | *input | zlibTest.cpp:71:26:71:30 | *input | zlibTest.cpp:85:19:85:25 | InflateString output argument |
#select
| brotliTest.cpp:18:35:18:53 | *access to array | main.cpp:7:33:7:36 | **argv | brotliTest.cpp:18:35:18:53 | *access to array | The decompression output of $@ is not limited | brotliTest.cpp:18:5:18:27 | call to BrotliDecoderDecompress | BrotliDecoderDecompress |
| brotliTest.cpp:24:51:24:58 | **& ... | main.cpp:7:33:7:36 | **argv | brotliTest.cpp:24:51:24:58 | **& ... | The decompression output of $@ is not limited | brotliTest.cpp:24:5:24:33 | call to BrotliDecoderDecompressStream | BrotliDecoderDecompressStream |
| libarchiveTests.cpp:22:41:22:42 | *ar | main.cpp:7:33:7:36 | **argv | libarchiveTests.cpp:22:41:22:42 | *ar | The decompression output of $@ is not limited | libarchiveTests.cpp:22:17:22:39 | call to archive_read_data_block | archive_read_data_block |
| minizipTest.cpp:17:52:17:67 | *access to array | main.cpp:7:33:7:36 | **argv | minizipTest.cpp:17:52:17:67 | *access to array | The decompression output of $@ is not limited | minizipTest.cpp:17:22:17:38 | call to mz_zip_entry_read | mz_zip_entry_read |
| minizipTest.cpp:26:30:26:39 | **zip_reader | main.cpp:7:33:7:36 | **argv | minizipTest.cpp:26:30:26:39 | **zip_reader | The decompression output of $@ is not limited | minizipTest.cpp:26:5:26:28 | call to mz_zip_reader_entry_save | mz_zip_reader_entry_save |
| minizipTest.cpp:26:30:26:39 | *zip_reader | main.cpp:7:33:7:36 | **argv | minizipTest.cpp:26:30:26:39 | *zip_reader | The decompression output of $@ is not limited | minizipTest.cpp:26:5:26:28 | call to mz_zip_reader_entry_save | mz_zip_reader_entry_save |
| minizipTest.cpp:28:13:28:19 | *access to array | main.cpp:7:33:7:36 | **argv | minizipTest.cpp:28:13:28:19 | *access to array | The decompression output of $@ is not limited | minizipTest.cpp:28:5:28:11 | call to UnzOpen | UnzOpen |
| zlibTest.cpp:25:13:25:22 | & ... | main.cpp:7:33:7:36 | **argv | zlibTest.cpp:25:13:25:22 | & ... | The decompression output of $@ is not limited | zlibTest.cpp:25:5:25:11 | call to inflate | inflate |
| zlibTest.cpp:41:20:41:26 | inFileZ | main.cpp:7:33:7:36 | **argv | zlibTest.cpp:41:20:41:26 | inFileZ | The decompression output of $@ is not limited | zlibTest.cpp:41:13:41:18 | call to gzread | gzread |
| zlibTest.cpp:51:38:51:44 | inFileZ | main.cpp:7:33:7:36 | **argv | zlibTest.cpp:51:38:51:44 | inFileZ | The decompression output of $@ is not limited | zlibTest.cpp:51:14:51:20 | call to gzfread | gzfread |
| zlibTest.cpp:62:25:62:31 | inFileZ | main.cpp:7:33:7:36 | **argv | zlibTest.cpp:62:25:62:31 | inFileZ | The decompression output of $@ is not limited | zlibTest.cpp:62:18:62:23 | call to gzgets | gzgets |
| zlibTest.cpp:77:45:77:59 | *input | main.cpp:7:33:7:36 | **argv | zlibTest.cpp:77:45:77:59 | *input | The decompression output of $@ is not limited | zlibTest.cpp:77:5:77:14 | call to uncompress | uncompress |
| zstdTest.cpp:39:69:39:74 | & ... | main.cpp:7:33:7:36 | **argv | zstdTest.cpp:39:69:39:74 | & ... | The decompression output of $@ is not limited | zstdTest.cpp:39:32:39:52 | call to ZSTD_decompressStream | ZSTD_decompressStream |

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-409/DecompressionBombs.ql

View File

@@ -0,0 +1,26 @@
typedef long unsigned int size_t;
typedef unsigned char uint8_t;
enum BrotliDecoderResult {};
struct BrotliDecoderState;
BrotliDecoderResult BrotliDecoderDecompress(
size_t encoded_size, const uint8_t encoded_buffer[],
size_t *decoded_size, uint8_t decoded_buffer[]);
BrotliDecoderResult BrotliDecoderDecompressStream(
BrotliDecoderState *state, size_t *available_in, const uint8_t **next_in,
size_t *available_out, uint8_t **next_out, size_t *total_out);
void brotli_test(int argc, const char **argv) {
uint8_t output[1024];
size_t output_size = sizeof(output);
BrotliDecoderDecompress(1024, (uint8_t *) argv[2], &output_size, output); // BAD
size_t input_size = 1024;
const uint8_t *input_p = (const uint8_t*)argv[2];
uint8_t *output_p = output;
size_t out_size;
BrotliDecoderDecompressStream(0, &input_size, &input_p, &output_size, // BAD
&output_p, &out_size);
}

View File

@@ -0,0 +1,42 @@
#define ARCHIVE_EOF 1
#define ARCHIVE_OK 0
#define ARCHIVE_WARN (-20)
struct archive;
struct archive_entry;
typedef int size_t;
typedef int la_int64_t;
archive *archive_read_new();
int archive_read_open_filename(archive *pArchive, const char *filename, int i);
int archive_read_next_header(archive *a, archive_entry **entry);
int archive_entry_size(archive_entry *pEntry);
int archive_read_data_block(archive *pArchive, const void **pVoid, size_t *pInt, la_int64_t *pInt1);
static int read_data(archive *ar) {
for (;;) {
const void *buff;
size_t size;
la_int64_t offset;
int r = archive_read_data_block(ar, &buff, &size, &offset); // BAD
if (r == ARCHIVE_EOF)
return ARCHIVE_OK;
if (r < ARCHIVE_OK)
return r;
}
}
void libarchive_test(int argc, const char **argv) {
archive *a = archive_read_new();
archive_entry *entry;
archive_read_open_filename(a, argv[1], 10240);
for (;;) {
archive_read_next_header(a, &entry);
if (archive_entry_size(entry) > 0) {
if (read_data(a) < ARCHIVE_WARN)
break;
}
}
}

View File

@@ -0,0 +1,14 @@
void brotli_test(int argc, const char **argv);
void libarchive_test(int argc, const char **argv);
void minizip_test(int argc, const char **argv);
void zlib_test(int argc, const char **argv);
void zstd_test(int argc, const char **argv);
int main(int argc, const char **argv) {
brotli_test(argc, argv);
libarchive_test(argc, argv);
minizip_test(argc, argv);
zlib_test(argc, argv);
zstd_test(argc, argv);
return 0;
}

View File

@@ -0,0 +1,29 @@
typedef signed int int32_t;
void *mz_zip_reader_create();
int32_t mz_zip_reader_open_file(void *handle, const char *path);
int32_t mz_zip_reader_goto_first_entry(void *pVoid);
int32_t mz_zip_reader_entry_save(void *pVoid, int stream, int write);
int32_t mz_zip_entry_read(void *pVoid, void *buf, int32_t i);
void UnzOpen(const char *string);
void *mz_zip_create();
void minizip_test(int argc, const char **argv) {
void *zip_handle = mz_zip_create();
int32_t bytes_read;
char buf[4096];
while(true) {
bytes_read = mz_zip_entry_read(zip_handle, (char *) argv[1], sizeof(buf)); // BAD
if (bytes_read <= 0) {
break;
}
}
void *zip_reader = mz_zip_reader_create();
mz_zip_reader_open_file(zip_reader, argv[1]);
mz_zip_reader_goto_first_entry(zip_reader);
mz_zip_reader_entry_save(zip_reader, 0, 0); // BAD
UnzOpen(argv[3]); // BAD
}

View File

@@ -0,0 +1,86 @@
typedef unsigned char Bytef;
typedef unsigned long uLong;
typedef uLong uLongf;
typedef unsigned int uInt;
struct z_stream {
Bytef *next_in;
Bytef *next_out;
uInt avail_out;
};
void inflateInit(z_stream *infstream);
void inflate(z_stream *infstream, int i);
void inflateEnd(z_stream *infstream);
void UnsafeInflate(char *input) {
unsigned char output[1024];
z_stream infstream;
infstream.next_in = (Bytef *) input; // input char array
infstream.avail_out = sizeof(output); // size of output
infstream.next_out = output; // output char array
inflateInit(&infstream);
inflate(&infstream, 0); // BAD
}
struct gzFile {
};
gzFile gzopen(char *str, const char *rb);
unsigned int gzread(gzFile gz_file, unsigned char *str, int i);
bool gzfread(char *str, int i, int i1, gzFile gz_file);
char *gzgets(gzFile gz_file, char *buffer, int i);
void UnsafeGzread(char *fileName) {
gzFile inFileZ = gzopen(fileName, "rb");
unsigned char unzipBuffer[8192];
while (true) {
if (gzread(inFileZ, unzipBuffer, 8192) <= 0) { // BAD
break;
}
}
}
void UnsafeGzfread(char *fileName) {
gzFile inFileZ = gzopen(fileName, "rb");
while (true) {
char buffer[1000];
if (!gzfread(buffer, 999, 1, inFileZ)) { // BAD
break;
}
}
}
void UnsafeGzgets(char *fileName) {
gzFile inFileZ = gzopen(fileName, "rb");
char *buffer = new char[4000000000];
char *result;
while (true) {
result = gzgets(inFileZ, buffer, 1000000000); // BAD
if (result == nullptr) {
break;
}
}
}
int uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
void InflateString(char *input) {
unsigned char output[1024];
uLong source_length = 500;
uLong destination_length = sizeof(output);
uncompress(output, &destination_length, (Bytef *) input, source_length); // BAD
}
void zlib_test(int argc, char **argv) {
UnsafeGzfread(argv[2]);
UnsafeGzgets(argv[2]);
UnsafeInflate(argv[2]);
UnsafeGzread(argv[2]);
InflateString(argv[2]);
}

View File

@@ -0,0 +1,43 @@
typedef long unsigned int size_t;
struct FILE;
FILE *fopen_orDie(const char *filename, const char *instruction);
size_t fread_orDie(void *const pVoid, const size_t read, FILE *const pFile);
void *const malloc_orDie(const size_t size);
struct ZSTD_DCtx;
typedef struct ZSTD_inBuffer_s {
const void *src;
size_t size;
size_t pos;
} ZSTD_inBuffer;
typedef struct ZSTD_outBuffer_s {
void *dst;
size_t size;
size_t pos;
} ZSTD_outBuffer;
const size_t ZSTD_DStreamInSize();
const size_t ZSTD_DStreamOutSize();
ZSTD_DCtx *const ZSTD_createDCtx();
const size_t ZSTD_decompressStream(ZSTD_DCtx *const pCtx, ZSTD_outBuffer *pS, ZSTD_inBuffer *pS1);
void CHECK_ZSTD(const size_t ret);
void zstd_test(int argc, const char **argv) {
FILE *const fin = fopen_orDie(argv[1], "rb");
size_t const buffInSize = ZSTD_DStreamInSize();
void *const buffIn = malloc_orDie(buffInSize);
size_t const buffOutSize = ZSTD_DStreamOutSize();
void *const buffOut = malloc_orDie(buffOutSize);
ZSTD_DCtx *const dctx = ZSTD_createDCtx();
size_t read;
while ((read = fread_orDie(buffIn, buffInSize, fin))) {
ZSTD_inBuffer input = {buffIn, read, 0};
while (input.pos < input.size) {
ZSTD_outBuffer output = {buffOut, buffOutSize, 0};
size_t const ret = ZSTD_decompressStream(dctx, &output, &input); // BAD
CHECK_ZSTD(ret);
}
}
}

View File

@@ -5,6 +5,5 @@
| main1.cpp:7:1:7:26 | #include "defines_issue.h" | Include | defines_issue.h | 1 |
| main2.cpp:3:1:3:19 | #include "common.h" | Include | common.h | 1 |
| main2.cpp:7:1:7:26 | #include "defines_issue.h" | Include | defines_issue.h | 1 |
| nameclash.h:3:1:3:27 | #include_next "nameclash.h" | IncludeNext | nameclash.h | 1 |
| nameclash.h:3:1:3:27 | #include_next "nameclash.h" | IncludeNext | subdir1/nameclash.h | 1 |
| nameclash.h:3:1:3:27 | #include_next "nameclash.h" | IncludeNext | subdir2/nameclash.h | 1 |

View File

@@ -1,4 +1,3 @@
| a/test.h:2:1:2:22 | #include_next <test.h> | a/test.h:0:0:0:0 | a/test.h |
| a/test.h:2:1:2:22 | #include_next <test.h> | b/test.h:0:0:0:0 | b/test.h |
| b/loop.h:2:1:2:22 | #include_next <test.h> | a/test.h:0:0:0:0 | a/test.h |
| b/test.h:4:1:4:17 | #include "loop.h" | b/loop.h:0:0:0:0 | b/loop.h |

View File

@@ -4474,6 +4474,33 @@ ir.c:
# 29| Type = [IntType] int
# 29| Value = [Literal] 0
# 29| ValueCategory = prvalue
# 32| [TopLevelFunction] void unexplained_loop_regression()
# 32| <params>:
# 33| getEntryPoint(): [BlockStmt] { ... }
# 34| getStmt(0): [MicrosoftTryExceptStmt] __try { ... } __except( ... ) { ... }
# 35| getStmt(): [BlockStmt] { ... }
# 36| getStmt(0): [ExprStmt] ExprStmt
# 36| getExpr(): [FunctionCall] call to ExRaiseAccessViolation
# 36| Type = [VoidType] void
# 36| ValueCategory = prvalue
# 36| getArgument(0): [Literal] 0
# 36| Type = [IntType] int
# 36| Value = [Literal] 0
# 36| ValueCategory = prvalue
# 38| getCondition(): [Literal] 1
# 38| Type = [IntType] int
# 38| Value = [Literal] 1
# 38| ValueCategory = prvalue
# 39| getExcept(): [BlockStmt] { ... }
# 40| getStmt(0): [ExprStmt] ExprStmt
# 40| getExpr(): [FunctionCall] call to ExRaiseAccessViolation
# 40| Type = [VoidType] void
# 40| ValueCategory = prvalue
# 40| getArgument(0): [Literal] 1
# 40| Type = [IntType] int
# 40| Value = [Literal] 1
# 40| ValueCategory = prvalue
# 42| getStmt(1): [ReturnStmt] return ...
ir.cpp:
# 1| [TopLevelFunction] void Constants()
# 1| <params>:

View File

@@ -3156,6 +3156,53 @@ ir.c:
# 21| Block 5
# 21| v21_11(void) = Unreached :
# 32| void unexplained_loop_regression()
# 32| Block 0
# 32| v32_1(void) = EnterFunction :
# 32| m32_2(unknown) = AliasedDefinition :
# 32| m32_3(unknown) = InitializeNonLocal :
# 32| m32_4(unknown) = Chi : total:m32_2, partial:m32_3
# 36| r36_1(glval<unknown>) = FunctionAddress[ExRaiseAccessViolation] :
# 36| r36_2(int) = Constant[0] :
# 36| v36_3(void) = Call[ExRaiseAccessViolation] : func:r36_1, 0:r36_2
# 36| m36_4(unknown) = ^CallSideEffect : ~m32_4
# 36| m36_5(unknown) = Chi : total:m32_4, partial:m36_4
#-----| Exception -> Block 3
# 39| Block 1
# 39| r39_1(int) = Constant[0] :
# 39| r39_2(bool) = CompareEQ : r38_2, r39_1
# 39| v39_3(void) = ConditionalBranch : r39_2
#-----| False (back edge) -> Block 2
#-----| True -> Block 5
# 39| Block 2
# 39| r39_4(int) = Constant[1] :
# 39| r39_5(bool) = CompareEQ : r38_2, r39_4
# 39| v39_6(void) = ConditionalBranch : r39_5
#-----| False -> Block 5
#-----| True (back edge) -> Block 4
# 38| Block 3
# 38| m38_1(unknown) = Phi : from 0:~m36_5, from 4:~m40_5
# 38| r38_2(int) = Constant[1] :
# 39| r39_7(int) = Constant[-1] :
# 39| r39_8(bool) = CompareEQ : r38_2, r39_7
# 39| v39_9(void) = ConditionalBranch : r39_8
#-----| False (back edge) -> Block 1
#-----| True -> Block 5
# 40| Block 4
# 40| r40_1(glval<unknown>) = FunctionAddress[ExRaiseAccessViolation] :
# 40| r40_2(int) = Constant[1] :
# 40| v40_3(void) = Call[ExRaiseAccessViolation] : func:r40_1, 0:r40_2
# 40| m40_4(unknown) = ^CallSideEffect : ~m38_1
# 40| m40_5(unknown) = Chi : total:m38_1, partial:m40_4
#-----| Exception (back edge) -> Block 3
# 32| Block 5
# 32| v32_5(void) = Unreached :
ir.cpp:
# 1| void Constants()
# 1| Block 0

View File

@@ -8,6 +8,22 @@ sideEffectWithoutPrimary
instructionWithoutSuccessor
ambiguousSuccessors
unexplainedLoop
| ir.c:38:13:38:37 | Constant: 1 | Instruction 'Constant: 1' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:38:13:38:37 | Phi: 1 | Instruction 'Phi: 1' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | CompareEQ: { ... } | Instruction 'CompareEQ: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | CompareEQ: { ... } | Instruction 'CompareEQ: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | CompareEQ: { ... } | Instruction 'CompareEQ: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | ConditionalBranch: { ... } | Instruction 'ConditionalBranch: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | ConditionalBranch: { ... } | Instruction 'ConditionalBranch: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | ConditionalBranch: { ... } | Instruction 'ConditionalBranch: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | Constant: { ... } | Instruction 'Constant: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | Constant: { ... } | Instruction 'Constant: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | Constant: { ... } | Instruction 'Constant: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | Call: call to ExRaiseAccessViolation | Instruction 'Call: call to ExRaiseAccessViolation' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | CallSideEffect: call to ExRaiseAccessViolation | Instruction 'CallSideEffect: call to ExRaiseAccessViolation' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | Chi: call to ExRaiseAccessViolation | Instruction 'Chi: call to ExRaiseAccessViolation' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | FunctionAddress: call to ExRaiseAccessViolation | Instruction 'FunctionAddress: call to ExRaiseAccessViolation' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:28:40:28 | Constant: 1 | Instruction 'Constant: 1' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
unnecessaryPhiInstruction
memoryOperandDefinitionIsUnmodeled
operandAcrossFunctions
@@ -18,6 +34,9 @@ containsLoopOfForwardEdges
missingIRType
multipleIRTypes
lostReachability
| ir.c:39:3:41:3 | Constant: { ... } | Block 'Constant: { ... }' is not reachable by traversing only forward edges in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | Constant: { ... } | Block 'Constant: { ... }' is not reachable by traversing only forward edges in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | FunctionAddress: call to ExRaiseAccessViolation | Block 'FunctionAddress: call to ExRaiseAccessViolation' is not reachable by traversing only forward edges in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge

View File

@@ -8,6 +8,22 @@ sideEffectWithoutPrimary
instructionWithoutSuccessor
ambiguousSuccessors
unexplainedLoop
| ir.c:38:13:38:37 | Constant: 1 | Instruction 'Constant: 1' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:38:13:38:37 | Phi: 1 | Instruction 'Phi: 1' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | CompareEQ: { ... } | Instruction 'CompareEQ: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | CompareEQ: { ... } | Instruction 'CompareEQ: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | CompareEQ: { ... } | Instruction 'CompareEQ: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | ConditionalBranch: { ... } | Instruction 'ConditionalBranch: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | ConditionalBranch: { ... } | Instruction 'ConditionalBranch: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | ConditionalBranch: { ... } | Instruction 'ConditionalBranch: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | Constant: { ... } | Instruction 'Constant: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | Constant: { ... } | Instruction 'Constant: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | Constant: { ... } | Instruction 'Constant: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | Call: call to ExRaiseAccessViolation | Instruction 'Call: call to ExRaiseAccessViolation' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | CallSideEffect: call to ExRaiseAccessViolation | Instruction 'CallSideEffect: call to ExRaiseAccessViolation' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | Chi: call to ExRaiseAccessViolation | Instruction 'Chi: call to ExRaiseAccessViolation' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | FunctionAddress: call to ExRaiseAccessViolation | Instruction 'FunctionAddress: call to ExRaiseAccessViolation' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:28:40:28 | Constant: 1 | Instruction 'Constant: 1' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
unnecessaryPhiInstruction
memoryOperandDefinitionIsUnmodeled
operandAcrossFunctions
@@ -18,6 +34,9 @@ containsLoopOfForwardEdges
missingIRType
multipleIRTypes
lostReachability
| ir.c:39:3:41:3 | Constant: { ... } | Block 'Constant: { ... }' is not reachable by traversing only forward edges in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | Constant: { ... } | Block 'Constant: { ... }' is not reachable by traversing only forward edges in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | FunctionAddress: call to ExRaiseAccessViolation | Block 'FunctionAddress: call to ExRaiseAccessViolation' is not reachable by traversing only forward edges in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge

View File

@@ -29,4 +29,16 @@ int TryExceptTest(int x) {
return 0;
}
void unexplained_loop_regression()
{
__try
{
ExRaiseAccessViolation(0);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
ExRaiseAccessViolation(1);
}
}
// semmle-extractor-options: --microsoft

View File

@@ -8,6 +8,20 @@ sideEffectWithoutPrimary
instructionWithoutSuccessor
ambiguousSuccessors
unexplainedLoop
| ir.c:38:13:38:37 | Constant: 1 | Instruction 'Constant: 1' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | CompareEQ: { ... } | Instruction 'CompareEQ: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | CompareEQ: { ... } | Instruction 'CompareEQ: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | CompareEQ: { ... } | Instruction 'CompareEQ: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | ConditionalBranch: { ... } | Instruction 'ConditionalBranch: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | ConditionalBranch: { ... } | Instruction 'ConditionalBranch: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | ConditionalBranch: { ... } | Instruction 'ConditionalBranch: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | Constant: { ... } | Instruction 'Constant: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | Constant: { ... } | Instruction 'Constant: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | Constant: { ... } | Instruction 'Constant: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | Call: call to ExRaiseAccessViolation | Instruction 'Call: call to ExRaiseAccessViolation' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | CallSideEffect: call to ExRaiseAccessViolation | Instruction 'CallSideEffect: call to ExRaiseAccessViolation' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | FunctionAddress: call to ExRaiseAccessViolation | Instruction 'FunctionAddress: call to ExRaiseAccessViolation' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:28:40:28 | Constant: 1 | Instruction 'Constant: 1' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
unnecessaryPhiInstruction
memoryOperandDefinitionIsUnmodeled
operandAcrossFunctions
@@ -18,6 +32,10 @@ containsLoopOfForwardEdges
missingIRType
multipleIRTypes
lostReachability
| ir.c:39:3:41:3 | Constant: { ... } | Block 'Constant: { ... }' is not reachable by traversing only forward edges in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | Constant: { ... } | Block 'Constant: { ... }' is not reachable by traversing only forward edges in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | Unwind: { ... } | Block 'Unwind: { ... }' is not reachable by traversing only forward edges in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | FunctionAddress: call to ExRaiseAccessViolation | Block 'FunctionAddress: call to ExRaiseAccessViolation' is not reachable by traversing only forward edges in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
backEdgeCountMismatch
useNotDominatedByDefinition
| ir.cpp:1535:8:1535:8 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1535:8:1535:8 | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() |

View File

@@ -2926,6 +2926,52 @@ ir.c:
# 27| mu27_3(int) = Store[#return] : &:r27_1, r27_2
#-----| Goto -> Block 1
# 32| void unexplained_loop_regression()
# 32| Block 0
# 32| v32_1(void) = EnterFunction :
# 32| mu32_2(unknown) = AliasedDefinition :
# 32| mu32_3(unknown) = InitializeNonLocal :
# 36| r36_1(glval<unknown>) = FunctionAddress[ExRaiseAccessViolation] :
# 36| r36_2(int) = Constant[0] :
# 36| v36_3(void) = Call[ExRaiseAccessViolation] : func:r36_1, 0:r36_2
# 36| mu36_4(unknown) = ^CallSideEffect : ~m?
#-----| Exception -> Block 4
# 39| Block 1
# 39| r39_1(int) = Constant[0] :
# 39| r39_2(bool) = CompareEQ : r38_1, r39_1
# 39| v39_3(void) = ConditionalBranch : r39_2
#-----| False (back edge) -> Block 2
#-----| True (back edge) -> Block 3
# 39| Block 2
# 39| r39_4(int) = Constant[1] :
# 39| r39_5(bool) = CompareEQ : r38_1, r39_4
# 39| v39_6(void) = ConditionalBranch : r39_5
#-----| True (back edge) -> Block 5
# 39| Block 3
# 39| v39_7(void) = Unwind :
# 42| v42_1(void) = NoOp :
# 32| v32_4(void) = ReturnVoid :
# 32| v32_5(void) = AliasedUse : ~m?
# 32| v32_6(void) = ExitFunction :
# 38| Block 4
# 38| r38_1(int) = Constant[1] :
# 39| r39_8(int) = Constant[-1] :
# 39| r39_9(bool) = CompareEQ : r38_1, r39_8
# 39| v39_10(void) = ConditionalBranch : r39_9
#-----| False (back edge) -> Block 1
#-----| True (back edge) -> Block 3
# 40| Block 5
# 40| r40_1(glval<unknown>) = FunctionAddress[ExRaiseAccessViolation] :
# 40| r40_2(int) = Constant[1] :
# 40| v40_3(void) = Call[ExRaiseAccessViolation] : func:r40_1, 0:r40_2
# 40| mu40_4(unknown) = ^CallSideEffect : ~m?
#-----| Exception (back edge) -> Block 4
ir.cpp:
# 1| void Constants()
# 1| Block 0

View File

@@ -8,6 +8,20 @@ sideEffectWithoutPrimary
instructionWithoutSuccessor
ambiguousSuccessors
unexplainedLoop
| ir.c:38:13:38:37 | Constant: 1 | Instruction 'Constant: 1' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | CompareEQ: { ... } | Instruction 'CompareEQ: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | CompareEQ: { ... } | Instruction 'CompareEQ: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | CompareEQ: { ... } | Instruction 'CompareEQ: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | ConditionalBranch: { ... } | Instruction 'ConditionalBranch: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | ConditionalBranch: { ... } | Instruction 'ConditionalBranch: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | ConditionalBranch: { ... } | Instruction 'ConditionalBranch: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | Constant: { ... } | Instruction 'Constant: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | Constant: { ... } | Instruction 'Constant: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | Constant: { ... } | Instruction 'Constant: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | Call: call to ExRaiseAccessViolation | Instruction 'Call: call to ExRaiseAccessViolation' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | CallSideEffect: call to ExRaiseAccessViolation | Instruction 'CallSideEffect: call to ExRaiseAccessViolation' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | FunctionAddress: call to ExRaiseAccessViolation | Instruction 'FunctionAddress: call to ExRaiseAccessViolation' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:28:40:28 | Constant: 1 | Instruction 'Constant: 1' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
unnecessaryPhiInstruction
memoryOperandDefinitionIsUnmodeled
operandAcrossFunctions
@@ -18,6 +32,9 @@ containsLoopOfForwardEdges
missingIRType
multipleIRTypes
lostReachability
| ir.c:39:3:41:3 | Constant: { ... } | Block 'Constant: { ... }' is not reachable by traversing only forward edges in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | Constant: { ... } | Block 'Constant: { ... }' is not reachable by traversing only forward edges in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | FunctionAddress: call to ExRaiseAccessViolation | Block 'FunctionAddress: call to ExRaiseAccessViolation' is not reachable by traversing only forward edges in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge

View File

@@ -8,6 +8,20 @@ sideEffectWithoutPrimary
instructionWithoutSuccessor
ambiguousSuccessors
unexplainedLoop
| ir.c:38:13:38:37 | Constant: 1 | Instruction 'Constant: 1' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | CompareEQ: { ... } | Instruction 'CompareEQ: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | CompareEQ: { ... } | Instruction 'CompareEQ: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | CompareEQ: { ... } | Instruction 'CompareEQ: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | ConditionalBranch: { ... } | Instruction 'ConditionalBranch: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | ConditionalBranch: { ... } | Instruction 'ConditionalBranch: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | ConditionalBranch: { ... } | Instruction 'ConditionalBranch: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | Constant: { ... } | Instruction 'Constant: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | Constant: { ... } | Instruction 'Constant: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | Constant: { ... } | Instruction 'Constant: { ... }' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | Call: call to ExRaiseAccessViolation | Instruction 'Call: call to ExRaiseAccessViolation' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | CallSideEffect: call to ExRaiseAccessViolation | Instruction 'CallSideEffect: call to ExRaiseAccessViolation' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | FunctionAddress: call to ExRaiseAccessViolation | Instruction 'FunctionAddress: call to ExRaiseAccessViolation' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:28:40:28 | Constant: 1 | Instruction 'Constant: 1' is part of an unexplained loop in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
unnecessaryPhiInstruction
memoryOperandDefinitionIsUnmodeled
operandAcrossFunctions
@@ -18,6 +32,9 @@ containsLoopOfForwardEdges
missingIRType
multipleIRTypes
lostReachability
| ir.c:39:3:41:3 | Constant: { ... } | Block 'Constant: { ... }' is not reachable by traversing only forward edges in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:39:3:41:3 | Constant: { ... } | Block 'Constant: { ... }' is not reachable by traversing only forward edges in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
| ir.c:40:5:40:26 | FunctionAddress: call to ExRaiseAccessViolation | Block 'FunctionAddress: call to ExRaiseAccessViolation' is not reachable by traversing only forward edges in function '$@'. | ir.c:32:6:32:32 | void unexplained_loop_regression() | void unexplained_loop_regression() |
backEdgeCountMismatch
useNotDominatedByDefinition
switchInstructionWithoutDefaultEdge

View File

@@ -18,17 +18,35 @@ private class ReturnNodeExt extends DataFlow::Node {
kind = DataFlowImplCommon::getParamReturnPosition(this, _).getKind()
}
string getOutput() {
kind instanceof DataFlowImplCommon::ValueReturnKind and
/**
* Gets the kind of the return node.
*/
DataFlowImplCommon::ReturnKindExt getKind() { result = kind }
}
bindingset[c]
private signature string printCallableParamSig(Callable c, ParameterPosition p);
private module PrintReturnNodeExt<printCallableParamSig/2 printCallableParam> {
string getOutput(ReturnNodeExt node) {
node.getKind() instanceof DataFlowImplCommon::ValueReturnKind and
result = "ReturnValue"
or
exists(ParameterPosition pos |
pos = kind.(DataFlowImplCommon::ParamUpdateReturnKind).getPosition() and
result = paramReturnNodeAsOutput(returnNodeEnclosingCallable(this), pos)
pos = node.getKind().(DataFlowImplCommon::ParamUpdateReturnKind).getPosition() and
result = printCallableParam(returnNodeEnclosingCallable(node), pos)
)
}
}
string getOutput(ReturnNodeExt node) {
result = PrintReturnNodeExt<paramReturnNodeAsOutput/2>::getOutput(node)
}
string getContentOutput(ReturnNodeExt node) {
result = PrintReturnNodeExt<paramReturnNodeAsContentOutput/2>::getOutput(node)
}
class DataFlowSummaryTargetApi extends SummaryTargetApi {
DataFlowSummaryTargetApi() { not isUninterestingForDataFlowModels(this) }
}
@@ -71,7 +89,8 @@ private predicate isRelevantTaintStep(DataFlow::Node node1, DataFlow::Node node2
* Holds if content `c` is either a field, a synthetic field or language specific
* content of a relevant type or a container like content.
*/
private predicate isRelevantContent(DataFlow::ContentSet c) {
pragma[nomagic]
private predicate isRelevantContent0(DataFlow::ContentSet c) {
isRelevantTypeInContent(c) or
containerContent(c)
}
@@ -85,6 +104,16 @@ string parameterNodeAsInput(DataFlow::ParameterNode p) {
result = qualifierString() and p instanceof InstanceParameterNode
}
/**
* Gets the MaD string representation of the parameter `p`
* when used in content flow.
*/
string parameterNodeAsContentInput(DataFlow::ParameterNode p) {
result = parameterContentAccess(p.asParameter())
or
result = qualifierString() and p instanceof InstanceParameterNode
}
/**
* Gets the MaD input string representation of `source`.
*/
@@ -170,7 +199,7 @@ module PropagateFlowConfig implements DataFlow::StateConfigSig {
) {
exists(DataFlow::ContentSet c |
DataFlowImplCommon::store(node1, c.getAStoreContent(), node2, _, _) and
isRelevantContent(c) and
isRelevantContent0(c) and
(
state1 instanceof TaintRead and state2.(TaintStore).getStep() = 1
or
@@ -180,7 +209,7 @@ module PropagateFlowConfig implements DataFlow::StateConfigSig {
or
exists(DataFlow::ContentSet c |
DataFlowPrivate::readStep(node1, c, node2) and
isRelevantContent(c) and
isRelevantContent0(c) and
state1.(TaintRead).getStep() + 1 = state2.(TaintRead).getStep()
)
}
@@ -196,6 +225,9 @@ module PropagateFlowConfig implements DataFlow::StateConfigSig {
module PropagateFlow = TaintTracking::GlobalWithState<PropagateFlowConfig>;
/**
* Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter.
*/
string captureThroughFlow0(
DataFlowSummaryTargetApi api, DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt
) {
@@ -203,7 +235,7 @@ string captureThroughFlow0(
p.getEnclosingCallable() = api and
returnNodeExt.(DataFlow::Node).getEnclosingCallable() = api and
input = parameterNodeAsInput(p) and
output = returnNodeExt.getOutput() and
output = getOutput(returnNodeExt) and
input != output and
result = Printing::asTaintModel(api, input, output)
)
@@ -219,6 +251,69 @@ string captureThroughFlow(DataFlowSummaryTargetApi api) {
)
}
private module PropagateContentFlowConfig implements ContentDataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof DataFlow::ParameterNode and
source.getEnclosingCallable() instanceof DataFlowSummaryTargetApi
}
predicate isSink(DataFlow::Node sink) {
sink instanceof ReturnNodeExt and
sink.getEnclosingCallable() instanceof DataFlowSummaryTargetApi
}
predicate isAdditionalFlowStep = isAdditionalContentFlowStep/2;
predicate isBarrier(DataFlow::Node n) {
exists(Type t | t = n.getType() and not isRelevantType(t))
}
int accessPathLimit() { result = 2 }
predicate isRelevantContent(DataFlow::ContentSet s) { isRelevantContent0(s) }
DataFlow::FlowFeature getAFeature() {
result instanceof DataFlow::FeatureEqualSourceSinkCallContext
}
}
private module PropagateContentFlow = ContentDataFlow::Global<PropagateContentFlowConfig>;
private string getContent(PropagateContentFlow::AccessPath ap, int i) {
exists(ContentSet head, PropagateContentFlow::AccessPath tail |
head = ap.getHead() and
tail = ap.getTail()
|
i = 0 and
result = "." + printContent(head)
or
i > 0 and result = getContent(tail, i - 1)
)
}
private string printStoreAccessPath(PropagateContentFlow::AccessPath ap) {
result = concat(int i | | getContent(ap, i), "" order by i)
}
private string printReadAccessPath(PropagateContentFlow::AccessPath ap) {
result = concat(int i | | getContent(ap, i), "" order by i desc)
}
string captureContentFlow(DataFlowSummaryTargetApi api) {
exists(
DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt, string input, string output,
PropagateContentFlow::AccessPath reads, PropagateContentFlow::AccessPath stores,
boolean preservesValue
|
PropagateContentFlow::flow(p, reads, returnNodeExt, stores, preservesValue) and
returnNodeExt.getEnclosingCallable() = api and
input = parameterNodeAsContentInput(p) + printReadAccessPath(reads) and
output = getContentOutput(returnNodeExt) + printStoreAccessPath(stores) and
input != output and
result = Printing::asModel(api, input, output, preservesValue)
)
}
/**
* A dataflow configuration used for finding new sources.
* The sources are the already known existing sources and the sinks are the API return nodes.
@@ -261,7 +356,7 @@ string captureSource(DataFlowSourceTargetApi api) {
ExternalFlow::sourceNode(source, kind) and
api = sink.getEnclosingCallable() and
not irrelevantSourceSinkApi(source.getEnclosingCallable(), api) and
result = Printing::asSourceModel(api, sink.getOutput(), kind)
result = Printing::asSourceModel(api, getOutput(sink), kind)
)
}

View File

@@ -5,11 +5,14 @@
private import csharp as CS
private import semmle.code.csharp.commons.Util as Util
private import semmle.code.csharp.commons.Collections as Collections
private import semmle.code.csharp.commons.QualifiedName as QualifiedName
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.csharp.frameworks.system.linq.Expressions
private import semmle.code.csharp.frameworks.System
private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate as TaintTrackingPrivate
import semmle.code.csharp.dataflow.internal.ExternalFlow as ExternalFlow
import semmle.code.csharp.dataflow.internal.ContentDataFlow as ContentDataFlow
import semmle.code.csharp.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate
import semmle.code.csharp.dataflow.internal.DataFlowDispatch as DataFlowDispatch
@@ -22,6 +25,8 @@ class Type = CS::Type;
class Callable = CS::Callable;
class ContentSet = DataFlow::ContentSet;
/**
* Holds if any of the parameters of `api` are `System.Func<>`.
*/
@@ -241,20 +246,40 @@ string parameterAccess(CS::Parameter p) {
else result = "Argument[" + p.getPosition() + "]"
}
/**
* Gets the MaD string representation of the parameter `p`
* when used in content flow.
*/
string parameterContentAccess(CS::Parameter p) { result = "Argument[" + p.getPosition() + "]" }
class InstanceParameterNode = DataFlowPrivate::InstanceParameterNode;
class ParameterPosition = DataFlowDispatch::ParameterPosition;
private signature string parameterAccessSig(Parameter p);
module ParamReturnNodeAsOutput<parameterAccessSig/1 getParamAccess> {
bindingset[c]
string paramReturnNodeAsOutput(CS::Callable c, ParameterPosition pos) {
result = getParamAccess(c.getParameter(pos.getPosition()))
or
pos.isThisParameter() and
result = qualifierString()
}
}
/**
* Gets the MaD string representation of return through parameter at position
* `pos` of callable `c`.
*/
bindingset[c]
string paramReturnNodeAsOutput(CS::Callable c, ParameterPosition pos) {
result = parameterAccess(c.getParameter(pos.getPosition()))
or
pos.isThisParameter() and
result = qualifierString()
result = ParamReturnNodeAsOutput<parameterAccess/1>::paramReturnNodeAsOutput(c, pos)
}
bindingset[c]
string paramReturnNodeAsContentOutput(Callable c, ParameterPosition pos) {
result = ParamReturnNodeAsOutput<parameterContentAccess/1>::paramReturnNodeAsOutput(c, pos)
}
/**
@@ -344,3 +369,44 @@ predicate isRelevantSourceKind(string kind) { any() }
* Holds if the the content `c` is a container.
*/
predicate containerContent(DataFlow::ContentSet c) { c.isElement() }
/**
* Holds if there is a taint step from `node1` to `node2` in content flow.
*/
predicate isAdditionalContentFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
TaintTrackingPrivate::defaultAdditionalTaintStep(nodeFrom, nodeTo, _) and
not nodeTo.asExpr() instanceof CS::ElementAccess and
not exists(DataFlow::ContentSet c |
DataFlowPrivate::readStep(nodeFrom, c, nodeTo) and containerContent(c)
)
}
bindingset[d]
private string getFullyQualifiedName(Declaration d) {
exists(string qualifier, string name |
d.hasFullyQualifiedName(qualifier, name) and
result = QualifiedName::getQualifiedName(qualifier, name)
)
}
/**
* Gets the MaD string representation of the contentset `c`.
*/
string printContent(DataFlow::ContentSet c) {
exists(CS::Field f, string name | name = getFullyQualifiedName(f) |
c.isField(f) and
if f.isEffectivelyPublic()
then result = "Field[" + name + "]"
else result = "SyntheticField[" + name + "]"
)
or
exists(CS::Property p, string name | name = getFullyQualifiedName(p) |
c.isProperty(p) and
if p.isEffectivelyPublic()
then result = "Property[" + name + "]"
else result = "SyntheticField[" + name + "]"
)
or
c.isElement() and
result = "Element"
}

View File

@@ -0,0 +1,2 @@
unexpectedModel
expectedModel

View File

@@ -0,0 +1,12 @@
extensions:
- addsTo:
pack: codeql/csharp-all
extensible: summaryModel
data:
- [ "Models", "ManuallyModelled", False, "HasSummary", "(System.Object)", "", "Argument[0]", "ReturnValue", "value", "manual"]
- addsTo:
pack: codeql/csharp-all
extensible: neutralModel
data:
- [ "Models", "ManuallyModelled", "HasNeutralSummary", "(System.Object)", "summary", "manual"]

View File

@@ -0,0 +1,11 @@
import csharp
import utils.modelgenerator.internal.CaptureModels
import TestUtilities.InlineMadTest
module InlineMadTestConfig implements InlineMadTestConfigSig {
string getCapturedModel(Callable c) { result = captureContentFlow(c) }
string getKind() { result = "contentbased-summary" }
}
import InlineMadTest<InlineMadTestConfig>

View File

@@ -13,18 +13,21 @@ public class BasicFlow
private string tainted;
// summary=Models;BasicFlow;false;ReturnThis;(System.Object);;Argument[this];ReturnValue;value;df-generated
// contentbased-summary=Models;BasicFlow;false;ReturnThis;(System.Object);;Argument[this];ReturnValue;value;df-generated
public BasicFlow ReturnThis(object input)
{
return this;
}
// summary=Models;BasicFlow;false;ReturnParam0;(System.String,System.Object);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;BasicFlow;false;ReturnParam0;(System.String,System.Object);;Argument[0];ReturnValue;value;df-generated
public string ReturnParam0(string input0, object input1)
{
return input0;
}
// summary=Models;BasicFlow;false;ReturnParam1;(System.String,System.Object);;Argument[1];ReturnValue;taint;df-generated
// contentbased-summary=Models;BasicFlow;false;ReturnParam1;(System.String,System.Object);;Argument[1];ReturnValue;value;df-generated
public object ReturnParam1(string input0, object input1)
{
return input1;
@@ -32,24 +35,29 @@ public class BasicFlow
// summary=Models;BasicFlow;false;ReturnParamMultiple;(System.Object,System.Object);;Argument[0];ReturnValue;taint;df-generated
// summary=Models;BasicFlow;false;ReturnParamMultiple;(System.Object,System.Object);;Argument[1];ReturnValue;taint;df-generated
// contentbased-summary=Models;BasicFlow;false;ReturnParamMultiple;(System.Object,System.Object);;Argument[0];ReturnValue;value;df-generated
// contentbased-summary=Models;BasicFlow;false;ReturnParamMultiple;(System.Object,System.Object);;Argument[1];ReturnValue;value;df-generated
public object ReturnParamMultiple(object input0, object input1)
{
return (System.DateTime.Now.DayOfWeek == System.DayOfWeek.Monday) ? input0 : input1;
}
// summary=Models;BasicFlow;false;ReturnSubstring;(System.String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;BasicFlow;false;ReturnSubstring;(System.String);;Argument[0];ReturnValue;taint;df-generated
public string ReturnSubstring(string s)
{
return s.Substring(0, 1);
}
// summary=Models;BasicFlow;false;SetField;(System.String);;Argument[0];Argument[this];taint;df-generated
// contentbased-summary=Models;BasicFlow;false;SetField;(System.String);;Argument[0];Argument[this].SyntheticField[Models.BasicFlow.tainted];value;df-generated
public void SetField(string s)
{
tainted = s;
}
// summary=Models;BasicFlow;false;ReturnField;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=Models;BasicFlow;false;ReturnField;();;Argument[this].SyntheticField[Models.BasicFlow.tainted];ReturnValue;value;df-generated
public string ReturnField()
{
return tainted;
@@ -61,72 +69,84 @@ public class CollectionFlow
private string tainted;
// summary=Models;CollectionFlow;false;ReturnArrayElement;(System.Object[]);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;ReturnArrayElement;(System.Object[]);;Argument[0].Element;ReturnValue;value;df-generated
public object ReturnArrayElement(object[] input)
{
return input[0];
}
// summary=Models;CollectionFlow;false;AssignToArray;(System.Object,System.Object[]);;Argument[0];Argument[1].Element;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;AssignToArray;(System.Object,System.Object[]);;Argument[0];Argument[1].Element;value;df-generated
public void AssignToArray(object data, object[] target)
{
target[0] = data;
}
// summary=Models;CollectionFlow;false;AssignFieldToArray;(System.Object[]);;Argument[this];Argument[0].Element;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;AssignFieldToArray;(System.Object[]);;Argument[this].SyntheticField[Models.CollectionFlow.tainted];Argument[0].Element;value;df-generated
public void AssignFieldToArray(object[] target)
{
target[0] = tainted;
}
// summary=Models;CollectionFlow;false;ReturnListElement;(System.Collections.Generic.List<System.Object>);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;ReturnListElement;(System.Collections.Generic.List<System.Object>);;Argument[0].Element;ReturnValue;value;df-generated
public object ReturnListElement(List<object> input)
{
return input[0];
}
// summary=Models;CollectionFlow;false;AddToList;(System.Collections.Generic.List<System.Object>,System.Object);;Argument[1];Argument[0].Element;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;AddToList;(System.Collections.Generic.List<System.Object>,System.Object);;Argument[1];Argument[0].Element;value;df-generated
public void AddToList(List<object> input, object data)
{
input.Add(data);
}
// summary=Models;CollectionFlow;false;AddFieldToList;(System.Collections.Generic.List<System.String>);;Argument[this];Argument[0].Element;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;AddFieldToList;(System.Collections.Generic.List<System.String>);;Argument[this].SyntheticField[Models.CollectionFlow.tainted];Argument[0].Element;value;df-generated
public void AddFieldToList(List<string> input)
{
input.Add(tainted);
}
// summary=Models;CollectionFlow;false;ReturnFieldInAList;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;ReturnFieldInAList;();;Argument[this].SyntheticField[Models.CollectionFlow.tainted];ReturnValue.Element;value;df-generated
public List<string> ReturnFieldInAList()
{
return new List<string> { tainted };
}
// summary=Models;CollectionFlow;false;ReturnComplexTypeArray;(System.String[]);;Argument[0].Element;ReturnValue;taint;df-generated
// SPURIOUS-summary=Models;CollectionFlow;false;ReturnComplexTypeArray;(System.String[]);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;ReturnComplexTypeArray;(System.String[]);;Argument[0];ReturnValue;value;df-generated
public string[] ReturnComplexTypeArray(string[] a)
{
return a;
}
// summary=Models;CollectionFlow;false;ReturnBulkTypeList;(System.Collections.Generic.List<System.Byte>);;Argument[0].Element;ReturnValue;taint;df-generated
// SPURIOUS-summary=Models;CollectionFlow;false;ReturnBulkTypeList;(System.Collections.Generic.List<System.Byte>);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;ReturnBulkTypeList;(System.Collections.Generic.List<System.Byte>);;Argument[0];ReturnValue;value;df-generated
public List<byte> ReturnBulkTypeList(List<byte> a)
{
return a;
}
// summary=Models;CollectionFlow;false;ReturnComplexTypeDictionary;(System.Collections.Generic.Dictionary<System.Int32,System.String>);;Argument[0].Element;ReturnValue;taint;df-generated
// SPURIOUS-summary=Models;CollectionFlow;false;ReturnComplexTypeDictionary;(System.Collections.Generic.Dictionary<System.Int32,System.String>);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;ReturnComplexTypeDictionary;(System.Collections.Generic.Dictionary<System.Int32,System.String>);;Argument[0];ReturnValue;value;df-generated
public Dictionary<int, string> ReturnComplexTypeDictionary(Dictionary<int, string> a)
{
return a;
}
// summary=Models;CollectionFlow;false;ReturnUntypedArray;(System.Array);;Argument[0].Element;ReturnValue;taint;df-generated
// SPURIOUS-summary=Models;CollectionFlow;false;ReturnUntypedArray;(System.Array);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;ReturnUntypedArray;(System.Array);;Argument[0];ReturnValue;value;df-generated
public Array ReturnUntypedArray(Array a)
{
return a;
}
// summary=Models;CollectionFlow;false;ReturnUntypedList;(System.Collections.IList);;Argument[0].Element;ReturnValue;taint;df-generated
// SPURIOUS-summary=Models;CollectionFlow;false;ReturnUntypedList;(System.Collections.IList);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;CollectionFlow;false;ReturnUntypedList;(System.Collections.IList);;Argument[0];ReturnValue;value;df-generated
public IList ReturnUntypedList(IList a)
{
return a;
@@ -159,19 +179,22 @@ public class IEnumerableFlow
{
private string tainted;
// summary=Models;IEnumerableFlow;false;ReturnIEnumerable;(System.Collections.Generic.IEnumerable<System.String>);;Argument[0].Element;ReturnValue;taint;df-generated
// SPURIOUS-summary=Models;IEnumerableFlow;false;ReturnIEnumerable;(System.Collections.Generic.IEnumerable<System.String>);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;IEnumerableFlow;false;ReturnIEnumerable;(System.Collections.Generic.IEnumerable<System.String>);;Argument[0];ReturnValue;value;df-generated
public IEnumerable<string> ReturnIEnumerable(IEnumerable<string> input)
{
return input;
}
// summary=Models;IEnumerableFlow;false;ReturnIEnumerableElement;(System.Collections.Generic.IEnumerable<System.Object>);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;IEnumerableFlow;false;ReturnIEnumerableElement;(System.Collections.Generic.IEnumerable<System.Object>);;Argument[0].Element;ReturnValue;value;df-generated
public object ReturnIEnumerableElement(IEnumerable<object> input)
{
return input.First();
}
// summary=Models;IEnumerableFlow;false;ReturnFieldInIEnumerable;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=Models;IEnumerableFlow;false;ReturnFieldInIEnumerable;();;Argument[this].SyntheticField[Models.IEnumerableFlow.tainted];ReturnValue.Element;value;df-generated
public IEnumerable<string> ReturnFieldInIEnumerable()
{
return new List<string> { tainted };
@@ -183,42 +206,49 @@ public class GenericFlow<T>
private T tainted;
// summary=Models;GenericFlow<T>;false;SetGenericField;(T);;Argument[0];Argument[this];taint;df-generated
// contentbased-summary=Models;GenericFlow<T>;false;SetGenericField;(T);;Argument[0];Argument[this].SyntheticField[Models.GenericFlow`1.tainted];value;df-generated
public void SetGenericField(T t)
{
tainted = t;
}
// summary=Models;GenericFlow<T>;false;ReturnGenericField;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=Models;GenericFlow<T>;false;ReturnGenericField;();;Argument[this].SyntheticField[Models.GenericFlow`1.tainted];ReturnValue;value;df-generated
public T ReturnGenericField()
{
return tainted;
}
// summary=Models;GenericFlow<T>;false;AddFieldToGenericList;(System.Collections.Generic.List<T>);;Argument[this];Argument[0].Element;taint;df-generated
// contentbased-summary=Models;GenericFlow<T>;false;AddFieldToGenericList;(System.Collections.Generic.List<T>);;Argument[this].SyntheticField[Models.GenericFlow`1.tainted];Argument[0].Element;value;df-generated
public void AddFieldToGenericList(List<T> input)
{
input.Add(tainted);
}
// summary=Models;GenericFlow<T>;false;ReturnFieldInGenericList;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=Models;GenericFlow<T>;false;ReturnFieldInGenericList;();;Argument[this].SyntheticField[Models.GenericFlow`1.tainted];ReturnValue.Element;value;df-generated
public List<T> ReturnFieldInGenericList()
{
return new List<T> { tainted };
}
// summary=Models;GenericFlow<T>;false;ReturnGenericParam<S>;(S);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;GenericFlow<T>;false;ReturnGenericParam<S>;(S);;Argument[0];ReturnValue;value;df-generated
public S ReturnGenericParam<S>(S input)
{
return input;
}
// summary=Models;GenericFlow<T>;false;ReturnGenericElement<S>;(System.Collections.Generic.List<S>);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;GenericFlow<T>;false;ReturnGenericElement<S>;(System.Collections.Generic.List<S>);;Argument[0].Element;ReturnValue;value;df-generated
public S ReturnGenericElement<S>(List<S> input)
{
return input[0];
}
// summary=Models;GenericFlow<T>;false;AddToGenericList<S>;(System.Collections.Generic.List<S>,S);;Argument[1];Argument[0].Element;taint;df-generated
// contentbased-summary=Models;GenericFlow<T>;false;AddToGenericList<S>;(System.Collections.Generic.List<S>,S);;Argument[1];Argument[0].Element;value;df-generated
public void AddToGenericList<S>(List<S> input, S data)
{
input.Add(data);
@@ -228,6 +258,7 @@ public class GenericFlow<T>
public abstract class BaseClassFlow
{
// summary=Models;BaseClassFlow;true;ReturnParam;(System.Object);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;BaseClassFlow;true;ReturnParam;(System.Object);;Argument[0];ReturnValue;value;df-generated
public virtual object ReturnParam(object input)
{
return input;
@@ -237,6 +268,7 @@ public abstract class BaseClassFlow
public class DerivedClass1Flow : BaseClassFlow
{
// summary=Models;DerivedClass1Flow;false;ReturnParam1;(System.String,System.String);;Argument[1];ReturnValue;taint;df-generated
// contentbased-summary=Models;DerivedClass1Flow;false;ReturnParam1;(System.String,System.String);;Argument[1];ReturnValue;value;df-generated
public string ReturnParam1(string input0, string input1)
{
return input1;
@@ -246,12 +278,14 @@ public class DerivedClass1Flow : BaseClassFlow
public class DerivedClass2Flow : BaseClassFlow
{
// summary=Models;BaseClassFlow;true;ReturnParam;(System.Object);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;BaseClassFlow;true;ReturnParam;(System.Object);;Argument[0];ReturnValue;value;df-generated
public override object ReturnParam(object input)
{
return input;
}
// summary=Models;DerivedClass2Flow;false;ReturnParam0;(System.String,System.Int32);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;DerivedClass2Flow;false;ReturnParam0;(System.String,System.Int32);;Argument[0];ReturnValue;value;df-generated
public string ReturnParam0(string input0, int input1)
{
return input0;
@@ -263,6 +297,7 @@ public class OperatorFlow
public readonly object Field;
// summary=Models;OperatorFlow;false;OperatorFlow;(System.Object);;Argument[0];Argument[this];taint;df-generated
// contentbased-summary=Models;OperatorFlow;false;OperatorFlow;(System.Object);;Argument[0];Argument[this].Field[Models.OperatorFlow.Field];value;df-generated
public OperatorFlow(object o)
{
Field = o;
@@ -270,6 +305,7 @@ public class OperatorFlow
// Flow Summary.
// summary=Models;OperatorFlow;false;op_Addition;(Models.OperatorFlow,Models.OperatorFlow);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;OperatorFlow;false;op_Addition;(Models.OperatorFlow,Models.OperatorFlow);;Argument[0];ReturnValue;value;df-generated
public static OperatorFlow operator +(OperatorFlow a, OperatorFlow b)
{
return a;
@@ -310,6 +346,7 @@ public class EqualsGetHashCodeNoFlow
}
// summary=Models;EqualsGetHashCodeNoFlow;false;Equals;(System.String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;EqualsGetHashCodeNoFlow;false;Equals;(System.String);;Argument[0];ReturnValue;value;df-generated
public string Equals(string s)
{
return s;
@@ -327,12 +364,14 @@ public class Properties
private string tainted;
// summary=Models;Properties;false;get_Prop1;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=Models;Properties;false;get_Prop1;();;Argument[this].SyntheticField[Models.Properties.tainted];ReturnValue;value;df-generated
public string Prop1
{
get { return tainted; }
}
// summary=Models;Properties;false;set_Prop2;(System.String);;Argument[0];Argument[this];taint;df-generated
// contentbased-summary=Models;Properties;false;set_Prop2;(System.String);;Argument[0];Argument[this].SyntheticField[Models.Properties.tainted];value;df-generated
public string Prop2
{
set { tainted = value; }
@@ -513,6 +552,7 @@ public class Inheritance
public class AImplBasePublic : BasePublic
{
// summary=Models;Inheritance+BasePublic;true;Id;(System.String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;Inheritance+BasePublic;true;Id;(System.String);;Argument[0];ReturnValue;value;df-generated
public override string Id(string x)
{
return x;
@@ -542,6 +582,7 @@ public class Inheritance
public class BImpl : B
{
// summary=Models;Inheritance+IPublic1;true;Id;(System.String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;Inheritance+IPublic1;true;Id;(System.String);;Argument[0];ReturnValue;value;df-generated
public override string Id(string x)
{
return x;
@@ -551,6 +592,7 @@ public class Inheritance
private class CImpl : C
{
// summary=Models;Inheritance+IPublic2;true;Id;(System.String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;Inheritance+IPublic2;true;Id;(System.String);;Argument[0];ReturnValue;value;df-generated
public override string Id(string x)
{
return x;
@@ -572,6 +614,7 @@ public class Inheritance
private string tainted;
// summary=Models;Inheritance+IPublic3;true;get_Prop;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=Models;Inheritance+IPublic3;true;get_Prop;();;Argument[this].SyntheticField[Models.Inheritance+DImpl.tainted];ReturnValue;value;df-generated
public override string Prop { get { return tainted; } }
}
}
@@ -586,14 +629,54 @@ public class MemberFlow
}
// summary=Models;MemberFlow;false;M1;(Models.MemberFlow+C);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;MemberFlow;false;M1;(Models.MemberFlow+C);;Argument[0].Property[Models.MemberFlow+C.Prop];ReturnValue;value;df-generated
public string M1(C c)
{
return c.Prop;
}
// summary=Models;MemberFlow;false;M2;(Models.MemberFlow+C);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=Models;MemberFlow;false;M2;(Models.MemberFlow+C);;Argument[0].Field[Models.MemberFlow+C.Field];ReturnValue;value;df-generated
public string M2(C c)
{
return c.Field;
}
}
public class IDictionaryFlow
{
// summary=Models;IDictionaryFlow;false;ReturnIDictionaryValue;(System.Collections.Generic.IDictionary<System.Object,System.Object>,System.Object);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=Models;IDictionaryFlow;false;ReturnIDictionaryValue;(System.Collections.Generic.IDictionary<System.Object,System.Object>,System.Object);;Argument[0].Element.Property[System.Collections.Generic.KeyValuePair`2.Value];ReturnValue;value;df-generated
public object ReturnIDictionaryValue(IDictionary<object, object> input, object key)
{
return input[key];
}
}
public class NestedFieldFlow
{
public NestedFieldFlow FieldA;
public NestedFieldFlow FieldB;
// summary=Models;NestedFieldFlow;false;Move;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=Models;NestedFieldFlow;false;Move;();;Argument[this].Field[Models.NestedFieldFlow.FieldA];ReturnValue.Field[Models.NestedFieldFlow.FieldB];value;df-generated
public NestedFieldFlow Move()
{
return new NestedFieldFlow() { FieldB = this.FieldA };
}
// summary=Models;NestedFieldFlow;false;MoveNested;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=Models;NestedFieldFlow;false;MoveNested;();;Argument[this].Field[Models.NestedFieldFlow.FieldB].Field[Models.NestedFieldFlow.FieldA];ReturnValue.Field[Models.NestedFieldFlow.FieldA].Field[Models.NestedFieldFlow.FieldB];value;df-generated
public NestedFieldFlow MoveNested()
{
return new NestedFieldFlow() { FieldA = FieldB.Move() };
}
// summary=Models;NestedFieldFlow;false;ReverseFields;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=Models;NestedFieldFlow;false;ReverseFields;();;Argument[this].Field[Models.NestedFieldFlow.FieldA].Field[Models.NestedFieldFlow.FieldB];ReturnValue.Field[Models.NestedFieldFlow.FieldA].Field[Models.NestedFieldFlow.FieldB];value;df-generated
public NestedFieldFlow ReverseFields()
{
var x = new NestedFieldFlow() { FieldB = this.FieldA.FieldB };
return new NestedFieldFlow() { FieldA = x };
}
}

View File

@@ -7,7 +7,7 @@ go 1.22.0
// when adding or removing dependencies, run
// bazel mod tidy
require (
golang.org/x/mod v0.20.0
golang.org/x/mod v0.21.0
golang.org/x/tools v0.24.0
)

View File

@@ -1,5 +1,5 @@
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=

View File

@@ -649,18 +649,28 @@ class ReceiverDecl extends FieldBase, Documentable, ExprParent {
* Examples:
*
* ```go
* int
* string
* error
* r io.Reader
* output string
* err error
* x, y int
* ```
*
* as in the following code:
*
* ```go
* func f(error) { return nil }
* func g(r io.Reader) { return nil }
* func h(x, y int) { return }
* func f1() int { return 0 }
* func f2(input string) (string, error) { return "", nil }
* func f3(a int) (r io.Reader) { return nil }
* func f4(input string) (output string, err error) { return}
* func f5(e error) (x, y int) { return }
* ```
*
* Note: `x, y int` is a single `ResultVariableDecl` even though it declares
* two different result variables. Use the member predicate `getTypeExpr()` to
* get `int`, `getNameExpr(0)` to get `x` and `getNameExpr(1)` to get `y`.
*/
class ResultVariableDecl extends ParameterOrResultDecl {
ResultVariableDecl() { rawIndex < 0 }

View File

@@ -0,0 +1,7 @@
private import java
private import DataFlowImplSpecific
private import codeql.dataflow.internal.ContentDataFlowImpl
module ContentDataFlow {
import MakeImplContentDataFlow<Location, JavaDataFlow>
}

View File

@@ -0,0 +1,13 @@
/**
* @name Capture content based summary models.
* @description Finds applicable content based summary models to be used by other queries.
* @kind diagnostic
* @id java/utils/modelgenerator/contentbased-summary-models
* @tags modelgenerator
*/
import internal.CaptureModels
from DataFlowSummaryTargetApi api, string flow
where flow = captureContentFlow(api)
select flow order by flow

View File

@@ -18,17 +18,35 @@ private class ReturnNodeExt extends DataFlow::Node {
kind = DataFlowImplCommon::getParamReturnPosition(this, _).getKind()
}
string getOutput() {
kind instanceof DataFlowImplCommon::ValueReturnKind and
/**
* Gets the kind of the return node.
*/
DataFlowImplCommon::ReturnKindExt getKind() { result = kind }
}
bindingset[c]
private signature string printCallableParamSig(Callable c, ParameterPosition p);
private module PrintReturnNodeExt<printCallableParamSig/2 printCallableParam> {
string getOutput(ReturnNodeExt node) {
node.getKind() instanceof DataFlowImplCommon::ValueReturnKind and
result = "ReturnValue"
or
exists(ParameterPosition pos |
pos = kind.(DataFlowImplCommon::ParamUpdateReturnKind).getPosition() and
result = paramReturnNodeAsOutput(returnNodeEnclosingCallable(this), pos)
pos = node.getKind().(DataFlowImplCommon::ParamUpdateReturnKind).getPosition() and
result = printCallableParam(returnNodeEnclosingCallable(node), pos)
)
}
}
string getOutput(ReturnNodeExt node) {
result = PrintReturnNodeExt<paramReturnNodeAsOutput/2>::getOutput(node)
}
string getContentOutput(ReturnNodeExt node) {
result = PrintReturnNodeExt<paramReturnNodeAsContentOutput/2>::getOutput(node)
}
class DataFlowSummaryTargetApi extends SummaryTargetApi {
DataFlowSummaryTargetApi() { not isUninterestingForDataFlowModels(this) }
}
@@ -71,7 +89,8 @@ private predicate isRelevantTaintStep(DataFlow::Node node1, DataFlow::Node node2
* Holds if content `c` is either a field, a synthetic field or language specific
* content of a relevant type or a container like content.
*/
private predicate isRelevantContent(DataFlow::ContentSet c) {
pragma[nomagic]
private predicate isRelevantContent0(DataFlow::ContentSet c) {
isRelevantTypeInContent(c) or
containerContent(c)
}
@@ -85,6 +104,16 @@ string parameterNodeAsInput(DataFlow::ParameterNode p) {
result = qualifierString() and p instanceof InstanceParameterNode
}
/**
* Gets the MaD string representation of the parameter `p`
* when used in content flow.
*/
string parameterNodeAsContentInput(DataFlow::ParameterNode p) {
result = parameterContentAccess(p.asParameter())
or
result = qualifierString() and p instanceof InstanceParameterNode
}
/**
* Gets the MaD input string representation of `source`.
*/
@@ -170,7 +199,7 @@ module PropagateFlowConfig implements DataFlow::StateConfigSig {
) {
exists(DataFlow::ContentSet c |
DataFlowImplCommon::store(node1, c.getAStoreContent(), node2, _, _) and
isRelevantContent(c) and
isRelevantContent0(c) and
(
state1 instanceof TaintRead and state2.(TaintStore).getStep() = 1
or
@@ -180,7 +209,7 @@ module PropagateFlowConfig implements DataFlow::StateConfigSig {
or
exists(DataFlow::ContentSet c |
DataFlowPrivate::readStep(node1, c, node2) and
isRelevantContent(c) and
isRelevantContent0(c) and
state1.(TaintRead).getStep() + 1 = state2.(TaintRead).getStep()
)
}
@@ -196,6 +225,9 @@ module PropagateFlowConfig implements DataFlow::StateConfigSig {
module PropagateFlow = TaintTracking::GlobalWithState<PropagateFlowConfig>;
/**
* Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter.
*/
string captureThroughFlow0(
DataFlowSummaryTargetApi api, DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt
) {
@@ -203,7 +235,7 @@ string captureThroughFlow0(
p.getEnclosingCallable() = api and
returnNodeExt.(DataFlow::Node).getEnclosingCallable() = api and
input = parameterNodeAsInput(p) and
output = returnNodeExt.getOutput() and
output = getOutput(returnNodeExt) and
input != output and
result = Printing::asTaintModel(api, input, output)
)
@@ -219,6 +251,69 @@ string captureThroughFlow(DataFlowSummaryTargetApi api) {
)
}
private module PropagateContentFlowConfig implements ContentDataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof DataFlow::ParameterNode and
source.getEnclosingCallable() instanceof DataFlowSummaryTargetApi
}
predicate isSink(DataFlow::Node sink) {
sink instanceof ReturnNodeExt and
sink.getEnclosingCallable() instanceof DataFlowSummaryTargetApi
}
predicate isAdditionalFlowStep = isAdditionalContentFlowStep/2;
predicate isBarrier(DataFlow::Node n) {
exists(Type t | t = n.getType() and not isRelevantType(t))
}
int accessPathLimit() { result = 2 }
predicate isRelevantContent(DataFlow::ContentSet s) { isRelevantContent0(s) }
DataFlow::FlowFeature getAFeature() {
result instanceof DataFlow::FeatureEqualSourceSinkCallContext
}
}
private module PropagateContentFlow = ContentDataFlow::Global<PropagateContentFlowConfig>;
private string getContent(PropagateContentFlow::AccessPath ap, int i) {
exists(ContentSet head, PropagateContentFlow::AccessPath tail |
head = ap.getHead() and
tail = ap.getTail()
|
i = 0 and
result = "." + printContent(head)
or
i > 0 and result = getContent(tail, i - 1)
)
}
private string printStoreAccessPath(PropagateContentFlow::AccessPath ap) {
result = concat(int i | | getContent(ap, i), "" order by i)
}
private string printReadAccessPath(PropagateContentFlow::AccessPath ap) {
result = concat(int i | | getContent(ap, i), "" order by i desc)
}
string captureContentFlow(DataFlowSummaryTargetApi api) {
exists(
DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt, string input, string output,
PropagateContentFlow::AccessPath reads, PropagateContentFlow::AccessPath stores,
boolean preservesValue
|
PropagateContentFlow::flow(p, reads, returnNodeExt, stores, preservesValue) and
returnNodeExt.getEnclosingCallable() = api and
input = parameterNodeAsContentInput(p) + printReadAccessPath(reads) and
output = getContentOutput(returnNodeExt) + printStoreAccessPath(stores) and
input != output and
result = Printing::asModel(api, input, output, preservesValue)
)
}
/**
* A dataflow configuration used for finding new sources.
* The sources are the already known existing sources and the sinks are the API return nodes.
@@ -261,7 +356,7 @@ string captureSource(DataFlowSourceTargetApi api) {
ExternalFlow::sourceNode(source, kind) and
api = sink.getEnclosingCallable() and
not irrelevantSourceSinkApi(source.getEnclosingCallable(), api) and
result = Printing::asSourceModel(api, sink.getOutput(), kind)
result = Printing::asSourceModel(api, getOutput(sink), kind)
)
}

View File

@@ -4,10 +4,12 @@
private import java as J
private import semmle.code.java.dataflow.internal.DataFlowPrivate
private import semmle.code.java.dataflow.internal.DataFlowUtil as DataFlowUtil
private import semmle.code.java.dataflow.internal.ContainerFlow as ContainerFlow
private import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.java.dataflow.internal.ModelExclusions
private import semmle.code.java.dataflow.DataFlow as Df
private import semmle.code.java.dataflow.internal.ContentDataFlow as Cdf
private import semmle.code.java.dataflow.SSA as Ssa
private import semmle.code.java.dataflow.TaintTracking as Tt
import semmle.code.java.dataflow.ExternalFlow as ExternalFlow
@@ -17,6 +19,8 @@ import semmle.code.java.dataflow.internal.DataFlowDispatch as DataFlowDispatch
module DataFlow = Df::DataFlow;
module ContentDataFlow = Cdf::ContentDataFlow;
module TaintTracking = Tt::TaintTracking;
class Type = J::Type;
@@ -25,6 +29,8 @@ class Unit = J::Unit;
class Callable = J::Callable;
class ContentSet = DataFlowUtil::ContentSet;
private predicate isInfrequentlyUsed(J::CompilationUnit cu) {
cu.getPackage().getName().matches("javax.swing%") or
cu.getPackage().getName().matches("java.awt%")
@@ -217,6 +223,12 @@ string parameterAccess(J::Parameter p) {
else result = "Argument[" + p.getPosition() + "]"
}
/**
* Gets the MaD string representation of the parameter `p`
* when used in content flow.
*/
string parameterContentAccess(J::Parameter p) { result = "Argument[" + p.getPosition() + "]" }
class InstanceParameterNode = DataFlow::InstanceParameterNode;
class ParameterPosition = DataFlowDispatch::ParameterPosition;
@@ -232,6 +244,17 @@ string paramReturnNodeAsOutput(Callable c, ParameterPosition pos) {
result = qualifierString() and pos = -1
}
/**
* Gets the MaD string representation of return through parameter at position
* `pos` of callable `c` for content flow.
*/
bindingset[c]
string paramReturnNodeAsContentOutput(Callable c, ParameterPosition pos) {
result = parameterContentAccess(c.getParameter(pos))
or
result = qualifierString() and pos = -1
}
/**
* Gets the enclosing callable of `ret`.
*/
@@ -305,3 +328,34 @@ bindingset[kind]
predicate isRelevantSourceKind(string kind) { any() }
predicate containerContent = DataFlowPrivate::containerContent/1;
/**
* Holds if there is a taint step from `node1` to `node2` in content flow.
*/
predicate isAdditionalContentFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
TaintTracking::defaultAdditionalTaintStep(node1, node2, _) and
not exists(DataFlow::Content f |
DataFlowPrivate::readStep(node1, f, node2) and containerContent(f)
)
}
/**
* Gets the MaD string representation of the contentset `c`.
*/
string printContent(ContentSet c) {
exists(Field f, string name |
f = c.(DataFlowUtil::FieldContent).getField() and name = f.getQualifiedName()
|
if f.isPublic() then result = "Field[" + name + "]" else result = "SyntheticField[" + name + "]"
)
or
result = "SyntheticField[" + c.(DataFlowUtil::SyntheticFieldContent).getField() + "]"
or
c instanceof DataFlowUtil::CollectionContent and result = "Element"
or
c instanceof DataFlowUtil::ArrayContent and result = "ArrayElement"
or
c instanceof DataFlowUtil::MapValueContent and result = "MapValue"
or
c instanceof DataFlowUtil::MapKeyContent and result = "MapKey"
}

View File

@@ -0,0 +1,2 @@
unexpectedModel
expectedModel

View File

@@ -0,0 +1,11 @@
import java
import utils.modelgenerator.internal.CaptureModels
import TestUtilities.InlineMadTest
module InlineMadTestConfig implements InlineMadTestConfigSig {
string getCapturedModel(Callable c) { result = captureContentFlow(c) }
string getKind() { result = "contentbased-summary" }
}
import InlineMadTest<InlineMadTestConfig>

View File

@@ -2,16 +2,18 @@ package p;
public final class Factory {
private String value;
public String value;
private int intValue;
// summary=p;Factory;false;create;(String,int);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;Factory;false;create;(String,int);;Argument[0];ReturnValue.Field[p.Factory.value];value;df-generated
public static Factory create(String value, int foo) {
return new Factory(value, foo);
}
// summary=p;Factory;false;create;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;Factory;false;create;(String);;Argument[0];ReturnValue.Field[p.Factory.value];value;df-generated
public static Factory create(String value) {
return new Factory(value, 0);
}
@@ -22,6 +24,7 @@ public final class Factory {
}
// summary=p;Factory;false;getValue;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=p;Factory;false;getValue;();;Argument[this].Field[p.Factory.value];ReturnValue;value;df-generated
public String getValue() {
return value;
}

View File

@@ -5,6 +5,7 @@ public final class FinalClass {
private static final String C = "constant";
// summary=p;FinalClass;false;returnsInput;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;FinalClass;false;returnsInput;(String);;Argument[0];ReturnValue;value;df-generated
public String returnsInput(String input) {
return input;
}

View File

@@ -3,6 +3,7 @@ package p;
public final class FluentAPI {
// summary=p;FluentAPI;false;returnsThis;(String);;Argument[this];ReturnValue;value;df-generated
// contentbased-summary=p;FluentAPI;false;returnsThis;(String);;Argument[this];ReturnValue;value;df-generated
public FluentAPI returnsThis(String input) {
return this;
}

View File

@@ -7,12 +7,14 @@ public final class ImmutablePojo {
private final long x;
// summary=p;ImmutablePojo;false;ImmutablePojo;(String,int);;Argument[0];Argument[this];taint;df-generated
// contentbased-summary=p;ImmutablePojo;false;ImmutablePojo;(String,int);;Argument[0];Argument[this].SyntheticField[p.ImmutablePojo.value];value;df-generated
public ImmutablePojo(String value, int x) {
this.value = value;
this.x = x;
}
// summary=p;ImmutablePojo;false;getValue;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=p;ImmutablePojo;false;getValue;();;Argument[this].SyntheticField[p.ImmutablePojo.value];ReturnValue;value;df-generated
public String getValue() {
return value;
}
@@ -24,6 +26,8 @@ public final class ImmutablePojo {
// summary=p;ImmutablePojo;false;or;(String);;Argument[0];ReturnValue;taint;df-generated
// summary=p;ImmutablePojo;false;or;(String);;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=p;ImmutablePojo;false;or;(String);;Argument[0];ReturnValue;value;df-generated
// contentbased-summary=p;ImmutablePojo;false;or;(String);;Argument[this].SyntheticField[p.ImmutablePojo.value];ReturnValue;value;df-generated
public String or(String defaultValue) {
return value != null ? value : defaultValue;
}

View File

@@ -11,6 +11,7 @@ public class Inheritance {
public class AImplBasePrivateImpl extends BasePrivate {
// summary=p;Inheritance$AImplBasePrivateImpl;true;id;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;Inheritance$AImplBasePrivateImpl;true;id;(String);;Argument[0];ReturnValue;value;df-generated
@Override
public String id(String s) {
return s;
@@ -19,6 +20,7 @@ public class Inheritance {
public class AImplBasePublic extends BasePublic {
// summary=p;Inheritance$BasePublic;true;id;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;Inheritance$BasePublic;true;id;(String);;Argument[0];ReturnValue;value;df-generated
@Override
public String id(String s) {
return s;
@@ -59,6 +61,7 @@ public class Inheritance {
public class BImpl extends B {
// summary=p;Inheritance$IPublic1;true;id;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;Inheritance$IPublic1;true;id;(String);;Argument[0];ReturnValue;value;df-generated
@Override
public String id(String s) {
return s;
@@ -67,6 +70,7 @@ public class Inheritance {
public class CImpl extends C {
// summary=p;Inheritance$C;true;id;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;Inheritance$C;true;id;(String);;Argument[0];ReturnValue;value;df-generated
@Override
public String id(String s) {
return s;
@@ -75,6 +79,7 @@ public class Inheritance {
public class DImpl extends D {
// summary=p;Inheritance$IPublic2;true;id;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;Inheritance$IPublic2;true;id;(String);;Argument[0];ReturnValue;value;df-generated
@Override
public String id(String s) {
return s;
@@ -83,6 +88,7 @@ public class Inheritance {
public class EImpl extends E {
// summary=p;Inheritance$EImpl;true;id;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;Inheritance$EImpl;true;id;(String);;Argument[0];ReturnValue;value;df-generated
@Override
public String id(String s) {
return s;

View File

@@ -10,12 +10,14 @@ public class InnerClasses {
public class CaptureMe {
// summary=p;InnerClasses$CaptureMe;true;yesCm;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;InnerClasses$CaptureMe;true;yesCm;(String);;Argument[0];ReturnValue;value;df-generated
public String yesCm(String input) {
return input;
}
}
// summary=p;InnerClasses;true;yes;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;InnerClasses;true;yes;(String);;Argument[0];ReturnValue;value;df-generated
public String yes(String input) {
return input;
}

View File

@@ -19,21 +19,25 @@ public final class InnerHolder {
private StringBuilder sb = new StringBuilder();
// summary=p;InnerHolder;false;setContext;(String);;Argument[0];Argument[this];taint;df-generated
// contentbased-summary=p;InnerHolder;false;setContext;(String);;Argument[0];Argument[this].SyntheticField[p.InnerHolder.context].SyntheticField[p.InnerHolder$Context.value];value;df-generated
public void setContext(String value) {
context = new Context(value);
}
// summary=p;InnerHolder;false;explicitSetContext;(String);;Argument[0];Argument[this];taint;df-generated
// contentbased-summary=p;InnerHolder;false;explicitSetContext;(String);;Argument[0];Argument[this].SyntheticField[p.InnerHolder.context].SyntheticField[p.InnerHolder$Context.value];value;df-generated
public void explicitSetContext(String value) {
this.context = new Context(value);
}
// summary=p;InnerHolder;false;append;(String);;Argument[0];Argument[this];taint;df-generated
// contentbased-summary=p;InnerHolder;false;append;(String);;Argument[0];Argument[this].SyntheticField[p.InnerHolder.sb];taint;df-generated
public void append(String value) {
sb.append(value);
}
// summary=p;InnerHolder;false;getValue;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=p;InnerHolder;false;getValue;();;Argument[this].SyntheticField[p.InnerHolder.context].SyntheticField[p.InnerHolder$Context.value];ReturnValue;value;df-generated
public String getValue() {
return context.getValue();
}

View File

@@ -13,6 +13,7 @@ public final class Joiner {
private String emptyValue;
// summary=p;Joiner;false;Joiner;(CharSequence);;Argument[0];Argument[this];taint;df-generated
// contentbased-summary=p;Joiner;false;Joiner;(CharSequence);;Argument[0];Argument[this].SyntheticField[p.Joiner.delimiter];taint;df-generated
public Joiner(CharSequence delimiter) {
this(delimiter, "", "");
}
@@ -20,6 +21,9 @@ public final class Joiner {
// summary=p;Joiner;false;Joiner;(CharSequence,CharSequence,CharSequence);;Argument[0];Argument[this];taint;df-generated
// summary=p;Joiner;false;Joiner;(CharSequence,CharSequence,CharSequence);;Argument[1];Argument[this];taint;df-generated
// summary=p;Joiner;false;Joiner;(CharSequence,CharSequence,CharSequence);;Argument[2];Argument[this];taint;df-generated
// contentbased-summary=p;Joiner;false;Joiner;(CharSequence,CharSequence,CharSequence);;Argument[0];Argument[this].SyntheticField[p.Joiner.delimiter];taint;df-generated
// contentbased-summary=p;Joiner;false;Joiner;(CharSequence,CharSequence,CharSequence);;Argument[1];Argument[this].SyntheticField[p.Joiner.prefix];taint;df-generated
// contentbased-summary=p;Joiner;false;Joiner;(CharSequence,CharSequence,CharSequence);;Argument[2];Argument[this].SyntheticField[p.Joiner.suffix];taint;df-generated
public Joiner(CharSequence delimiter, CharSequence prefix, CharSequence suffix) {
Objects.requireNonNull(prefix, "The prefix must not be null");
Objects.requireNonNull(delimiter, "The delimiter must not be null");
@@ -32,6 +36,9 @@ public final class Joiner {
// summary=p;Joiner;false;setEmptyValue;(CharSequence);;Argument[0];Argument[this];taint;df-generated
// summary=p;Joiner;false;setEmptyValue;(CharSequence);;Argument[this];ReturnValue;value;df-generated
// contentbased-summary=p;Joiner;false;setEmptyValue;(CharSequence);;Argument[0];Argument[this].SyntheticField[p.Joiner.emptyValue];taint;df-generated
// contentbased-summary=p;Joiner;false;setEmptyValue;(CharSequence);;Argument[0];ReturnValue.SyntheticField[p.Joiner.emptyValue];taint;df-generated
// contentbased-summary=p;Joiner;false;setEmptyValue;(CharSequence);;Argument[this];ReturnValue;value;df-generated
public Joiner setEmptyValue(CharSequence emptyValue) {
this.emptyValue =
Objects.requireNonNull(emptyValue, "The empty value must not be null").toString();
@@ -71,6 +78,8 @@ public final class Joiner {
}
// summary=p;Joiner;false;add;(CharSequence);;Argument[this];ReturnValue;value;df-generated
// contentbased-summary=p;Joiner;false;add;(CharSequence);;Argument[this].SyntheticField[p.Joiner.elts].ArrayElement;ReturnValue.SyntheticField[p.Joiner.elts].ArrayElement;value;df-generated
// contentbased-summary=p;Joiner;false;add;(CharSequence);;Argument[this];ReturnValue;value;df-generated
public Joiner add(CharSequence newElement) {
final String elt = String.valueOf(newElement);
if (elts == null) {
@@ -94,6 +103,8 @@ public final class Joiner {
}
// summary=p;Joiner;false;merge;(Joiner);;Argument[this];ReturnValue;value;df-generated
// contentbased-summary=p;Joiner;false;merge;(Joiner);;Argument[this].SyntheticField[p.Joiner.elts].ArrayElement;ReturnValue.SyntheticField[p.Joiner.elts].ArrayElement;value;df-generated
// contentbased-summary=p;Joiner;false;merge;(Joiner);;Argument[this];ReturnValue;value;df-generated
public Joiner merge(Joiner other) {
Objects.requireNonNull(other);
if (other.elts == null) {

View File

@@ -17,6 +17,7 @@ class MultipleImpl2 {
public class Impl2 implements IInterface {
// summary=p;MultipleImpl2$IInterface;true;m;(Object);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;MultipleImpl2$IInterface;true;m;(Object);;Argument[0];ReturnValue;value;df-generated
public Object m(Object value) {
return value;
}

View File

@@ -10,6 +10,7 @@ public class MultipleImpls {
public static class Strat1 implements Strategy {
// summary=p;MultipleImpls$Strategy;true;doSomething;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;MultipleImpls$Strategy;true;doSomething;(String);;Argument[0];ReturnValue;value;df-generated
public String doSomething(String value) {
return value;
}
@@ -29,12 +30,18 @@ public class MultipleImpls {
private String foo;
// summary=p;MultipleImpls$Strategy;true;doSomething;(String);;Argument[0];Argument[this];taint;df-generated
// A field based model should not be lifted if the field pertains to the concrete
// implementation.
// SPURIOUS-contentbased-summary=p;MultipleImpls$Strategy;true;doSomething;(String);;Argument[0];Argument[this].SyntheticField[p.MultipleImpls$Strat2.foo];value;df-generated
public String doSomething(String value) {
this.foo = value;
return "none";
}
// summary=p;MultipleImpls$Strat2;true;getValue;();;Argument[this];ReturnValue;taint;df-generated
// A field based model should not be lifted if the field pertains to the concrete
// implementation.
// SPURIOUS-contentbased-summary=p;MultipleImpls$Strat2;true;getValue;();;Argument[this].SyntheticField[p.MultipleImpls$Strat2.foo];ReturnValue;value;df-generated
public String getValue() {
return this.foo;
}

View File

@@ -8,6 +8,7 @@ import java.util.List;
public class ParamFlow {
// summary=p;ParamFlow;true;returnsInput;(String);;Argument[0];ReturnValue;taint;df-generated
// contentbased-summary=p;ParamFlow;true;returnsInput;(String);;Argument[0];ReturnValue;value;df-generated
public String returnsInput(String input) {
return input;
}
@@ -19,6 +20,8 @@ public class ParamFlow {
// summary=p;ParamFlow;true;returnMultipleParameters;(String,String);;Argument[0];ReturnValue;taint;df-generated
// summary=p;ParamFlow;true;returnMultipleParameters;(String,String);;Argument[1];ReturnValue;taint;df-generated
// contentbased-summary=p;ParamFlow;true;returnMultipleParameters;(String,String);;Argument[0];ReturnValue;value;df-generated
// contentbased-summary=p;ParamFlow;true;returnMultipleParameters;(String,String);;Argument[1];ReturnValue;value;df-generated
public String returnMultipleParameters(String one, String two) {
if (System.currentTimeMillis() > 100) {
return two;
@@ -27,26 +30,31 @@ public class ParamFlow {
}
// summary=p;ParamFlow;true;returnArrayElement;(String[]);;Argument[0].ArrayElement;ReturnValue;taint;df-generated
// contentbased-summary=p;ParamFlow;true;returnArrayElement;(String[]);;Argument[0].ArrayElement;ReturnValue;value;df-generated
public String returnArrayElement(String[] input) {
return input[0];
}
// summary=p;ParamFlow;true;returnVarArgElement;(String[]);;Argument[0].ArrayElement;ReturnValue;taint;df-generated
// contentbased-summary=p;ParamFlow;true;returnVarArgElement;(String[]);;Argument[0].ArrayElement;ReturnValue;value;df-generated
public String returnVarArgElement(String... input) {
return input[0];
}
// summary=p;ParamFlow;true;returnCollectionElement;(List);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=p;ParamFlow;true;returnCollectionElement;(List);;Argument[0].Element;ReturnValue;value;df-generated
public String returnCollectionElement(List<String> input) {
return input.get(0);
}
// summary=p;ParamFlow;true;returnIteratorElement;(Iterator);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=p;ParamFlow;true;returnIteratorElement;(Iterator);;Argument[0].Element;ReturnValue;value;df-generated
public String returnIteratorElement(Iterator<String> input) {
return input.next();
}
// summary=p;ParamFlow;true;returnIterableElement;(Iterable);;Argument[0].Element;ReturnValue;taint;df-generated
// contentbased-summary=p;ParamFlow;true;returnIterableElement;(Iterable);;Argument[0].Element;ReturnValue;value;df-generated
public String returnIterableElement(Iterable<String> input) {
return input.iterator().next();
}
@@ -57,16 +65,19 @@ public class ParamFlow {
}
// summary=p;ParamFlow;true;writeChunked;(byte[],OutputStream);;Argument[0];Argument[1];taint;df-generated
// contentbased-summary=p;ParamFlow;true;writeChunked;(byte[],OutputStream);;Argument[0];Argument[1];taint;df-generated
public void writeChunked(byte[] data, OutputStream output) throws IOException {
output.write(data, 0, data.length);
}
// summary=p;ParamFlow;true;writeChunked;(char[],OutputStream);;Argument[0];Argument[1];taint;df-generated
// contentbased-summary=p;ParamFlow;true;writeChunked;(char[],OutputStream);;Argument[0];Argument[1];taint;df-generated
public void writeChunked(char[] data, OutputStream output) throws IOException {
output.write(String.valueOf(data).getBytes(), 0, data.length);
}
// summary=p;ParamFlow;true;addTo;(String,List);;Argument[0];Argument[1].Element;taint;df-generated
// contentbased-summary=p;ParamFlow;true;addTo;(String,List);;Argument[0];Argument[1].Element;value;df-generated
public void addTo(String data, List<String> target) {
target.add(data);
}

View File

@@ -24,18 +24,20 @@ public final class Pojo {
private int intValue = 2;
private byte[] byteArray = new byte[] {1, 2, 3};
public byte[] byteArray = new byte[] {1, 2, 3};
private float[] floatArray = new float[] {1, 2, 3};
private char[] charArray = new char[] {'a', 'b', 'c'};
private List<Character> charList = Arrays.asList('a', 'b', 'c');
private Byte[] byteObjectArray = new Byte[] {1, 2, 3};
// summary=p;Pojo;false;getValue;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=p;Pojo;false;getValue;();;Argument[this].SyntheticField[p.Pojo.value];ReturnValue;value;df-generated
public String getValue() {
return value;
}
// summary=p;Pojo;false;setValue;(String);;Argument[0];Argument[this];taint;df-generated
// contentbased-summary=p;Pojo;false;setValue;(String);;Argument[0];Argument[this].SyntheticField[p.Pojo.value];value;df-generated
public void setValue(String value) {
this.value = value;
}
@@ -62,11 +64,13 @@ public final class Pojo {
}
// summary=p;Pojo;false;getCharArray;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=p;Pojo;false;getCharArray;();;Argument[this].SyntheticField[p.Pojo.charArray];ReturnValue;value;df-generated
public char[] getCharArray() {
return charArray;
}
// summary=p;Pojo;false;getByteArray;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=p;Pojo;false;getByteArray;();;Argument[this].Field[p.Pojo.byteArray];ReturnValue;value;df-generated
public byte[] getByteArray() {
return byteArray;
}
@@ -87,11 +91,13 @@ public final class Pojo {
}
// summary=p;Pojo;false;getBoxedChars;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=p;Pojo;false;getBoxedChars;();;Argument[this].SyntheticField[p.Pojo.charList];ReturnValue;value;df-generated
public List<Character> getBoxedChars() {
return charList;
}
// summary=p;Pojo;false;getBoxedBytes;();;Argument[this];ReturnValue;taint;df-generated
// contentbased-summary=p;Pojo;false;getBoxedBytes;();;Argument[this].SyntheticField[p.Pojo.byteObjectArray];ReturnValue;value;df-generated
public Byte[] getBoxedBytes() {
return byteObjectArray;
}
@@ -107,6 +113,7 @@ public final class Pojo {
}
// summary=p;Pojo;false;fillIn;(List);;Argument[this];Argument[0].Element;taint;df-generated
// contentbased-summary=p;Pojo;false;fillIn;(List);;Argument[this].SyntheticField[p.Pojo.value];Argument[0].Element;value;df-generated
public void fillIn(List<String> target) {
target.add(value);
}

View File

@@ -29,6 +29,9 @@ public class PrivateFlowViaPublicInterface {
}
// summary=p;PrivateFlowViaPublicInterface$SPI;true;openStream;();;Argument[this];ReturnValue;taint;df-generated
// A field based model should not be lifted if the field pertains to the concrete
// implementation.
// SPURIOUS-contentbased-summary=p;PrivateFlowViaPublicInterface$SPI;true;openStream;();;Argument[this].SyntheticField[p.PrivateFlowViaPublicInterface$PrivateImplWithSink.file];ReturnValue;taint;df-generated
@Override
public OutputStream openStream() throws IOException {
return new FileOutputStream(file);
@@ -51,6 +54,9 @@ public class PrivateFlowViaPublicInterface {
}
// summary=p;PrivateFlowViaPublicInterface;true;createAnSPI;(File);;Argument[0];ReturnValue;taint;df-generated
// A field based model should not be lifted if the field pertains to the concrete
// implementation.
// SPURIOUS-contentbased-summary=p;PrivateFlowViaPublicInterface;true;createAnSPI;(File);;Argument[0];ReturnValue.SyntheticField[p.PrivateFlowViaPublicInterface$PrivateImplWithSink.file];value;df-generated
public static SPI createAnSPI(File file) {
return new PrivateImplWithSink(file);
}

View File

@@ -33,6 +33,7 @@ class Generator:
self.generateSources = False
self.generateSummaries = False
self.generateNeutrals = False
self.generateContentSummaries = False
self.generateTypeBasedSummaries = False
self.dryRun = False
self.dirname = "modelgenerator"
@@ -50,6 +51,7 @@ Which models are generated is controlled by the flags:
--with-sources
--with-summaries
--with-neutrals
--with-content-summaries (Experimental). May not be used in conjunction with --with-summaries
--with-typebased-summaries (Experimental)
If none of these flags are specified, all models are generated except for the type based models.
@@ -81,6 +83,10 @@ Requirements: `codeql` should both appear on your path.
generator.printHelp()
sys.exit(0)
if "--with-summaries" in sys.argv and "--with-content-summaries" in sys.argv:
generator.printHelp()
sys.exit(0)
if "--with-sinks" in sys.argv:
sys.argv.remove("--with-sinks")
generator.generateSinks = True
@@ -97,6 +103,10 @@ Requirements: `codeql` should both appear on your path.
sys.argv.remove("--with-neutrals")
generator.generateNeutrals = True
if "--with-content-summaries" in sys.argv:
sys.argv.remove("--with-content-summaries")
generator.generateContentSummaries = True
if "--with-typebased-summaries" in sys.argv:
sys.argv.remove("--with-typebased-summaries")
generator.generateTypeBasedSummaries = True
@@ -105,7 +115,7 @@ Requirements: `codeql` should both appear on your path.
sys.argv.remove("--dry-run")
generator.dryRun = True
if not generator.generateSinks and not generator.generateSources and not generator.generateSummaries and not generator.generateNeutrals and not generator.generateTypeBasedSummaries:
if not generator.generateSinks and not generator.generateSources and not generator.generateSummaries and not generator.generateNeutrals and not generator.generateTypeBasedSummaries and not generator.generateContentSummaries:
generator.generateSinks = generator.generateSources = generator.generateSummaries = generator.generateNeutrals = True
n = len(sys.argv)
@@ -162,8 +172,13 @@ Requirements: `codeql` should both appear on your path.
neutralAddsTo = self.getAddsTo("CaptureNeutralModels.ql", helpers.neutralModelPredicate)
else:
neutralAddsTo = { }
return helpers.merge(summaryAddsTo, sinkAddsTo, sourceAddsTo, neutralAddsTo)
if self.generateContentSummaries:
contentSummaryAddsTo = self.getAddsTo("CaptureContentSummaryModels.ql", helpers.summaryModelPredicate)
else:
contentSummaryAddsTo = { }
return helpers.merge(summaryAddsTo, contentSummaryAddsTo, sinkAddsTo, sourceAddsTo, neutralAddsTo)
def makeTypeBasedContent(self):
if self.generateTypeBasedSummaries:

View File

@@ -41,7 +41,9 @@ module CleartextLogging {
*/
class SensitiveDataSourceAsSource extends Source, SensitiveDataSource {
SensitiveDataSourceAsSource() {
not SensitiveDataSource.super.getClassification() = SensitiveDataClassification::id()
not SensitiveDataSource.super.getClassification() in [
SensitiveDataClassification::id(), SensitiveDataClassification::certificate()
]
}
override SensitiveDataClassification getClassification() {

View File

@@ -40,7 +40,9 @@ module CleartextStorage {
*/
class SensitiveDataSourceAsSource extends Source, SensitiveDataSource {
SensitiveDataSourceAsSource() {
not SensitiveDataSource.super.getClassification() = SensitiveDataClassification::id()
not SensitiveDataSource.super.getClassification() in [
SensitiveDataClassification::id(), SensitiveDataClassification::certificate()
]
}
override SensitiveDataClassification getClassification() {

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The `py/clear-text-logging-sensitive-data` and `py/clear-text-storage-sensitive-data` queries have been updated to exclude the `certificate` classification of sensitive sources, which often do not contain sensitive data.

View File

@@ -30,7 +30,6 @@ nodes
| test.py:23:58:23:65 | ControlFlowNode for password | semmle.label | ControlFlowNode for password |
| test.py:27:40:27:47 | ControlFlowNode for password | semmle.label | ControlFlowNode for password |
| test.py:30:58:30:65 | ControlFlowNode for password | semmle.label | ControlFlowNode for password |
| test.py:34:30:34:39 | ControlFlowNode for get_cert() | semmle.label | ControlFlowNode for get_cert() |
| test.py:37:11:37:24 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() |
| test.py:39:22:39:35 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() |
| test.py:40:22:40:35 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() |
@@ -73,7 +72,6 @@ subpaths
| test.py:23:58:23:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:23:58:23:65 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) |
| test.py:27:40:27:47 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:27:40:27:47 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) |
| test.py:30:58:30:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:30:58:30:65 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) |
| test.py:34:30:34:39 | ControlFlowNode for get_cert() | test.py:34:30:34:39 | ControlFlowNode for get_cert() | test.py:34:30:34:39 | ControlFlowNode for get_cert() | This expression logs $@ as clear text. | test.py:34:30:34:39 | ControlFlowNode for get_cert() | sensitive data (certificate) |
| test.py:37:11:37:24 | ControlFlowNode for get_password() | test.py:37:11:37:24 | ControlFlowNode for get_password() | test.py:37:11:37:24 | ControlFlowNode for get_password() | This expression logs $@ as clear text. | test.py:37:11:37:24 | ControlFlowNode for get_password() | sensitive data (password) |
| test.py:39:22:39:35 | ControlFlowNode for get_password() | test.py:39:22:39:35 | ControlFlowNode for get_password() | test.py:39:22:39:35 | ControlFlowNode for get_password() | This expression logs $@ as clear text. | test.py:39:22:39:35 | ControlFlowNode for get_password() | sensitive data (password) |
| test.py:40:22:40:35 | ControlFlowNode for get_password() | test.py:40:22:40:35 | ControlFlowNode for get_password() | test.py:40:22:40:35 | ControlFlowNode for get_password() | This expression logs $@ as clear text. | test.py:40:22:40:35 | ControlFlowNode for get_password() | sensitive data (password) |

View File

@@ -31,7 +31,7 @@ def log_password():
def log_cert():
logging.debug("Cert=%s", get_cert()) # NOT OK
logging.debug("Cert=%s", get_cert()) # OK
def print_password():
print(get_password()) # NOT OK
@@ -52,8 +52,8 @@ def log_private():
print(passportNo) # NOT OK
def log2(post_code, zipCode, home_address):
print(post_code) # NOT OK, but NOT FOUND - "code" is treated as enxrypted and thus not sensitive
print(zipCode) # NOT OK, but NOT FOUND - "code" is treated as enxrypted and thus not sensitive
print(post_code) # NOT OK, but NOT FOUND - "code" is treated as encrypted and thus not sensitive
print(zipCode) # NOT OK, but NOT FOUND - "code" is treated as encrypted and thus not sensitive
print(home_address) # NOT OK
def log3(user_latitude, user_longitude):

View File

@@ -1,16 +1,16 @@
edges
| test.py:9:5:9:8 | ControlFlowNode for cert | test.py:12:21:12:24 | ControlFlowNode for cert | provenance | |
| test.py:9:5:9:8 | ControlFlowNode for cert | test.py:13:22:13:41 | ControlFlowNode for Attribute() | provenance | |
| test.py:9:5:9:8 | ControlFlowNode for cert | test.py:15:26:15:29 | ControlFlowNode for cert | provenance | |
| test.py:9:12:9:21 | ControlFlowNode for get_cert() | test.py:9:5:9:8 | ControlFlowNode for cert | provenance | |
| test.py:9:5:9:12 | ControlFlowNode for password | test.py:12:21:12:28 | ControlFlowNode for password | provenance | |
| test.py:9:5:9:12 | ControlFlowNode for password | test.py:13:22:13:45 | ControlFlowNode for Attribute() | provenance | |
| test.py:9:5:9:12 | ControlFlowNode for password | test.py:15:26:15:33 | ControlFlowNode for password | provenance | |
| test.py:9:16:9:29 | ControlFlowNode for get_password() | test.py:9:5:9:12 | ControlFlowNode for password | provenance | |
nodes
| test.py:9:5:9:8 | ControlFlowNode for cert | semmle.label | ControlFlowNode for cert |
| test.py:9:12:9:21 | ControlFlowNode for get_cert() | semmle.label | ControlFlowNode for get_cert() |
| test.py:12:21:12:24 | ControlFlowNode for cert | semmle.label | ControlFlowNode for cert |
| test.py:13:22:13:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| test.py:15:26:15:29 | ControlFlowNode for cert | semmle.label | ControlFlowNode for cert |
| test.py:9:5:9:12 | ControlFlowNode for password | semmle.label | ControlFlowNode for password |
| test.py:9:16:9:29 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() |
| test.py:12:21:12:28 | ControlFlowNode for password | semmle.label | ControlFlowNode for password |
| test.py:13:22:13:45 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| test.py:15:26:15:33 | ControlFlowNode for password | semmle.label | ControlFlowNode for password |
subpaths
#select
| test.py:12:21:12:24 | ControlFlowNode for cert | test.py:9:12:9:21 | ControlFlowNode for get_cert() | test.py:12:21:12:24 | ControlFlowNode for cert | This expression stores $@ as clear text. | test.py:9:12:9:21 | ControlFlowNode for get_cert() | sensitive data (certificate) |
| test.py:13:22:13:41 | ControlFlowNode for Attribute() | test.py:9:12:9:21 | ControlFlowNode for get_cert() | test.py:13:22:13:41 | ControlFlowNode for Attribute() | This expression stores $@ as clear text. | test.py:9:12:9:21 | ControlFlowNode for get_cert() | sensitive data (certificate) |
| test.py:15:26:15:29 | ControlFlowNode for cert | test.py:9:12:9:21 | ControlFlowNode for get_cert() | test.py:15:26:15:29 | ControlFlowNode for cert | This expression stores $@ as clear text. | test.py:9:12:9:21 | ControlFlowNode for get_cert() | sensitive data (certificate) |
| test.py:12:21:12:28 | ControlFlowNode for password | test.py:9:16:9:29 | ControlFlowNode for get_password() | test.py:12:21:12:28 | ControlFlowNode for password | This expression stores $@ as clear text. | test.py:9:16:9:29 | ControlFlowNode for get_password() | sensitive data (password) |
| test.py:13:22:13:45 | ControlFlowNode for Attribute() | test.py:9:16:9:29 | ControlFlowNode for get_password() | test.py:13:22:13:45 | ControlFlowNode for Attribute() | This expression stores $@ as clear text. | test.py:9:16:9:29 | ControlFlowNode for get_password() | sensitive data (password) |
| test.py:15:26:15:33 | ControlFlowNode for password | test.py:9:16:9:29 | ControlFlowNode for get_password() | test.py:15:26:15:33 | ControlFlowNode for password | This expression stores $@ as clear text. | test.py:9:16:9:29 | ControlFlowNode for get_password() | sensitive data (password) |

View File

@@ -1,15 +1,15 @@
import pathlib
def get_cert():
return "<CERT>"
def get_password():
return "password"
def write_password(filename):
cert = get_cert()
password = get_password()
path = pathlib.Path(filename)
path.write_text(cert) # NOT OK
path.write_bytes(cert.encode("utf-8")) # NOT OK
path.write_text(password) # NOT OK
path.write_bytes(password.encode("utf-8")) # NOT OK
path.open("w").write(cert) # NOT OK
path.open("w").write(password) # NOT OK

View File

@@ -3,10 +3,10 @@ edges
| password_in_cookie.py:7:16:7:43 | ControlFlowNode for Attribute() | password_in_cookie.py:7:5:7:12 | ControlFlowNode for password | provenance | |
| password_in_cookie.py:14:5:14:12 | ControlFlowNode for password | password_in_cookie.py:16:33:16:40 | ControlFlowNode for password | provenance | |
| password_in_cookie.py:14:16:14:43 | ControlFlowNode for Attribute() | password_in_cookie.py:14:5:14:12 | ControlFlowNode for password | provenance | |
| test.py:6:5:6:8 | ControlFlowNode for cert | test.py:8:20:8:23 | ControlFlowNode for cert | provenance | |
| test.py:6:5:6:8 | ControlFlowNode for cert | test.py:9:9:9:13 | ControlFlowNode for lines | provenance | |
| test.py:6:12:6:21 | ControlFlowNode for get_cert() | test.py:6:5:6:8 | ControlFlowNode for cert | provenance | |
| test.py:9:9:9:13 | ControlFlowNode for lines | test.py:10:25:10:29 | ControlFlowNode for lines | provenance | |
| test.py:15:5:15:12 | ControlFlowNode for password | test.py:17:20:17:27 | ControlFlowNode for password | provenance | |
| test.py:15:5:15:12 | ControlFlowNode for password | test.py:18:9:18:13 | ControlFlowNode for lines | provenance | |
| test.py:15:16:15:29 | ControlFlowNode for get_password() | test.py:15:5:15:12 | ControlFlowNode for password | provenance | |
| test.py:18:9:18:13 | ControlFlowNode for lines | test.py:19:25:19:29 | ControlFlowNode for lines | provenance | |
nodes
| password_in_cookie.py:7:5:7:12 | ControlFlowNode for password | semmle.label | ControlFlowNode for password |
| password_in_cookie.py:7:16:7:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
@@ -14,14 +14,14 @@ nodes
| password_in_cookie.py:14:5:14:12 | ControlFlowNode for password | semmle.label | ControlFlowNode for password |
| password_in_cookie.py:14:16:14:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| password_in_cookie.py:16:33:16:40 | ControlFlowNode for password | semmle.label | ControlFlowNode for password |
| test.py:6:5:6:8 | ControlFlowNode for cert | semmle.label | ControlFlowNode for cert |
| test.py:6:12:6:21 | ControlFlowNode for get_cert() | semmle.label | ControlFlowNode for get_cert() |
| test.py:8:20:8:23 | ControlFlowNode for cert | semmle.label | ControlFlowNode for cert |
| test.py:9:9:9:13 | ControlFlowNode for lines | semmle.label | ControlFlowNode for lines |
| test.py:10:25:10:29 | ControlFlowNode for lines | semmle.label | ControlFlowNode for lines |
| test.py:15:5:15:12 | ControlFlowNode for password | semmle.label | ControlFlowNode for password |
| test.py:15:16:15:29 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() |
| test.py:17:20:17:27 | ControlFlowNode for password | semmle.label | ControlFlowNode for password |
| test.py:18:9:18:13 | ControlFlowNode for lines | semmle.label | ControlFlowNode for lines |
| test.py:19:25:19:29 | ControlFlowNode for lines | semmle.label | ControlFlowNode for lines |
subpaths
#select
| password_in_cookie.py:9:33:9:40 | ControlFlowNode for password | password_in_cookie.py:7:16:7:43 | ControlFlowNode for Attribute() | password_in_cookie.py:9:33:9:40 | ControlFlowNode for password | This expression stores $@ as clear text. | password_in_cookie.py:7:16:7:43 | ControlFlowNode for Attribute() | sensitive data (password) |
| password_in_cookie.py:16:33:16:40 | ControlFlowNode for password | password_in_cookie.py:14:16:14:43 | ControlFlowNode for Attribute() | password_in_cookie.py:16:33:16:40 | ControlFlowNode for password | This expression stores $@ as clear text. | password_in_cookie.py:14:16:14:43 | ControlFlowNode for Attribute() | sensitive data (password) |
| test.py:8:20:8:23 | ControlFlowNode for cert | test.py:6:12:6:21 | ControlFlowNode for get_cert() | test.py:8:20:8:23 | ControlFlowNode for cert | This expression stores $@ as clear text. | test.py:6:12:6:21 | ControlFlowNode for get_cert() | sensitive data (certificate) |
| test.py:10:25:10:29 | ControlFlowNode for lines | test.py:6:12:6:21 | ControlFlowNode for get_cert() | test.py:10:25:10:29 | ControlFlowNode for lines | This expression stores $@ as clear text. | test.py:6:12:6:21 | ControlFlowNode for get_cert() | sensitive data (certificate) |
| test.py:17:20:17:27 | ControlFlowNode for password | test.py:15:16:15:29 | ControlFlowNode for get_password() | test.py:17:20:17:27 | ControlFlowNode for password | This expression stores $@ as clear text. | test.py:15:16:15:29 | ControlFlowNode for get_password() | sensitive data (password) |
| test.py:19:25:19:29 | ControlFlowNode for lines | test.py:15:16:15:29 | ControlFlowNode for get_password() | test.py:19:25:19:29 | ControlFlowNode for lines | This expression stores $@ as clear text. | test.py:15:16:15:29 | ControlFlowNode for get_password() | sensitive data (password) |

View File

@@ -1,12 +1,21 @@
def get_cert():
return "<CERT>"
def get_password():
return "password"
def write_cert(filename):
cert = get_cert()
with open(filename, "w") as file:
file.write(cert) # NOT OK
file.write(cert) # OK
lines = [cert + "\n"]
file.writelines(lines) # OK
def write_password(filename):
password = get_password()
with open(filename, "w") as file:
file.write(password) # NOT OK
lines = [password + "\n"]
file.writelines(lines) # NOT OK
def FPs():

View File

@@ -90,6 +90,7 @@ impl TrapFile {
let end_line = end.line as usize;
let end_column = end.col as usize;
let (ret, _) = self.writer.location_label(trap::Location {
file_label,
start_line,
start_column,
end_line,

View File

@@ -97,6 +97,18 @@ module ModelPrintingImpl<ModelPrintingLangSig Lang> {
result = asSummaryModel(api, input, output, "taint")
}
/**
* Gets the summary model for `api` with `input` and `output`.
*/
bindingset[input, output, preservesValue]
string asModel(Printing::SummaryApi api, string input, string output, boolean preservesValue) {
preservesValue = true and
result = asValueModel(api, input, output)
or
preservesValue = false and
result = asTaintModel(api, input, output)
}
/**
* Gets the sink model for `api` with `input` and `kind`.
*/

View File

@@ -76,8 +76,8 @@ pub fn populate_empty_location(writer: &mut trap::Writer) {
let file_label = populate_empty_file(writer);
let loc_label = global_location(
writer,
file_label,
trap::Location {
file_label,
start_line: 0,
start_column: 0,
end_line: 0,
@@ -127,14 +127,10 @@ pub fn populate_parent_folders(
}
/** Get the label for the given location, defining it a global ID if it doesn't exist yet. */
fn global_location(
writer: &mut trap::Writer,
file_label: trap::Label,
location: trap::Location,
) -> trap::Label {
fn global_location(writer: &mut trap::Writer, location: trap::Location) -> trap::Label {
let (loc_label, fresh) = writer.global_id(&format!(
"loc,{{{}}},{},{},{},{}",
file_label,
location.file_label,
location.start_line,
location.start_column,
location.end_line,
@@ -145,7 +141,7 @@ fn global_location(
"locations_default",
vec![
trap::Arg::Label(loc_label),
trap::Arg::Label(file_label),
trap::Arg::Label(location.file_label),
trap::Arg::Int(location.start_line),
trap::Arg::Int(location.start_column),
trap::Arg::Int(location.end_line),
@@ -158,18 +154,14 @@ fn global_location(
/** Get the label for the given location, creating it as a fresh ID if we haven't seen the location
* yet for this file. */
fn location_label(
writer: &mut trap::Writer,
file_label: trap::Label,
location: trap::Location,
) -> trap::Label {
fn location_label(writer: &mut trap::Writer, location: trap::Location) -> trap::Label {
let (loc_label, fresh) = writer.location_label(location);
if fresh {
writer.add_tuple(
"locations_default",
vec![
trap::Arg::Label(loc_label),
trap::Arg::Label(file_label),
trap::Arg::Label(location.file_label),
trap::Arg::Int(location.start_line),
trap::Arg::Int(location.start_column),
trap::Arg::Int(location.end_line),
@@ -312,8 +304,8 @@ impl<'a> Visitor<'a> {
node: Node,
status_page: bool,
) {
let loc = location_for(self, node);
let loc_label = location_label(self.trap_writer, self.file_label, loc);
let loc = location_for(self, self.file_label, node);
let loc_label = location_label(self.trap_writer, loc);
let mut mesg = self.diagnostics_writer.new_entry(
"parse-error",
"Could not process some files due to syntax errors",
@@ -364,8 +356,8 @@ impl<'a> Visitor<'a> {
return;
}
let (id, _, child_nodes) = self.stack.pop().expect("Vistor: empty stack");
let loc = location_for(self, node);
let loc_label = location_label(self.trap_writer, self.file_label, loc);
let loc = location_for(self, self.file_label, node);
let loc_label = location_label(self.trap_writer, loc);
let table = self
.schema
.get(&TypeName {
@@ -627,7 +619,7 @@ fn sliced_source_arg(source: &[u8], n: Node) -> trap::Arg {
// Emit a pair of `TrapEntry`s for the provided node, appropriately calibrated.
// The first is the location and label definition, and the second is the
// 'Located' entry.
fn location_for(visitor: &mut Visitor, n: Node) -> trap::Location {
fn location_for(visitor: &mut Visitor, file_label: trap::Label, n: Node) -> trap::Location {
// Tree-sitter row, column values are 0-based while CodeQL starts
// counting at 1. In addition Tree-sitter's row and column for the
// end position are exclusive while CodeQL's end positions are inclusive.
@@ -685,6 +677,7 @@ fn location_for(visitor: &mut Visitor, n: Node) -> trap::Location {
}
}
trap::Location {
file_label,
start_line,
start_column,
end_line,

View File

@@ -7,6 +7,7 @@ use flate2::write::GzEncoder;
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub struct Location {
pub file_label: Label,
pub start_line: usize,
pub start_column: usize,
pub end_line: usize,
@@ -136,7 +137,7 @@ impl fmt::Display for Entry {
}
}
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
// Identifiers of the form #0, #1...
pub struct Label(u32);