Skip to content

Commit c357074

Browse files
committed
Fixing fs and rasp/iast problems
1 parent fd626ea commit c357074

File tree

4 files changed

+53
-12
lines changed

4 files changed

+53
-12
lines changed

packages/dd-trace/src/appsec/rasp/fs-plugin.js

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,27 @@ const enabledFor = {
1414

1515
let fsPlugin
1616

17-
function enterWith (fsProps, store = storage('legacy').getStore()) {
17+
function storeToStart (fsProps, store = storage('legacy').getStore()) {
1818
if (store && !store.fs?.opExcluded) {
19-
storage('legacy').enterWith({
19+
return {
2020
...store,
2121
fs: {
2222
...store.fs,
2323
...fsProps,
2424
parentStore: store
2525
}
26-
})
26+
}
2727
}
28+
29+
return store
2830
}
2931

3032
class AppsecFsPlugin extends Plugin {
3133
enable () {
32-
this.addSub('apm:fs:operation:start', this._onFsOperationStart)
33-
this.addSub('apm:fs:operation:finish', this._onFsOperationFinishOrRenderEnd)
34-
this.addSub('tracing:datadog:express:response:render:start', this._onResponseRenderStart)
35-
this.addSub('tracing:datadog:express:response:render:end', this._onFsOperationFinishOrRenderEnd)
34+
this.addBind('apm:fs:operation:start', this._onFsOperationStart)
35+
this.addBind('apm:fs:operation:finish', this._onFsOperationFinishOrRenderEnd)
36+
this.addBind('tracing:datadog:express:response:render:start', this._onResponseRenderStart)
37+
this.addBind('tracing:datadog:express:response:render:end', this._onFsOperationFinishOrRenderEnd)
3638

3739
super.configure(true)
3840
}
@@ -44,19 +46,20 @@ class AppsecFsPlugin extends Plugin {
4446
_onFsOperationStart () {
4547
const store = storage('legacy').getStore()
4648
if (store) {
47-
enterWith({ root: store.fs?.root === undefined }, store)
49+
return storeToStart({ root: store.fs?.root === undefined }, store)
4850
}
4951
}
5052

5153
_onResponseRenderStart () {
52-
enterWith({ opExcluded: true })
54+
return storeToStart({ opExcluded: true })
5355
}
5456

5557
_onFsOperationFinishOrRenderEnd () {
5658
const store = storage('legacy').getStore()
57-
if (store?.fs?.parentStore) {
58-
storage('legacy').enterWith(store.fs.parentStore)
59+
if (store?.fs) {
60+
return store.fs.parentStore
5961
}
62+
return store
6063
}
6164
}
6265

packages/dd-trace/test/appsec/iast/analyzers/path-traversal-analyzer.spec.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,26 @@ prepareTestServerForIast('integration test', (testThatRequestHasVulnerability, t
477477

478478
describe('test stat', () => {
479479
runFsMethodTestThreeWay('stat', 0, null, __filename)
480+
481+
describe('with two calls to async method without waiting to the callback', () => {
482+
const fsAsyncWayMethodPath = path.join(os.tmpdir(), 'fs-async-way-method.js')
483+
484+
before(() => {
485+
fs.copyFileSync(path.join(__dirname, 'resources', 'fs-async-way-method.js'), fsAsyncWayMethodPath)
486+
})
487+
488+
after(() => {
489+
fs.unlinkSync(fsAsyncWayMethodPath)
490+
})
491+
492+
testThatRequestHasVulnerability(function () {
493+
const store = storage('legacy').getStore()
494+
const iastCtx = iastContextFunctions.getIastContext(store)
495+
const callArgs = [fsAsyncWayMethodPath]
496+
callArgs[0] = newTaintedString(iastCtx, callArgs[0], 'param', 'Request')
497+
return require(fsAsyncWayMethodPath).doubleCallIgnoringCb('stat', callArgs)
498+
}, 'PATH_TRAVERSAL', { occurrences: 2 })
499+
})
480500
})
481501

482502
describe('test symlink', () => {

packages/dd-trace/test/appsec/iast/analyzers/resources/fs-async-way-method.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,21 @@
22

33
const fs = require('fs')
44

5-
module.exports = function (methodName, args, cb) {
5+
function main (methodName, args, cb) {
66
return new Promise((resolve, reject) => {
77
fs[methodName](...args, (err, res) => {
88
resolve(cb(res))
99
})
1010
})
1111
}
12+
13+
main.doubleCallIgnoringCb = function (methodName, args) {
14+
return new Promise((resolve) => {
15+
fs[methodName](...args, () => {})
16+
fs[methodName](...args, () => {
17+
resolve()
18+
})
19+
})
20+
}
21+
22+
module.exports = main

packages/dd-trace/test/appsec/rasp/lfi.express.plugin.spec.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,13 @@ describe('RASP - lfi', () => {
296296

297297
describe('test readFile', () => {
298298
runFsMethodTestThreeWay('readFile', undefined, __filename)
299+
300+
runFsMethodTest('an async operation without callback is executed before',
301+
{ getAppFn: getAppSync, ruleEvalCount: 2 }, (args) => {
302+
const fs = require('fs')
303+
fs.readFile(path.join(__dirname, 'utils.js'), () => {}) // safe and ignored operation
304+
return fs.readFileSync(...args)
305+
}, __filename)
299306
})
300307

301308
describe('test readlink', () => {

0 commit comments

Comments
 (0)