Skip to content

Commit 3522200

Browse files
author
Max Schaefer
authored
Merge pull request #342 from xiemaisi/rc/1.18-cherry-picks
JavaScript: 1.18.1 cherry-picks
2 parents e2a001f + 25224cc commit 3522200

34 files changed

+374
-39
lines changed

javascript/externs/web/w3c_dom1.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@
2525

2626
/**
2727
* @constructor
28+
* @param {string=} message
29+
* @param {string=} message
2830
* @see http://www.w3.org/TR/1998/REC-DOM-Level-1-19981001/level-one-core.html#ID-17189187
2931
*/
30-
function DOMException() {}
32+
function DOMException(message, name) {}
3133

3234
/**
3335
* @type {number}

javascript/ql/src/Expressions/ImplicitOperandConversion.qhelp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ property of the name stored in variable <code>member</code>:
3939

4040
<p>
4141
However, this test is ineffective as written: the operator <code>!</code> binds more
42-
tighly than <code>in</code>, so it is applied first. Applying <code>!</code> to a
42+
tightly than <code>in</code>, so it is applied first. Applying <code>!</code> to a
4343
non-empty string yields <code>false</code>, so the <code>in</code> operator actually
4444
ends up checking whether <code>obj</code> contains a property called <code>"false"</code>.
4545
</p>

javascript/ql/src/LanguageFeatures/EmptyArrayInit.ql

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,4 @@ class OmittedArrayElement extends ArrayExpr {
4545
}
4646

4747
from OmittedArrayElement ae
48-
where not ae.getFile().getFileType().isTypeScript() // ignore quirks in TypeScript tokenizer
4948
select ae, "Avoid omitted array elements."

javascript/ql/src/LanguageFeatures/SemicolonInsertion.ql

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ where s.hasSemicolonInserted() and
3636
asi = strictcount(Stmt ss | asi(sc, ss, true)) and
3737
nstmt = strictcount(Stmt ss | asi(sc, ss, _)) and
3838
perc = ((1-asi/nstmt)*100).floor() and
39-
perc >= 90 and
40-
not s.getFile().getFileType().isTypeScript() // ignore some quirks in the TypeScript tokenizer
39+
perc >= 90
4140
select (LastLineOf)s, "Avoid automated semicolon insertion " +
4241
"(" + perc + "% of all statements in $@ have an explicit semicolon).",
4342
sc, "the enclosing " + sctype

javascript/ql/src/Security/CWE-807/ConditionalBypass.ql

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @description Conditions that the user controls are not suited for making security-related decisions.
44
* @kind problem
55
* @problem.severity error
6-
* @precision high
6+
* @precision medium
77
* @id js/user-controlled-bypass
88
* @tags security
99
* external/cwe/cwe-807
@@ -83,8 +83,32 @@ predicate isTaintedGuardForSensitiveAction(Sink sink, DataFlow::Node source, Sen
8383
)
8484
}
8585

86+
/**
87+
* Holds if `e` effectively guards access to `action` by returning or throwing early.
88+
*
89+
* Example: `if (e) return; action(x)`.
90+
*/
91+
predicate isEarlyAbortGuard(Sink e, SensitiveAction action) {
92+
exists (IfStmt guard |
93+
// `e` is in the condition of an if-statement ...
94+
e.asExpr().getParentExpr*() = guard.getCondition() and
95+
// ... where the then-branch always throws or returns
96+
exists (Stmt abort |
97+
abort instanceof ThrowStmt or
98+
abort instanceof ReturnStmt |
99+
abort.nestedIn(guard) and
100+
abort.getBasicBlock().(ReachableBasicBlock).postDominates(guard.getThen().getBasicBlock() )
101+
) and
102+
// ... and the else-branch does not exist
103+
not exists (guard.getElse()) |
104+
// ... and `action` is outside the if-statement
105+
not action.asExpr().getEnclosingStmt().nestedIn(guard)
106+
)
107+
}
108+
86109
from DataFlow::Node source, DataFlow::Node sink, SensitiveAction action
87-
where isTaintedGuardForSensitiveAction(sink, source, action)
110+
where isTaintedGuardForSensitiveAction(sink, source, action) and
111+
not isEarlyAbortGuard(sink, action)
88112
select sink, "This condition guards a sensitive $@, but $@ controls it.",
89113
action, "action",
90114
source, "a user-provided value"

javascript/ql/src/Statements/MisleadingIndentationAfterControlStmt.ql

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ where misleadingIndentationCandidate(ctrl, s1, s2) and
3939
f.hasIndentation(ctrlStartLine, indent, _) and
4040
f.hasIndentation(startLine1, indent, _) and
4141
f.hasIndentation(startLine2, indent, _) and
42-
not s2 instanceof EmptyStmt and
43-
not f.getFileType().isTypeScript() // ignore quirks in TypeScript tokenizer
42+
not s2 instanceof EmptyStmt
4443
select (FirstLineOf)s2, "The indentation of this statement suggests that it is controlled by $@, while in fact it is not.",
4544
(FirstLineOf)ctrl, "this statement"

