From 2879f4b7ddcc7466056665a96b8b31a58c455a8f Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Tue, 29 Sep 2015 16:11:34 +0800 Subject: [PATCH] client: refactor permission check for opening files Signed-off-by: Yan, Zheng --- src/client/Client.cc | 76 ++++++++++++++++++++++++++--------- src/client/Client.h | 5 ++- src/client/SyntheticClient.cc | 2 +- src/client/fuse_ll.cc | 2 +- src/libcephfs.cc | 4 +- 5 files changed, 64 insertions(+), 25 deletions(-) diff --git a/src/client/Client.cc b/src/client/Client.cc index e64e42a874a76..c3ddda64e12df 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -4829,29 +4829,64 @@ int Client::_getgrouplist(gid_t** sgids, int uid, int gid) #endif } -int Client::check_permissions(Inode *in, int flags, int uid, int gid) +int Client::inode_permission(Inode *in, uid_t uid, UserGroups& groups, unsigned want) +{ + if (uid == 0) + return 0; + + int ret; + if (uid != in->uid && (in->mode & S_IRWXG)) { + ret = _posix_acl_permission(in, uid, groups, want); + if (ret != -EAGAIN) + return ret; + } + + // check permissions before doing anything else + if (!in->check_mode(uid, groups, want)) + return -EACCES; + return 0; +} + +int Client::may_open(Inode *in, int flags, int uid, int gid) { unsigned want = 0; + if ((flags & O_ACCMODE) == O_WRONLY) want = MAY_WRITE; else if ((flags & O_ACCMODE) == O_RDWR) want = MAY_READ | MAY_WRITE; else if ((flags & O_ACCMODE) == O_RDONLY) want = MAY_READ; + if (flags & O_TRUNC) + want |= MAY_WRITE; + if (uid < 0) + uid = get_uid(); + if (gid < 0) + gid = get_gid(); RequestUserGroups groups(this, uid, gid); - int ret = _posix_acl_permission(in, uid, groups, want); - if (ret != -EAGAIN) - return ret; + int r = 0; + switch (in->mode & S_IFMT) { + case S_IFLNK: + r = -ELOOP; + goto out; + case S_IFDIR: + if (want & MAY_WRITE) { + r = -EISDIR; + goto out; + } + break; + } - // check permissions before doing anything else - if (uid == 0 || in->check_mode(uid, groups, want)) - ret = 0; - else - ret = -EACCES; + r = _getattr(in, CEPH_STAT_CAP_MODE, uid, gid); + if (r < 0) + goto out; - return ret; + r = inode_permission(in, uid, groups, want); +out: + ldout(cct, 3) << __func__ << " " << in << " = " << r << dendl; + return r; } vinodeno_t Client::_get_vino(Inode *in) @@ -7027,9 +7062,7 @@ int Client::open(const char *relpath, int flags, mode_t mode, int stripe_unit, if (!created) { // posix says we can only check permissions of existing files - uid_t uid = get_uid(); - gid_t gid = get_gid(); - r = check_permissions(in.get(), flags, uid, gid); + r = may_open(in.get(), flags); if (r < 0) goto out; } @@ -10457,7 +10490,8 @@ uint64_t Client::ll_get_internal_offset(Inode *in, uint64_t blockno) return (blockno % stripes_per_object) * su; } -int Client::ll_opendir(Inode *in, dir_result_t** dirpp, int uid, int gid) +int Client::ll_opendir(Inode *in, int flags, dir_result_t** dirpp, + int uid, int gid) { Mutex::Locker lock(client_lock); @@ -10467,6 +10501,12 @@ int Client::ll_opendir(Inode *in, dir_result_t** dirpp, int uid, int gid) tout(cct) << "ll_opendir" << std::endl; tout(cct) << vino.ino.val << std::endl; + if (!cct->_conf->fuse_default_permissions) { + int r = may_open(in, flags, uid, gid); + if (r < 0) + return r; + } + int r = 0; if (vino.snapid == CEPH_SNAPDIR) { *dirpp = new dir_result_t(in); @@ -10520,7 +10560,7 @@ int Client::ll_open(Inode *in, int flags, Fh **fhp, int uid, int gid) gid = get_gid(); } if (!cct->_conf->fuse_default_permissions) { - r = check_permissions(in, flags, uid, gid); + r = may_open(in, flags, uid, gid); if (r < 0) goto out; } @@ -10574,7 +10614,7 @@ int Client::ll_create(Inode *parent, const char *name, mode_t mode, ldout(cct, 20) << "ll_create created = " << created << dendl; if (!created) { if (!cct->_conf->fuse_default_permissions) { - r = check_permissions(in.get(), flags, uid, gid); + r = may_open(in.get(), flags, uid, gid); if (r < 0) { if (fhp && *fhp) { int release_r = _release_fh(*fhp); @@ -11595,9 +11635,7 @@ int Client::_posix_acl_permission(Inode *in, uid_t uid, UserGroups& groups, unsi if (in->xattrs.count(ACL_EA_ACCESS)) { const bufferptr& access_acl = in->xattrs[ACL_EA_ACCESS]; - if (in->mode & S_IRWXG) - return posix_acl_permits(access_acl, in->uid, in->gid, - uid, groups, want); + return posix_acl_permits(access_acl, in->uid, in->gid, uid, groups, want); } } return -EAGAIN; diff --git a/src/client/Client.h b/src/client/Client.h index 16f525ad9aed4..0752e864d01b8 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -782,7 +782,8 @@ private: int get_gids(const gid_t **out); }; - int check_permissions(Inode *in, int flags, int uid, int gid); + int inode_permission(Inode *in, uid_t uid, UserGroups& groups, unsigned want); + int may_open(Inode *in, int flags, int uid=-1, int gid=-1); int _getgrouplist(gid_t **sgids, int uid=-1, int gid=-1); int check_data_pool_exist(string name, string value, const OSDMap *osdmap); @@ -1025,7 +1026,7 @@ public: int flags, int uid=-1, int gid=-1); int ll_removexattr(Inode *in, const char *name, int uid=-1, int gid=-1); int ll_listxattr(Inode *in, char *list, size_t size, int uid=-1, int gid=-1); - int ll_opendir(Inode *in, dir_result_t **dirpp, int uid = -1, int gid = -1); + int ll_opendir(Inode *in, int flags, dir_result_t **dirpp, int uid = -1, int gid = -1); int ll_releasedir(dir_result_t* dirp); int ll_fsyncdir(dir_result_t* dirp); int ll_readlink(Inode *in, char *buf, size_t bufsize, int uid = -1, int gid = -1); diff --git a/src/client/SyntheticClient.cc b/src/client/SyntheticClient.cc index d2ab7ecc576fc..9d1888b019e88 100644 --- a/src/client/SyntheticClient.cc +++ b/src/client/SyntheticClient.cc @@ -1348,7 +1348,7 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) dir_result_t *dirp; if (ll_inos.count(i)) { i1 = client->ll_get_inode(vinodeno_t(ll_inos[i],CEPH_NOSNAP)); - if (client->ll_opendir(i1, &dirp) == 0) + if (client->ll_opendir(i1, O_RDONLY, &dirp) == 0) ll_dirs[r] = dirp; client->ll_put(i1); } diff --git a/src/client/fuse_ll.cc b/src/client/fuse_ll.cc index 866a9ffd20bf5..77d696e720449 100644 --- a/src/client/fuse_ll.cc +++ b/src/client/fuse_ll.cc @@ -266,7 +266,7 @@ static void fuse_ll_opendir(fuse_req_t req, fuse_ino_t ino, Inode *in = cfuse->iget(ino); void *dirp; - int r = cfuse->client->ll_opendir(in, (dir_result_t **)&dirp, + int r = cfuse->client->ll_opendir(in, fi->flags, (dir_result_t **)&dirp, ctx->uid, ctx->gid); if (r >= 0) { fi->fh = (long)dirp; diff --git a/src/libcephfs.cc b/src/libcephfs.cc index 849b1c0a66505..6d8bee99e53de 100644 --- a/src/libcephfs.cc +++ b/src/libcephfs.cc @@ -1528,8 +1528,8 @@ extern "C" int ceph_ll_opendir(class ceph_mount_info *cmount, struct ceph_dir_result **dirpp, int uid, int gid) { - return (cmount->get_client()->ll_opendir(in, (dir_result_t**) dirpp, uid, - gid)); + return (cmount->get_client()->ll_opendir(in, O_RDONLY, (dir_result_t**) dirpp, + uid, gid)); } extern "C" int ceph_ll_releasedir(class ceph_mount_info *cmount, -- 2.39.5