Merge branch 'main' into js/case-sensitive-middleware

This commit is contained in:
Asger F
2022-07-14 09:38:35 +02:00
committed by GitHub
748 changed files with 15085 additions and 4847 deletions

View File

@@ -1,3 +1,10 @@
## 0.2.0
### Minor Analysis Improvements
* The `js/resource-exhaustion` query no longer treats the 3-argument version of `Buffer.from` as a sink,
since it does not allocate a new buffer.
## 0.1.4
## 0.1.3

View File

@@ -154,7 +154,7 @@ predicate maybeAssignsAccessedPropInBlock(DataFlow::PropWrite assign, boolean af
*/
private module PurityCheck {
/**
* Holds if a ControlFlowNode `c` is before an impure expression inside `bb`.
* Holds if `write` is before an impure expression inside `bb`.
*/
predicate isBeforeImpure(DataFlow::PropWrite write, ReachableBasicBlock bb) {
getANodeAfterWrite(write, bb).(Expr).isImpure()
@@ -181,7 +181,7 @@ private module PurityCheck {
}
/**
* Holds if a ControlFlowNode `c` is after an impure expression inside `bb`.
* Holds if `write` is after an impure expression inside `bb`.
*/
predicate isAfterImpure(DataFlow::PropWrite write, ReachableBasicBlock bb) {
getANodeBeforeWrite(write, bb).(Expr).isImpure()

View File

@@ -10,7 +10,7 @@
*/
import javascript
private import Declarations
private import Declarations.Declarations
from VarAccess acc, VarDecl decl, Variable var, StmtContainer sc
where

View File

@@ -1,61 +0,0 @@
/**
* Provides predicates for finding variable references and declarations
* in a given function or toplevel.
*/
import javascript
/**
* Classification of variable references; all references have kind `Ref`,
* but only declarations have kind `Decl`.
*
* Note that references that are not declarations are called accesses elsewhere,
* but they are not treated specially in this context.
*/
newtype RefKind =
Ref() or
Decl()
/**
* Gets a reference to `var` (if `kind` is `Ref()`) or declaration of
* `var` (if `kind` is `Decl()`) in `sc`.
*/
VarRef refInContainer(Variable var, RefKind kind, StmtContainer sc) {
result.getVariable() = var and
result.getContainer() = sc and
(kind = Decl() implies result instanceof VarDecl)
}
/**
* Gets the textually first reference to `var` (if `kind` is `Ref()`) or
* declaration of `var` (if `kind` is `Decl()`) in `sc`.
*/
VarRef firstRefInContainer(Variable var, RefKind kind, StmtContainer sc) {
result =
min(refInContainer(var, kind, sc) as ref
order by
ref.getLocation().getStartLine(), ref.getLocation().getStartColumn()
)
}
/**
* Gets a reference to `var` (if `kind` is `Ref()`) or declaration of
* `var` (if `kind` is `Decl()`) in `tl`.
*/
VarRef refInTopLevel(Variable var, RefKind kind, TopLevel tl) {
result.getVariable() = var and
result.getTopLevel() = tl and
(kind = Decl() implies result instanceof VarDecl)
}
/**
* Gets the textually first reference to `var` (if `kind` is `Ref()`) or
* declaration of `var` (if `kind` is `Decl()`) in `tl`.
*/
VarRef firstRefInTopLevel(Variable var, RefKind kind, TopLevel tl) {
result =
min(refInTopLevel(var, kind, tl) as ref
order by
ref.getLocation().getStartLine(), ref.getLocation().getStartColumn()
)
}

View File

@@ -10,7 +10,7 @@
*/
import javascript
private import Declarations
private import Declarations.Declarations
from Variable v, TopLevel tl, VarDecl decl, VarDecl redecl
where

View File

@@ -5793,6 +5793,8 @@ predicate typos(string wrong, string right) {
or
wrong = "paramters" and right = "parameters"
or
wrong = "parametarized" and right = "parameterized"
or
wrong = "paranthesis" and right = "parenthesis"
or
wrong = "paraphenalia" and right = "paraphernalia"

View File

@@ -1,22 +0,0 @@
/**
* Provides shared predicates related to contextual queries in the code viewer.
*/
import semmle.files.FileSystem
/**
* Returns the `File` matching the given source file name as encoded by the VS
* Code extension.
*/
cached
File getFileBySourceArchiveName(string name) {
// The name provided for a file in the source archive by the VS Code extension
// has some differences from the absolute path in the database:
// 1. colons are replaced by underscores
// 2. there's a leading slash, even for Windows paths: "C:/foo/bar" ->
// "/C_/foo/bar"
// 3. double slashes in UNC prefixes are replaced with a single slash
// We can handle 2 and 3 together by unconditionally adding a leading slash
// before replacing double slashes.
name = ("/" + result.getAbsolutePath().replaceAll(":", "_")).replaceAll("//", "/")
}

View File

@@ -84,10 +84,10 @@ predicate hasObjectProvidingTemplateVariables(CandidateStringLiteral lit) {
* Gets a declaration of variable `v` in `tl`, where `v` has the given `name` and
* belongs to `scope`.
*/
VarDecl getDeclIn(Variable v, Scope s, string name, CandidateTopLevel tl) {
VarDecl getDeclIn(Variable v, Scope scope, string name, CandidateTopLevel tl) {
v.getName() = name and
v.getADeclaration() = result and
v.getScope() = s and
v.getScope() = scope and
result.getTopLevel() = tl
}

View File

@@ -6,7 +6,7 @@
import javascript
/**
* Holds if `nd` is a use of a feature introduced in ECMAScript version `ver`
* Holds if `nd` is a use of a feature introduced in ECMAScript `version`
* from the given category.
*
* Categories are taken from Kangax' [ECMAScript 6 compatibility table]

View File

@@ -16,14 +16,14 @@ import javascript
/**
* Holds if `assign` assigns the value of `nd` to `exportsVar`, which is an `exports` variable
*/
predicate exportsAssign(Assignment assgn, Variable exportsVar, DataFlow::Node nd) {
predicate exportsAssign(Assignment assign, Variable exportsVar, DataFlow::Node nd) {
exists(NodeModule m |
exportsVar = m.getScope().getVariable("exports") and
assgn.getLhs() = exportsVar.getAnAccess() and
nd = assgn.getRhs().flow()
assign.getLhs() = exportsVar.getAnAccess() and
nd = assign.getRhs().flow()
)
or
exportsAssign(assgn, exportsVar, nd.getASuccessor())
exportsAssign(assign, exportsVar, nd.getASuccessor())
}
/**

View File

@@ -39,10 +39,10 @@ RegExpTerm getEffectiveRoot(RegExpTerm actualRoot) {
/**
* Holds if `term` contains an anchor on both ends.
*/
predicate isPossiblyAnchoredOnBothEnds(RegExpSequence node) {
node.getAChild*() instanceof RegExpCaret and
node.getAChild*() instanceof RegExpDollar and
node.getNumChild() >= 2
predicate isPossiblyAnchoredOnBothEnds(RegExpSequence term) {
term.getAChild*() instanceof RegExpCaret and
term.getAChild*() instanceof RegExpDollar and
term.getNumChild() >= 2
}
/**

View File

@@ -53,7 +53,7 @@ predicate matchesBeginningOfString(RegExpTerm term) {
}
/**
* Holds if the given sequence contains top-level domain preceded by a dot, such as `.com`,
* Holds if the given sequence `seq` contains top-level domain preceded by a dot, such as `.com`,
* excluding cases where this is at the very beginning of the regexp.
*
* `i` is bound to the index of the last child in the top-level domain part.

View File

@@ -109,8 +109,8 @@ DataFlow::Node schemeCheck(DataFlow::Node nd, DangerousScheme scheme) {
}
/** Gets a data-flow node that checks an instance of `ap` against the given `scheme`. */
DataFlow::Node schemeCheckOn(DataFlow::SourceNode root, string path, DangerousScheme scheme) {
result = schemeCheck(AccessPath::getAReferenceTo(root, path), scheme)
DataFlow::Node schemeCheckOn(DataFlow::SourceNode root, string ap, DangerousScheme scheme) {
result = schemeCheck(AccessPath::getAReferenceTo(root, ap), scheme)
}
from DataFlow::SourceNode root, string path, int n

View File

@@ -84,7 +84,7 @@ class LiteralLengthExpr extends DotExpr {
}
/**
* Holds if `length` is derived from the length of the given `indexOf`-operand.
* Holds if `length` is derived from the length of the given indexOf `operand`.
*/
predicate isDerivedFromLength(DataFlow::Node length, DataFlow::Node operand) {
exists(IndexOfCall call | operand = call.getAnOperand() |

View File

@@ -72,11 +72,11 @@ pragma[noinline]
Folder getAPackageJsonFolder() { result = any(PackageJson json).getFile().getParentContainer() }
/**
* Gets a reference to `dirname`, the home folder, the current working folder, or the root folder.
* Gets a reference to a directory that has a `package.json` in the same folder, the home folder,
* the current working folder, or the root folder.
* All of these might cause information to be leaked.
*
* For `dirname` that can happen if there is a `package.json` file in the same folder.
* It is assumed that the presence of a `package.json` file means that a `node_modules` folder can also exist.
* For the first case it is assumed that the presence of a `package.json` file means that a `node_modules` folder can also exist.
*
* For the root/home/working folder, they contain so much information that they must leak information somehow (e.g. ssh keys in the `~/.ssh` folder).
*/
@@ -108,7 +108,7 @@ DataFlow::Node getALeakingFolder(string description) {
}
/**
* Gets a data-flow node that represents a path to the private folder `path`.
* Gets a data-flow node that represents the private folder descriped by `description`.
*/
DataFlow::Node getAPrivateFolderPath(string description) {
exists(string path |
@@ -119,7 +119,7 @@ DataFlow::Node getAPrivateFolderPath(string description) {
}
/**
* Gest a call that serves the folder `path` to the public.
* Gest a call that serves the folder descriped by `description` to the public.
*/
DataFlow::CallNode servesAPrivateFolder(string description) {
result = DataFlow::moduleMember(["express", "connect"], "static").getACall() and

View File

@@ -34,7 +34,7 @@ predicate isLoginSetup(Express::RouteSetup setup) {
}
/**
* Holds if `handler` regenerates its session using `req.session.regenerate`.
* Holds if `setup` regenerates its session using `req.session.regenerate`.
*/
pragma[inline]
predicate regeneratesSession(Express::RouteSetup setup) {

View File

@@ -0,0 +1,4 @@
---
category: breaking
---
* Contextual queries and the query libraries they depend on have been moved to the `codeql/javascript-all` package.

View File

@@ -1,5 +1,6 @@
---
category: minorAnalysis
---
## 0.2.0
### Minor Analysis Improvements
* The `js/resource-exhaustion` query no longer treats the 3-argument version of `Buffer.from` as a sink,
since it does not allocate a new buffer.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.1.4
lastReleaseVersion: 0.2.0

View File

@@ -1,13 +0,0 @@
/**
* @name Jump-to-definition links
* @description Generates use-definition pairs that provide the data
* for jump-to-definition in the code viewer.
* @kind definitions
* @id js/jump-to-definition
*/
import definitions
from Locatable e, AstNode def, string kind
where def = definitionOf(e, kind)
select e, def, kind

View File

@@ -1,181 +0,0 @@
/**
* Provides classes and predicates related to jump-to-definition links
* in the code viewer.
*/
import javascript
import IDEContextual
private import Declarations.Declarations
/**
* Gets the kind of reference that `r` represents.
*
* References in callee position have kind `"M"` (for "method"), all
* others have kind `"V"` (for "variable").
*
* For example, in the expression `f(x)`, `f` has kind `"M"` while
* `x` has kind `"V"`.
*/
private string refKind(RefExpr r) {
if exists(InvokeExpr invk | r = invk.getCallee().getUnderlyingReference())
then result = "M"
else result = "V"
}
/**
* Gets a class, function or object literal `va` may refer to.
*/
private AstNode lookupDef(VarAccess va) {
exists(AbstractValue av | av = va.analyze().getAValue() |
result = av.(AbstractClass).getClass() or
result = av.(AbstractFunction).getFunction() or
result = av.(AbstractObjectLiteral).getObjectExpr()
)
}
/**
* Holds if `va` is of kind `kind` and `def` is the unique class,
* function or object literal it refers to.
*/
private predicate variableDefLookup(VarAccess va, AstNode def, string kind) {
count(lookupDef(va)) = 1 and
def = lookupDef(va) and
kind = refKind(va)
}
/**
* Holds if variable access `va` is of kind `kind` and refers to the
* variable declaration.
*
* For example, in the statement `var x = 42, y = x;`, the initializing
* expression of `y` is a variable access `x` of kind `"V"` that refers to
* the declaration `x = 42`.
*/
private predicate variableDeclLookup(VarAccess va, VarDecl decl, string kind) {
// restrict to declarations in same file to avoid accidentally picking up
// unrelated global definitions
decl = firstRefInTopLevel(va.getVariable(), Decl(), va.getTopLevel()) and
kind = refKind(va)
}
/**
* Holds if path expression `path`, which appears in a CommonJS `require`
* call or an ES 2015 import statement, imports module `target`; `kind`
* is always "I" (for "import").
*
* For example, in the statement `var a = require("./a")`, the path expression
* `"./a"` imports a module `a` in the same folder.
*/
private predicate importLookup(AstNode path, Module target, string kind) {
kind = "I" and
(
exists(Import i |
path = i.getImportedPath() and
target = i.getImportedModule()
)
or
exists(ReExportDeclaration red |
path = red.getImportedPath() and
target = red.getReExportedModule()
)
)
}
/**
* Gets a node that may write the property read by `prn`.
*/
private AstNode getAWrite(DataFlow::PropRead prn) {
exists(DataFlow::AnalyzedNode base, DefiniteAbstractValue baseVal, string propName |
base = prn.getBase() and
propName = prn.getPropertyName() and
baseVal = base.getAValue().getAPrototype*()
|
// write to a property on baseVal
exists(AnalyzedPropertyWrite apw |
result = apw.getAstNode() and
apw.writes(baseVal, propName, _)
)
or
// non-static class members aren't covered by `AnalyzedPropWrite`, so have to be handled
// separately
exists(ClassDefinition c, MemberDefinition m |
m = c.getMember(propName) and
baseVal.(AbstractInstance).getConstructor().(AbstractClass).getClass() = c and
result = m.getNameExpr()
)
)
}
/**
* Holds if `prop` is the property name expression of a property read that
* may read the property written by `write`. Furthermore, `write` must be the
* only such property write. Parameter `kind` is always bound to `"M"`
* at the moment.
*/
private predicate propertyLookup(Expr prop, AstNode write, string kind) {
exists(DataFlow::PropRead prn | prop = prn.getPropertyNameExpr() |
count(getAWrite(prn)) = 1 and
write = getAWrite(prn) and
kind = "M"
)
}
/**
* Holds if `ref` is an identifier that refers to a type declared at `decl`.
*/
private predicate typeLookup(AstNode ref, AstNode decl, string kind) {
exists(TypeAccess typeAccess |
ref = typeAccess.getIdentifier() and
decl = typeAccess.getTypeName().getADefinition() and
kind = "T"
)
}
/**
* Holds if `ref` is the callee name of an invocation of `decl`.
*/
private predicate typedInvokeLookup(AstNode ref, AstNode decl, string kind) {
not variableDefLookup(ref, decl, _) and
not propertyLookup(ref, decl, _) and
exists(InvokeExpr invoke, Expr callee |
callee = invoke.getCallee().getUnderlyingReference() and
(ref = callee.(Identifier) or ref = callee.(DotExpr).getPropertyNameExpr()) and
decl = invoke.getResolvedCallee() and
kind = "M"
)
}
/**
* Holds if `ref` is a JSDoc type annotation referring to a class defined at `decl`.
*/
private predicate jsdocTypeLookup(JSDocNamedTypeExpr ref, AstNode decl, string kind) {
decl = ref.getClass().getAstNode() and
kind = "T"
}
/**
* Gets an element, of kind `kind`, that element `e` uses, if any.
*
* The `kind` is a string representing what kind of use it is:
* - `"M"` for function and method calls
* - `"T"` for uses of types
* - `"V"` for variable accesses
* - `"I"` for imports
*/
cached
AstNode definitionOf(Locatable e, string kind) {
variableDefLookup(e, result, kind)
or
// prefer definitions over declarations
not variableDefLookup(e, _, _) and variableDeclLookup(e, result, kind)
or
importLookup(e, result, kind)
or
propertyLookup(e, result, kind)
or
typeLookup(e, result, kind)
or
typedInvokeLookup(e, result, kind)
or
jsdocTypeLookup(e, result, kind)
}

View File

@@ -5,8 +5,8 @@ import semmle.javascript.Files
/**
* Holds if `id` in the opaque identifier of a result reported by query `queryPath`,
* such that `message` is the associated message and the location of the result spans
* column `startcolumn` of line `startline` to column `endcolumn` of line `endline`
* in file `filepath`.
* column `startcol` of line `startline` to column `endcol` of line `endline`
* in `file`.
*
* For more information, see [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/

View File

@@ -5,8 +5,8 @@ import javascript
/**
* Holds if `id` in the opaque identifier of a result reported by query `queryPath`,
* such that `value` is the reported metric value and the location of the result spans
* column `startcolumn` of line `startline` to column `endcolumn` of line `endline`
* in file `filepath`.
* column `startcol` of line `startline` to column `endcol` of line `endline`
* in `file`.
*
* For more information, see [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/

View File

@@ -1,16 +0,0 @@
/**
* @name Jump-to-definition links
* @description Generates use-definition pairs that provide the data
* for jump-to-definition in the code viewer.
* @kind definitions
* @id js/ide-jump-to-definition
* @tags ide-contextual-queries/local-definitions
*/
import definitions
external string selectedSourceFile();
from Locatable e, AstNode def, string kind
where def = definitionOf(e, kind) and e.getFile() = getFileBySourceArchiveName(selectedSourceFile())
select e, def, kind

View File

@@ -1,17 +0,0 @@
/**
* @name Find-references links
* @description Generates use-definition pairs that provide the data
* for find-references in the code viewer.
* @kind definitions
* @id js/ide-find-references
* @tags ide-contextual-queries/local-references
*/
import definitions
external string selectedSourceFile();
from Locatable e, AstNode def, string kind
where
def = definitionOf(e, kind) and def.getFile() = getFileBySourceArchiveName(selectedSourceFile())
select e, def, kind

View File

@@ -1,28 +0,0 @@
/**
* @name Print AST
* @description Outputs a representation of a file's Abstract Syntax Tree. This
* query is used by the VS Code extension.
* @id js/print-ast
* @kind graph
* @tags ide-contextual-queries/print-ast
*/
import javascript
import semmle.javascript.PrintAst
import definitions
/**
* Gets the source file to generate an AST from.
*/
external string selectedSourceFile();
class PrintAstConfigurationOverride extends PrintAstConfiguration {
/**
* Holds if the location matches the selected file in the VS Code extension and
* the element is not a synthetic constructor.
*/
override predicate shouldPrint(Locatable e, Location l) {
super.shouldPrint(e, l) and
l.getFile() = getFileBySourceArchiveName(selectedSourceFile())
}
}

View File

@@ -1,5 +1,5 @@
name: codeql/javascript-queries
version: 0.2.0-dev
version: 0.2.1-dev
groups:
- javascript
- queries