diff options
author | Jinmou Li <jinmli@google.com> | 2020-09-16 22:46:33 +0000 |
---|---|---|
committer | Jinmou Li <jinmli@google.com> | 2020-09-17 21:07:12 +0000 |
commit | 15f50c8da63486ac0f24cbb6c2891b66a8081c05 (patch) | |
tree | 24f24d3600e386b8f6aa1002605b932df4e8384d | |
parent | 51a2fe8eb4f045383e67093e3f3fa0b5fac8e9ac (diff) |
Fix kernfs unlinkat and rmdirat incorrect resolved path name
-rw-r--r-- | pkg/sentry/fsimpl/kernfs/filesystem.go | 10 | ||||
-rw-r--r-- | test/fuse/linux/rmdir_test.cc | 27 | ||||
-rw-r--r-- | test/fuse/linux/unlink_test.cc | 24 |
3 files changed, 53 insertions, 8 deletions
diff --git a/pkg/sentry/fsimpl/kernfs/filesystem.go b/pkg/sentry/fsimpl/kernfs/filesystem.go index 49f6a0f1d..c659436ac 100644 --- a/pkg/sentry/fsimpl/kernfs/filesystem.go +++ b/pkg/sentry/fsimpl/kernfs/filesystem.go @@ -658,9 +658,6 @@ func (fs *Filesystem) RmdirAt(ctx context.Context, rp *vfs.ResolvingPath) error fs.mu.Lock() defer fs.mu.Unlock() - // Store the name before walkExistingLocked as rp will be advanced past the - // name in the following call. - name := rp.Component() vfsd, inode, err := fs.walkExistingLocked(ctx, rp) fs.processDeferredDecRefsLocked(ctx) if err != nil { @@ -691,7 +688,7 @@ func (fs *Filesystem) RmdirAt(ctx context.Context, rp *vfs.ResolvingPath) error return err } - if err := parentDentry.inode.RmDir(ctx, name, vfsd); err != nil { + if err := parentDentry.inode.RmDir(ctx, d.name, vfsd); err != nil { virtfs.AbortDeleteDentry(vfsd) return err } @@ -771,9 +768,6 @@ func (fs *Filesystem) UnlinkAt(ctx context.Context, rp *vfs.ResolvingPath) error fs.mu.Lock() defer fs.mu.Unlock() - // Store the name before walkExistingLocked as rp will be advanced past the - // name in the following call. - name := rp.Component() vfsd, _, err := fs.walkExistingLocked(ctx, rp) fs.processDeferredDecRefsLocked(ctx) if err != nil { @@ -799,7 +793,7 @@ func (fs *Filesystem) UnlinkAt(ctx context.Context, rp *vfs.ResolvingPath) error if err := virtfs.PrepareDeleteDentry(mntns, vfsd); err != nil { return err } - if err := parentDentry.inode.Unlink(ctx, name, vfsd); err != nil { + if err := parentDentry.inode.Unlink(ctx, d.name, vfsd); err != nil { virtfs.AbortDeleteDentry(vfsd) return err } diff --git a/test/fuse/linux/rmdir_test.cc b/test/fuse/linux/rmdir_test.cc index 913d3f910..e3200e446 100644 --- a/test/fuse/linux/rmdir_test.cc +++ b/test/fuse/linux/rmdir_test.cc @@ -38,6 +38,7 @@ namespace { class RmDirTest : public FuseTest { protected: const std::string test_dir_name_ = "test_dir"; + const std::string test_subdir_ = "test_subdir"; const mode_t test_dir_mode_ = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO; }; @@ -67,6 +68,32 @@ TEST_F(RmDirTest, NormalRmDir) { EXPECT_EQ(std::string(actual_dirname.data()), test_dir_name_); } +TEST_F(RmDirTest, NormalRmDirSubdir) { + SetServerInodeLookup(test_subdir_, S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO); + const std::string test_dir_path_ = + JoinPath(mount_point_.path().c_str(), test_subdir_, test_dir_name_); + SetServerInodeLookup(test_dir_name_, test_dir_mode_); + + // RmDir code. + struct fuse_out_header rmdir_header = { + .len = sizeof(struct fuse_out_header), + }; + + auto iov_out = FuseGenerateIovecs(rmdir_header); + SetServerResponse(FUSE_RMDIR, iov_out); + + ASSERT_THAT(rmdir(test_dir_path_.c_str()), SyscallSucceeds()); + + struct fuse_in_header in_header; + std::vector<char> actual_dirname(test_dir_name_.length() + 1); + auto iov_in = FuseGenerateIovecs(in_header, actual_dirname); + GetServerActualRequest(iov_in); + + EXPECT_EQ(in_header.len, sizeof(in_header) + test_dir_name_.length() + 1); + EXPECT_EQ(in_header.opcode, FUSE_RMDIR); + EXPECT_EQ(std::string(actual_dirname.data()), test_dir_name_); +} + } // namespace } // namespace testing diff --git a/test/fuse/linux/unlink_test.cc b/test/fuse/linux/unlink_test.cc index 5702e9b32..13efbf7c7 100644 --- a/test/fuse/linux/unlink_test.cc +++ b/test/fuse/linux/unlink_test.cc @@ -37,6 +37,7 @@ namespace { class UnlinkTest : public FuseTest { protected: const std::string test_file_ = "test_file"; + const std::string test_subdir_ = "test_subdir"; }; TEST_F(UnlinkTest, RegularFile) { @@ -61,6 +62,29 @@ TEST_F(UnlinkTest, RegularFile) { EXPECT_EQ(std::string(unlinked_file.data()), test_file_); } +TEST_F(UnlinkTest, RegularFileSubDir) { + SetServerInodeLookup(test_subdir_, S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO); + const std::string test_file_path = + JoinPath(mount_point_.path().c_str(), test_subdir_, test_file_); + SetServerInodeLookup(test_file_, S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO); + + struct fuse_out_header out_header = { + .len = sizeof(struct fuse_out_header), + }; + auto iov_out = FuseGenerateIovecs(out_header); + SetServerResponse(FUSE_UNLINK, iov_out); + + ASSERT_THAT(unlink(test_file_path.c_str()), SyscallSucceeds()); + struct fuse_in_header in_header; + std::vector<char> unlinked_file(test_file_.length() + 1); + auto iov_in = FuseGenerateIovecs(in_header, unlinked_file); + GetServerActualRequest(iov_in); + + EXPECT_EQ(in_header.len, sizeof(in_header) + test_file_.length() + 1); + EXPECT_EQ(in_header.opcode, FUSE_UNLINK); + EXPECT_EQ(std::string(unlinked_file.data()), test_file_); +} + TEST_F(UnlinkTest, NoFile) { const std::string test_file_path = JoinPath(mount_point_.path().c_str(), test_file_); |