From 6d20d5ef04b8633774ab587f77b67c07acd2a7af Mon Sep 17 00:00:00 2001 From: Andrey Kuznetsov Date: Wed, 10 Jul 2013 14:27:28 -0700 Subject: client, libcephfs: make readlink sane Supply a buffer and copy the data into it. Do not ever expose internal pointers from libcephfs's own cache. Signed-off-by: Sage Weil --- src/client/Client.cc | 24 +++++++++++------------- src/client/Client.h | 4 +++- src/client/fuse_ll.cc | 12 +++++++----- src/include/cephfs/libcephfs.h | 2 +- src/libcephfs.cc | 5 ++--- 5 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/client/Client.cc b/src/client/Client.cc index 8b9185165f1..c40c75560aa 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -4349,13 +4349,18 @@ int Client::readlink(const char *relpath, char *buf, loff_t size) int r = path_walk(path, &in, false); if (r < 0) return r; - + + return _readlink(in, buf, size); +} + +int Client::_readlink(Inode *in, char *buf, size_t size) +{ if (!in->is_symlink()) return -EINVAL; // copy into buf (at most size bytes) - r = in->symlink.length(); - if (r > size) + int r = in->symlink.length(); + if (r > (int)size) r = size; memcpy(buf, in->symlink.c_str(), r); return r; @@ -7016,7 +7021,7 @@ int Client::ll_removexattr(Inode *in, const char *name, int uid, int gid) } -int Client::ll_readlink(Inode *in, const char **value, int uid, int gid) +int Client::ll_readlink(Inode *in, char *buf, size_t buflen, int uid, int gid) { Mutex::Locker lock(client_lock); @@ -7032,15 +7037,8 @@ int Client::ll_readlink(Inode *in, const char **value, int uid, int gid) ++dn; } - int r = 0; - if (in->is_symlink()) { - *value = in->symlink.c_str(); - } else { - *value = ""; - r = -EINVAL; - } - ldout(cct, 3) << "ll_readlink " << vino << " = " << r << " (" << *value - << ")" << dendl; + int r = _readlink(in, buf, buflen); + ldout(cct, 3) << "ll_readlink " << vino << " = " << r << dendl; return r; } diff --git a/src/client/Client.h b/src/client/Client.h index baeb8d5ebdb..f7302338584 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -555,6 +555,7 @@ private: int _mknod(Inode *dir, const char *name, mode_t mode, dev_t rdev, int uid=-1, int gid=-1, Inode **inp = 0); int _setattr(Inode *in, struct stat *attr, int mask, int uid=-1, int gid=-1, Inode **inp = 0); int _getattr(Inode *in, int mask, int uid=-1, int gid=-1, bool force=false); + int _readlink(Inode *in, char *buf, size_t size); int _getxattr(Inode *in, const char *name, void *value, size_t len, int uid=-1, int gid=-1); int _listxattr(Inode *in, char *names, size_t len, int uid=-1, int gid=-1); int _setxattr(Inode *in, const char *name, const void *value, size_t len, int flags, int uid=-1, int gid=-1); @@ -638,6 +639,7 @@ public: // symlinks int readlink(const char *path, char *buf, loff_t size); + int symlink(const char *existing, const char *newname); // inode stuff @@ -740,7 +742,7 @@ public: 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_releasedir(dir_result_t* dirp); - int ll_readlink(Inode *in, const char **value, int uid = -1, int gid = -1); + int ll_readlink(Inode *in, char *buf, size_t bufsize, int uid = -1, int gid = -1); int ll_mknod(Inode *in, const char *name, mode_t mode, dev_t rdev, struct stat *attr, Inode **out, int uid = -1, int gid = -1); int ll_mkdir(Inode *in, const char *name, mode_t mode, struct stat *attr, diff --git a/src/client/fuse_ll.cc b/src/client/fuse_ll.cc index 97a11f187fe..57aca0585b1 100644 --- a/src/client/fuse_ll.cc +++ b/src/client/fuse_ll.cc @@ -258,13 +258,15 @@ static void fuse_ll_readlink(fuse_req_t req, fuse_ino_t ino) CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(req); const struct fuse_ctx *ctx = fuse_req_ctx(req); Inode *in = cfuse->iget(ino); - const char *value; + char buf[PATH_MAX + 1]; // leave room for a null terminator - int r = cfuse->client->ll_readlink(in, &value, ctx->uid, ctx->gid); - if (r == 0) - fuse_reply_readlink(req, value); - else + int r = cfuse->client->ll_readlink(in, buf, sizeof(buf) - 1, ctx->uid, ctx->gid); + if (r >= 0) { + buf[r] = '\0'; + fuse_reply_readlink(req, buf); + } else { fuse_reply_err(req, -r); + } cfuse->iput(in); // iput required } diff --git a/src/include/cephfs/libcephfs.h b/src/include/cephfs/libcephfs.h index c45c19d8c96..bf8634ff0f2 100644 --- a/src/include/cephfs/libcephfs.h +++ b/src/include/cephfs/libcephfs.h @@ -1291,7 +1291,7 @@ int ceph_ll_unlink(struct ceph_mount_info *cmount, struct Inode *in, int ceph_ll_statfs(struct ceph_mount_info *cmount, struct Inode *in, struct statvfs *stbuf); int ceph_ll_readlink(struct ceph_mount_info *cmount, struct Inode *in, - char **value, int uid, int gid); + char *buf, size_t bufsize, int uid, int gid); int ceph_ll_symlink(struct ceph_mount_info *cmount, struct Inode *parent, const char *name, const char *value, struct stat *attr, struct Inode **in, int uid, int gid); diff --git a/src/libcephfs.cc b/src/libcephfs.cc index 97a51aec3c6..5f346703878 100644 --- a/src/libcephfs.cc +++ b/src/libcephfs.cc @@ -1374,11 +1374,10 @@ extern "C" int ceph_ll_statfs(class ceph_mount_info *cmount, } extern "C" int ceph_ll_readlink(class ceph_mount_info *cmount, - Inode *in, char **value, int uid, + Inode *in, char *buf, size_t bufsiz, int uid, int gid) { - return (cmount->get_client()->ll_readlink(in, (const char**) value, - uid, gid)); + return (cmount->get_client()->ll_readlink(in, buf, bufsiz, uid, gid)); } extern "C" int ceph_ll_symlink(class ceph_mount_info *cmount, -- cgit v1.2.1