diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index 886183c32ba6..33bb0895d8c3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -82,6 +82,7 @@ private newtype TOpcode = TSizedBufferReadSideEffect() or TSizedBufferMustWriteSideEffect() or TSizedBufferMayWriteSideEffect() or + TInitializeDynamicAllocation() or TChi() or TInlineAsm() or TUnreached() or @@ -695,6 +696,11 @@ module Opcode { final override string toString() { result = "SizedBufferMayWriteSideEffect" } } + class InitializeDynamicAllocation extends SideEffectOpcode, EntireAllocationWriteOpcode, + TInitializeDynamicAllocation { + final override string toString() { result = "InitializeDynamicAllocation" } + } + class Chi extends Opcode, TChi { final override string toString() { result = "Chi" } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index d058a6c5a3e8..d14cdf089109 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -1350,6 +1350,26 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } } +/** + * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * call to `malloc`. + */ +class InitializeDynamicAllocationInstruction extends SideEffectInstruction { + InitializeDynamicAllocationInstruction() { + getOpcode() instanceof Opcode::InitializeDynamicAllocation + } + + /** + * Gets the address of the allocation this instruction is initializing. + */ + final AddressOperand getAllocationAddressOperand() { result = getAnOperand() } + + /** + * Gets the operand for the allocation this instruction is initializing. + */ + final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() } +} + /** * An instruction representing a GNU or MSVC inline assembly statement. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasConfiguration.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasConfiguration.qll index d9937294d701..e95086c89fc9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasConfiguration.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasConfiguration.qll @@ -7,6 +7,9 @@ private newtype TAllocation = TVariableAllocation(IRVariable var) or TIndirectParameterAllocation(IRAutomaticUserVariable var) { exists(InitializeIndirectionInstruction instr | instr.getIRVariable() = var) + } or + TDynamicAllocation(CallInstruction call) { + exists(InitializeDynamicAllocationInstruction instr | instr.getPrimaryInstruction() = call) } /** @@ -95,3 +98,29 @@ class IndirectParameterAllocation extends Allocation, TIndirectParameterAllocati final override predicate alwaysEscapes() { none() } } + +class DynamicAllocation extends Allocation, TDynamicAllocation { + CallInstruction call; + + DynamicAllocation() { this = TDynamicAllocation(call) } + + final override string toString() { + result = call.toString() + " at " + call.getLocation() // This isn't performant, but it's only used in test/dump code right now. + } + + final override CallInstruction getABaseInstruction() { result = call } + + final override IRFunction getEnclosingIRFunction() { result = call.getEnclosingIRFunction() } + + final override Language::Location getLocation() { result = call.getLocation() } + + final override string getUniqueId() { result = call.getUniqueId() } + + final override IRType getIRType() { result instanceof IRUnknownType } + + final override predicate isReadOnly() { none() } + + final override predicate isAlwaysAllocatedOnStack() { none() } + + final override predicate alwaysEscapes() { none() } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll index c65570c5999d..cb55ec0924ca 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll @@ -68,8 +68,12 @@ private newtype TMemoryLocation = ) and languageType = type.getCanonicalLanguageType() } or - TEntireAllocationMemoryLocation(IndirectParameterAllocation var, boolean isMayAccess) { - isMayAccess = false or isMayAccess = true + TEntireAllocationMemoryLocation(Allocation var, boolean isMayAccess) { + ( + var instanceof IndirectParameterAllocation or + var instanceof DynamicAllocation + ) and + (isMayAccess = false or isMayAccess = true) } or TUnknownMemoryLocation(IRFunction irFunc, boolean isMayAccess) { isMayAccess = false or isMayAccess = true diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index d058a6c5a3e8..d14cdf089109 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -1350,6 +1350,26 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } } +/** + * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * call to `malloc`. + */ +class InitializeDynamicAllocationInstruction extends SideEffectInstruction { + InitializeDynamicAllocationInstruction() { + getOpcode() instanceof Opcode::InitializeDynamicAllocation + } + + /** + * Gets the address of the allocation this instruction is initializing. + */ + final AddressOperand getAllocationAddressOperand() { result = getAnOperand() } + + /** + * Gets the operand for the allocation this instruction is initializing. + */ + final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() } +} + /** * An instruction representing a GNU or MSVC inline assembly statement. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll index 93e5c43bf3b0..ba763a4c03cb 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll @@ -341,16 +341,32 @@ class TranslatedSideEffects extends TranslatedElement, TTranslatedSideEffects { ) } - override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType type) { none() } - - override Instruction getFirstInstruction() { result = getChild(0).getFirstInstruction() } + override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType type) { + expr.getTarget() instanceof AllocationFunction and + opcode instanceof Opcode::InitializeDynamicAllocation and + tag = OnlyInstructionTag() and + type = getUnknownType() + } - override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() } + override Instruction getFirstInstruction() { + if expr.getTarget() instanceof AllocationFunction + then result = getInstruction(OnlyInstructionTag()) + else result = getChild(0).getFirstInstruction() + } - override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() } + override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { + tag = OnlyInstructionTag() and + kind = gotoEdge() and + expr.getTarget() instanceof AllocationFunction and + if exists(getChild(0)) + then result = getChild(0).getFirstInstruction() + else result = getParent().getChildSuccessor(this) + } - override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { - none() + override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { + tag = OnlyInstructionTag() and + operandTag = addressOperand() and + result = getPrimaryInstructionForSideEffect(OnlyInstructionTag()) } override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index 64dc7e869c25..81abc58495da 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -411,7 +411,9 @@ newtype TTranslatedElement = TTranslatedConditionDecl(ConditionDeclExpr expr) { not ignoreExpr(expr) } or // The side effects of a `Call` TTranslatedSideEffects(Call expr) { - exists(TTranslatedArgumentSideEffect(expr, _, _, _)) or expr instanceof ConstructorCall + exists(TTranslatedArgumentSideEffect(expr, _, _, _)) or + expr instanceof ConstructorCall or + expr.getTarget() instanceof AllocationFunction } or // A precise side effect of an argument to a `Call` TTranslatedArgumentSideEffect(Call call, Expr expr, int n, boolean isWrite) { ( diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index d058a6c5a3e8..d14cdf089109 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -1350,6 +1350,26 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } } +/** + * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * call to `malloc`. + */ +class InitializeDynamicAllocationInstruction extends SideEffectInstruction { + InitializeDynamicAllocationInstruction() { + getOpcode() instanceof Opcode::InitializeDynamicAllocation + } + + /** + * Gets the address of the allocation this instruction is initializing. + */ + final AddressOperand getAllocationAddressOperand() { result = getAnOperand() } + + /** + * Gets the operand for the allocation this instruction is initializing. + */ + final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() } +} + /** * An instruction representing a GNU or MSVC inline assembly statement. */ diff --git a/cpp/ql/test/library-tests/dataflow/security-taint/tainted.expected b/cpp/ql/test/library-tests/dataflow/security-taint/tainted.expected index 7359b068d8ea..a62b9b3e2043 100644 --- a/cpp/ql/test/library-tests/dataflow/security-taint/tainted.expected +++ b/cpp/ql/test/library-tests/dataflow/security-taint/tainted.expected @@ -52,3 +52,18 @@ | test.cpp:75:20:75:25 | call to getenv | test.cpp:75:15:75:18 | call to atoi | | | test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:25 | call to getenv | | | test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:45 | (const char *)... | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:8:24:8:25 | s1 | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:11:20:11:21 | s1 | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:11:36:11:37 | s2 | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:83:17:83:24 | userName | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:83:28:83:33 | call to getenv | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:83:28:83:46 | (const char *)... | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:85:8:85:11 | copy | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:86:2:86:7 | call to strcpy | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:86:9:86:12 | copy | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:86:15:86:22 | userName | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:6:88:27 | ! ... | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:7:88:12 | call to strcmp | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:7:88:27 | (bool)... | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:14:88:17 | (const char *)... | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:14:88:17 | copy | | diff --git a/cpp/ql/test/library-tests/dataflow/security-taint/tainted_diff.expected b/cpp/ql/test/library-tests/dataflow/security-taint/tainted_diff.expected index ed954b5444a7..ca905d718239 100644 --- a/cpp/ql/test/library-tests/dataflow/security-taint/tainted_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/security-taint/tainted_diff.expected @@ -8,3 +8,6 @@ | test.cpp:68:28:68:33 | call to getenv | test.cpp:69:10:69:13 | copy | AST only | | test.cpp:68:28:68:33 | call to getenv | test.cpp:70:12:70:15 | copy | AST only | | test.cpp:68:28:68:33 | call to getenv | test.cpp:71:12:71:15 | copy | AST only | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:11:20:11:21 | s1 | AST only | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:85:8:85:11 | copy | AST only | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:86:9:86:12 | copy | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/security-taint/tainted_ir.expected b/cpp/ql/test/library-tests/dataflow/security-taint/tainted_ir.expected index 114c213ff54f..1a7027d399cf 100644 --- a/cpp/ql/test/library-tests/dataflow/security-taint/tainted_ir.expected +++ b/cpp/ql/test/library-tests/dataflow/security-taint/tainted_ir.expected @@ -40,3 +40,15 @@ | test.cpp:75:20:75:25 | call to getenv | test.cpp:75:15:75:18 | call to atoi | | | test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:25 | call to getenv | | | test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:45 | (const char *)... | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:8:24:8:25 | s1 | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:11:36:11:37 | s2 | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:83:17:83:24 | userName | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:83:28:83:33 | call to getenv | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:83:28:83:46 | (const char *)... | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:86:2:86:7 | call to strcpy | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:86:15:86:22 | userName | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:6:88:27 | ! ... | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:7:88:12 | call to strcmp | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:7:88:27 | (bool)... | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:14:88:17 | (const char *)... | | +| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:14:88:17 | copy | | diff --git a/cpp/ql/test/library-tests/dataflow/security-taint/test.cpp b/cpp/ql/test/library-tests/dataflow/security-taint/test.cpp index 5eb7ee79b46b..9d28f9680ca2 100644 --- a/cpp/ql/test/library-tests/dataflow/security-taint/test.cpp +++ b/cpp/ql/test/library-tests/dataflow/security-taint/test.cpp @@ -76,3 +76,16 @@ void guard() { if (len > 1000) return; char **node = (char **) malloc(len * sizeof(char *)); } + +const char *alias_global; + +void mallocBuffer() { + const char *userName = getenv("USER_NAME"); + char *alias = (char*)malloc(4096); + char *copy = (char*)malloc(4096); + strcpy(copy, userName); + alias_global = alias; // to force a Chi node on all aliased memory + if (!strcmp(copy, "admin")) { // copy should be tainted + isAdmin = true; + } +} \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected index 8f312e7f47f2..07c0a9fdd975 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected @@ -1238,3 +1238,47 @@ ssa.cpp: # 254| v254_10(void) = UnmodeledUse : mu* # 254| v254_11(void) = AliasedUse : ~m262_1 # 254| v254_12(void) = ExitFunction : + +# 268| void* MallocAliasing(void*, int) +# 268| Block 0 +# 268| v268_1(void) = EnterFunction : +# 268| m268_2(unknown) = AliasedDefinition : +# 268| m268_3(unknown) = InitializeNonLocal : +# 268| m268_4(unknown) = Chi : total:m268_2, partial:m268_3 +# 268| mu268_5(unknown) = UnmodeledDefinition : +# 268| r268_6(glval) = VariableAddress[s] : +# 268| m268_7(void *) = InitializeParameter[s] : &:r268_6 +# 268| r268_8(void *) = Load : &:r268_6, m268_7 +# 268| m268_9(unknown) = InitializeIndirection[s] : &:r268_8 +# 268| r268_10(glval) = VariableAddress[size] : +# 268| m268_11(int) = InitializeParameter[size] : &:r268_10 +# 269| r269_1(glval) = VariableAddress[buf] : +# 269| r269_2(glval) = FunctionAddress[malloc] : +# 269| r269_3(glval) = VariableAddress[size] : +# 269| r269_4(int) = Load : &:r269_3, m268_11 +# 269| r269_5(void *) = Call : func:r269_2, 0:r269_4 +# 269| m269_6(unknown) = ^CallSideEffect : ~m268_9 +# 269| m269_7(unknown) = Chi : total:m268_9, partial:m269_6 +# 269| m269_8(unknown) = ^InitializeDynamicAllocation : &:r269_5 +# 269| m269_9(void *) = Store : &:r269_1, r269_5 +# 270| r270_1(glval) = FunctionAddress[memcpy] : +# 270| r270_2(glval) = VariableAddress[buf] : +# 270| r270_3(void *) = Load : &:r270_2, m269_9 +# 270| r270_4(glval) = VariableAddress[s] : +# 270| r270_5(void *) = Load : &:r270_4, m268_7 +# 270| r270_6(glval) = VariableAddress[size] : +# 270| r270_7(int) = Load : &:r270_6, m268_11 +# 270| r270_8(void *) = Call : func:r270_1, 0:r270_3, 1:r270_5, 2:r270_7 +# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~m269_8 +# 270| m270_10(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r270_3, r270_7 +# 270| m270_11(unknown) = Chi : total:m269_8, partial:m270_10 +# 271| r271_1(glval) = VariableAddress[#return] : +# 271| r271_2(glval) = VariableAddress[buf] : +# 271| r271_3(void *) = Load : &:r271_2, m269_9 +# 271| m271_4(void *) = Store : &:r271_1, r271_3 +# 268| v268_12(void) = ReturnIndirection : &:r268_8, ~m270_11 +# 268| r268_13(glval) = VariableAddress[#return] : +# 268| v268_14(void) = ReturnValue : &:r268_13, m271_4 +# 268| v268_15(void) = UnmodeledUse : mu* +# 268| v268_16(void) = AliasedUse : ~m270_11 +# 268| v268_17(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected index c09c280bf9b5..c6e1955c12db 100644 --- a/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected @@ -1233,3 +1233,47 @@ ssa.cpp: # 254| v254_10(void) = UnmodeledUse : mu* # 254| v254_11(void) = AliasedUse : ~m262_1 # 254| v254_12(void) = ExitFunction : + +# 268| void* MallocAliasing(void*, int) +# 268| Block 0 +# 268| v268_1(void) = EnterFunction : +# 268| m268_2(unknown) = AliasedDefinition : +# 268| m268_3(unknown) = InitializeNonLocal : +# 268| m268_4(unknown) = Chi : total:m268_2, partial:m268_3 +# 268| mu268_5(unknown) = UnmodeledDefinition : +# 268| r268_6(glval) = VariableAddress[s] : +# 268| m268_7(void *) = InitializeParameter[s] : &:r268_6 +# 268| r268_8(void *) = Load : &:r268_6, m268_7 +# 268| m268_9(unknown) = InitializeIndirection[s] : &:r268_8 +# 268| r268_10(glval) = VariableAddress[size] : +# 268| m268_11(int) = InitializeParameter[size] : &:r268_10 +# 269| r269_1(glval) = VariableAddress[buf] : +# 269| r269_2(glval) = FunctionAddress[malloc] : +# 269| r269_3(glval) = VariableAddress[size] : +# 269| r269_4(int) = Load : &:r269_3, m268_11 +# 269| r269_5(void *) = Call : func:r269_2, 0:r269_4 +# 269| m269_6(unknown) = ^CallSideEffect : ~m268_4 +# 269| m269_7(unknown) = Chi : total:m268_4, partial:m269_6 +# 269| m269_8(unknown) = ^InitializeDynamicAllocation : &:r269_5 +# 269| m269_9(void *) = Store : &:r269_1, r269_5 +# 270| r270_1(glval) = FunctionAddress[memcpy] : +# 270| r270_2(glval) = VariableAddress[buf] : +# 270| r270_3(void *) = Load : &:r270_2, m269_9 +# 270| r270_4(glval) = VariableAddress[s] : +# 270| r270_5(void *) = Load : &:r270_4, m268_7 +# 270| r270_6(glval) = VariableAddress[size] : +# 270| r270_7(int) = Load : &:r270_6, m268_11 +# 270| r270_8(void *) = Call : func:r270_1, 0:r270_3, 1:r270_5, 2:r270_7 +# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~m268_9 +# 270| m270_10(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r270_3, r270_7 +# 270| m270_11(unknown) = Chi : total:m269_8, partial:m270_10 +# 271| r271_1(glval) = VariableAddress[#return] : +# 271| r271_2(glval) = VariableAddress[buf] : +# 271| r271_3(void *) = Load : &:r271_2, m269_9 +# 271| m271_4(void *) = Store : &:r271_1, r271_3 +# 268| v268_12(void) = ReturnIndirection : &:r268_8, m268_9 +# 268| r268_13(glval) = VariableAddress[#return] : +# 268| v268_14(void) = ReturnValue : &:r268_13, m271_4 +# 268| v268_15(void) = UnmodeledUse : mu* +# 268| v268_16(void) = AliasedUse : ~m269_7 +# 268| v268_17(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/ssa.cpp b/cpp/ql/test/library-tests/ir/ssa/ssa.cpp index 5bdfd254e8f8..ee75a2f28e46 100644 --- a/cpp/ql/test/library-tests/ir/ssa/ssa.cpp +++ b/cpp/ql/test/library-tests/ir/ssa/ssa.cpp @@ -262,3 +262,11 @@ char StringLiteralAliasing2(bool b) { const char* s = "Literal"; return s[2]; } + +void *malloc(int size); + +void *MallocAliasing(void *s, int size) { + void *buf = malloc(size); + memcpy(buf, s, size); + return buf; +} \ No newline at end of file diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected index 213f97589d6c..fb7a6eccc15b 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected @@ -1147,3 +1147,44 @@ ssa.cpp: # 254| v254_9(void) = UnmodeledUse : mu* # 254| v254_10(void) = AliasedUse : ~mu254_4 # 254| v254_11(void) = ExitFunction : + +# 268| void* MallocAliasing(void*, int) +# 268| Block 0 +# 268| v268_1(void) = EnterFunction : +# 268| mu268_2(unknown) = AliasedDefinition : +# 268| mu268_3(unknown) = InitializeNonLocal : +# 268| mu268_4(unknown) = UnmodeledDefinition : +# 268| r268_5(glval) = VariableAddress[s] : +# 268| m268_6(void *) = InitializeParameter[s] : &:r268_5 +# 268| r268_7(void *) = Load : &:r268_5, m268_6 +# 268| mu268_8(unknown) = InitializeIndirection[s] : &:r268_7 +# 268| r268_9(glval) = VariableAddress[size] : +# 268| m268_10(int) = InitializeParameter[size] : &:r268_9 +# 269| r269_1(glval) = VariableAddress[buf] : +# 269| r269_2(glval) = FunctionAddress[malloc] : +# 269| r269_3(glval) = VariableAddress[size] : +# 269| r269_4(int) = Load : &:r269_3, m268_10 +# 269| r269_5(void *) = Call : func:r269_2, 0:r269_4 +# 269| mu269_6(unknown) = ^CallSideEffect : ~mu268_4 +# 269| mu269_7(unknown) = ^InitializeDynamicAllocation : &:r269_5 +# 269| m269_8(void *) = Store : &:r269_1, r269_5 +# 270| r270_1(glval) = FunctionAddress[memcpy] : +# 270| r270_2(glval) = VariableAddress[buf] : +# 270| r270_3(void *) = Load : &:r270_2, m269_8 +# 270| r270_4(glval) = VariableAddress[s] : +# 270| r270_5(void *) = Load : &:r270_4, m268_6 +# 270| r270_6(glval) = VariableAddress[size] : +# 270| r270_7(int) = Load : &:r270_6, m268_10 +# 270| r270_8(void *) = Call : func:r270_1, 0:r270_3, 1:r270_5, 2:r270_7 +# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~mu268_4 +# 270| mu270_10(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r270_3, r270_7 +# 271| r271_1(glval) = VariableAddress[#return] : +# 271| r271_2(glval) = VariableAddress[buf] : +# 271| r271_3(void *) = Load : &:r271_2, m269_8 +# 271| m271_4(void *) = Store : &:r271_1, r271_3 +# 268| v268_11(void) = ReturnIndirection : &:r268_7, ~mu268_4 +# 268| r268_12(glval) = VariableAddress[#return] : +# 268| v268_13(void) = ReturnValue : &:r268_12, m271_4 +# 268| v268_14(void) = UnmodeledUse : mu* +# 268| v268_15(void) = AliasedUse : ~mu268_4 +# 268| v268_16(void) = ExitFunction : diff --git a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected index 213f97589d6c..fb7a6eccc15b 100644 --- a/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected +++ b/cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected @@ -1147,3 +1147,44 @@ ssa.cpp: # 254| v254_9(void) = UnmodeledUse : mu* # 254| v254_10(void) = AliasedUse : ~mu254_4 # 254| v254_11(void) = ExitFunction : + +# 268| void* MallocAliasing(void*, int) +# 268| Block 0 +# 268| v268_1(void) = EnterFunction : +# 268| mu268_2(unknown) = AliasedDefinition : +# 268| mu268_3(unknown) = InitializeNonLocal : +# 268| mu268_4(unknown) = UnmodeledDefinition : +# 268| r268_5(glval) = VariableAddress[s] : +# 268| m268_6(void *) = InitializeParameter[s] : &:r268_5 +# 268| r268_7(void *) = Load : &:r268_5, m268_6 +# 268| mu268_8(unknown) = InitializeIndirection[s] : &:r268_7 +# 268| r268_9(glval) = VariableAddress[size] : +# 268| m268_10(int) = InitializeParameter[size] : &:r268_9 +# 269| r269_1(glval) = VariableAddress[buf] : +# 269| r269_2(glval) = FunctionAddress[malloc] : +# 269| r269_3(glval) = VariableAddress[size] : +# 269| r269_4(int) = Load : &:r269_3, m268_10 +# 269| r269_5(void *) = Call : func:r269_2, 0:r269_4 +# 269| mu269_6(unknown) = ^CallSideEffect : ~mu268_4 +# 269| mu269_7(unknown) = ^InitializeDynamicAllocation : &:r269_5 +# 269| m269_8(void *) = Store : &:r269_1, r269_5 +# 270| r270_1(glval) = FunctionAddress[memcpy] : +# 270| r270_2(glval) = VariableAddress[buf] : +# 270| r270_3(void *) = Load : &:r270_2, m269_8 +# 270| r270_4(glval) = VariableAddress[s] : +# 270| r270_5(void *) = Load : &:r270_4, m268_6 +# 270| r270_6(glval) = VariableAddress[size] : +# 270| r270_7(int) = Load : &:r270_6, m268_10 +# 270| r270_8(void *) = Call : func:r270_1, 0:r270_3, 1:r270_5, 2:r270_7 +# 270| v270_9(void) = ^SizedBufferReadSideEffect[1] : &:r270_5, r270_7, ~mu268_4 +# 270| mu270_10(unknown) = ^SizedBufferMustWriteSideEffect[0] : &:r270_3, r270_7 +# 271| r271_1(glval) = VariableAddress[#return] : +# 271| r271_2(glval) = VariableAddress[buf] : +# 271| r271_3(void *) = Load : &:r271_2, m269_8 +# 271| m271_4(void *) = Store : &:r271_1, r271_3 +# 268| v268_11(void) = ReturnIndirection : &:r268_7, ~mu268_4 +# 268| r268_12(glval) = VariableAddress[#return] : +# 268| v268_13(void) = ReturnValue : &:r268_12, m271_4 +# 268| v268_14(void) = UnmodeledUse : mu* +# 268| v268_15(void) = AliasedUse : ~mu268_4 +# 268| v268_16(void) = ExitFunction : diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll index 886183c32ba6..33bb0895d8c3 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll @@ -82,6 +82,7 @@ private newtype TOpcode = TSizedBufferReadSideEffect() or TSizedBufferMustWriteSideEffect() or TSizedBufferMayWriteSideEffect() or + TInitializeDynamicAllocation() or TChi() or TInlineAsm() or TUnreached() or @@ -695,6 +696,11 @@ module Opcode { final override string toString() { result = "SizedBufferMayWriteSideEffect" } } + class InitializeDynamicAllocation extends SideEffectOpcode, EntireAllocationWriteOpcode, + TInitializeDynamicAllocation { + final override string toString() { result = "InitializeDynamicAllocation" } + } + class Chi extends Opcode, TChi { final override string toString() { result = "Chi" } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index d058a6c5a3e8..d14cdf089109 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -1350,6 +1350,26 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } } +/** + * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * call to `malloc`. + */ +class InitializeDynamicAllocationInstruction extends SideEffectInstruction { + InitializeDynamicAllocationInstruction() { + getOpcode() instanceof Opcode::InitializeDynamicAllocation + } + + /** + * Gets the address of the allocation this instruction is initializing. + */ + final AddressOperand getAllocationAddressOperand() { result = getAnOperand() } + + /** + * Gets the operand for the allocation this instruction is initializing. + */ + final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() } +} + /** * An instruction representing a GNU or MSVC inline assembly statement. */ diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index d058a6c5a3e8..d14cdf089109 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -1350,6 +1350,26 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } } +/** + * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * call to `malloc`. + */ +class InitializeDynamicAllocationInstruction extends SideEffectInstruction { + InitializeDynamicAllocationInstruction() { + getOpcode() instanceof Opcode::InitializeDynamicAllocation + } + + /** + * Gets the address of the allocation this instruction is initializing. + */ + final AddressOperand getAllocationAddressOperand() { result = getAnOperand() } + + /** + * Gets the operand for the allocation this instruction is initializing. + */ + final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() } +} + /** * An instruction representing a GNU or MSVC inline assembly statement. */