Skip to content

Commit 87a1ccd

Browse files
committed
Merge branch 'main' into getRubyInSync
2 parents b2e40ac + 8c9e817 commit 87a1ccd

File tree

212 files changed

+11505
-2114
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

212 files changed

+11505
-2114
lines changed

.codeqlmanifest.json

+16-11
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
{ "provide": [ "ruby/.codeqlmanifest.json",
2-
"*/ql/src/qlpack.yml",
3-
"*/ql/lib/qlpack.yml",
4-
"*/ql/test/qlpack.yml",
5-
"cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml",
6-
"*/ql/examples/qlpack.yml",
7-
"*/upgrades/qlpack.yml",
8-
"javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml",
9-
"javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml",
10-
"misc/legacy-support/*/qlpack.yml",
11-
"misc/suite-helpers/qlpack.yml" ] }
1+
{
2+
"provide": [
3+
"*/ql/src/qlpack.yml",
4+
"*/ql/lib/qlpack.yml",
5+
"*/ql/test/qlpack.yml",
6+
"*/ql/examples/qlpack.yml",
7+
"*/upgrades/qlpack.yml",
8+
"cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml",
9+
"javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml",
10+
"javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml",
11+
"misc/legacy-support/*/qlpack.yml",
12+
"misc/suite-helpers/qlpack.yml",
13+
"ruby/ql/consistency-queries/qlpack.yml",
14+
"ruby/extractor-pack/codeql-extractor.yml"
15+
]
16+
}

.github/workflows/ruby-qltest.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
- uses: ./ruby/actions/create-extractor-pack
3333
- name: Run QL tests
3434
run: |
35-
codeql test run --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --search-path "${{ github.workspace }}/ruby" --additional-packs "${{ github.workspace }}" --consistency-queries ql/consistency-queries ql/test
35+
codeql test run --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test
3636
env:
3737
GITHUB_TOKEN: ${{ github.token }}
3838
- name: Check QL formatting

cpp/ql/lib/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll

+3-2
Original file line numberDiff line numberDiff line change
@@ -484,8 +484,9 @@ module TaintedWithPath {
484484
/** Gets the element that `pathNode` wraps, if any. */
485485
Element getElementFromPathNode(PathNode pathNode) {
486486
exists(DataFlow::Node node | node = pathNode.(WrapPathNode).inner().getNode() |
487-
result = node.asExpr() or
488-
result = node.asParameter()
487+
result = node.asInstruction().getAST()
488+
or
489+
result = node.asOperand().getDef().getAST()
489490
)
490491
or
491492
result = pathNode.(EndpointPathNode).inner()

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll

+12-16
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,7 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
806806
simpleOperandLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asOperand())
807807
or
808808
// Flow into, through, and out of store nodes
809-
StoreNodeFlow::flowInto(nodeFrom, nodeTo)
809+
StoreNodeFlow::flowInto(nodeFrom.asInstruction(), nodeTo)
810810
or
811811
StoreNodeFlow::flowThrough(nodeFrom, nodeTo)
812812
or
@@ -831,18 +831,11 @@ private predicate adjacentDefUseFlow(Node nodeFrom, Node nodeTo) {
831831
//Def-use flow
832832
Ssa::ssaFlow(nodeFrom, nodeTo)
833833
or
834-
exists(Instruction loadAddress | loadAddress = Ssa::getSourceAddressFromNode(nodeFrom) |
835-
// Use-use flow through reads
836-
exists(Node address |
837-
Ssa::addressFlowTC(address.asInstruction(), loadAddress) and
838-
Ssa::ssaFlow(address, nodeTo)
839-
)
840-
or
841-
// Use-use flow through stores.
842-
exists(Node store |
843-
Ssa::explicitWrite(_, store.asInstruction(), loadAddress) and
844-
Ssa::ssaFlow(store, nodeTo)
845-
)
834+
// Use-use flow through stores.
835+
exists(Instruction loadAddress, Node store |
836+
loadAddress = Ssa::getSourceAddressFromNode(nodeFrom) and
837+
Ssa::explicitWrite(_, store.asInstruction(), loadAddress) and
838+
Ssa::ssaFlow(store, nodeTo)
846839
)
847840
)
848841
}
@@ -906,10 +899,13 @@ private module ReadNodeFlow {
906899
}
907900
}
908901

