Skip to content

Commit f8fe795

Browse files
committed
Fix for pathnames with trailing slash
Such paths should be rejected by open / stat / realpath but we were silently ignoring the tailing slashed. Fixes: #22335
1 parent 80d2150 commit f8fe795

File tree

10 files changed

+28
-18
lines changed

10 files changed

+28
-18
lines changed

src/library_fs.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ FS.staticInit();
177177
// paths
178178
//
179179
lookupPath(path, opts = {}) {
180+
var trailingSlash = path.endsWith('/');
180181
path = PATH_FS.resolve(path);
181182

182183
if (!path) return { path: '', node: null };
@@ -233,6 +234,10 @@ FS.staticInit();
233234
}
234235
}
235236

237+
if (trailingSlash && !FS.isDir(current.mode)) {
238+
throw new FS.ErrnoError({{{ cDefs.ENOTDIR }}});
239+
}
240+
236241
return { path: current_path, node: current };
237242
},
238243
getPath(node) {

src/library_path.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ addToLibrary({
3737
return parts;
3838
},
3939
normalize: (path) => {
40-
var isAbsolute = PATH.isAbs(path),
41-
trailingSlash = path.substr(-1) === '/';
40+
var isAbsolute = PATH.isAbs(path);
41+
var trailingSlash = path.endsWith('/');
4242
// Normalize the path
4343
path = PATH.normalizeArray(path.split('/').filter((p) => !!p), !isAbsolute).join('/');
4444
if (!path && !isAbsolute) {

system/lib/wasmfs/paths.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,6 @@ ParsedParent doParseParent(std::string_view path,
7575
path.remove_prefix(1);
7676
}
7777

78-
// Ignore trailing '/'.
79-
while (!path.empty() && path.back() == '/') {
80-
path.remove_suffix(1);
81-
}
82-
8378
// An empty path here means that the path was equivalent to "/" and does not
8479
// contain a child segment for us to return. The root is its own parent, so we
8580
// can handle this by returning (root, ".").

test/other/metadce/test_metadce_files_wasmfs.funcs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ $__wasm_call_ctors
3131
$abort
3232
$char*\20std::__2::copy_n\5babi:nn180100\5d<char\20const*\2c\20unsigned\20long\2c\20char*\2c\200>\28char\20const*\2c\20unsigned\20long\2c\20char*\29
3333
$decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul>::__dispatch\5babi:nn180100\5d<std::__2::__variant_detail::__dtor<std::__2::__variant_detail::__traits<std::__2::vector<wasmfs::Directory::Entry\2c\20std::__2::allocator<wasmfs::Directory::Entry>>\2c\20int>\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:nn180100\5d\28\29::'lambda'\28auto&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20std::__2::vector<wasmfs::Directory::Entry\2c\20std::__2::allocator<wasmfs::Directory::Entry>>\2c\20int>&>\28auto\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20std::__2::vector<wasmfs::Directory::Entry\2c\20std::__2::allocator<wasmfs::Directory::Entry>>\2c\20int>&\29
34+
$decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:nn180100\5d<void\20std::__2::__variant_detail::__ctor<std::__2::__variant_detail::__traits<long\2c\20std::__2::shared_ptr<wasmfs::File>>>::__generic_construct\5babi:nn180100\5d<std::__2::__variant_detail::__move_constructor<std::__2::__variant_detail::__traits<long\2c\20std::__2::shared_ptr<wasmfs::File>>\2c\20\28std::__2::__variant_detail::_Trait\291>>\28std::__2::__variant_detail::__ctor<std::__2::__variant_detail::__traits<long\2c\20std::__2::shared_ptr<wasmfs::File>>>&\2c\20std::__2::__variant_detail::__move_constructor<std::__2::__variant_detail::__traits<long\2c\20std::__2::shared_ptr<wasmfs::File>>\2c\20\28std::__2::__variant_detail::_Trait\291>&&\29::'lambda'\28std::__2::__variant_detail::__move_constructor<std::__2::__variant_detail::__traits<long\2c\20std::__2::shared_ptr<wasmfs::File>>\2c\20\28std::__2::__variant_detail::_Trait\291>&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20long\2c\20std::__2::shared_ptr<wasmfs::File>>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20long\2c\20std::__2::shared_ptr<wasmfs::File>>&&>\28std::__2::__variant_detail::__move_constructor<std::__2::__variant_detail::__traits<long\2c\20std::__2::shared_ptr<wasmfs::File>>\2c\20\28std::__2::__variant_detail::_Trait\291>\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20long\2c\20std::__2::shared_ptr<wasmfs::File>>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20long\2c\20std::__2::shared_ptr<wasmfs::File>>&&\29
3435
$decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul>::__dispatch\5babi:nn180100\5d<std::__2::__variant_detail::__dtor<std::__2::__variant_detail::__traits<long\2c\20std::__2::shared_ptr<wasmfs::File>>\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:nn180100\5d\28\29::'lambda'\28auto&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20long\2c\20std::__2::shared_ptr<wasmfs::File>>&>\28auto\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20long\2c\20std::__2::shared_ptr<wasmfs::File>>&\29
36+
$decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul\2c\201ul>::__dispatch\5babi:nn180100\5d<void\20std::__2::__variant_detail::__ctor<std::__2::__variant_detail::__traits<long\2c\20std::__2::shared_ptr<wasmfs::File>>>::__generic_construct\5babi:nn180100\5d<std::__2::__variant_detail::__move_constructor<std::__2::__variant_detail::__traits<long\2c\20std::__2::shared_ptr<wasmfs::File>>\2c\20\28std::__2::__variant_detail::_Trait\291>>\28std::__2::__variant_detail::__ctor<std::__2::__variant_detail::__traits<long\2c\20std::__2::shared_ptr<wasmfs::File>>>&\2c\20std::__2::__variant_detail::__move_constructor<std::__2::__variant_detail::__traits<long\2c\20std::__2::shared_ptr<wasmfs::File>>\2c\20\28std::__2::__variant_detail::_Trait\291>&&\29::'lambda'\28std::__2::__variant_detail::__move_constructor<std::__2::__variant_detail::__traits<long\2c\20std::__2::shared_ptr<wasmfs::File>>\2c\20\28std::__2::__variant_detail::_Trait\291>&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20long\2c\20std::__2::shared_ptr<wasmfs::File>>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20long\2c\20std::__2::shared_ptr<wasmfs::File>>&&>\28std::__2::__variant_detail::__move_constructor<std::__2::__variant_detail::__traits<long\2c\20std::__2::shared_ptr<wasmfs::File>>\2c\20\28std::__2::__variant_detail::_Trait\291>\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20long\2c\20std::__2::shared_ptr<wasmfs::File>>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20long\2c\20std::__2::shared_ptr<wasmfs::File>>&&\29
3537
$dummy
3638
$emscripten_builtin_malloc
3739
$fflush
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
50957
1+
51335

test/other/test_realpath_2.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ int main(int argc, char **argv) {
2020
testrealpath("testfile.txt");
2121
testrealpath("Folder/testfile.txt");
2222
testrealpath("testnonexistentfile.txt");
23+
// Filenames with trailing slash should fail.
24+
testrealpath("Folder/testfile.txt/");
2325
// folders
2426
testrealpath("Folder");
2527
testrealpath("/Folder");

test/other/test_realpath_2.out

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
Resolved: "testfile.txt" => "/testfile.txt"
22
Resolved: "Folder/testfile.txt" => "/Folder/testfile.txt"
33
Resolve failed: "testnonexistentfile.txt"
4+
Resolve failed: "Folder/testfile.txt/"
45
Resolved: "Folder" => "/Folder"
56
Resolved: "/Folder" => "/Folder"
67
Resolved: "./" => "/"

test/wasmfs/wasmfs_open.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@
1616
// FIXME: Merge with other existing close and open tests.
1717

1818
int main() {
19-
// Test writing to a file with a trailing slash.
19+
// Opening a file with trailing backslash should fail.
2020
int fd = open("/dev/stdout/", O_WRONLY);
21-
22-
dprintf(fd, "WORKING WITH TRAILING BACKSLASH\n");
23-
24-
// Close open file
25-
close(fd);
21+
assert(fd == -1);
22+
#ifdef WASMFS
23+
assert(errno == ENOTDIR);
24+
#else
25+
assert(errno == ENOENT);
26+
#endif
27+
printf("Errno: %s\n", strerror(errno));
2628

2729
// Test writing to a file with no trailing backslash.
2830
int fd2 = open("/dev/stdout", O_WRONLY);

test/wasmfs/wasmfs_open.out

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
WORKING WITH TRAILING BACKSLASH
21
WORKING WITHOUT TRAILING BACKSLASH
32
Errno: Bad file descriptor
43
Errno: Is a directory

test/wasmfs/wasmfs_stat.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,13 @@ int main() {
2525
assert(result == -1);
2626
assert(errno == EBADF);
2727

28+
// Test stat of file with trailing slash should fail.
29+
assert(stat("/dev/stdout/", &invalid) == -1);
30+
assert(errno == ENOTDIR);
31+
2832
// Test opening a file and calling fstat.
2933
struct stat file;
30-
int fd = open("/dev/stdout/", O_WRONLY);
34+
int fd = open("/dev/stdout", O_WRONLY);
3135
assert(fd >= 0);
3236
assert(fstat(fd, &file) != -1);
3337

@@ -48,7 +52,7 @@ int main() {
4852
close(fd);
4953

5054
// Check to see if the previous inode number matches.
51-
int newfd = open("/dev/stdout/", O_WRONLY);
55+
int newfd = open("/dev/stdout", O_WRONLY);
5256
struct stat newFile;
5357
assert(newfd >= 0);
5458
assert(fstat(newfd, &newFile) != -1);
@@ -95,7 +99,7 @@ int main() {
9599

96100
// Test calling stat without opening a file.
97101
struct stat statFile;
98-
assert(stat("/dev/stdout/", &statFile) != -1);
102+
assert(stat("/dev/stdout", &statFile) != -1);
99103

100104
assert(statFile.st_size == 0);
101105
assert((statFile.st_mode & S_IFMT) == S_IFCHR);

0 commit comments

Comments
 (0)