Skip to content

Commit d1bf8ce

Browse files
targosMylesBorins
authored andcommitted
path: fix normalize paths ending with two dots
Fixes: https://github.com/nodejs/security/issues/147 PR-URL: https://github.com/nodejs-private/node-private/pull/94 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Doug Wilson <doug@somethingdoug.com> Reviewed-By: Myles Borins <myles.borins@gmail.com> Reviewed-By: Evan Lucas <evanlucas@me.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
1 parent b622a51 commit d1bf8ce

File tree

2 files changed

+27
-16
lines changed

2 files changed

+27
-16
lines changed

lib/path.js

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ function assertPath(path) {
1111
// Resolves . and .. elements in a path with directory names
1212
function normalizeStringWin32(path, allowAboveRoot) {
1313
var res = '';
14+
var lastSegmentLength = 0;
1415
var lastSlash = -1;
1516
var dots = 0;
1617
var code;
17-
var isAboveRoot = false;
1818
for (var i = 0; i <= path.length; ++i) {
1919
if (i < path.length)
2020
code = path.charCodeAt(i);
@@ -26,7 +26,7 @@ function normalizeStringWin32(path, allowAboveRoot) {
2626
if (lastSlash === i - 1 || dots === 1) {
2727
// NOOP
2828
} else if (lastSlash !== i - 1 && dots === 2) {
29-
if (res.length < 2 || !isAboveRoot ||
29+
if (res.length < 2 || lastSegmentLength !== 2 ||
3030
res.charCodeAt(res.length - 1) !== 46/*.*/ ||
3131
res.charCodeAt(res.length - 2) !== 46/*.*/) {
3232
if (res.length > 2) {
@@ -37,20 +37,22 @@ function normalizeStringWin32(path, allowAboveRoot) {
3737
break;
3838
}
3939
if (j !== start) {
40-
if (j === -1)
40+
if (j === -1) {
4141
res = '';
42-
else
42+
lastSegmentLength = 0;
43+
} else {
4344
res = res.slice(0, j);
45+
lastSegmentLength = j;
46+
}
4447
lastSlash = i;
4548
dots = 0;
46-
isAboveRoot = false;
4749
continue;
4850
}
4951
} else if (res.length === 2 || res.length === 1) {
5052
res = '';
53+
lastSegmentLength = 0;
5154
lastSlash = i;
5255
dots = 0;
53-
isAboveRoot = false;
5456
continue;
5557
}
5658
}
@@ -59,14 +61,14 @@ function normalizeStringWin32(path, allowAboveRoot) {
5961
res += '\\..';
6062
else
6163
res = '..';
62-
isAboveRoot = true;
64+
lastSegmentLength = 2;
6365
}
6466
} else {
6567
if (res.length > 0)
6668
res += '\\' + path.slice(lastSlash + 1, i);
6769
else
6870
res = path.slice(lastSlash + 1, i);
69-
isAboveRoot = false;
71+
lastSegmentLength = i - lastSlash - 1;
7072
}
7173
lastSlash = i;
7274
dots = 0;
@@ -82,10 +84,10 @@ function normalizeStringWin32(path, allowAboveRoot) {
8284
// Resolves . and .. elements in a path with directory names
8385
function normalizeStringPosix(path, allowAboveRoot) {
8486
var res = '';
87+
var lastSegmentLength = 0;
8588
var lastSlash = -1;
8689
var dots = 0;
8790
var code;
88-
var isAboveRoot = false;
8991
for (var i = 0; i <= path.length; ++i) {
9092
if (i < path.length)
9193
code = path.charCodeAt(i);
@@ -97,7 +99,7 @@ function normalizeStringPosix(path, allowAboveRoot) {
9799
if (lastSlash === i - 1 || dots === 1) {
98100
// NOOP
99101
} else if (lastSlash !== i - 1 && dots === 2) {
100-
if (res.length < 2 || !isAboveRoot ||
102+
if (res.length < 2 || lastSegmentLength !== 2 ||
101103
res.charCodeAt(res.length - 1) !== 46/*.*/ ||
102104
res.charCodeAt(res.length - 2) !== 46/*.*/) {
103105
if (res.length > 2) {
@@ -108,20 +110,22 @@ function normalizeStringPosix(path, allowAboveRoot) {
108110
break;
109111
}
110112
if (j !== start) {
111-
if (j === -1)
113+
if (j === -1) {
112114
res = '';
113-
else
115+
lastSegmentLength = 0;
116+
} else {
114117
res = res.slice(0, j);
118+
lastSegmentLength = j;
119+
}
115120
lastSlash = i;
116121
dots = 0;
117-
isAboveRoot = false;
118122
continue;
119123
}
120124
} else if (res.length === 2 || res.length === 1) {
121125
res = '';
126+
lastSegmentLength = 0;
122127
lastSlash = i;
123128
dots = 0;
124-
isAboveRoot = false;
125129
continue;
126130
}
127131
}
@@ -130,14 +134,14 @@ function normalizeStringPosix(path, allowAboveRoot) {
130134
res += '/..';
131135
else
132136
res = '..';
133-
isAboveRoot = true;
137+
lastSegmentLength = 2;
134138
}
135139
} else {
136140
if (res.length > 0)
137141
res += '/' + path.slice(lastSlash + 1, i);
138142
else
139143
res = path.slice(lastSlash + 1, i);
140-
isAboveRoot = false;
144+
lastSegmentLength = i - lastSlash - 1;
141145
}
142146
lastSlash = i;
143147
dots = 0;

test/parallel/test-path-normalize.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ assert.strictEqual(path.win32.normalize('bar\\foo..\\..'), 'bar');
2323
assert.strictEqual(path.win32.normalize('bar\\foo..\\..\\baz'), 'bar\\baz');
2424
assert.strictEqual(path.win32.normalize('bar\\foo..\\'), 'bar\\foo..\\');
2525
assert.strictEqual(path.win32.normalize('bar\\foo..'), 'bar\\foo..');
26+
assert.strictEqual(path.win32.normalize('..\\foo..\\..\\..\\bar'),
27+
'..\\..\\bar');
28+
assert.strictEqual(path.win32.normalize('..\\...\\..\\.\\...\\..\\..\\bar'),
29+
'..\\..\\bar');
2630

2731
assert.strictEqual(path.posix.normalize('./fixtures///b/../b/c.js'),
2832
'fixtures/b/c.js');
@@ -37,3 +41,6 @@ assert.strictEqual(path.posix.normalize('bar/foo../..'), 'bar');
3741
assert.strictEqual(path.posix.normalize('bar/foo../../baz'), 'bar/baz');
3842
assert.strictEqual(path.posix.normalize('bar/foo../'), 'bar/foo../');
3943
assert.strictEqual(path.posix.normalize('bar/foo..'), 'bar/foo..');
44+
assert.strictEqual(path.posix.normalize('../foo../../../bar'), '../../bar');
45+
assert.strictEqual(path.posix.normalize('../.../.././.../../../bar'),
46+
'../../bar');

0 commit comments

Comments
 (0)