Browse Source

make changing credentials opportunistic + per thread setgroups cache

closes #129,#131
pull/135/head
Antonio SJ Musumeci 9 years ago
parent
commit
3163258a33
  1. 6
      Makefile
  2. 2
      src/access.cpp
  3. 2
      src/chmod.cpp
  4. 2
      src/chown.cpp
  5. 5
      src/create.cpp
  6. 2
      src/getattr.cpp
  7. 2
      src/getxattr.cpp
  8. 3
      src/init.cpp
  9. 2
      src/ioctl.cpp
  10. 5
      src/link.cpp
  11. 2
      src/listxattr.cpp
  12. 5
      src/mkdir.cpp
  13. 6
      src/mknod.cpp
  14. 2
      src/open.cpp
  15. 2
      src/readdir.cpp
  16. 2
      src/readlink.cpp
  17. 2
      src/removexattr.cpp
  18. 2
      src/rename.cpp
  19. 2
      src/rmdir.cpp
  20. 2
      src/setxattr.cpp
  21. 2
      src/statfs.cpp
  22. 2
      src/symlink.cpp
  23. 2
      src/truncate.cpp
  24. 63
      src/ugid.cpp
  25. 23
      src/ugid.hpp
  26. 69
      src/ugid_linux.hpp
  27. 36
      src/ugid_linux.ipp
  28. 107
      src/ugid_rwlock.hpp
  29. 50
      src/ugid_rwlock.ipp
  30. 2
      src/unlink.cpp
  31. 2
      src/utimens.cpp

6
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

2
src/access.cpp

@ -76,7 +76,7 @@ namespace mergerfs
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc);
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _access(config.access,

2
src/chmod.cpp

@ -76,7 +76,7 @@ namespace mergerfs
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc);
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _chmod(config.chmod,

2
src/chown.cpp

@ -80,7 +80,7 @@ namespace mergerfs
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc);
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _chown(config.chown,

5
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);
}
@ -95,7 +96,7 @@ namespace mergerfs
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc);
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _create(config.getattr,

2
src/getattr.cpp

@ -100,7 +100,7 @@ namespace mergerfs
if(fusepath == config.controlfile)
return _getattr_controlfile(*st);
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _getattr(config.getattr,

2
src/getxattr.cpp

@ -303,7 +303,7 @@ namespace mergerfs
buf,
count);
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _getxattr(config.getxattr,

3
src/init.cpp

@ -25,6 +25,7 @@
#include <fuse.h>
#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

2
src/ioctl.cpp

@ -100,7 +100,7 @@ _ioctl_dir(const string &fusepath,
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc);
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _ioctl_dir_base(config.getattr,

5
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);
}
@ -112,7 +113,7 @@ namespace mergerfs
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc);
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _link(config.getattr,

2
src/listxattr.cpp

@ -117,7 +117,7 @@ namespace mergerfs
if(fusepath == config.controlfile)
return _listxattr_controlfile(list,size);
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _listxattr(config.listxattr,

5
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);
}
@ -96,7 +97,7 @@ namespace mergerfs
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc);
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _mkdir(config.getattr,

6
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);
}
@ -99,7 +99,7 @@ namespace mergerfs
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc);
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _mknod(config.getattr,

2
src/open.cpp

@ -78,7 +78,7 @@ namespace mergerfs
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc);
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _open(config.open,

2
src/readdir.cpp

@ -98,7 +98,7 @@ namespace mergerfs
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc);
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _readdir(config.srcmounts,

2
src/readlink.cpp

@ -77,7 +77,7 @@ namespace mergerfs
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc);
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _readlink(config.readlink,

2
src/removexattr.cpp

@ -87,7 +87,7 @@ namespace mergerfs
if(fusepath == config.controlfile)
return -ENOTSUP;
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _removexattr(config.removexattr,

2
src/rename.cpp

@ -132,7 +132,7 @@ namespace mergerfs
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc);
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _rename(config.getattr,

2
src/rmdir.cpp

@ -75,7 +75,7 @@ namespace mergerfs
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc);
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readguard(&config.srcmountslock);
return _rmdir(config.rmdir,

2
src/setxattr.cpp

@ -323,7 +323,7 @@ namespace mergerfs
flags);
}
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _setxattr(config.setxattr,

2
src/statfs.cpp

@ -126,7 +126,7 @@ namespace mergerfs
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc);
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _statfs(config.srcmounts,

2
src/symlink.cpp

@ -79,7 +79,7 @@ namespace mergerfs
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc);
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _symlink(config.symlink,

2
src/truncate.cpp

@ -79,7 +79,7 @@ namespace mergerfs
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc);
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _truncate(config.truncate,

63
src/ugid.cpp

@ -22,10 +22,65 @@
THE SOFTWARE.
*/
#include "ugid.hpp"
#include <stdlib.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
#if defined __linux__
#elif defined __APPLE__
#include <vector>
#include <map>
typedef std::vector<gid_t> gid_t_vector;
typedef std::map<uid_t,gid_t_vector> 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);
}
}
}

