Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4116c1e

Browse files
committed
JS: Add category for promise steps
1 parent f009a61 commit 4116c1e

4 files changed

Lines changed: 80 additions & 63 deletions

File tree

javascript/ql/src/semmle/javascript/Promises.qll

Lines changed: 55 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -398,70 +398,65 @@ module PromiseFlow {
398398
}
399399

400400
/**
401-
* Holds if taint propagates from `pred` to `succ` through promises.
401+
* DEPRECATED. Use `TaintTracking::promiseStep` instead.
402402
*/
403-
predicate promiseTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
404-
// from `x` to `new Promise((res, rej) => res(x))`
405-
pred = succ.(PromiseDefinition).getResolveParameter().getACall().getArgument(0)
406-
or
407-
// from `x` to `Promise.resolve(x)`
408-
pred = succ.(PromiseCreationCall).getValue() and
409-
not succ instanceof PromiseAllCreation
410-
or
411-
// from `arr` to `Promise.all(arr)`
412-
pred = succ.(PromiseAllCreation).getArrayNode()
413-
or
414-
exists(DataFlow::MethodCallNode thn | thn.getMethodName() = "then" |
415-
// from `p` to `x` in `p.then(x => ...)`
416-
pred = thn.getReceiver() and
417-
succ = thn.getCallback(0).getParameter(0)
403+
deprecated predicate promiseTaintStep = TaintTracking::promiseStep/2;
404+
405+
private class PromiseTaintStep extends TaintTracking::SharedTaintStep {
406+
override predicate promiseStep(DataFlow::Node pred, DataFlow::Node succ) {
407+
// from `x` to `new Promise((res, rej) => res(x))`
408+
pred = succ.(PromiseDefinition).getResolveParameter().getACall().getArgument(0)
418409
or
419-
// from `v` to `p.then(x => return v)`
420-
pred = thn.getCallback([0 .. 1]).getAReturn() and
421-
succ = thn
422-
)
423-
or
424-
exists(DataFlow::MethodCallNode catch | catch.getMethodName() = "catch" |
425-
// from `p` to `p.catch(..)`
426-
pred = catch.getReceiver() and
427-
succ = catch
410+
// from `x` to `Promise.resolve(x)`
411+
pred = succ.(PromiseCreationCall).getValue() and
412+
not succ instanceof PromiseAllCreation
428413
or
429-
// from `v` to `p.catch(x => return v)`
430-
pred = catch.getCallback(0).getAReturn() and
431-
succ = catch
432-
)
433-
or
434-
// from `p` to `p.finally(..)`
435-
exists(DataFlow::MethodCallNode finally | finally.getMethodName() = "finally" |
436-
pred = finally.getReceiver() and
437-
succ = finally
438-
)
439-
or
440-
// from `x` to `await x`
441-
exists(AwaitExpr await |
442-
pred.getEnclosingExpr() = await.getOperand() and
443-
succ.getEnclosingExpr() = await
444-
)
445-
or
446-
exists(DataFlow::CallNode mapSeries |
447-
mapSeries = DataFlow::moduleMember("bluebird", "mapSeries").getACall()
448-
|
449-
// from `xs` to `x` in `require("bluebird").mapSeries(xs, (x) => {...})`.
450-
pred = mapSeries.getArgument(0) and
451-
succ = mapSeries.getABoundCallbackParameter(1, 0)
414+
// from `arr` to `Promise.all(arr)`
415+
pred = succ.(PromiseAllCreation).getArrayNode()
452416
or
453-
// from `y` to `require("bluebird").mapSeries(x, x => y)`.
454-
pred = mapSeries.getCallback(1).getAReturn() and
455-
succ = mapSeries
456-
)
457-
}
458-
459-
/**
460-
* An additional taint step that involves promises.
461-
*/
462-
private class PromiseTaintStep extends TaintTracking::SharedTaintStep {
463-
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
464-
promiseTaintStep(pred, succ)
417+
exists(DataFlow::MethodCallNode thn | thn.getMethodName() = "then" |
418+
// from `p` to `x` in `p.then(x => ...)`
419+
pred = thn.getReceiver() and
420+
succ = thn.getCallback(0).getParameter(0)
421+
or
422+
// from `v` to `p.then(x => return v)`
423+
pred = thn.getCallback([0 .. 1]).getAReturn() and
424+
succ = thn
425+
)
426+
or
427+
exists(DataFlow::MethodCallNode catch | catch.getMethodName() = "catch" |
428+
// from `p` to `p.catch(..)`
429+
pred = catch.getReceiver() and
430+
succ = catch
431+
or
432+
// from `v` to `p.catch(x => return v)`
433+
pred = catch.getCallback(0).getAReturn() and
434+
succ = catch
435+
)
436+
or
437+
// from `p` to `p.finally(..)`
438+
exists(DataFlow::MethodCallNode finally | finally.getMethodName() = "finally" |
439+
pred = finally.getReceiver() and
440+
succ = finally
441+
)
442+
or
443+
// from `x` to `await x`
444+
exists(AwaitExpr await |
445+
pred.getEnclosingExpr() = await.getOperand() and
446+
succ.getEnclosingExpr() = await
447+
)
448+
or
449+
exists(DataFlow::CallNode mapSeries |
450+
mapSeries = DataFlow::moduleMember("bluebird", "mapSeries").getACall()
451+
|
452+
// from `xs` to `x` in `require("bluebird").mapSeries(xs, (x) => {...})`.
453+
pred = mapSeries.getArgument(0) and
454+
succ = mapSeries.getABoundCallbackParameter(1, 0)
455+
or
456+
// from `y` to `require("bluebird").mapSeries(x, x => y)`.
457+
pred = mapSeries.getCallback(1).getAReturn() and
458+
succ = mapSeries
459+
)
465460
}
466461
}
467462

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

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,15 @@ module TaintTracking {
288288
* data flow edge through data deserialization, such as `JSON.parse`.
289289
*/
290290
predicate deserializeStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
291+
292+
/**
293+
* Holds if `pred` → `succ` should be considered a taint-propagating
294+
* data flow edge through a promise.
295+
*
296+
* These steps consider a promise object to tainted if it can resolve to
297+
* a tainted value.
298+
*/
299+
predicate promiseStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
291300
}
292301

