Skip to content

Commit 76db324

Browse files
authored
Fix a bug in linkat (#690)
This commit fixes a longstanding issue in wasi-libc where the `linkat` function, when both parameters are `AT_FDCWD` or absolute paths, would relativize the two input paths in such a way that the previous stomped over the first, meaning that the wrong actual syscall was issued. This fixes the problem in the same manner as other two-path-taking functions which is to use `find_relpath` for one path and `find_relpath_alt` for the other path.
1 parent ea73f9c commit 76db324

2 files changed

Lines changed: 26 additions & 1 deletion

File tree

libc-bottom-half/sources/posix.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ __wasilibc_link(const char *oldpath, const char *newpath, int flags)
408408
char *old_relative_path;
409409
char *new_relative_path;
410410
int old_dirfd = find_relpath(oldpath, &old_relative_path);
411-
int new_dirfd = find_relpath(newpath, &new_relative_path);
411+
int new_dirfd = find_relpath_alt(newpath, &new_relative_path);
412412

413413
// If we can't find a preopen for it, fail as if we can't find the path.
414414
if (old_dirfd == -1 || new_dirfd == -1) {

test/src/link.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,34 @@ int main(void)
2525
close(fd);
2626

2727
TEST(link(tmp, tmp1)==0);
28+
TEST(unlink(tmp1) != -1);
2829

30+
TEST(linkat(AT_FDCWD, tmp, AT_FDCWD, tmp1, 0)==0);
2931
TEST(unlink(tmp1) != -1);
32+
3033
TEST(unlink(tmp) != -1);
3134

35+
char src[] = "/dir/a";
36+
char dst[] = "/dir/b";
37+
38+
TEST(mkdir("dir", 0700) == 0);
39+
TEST((fd = open(src, flags | O_WRONLY | O_CREAT | O_EXCL, 0600)) > 2);
40+
close(fd);
41+
42+
TEST(link(src, dst)==0);
43+
TEST(unlink(dst) != -1);
44+
45+
TEST(linkat(AT_FDCWD, src, AT_FDCWD, dst, 0) == 0);
46+
TEST(unlink(dst) != -1);
47+
48+
TEST(chdir("/dir") == 0);
49+
50+
TEST(linkat(AT_FDCWD, "a", AT_FDCWD, "b", 0) == 0);
51+
TEST(unlink("b") != -1);
52+
53+
TEST(chdir("/") == 0);
54+
55+
TEST(unlink(src) != -1);
56+
3257
return t_status;
3358
}

0 commit comments

Comments
 (0)