mirror of
https://github.com/ceph/ceph
synced 2024-12-18 17:37:38 +00:00
client/Client.cc: prevent segfaulting
The segfaulting in the rmdir function is caused by calling filepath::last_dentry() function. last_dentry() function assumes that the bits vector has always at least one element, which is not the case for the the filepath object created with "/" input. This commit also fixes other functions affected by this bug: link, unlink, rename, mkdir, mknod and symlink. Fixes: http://tracker.ceph.com/issues/9935 Signed-off-by: Michal Jarzabek <stiopa@gmail.com>
This commit is contained in:
parent
a30d90cdc6
commit
6ed7f2364a
@ -6162,31 +6162,35 @@ int Client::link(const char *relexisting, const char *relpath, const UserPerm& p
|
||||
tout(cct) << relpath << std::endl;
|
||||
|
||||
filepath existing(relexisting);
|
||||
filepath path(relpath);
|
||||
string name = path.last_dentry();
|
||||
path.pop_dentry();
|
||||
|
||||
InodeRef in, dir;
|
||||
int r = path_walk(existing, &in, perm, true);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
return r;
|
||||
if (std::string(relpath) == "/") {
|
||||
r = -EEXIST;
|
||||
return r;
|
||||
}
|
||||
filepath path(relpath);
|
||||
string name = path.last_dentry();
|
||||
path.pop_dentry();
|
||||
|
||||
r = path_walk(path, &dir, perm, true);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
return r;
|
||||
if (cct->_conf->client_permissions) {
|
||||
if (S_ISDIR(in->mode)) {
|
||||
r = -EPERM;
|
||||
goto out;
|
||||
return r;
|
||||
}
|
||||
r = may_hardlink(in.get(), perm);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
return r;
|
||||
r = may_create(dir.get(), perm);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
return r;
|
||||
}
|
||||
r = _link(in.get(), dir.get(), name.c_str(), perm);
|
||||
out:
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -6196,6 +6200,9 @@ int Client::unlink(const char *relpath, const UserPerm& perm)
|
||||
tout(cct) << "unlink" << std::endl;
|
||||
tout(cct) << relpath << std::endl;
|
||||
|
||||
if (std::string(relpath) == "/")
|
||||
return -EISDIR;
|
||||
|
||||
filepath path(relpath);
|
||||
string name = path.last_dentry();
|
||||
path.pop_dentry();
|
||||
@ -6218,6 +6225,9 @@ int Client::rename(const char *relfrom, const char *relto, const UserPerm& perm)
|
||||
tout(cct) << relfrom << std::endl;
|
||||
tout(cct) << relto << std::endl;
|
||||
|
||||
if (std::string(relfrom) == "/" || std::string(relto) == "/")
|
||||
return -EBUSY;
|
||||
|
||||
filepath from(relfrom);
|
||||
filepath to(relto);
|
||||
string fromname = from.last_dentry();
|
||||
@ -6256,6 +6266,9 @@ int Client::mkdir(const char *relpath, mode_t mode, const UserPerm& perm)
|
||||
tout(cct) << mode << std::endl;
|
||||
ldout(cct, 10) << "mkdir: " << relpath << dendl;
|
||||
|
||||
if (std::string(relpath) == "/")
|
||||
return -EEXIST;
|
||||
|
||||
filepath path(relpath);
|
||||
string name = path.last_dentry();
|
||||
path.pop_dentry();
|
||||
@ -6325,6 +6338,10 @@ int Client::rmdir(const char *relpath, const UserPerm& perms)
|
||||
Mutex::Locker lock(client_lock);
|
||||
tout(cct) << "rmdir" << std::endl;
|
||||
tout(cct) << relpath << std::endl;
|
||||
|
||||
if (std::string(relpath) == "/")
|
||||
return -EBUSY;
|
||||
|
||||
filepath path(relpath);
|
||||
string name = path.last_dentry();
|
||||
path.pop_dentry();
|
||||
@ -6347,6 +6364,10 @@ int Client::mknod(const char *relpath, mode_t mode, const UserPerm& perms, dev_t
|
||||
tout(cct) << relpath << std::endl;
|
||||
tout(cct) << mode << std::endl;
|
||||
tout(cct) << rdev << std::endl;
|
||||
|
||||
if (std::string(relpath) == "/")
|
||||
return -EEXIST;
|
||||
|
||||
filepath path(relpath);
|
||||
string name = path.last_dentry();
|
||||
path.pop_dentry();
|
||||
@ -6371,6 +6392,9 @@ int Client::symlink(const char *target, const char *relpath, const UserPerm& per
|
||||
tout(cct) << target << std::endl;
|
||||
tout(cct) << relpath << std::endl;
|
||||
|
||||
if (std::string(relpath) == "/")
|
||||
return -EEXIST;
|
||||
|
||||
filepath path(relpath);
|
||||
string name = path.last_dentry();
|
||||
path.pop_dentry();
|
||||
|
@ -130,6 +130,7 @@ class filepath {
|
||||
|
||||
const string& last_dentry() const {
|
||||
if (bits.empty() && path.length() > 0) parse_bits();
|
||||
assert(!bits.empty());
|
||||
return bits[ bits.size()-1 ];
|
||||
}
|
||||
|
||||
|
@ -1739,3 +1739,41 @@ TEST(LibCephFS, ClearSetuid) {
|
||||
|
||||
ceph_shutdown(cmount);
|
||||
}
|
||||
|
||||
TEST(LibCephFS, OperationsOnRoot)
|
||||
{
|
||||
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, "/"), 0);
|
||||
|
||||
char dirname[32];
|
||||
sprintf(dirname, "/somedir%x", getpid());
|
||||
|
||||
ASSERT_EQ(ceph_mkdir(cmount, dirname, 0755), 0);
|
||||
|
||||
ASSERT_EQ(ceph_rmdir(cmount, "/"), -EBUSY);
|
||||
|
||||
ASSERT_EQ(ceph_link(cmount, "/", "/"), -EEXIST);
|
||||
ASSERT_EQ(ceph_link(cmount, dirname, "/"), -EEXIST);
|
||||
ASSERT_EQ(ceph_link(cmount, "nonExisitingDir", "/"), -ENOENT);
|
||||
|
||||
ASSERT_EQ(ceph_unlink(cmount, "/"), -EISDIR);
|
||||
|
||||
ASSERT_EQ(ceph_rename(cmount, "/", "/"), -EBUSY);
|
||||
ASSERT_EQ(ceph_rename(cmount, dirname, "/"), -EBUSY);
|
||||
ASSERT_EQ(ceph_rename(cmount, "nonExistingDir", "/"), -EBUSY);
|
||||
ASSERT_EQ(ceph_rename(cmount, "/", dirname), -EBUSY);
|
||||
ASSERT_EQ(ceph_rename(cmount, "/", "nonExistingDir"), -EBUSY);
|
||||
|
||||
ASSERT_EQ(ceph_mkdir(cmount, "/", 0777), -EEXIST);
|
||||
|
||||
ASSERT_EQ(ceph_mknod(cmount, "/", 0, 0), -EEXIST);
|
||||
|
||||
ASSERT_EQ(ceph_symlink(cmount, "/", "/"), -EEXIST);
|
||||
ASSERT_EQ(ceph_symlink(cmount, dirname, "/"), -EEXIST);
|
||||
ASSERT_EQ(ceph_symlink(cmount, "nonExistingDir", "/"), -EEXIST);
|
||||
|
||||
ceph_shutdown(cmount);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user