293302
/**
@@ -378,6 +387,18 @@ module TaintTracking {
378387
any(SharedTaintStep step).deserializeStep(pred, succ)
379388
}
380389

390+
/**
391+
* Holds if `pred` → `succ` should be considered a taint-propagating
392+
* data flow edge through data deserialization, such as `JSON.parse`.
393+
*
394+
* These steps consider a promise object to tainted if it can resolve to
395+
* a tainted value.
396+
*/
397+
cached
398+
predicate promiseStep(DataFlow::Node pred, DataFlow::Node succ) {
399+
any(SharedTaintStep step).promiseStep(pred, succ)
400+
}
401+
381402
/**
382403
* Holds if `pred -> succ` is a taint propagating data flow edge through a string operation.
383404
*/
@@ -409,7 +430,8 @@ module TaintTracking {
409430
stringConcatenationStep(pred, succ) or
410431
stringManipulationStep(pred, succ) or
411432
serializeStep(pred, succ) or
412-
deserializeStep(pred, succ)
433+
deserializeStep(pred, succ) or
434+
promiseStep(pred, succ)
413435
}
414436

415437
/**

javascript/ql/src/semmle/javascript/frameworks/Firebase.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ module Firebase {
275275
result.hasUnderlyingType("firebase", "database.DataSnapshot")
276276
)
277277
or
278-
promiseTaintStep(snapshot(t), result)
278+
TaintTracking::promiseStep(snapshot(t), result)
279279
or
280280
exists(DataFlow::TypeTracker t2 | result = snapshot(t2).track(t2, t))
281281
}

javascript/ql/src/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ module TaintedPath {
659659
)
660660
)
661661
or
662-
promiseTaintStep(src, dst) and srclabel = dstlabel
662+
TaintTracking::promiseStep(src, dst) and srclabel = dstlabel
663663
or
664664
TaintTracking::persistentStorageStep(src, dst) and srclabel = dstlabel
665665
or

0 commit comments

Comments
 (0)