mirror of
https://github.com/github/codeql.git
synced 2026-05-05 05:35:13 +02:00
change Decompression bombs Query structure
This commit is contained in:
@@ -12,47 +12,10 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import MultipartAndFormRemoteSource
|
||||
import experimental.frameworks.DecompressionBombs
|
||||
import DecompressionBomb::Flow::PathGraph
|
||||
|
||||
module Config implements DataFlow::StateConfigSig {
|
||||
class FlowState = DecompressionBombs::FlowState;
|
||||
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
source instanceof UntrustedFlowSource and
|
||||
state = ""
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
sink instanceof DecompressionBombs::Sink and
|
||||
state =
|
||||
[
|
||||
"ZstdNewReader", "XzNewReader", "GzipNewReader", "PgzipNewReader", "S2NewReader",
|
||||
"SnappyNewReader", "ZlibNewReader", "FlateNewReader", "Bzip2NewReader", "ZipOpenReader",
|
||||
"ZipKlauspost"
|
||||
]
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
exists(DecompressionBombs::AdditionalTaintStep addStep |
|
||||
addStep.isAdditionalFlowStep(fromNode, toNode)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(DecompressionBombs::AdditionalTaintStep addStep |
|
||||
addStep.isAdditionalFlowStep(fromNode, fromState, toNode, toState)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module Flow = TaintTracking::GlobalWithState<Config>;
|
||||
|
||||
import Flow::PathGraph
|
||||
|
||||
from Flow::PathNode source, Flow::PathNode sink
|
||||
where Flow::flowPath(source, sink)
|
||||
from DecompressionBomb::Flow::PathNode source, DecompressionBomb::Flow::PathNode sink
|
||||
where DecompressionBomb::Flow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "This decompression is $@.", source.getNode(),
|
||||
"decompressing compressed data without managing output size"
|
||||
|
||||
@@ -1,772 +1,47 @@
|
||||
/**
|
||||
* Provides a taint tracking configuration for reasoning about decompression bomb vulnerabilities.
|
||||
*/
|
||||
|
||||
import go
|
||||
|
||||
module DecompressionBombs {
|
||||
class FlowState extends string {
|
||||
FlowState() {
|
||||
this =
|
||||
/** Provides a taint tracking configuration for reasoning about decompression bomb vulnerabilities. */
|
||||
module DecompressionBomb {
|
||||
import DecompressionBombsCustomizations
|
||||
import MultipartAndFormRemoteSource
|
||||
|
||||
module Config implements DataFlow::StateConfigSig {
|
||||
class FlowState = DecompressionBombs::FlowState;
|
||||
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
source instanceof UntrustedFlowSource and
|
||||
state = ""
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
sink instanceof DecompressionBombs::Sink and
|
||||
state =
|
||||
[
|
||||
"ZstdNewReader", "XzNewReader", "GzipNewReader", "PgzipNewReader", "S2NewReader",
|
||||
"SnappyNewReader", "ZlibNewReader", "FlateNewReader", "Bzip2NewReader", "ZipOpenReader",
|
||||
"ZipKlauspost", ""
|
||||
"ZipKlauspost"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The additional taint steps that need for creating taint tracking or dataflow.
|
||||
*/
|
||||
abstract class AdditionalTaintStep extends string {
|
||||
AdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
exists(DecompressionBombs::AdditionalTaintStep addStep |
|
||||
addStep.isAdditionalFlowStep(fromNode, toNode)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a additional taint step between pred and succ.
|
||||
*/
|
||||
abstract predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode);
|
||||
|
||||
/**
|
||||
* Holds if there is a additional taint step between pred and succ.
|
||||
*/
|
||||
abstract predicate isAdditionalFlowStep(
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Sinks of uncontrolled data decompression
|
||||
*/
|
||||
abstract class Sink extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `github.com/DataDog/zstd` package
|
||||
*/
|
||||
module DataDogZstd {
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/DataDog/zstd", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "ZstdNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
) {
|
||||
exists(DecompressionBombs::AdditionalTaintStep addStep |
|
||||
addStep.isAdditionalFlowStep(fromNode, fromState, toNode, toState)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `github.com/klauspost/compress/zstd` package
|
||||
*/
|
||||
module KlauspostZstd {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m |
|
||||
m.hasQualifiedName("github.com/klauspost/compress/zstd", "Decoder", "DecodeAll")
|
||||
|
|
||||
this = m.getACall().getReceiver()
|
||||
)
|
||||
or
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("github.com/klauspost/compress/zstd", "Decoder", ["WriteTo", "Read"]) and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/klauspost/compress/zstd", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "ZstdNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides additional flow steps for `archive/zip` package
|
||||
*/
|
||||
module ArchiveZipBombs {
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("archive/zip", ["OpenReader", "NewReader"]) and call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "ZipOpenReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides Decompression additional taint steps for `github.com/klauspost/compress/zip` package
|
||||
*/
|
||||
module KlauspostZip {
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/klauspost/compress/zip", ["NewReader", "OpenReader"]) and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "ZipKlauspost"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
exists(DataFlow::FieldReadNode fi |
|
||||
fi.getType().hasQualifiedName("github.com/klauspost/compress/zip", "Reader")
|
||||
|
|
||||
fromNode = fi.getBase() and
|
||||
toNode = fi
|
||||
)
|
||||
or
|
||||
exists(Method m, DataFlow::CallNode call |
|
||||
m.hasQualifiedName("github.com/klauspost/compress/zip", "File", ["Open", "OpenRaw"]) and
|
||||
call = m.getACall()
|
||||
|
|
||||
fromNode = call.getReceiver() and
|
||||
toNode = call
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `github.com/ulikunitz/xz` package
|
||||
*/
|
||||
module UlikunitzXz {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("github.com/ulikunitz/xz", "Reader", "Read") and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/ulikunitz/xz", "NewReader") and call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "XzNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `compress/gzip` package
|
||||
*/
|
||||
module CompressGzipBombs {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("compress/gzip", "Reader", "Read") and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("compress/gzip", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "GzipNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `github.com/klauspost/compress/gzip` package
|
||||
*/
|
||||
module KlauspostGzipAndPgzip {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName(["github.com/klauspost/compress/gzip", "github.com/klauspost/pgzip"],
|
||||
"Reader", ["Read", "WriteTo"]) and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/klauspost/pgzip", "NewReader") and
|
||||
call = f.getACall() and
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "PgzipNewReader"
|
||||
or
|
||||
f.hasQualifiedName("github.com/klauspost/compress/gzip", "NewReader") and
|
||||
call = f.getACall() and
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "GzipNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `compress/bzip2` package
|
||||
*/
|
||||
module CompressBzip2 {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("compress/bzip2", "reader", "Read") and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("compress/bzip2", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "Bzip2NewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `github.com/dsnet/compress/bzip2` package
|
||||
*/
|
||||
module DsnetBzip2 {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("github.com/dsnet/compress/bzip2", "Reader", "Read") and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/dsnet/compress/bzip2", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "Bzip2NewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `github.com/dsnet/compress/flate` package
|
||||
*/
|
||||
module DsnetFlate {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("github.com/dsnet/compress/flate", "Reader", "Read") and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/dsnet/compress/flate", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "FlateNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `compress/flate` package
|
||||
*/
|
||||
module CompressFlateBombs {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("compress/flate", "decompressor", "Read") and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("compress/flate", ["NewReaderDict", "NewReader"]) and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "FlateNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `github.com/klauspost/compress/flate` package
|
||||
*/
|
||||
module KlauspostFlate {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("github.com/klauspost/compress/flate", "decompressor", "Read") and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/klauspost/compress/flate", ["NewReaderDict", "NewReader"]) and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "FlateNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `github.com/klauspost/compress/zlib` package
|
||||
*/
|
||||
module KlauspostZlib {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("github.com/klauspost/compress/zlib", "reader", "Read") and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/klauspost/compress/zlib", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "ZlibNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `compress/zlib` package
|
||||
*/
|
||||
module CompressZlibBombs {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("compress/zlib", "reader", "Read") and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("compress/zlib", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "ZlibNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `github.com/golang/snappy` package
|
||||
*/
|
||||
module GolangSnappy {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("github.com/golang/snappy", "Reader", ["Read", "ReadByte"]) and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/golang/snappy", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "SnappyNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bombs sinks and additional flow steps for `github.com/klauspost/compress/snappy` package
|
||||
*/
|
||||
module KlauspostSnappy {
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/klauspost/compress/snappy", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "SnappyNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `github.com/klauspost/compress/s2` package
|
||||
*/
|
||||
module KlauspostS2 {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("github.com/klauspost/compress/s2", "Reader",
|
||||
["DecodeConcurrent", "ReadByte", "Read"]) and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/klauspost/compress/s2", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "S2NewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks for packages that use some standard IO interfaces/methods for reading decompressed data
|
||||
*/
|
||||
module GeneralReadIoSink {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Function f, DataFlow::CallNode cn |
|
||||
f.hasQualifiedName("io", "CopyN") and cn = f.getACall()
|
||||
|
|
||||
this = cn.getArgument(1) and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
or
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("io", "Reader", "Read") and cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
or
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("archive/tar", "Reader", "Read") and cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
or
|
||||
exists(Function f | f.hasQualifiedName("io", ["Copy", "CopyBuffer"]) |
|
||||
this = f.getACall().getArgument(1)
|
||||
)
|
||||
or
|
||||
exists(Function f |
|
||||
f.hasQualifiedName("io", ["Pipe", "ReadAll", "ReadAtLeast", "ReadFull"])
|
||||
|
|
||||
this = f.getACall().getArgument(0)
|
||||
)
|
||||
or
|
||||
exists(Method m |
|
||||
m.hasQualifiedName("bufio", "Reader",
|
||||
["ReadBytes", "ReadByte", "ReadLine", "ReadRune", "ReadSlice", "ReadString"])
|
||||
|
|
||||
this = m.getACall().getReceiver()
|
||||
)
|
||||
or
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("bufio", "Reader", ["Read", "WriteTo"]) and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
or
|
||||
exists(Method m | m.hasQualifiedName("bufio", "Scanner", ["Text", "Bytes"]) |
|
||||
this = m.getACall().getReceiver()
|
||||
)
|
||||
or
|
||||
exists(Function f | f.hasQualifiedName("io/ioutil", "ReadAll") |
|
||||
this = f.getACall().getArgument(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value of `n` flow into a comparison (<, >, <=, >=).
|
||||
*/
|
||||
predicate hasFlowToComparison(DataFlow::Node n) {
|
||||
localStep*(n, any(DataFlow::RelationalComparisonNode rcn).getAnOperand())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value of `pred` can flow into `succ` in one step through an
|
||||
* arithmetic operation (other than remainder).
|
||||
*
|
||||
* Note: this predicate is copied from AllocationSizeOverflow. When this query
|
||||
* is promoted it should be put in a shared location.
|
||||
*/
|
||||
predicate additionalStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
succ.asExpr().(ArithmeticExpr).getAnOperand() = pred.asExpr() and
|
||||
not succ.asExpr() instanceof RemExpr
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value of `pred` can flow into `succ` in one step, either by a standard taint step
|
||||
* or by an additional step.
|
||||
*
|
||||
* Note: this predicate is copied from AllocationSizeOverflow. When this query
|
||||
* is promoted it should be put in a shared location.
|
||||
*/
|
||||
predicate localStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
TaintTracking::localTaintStep(pred, succ) or
|
||||
additionalStep(pred, succ)
|
||||
}
|
||||
/** Tracks taint flow for reasoning about decompression bomb vulnerabilities. */
|
||||
module Flow = TaintTracking::GlobalWithState<Config>;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,772 @@
|
||||
import go
|
||||
|
||||
module DecompressionBombs {
|
||||
class FlowState extends string {
|
||||
FlowState() {
|
||||
this =
|
||||
[
|
||||
"ZstdNewReader", "XzNewReader", "GzipNewReader", "PgzipNewReader", "S2NewReader",
|
||||
"SnappyNewReader", "ZlibNewReader", "FlateNewReader", "Bzip2NewReader", "ZipOpenReader",
|
||||
"ZipKlauspost", ""
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The additional taint steps that need for creating taint tracking or dataflow.
|
||||
*/
|
||||
abstract class AdditionalTaintStep extends string {
|
||||
AdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
/**
|
||||
* Holds if there is a additional taint step between pred and succ.
|
||||
*/
|
||||
abstract predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode);
|
||||
|
||||
/**
|
||||
* Holds if there is a additional taint step between pred and succ.
|
||||
*/
|
||||
abstract predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Sinks of uncontrolled data decompression
|
||||
*/
|
||||
abstract class Sink extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `github.com/DataDog/zstd` package
|
||||
*/
|
||||
module DataDogZstd {
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/DataDog/zstd", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "ZstdNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `github.com/klauspost/compress/zstd` package
|
||||
*/
|
||||
module KlauspostZstd {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m |
|
||||
m.hasQualifiedName("github.com/klauspost/compress/zstd", "Decoder", "DecodeAll")
|
||||
|
|
||||
this = m.getACall().getReceiver()
|
||||
)
|
||||
or
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("github.com/klauspost/compress/zstd", "Decoder", ["WriteTo", "Read"]) and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/klauspost/compress/zstd", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "ZstdNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides additional flow steps for `archive/zip` package
|
||||
*/
|
||||
module ArchiveZipBombs {
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("archive/zip", ["OpenReader", "NewReader"]) and call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "ZipOpenReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides Decompression additional taint steps for `github.com/klauspost/compress/zip` package
|
||||
*/
|
||||
module KlauspostZip {
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/klauspost/compress/zip", ["NewReader", "OpenReader"]) and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "ZipKlauspost"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
exists(DataFlow::FieldReadNode fi |
|
||||
fi.getType().hasQualifiedName("github.com/klauspost/compress/zip", "Reader")
|
||||
|
|
||||
fromNode = fi.getBase() and
|
||||
toNode = fi
|
||||
)
|
||||
or
|
||||
exists(Method m, DataFlow::CallNode call |
|
||||
m.hasQualifiedName("github.com/klauspost/compress/zip", "File", ["Open", "OpenRaw"]) and
|
||||
call = m.getACall()
|
||||
|
|
||||
fromNode = call.getReceiver() and
|
||||
toNode = call
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `github.com/ulikunitz/xz` package
|
||||
*/
|
||||
module UlikunitzXz {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("github.com/ulikunitz/xz", "Reader", "Read") and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/ulikunitz/xz", "NewReader") and call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "XzNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `compress/gzip` package
|
||||
*/
|
||||
module CompressGzipBombs {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("compress/gzip", "Reader", "Read") and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("compress/gzip", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "GzipNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `github.com/klauspost/compress/gzip` package
|
||||
*/
|
||||
module KlauspostGzipAndPgzip {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName(["github.com/klauspost/compress/gzip", "github.com/klauspost/pgzip"],
|
||||
"Reader", ["Read", "WriteTo"]) and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/klauspost/pgzip", "NewReader") and
|
||||
call = f.getACall() and
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "PgzipNewReader"
|
||||
or
|
||||
f.hasQualifiedName("github.com/klauspost/compress/gzip", "NewReader") and
|
||||
call = f.getACall() and
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "GzipNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `compress/bzip2` package
|
||||
*/
|
||||
module CompressBzip2 {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("compress/bzip2", "reader", "Read") and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("compress/bzip2", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "Bzip2NewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `github.com/dsnet/compress/bzip2` package
|
||||
*/
|
||||
module DsnetBzip2 {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("github.com/dsnet/compress/bzip2", "Reader", "Read") and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/dsnet/compress/bzip2", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "Bzip2NewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `github.com/dsnet/compress/flate` package
|
||||
*/
|
||||
module DsnetFlate {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("github.com/dsnet/compress/flate", "Reader", "Read") and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/dsnet/compress/flate", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "FlateNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `compress/flate` package
|
||||
*/
|
||||
module CompressFlateBombs {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("compress/flate", "decompressor", "Read") and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("compress/flate", ["NewReaderDict", "NewReader"]) and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "FlateNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `github.com/klauspost/compress/flate` package
|
||||
*/
|
||||
module KlauspostFlate {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("github.com/klauspost/compress/flate", "decompressor", "Read") and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/klauspost/compress/flate", ["NewReaderDict", "NewReader"]) and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "FlateNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `github.com/klauspost/compress/zlib` package
|
||||
*/
|
||||
module KlauspostZlib {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("github.com/klauspost/compress/zlib", "reader", "Read") and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/klauspost/compress/zlib", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "ZlibNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `compress/zlib` package
|
||||
*/
|
||||
module CompressZlibBombs {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("compress/zlib", "reader", "Read") and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("compress/zlib", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "ZlibNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `github.com/golang/snappy` package
|
||||
*/
|
||||
module GolangSnappy {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("github.com/golang/snappy", "Reader", ["Read", "ReadByte"]) and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/golang/snappy", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "SnappyNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bombs sinks and additional flow steps for `github.com/klauspost/compress/snappy` package
|
||||
*/
|
||||
module KlauspostSnappy {
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/klauspost/compress/snappy", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "SnappyNewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks and additional flow steps for `github.com/klauspost/compress/s2` package
|
||||
*/
|
||||
module KlauspostS2 {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("github.com/klauspost/compress/s2", "Reader",
|
||||
["DecodeConcurrent", "ReadByte", "Read"]) and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TheAdditionalTaintStep extends AdditionalTaintStep {
|
||||
TheAdditionalTaintStep() { this = "AdditionalTaintStep" }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node fromNode, FlowState fromState, DataFlow::Node toNode, FlowState toState
|
||||
) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName("github.com/klauspost/compress/s2", "NewReader") and
|
||||
call = f.getACall()
|
||||
|
|
||||
fromNode = call.getArgument(0) and
|
||||
toNode = call.getResult(0) and
|
||||
fromState = "" and
|
||||
toState = "S2NewReader"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides decompression bomb sinks for packages that use some standard IO interfaces/methods for reading decompressed data
|
||||
*/
|
||||
module GeneralReadIoSink {
|
||||
class TheSink extends Sink {
|
||||
TheSink() {
|
||||
exists(Function f, DataFlow::CallNode cn |
|
||||
f.hasQualifiedName("io", "CopyN") and cn = f.getACall()
|
||||
|
|
||||
this = cn.getArgument(1) and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
or
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("io", "Reader", "Read") and cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
or
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("archive/tar", "Reader", "Read") and cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
or
|
||||
exists(Function f | f.hasQualifiedName("io", ["Copy", "CopyBuffer"]) |
|
||||
this = f.getACall().getArgument(1)
|
||||
)
|
||||
or
|
||||
exists(Function f |
|
||||
f.hasQualifiedName("io", ["Pipe", "ReadAll", "ReadAtLeast", "ReadFull"])
|
||||
|
|
||||
this = f.getACall().getArgument(0)
|
||||
)
|
||||
or
|
||||
exists(Method m |
|
||||
m.hasQualifiedName("bufio", "Reader",
|
||||
["ReadBytes", "ReadByte", "ReadLine", "ReadRune", "ReadSlice", "ReadString"])
|
||||
|
|
||||
this = m.getACall().getReceiver()
|
||||
)
|
||||
or
|
||||
exists(Method m, DataFlow::CallNode cn |
|
||||
m.hasQualifiedName("bufio", "Reader", ["Read", "WriteTo"]) and
|
||||
cn = m.getACall()
|
||||
|
|
||||
this = cn.getReceiver() and
|
||||
not hasFlowToComparison(cn.getResult(0))
|
||||
)
|
||||
or
|
||||
exists(Method m | m.hasQualifiedName("bufio", "Scanner", ["Text", "Bytes"]) |
|
||||
this = m.getACall().getReceiver()
|
||||
)
|
||||
or
|
||||
exists(Function f | f.hasQualifiedName("io/ioutil", "ReadAll") |
|
||||
this = f.getACall().getArgument(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value of `n` flow into a comparison (<, >, <=, >=).
|
||||
*/
|
||||
predicate hasFlowToComparison(DataFlow::Node n) {
|
||||
localStep*(n, any(DataFlow::RelationalComparisonNode rcn).getAnOperand())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value of `pred` can flow into `succ` in one step through an
|
||||
* arithmetic operation (other than remainder).
|
||||
*
|
||||
* Note: this predicate is copied from AllocationSizeOverflow. When this query
|
||||
* is promoted it should be put in a shared location.
|
||||
*/
|
||||
predicate additionalStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
succ.asExpr().(ArithmeticExpr).getAnOperand() = pred.asExpr() and
|
||||
not succ.asExpr() instanceof RemExpr
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value of `pred` can flow into `succ` in one step, either by a standard taint step
|
||||
* or by an additional step.
|
||||
*
|
||||
* Note: this predicate is copied from AllocationSizeOverflow. When this query
|
||||
* is promoted it should be put in a shared location.
|
||||
*/
|
||||
predicate localStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
TaintTracking::localTaintStep(pred, succ) or
|
||||
additionalStep(pred, succ)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user