909-
private module StoreNodeFlow {
902+
/**
903+
* INTERNAL: Do not use.
904+
*/
905+
module StoreNodeFlow {
910906
/** Holds if the store node `nodeTo` should receive flow from `nodeFrom`. */
911-
predicate flowInto(Node nodeFrom, StoreNode nodeTo) {
912-
nodeTo.flowInto(Ssa::getDestinationAddress(nodeFrom.asInstruction()))
907+
predicate flowInto(Instruction instrFrom, StoreNode nodeTo) {
908+
nodeTo.flowInto(Ssa::getDestinationAddress(instrFrom))
913909
}
914910

915911
/** Holds if the store node `nodeTo` should receive flow from `nodeFom`. */

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll

+26
Original file line numberDiff line numberDiff line change
@@ -634,3 +634,29 @@ class UncertainWriteDefinition extends WriteDefinition {
634634
)
635635
}
636636
}
637+
638+
/** Provides a set of consistency queries. */
639+
module Consistency {
640+
abstract class RelevantDefinition extends Definition {
641+
abstract predicate hasLocationInfo(
642+
string filepath, int startline, int startcolumn, int endline, int endcolumn
643+
);
644+
}
645+
646+
query predicate nonUniqueDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
647+
ssaDefReachesRead(v, def, bb, i) and
648+
not exists(unique(Definition def0 | ssaDefReachesRead(v, def0, bb, i)))
649+
}
650+
651+
query predicate readWithoutDef(SourceVariable v, BasicBlock bb, int i) {
652+
variableRead(bb, i, v, _) and
653+
not ssaDefReachesRead(v, _, bb, i)
654+
}
655+
656+
query predicate deadDef(RelevantDefinition def, SourceVariable v) {
657+
v = def.getSourceVariable() and
658+
not ssaDefReachesRead(_, def, _, _) and
659+
not phiHasInputFromBlock(_, def, _) and
660+
not uncertainWriteDefinitionInput(_, def)
661+
}
662+
}

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll

+59-20
Original file line numberDiff line numberDiff line change
@@ -244,17 +244,6 @@ Instruction getDestinationAddress(Instruction instr) {
244244
]
245245
}
246246

247-
class ReferenceToInstruction extends CopyValueInstruction {
248-
ReferenceToInstruction() {
249-
this.getResultType() instanceof Cpp::ReferenceType and
250-
not this.getUnary().getResultType() instanceof Cpp::ReferenceType
251-
}
252-
253-
Instruction getSourceAddress() { result = getSourceAddressOperand().getDef() }
254-
255-
Operand getSourceAddressOperand() { result = this.getUnaryOperand() }
256-
}
257-
258247
/** Gets the source address of `instr` if it is an instruction that behaves like a `LoadInstruction`. */
259248
Instruction getSourceAddress(Instruction instr) { result = getSourceAddressOperand(instr).getDef() }
260249

@@ -266,11 +255,7 @@ Operand getSourceAddressOperand(Instruction instr) {
266255
result =
267256
[
268257
instr.(LoadInstruction).getSourceAddressOperand(),
269-
instr.(ReadSideEffectInstruction).getArgumentOperand(),
270-
// `ReferenceToInstruction` is really more of an address-of operation,
271-
// but by including it in this list we break out of `flowOutOfAddressStep` at an
272-
// instruction that, at the source level, looks like a use of a variable.
273-
instr.(ReferenceToInstruction).getSourceAddressOperand()
258+
instr.(ReadSideEffectInstruction).getArgumentOperand()
274259
]
275260
}
276261

