From 3163258a33188f7928a796acfdfdac7b35f03278 Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Tue, 8 Sep 2015 15:56:02 -0400 Subject: [PATCH] make changing credentials opportunistic + per thread setgroups cache closes #129,#131 --- Makefile | 6 +- src/access.cpp | 8 +- src/chmod.cpp | 8 +- src/chown.cpp | 8 +- src/create.cpp | 11 +-- src/getattr.cpp | 4 +- src/getxattr.cpp | 4 +- src/init.cpp | 3 + src/ioctl.cpp | 8 +- src/link.cpp | 11 +-- src/listxattr.cpp | 4 +- src/mkdir.cpp | 11 +-- src/mknod.cpp | 12 +-- src/open.cpp | 8 +- src/readdir.cpp | 8 +- src/readlink.cpp | 8 +- src/removexattr.cpp | 4 +- src/rename.cpp | 8 +- src/rmdir.cpp | 8 +- src/setxattr.cpp | 4 +- src/statfs.cpp | 8 +- src/symlink.cpp | 8 +- src/truncate.cpp | 8 +- src/ugid.cpp | 63 +++++++++++++- src/ugid.hpp | 23 ++++- src/ugid_linux.hpp | 73 +++++++++++----- src/{ugid_osx.hpp => ugid_linux.ipp} | 44 +++++----- src/ugid_rwlock.hpp | 107 ++++++++++++++++++++++++ src/{ugid_mutex.hpp => ugid_rwlock.ipp} | 54 ++++++------ src/unlink.cpp | 8 +- src/utimens.cpp | 8 +- 31 files changed, 381 insertions(+), 169 deletions(-) rename src/{ugid_osx.hpp => ugid_linux.ipp} (68%) create mode 100644 src/ugid_rwlock.hpp rename src/{ugid_mutex.hpp => ugid_rwlock.ipp} (65%) diff --git a/Makefile b/Makefile index 89129e39..9516e8f3 100644 --- a/Makefile +++ b/Makefile @@ -65,6 +65,8 @@ FLOCK = $(shell $(CPPFIND) "fuse_fs_flock") READ_BUF = $(shell $(CPPFIND) "fuse_fs_read_buf") WRITE_BUF = $(shell $(CPPFIND) "fuse_fs_write_buf") +UGID_USE_RWLOCK = 0 + OPTS = -O2 SRC = $(wildcard src/*.cpp) OBJ = $(SRC:src/%.cpp=obj/%.o) @@ -74,6 +76,7 @@ MANPAGE = $(TARGET).1 FUSE_CFLAGS = $(shell $(PKGCONFIG) --cflags fuse) CFLAGS = -g -Wall \ $(OPTS) \ + -Wno-unused-result \ $(FUSE_CFLAGS) \ -DFUSE_USE_VERSION=26 \ -MMD \ @@ -81,7 +84,8 @@ CFLAGS = -g -Wall \ -DFALLOCATE=$(FALLOCATE) \ -DFLOCK=$(FLOCK) \ -DREAD_BUF=$(READ_BUF) \ - -DWRITE_BUF=$(WRITE_BUF) + -DWRITE_BUF=$(WRITE_BUF) \ + -DUGID_USE_RWLOCK=$(UGID_USE_RWLOCK) LDFLAGS = $(shell $(PKGCONFIG) fuse --libs) PREFIX = /usr/local diff --git a/src/access.cpp b/src/access.cpp index 2da0a538..3a83fb84 100644 --- a/src/access.cpp +++ b/src/access.cpp @@ -74,10 +74,10 @@ namespace mergerfs access(const char *fusepath, int mask) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::get(fc); - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const fuse_context *fc = fuse_get_context(); + const Config &config = Config::get(fc); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _access(config.access, config.srcmounts, diff --git a/src/chmod.cpp b/src/chmod.cpp index dc5dab10..913cc759 100644 --- a/src/chmod.cpp +++ b/src/chmod.cpp @@ -74,10 +74,10 @@ namespace mergerfs chmod(const char *fusepath, mode_t mode) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::get(fc); - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const fuse_context *fc = fuse_get_context(); + const Config &config = Config::get(fc); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _chmod(config.chmod, config.srcmounts, diff --git a/src/chown.cpp b/src/chown.cpp index 27dc7400..7817c06f 100644 --- a/src/chown.cpp +++ b/src/chown.cpp @@ -78,10 +78,10 @@ namespace mergerfs uid_t uid, gid_t gid) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::get(fc); - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const fuse_context *fc = fuse_get_context(); + const Config &config = Config::get(fc); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _chown(config.chown, config.srcmounts, diff --git a/src/create.cpp b/src/create.cpp index ae2ed60e..0bfa85b3 100644 --- a/src/create.cpp +++ b/src/create.cpp @@ -40,6 +40,7 @@ using std::string; using std::vector; using mergerfs::Policy; +using namespace mergerfs; static int @@ -69,7 +70,7 @@ _create(Policy::Func::Search searchFunc, if(createpath[0] != existingpath[0]) { - const mergerfs::ugid::SetResetGuard ugid(0,0); + const ugid::SetRootGuard ugidGuard; fs::clonepath(existingpath[0],createpath[0],dirname); } @@ -93,10 +94,10 @@ namespace mergerfs mode_t mode, fuse_file_info *fileinfo) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::get(fc); - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const fuse_context *fc = fuse_get_context(); + const Config &config = Config::get(fc); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _create(config.getattr, config.create, diff --git a/src/getattr.cpp b/src/getattr.cpp index bf4f487f..c2a25409 100644 --- a/src/getattr.cpp +++ b/src/getattr.cpp @@ -100,8 +100,8 @@ namespace mergerfs if(fusepath == config.controlfile) return _getattr_controlfile(*st); - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _getattr(config.getattr, config.srcmounts, diff --git a/src/getxattr.cpp b/src/getxattr.cpp index d3105e29..a9fb1eab 100644 --- a/src/getxattr.cpp +++ b/src/getxattr.cpp @@ -303,8 +303,8 @@ namespace mergerfs buf, count); - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _getxattr(config.getxattr, config.srcmounts, diff --git a/src/init.cpp b/src/init.cpp index e495286d..b21818af 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -25,6 +25,7 @@ #include #include "config.hpp" +#include "ugid.hpp" namespace mergerfs { @@ -33,6 +34,8 @@ namespace mergerfs void * init(fuse_conn_info *conn) { + ugid::init(); + #ifdef FUSE_CAP_ASYNC_READ conn->want |= FUSE_CAP_ASYNC_READ; #endif diff --git a/src/ioctl.cpp b/src/ioctl.cpp index 9ef0d1e4..ee03a7ba 100644 --- a/src/ioctl.cpp +++ b/src/ioctl.cpp @@ -98,10 +98,10 @@ _ioctl_dir(const string &fusepath, const int cmd, void *data) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::get(fc); - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const fuse_context *fc = fuse_get_context(); + const Config &config = Config::get(fc); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _ioctl_dir_base(config.getattr, config.srcmounts, diff --git a/src/link.cpp b/src/link.cpp index d8e7733c..0c9a8f89 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -38,6 +38,7 @@ using std::string; using std::vector; using mergerfs::Policy; +using namespace mergerfs; static int @@ -64,7 +65,7 @@ _single_link(Policy::Func::Search searchFunc, return -1; { - const mergerfs::ugid::SetResetGuard ugid(0,0); + const ugid::SetRootGuard ugidGuard; fs::clonepath(foundpath[0],base,newpathdir); } @@ -110,10 +111,10 @@ namespace mergerfs link(const char *from, const char *to) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::get(fc); - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const fuse_context *fc = fuse_get_context(); + const Config &config = Config::get(fc); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _link(config.getattr, config.link, diff --git a/src/listxattr.cpp b/src/listxattr.cpp index 4d8a1e54..73f86c4d 100644 --- a/src/listxattr.cpp +++ b/src/listxattr.cpp @@ -117,8 +117,8 @@ namespace mergerfs if(fusepath == config.controlfile) return _listxattr_controlfile(list,size); - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _listxattr(config.listxattr, config.srcmounts, diff --git a/src/mkdir.cpp b/src/mkdir.cpp index 1ddb3bbc..6b600dbe 100644 --- a/src/mkdir.cpp +++ b/src/mkdir.cpp @@ -39,6 +39,7 @@ using std::string; using std::vector; using mergerfs::Policy; +using namespace mergerfs; static int @@ -72,7 +73,7 @@ _mkdir(Policy::Func::Search searchFunc, if(createpath != existingpath[0]) { - const mergerfs::ugid::SetResetGuard ugid(0,0); + const ugid::SetRootGuard ugidGuard; fs::clonepath(existingpath[0],createpath,dirname); } @@ -94,10 +95,10 @@ namespace mergerfs mkdir(const char *fusepath, mode_t mode) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::get(fc); - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const fuse_context *fc = fuse_get_context(); + const Config &config = Config::get(fc); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _mkdir(config.getattr, config.mkdir, diff --git a/src/mknod.cpp b/src/mknod.cpp index 9a8f2504..62c55803 100644 --- a/src/mknod.cpp +++ b/src/mknod.cpp @@ -40,7 +40,7 @@ using std::string; using std::vector; -using mergerfs::Policy; +using namespace mergerfs; static int @@ -74,7 +74,7 @@ _mknod(Policy::Func::Search searchFunc, if(createpath != existingpath[0]) { - const mergerfs::ugid::SetResetGuard ugid(0,0); + const ugid::SetRootGuard ugidGuard; fs::clonepath(existingpath[0],createpath,dirname); } @@ -97,10 +97,10 @@ namespace mergerfs mode_t mode, dev_t rdev) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::get(fc); - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const fuse_context *fc = fuse_get_context(); + const Config &config = Config::get(fc); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _mknod(config.getattr, config.mknod, diff --git a/src/open.cpp b/src/open.cpp index 08a8c3da..4efaaa6e 100644 --- a/src/open.cpp +++ b/src/open.cpp @@ -76,10 +76,10 @@ namespace mergerfs open(const char *fusepath, fuse_file_info *fileinfo) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::get(fc); - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const fuse_context *fc = fuse_get_context(); + const Config &config = Config::get(fc); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _open(config.open, config.srcmounts, diff --git a/src/readdir.cpp b/src/readdir.cpp index 77826ef2..10fb8392 100644 --- a/src/readdir.cpp +++ b/src/readdir.cpp @@ -96,10 +96,10 @@ namespace mergerfs off_t offset, fuse_file_info *fi) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::get(fc); - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const fuse_context *fc = fuse_get_context(); + const Config &config = Config::get(fc); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _readdir(config.srcmounts, fusepath, diff --git a/src/readlink.cpp b/src/readlink.cpp index 08e8b7ce..3bb40492 100644 --- a/src/readlink.cpp +++ b/src/readlink.cpp @@ -75,10 +75,10 @@ namespace mergerfs char *buf, size_t size) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::get(fc); - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const fuse_context *fc = fuse_get_context(); + const Config &config = Config::get(fc); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _readlink(config.readlink, config.srcmounts, diff --git a/src/removexattr.cpp b/src/removexattr.cpp index 3b1cfca5..ce5b238b 100644 --- a/src/removexattr.cpp +++ b/src/removexattr.cpp @@ -87,8 +87,8 @@ namespace mergerfs if(fusepath == config.controlfile) return -ENOTSUP; - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _removexattr(config.removexattr, config.srcmounts, diff --git a/src/rename.cpp b/src/rename.cpp index 265189fe..9e4b91f8 100644 --- a/src/rename.cpp +++ b/src/rename.cpp @@ -130,10 +130,10 @@ namespace mergerfs rename(const char *oldpath, const char *newpath) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::get(fc); - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const fuse_context *fc = fuse_get_context(); + const Config &config = Config::get(fc); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _rename(config.getattr, config.rename, diff --git a/src/rmdir.cpp b/src/rmdir.cpp index 30b94af1..4f28d741 100644 --- a/src/rmdir.cpp +++ b/src/rmdir.cpp @@ -73,10 +73,10 @@ namespace mergerfs int rmdir(const char *fusepath) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::get(fc); - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readguard(&config.srcmountslock); + const fuse_context *fc = fuse_get_context(); + const Config &config = Config::get(fc); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readguard(&config.srcmountslock); return _rmdir(config.rmdir, config.srcmounts, diff --git a/src/setxattr.cpp b/src/setxattr.cpp index b82f1b66..03df2004 100644 --- a/src/setxattr.cpp +++ b/src/setxattr.cpp @@ -323,8 +323,8 @@ namespace mergerfs flags); } - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _setxattr(config.setxattr, config.srcmounts, diff --git a/src/statfs.cpp b/src/statfs.cpp index 7c9a3827..263fe13a 100644 --- a/src/statfs.cpp +++ b/src/statfs.cpp @@ -124,10 +124,10 @@ namespace mergerfs statfs(const char *fusepath, struct statvfs *stat) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::get(fc); - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const fuse_context *fc = fuse_get_context(); + const Config &config = Config::get(fc); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _statfs(config.srcmounts, *stat); diff --git a/src/symlink.cpp b/src/symlink.cpp index e20ff9c1..1a76b722 100644 --- a/src/symlink.cpp +++ b/src/symlink.cpp @@ -77,10 +77,10 @@ namespace mergerfs symlink(const char *oldpath, const char *newpath) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::get(fc); - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const fuse_context *fc = fuse_get_context(); + const Config &config = Config::get(fc); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _symlink(config.symlink, config.srcmounts, diff --git a/src/truncate.cpp b/src/truncate.cpp index ab99bd30..c0509699 100644 --- a/src/truncate.cpp +++ b/src/truncate.cpp @@ -77,10 +77,10 @@ namespace mergerfs truncate(const char *fusepath, off_t size) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::get(fc); - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const fuse_context *fc = fuse_get_context(); + const Config &config = Config::get(fc); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _truncate(config.truncate, config.srcmounts, diff --git a/src/ugid.cpp b/src/ugid.cpp index 3f093739..28cf5d93 100644 --- a/src/ugid.cpp +++ b/src/ugid.cpp @@ -22,10 +22,65 @@ THE SOFTWARE. */ -#include "ugid.hpp" +#include +#include +#include +#include +#include -#if defined __linux__ -#elif defined __APPLE__ +#include +#include + +typedef std::vector gid_t_vector; +typedef std::map gid_t_cache; + +#if defined __linux__ and UGID_USE_RWLOCK == 0 +#include "ugid_linux.ipp" #else -pthread_mutex_t mergerfs::ugid::SetResetGuard::lock = PTHREAD_MUTEX_INITIALIZER; +#include "ugid_rwlock.ipp" #endif + +namespace mergerfs +{ + namespace ugid + { + static + inline + void + prime_cache(const uid_t uid, + const gid_t gid, + gid_t_vector &gidlist) + { + int rv; + char buf[4096]; + struct passwd pwd; + struct passwd *pwdrv; + + rv = getpwuid_r(uid,&pwd,buf,sizeof(buf),&pwdrv); + if(pwdrv != NULL && rv == 0) + { + int count; + + count = 0; + rv = ::getgrouplist(pwd.pw_name,gid,NULL,&count); + gidlist.resize(count); + rv = ::getgrouplist(pwd.pw_name,gid,&gidlist[0],&count); + if(rv == -1) + gidlist.resize(1,gid); + } + } + + void + initgroups(const uid_t uid, + const gid_t gid) + { + static __thread gid_t_cache cache; + + gid_t_vector &gidlist = cache[uid]; + if(gidlist.empty()) + prime_cache(uid,gid,gidlist); + + setgroups(gidlist); + } + } +} diff --git a/src/ugid.hpp b/src/ugid.hpp index ffb42fe5..4555f333 100644 --- a/src/ugid.hpp +++ b/src/ugid.hpp @@ -25,12 +25,27 @@ #ifndef __UGID_HPP__ #define __UGID_HPP__ -#if defined __linux__ +#include +#include + +#include + +typedef std::vector gid_t_vector; + +namespace mergerfs +{ + namespace ugid + { + void init(); + void initgroups(const uid_t uid, const gid_t gid); + void setgroups(const gid_t_vector &gidlist); + } +} + +#if defined __linux__ and UGID_USE_RWLOCK == 0 #include "ugid_linux.hpp" -#elif defined __APPLE__ -#include "ugid_osx.hpp" #else -#include "ugid_mutex.hpp" +#include "ugid_rwlock.hpp" #endif #endif /* __UGID_HPP__ */ diff --git a/src/ugid_linux.hpp b/src/ugid_linux.hpp index bc047bf6..5e5b2706 100644 --- a/src/ugid_linux.hpp +++ b/src/ugid_linux.hpp @@ -27,38 +27,71 @@ #include #include +#include +#include + +#include +#include + namespace mergerfs { namespace ugid { - struct SetResetGuard + extern __thread uid_t currentuid; + extern __thread gid_t currentgid; + extern __thread bool initialized; + + struct Set { - SetResetGuard(const uid_t _newuid, - const gid_t _newgid) + Set(const uid_t newuid, + const gid_t newgid) { - olduid = ::syscall(SYS_geteuid); - oldgid = ::syscall(SYS_getegid); - newuid = _newuid; - newgid = _newgid; - - if(newgid != oldgid) - ::syscall(SYS_setregid,-1,newgid); - if(newuid != olduid) + if(!initialized) + { + currentuid = ::syscall(SYS_geteuid); + currentgid = ::syscall(SYS_getegid); + initialized = true; + } + + if(newuid == currentuid && newgid == currentgid) + return; + + if(currentuid != 0) + { + ::syscall(SYS_setreuid,-1,0); + ::syscall(SYS_setregid,-1,0); + } + + if(newgid) + { + ::syscall(SYS_setregid,-1,newgid); + initgroups(newuid,newgid); + } + + if(newuid) ::syscall(SYS_setreuid,-1,newuid); + + currentuid = newuid; + currentgid = newgid; + } + }; + + struct SetRootGuard + { + SetRootGuard() : + prevuid(currentuid), + prevgid(currentgid) + { + Set(0,0); } - ~SetResetGuard() + ~SetRootGuard() { - if(olduid != newuid) - ::syscall(SYS_setreuid,-1,olduid); - if(oldgid != newgid) - ::syscall(SYS_setregid,-1,oldgid); + Set(prevuid,prevgid); } - uid_t olduid; - gid_t oldgid; - uid_t newuid; - gid_t newgid; + const uid_t prevuid; + const gid_t prevgid; }; } } diff --git a/src/ugid_osx.hpp b/src/ugid_linux.ipp similarity index 68% rename from src/ugid_osx.hpp rename to src/ugid_linux.ipp index b0cd18c2..880ca1f8 100644 --- a/src/ugid_osx.hpp +++ b/src/ugid_linux.ipp @@ -22,36 +22,32 @@ THE SOFTWARE. */ +#include #include -#include +#include +#include + +#include + +typedef std::vector gid_t_vector; namespace mergerfs { namespace ugid { - struct SetResetGuard + __thread uid_t currentuid = 0; + __thread gid_t currentgid = 0; + __thread bool initialized = false; + + void + init() + { + } + + int + setgroups(const gid_t_vector &gidlist) { - SetResetGuard(const uid_t _newuid, - const gid_t _newgid) - { - pthread_getugid_np(&olduid,&oldgid); - newuid = _newuid; - newgid = _newgid; - - if(newgid != oldgid || newuid != olduid) - pthread_setugid_np(newuid,newgid); - } - - ~SetResetGuard() - { - if(newgid != oldgid || newuid != olduid) - pthread_setugid_np(newuid,newgid); - } - - uid_t olduid; - gid_t oldgid; - uid_t newuid; - gid_t newgid; - }; + return ::syscall(SYS_setgroups,gidlist.size(),&gidlist[0]); + } } } diff --git a/src/ugid_rwlock.hpp b/src/ugid_rwlock.hpp new file mode 100644 index 00000000..d4d64895 --- /dev/null +++ b/src/ugid_rwlock.hpp @@ -0,0 +1,107 @@ +/* + The MIT License (MIT) + + Copyright (c) 2014 Antonio SJ Musumeci + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include +#include +#include +#include + +namespace mergerfs +{ + namespace ugid + { + extern uid_t currentuid; + extern gid_t currentgid; + extern pthread_rwlock_t rwlock; + + static + void + ugid_set(const uid_t newuid, + const gid_t newgid) + { + pthread_rwlock_rdlock(&rwlock); + + if(newuid == currentuid && newgid == currentgid) + return; + + pthread_rwlock_unlock(&rwlock); + pthread_rwlock_wrlock(&rwlock); + + if(newuid == currentuid && newgid == currentgid) + return; + + if(currentuid != 0) + { + ::seteuid(0); + ::setegid(0); + } + + if(newgid) + { + ::setegid(newgid); + initgroups(newuid,newgid); + } + + if(newuid) + ::seteuid(newuid); + + currentuid = newuid; + currentgid = newgid; + } + + struct Set + { + Set(const uid_t newuid, + const gid_t newgid) + { + ugid_set(newuid,newgid); + } + + ~Set() + { + pthread_rwlock_unlock(&rwlock); + } + }; + + struct SetRootGuard + { + SetRootGuard() : + prevuid(currentuid), + prevgid(currentgid) + { + pthread_rwlock_unlock(&rwlock); + ugid_set(0,0); + } + + ~SetRootGuard() + { + pthread_rwlock_unlock(&rwlock); + ugid_set(prevuid,prevgid); + } + + const uid_t prevuid; + const gid_t prevgid; + }; + } +} diff --git a/src/ugid_mutex.hpp b/src/ugid_rwlock.ipp similarity index 65% rename from src/ugid_mutex.hpp rename to src/ugid_rwlock.ipp index b6b4f022..3b85776c 100644 --- a/src/ugid_mutex.hpp +++ b/src/ugid_rwlock.ipp @@ -22,47 +22,43 @@ THE SOFTWARE. */ +#include #include -#include #include #include +#include + +typedef std::vector gid_t_vector; + namespace mergerfs { namespace ugid { - struct SetResetGuard - { - SetResetGuard(const uid_t _newuid, - const gid_t _newgid) - { - pthread_mutex_lock(&lock); + uid_t currentuid; + gid_t currentgid; + pthread_rwlock_t rwlock; - olduid = ::geteuid(); - oldgid = ::getegid(); - newuid = _newuid; - newgid = _newgid; + void + init() + { + pthread_rwlockattr_t attr; - if(newgid != oldgid) - setegid(newgid); - if(newuid != olduid) - seteuid(newuid); - } + pthread_rwlockattr_init(&attr); +# if defined PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP + pthread_rwlockattr_setkind_np(&attr,PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); +# endif - ~SetResetGuard() - { - if(olduid != newuid) - seteuid(newuid); - if(oldgid != newgid) - setegid(newgid); - } + pthread_rwlock_init(&rwlock,&attr); - uid_t olduid; - gid_t oldgid; - uid_t newuid; - gid_t newgid; + currentuid = ::geteuid(); + currentgid = ::getegid(); + } - static pthread_mutex_t lock; - }; + int + setgroups(const gid_t_vector &gidlist) + { + return ::setgroups(gidlist.size(),&gidlist[0]); + } } } diff --git a/src/unlink.cpp b/src/unlink.cpp index 108dfc51..bb11cd28 100644 --- a/src/unlink.cpp +++ b/src/unlink.cpp @@ -74,10 +74,10 @@ namespace mergerfs int unlink(const char *fusepath) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::get(fc); - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const fuse_context *fc = fuse_get_context(); + const Config &config = Config::get(fc); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _unlink(config.unlink, config.srcmounts, diff --git a/src/utimens.cpp b/src/utimens.cpp index f75c5ff5..229c8b1b 100644 --- a/src/utimens.cpp +++ b/src/utimens.cpp @@ -77,10 +77,10 @@ namespace mergerfs utimens(const char *fusepath, const timespec ts[2]) { - const fuse_context *fc = fuse_get_context(); - const Config &config = Config::get(fc); - const ugid::SetResetGuard ugid(fc->uid,fc->gid); - const rwlock::ReadGuard readlock(&config.srcmountslock); + const fuse_context *fc = fuse_get_context(); + const Config &config = Config::get(fc); + const ugid::Set ugid(fc->uid,fc->gid); + const rwlock::ReadGuard readlock(&config.srcmountslock); return _utimens(config.utimens, config.srcmounts,