summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPolampalli, Archana <archana.polampalli@windriver.com>2023-08-31 04:57:43 +0000
committerArmin Kuster <akuster808@gmail.com>2023-09-04 11:59:59 -0400
commitd3ee870fb0acbda1c27aa58311547733cccb1df2 (patch)
tree361549c4a346a05c7a0ddec7592f111dc74663b7
parent71d9cabed74b29741babe26a657adf6ecedb3bf4 (diff)
downloadmeta-openembedded-d3ee870fb0acbda1c27aa58311547733cccb1df2.tar.gz
nodejs: fix CVE-2022-25883
Versions of the package semver before 7.5.2 are vulnerable to Regular Expression Denial of Service (ReDoS) via the function new Range, when untrusted user data is provided as a range. References: https://nvd.nist.gov/vuln/detail/CVE-2022-25883 Upstream patches: https://github.com/npm/node-semver/commit/717534ee353682f3bcf33e60a8af4292626d4441 Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com> Signed-off-by: Armin Kuster <akuster808@gmail.com>
-rw-r--r--meta-oe/recipes-devtools/nodejs/nodejs/CVE-2022-25883.patch262
-rw-r--r--meta-oe/recipes-devtools/nodejs/nodejs_16.20.2.bb1
2 files changed, 263 insertions, 0 deletions
diff --git a/meta-oe/recipes-devtools/nodejs/nodejs/CVE-2022-25883.patch b/meta-oe/recipes-devtools/nodejs/nodejs/CVE-2022-25883.patch
new file mode 100644
index 0000000000..4c73b556f9
--- /dev/null
+++ b/meta-oe/recipes-devtools/nodejs/nodejs/CVE-2022-25883.patch
@@ -0,0 +1,262 @@
1From 717534ee353682f3bcf33e60a8af4292626d4441 Mon Sep 17 00:00:00 2001
2From: Luke Karrys <luke@lukekarrys.com>
3Date: Thu, 15 Jun 2023 12:21:14 -0700
4Subject: [PATCH] fix: better handling of whitespace (#564)
5
6CVE: CVE-2022-25883
7
8Upstream-Status: Backport [https://github.com/npm/node-semver/commit/717534ee353682f3bcf33e60a8af4292626d4441]
9
10Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
11---
12 .../node_modules/semver/classes/comparator.js | 3 +-
13 deps/npm/node_modules/semver/classes/range.js | 64 +++++++++++--------
14 .../npm/node_modules/semver/classes/semver.js | 2 +-
15 .../node_modules/semver/functions/coerce.js | 2 +-
16 deps/npm/node_modules/semver/internal/re.js | 11 ++++
17 deps/npm/node_modules/semver/package.json | 2 +-
18 6 files changed, 53 insertions(+), 31 deletions(-)
19
20diff --git a/deps/npm/node_modules/semver/classes/comparator.js b/deps/npm/node_modules/semver/classes/comparator.js
21index 62cd204..c909446 100644
22--- a/deps/npm/node_modules/semver/classes/comparator.js
23+++ b/deps/npm/node_modules/semver/classes/comparator.js
24@@ -16,6 +16,7 @@ class Comparator {
25 }
26 }
27
28+ comp = comp.trim().split(/\s+/).join(' ')
29 debug('comparator', comp, options)
30 this.options = options
31 this.loose = !!options.loose
32@@ -129,7 +130,7 @@ class Comparator {
33 module.exports = Comparator
34
35 const parseOptions = require('../internal/parse-options')
36-const { re, t } = require('../internal/re')
37+const { safeRe: re, t } = require('../internal/re')
38 const cmp = require('../functions/cmp')
39 const debug = require('../internal/debug')
40 const SemVer = require('./semver')
41diff --git a/deps/npm/node_modules/semver/classes/range.js b/deps/npm/node_modules/semver/classes/range.js
42index 7dc24bc..8e2e1f9 100644
43--- a/deps/npm/node_modules/semver/classes/range.js
44+++ b/deps/npm/node_modules/semver/classes/range.js
45@@ -26,19 +26,26 @@ class Range {
46 this.loose = !!options.loose
47 this.includePrerelease = !!options.includePrerelease
48
49- // First, split based on boolean or ||
50+ // First reduce all whitespace as much as possible so we do not have to rely
51+ // on potentially slow regexes like \s*. This is then stored and used for
52+ // future error messages as well.
53 this.raw = range
54- this.set = range
55+ .trim()
56+ .split(/\s+/)
57+ .join(' ')
58+
59+ // First, split on ||
60+ this.set = this.raw
61 .split('||')
62 // map the range to a 2d array of comparators
63- .map(r => this.parseRange(r.trim()))
64+ .map(r => this.parseRange(r))
65 // throw out any comparator lists that are empty
66 // this generally means that it was not a valid range, which is allowed
67 // in loose mode, but will still throw if the WHOLE range is invalid.
68 .filter(c => c.length)
69
70 if (!this.set.length) {
71- throw new TypeError(`Invalid SemVer Range: ${range}`)
72+ throw new TypeError(`Invalid SemVer Range: ${this.raw}`)
73 }
74
75 // if we have any that are not the null set, throw out null sets.
76@@ -64,9 +71,7 @@ class Range {
77
78 format () {
79 this.range = this.set
80- .map((comps) => {
81- return comps.join(' ').trim()
82- })
83+ .map((comps) => comps.join(' ').trim())
84 .join('||')
85 .trim()
86 return this.range
87@@ -77,8 +82,6 @@ class Range {
88 }
89
90 parseRange (range) {
91- range = range.trim()
92-
93 // memoize range parsing for performance.
94 // this is a very hot path, and fully deterministic.
95 const memoOpts = Object.keys(this.options).join(',')
96@@ -103,9 +106,6 @@ class Range {
97 // `^ 1.2.3` => `^1.2.3`
98 range = range.replace(re[t.CARETTRIM], caretTrimReplace)
99
100- // normalize spaces
101- range = range.split(/\s+/).join(' ')
102-
103 // At this point, the range is completely trimmed and
104 // ready to be split into comparators.
105
106@@ -200,7 +200,7 @@ const Comparator = require('./comparator')
107 const debug = require('../internal/debug')
108 const SemVer = require('./semver')
109 const {
110- re,
111+ safeRe: re,
112 t,
113 comparatorTrimReplace,
114 tildeTrimReplace,
115@@ -252,10 +252,13 @@ const isX = id => !id || id.toLowerCase() === 'x' || id === '*'
116 // ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0-0
117 // ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0-0
118 // ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0-0
119-const replaceTildes = (comp, options) =>
120- comp.trim().split(/\s+/).map((c) => {
121- return replaceTilde(c, options)
122- }).join(' ')
123+const replaceTildes = (comp, options) => {
124+ return comp
125+ .trim()
126+ .split(/\s+/)
127+ .map((c) => replaceTilde(c, options))
128+ .join(' ')
129+}
130
131 const replaceTilde = (comp, options) => {
132 const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE]
133@@ -291,10 +294,13 @@ const replaceTilde = (comp, options) => {
134 // ^1.2, ^1.2.x --> >=1.2.0 <2.0.0-0
135 // ^1.2.3 --> >=1.2.3 <2.0.0-0
136 // ^1.2.0 --> >=1.2.0 <2.0.0-0
137-const replaceCarets = (comp, options) =>
138- comp.trim().split(/\s+/).map((c) => {
139- return replaceCaret(c, options)
140- }).join(' ')
141+const replaceCarets = (comp, options) => {
142+ return comp
143+ .trim()
144+ .split(/\s+/)
145+ .map((c) => replaceCaret(c, options))
146+ .join(' ')
147+}
148
149 const replaceCaret = (comp, options) => {
150 debug('caret', comp, options)
151@@ -351,9 +357,10 @@ const replaceCaret = (comp, options) => {
152
153 const replaceXRanges = (comp, options) => {
154 debug('replaceXRanges', comp, options)
155- return comp.split(/\s+/).map((c) => {
156- return replaceXRange(c, options)
157- }).join(' ')
158+ return comp
159+ .split(/\s+/)
160+ .map((c) => replaceXRange(c, options))
161+ .join(' ')
162 }
163
164 const replaceXRange = (comp, options) => {
165@@ -436,12 +443,15 @@ const replaceXRange = (comp, options) => {
166 const replaceStars = (comp, options) => {
167 debug('replaceStars', comp, options)
168 // Looseness is ignored here. star is always as loose as it gets!
169- return comp.trim().replace(re[t.STAR], '')
170+ return comp
171+ .trim()
172+ .replace(re[t.STAR], '')
173 }
174
175 const replaceGTE0 = (comp, options) => {
176 debug('replaceGTE0', comp, options)
177- return comp.trim()
178+ return comp
179+ .trim()
180 .replace(re[options.includePrerelease ? t.GTE0PRE : t.GTE0], '')
181 }
182
183@@ -479,7 +489,7 @@ const hyphenReplace = incPr => ($0,
184 to = `<=${to}`
185 }
186
187- return (`${from} ${to}`).trim()
188+ return `${from} ${to}`.trim()
189 }
190
191 const testSet = (set, version, options) => {
192diff --git a/deps/npm/node_modules/semver/classes/semver.js b/deps/npm/node_modules/semver/classes/semver.js
193index af62955..ad4e877 100644
194--- a/deps/npm/node_modules/semver/classes/semver.js
195+++ b/deps/npm/node_modules/semver/classes/semver.js
196@@ -1,6 +1,6 @@
197 const debug = require('../internal/debug')
198 const { MAX_LENGTH, MAX_SAFE_INTEGER } = require('../internal/constants')
199-const { re, t } = require('../internal/re')
200+const { safeRe: re, t } = require('../internal/re')
201
202 const parseOptions = require('../internal/parse-options')
203 const { compareIdentifiers } = require('../internal/identifiers')
204diff --git a/deps/npm/node_modules/semver/functions/coerce.js b/deps/npm/node_modules/semver/functions/coerce.js
205index 2e01452..febbff9 100644
206--- a/deps/npm/node_modules/semver/functions/coerce.js
207+++ b/deps/npm/node_modules/semver/functions/coerce.js
208@@ -1,6 +1,6 @@
209 const SemVer = require('../classes/semver')
210 const parse = require('./parse')
211-const { re, t } = require('../internal/re')
212+const { safeRe: re, t } = require('../internal/re')
213
214 const coerce = (version, options) => {
215 if (version instanceof SemVer) {
216diff --git a/deps/npm/node_modules/semver/internal/re.js b/deps/npm/node_modules/semver/internal/re.js
217index ed88398..f73ef1a 100644
218--- a/deps/npm/node_modules/semver/internal/re.js
219+++ b/deps/npm/node_modules/semver/internal/re.js
220@@ -4,16 +4,27 @@ exports = module.exports = {}
221
222 // The actual regexps go on exports.re
223 const re = exports.re = []
224+const safeRe = exports.safeRe = []
225 const src = exports.src = []
226 const t = exports.t = {}
227 let R = 0
228
229 const createToken = (name, value, isGlobal) => {
230+ // Replace all greedy whitespace to prevent regex dos issues. These regex are
231+ // used internally via the safeRe object since all inputs in this library get
232+ // normalized first to trim and collapse all extra whitespace. The original
233+ // regexes are exported for userland consumption and lower level usage. A
234+ // future breaking change could export the safer regex only with a note that
235+ // all input should have extra whitespace removed.
236+ const safe = value
237+ .split('\\s*').join('\\s{0,1}')
238+ .split('\\s+').join('\\s')
239 const index = R++
240 debug(name, index, value)
241 t[name] = index
242 src[index] = value
243 re[index] = new RegExp(value, isGlobal ? 'g' : undefined)
244+ safeRe[index] = new RegExp(safe, isGlobal ? 'g' : undefined)
245 }
246
247 // The following Regular Expressions can be used for tokenizing,
248diff --git a/deps/npm/node_modules/semver/package.json b/deps/npm/node_modules/semver/package.json
249index 7898f59..d8ae619 100644
250--- a/deps/npm/node_modules/semver/package.json
251+++ b/deps/npm/node_modules/semver/package.json
252@@ -40,7 +40,7 @@
253 "range.bnf"
254 ],
255 "tap": {
256- "check-coverage": true,
257+ "timeout": 30,
258 "coverage-map": "map.js"
259 },
260 "engines": {
261--
2622.40.0
diff --git a/meta-oe/recipes-devtools/nodejs/nodejs_16.20.2.bb b/meta-oe/recipes-devtools/nodejs/nodejs_16.20.2.bb
index 4761bfb14f..16593a0fe6 100644
--- a/meta-oe/recipes-devtools/nodejs/nodejs_16.20.2.bb
+++ b/meta-oe/recipes-devtools/nodejs/nodejs_16.20.2.bb
@@ -26,6 +26,7 @@ SRC_URI = "http://nodejs.org/dist/v${PV}/node-v${PV}.tar.xz \
26 file://0001-liftoff-Correct-function-signatures.patch \ 26 file://0001-liftoff-Correct-function-signatures.patch \
27 file://0001-mips-Use-32bit-cast-for-operand-on-mips32.patch \ 27 file://0001-mips-Use-32bit-cast-for-operand-on-mips32.patch \
28 file://0001-Nodejs-Fixed-pipes-DeprecationWarning.patch \ 28 file://0001-Nodejs-Fixed-pipes-DeprecationWarning.patch \
29 file://CVE-2022-25883.patch \
29 " 30 "
30SRC_URI:append:class-target = " \ 31SRC_URI:append:class-target = " \
31 file://0001-Using-native-binaries.patch \ 32 file://0001-Using-native-binaries.patch \