summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNicolas Lacasse <nlacasse@google.com>2019-03-22 17:37:10 -0700
committerShentubot <shentubot@google.com>2019-03-22 17:38:13 -0700
commitb81bfd6013ce871524e493272ac36b134f7fbbdf (patch)
tree3d9ac53c18648617ff4a2ebec424b56a96847151
parent3d0b960112c94379e4974fd9b60d4632548a4389 (diff)
lstat should resolve the final path component if it ends in a slash.
PiperOrigin-RevId: 239896221 Change-Id: I0949981fe50c57131c5631cdeb10b225648575c0
-rw-r--r--pkg/sentry/syscalls/linux/sys_stat.go6
-rw-r--r--test/syscalls/linux/stat.cc25
2 files changed, 30 insertions, 1 deletions
diff --git a/pkg/sentry/syscalls/linux/sys_stat.go b/pkg/sentry/syscalls/linux/sys_stat.go
index 95f161aac..8d6a8f616 100644
--- a/pkg/sentry/syscalls/linux/sys_stat.go
+++ b/pkg/sentry/syscalls/linux/sys_stat.go
@@ -78,7 +78,11 @@ func Lstat(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
return 0, nil, err
}
- return 0, nil, fileOpOn(t, linux.AT_FDCWD, path, false /* resolve */, func(root *fs.Dirent, d *fs.Dirent) error {
+ // If the path ends in a slash (i.e. dirPath is true), then we *do*
+ // want to resolve the final component.
+ resolve := dirPath
+
+ return 0, nil, fileOpOn(t, linux.AT_FDCWD, path, resolve, func(root *fs.Dirent, d *fs.Dirent) error {
return stat(t, d, dirPath, statAddr)
})
}
diff --git a/test/syscalls/linux/stat.cc b/test/syscalls/linux/stat.cc
index 625392375..f96da5706 100644
--- a/test/syscalls/linux/stat.cc
+++ b/test/syscalls/linux/stat.cc
@@ -374,6 +374,31 @@ TEST_F(StatTest, ChildOfNonDir) {
EXPECT_THAT(lstat(filename.c_str(), &st), SyscallFailsWithErrno(ENOTDIR));
}
+// Test lstating a symlink directory.
+TEST_F(StatTest, LstatSymlinkDir) {
+ // Create a directory and symlink to it.
+ const auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
+ const std::string symlink_to_dir = NewTempAbsPath();
+ EXPECT_THAT(symlink(dir.path().c_str(), symlink_to_dir.c_str()),
+ SyscallSucceeds());
+ auto cleanup = Cleanup([&symlink_to_dir]() {
+ EXPECT_THAT(unlink(symlink_to_dir.c_str()), SyscallSucceeds());
+ });
+
+ // Lstat on the symlink should return symlink data.
+ struct stat st = {};
+ ASSERT_THAT(lstat(symlink_to_dir.c_str(), &st), SyscallSucceeds());
+ EXPECT_FALSE(S_ISDIR(st.st_mode));
+ EXPECT_TRUE(S_ISLNK(st.st_mode));
+
+ // Lstat on the symlink with a trailing slash should return the directory
+ // data.
+ ASSERT_THAT(lstat(absl::StrCat(symlink_to_dir, "/").c_str(), &st),
+ SyscallSucceeds());
+ EXPECT_TRUE(S_ISDIR(st.st_mode));
+ EXPECT_FALSE(S_ISLNK(st.st_mode));
+}
+
// Verify that we get an ELOOP from too many symbolic links even when there
// are directories in the middle.
TEST_F(StatTest, LstatELOOPPath) {