diff --git a/CVE-2022-25883.patch b/CVE-2022-25883.patch new file mode 100644 index 0000000000000000000000000000000000000000..cde302b3a4fb6387ad003672268f21d05f1db386 --- /dev/null +++ b/CVE-2022-25883.patch @@ -0,0 +1,260 @@ +From ac529638de1c057b86b17d526e57751a8e838cd6 Mon Sep 17 00:00:00 2001 +From: Luke Karrys +Date: Thu, 15 Jun 2023 12:21:14 -0700 +Subject: [PATCH] fix: better handling of whitespace (#564) + +commit 717534ee353682f3bcf33e60a8af4292626d4441 upstream. + +--- + .../node_modules/semver/classes/comparator.js | 3 +- + deps/npm/node_modules/semver/classes/range.js | 64 +++++++++++-------- + .../npm/node_modules/semver/classes/semver.js | 2 +- + .../node_modules/semver/functions/coerce.js | 2 +- + deps/npm/node_modules/semver/internal/re.js | 11 ++++ + deps/npm/node_modules/semver/package.json | 2 +- + 6 files changed, 53 insertions(+), 31 deletions(-) + +diff --git a/deps/npm/node_modules/semver/classes/comparator.js b/deps/npm/node_modules/semver/classes/comparator.js +index 62cd204d..c909446d 100644 +--- a/deps/npm/node_modules/semver/classes/comparator.js ++++ b/deps/npm/node_modules/semver/classes/comparator.js +@@ -16,6 +16,7 @@ class Comparator { + } + } + ++ comp = comp.trim().split(/\s+/).join(' ') + debug('comparator', comp, options) + this.options = options + this.loose = !!options.loose +@@ -129,7 +130,7 @@ class Comparator { + module.exports = Comparator + + const parseOptions = require('../internal/parse-options') +-const { re, t } = require('../internal/re') ++const { safeRe: re, t } = require('../internal/re') + const cmp = require('../functions/cmp') + const debug = require('../internal/debug') + const SemVer = require('./semver') +diff --git a/deps/npm/node_modules/semver/classes/range.js b/deps/npm/node_modules/semver/classes/range.js +index a791d912..a8c9d591 100644 +--- a/deps/npm/node_modules/semver/classes/range.js ++++ b/deps/npm/node_modules/semver/classes/range.js +@@ -26,19 +26,26 @@ class Range { + this.loose = !!options.loose + this.includePrerelease = !!options.includePrerelease + +- // First, split based on boolean or || ++ // First reduce all whitespace as much as possible so we do not have to rely ++ // on potentially slow regexes like \s*. This is then stored and used for ++ // future error messages as well. + this.raw = range +- this.set = range ++ .trim() ++ .split(/\s+/) ++ .join(' ') ++ ++ // First, split on || ++ this.set = this.raw + .split('||') + // map the range to a 2d array of comparators +- .map(r => this.parseRange(r.trim())) ++ .map(r => this.parseRange(r)) + // throw out any comparator lists that are empty + // this generally means that it was not a valid range, which is allowed + // in loose mode, but will still throw if the WHOLE range is invalid. + .filter(c => c.length) + + if (!this.set.length) { +- throw new TypeError(`Invalid SemVer Range: ${range}`) ++ throw new TypeError(`Invalid SemVer Range: ${this.raw}`) + } + + // if we have any that are not the null set, throw out null sets. +@@ -64,9 +71,7 @@ class Range { + + format () { + this.range = this.set +- .map((comps) => { +- return comps.join(' ').trim() +- }) ++ .map((comps) => comps.join(' ').trim()) + .join('||') + .trim() + return this.range +@@ -77,8 +82,6 @@ class Range { + } + + parseRange (range) { +- range = range.trim() +- + // memoize range parsing for performance. + // this is a very hot path, and fully deterministic. + const memoOpts = Object.keys(this.options).join(',') +@@ -103,9 +106,6 @@ class Range { + // `^ 1.2.3` => `^1.2.3` + range = range.replace(re[t.CARETTRIM], caretTrimReplace) + +- // normalize spaces +- range = range.split(/\s+/).join(' ') +- + // At this point, the range is completely trimmed and + // ready to be split into comparators. + +@@ -200,7 +200,7 @@ const Comparator = require('./comparator') + const debug = require('../internal/debug') + const SemVer = require('./semver') + const { +- re, ++ safeRe: re, + t, + comparatorTrimReplace, + tildeTrimReplace, +@@ -253,10 +253,13 @@ const isX = id => !id || id.toLowerCase() === 'x' || id === '*' + // ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0-0 + // ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0-0 + // ~0.0.1 --> >=0.0.1 <0.1.0-0 +-const replaceTildes = (comp, options) => +- comp.trim().split(/\s+/).map((c) => { +- return replaceTilde(c, options) +- }).join(' ') ++const replaceTildes = (comp, options) => { ++ return comp ++ .trim() ++ .split(/\s+/) ++ .map((c) => replaceTilde(c, options)) ++ .join(' ') ++} + + const replaceTilde = (comp, options) => { + const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE] +@@ -294,10 +297,13 @@ const replaceTilde = (comp, options) => { + // ^1.2.0 --> >=1.2.0 <2.0.0-0 + // ^0.0.1 --> >=0.0.1 <0.0.2-0 + // ^0.1.0 --> >=0.1.0 <0.2.0-0 +-const replaceCarets = (comp, options) => +- comp.trim().split(/\s+/).map((c) => { +- return replaceCaret(c, options) +- }).join(' ') ++const replaceCarets = (comp, options) => { ++ return comp ++ .trim() ++ .split(/\s+/) ++ .map((c) => replaceCaret(c, options)) ++ .join(' ') ++} + + const replaceCaret = (comp, options) => { + debug('caret', comp, options) +@@ -354,9 +360,10 @@ const replaceCaret = (comp, options) => { + + const replaceXRanges = (comp, options) => { + debug('replaceXRanges', comp, options) +- return comp.split(/\s+/).map((c) => { +- return replaceXRange(c, options) +- }).join(' ') ++ return comp ++ .split(/\s+/) ++ .map((c) => replaceXRange(c, options)) ++ .join(' ') + } + + const replaceXRange = (comp, options) => { +@@ -439,12 +446,15 @@ const replaceXRange = (comp, options) => { + const replaceStars = (comp, options) => { + debug('replaceStars', comp, options) + // Looseness is ignored here. star is always as loose as it gets! +- return comp.trim().replace(re[t.STAR], '') ++ return comp ++ .trim() ++ .replace(re[t.STAR], '') + } + + const replaceGTE0 = (comp, options) => { + debug('replaceGTE0', comp, options) +- return comp.trim() ++ return comp ++ .trim() + .replace(re[options.includePrerelease ? t.GTE0PRE : t.GTE0], '') + } + +@@ -482,7 +492,7 @@ const hyphenReplace = incPr => ($0, + to = `<=${to}` + } + +- return (`${from} ${to}`).trim() ++ return `${from} ${to}`.trim() + } + + const testSet = (set, version, options) => { +diff --git a/deps/npm/node_modules/semver/classes/semver.js b/deps/npm/node_modules/semver/classes/semver.js +index af629551..ad4e8775 100644 +--- a/deps/npm/node_modules/semver/classes/semver.js ++++ b/deps/npm/node_modules/semver/classes/semver.js +@@ -1,6 +1,6 @@ + const debug = require('../internal/debug') + const { MAX_LENGTH, MAX_SAFE_INTEGER } = require('../internal/constants') +-const { re, t } = require('../internal/re') ++const { safeRe: re, t } = require('../internal/re') + + const parseOptions = require('../internal/parse-options') + const { compareIdentifiers } = require('../internal/identifiers') +diff --git a/deps/npm/node_modules/semver/functions/coerce.js b/deps/npm/node_modules/semver/functions/coerce.js +index 2e01452f..febbff9c 100644 +--- a/deps/npm/node_modules/semver/functions/coerce.js ++++ b/deps/npm/node_modules/semver/functions/coerce.js +@@ -1,6 +1,6 @@ + const SemVer = require('../classes/semver') + const parse = require('./parse') +-const { re, t } = require('../internal/re') ++const { safeRe: re, t } = require('../internal/re') + + const coerce = (version, options) => { + if (version instanceof SemVer) { +diff --git a/deps/npm/node_modules/semver/internal/re.js b/deps/npm/node_modules/semver/internal/re.js +index ed88398a..f73ef1aa 100644 +--- a/deps/npm/node_modules/semver/internal/re.js ++++ b/deps/npm/node_modules/semver/internal/re.js +@@ -4,16 +4,27 @@ exports = module.exports = {} + + // The actual regexps go on exports.re + const re = exports.re = [] ++const safeRe = exports.safeRe = [] + const src = exports.src = [] + const t = exports.t = {} + let R = 0 + + const createToken = (name, value, isGlobal) => { ++ // Replace all greedy whitespace to prevent regex dos issues. These regex are ++ // used internally via the safeRe object since all inputs in this library get ++ // normalized first to trim and collapse all extra whitespace. The original ++ // regexes are exported for userland consumption and lower level usage. A ++ // future breaking change could export the safer regex only with a note that ++ // all input should have extra whitespace removed. ++ const safe = value ++ .split('\\s*').join('\\s{0,1}') ++ .split('\\s+').join('\\s') + const index = R++ + debug(name, index, value) + t[name] = index + src[index] = value + re[index] = new RegExp(value, isGlobal ? 'g' : undefined) ++ safeRe[index] = new RegExp(safe, isGlobal ? 'g' : undefined) + } + + // The following Regular Expressions can be used for tokenizing, +diff --git a/deps/npm/node_modules/semver/package.json b/deps/npm/node_modules/semver/package.json +index 72d3f66e..48949225 100644 +--- a/deps/npm/node_modules/semver/package.json ++++ b/deps/npm/node_modules/semver/package.json +@@ -37,7 +37,7 @@ + "range.bnf" + ], + "tap": { +- "check-coverage": true, ++ "timeout": 30, + "coverage-map": "map.js", + "nyc-arg": [ + "--exclude", +-- +2.31.1 + diff --git a/nodejs.spec b/nodejs.spec index 51d115cad3c7e1dd26308412a67ecc0f3b3d1a57..415b5eac3b4043124ab82858fe34b64d2da41479 100644 --- a/nodejs.spec +++ b/nodejs.spec @@ -30,7 +30,7 @@ # This is used by both the nodejs package and the npm subpackage that # has a separate version - the name is special so that rpmdev-bumpspec # will bump this rather than adding .1 to the end. -%global baserelease 1 +%global baserelease 2 %{?!_pkgdocdir:%global _pkgdocdir %{_docdir}/%{name}-%{version}} @@ -200,6 +200,8 @@ Source112: https://github.com/WebAssembly/wasi-sdk/archive/wasi-sdk-14/wasi-sdk- # Disable running gyp on bundled deps we don't use Patch1: 0001-Disable-running-gyp-on-shared-deps.patch +# https://github.com/npm/node-semver/commit/717534ee353682f3bcf33e60a8af4292626d4441 +Patch2: CVE-2022-25883.patch BuildRequires: make BuildRequires: python3-devel @@ -734,6 +736,9 @@ end %changelog +* Thu Sep 28 2023 Bo Liu -1:18.16.1-2 +- Fixes CVE-2022-25883 + * Wed Jul 12 2023 Jan Staněk - 1:18.16.1-1 - Rebase to 18.16.1 Resolves: rhbz#2188290 rhbz#2166926