23
src/ugid.hpp

@ -25,12 +25,27 @@
#ifndef __UGID_HPP__
#define __UGID_HPP__
#if defined __linux__
#include <sys/types.h>
#include <unistd.h>
#include <vector>
typedef std::vector<gid_t> 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__ */

69
src/ugid_linux.hpp

@ -27,38 +27,71 @@
#include <unistd.h>
#include <sys/syscall.h>
#include <grp.h>
#include <pwd.h>
#include <map>
#include <vector>
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(!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 != oldgid)
if(newgid)
{
::syscall(SYS_setregid,-1,newgid);
if(newuid != olduid)
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;
};
}
}

36
src/ugid_osx.hpp → src/ugid_linux.ipp

@ -22,36 +22,32 @@
THE SOFTWARE.
*/
#include <stdlib.h>
#include <sys/types.h>
#include <sys/unistd.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <vector>
typedef std::vector<gid_t> gid_t_vector;
namespace mergerfs
{
namespace ugid
{
struct SetResetGuard
{
SetResetGuard(const uid_t _newuid,
const gid_t _newgid)
{
pthread_getugid_np(&olduid,&oldgid);
newuid = _newuid;
newgid = _newgid;
__thread uid_t currentuid = 0;
__thread gid_t currentgid = 0;
__thread bool initialized = false;
if(newgid != oldgid || newuid != olduid)
pthread_setugid_np(newuid,newgid);
void
init()
{
}
~SetResetGuard()
int
setgroups(const gid_t_vector &gidlist)
{
if(newgid != oldgid || newuid != olduid)
pthread_setugid_np(newuid,newgid);
return ::syscall(SYS_setgroups,gidlist.size(),&gidlist[0]);
}
uid_t olduid;
gid_t oldgid;
uid_t newuid;
gid_t newgid;
};
}
}

107
src/ugid_rwlock.hpp

@ -0,0 +1,107 @@
/*
The MIT License (MIT)
Copyright (c) 2014 Antonio SJ Musumeci <trapexit@spawn.link>
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 <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
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;
};
}
}

50
src/ugid_mutex.hpp → src/ugid_rwlock.ipp

@ -22,47 +22,43 @@
THE SOFTWARE.
*/
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
#include <vector>
typedef std::vector<gid_t> gid_t_vector;
namespace mergerfs
{
namespace ugid
{
struct SetResetGuard
{
SetResetGuard(const uid_t _newuid,
const gid_t _newgid)
uid_t currentuid;
gid_t currentgid;
pthread_rwlock_t rwlock;
void
init()
{
pthread_mutex_lock(&lock);
pthread_rwlockattr_t attr;
olduid = ::geteuid();
oldgid = ::getegid();
newuid = _newuid;
newgid = _newgid;
pthread_rwlockattr_init(&attr);
# if defined PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
pthread_rwlockattr_setkind_np(&attr,PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
# endif
if(newgid != oldgid)
setegid(newgid);
if(newuid != olduid)
seteuid(newuid);
pthread_rwlock_init(&rwlock,&attr);
currentuid = ::geteuid();
currentgid = ::getegid();
}
~SetResetGuard()
int
setgroups(const gid_t_vector &gidlist)
{
if(olduid != newuid)
seteuid(newuid);
if(oldgid != newgid)
setegid(newgid);
return ::setgroups(gidlist.size(),&gidlist[0]);
}
uid_t olduid;
gid_t oldgid;
uid_t newuid;
gid_t newgid;
static pthread_mutex_t lock;
};
}
}

2
src/unlink.cpp

@ -76,7 +76,7 @@ namespace mergerfs
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc);
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _unlink(config.unlink,

2
src/utimens.cpp

@ -79,7 +79,7 @@ namespace mergerfs
{
const fuse_context *fc = fuse_get_context();
const Config &config = Config::get(fc);
const ugid::SetResetGuard ugid(fc->uid,fc->gid);
const ugid::Set ugid(fc->uid,fc->gid);
const rwlock::ReadGuard readlock(&config.srcmountslock);
return _utimens(config.utimens,

Loading…
Cancel
Save