C++: Add models for BSD-style send and recv functions.

This commit is contained in:
Mathias Vorreiter Pedersen
2021-02-11 17:21:32 +01:00
parent 18225fa254
commit 91627cbd88
9 changed files with 220 additions and 1 deletions

View File

@@ -28,3 +28,5 @@ private import implementations.Swap
private import implementations.GetDelim
private import implementations.SmartPointer
private import implementations.Sscanf
private import implementations.Send
private import implementations.Recv

View File

@@ -0,0 +1,73 @@
/**
* Provides implementation classes modeling `recv` and various similar
* functions. See `semmle.code.cpp.models.Models` for usage information.
*/
import semmle.code.cpp.models.interfaces.Taint
import semmle.code.cpp.models.interfaces.ArrayFunction
import semmle.code.cpp.models.interfaces.Alias
import semmle.code.cpp.models.interfaces.FlowSource
import semmle.code.cpp.models.interfaces.SideEffect
/** The function `recv` and its assorted variants */
private class Recv extends AliasFunction, ArrayFunction, SideEffectFunction, RemoteFlowFunction {
Recv() {
this.hasGlobalName([
"recv", // recv(socket, dest, len, flags)
"recvfrom", // recvfrom(socket, dest, len, flags, from, fromlen)
"read", // read(socket, dest, len)
"pread" // pread(socket, dest, len, offset)
])
}
override predicate parameterNeverEscapes(int index) {
this.getParameter(index).getUnspecifiedType() instanceof PointerType
}
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate parameterIsAlwaysReturned(int index) { none() }
override predicate hasArrayWithVariableSize(int bufParam, int countParam) {
bufParam = 1 and countParam = 2
}
override predicate hasArrayInput(int bufParam) { this.hasGlobalName("recvfrom") and bufParam = 4 }
override predicate hasArrayOutput(int bufParam) {
bufParam = 1
or
this.hasGlobalName("recvfrom") and bufParam = 4
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
this.hasGlobalName("recvfrom") and
(
i = 4 and buffer = true
or
i = 5 and buffer = false
)
}
override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = 1 and buffer = true and mustWrite = false
or
this.hasGlobalName("recvfrom") and
(
i = 4 and buffer = true and mustWrite = false
or
i = 5 and buffer = false and mustWrite = false
)
}
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasRemoteFlowSource(FunctionOutput output, string description) {
output.isParameterDeref(1) and
description = "Buffer read by " + this.getName()
}
}

View File

@@ -0,0 +1,55 @@
/**
* Provides implementation classes modeling `send` and various similar
* functions. See `semmle.code.cpp.models.Models` for usage information.
*/
import semmle.code.cpp.models.interfaces.Taint
import semmle.code.cpp.models.interfaces.ArrayFunction
import semmle.code.cpp.models.interfaces.Alias
import semmle.code.cpp.models.interfaces.FlowSource
import semmle.code.cpp.models.interfaces.SideEffect
/** The function `send` and its assorted variants */
private class Send extends AliasFunction, ArrayFunction, SideEffectFunction, RemoteFlowFunctionSink {
Send() {
this.hasGlobalName([
"send", // send(socket, buf, len, flags)
"sendto", // sendto(socket, buf, len, flags, to, tolen)
"write" // write(socket, buf, len);
])
}
override predicate parameterNeverEscapes(int index) {
this.getParameter(index).getUnspecifiedType() instanceof PointerType
}
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
override predicate parameterIsAlwaysReturned(int index) { none() }
override predicate hasArrayWithVariableSize(int bufParam, int countParam) {
bufParam = 1 and countParam = 2
}
override predicate hasArrayInput(int bufParam) { bufParam = 1 }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
none()
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = 1 and buffer = true
or
exists(this.getParameter(4)) and i = 4 and buffer = false
}
override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 }
override predicate hasRemoteFlowSink(FunctionInput input, string description) {
input.isParameterDeref(1) and description = "Buffer sent by " + this.getName()
}
}

View File

@@ -29,3 +29,12 @@ abstract class LocalFlowFunction extends Function {
*/
abstract predicate hasLocalFlowSource(FunctionOutput output, string description);
}
/** A library function that sends data over a network connection. */
abstract class RemoteFlowFunctionSink extends Function {
/**
* Holds if data described by `description` flows into `input` to a call to this function, and is then
* send over a network connection.
*/
abstract predicate hasRemoteFlowSink(FunctionInput input, string description);
}

View File

@@ -98,3 +98,31 @@ private class ArgvSource extends LocalFlowSource {
override string getSourceType() { result = "a command-line argument" }
}
/** A remote data flow sink. */
abstract class RemoteFlowSink extends DataFlow::Node {
/** Gets a string that describes the type of this flow sink. */
abstract string getSinkType();
}
private class RemoteParameterSink extends RemoteFlowSink {
string sourceType;
RemoteParameterSink() {
exists(RemoteFlowFunctionSink func, FunctionInput input, CallInstruction call, int index |
func.hasRemoteFlowSink(input, sourceType) and call.getStaticCallTarget() = func
|
exists(ReadSideEffectInstruction read |
call = read.getPrimaryInstruction() and
read.getIndex() = index and
this.asOperand() = read.getSideEffectOperand() and
input.isParameterDerefOrQualifierObject(index)
)
or
input.isParameterOrQualifierAddress(index) and
this.asOperand() = call.getArgumentOperand(index)
)
}
override string getSinkType() { result = sourceType }
}

View File

@@ -6,6 +6,7 @@
import semmle.code.cpp.exprs.Expr
import semmle.code.cpp.commons.Environment
import semmle.code.cpp.security.SecurityOptions
import semmle.code.cpp.models.interfaces.FlowSource
/**
* Extend this class to customize the security queries for
@@ -60,7 +61,7 @@ class SecurityOptions extends string {
functionCall.getTarget().hasGlobalName(fname) and
exists(functionCall.getArgument(arg)) and
(
fname = ["read", "recv", "recvmsg"] and arg = 1
fname = "recvmsg" and arg = 1
or
fname = "getaddrinfo" and arg = 3
or
@@ -68,6 +69,12 @@ class SecurityOptions extends string {
(arg = 1 or arg = 4 or arg = 5)
)
)
or
exists(RemoteFlowFunction remote, FunctionOutput output |
functionCall.getTarget() = remote and
output.isParameterDerefOrQualifierObject(arg) and
remote.hasRemoteFlowSource(output, _)
)
}
/**
@@ -81,6 +88,12 @@ class SecurityOptions extends string {
userInputReturn(fname)
)
)
or
exists(RemoteFlowFunction remote, FunctionOutput output |
functionCall.getTarget() = remote and
(output.isReturnValue() or output.isReturnValueDeref()) and
remote.hasRemoteFlowSource(output, _)
)
}
/**