Sophie

Sophie

distrib > Mageia > 8 > x86_64 > by-pkgid > 6f5fcdec8aea1fd3ce63eeed80376ca7 > files > 4

nodejs-tar-6.0.5-1.1.mga8.src.rpm

Description: prevent path escape using drive-relative paths
Author: isaacs <i@izs.me>
Origin: upstream, https://github.com/npm/node-tar/commit/875a37e3
Bug: https://github.com/npm/node-tar/security/advisories/GHSA-qq89-hq3f-393p
Forwarded: not-needed
Reviewed-By: Yadd <yadd@debian.org>
Last-Update: 2021-11-11

--- a/lib/strip-absolute-path.js
+++ b/lib/strip-absolute-path.js
@@ -2,13 +2,23 @@
 const { isAbsolute, parse } = require('path').win32
 
 // returns [root, stripped]
+// Note that windows will think that //x/y/z/a has a "root" of //x/y, and in
+// those cases, we want to sanitize it to x/y/z/a, not z/a, so we strip /
+// explicitly if it's the first character.
+// drive-specific relative paths on Windows get their root stripped off even
+// though they are not absolute, so `c:../foo` becomes ['c:', '../foo']
 module.exports = path => {
   let r = ''
-  while (isAbsolute(path)) {
+
+  let parsed = parse(path)
+  while (isAbsolute(path) || parsed.root) {
     // windows will think that //x/y/z has a "root" of //x/y/
-    const root = path.charAt(0) === '/' ? '/' : parse(path).root
+    // but strip the //?/C:/ off of //?/C:/path
+    const root = path.charAt(0) === '/' && path.slice(0, 4) !== '//?/' ? '/'
+      : parsed.root
     path = path.substr(root.length)
     r += root
+    parsed = parse(path)
   }
   return [r, path]
 }
--- a/lib/unpack.js
+++ b/lib/unpack.js
@@ -45,6 +45,8 @@
 const GID = Symbol('gid')
 const crypto = require('crypto')
 const getFlag = require('./get-write-flag.js')
+const platform = process.env.TESTING_TAR_FAKE_PLATFORM || process.platform
+const isWindows = platform === 'win32'
 
 /* istanbul ignore next */
 const neverCalled = () => {
@@ -226,7 +228,8 @@
 
     if (!this.preservePaths) {
       const p = normPath(entry.path)
-      if (p.split('/').includes('..')) {
+      const parts = p.split('/')
+      if (parts.includes('..') || isWindows && /^[a-z]:\.\.$/i.test(parts[0])) {
         this.warn('TAR_ENTRY_ERROR', `path contains '..'`, {
           entry,
           path: p,
@@ -234,8 +237,7 @@
         return false
       }
 
-      // absolutes on posix are also absolutes on win32
-      // so we only need to test this one to get both
+      // strip off the root
       const [root, stripped] = stripAbsolutePath(p)
       if (root) {
         entry.path = stripped
@@ -258,6 +260,22 @@
     else
       entry.absolute = normPath(path.resolve(this.cwd, entry.path))
 
+    // if we somehow ended up with a path that escapes the cwd, and we are
+    // not in preservePaths mode, then something is fishy!  This should have
+    // been prevented above, so ignore this for coverage.
+    /* istanbul ignore if - defense in depth */
+    if (!this.preservePaths &&
+        entry.absolute.indexOf(this.cwd + '/') !== 0 &&
+        entry.absolute !== this.cwd) {
+      this.warn('TAR_ENTRY_ERROR', 'path escaped extraction target', {
+        entry,
+        path: normPath(entry.path),
+        resolvedPath: entry.absolute,
+        cwd: this.cwd,
+      })
+      return false
+    }
+
     return true
   }