From 2712c11435506cdbe0b1c3a8932710fa3a6118e0 Mon Sep 17 00:00:00 2001 From: Mathias Buus Date: Sun, 29 Apr 2018 16:47:42 +0200 Subject: [PATCH] validate parent paths --- .gitignore | 1 + index.js | 38 +++++++++++++++++++++++++++----------- test/fixtures/invalid.tar | Bin 0 -> 2560 bytes test/index.js | 18 ++++++++++++++++++ 4 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 test/fixtures/invalid.tar diff --git a/.gitignore b/.gitignore index 118a137..cd38f37 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules test/fixtures/copy +test/fixtures/invalid diff --git a/index.js b/index.js index e4c1857..2e1ae6d 100644 --- a/index.js +++ b/index.js @@ -295,21 +295,28 @@ exports.extract = function (cwd, opts) { }, stat) } - mkdirfix(path.dirname(name), { - fs: xfs, own: own, uid: header.uid, gid: header.gid - }, function (err) { + var dir = path.dirname(name) + + validate(xfs, dir, path.join(cwd, '.'), function (err, valid) { if (err) return next(err) + if (!valid) return next(new Error(dir + ' is not a valid path')) - switch (header.type) { - case 'file': return onfile() - case 'link': return onlink() - case 'symlink': return onsymlink() - } + mkdirfix(dir, { + fs: xfs, own: own, uid: header.uid, gid: header.gid + }, function (err) { + if (err) return next(err) - if (strict) return next(new Error('unsupported type for ' + name + ' (' + header.type + ')')) + switch (header.type) { + case 'file': return onfile() + case 'link': return onlink() + case 'symlink': return onsymlink() + } - stream.resume() - next() + if (strict) return next(new Error('unsupported type for ' + name + ' (' + header.type + ')')) + + stream.resume() + next() + }) }) }) @@ -318,6 +325,15 @@ exports.extract = function (cwd, opts) { return extract } +function validate (fs, name, root, cb) { + if (name === root) return cb(null, true) + fs.lstat(name, function (err, st) { + if (err && err.code !== 'ENOENT') return cb(err) + if (err || st.isDirectory()) return validate(fs, path.join(name, '..'), root, cb) + cb(null, false) + }) +} + function mkdirfix (name, opts, cb) { mkdirp(name, {fs: opts.xfs}, function (err, made) { if (!err && made && opts.own) { diff --git a/test/fixtures/invalid.tar b/test/fixtures/invalid.tar new file mode 100644 index 0000000000000000000000000000000000000000..a645e9ce59e35b70c748a3c47c5b791c86d61ae3 GIT binary patch literal 2560 zcmYex&u5@DFfcGMGci$M0MbB!PD2C@jg8C=jZKZr3{4aa3=IrT3>6rR^z`&;?KXze z;*!K7pwlR|2<#0c&rxa~o%E;W=j$f{1AvwQ7&HXp-&6rD{!PqHf$4;nj)Ivz!s9<9 bH7AGmB>*h2N9oZJ7!85Z5Eu=C!4d)hnE)h9 literal 0 HcmV?d00001 diff --git a/test/index.js b/test/index.js index e9b57be..3129eb7 100644 --- a/test/index.js +++ b/test/index.js @@ -292,3 +292,21 @@ test('not finalizing the pack', function (t) { t.deepEqual(aFiles, ['hello.txt']) } }) + +test('do not extract invalid tar', function (t) { + var a = path.join(__dirname, 'fixtures', 'invalid.tar') + + var out = path.join(__dirname, 'fixtures', 'invalid') + + rimraf.sync(out) + + fs.createReadStream(a) + .pipe(tar.extract(out)) + .on('error', function (err) { + t.ok(/is not a valid path/i.test(err.message)) + fs.stat(path.join(out, '../bar'), function (err) { + t.ok(err) + t.end() + }) + }) +})