mirror of
https://github.com/github/codeql.git
synced 2026-05-02 20:25:13 +02:00
C++: Restore the missing flow. This has a couple of side-effects: First, it gives us some new good flow (yay). Second, it causes some duplication of results that uses 'argv' as a taint source. The duplication isn't very bad, though. And since it is only for paths that start at 'argv', I think we can live with it for now.
This commit is contained in:
@@ -806,7 +806,7 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
simpleOperandLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asOperand())
|
||||
or
|
||||
// Flow into, through, and out of store nodes
|
||||
StoreNodeFlow::flowInto(nodeFrom, nodeTo)
|
||||
StoreNodeFlow::flowInto(nodeFrom.asInstruction(), nodeTo)
|
||||
or
|
||||
StoreNodeFlow::flowThrough(nodeFrom, nodeTo)
|
||||
or
|
||||
@@ -831,18 +831,11 @@ private predicate adjacentDefUseFlow(Node nodeFrom, Node nodeTo) {
|
||||
//Def-use flow
|
||||
Ssa::ssaFlow(nodeFrom, nodeTo)
|
||||
or
|
||||
exists(Instruction loadAddress | loadAddress = Ssa::getSourceAddressFromNode(nodeFrom) |
|
||||
// Use-use flow through reads
|
||||
exists(Node address |
|
||||
Ssa::addressFlowTC(address.asInstruction(), loadAddress) and
|
||||
Ssa::ssaFlow(address, nodeTo)
|
||||
)
|
||||
or
|
||||
// Use-use flow through stores.
|
||||
exists(Node store |
|
||||
Ssa::explicitWrite(_, store.asInstruction(), loadAddress) and
|
||||
Ssa::ssaFlow(store, nodeTo)
|
||||
)
|
||||
// Use-use flow through stores.
|
||||
exists(Instruction loadAddress, Node store |
|
||||
loadAddress = Ssa::getSourceAddressFromNode(nodeFrom) and
|
||||
Ssa::explicitWrite(_, store.asInstruction(), loadAddress) and
|
||||
Ssa::ssaFlow(store, nodeTo)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -906,10 +899,13 @@ private module ReadNodeFlow {
|
||||
}
|
||||
}
|
||||
|
||||
private module StoreNodeFlow {
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
module StoreNodeFlow {
|
||||
/** Holds if the store node `nodeTo` should receive flow from `nodeFrom`. */
|
||||
predicate flowInto(Node nodeFrom, StoreNode nodeTo) {
|
||||
nodeTo.flowInto(Ssa::getDestinationAddress(nodeFrom.asInstruction()))
|
||||
predicate flowInto(Instruction instrFrom, StoreNode nodeTo) {
|
||||
nodeTo.flowInto(Ssa::getDestinationAddress(instrFrom))
|
||||
}
|
||||
|
||||
/** Holds if the store node `nodeTo` should receive flow from `nodeFom`. */
|
||||
|
||||
@@ -494,6 +494,64 @@ private module Cached {
|
||||
explicitWrite(false, storeNode.getStoreInstruction(), def)
|
||||
)
|
||||
or
|
||||
// The destination of a store operation has undergone lvalue-to-rvalue conversion and is now a
|
||||
// right-hand-side of a store operation.
|
||||
// Find the next use of the variable in that store operation, and recursively find the load of that
|
||||
// pointer. For example, consider this case:
|
||||
//
|
||||
// ```cpp
|
||||
// int x = source();
|
||||
// int* p = &x;
|
||||
// sink(*p);
|
||||
// ```
|
||||
//
|
||||
// if we want to find the load of the address of `x`, we see that the pointer is stored into `p`,
|
||||
// and we then need to recursively look for the load of `p`.
|
||||
exists(
|
||||
Def def, StoreInstruction store, IRBlock block1, int rnk1, Use use, IRBlock block2, int rnk2
|
||||
|
|
||||
store = def.getInstruction() and
|
||||
store.getSourceValueOperand() = operand and
|
||||
def.hasRankInBlock(block1, rnk1) and
|
||||
use.hasRankInBlock(block2, rnk2) and
|
||||
adjacentDefRead(_, block1, rnk1, block2, rnk2)
|
||||
|
|
||||
// The shared SSA library has determined that `use` is the next use of the operand
|
||||
// so we find the next load of that use (but only if there is no `PostUpdateNode`) we
|
||||
// need to flow into first.
|
||||
not StoreNodeFlow::flowInto(store, _) and
|
||||
flowOutOfAddressStep(use.getOperand(), nodeTo)
|
||||
or
|
||||
// It may also be the case that `store` gives rise to another store step. So let's make sure that
|
||||
// we also take those into account.
|
||||
StoreNodeFlow::flowInto(store, nodeTo)
|
||||
)
|
||||
or
|
||||
// As we find the next load of an address, we might come across another use of the same variable.
|
||||
// In that case, we recursively find the next use of _that_ operand, and continue searching for
|
||||
// the next load of that operand. For example, consider this case:
|
||||
//
|
||||
// ```cpp
|
||||
// int x = source();
|
||||
// use(&x);
|
||||
// int* p = &x;
|
||||
// sink(*p);
|
||||
// ```
|
||||
//
|
||||
// The next use of `x` after its definition is `use(&x)`, but there is a later load of the address
|
||||
// of `x` that we want to flow to. So we use the shared SSA library to find the next load.
|
||||
not operand = getSourceAddressOperand(_) and
|
||||
exists(Use use1, Use use2, IRBlock block1, int rnk1, IRBlock block2, int rnk2 |
|
||||
use1.getOperand() = operand and
|
||||
use1.hasRankInBlock(block1, rnk1) and
|
||||
// Don't flow to the next use if this use is part of a store operation that totally
|
||||
// overrides a variable.
|
||||
not explicitWrite(true, _, use1.getOperand().getDef()) and
|
||||
adjacentDefRead(_, block1, rnk1, block2, rnk2) and
|
||||
use2.hasRankInBlock(block2, rnk2) and
|
||||
flowOutOfAddressStep(use2.getOperand(), nodeTo)
|
||||
)
|
||||
or
|
||||
operand = getSourceAddressOperand(nodeTo.asInstruction())
|
||||
or
|
||||
exists(ReturnIndirectionInstruction ret |
|
||||
|
||||
Reference in New Issue
Block a user