javascript/ql/src/semmle/javascript/ES2015Modules.qll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class ES2015Module extends Module {
2727

2828
/** Gets an export declaration in this module. */
2929
ExportDeclaration getAnExport() {
30-
result.getContainer() = this
30+
result.getTopLevel() = this
3131
}
3232

3333
override Module getAnImportedModule() {
@@ -55,7 +55,7 @@ class ES2015Module extends Module {
5555
/** An import declaration. */
5656
class ImportDeclaration extends Stmt, Import, @importdeclaration {
5757
override ES2015Module getEnclosingModule() {
58-
result = getContainer()
58+
result = getTopLevel()
5959
}
6060

6161
override PathExprInModule getImportedPath() {
@@ -254,7 +254,7 @@ class BulkReExportDeclaration extends ReExportDeclaration, @exportalldeclaration
254254
* but we ignore this subtlety.
255255
*/
256256
private predicate isShadowedFromBulkExport(BulkReExportDeclaration reExport, string name) {
257-
exists (ExportNamedDeclaration other | other.getContainer() = reExport.getEnclosingModule() |
257+
exists (ExportNamedDeclaration other | other.getTopLevel() = reExport.getEnclosingModule() |
258258
other.getAnExportedDecl().getName() = name
259259
or
260260
other.getASpecifier().getExportedName() = name)

javascript/ql/src/semmle/javascript/dataflow/AbstractProperties.qll

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,7 @@ class AbstractProtoProperty extends AbstractProperty {
9696
* which in turn introduces a materialization.
9797
*/
9898
private AbstractValue getAnAssignedValue(AbstractValue b, string p) {
99-
exists (AnalyzedPropertyWrite apw, DataFlow::AnalyzedNode afn |
100-
apw.writes(b, p, afn) and
101-
result = afn.getALocalValue()
99+
exists (AnalyzedPropertyWrite apw |
100+
apw.writesValue(b, p, result)
102101
)
103102
}

javascript/ql/src/semmle/javascript/dataflow/internal/InterModuleTypeInference.qll

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,12 @@ private class AnalyzedVariableExport extends AnalyzedPropertyWrite, DataFlow::Va
268268
propName = name and
269269
source = varDef.getSource().analyze()
270270
}
271+
272+
override predicate writesValue(AbstractValue baseVal, string propName, AbstractValue val) {
273+
baseVal = TAbstractExportsObject(export.getEnclosingModule()) and
274+
propName = name and
275+
val = varDef.getAnAssignedValue()
276+
}
271277
}
272278

273279
/**
@@ -301,7 +307,7 @@ private class AnalyzedExportAssign extends AnalyzedPropertyWrite, DataFlow::Valu
301307
}
302308

303309
override predicate writes(AbstractValue baseVal, string propName, DataFlow::AnalyzedNode source) {
304-
baseVal = TAbstractModuleObject(exportAssign.getContainer()) and
310+
baseVal = TAbstractModuleObject(exportAssign.getTopLevel()) and
305311
propName = "exports" and
306312
source = this
307313
}

javascript/ql/src/semmle/javascript/dataflow/internal/InterProceduralTypeInference.qll

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -160,18 +160,26 @@ private class IIFEWithAnalyzedReturnFlow extends CallWithAnalyzedReturnFlow {
160160

161161
}
162162

163+
/**
164+
* Gets the only access to `v`, which is the variable declared by `fn`.
165+
*
166+
* This predicate is not defined for global functions `fn`, or for
167+
* local variables `v` that do not have exactly one access.
168+
*/
169+
private VarAccess getOnlyAccess(FunctionDeclStmt fn, LocalVariable v) {
170+
v = fn.getVariable() and
171+
result = v.getAnAccess() and
172+
strictcount(v.getAnAccess()) = 1
173+
}
174+
163175
/** A function that only is used locally, making it amenable to type inference. */
164176
class LocalFunction extends Function {
165177

166178
DataFlow::Impl::ExplicitInvokeNode invk;
167179

168180
LocalFunction() {
169-
this instanceof FunctionDeclStmt and
170-
exists (LocalVariable v, Expr callee |
171-
callee = invk.getCalleeNode().asExpr() and
172-
v = getVariable() and
173-
v.getAnAccess() = callee and
174-
forall(VarAccess o | o = v.getAnAccess() | o = callee) and
181+
exists (LocalVariable v |
182+
getOnlyAccess(this, v) = invk.getCalleeNode().asExpr() and
175183
not exists(v.getAnAssignedExpr()) and
176184
not exists(ExportDeclaration export | export.exportsAs(v, _))
177185
) and

0 commit comments

Comments
 (0)