Skip to content

Commit d37649a

Browse files
committed
call site frames
1 parent 0a9cc8d commit d37649a

File tree

6 files changed

+52
-53
lines changed

6 files changed

+52
-53
lines changed

packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,15 @@ class CookieAnalyzer extends Analyzer {
5454
return super._checkOCE(context, value)
5555
}
5656

57-
_getLocation (value, callSiteList) {
57+
_getLocation (value, callSiteFrames) {
5858
if (!value) {
59-
return super._getLocation(value, callSiteList)
59+
return super._getLocation(value, callSiteFrames)
6060
}
6161

6262
if (value.location) {
6363
return value.location
6464
}
65-
const location = super._getLocation(value, callSiteList)
65+
const location = super._getLocation(value, callSiteFrames)
6666
value.location = location
6767
return location
6868
}

packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js

+12-9
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
'use strict'
22

33
const { storage } = require('../../../../../datadog-core')
4-
const { getFirstNonDDPathAndLine } = require('../path-line')
5-
const { addVulnerability, getVulnerabilityCallSiteList } = require('../vulnerability-reporter')
4+
const { getNonDDPathAndLineCallsites } = require('../path-line')
5+
const { addVulnerability, getVulnerabilityCallSiteFrames } = require('../vulnerability-reporter')
66
const { getIastContext, getIastStackTraceId } = require('../iast-context')
77
const overheadController = require('../overhead-controller')
88
const { SinkIastPlugin } = require('../iast-plugin')
@@ -28,15 +28,17 @@ class Analyzer extends SinkIastPlugin {
2828
}
2929

3030
_reportEvidence (value, context, evidence) {
31-
const callSiteList = getVulnerabilityCallSiteList()
32-
const location = this._getLocation(value, callSiteList)
31+
const callSiteFrames = getVulnerabilityCallSiteFrames()
32+
const nonDDCallSiteFrames = getNonDDPathAndLineCallsites(callSiteFrames, this._getExcludedPaths())
33+
34+
const location = this._getLocation(null, nonDDCallSiteFrames)
3335

3436
if (!this._isExcluded(location)) {
35-
const locationSourceMap = this._replaceLocationFromSourceMap(location)
37+
const originalCallSiteFrames = nonDDCallSiteFrames.map(callSite => this._replaceLocationFromSourceMap(callSite))
3638
const spanId = context && context.rootSpan && context.rootSpan.context().toSpanId()
3739
const stackId = getIastStackTraceId(context)
38-
const vulnerability = this._createVulnerability(this._type, evidence, spanId, locationSourceMap, stackId)
39-
addVulnerability(context, vulnerability, callSiteList, stackId)
40+
const vulnerability = this._createVulnerability(this._type, evidence, spanId, originalCallSiteFrames[0], stackId)
41+
addVulnerability(context, vulnerability, originalCallSiteFrames, stackId)
4042
}
4143
}
4244

@@ -52,15 +54,16 @@ class Analyzer extends SinkIastPlugin {
5254
return { value }
5355
}
5456

55-
_getLocation (value, callSiteList) {
56-
return getFirstNonDDPathAndLine(callSiteList, this._getExcludedPaths())
57+
_getLocation (value, callSiteFrames) {
58+
return callSiteFrames[0]
5759
}
5860

5961
_replaceLocationFromSourceMap (location) {
6062
if (location) {
6163
const { path, line, column } = getOriginalPathAndLineFromSourceMap(location)
6264
if (path) {
6365
location.path = path
66+
location.file = path
6467
}
6568
if (line) {
6669
location.line = line

packages/dd-trace/src/appsec/iast/path-line.js

+20-22
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ const path = require('path')
44
const process = require('process')
55
const { calculateDDBasePath } = require('../../util')
66
const pathLine = {
7-
getFirstNonDDPathAndLine,
87
getNodeModulesPaths,
98
getRelativePath,
10-
getFirstNonDDPathAndLineFromCallsites, // Exported only for test purposes
9+
getNonDDPathAndLineCallsites,
1110
calculateDDBasePath, // Exported only for test purposes
1211
ddBasePath: calculateDDBasePath(__dirname) // Only for test purposes
1312
}
@@ -24,31 +23,34 @@ const EXCLUDED_PATH_PREFIXES = [
2423
'async_hooks'
2524
]
2625

27-
function getFirstNonDDPathAndLineFromCallsites (callsites, externallyExcludedPaths) {
28-
if (callsites) {
29-
for (let i = 0; i < callsites.length; i++) {
30-
const callsite = callsites[i]
31-
const filepath = callsite.getFileName()
32-
if (!isExcluded(callsite, externallyExcludedPaths) && filepath.indexOf(pathLine.ddBasePath) === -1) {
33-
return {
34-
path: getRelativePath(filepath),
35-
line: callsite.getLineNumber(),
36-
column: callsite.getColumnNumber(),
37-
isInternal: !path.isAbsolute(filepath)
38-
}
39-
}
26+
function getNonDDPathAndLineCallsites (callsites, externallyExcludedPaths) {
27+
if (!callsites) {
28+
return []
29+
}
30+
31+
const result = []
32+
33+
for (const callsite of callsites) {
34+
const filepath = callsite.file
35+
if (!isExcluded(callsite, externallyExcludedPaths) && filepath.indexOf(pathLine.ddBasePath) === -1) {
36+
result.push({
37+
...callsite,
38+
path: getRelativePath(filepath),
39+
isInternal: !path.isAbsolute(filepath)
40+
})
4041
}
4142
}
42-
return null
43+
44+
return result
4345
}
4446

4547
function getRelativePath (filepath) {
4648
return path.relative(process.cwd(), filepath)
4749
}
4850

4951
function isExcluded (callsite, externallyExcludedPaths) {
50-
if (callsite.isNative()) return true
51-
const filename = callsite.getFileName()
52+
if (callsite.isNative) return true
53+
const filename = callsite.file
5254
if (!filename) {
5355
return true
5456
}
@@ -72,10 +74,6 @@ function isExcluded (callsite, externallyExcludedPaths) {
7274
return false
7375
}
7476

75-
function getFirstNonDDPathAndLine (callSiteList, externallyExcludedPaths) {
76-
return getFirstNonDDPathAndLineFromCallsites(callSiteList, externallyExcludedPaths)
77-
}
78-
7977
function getNodeModulesPaths (...paths) {
8078
const nodeModulesPaths = []
8179

packages/dd-trace/src/appsec/iast/vulnerability-reporter.js

+6-7
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const { IAST_ENABLED_TAG_KEY, IAST_JSON_TAG_KEY } = require('./tags')
66
const standalone = require('../standalone')
77
const { SAMPLING_MECHANISM_APPSEC } = require('../../constants')
88
const { keepTrace } = require('../../priority_sampler')
9-
const { reportStackTrace, getCallSiteList, STACK_TRACE_NAMESPACES } = require('../stack_trace')
9+
const { reportStackTrace, getCallSiteFrames, STACK_TRACE_NAMESPACES } = require('../stack_trace')
1010

1111
const VULNERABILITIES_KEY = 'vulnerabilities'
1212
const VULNERABILITY_HASHES_MAX_SIZE = 1000
@@ -19,7 +19,7 @@ let deduplicationEnabled = true
1919
let stackTraceMaxDepth
2020
let maxStackTraces
2121

22-
function addVulnerability (iastContext, vulnerability, callSiteList, stackId) {
22+
function addVulnerability (iastContext, vulnerability, callSiteFrames, stackId) {
2323
if (vulnerability?.evidence && vulnerability?.type && vulnerability?.location) {
2424
if (deduplicationEnabled && isDuplicatedVulnerability(vulnerability)) return
2525

@@ -47,9 +47,8 @@ function addVulnerability (iastContext, vulnerability, callSiteList, stackId) {
4747
reportStackTrace(
4848
iastContext?.rootSpan,
4949
stackId,
50-
stackTraceMaxDepth,
5150
maxStackTraces,
52-
callSiteList,
51+
callSiteFrames,
5352
STACK_TRACE_NAMESPACES.IAST
5453
)
5554

@@ -106,8 +105,8 @@ function isDuplicatedVulnerability (vulnerability) {
106105
return VULNERABILITY_HASHES.get(`${vulnerability.type}${vulnerability.hash}`)
107106
}
108107

109-
function getVulnerabilityCallSiteList () {
110-
return getCallSiteList(stackTraceMaxDepth)
108+
function getVulnerabilityCallSiteFrames () {
109+
return getCallSiteFrames(stackTraceMaxDepth)
111110
}
112111

113112
function start (config, _tracer) {
@@ -133,7 +132,7 @@ function stop () {
133132
module.exports = {
134133
addVulnerability,
135134
sendVulnerabilities,
136-
getVulnerabilityCallSiteList,
135+
getVulnerabilityCallSiteFrames,
137136
clearCache,
138137
start,
139138
stop

packages/dd-trace/src/appsec/rasp/utils.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict'
22

33
const web = require('../../plugins/util/web')
4-
const { getCallSiteList, reportStackTrace } = require('../stack_trace')
4+
const { getCallSiteFrames, reportStackTrace } = require('../stack_trace')
55
const { getBlockingAction } = require('../blocking')
66
const log = require('../../log')
77

@@ -34,15 +34,14 @@ function handleResult (actions, req, res, abortController, config) {
3434
const { enabled, maxDepth, maxStackTraces } = config.appsec.stackTrace
3535

3636
if (generateStackTraceAction && enabled) {
37-
const callSiteList = getCallSiteList(maxDepth)
37+
const callSiteFrames = getCallSiteFrames(maxDepth)
3838

3939
const rootSpan = web.root(req)
4040
reportStackTrace(
4141
rootSpan,
4242
generateStackTraceAction.stack_id,
43-
maxDepth,
4443
maxStackTraces,
45-
callSiteList
44+
callSiteFrames
4645
)
4746
}
4847

packages/dd-trace/src/appsec/stack_trace.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ function filterOutFramesFromLibrary (callSiteList) {
3939
return callSiteList.filter(callSite => !callSite.getFileName()?.startsWith(ddBasePath))
4040
}
4141

42-
function getFramesForMetaStruct (callSiteList, maxDepth = 32) {
42+
function getCallSiteFrames (maxDepth = 32) {
43+
const callSiteList = getCallSiteList(maxDepth)
4344
const filteredFrames = filterOutFramesFromLibrary(callSiteList)
4445

4546
const half = filteredFrames.length > maxDepth ? Math.round(maxDepth / 2) : Infinity
@@ -54,20 +55,21 @@ function getFramesForMetaStruct (callSiteList, maxDepth = 32) {
5455
line: callSite.getLineNumber(),
5556
column: callSite.getColumnNumber(),
5657
function: callSite.getFunctionName(),
57-
class_name: callSite.getTypeName()
58+
class_name: callSite.getTypeName(),
59+
isNative: callSite.isNative()
5860
})
5961
}
6062

6163
return indexedFrames
6264
}
6365

6466
function reportStackTrace (
65-
rootSpan, stackId, maxDepth, maxStackTraces, callSiteList, namespace = STACK_TRACE_NAMESPACES.RASP) {
67+
rootSpan, stackId, maxStackTraces, frames, namespace = STACK_TRACE_NAMESPACES.RASP) {
6668
if (!rootSpan) return
6769

6870
if (maxStackTraces < 1 || (rootSpan.meta_struct?.['_dd.stack']?.[namespace]?.length ?? 0) < maxStackTraces) {
69-
if (maxDepth < 1) maxDepth = Infinity
70-
if (!Array.isArray(callSiteList)) return
71+
if (!Array.isArray(frames)) return
72+
if (!frames.length) return
7173

7274
if (!rootSpan.meta_struct) {
7375
rootSpan.meta_struct = {}
@@ -81,8 +83,6 @@ function reportStackTrace (
8183
rootSpan.meta_struct['_dd.stack'][namespace] = []
8284
}
8385

84-
const frames = getFramesForMetaStruct(callSiteList, maxDepth)
85-
8686
rootSpan.meta_struct['_dd.stack'][namespace].push({
8787
id: stackId,
8888
language: 'nodejs',
@@ -92,7 +92,7 @@ function reportStackTrace (
9292
}
9393

9494
module.exports = {
95-
getCallSiteList,
95+
getCallSiteFrames,
9696
reportStackTrace,
9797
STACK_TRACE_NAMESPACES
9898
}

0 commit comments

Comments
 (0)