From bae6c9db656afeff1dede6253300d22082313187 Mon Sep 17 00:00:00 2001 From: Venky Shankar Date: Mon, 6 Aug 2018 06:12:28 -0400 Subject: [PATCH] mds: disallow certain file operations to "." and ".." dirents Also, fixup return value for file operations such as rmdir() and rename() on these directories. Signed-off-by: Venky Shankar --- src/include/filepath.h | 11 +++++++++++ src/mds/Server.cc | 23 +++++++++++++++++++---- src/test/libcephfs/test.cc | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 4 deletions(-) diff --git a/src/include/filepath.h b/src/include/filepath.h index 09821b6ed371d..b7b7b54385e5a 100644 --- a/src/include/filepath.h +++ b/src/include/filepath.h @@ -219,6 +219,17 @@ class filepath { o.push_back(new filepath("var/log", 1)); o.push_back(new filepath("foo/bar", 101)); } + + bool is_last_dot_or_dotdot() const { + if (depth() > 0) { + std::string dname = last_dentry(); + if (dname == "." || dname == "..") { + return true; + } + } + + return false; + } }; WRITE_CLASS_ENCODER(filepath) diff --git a/src/mds/Server.cc b/src/mds/Server.cc index f1077a78ace9b..f79020f4cb19a 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -5356,6 +5356,11 @@ void Server::handle_client_mknod(MDRequestRef& mdr) void Server::handle_client_mkdir(MDRequestRef& mdr) { const MClientRequest::const_ref &req = mdr->client_request; + if (req->get_filepath().is_last_dot_or_dotdot()) { + respond_to_request(mdr, -EEXIST); + return; + } + set rdlocks, wrlocks, xlocks; CDentry *dn = rdlock_path_xlock_dentry(mdr, 0, rdlocks, wrlocks, xlocks, false, false, false); if (!dn) return; @@ -6141,21 +6146,26 @@ void Server::handle_client_unlink(MDRequestRef& mdr) bool rmdir = false; if (req->get_op() == CEPH_MDS_OP_RMDIR) rmdir = true; - if (req->get_filepath().depth() == 0) { + const filepath& refpath = req->get_filepath(); + if (refpath.depth() == 0) { respond_to_request(mdr, -EINVAL); return; - } + } + if (refpath.is_last_dot_or_dotdot()) { + respond_to_request(mdr, -ENOTEMPTY); + return; + } // traverse to path vector trace; CInode *in; CF_MDS_MDRContextFactory cf(mdcache, mdr); - int r = mdcache->path_traverse(mdr, cf, req->get_filepath(), &trace, &in, MDS_TRAVERSE_FORWARD); + int r = mdcache->path_traverse(mdr, cf, refpath, &trace, &in, MDS_TRAVERSE_FORWARD); if (r > 0) return; if (r < 0) { if (r == -ESTALE) { dout(10) << "FAIL on ESTALE but attempting recovery" << dendl; - mdcache->find_ino_peers(req->get_filepath().get_ino(), new C_MDS_TryFindInode(this, mdr)); + mdcache->find_ino_peers(refpath.get_ino(), new C_MDS_TryFindInode(this, mdr)); return; } respond_to_request(mdr, r); @@ -6914,6 +6924,11 @@ void Server::handle_client_rename(MDRequestRef& mdr) respond_to_request(mdr, -EINVAL); return; } + if (srcpath.is_last_dot_or_dotdot() || destpath.is_last_dot_or_dotdot()) { + respond_to_request(mdr, -EBUSY); + return; + } + std::string_view destname = destpath.last_dentry(); vector& srctrace = mdr->dn[1]; diff --git a/src/test/libcephfs/test.cc b/src/test/libcephfs/test.cc index 6659cc0a82e67..fa1cc63bcb82c 100644 --- a/src/test/libcephfs/test.cc +++ b/src/test/libcephfs/test.cc @@ -2147,3 +2147,41 @@ TEST(LibCephFS, TestFutimens) { ceph_close(cmount, fd); ceph_shutdown(cmount); } + +TEST(LibCephFS, OperationsOnDotDot) { + struct ceph_mount_info *cmount; + ASSERT_EQ(ceph_create(&cmount, NULL), 0); + ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0); + ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL)); + ASSERT_EQ(ceph_mount(cmount, NULL), 0); + + char c_dir[1024], c_dir_dot[1024], c_dir_dotdot[1024]; + char c_non_existent_dir[1024], c_non_existent_dirs[1024]; + char c_temp[1024]; + + pid_t mypid = getpid(); + sprintf(c_dir, "/oodd_dir_%d", mypid); + sprintf(c_dir_dot, "/%s/.", c_dir); + sprintf(c_dir_dotdot, "/%s/..", c_dir); + sprintf(c_non_existent_dir, "/%s/../oodd_nonexistent/..", c_dir); + sprintf(c_non_existent_dirs, + "/%s/../ood_nonexistent1_%d/oodd_nonexistent2_%d", c_dir, mypid, mypid); + sprintf(c_temp, "/oodd_temp_%d", mypid); + + ASSERT_EQ(0, ceph_mkdir(cmount, c_dir, 0777)); + ASSERT_EQ(-EEXIST, ceph_mkdir(cmount, c_dir_dot, 0777)); + ASSERT_EQ(-EEXIST, ceph_mkdir(cmount, c_dir_dotdot, 0777)); + ASSERT_EQ(0, ceph_mkdirs(cmount, c_non_existent_dirs, 0777)); + + ASSERT_EQ(-ENOTEMPTY, ceph_rmdir(cmount, c_dir_dot)); + ASSERT_EQ(-ENOTEMPTY, ceph_rmdir(cmount, c_dir_dotdot)); + // non existent directory should return -ENOENT + ASSERT_EQ(-ENOENT, ceph_rmdir(cmount, c_non_existent_dir)); + + ASSERT_EQ(-EBUSY, ceph_rename(cmount, c_dir_dot, c_temp)); + ASSERT_EQ(0, ceph_chdir(cmount, c_dir)); + ASSERT_EQ(0, ceph_mkdir(cmount, c_temp, 0777)); + ASSERT_EQ(-EBUSY, ceph_rename(cmount, c_temp, "..")); + + ceph_shutdown(cmount); +} -- 2.39.5