@@ -295,10 +280,6 @@ Operand getSourceValueOperand(Instruction instr) {
295280
result = instr.(LoadInstruction).getSourceValueOperand()
296281
or
297282
result = instr.(ReadSideEffectInstruction).getSideEffectOperand()
298-
or
299-
// See the comment on the `ReferenceToInstruction` disjunct in `getSourceAddressOperand` for why
300-
// this case is included.
301-
result = instr.(ReferenceToInstruction).getSourceValueOperand()
302283
}
303284

304285
/**
@@ -513,6 +494,64 @@ private module Cached {
513494
explicitWrite(false, storeNode.getStoreInstruction(), def)
514495
)
515496
or
497+
// The destination of a store operation has undergone lvalue-to-rvalue conversion and is now a
498+
// right-hand-side of a store operation.
499+
// Find the next use of the variable in that store operation, and recursively find the load of that
500+
// pointer. For example, consider this case:
501+
//
502+
// ```cpp
503+
// int x = source();
504+
// int* p = &x;
505+
// sink(*p);
506+
// ```
507+
//
508+
// if we want to find the load of the address of `x`, we see that the pointer is stored into `p`,
509+
// and we then need to recursively look for the load of `p`.
510+
exists(
511+
Def def, StoreInstruction store, IRBlock block1, int rnk1, Use use, IRBlock block2, int rnk2
512+
|
513+
store = def.getInstruction() and
514+
store.getSourceValueOperand() = operand and
515+
def.hasRankInBlock(block1, rnk1) and
516+
use.hasRankInBlock(block2, rnk2) and
517+
adjacentDefRead(_, block1, rnk1, block2, rnk2)
518+
|
519+
// The shared SSA library has determined that `use` is the next use of the operand
520+
// so we find the next load of that use (but only if there is no `PostUpdateNode`) we
521+
// need to flow into first.
522+
not StoreNodeFlow::flowInto(store, _) and
523+
flowOutOfAddressStep(use.getOperand(), nodeTo)
524+
or
525+
// It may also be the case that `store` gives rise to another store step. So let's make sure that
526+
// we also take those into account.
527+
StoreNodeFlow::flowInto(store, nodeTo)
528+
)
529+
or
530+
// As we find the next load of an address, we might come across another use of the same variable.
531+
// In that case, we recursively find the next use of _that_ operand, and continue searching for
532+
// the next load of that operand. For example, consider this case:
533+
//
534+
// ```cpp
535+
// int x = source();
536+
// use(&x);
537+
// int* p = &x;
538+
// sink(*p);
539+
// ```
540+
//
541+
// The next use of `x` after its definition is `use(&x)`, but there is a later load of the address
542+
// of `x` that we want to flow to. So we use the shared SSA library to find the next load.
543+
not operand = getSourceAddressOperand(_) and
544+
exists(Use use1, Use use2, IRBlock block1, int rnk1, IRBlock block2, int rnk2 |
545+
use1.getOperand() = operand and
546+
use1.hasRankInBlock(block1, rnk1) and
547+
// Don't flow to the next use if this use is part of a store operation that totally
548+
// overrides a variable.
549+
not explicitWrite(true, _, use1.getOperand().getDef()) and
550+
adjacentDefRead(_, block1, rnk1, block2, rnk2) and
551+
use2.hasRankInBlock(block2, rnk2) and
552+
flowOutOfAddressStep(use2.getOperand(), nodeTo)
553+
)
554+
or
516555
operand = getSourceAddressOperand(nodeTo.asInstruction())
517556
or
518557
exists(ReturnIndirectionInstruction ret |

cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll

+24-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ private import internal.OperandInternal
2020
private class TStageOperand =
2121
TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand;
2222

23+
/**
24+
* A known location. Testing `loc instanceof KnownLocation` will account for non existing locations, as
25+
* opposed to testing `not loc isntanceof UnknownLocation`
26+
*/
27+
private class KnownLocation extends Language::Location {
28+
KnownLocation() { not this instanceof Language::UnknownLocation }
29+
}
30+
2331
/**
2432
* An operand of an `Instruction`. The operand represents a use of the result of one instruction
2533
* (the defining instruction) in another instruction (the use instruction)
@@ -45,8 +53,10 @@ class Operand extends TStageOperand {
4553

4654
/**
4755
* Gets the location of the source code for this operand.
56+
* By default this is where the operand is used, but some subclasses may override this
57+
* using `getAnyDef()` if it makes more sense.
4858
*/
49-
final Language::Location getLocation() { result = this.getUse().getLocation() }
59+
Language::Location getLocation() { result = this.getUse().getLocation() }
5060

5161
/**
5262
* Gets the function that contains this operand.
@@ -269,6 +279,10 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand {
269279

270280
final override string toString() { result = tag.toString() }
271281

282+
// most `RegisterOperands` have a more meaningful location at the definition
283+
// the only exception are specific cases of `ThisArgumentOperand`
284+
override Language::Location getLocation() { result = this.getAnyDef().getLocation() }
285+
272286
final override Instruction getAnyDef() { result = defInstr }
273287

274288
final override Overlap getDefinitionOverlap() {
@@ -401,11 +415,19 @@ class ArgumentOperand extends RegisterOperand {
401415
}
402416

403417
/**
404-
* An operand representing the implicit 'this' argument to a member function
418+
* An operand representing the implicit `this` argument to a member function
405419
* call.
406420
*/
407421
class ThisArgumentOperand extends ArgumentOperand {
408422
override ThisArgumentOperandTag tag;
423+
424+
// in most cases the def location makes more sense, but in some corner cases it
425+
// has an unknown location: in those cases we fall back to the use location
426+
override Language::Location getLocation() {
427+
if this.getAnyDef().getLocation() instanceof KnownLocation
428+
then result = this.getAnyDef().getLocation()
429+
else result = this.getUse().getLocation()
430+
}
409431
}
410432

411433
/**

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Operand.qll

+24-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ private import internal.OperandInternal
2020
private class TStageOperand =
2121
TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand;
2222

23+
/**
24+
* A known location. Testing `loc instanceof KnownLocation` will account for non existing locations, as
25+
* opposed to testing `not loc isntanceof UnknownLocation`
26+
*/
27+
private class KnownLocation extends Language::Location {
28+
KnownLocation() { not this instanceof Language::UnknownLocation }
29+
}
30+
2331
/**
2432
* An operand of an `Instruction`. The operand represents a use of the result of one instruction
2533
* (the defining instruction) in another instruction (the use instruction)
@@ -45,8 +53,10 @@ class Operand extends TStageOperand {
4553

4654
/**
4755
* Gets the location of the source code for this operand.
56+
* By default this is where the operand is used, but some subclasses may override this
57+
* using `getAnyDef()` if it makes more sense.
4858
*/
49-
final Language::Location getLocation() { result = this.getUse().getLocation() }
59+
Language::Location getLocation() { result = this.getUse().getLocation() }
5060

5161
/**
5262
* Gets the function that contains this operand.
@@ -269,6 +279,10 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand {
269279

270280
final override string toString() { result = tag.toString() }
271281

282+
// most `RegisterOperands` have a more meaningful location at the definition
283+
// the only exception are specific cases of `ThisArgumentOperand`
284+
override Language::Location getLocation() { result = this.getAnyDef().getLocation() }
285+
272286
final override Instruction getAnyDef() { result = defInstr }
273287

274288
final override Overlap getDefinitionOverlap() {
@@ -401,11 +415,19 @@ class ArgumentOperand extends RegisterOperand {
401415
}
402416

403417
/**
404-
* An operand representing the implicit 'this' argument to a member function
418+
* An operand representing the implicit `this` argument to a member function
405419
* call.
406420
*/
407421
class ThisArgumentOperand extends ArgumentOperand {
408422
override ThisArgumentOperandTag tag;
423+
424+
// in most cases the def location makes more sense, but in some corner cases it
425+
// has an unknown location: in those cases we fall back to the use location
426+
override Language::Location getLocation() {
427+
if this.getAnyDef().getLocation() instanceof KnownLocation
428+
then result = this.getAnyDef().getLocation()
429+
else result = this.getUse().getLocation()
430+
}
409431
}
410432

411433
/**

0 commit comments

Comments
 (0)