Browse Source

Rework credential handling to support chroot & idmap

Run in an elevated credential mode (caps for Linux and root for
FreeBSD) and let the kernel manage entitlements. Will result in
slightly different behavior but should not be noticed by most.
Antonio SJ Musumeci 2 months ago
parent
commit
071cc93584
  1. 1
      Makefile
  2. 19
      libfuse/lib/fuse_lowlevel.cpp
  3. 102
      src/caps.cpp
  4. 6
      src/caps.hpp
  5. 4
      src/fs_attr_linux.icpp
  6. 75
      src/fs_clonepath.cpp
  7. 5
      src/fs_clonepath.hpp
  8. 2
      src/fs_is_rofs.hpp
  9. 50
      src/fs_mkdir_as.hpp
  10. 35
      src/fs_mkdir_as_root.hpp
  11. 48
      src/fs_mkdirat.hpp
  12. 50
      src/fs_mknod_as.hpp
  13. 2
      src/fs_movefile_and_open.cpp
  14. 50
      src/fs_open_as.hpp
  15. 48
      src/fs_symlink_as.hpp
  16. 3
      src/fuse_access.cpp
  17. 1
      src/fuse_chmod.cpp
  18. 3
      src/fuse_chown.cpp
  19. 33
      src/fuse_create.cpp
  20. 2
      src/fuse_getattr.cpp
  21. 2
      src/fuse_getxattr.cpp
  22. 4
      src/fuse_init.cpp
  23. 6
      src/fuse_ioctl.cpp
  24. 9
      src/fuse_link.cpp
  25. 2
      src/fuse_listxattr.cpp
  26. 39
      src/fuse_mkdir.cpp
  27. 39
      src/fuse_mknod.cpp
  28. 2
      src/fuse_open.cpp
  29. 4
      src/fuse_passthrough.hpp
  30. 2
      src/fuse_readdir_cor.cpp
  31. 10
      src/fuse_readdir_cosr.cpp
  32. 7
      src/fuse_readdir_cosr_getdents.icpp
  33. 7
      src/fuse_readdir_cosr_readdir.icpp
  34. 3
      src/fuse_readdir_seq.cpp
  35. 3
      src/fuse_readlink.cpp
  36. 2
      src/fuse_removexattr.cpp
  37. 12
      src/fuse_rename.cpp
  38. 1
      src/fuse_rmdir.cpp
  39. 2
      src/fuse_setxattr.cpp
  40. 1
      src/fuse_statfs.cpp
  41. 4
      src/fuse_statx_supported.icpp
  42. 64
      src/fuse_symlink.cpp
  43. 3
      src/fuse_truncate.cpp
  44. 3
      src/fuse_unlink.cpp
  45. 3
      src/fuse_utimens.cpp
  46. 2
      src/mergerfs.cpp
  47. 2
      src/policy_ff.cpp
  48. 33
      src/ugid.cpp
  49. 113
      src/ugid.hpp
  50. 128
      src/ugid_linux.hpp
  51. 34
      src/ugid_linux.icpp
  52. 106
      src/ugid_rwlock.hpp
  53. 45
      src/ugid_rwlock.icpp

1
Makefile

@ -65,7 +65,6 @@ OPT_FLAGS := -O0 \
$(SANITIZE) \
-fstack-protector-strong \
-Wextra \
-Werror \
-Wno-unused-parameter \
-DDEBUG
endif

19
libfuse/lib/fuse_lowlevel.cpp

@ -1737,14 +1737,14 @@ fuse_send_enomem(struct fuse_ll *f_,
fuse_send_errno(f_,ch_,ENOMEM,unique_id_);
}
static
void
fuse_send_einval(struct fuse_ll *f_,
struct fuse_chan *ch_,
const uint64_t unique_id_)
{
fuse_send_errno(f_,ch_,EINVAL,unique_id_);
}
// static
// void
// fuse_send_einval(struct fuse_ll *f_,
// struct fuse_chan *ch_,
// const uint64_t unique_id_)
// {
// fuse_send_errno(f_,ch_,EINVAL,unique_id_);
// }
static
int
@ -1777,9 +1777,6 @@ fuse_ll_buf_process_read(struct fuse_session *se_,
in = (struct fuse_in_header*)msgbuf_->mem;
if((in->uid == FUSE_INVALID_UIDGID) || (in->gid == FUSE_INVALID_UIDGID))
return fuse_send_einval(se_->f,se_->ch,in->unique);
req = fuse_ll_alloc_req(se_->f);
if(req == NULL)
return fuse_send_enomem(se_->f,se_->ch,in->unique);

102
src/caps.cpp

@ -0,0 +1,102 @@
#include "caps.hpp"
#if defined __linux__
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/prctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <grp.h>
#include <linux/capability.h>
#include <linux/securebits.h>
static
int
capset(cap_user_header_t header_,
const cap_user_data_t data_)
{
return ::syscall(SYS_capset,header_,data_);
}
static
int
capget(cap_user_header_t header_,
cap_user_data_t data_)
{
return ::syscall(SYS_capget,header_,data_);
}
static
int
capset(int cap_bit_)
{
int rv;
struct __user_cap_header_struct header;
struct __user_cap_data_struct data[2];
header.version = _LINUX_CAPABILITY_VERSION_3;
header.pid = 0;
rv = capget(&header,data);
if(rv < 0)
return rv;
int word = cap_bit_ / 32;
int bit = cap_bit_ % 32;
data[word].permitted |= (1 << bit);
data[word].effective |= (1 << bit);
data[word].inheritable |= (1 << bit);
rv = capset(&header,data);
if(rv < 0)
return rv;
return 0;
}
int
caps::setup()
{
int rv;
rv = capset(CAP_DAC_OVERRIDE);
if(rv < 0)
return rv;
rv = capset(CAP_DAC_READ_SEARCH);
if(rv < 0)
return rv;
rv = capset(CAP_FOWNER);
if(rv < 0)
return rv;
rv = capset(CAP_CHOWN);
if(rv < 0)
return rv;
rv = capset(CAP_SETUID);
if(rv < 0)
return rv;
rv = capset(CAP_SETGID);
if(rv < 0)
return rv;
rv = prctl(PR_SET_SECUREBITS,
SECBIT_KEEP_CAPS | SECBIT_NO_SETUID_FIXUP);
if(rv < 0)
return -errno;
return 0;
}
#else
int
caps::setup()
{
return -ENOTSUP;
}
#endif

6
src/caps.hpp

@ -0,0 +1,6 @@
#pragma once
namespace caps
{
int setup();
}

4
src/fs_attr_linux.icpp

@ -31,7 +31,7 @@ using std::string;
static
int
_get_fs_ioc_flags(const int fd,
int &flags)
int &flags)
{
int rv;
@ -45,7 +45,7 @@ _get_fs_ioc_flags(const int fd,
static
int
_get_fs_ioc_flags(const string &file,
int &flags)
int &flags)
{
int fd;
int rv;

75
src/fs_clonepath.cpp

@ -27,6 +27,16 @@
#include "fs_xattr.hpp"
#include "ugid.hpp"
#include "fs_close.hpp"
#include "fs_fstat.hpp"
#include "fs_mkdirat.hpp"
#include "fs_openat.hpp"
#include "fs_fchown.hpp"
#include "fs_fchmod.hpp"
#include "fs_futimens.hpp"
#include "scope_guard.hpp"
static
bool
@ -107,21 +117,62 @@ fs::clonepath(const fs::path &srcpath_,
return 0;
}
// WORK IN PROGRESS
static
int
fs::clonepath_as_root(const fs::path &srcpath_,
const fs::path &dstpath_,
const fs::path &relpath_,
const bool return_metadata_errors_)
_clonepath2(const int srcfd_,
const int dstfd_,
const fs::path &dirname_,
const bool return_metadata_errors_)
{
if(relpath_.empty())
return 0;
if(srcpath_ == dstpath_)
int rv;
int srcdirfd;
int dstdirfd;
struct stat st;
if(dirname_.empty())
return 0;
const ugid::SetRootGuard ugid_guard;
rv = fs::mkdirat(dstfd_,dirname_,0);
if(rv < 0)
return ((rv == -EEXIST) ? 0 : rv);
srcdirfd = fs::openat(srcfd_,dirname_,O_DIRECTORY);
if(srcdirfd < 0)
return srcdirfd;
DEFER { fs::close(srcdirfd); };
dstdirfd = fs::openat(dstfd_,dirname_,O_DIRECTORY);
if(dstdirfd < 0)
return dstdirfd;
DEFER { fs::close(dstdirfd); };
rv = fs::attr::copy(srcdirfd,dstdirfd,FS_ATTR_CLEAR_IMMUTABLE);
if(return_metadata_errors_ && (rv < 0) && !::_ignorable_error(-rv))
return rv;
rv = fs::xattr::copy(srcdirfd,dstdirfd);
if(return_metadata_errors_ && (rv < 0) && !::_ignorable_error(-rv))
return rv;
rv = fs::fstat(srcdirfd,&st);
if(rv < 0)
return rv;
if(!S_ISDIR(st.st_mode))
return -ENOTDIR;
rv = fs::fchown_check_on_error(dstdirfd,st);
if(rv < 0)
return rv;
rv = fs::fchmod_check_on_error(dstdirfd,st);
if(rv < 0)
return rv;
return fs::clonepath(srcpath_,
dstpath_,
relpath_,
return_metadata_errors_);
rv = fs::futimens(dstdirfd,st);
if(rv < 0)
return rv;
return 0;
}

5
src/fs_clonepath.hpp

@ -25,9 +25,4 @@ namespace fs
const fs::path &dstpath,
const fs::path &relpath,
const bool return_metadata_errors = false);
int clonepath_as_root(const fs::path &srcpath,
const fs::path &dstpath,
const fs::path &relpath,
const bool return_metadata_errors = false);
}

2
src/fs_is_rofs.hpp

@ -49,8 +49,6 @@ namespace fs
bool
is_rofs(const fs::path &path_)
{
ugid::SetRootGuard const ugid;
int fd;
std::string tmp_filepath;

50
src/fs_mkdir_as.hpp

@ -0,0 +1,50 @@
#pragma once
#include "fs_mkdir.hpp"
#if defined __linux__
#include "ugid.hpp"
namespace fs
{
template<typename T>
static
inline
int
mkdir_as(const ugid_t ugid_,
const T &path_,
const mode_t mode_)
{
const ugid::Set _(ugid_);
return fs::mkdir(path_,mode_);
}
}
#elif defined __FreeBSD__
#include "fs_lchown.hpp"
namespace fs
{
template<typename T>
static
inline
int
mkdir_as(const ugid_t ugid_,
const T &path_,`
const mode_t mode_)
{
int rv;
rv = fs::mkdir(path_,mode_);
if(rv < 0)
return rv;
fs::lchown(path_,ugid_.uid,ugid_.gid);
return 0;
}
}
#else
#error "Not Supported"
#endif

35
src/fs_mkdir_as_root.hpp

@ -1,35 +0,0 @@
/*
ISC License
Copyright (c) 2021, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "fs_mkdir.hpp"
#include "ugid.hpp"
namespace fs
{
template<typename T>
static
inline
int
mkdir_as_root(const T &path_,
const mode_t mode_)
{
const ugid::SetRootGuard guard;
return fs::mkdir(path_,mode_);
}
}

48
src/fs_mkdirat.hpp

@ -0,0 +1,48 @@
#pragma once
#include "to_neg_errno.hpp"
#include "fs_path.hpp"
#include <fcntl.h>
#include <sys/stat.h>
namespace fs
{
static
inline
int
mkdirat(const int dirfd_,
const char *pathname_,
const mode_t mode_)
{
int rv;
rv = ::mkdirat(dirfd_,pathname_,mode_);
return ::to_neg_errno(rv);
}
static
inline
int
mkdirat(const int dirfd_,
const std::string &pathname_,
const mode_t mode_)
{
return fs::mkdirat(dirfd_,
pathname_.c_str(),
mode_);
}
static
inline
int
mkdirat(const int dirfd_,
const fs::path &pathname_,
const mode_t mode_)
{
return fs::mkdirat(dirfd_,
pathname_.c_str(),
mode_);
}
}

50
src/fs_mknod_as.hpp

@ -0,0 +1,50 @@
#pragma once
#include "fs_mknod.hpp"
#if defined __linux__
#include "ugid.hpp"
namespace fs
{
template<typename T>
static
inline
int
mknod_as(const ugid_t ugid_,
const T &path_,
const mode_t mode_,
const dev_t dev_)
{
const ugid::Set _(ugid_);
return fs::mknod(path_,mode_,dev_);
}
}
#elif defined __FreeBSD__
#include "fs_lchown.hpp"
namespace fs
{
template<typename T>
static
inline
int
mknod_as(const ugid_t ugid_,
const T &path_,
const mode_t mode_,
const dev_t dev_)
{
int rv;
rv = fs::mknod(path_,mode_,dev_);
fs::lchown(path_,ugid_.uid,ugid_.gid);
return rv;
}
}
#else
#error "Not Supported!"
#endif

2
src/fs_movefile_and_open.cpp

@ -137,8 +137,6 @@ fs::movefile_and_open_as_root(const Policy::Create &policy_,
const fs::path &fusepath_,
const int origfd_)
{
const ugid::Set ugid(0,0);
return fs::movefile_and_open(policy_,
branches_,
branchpath_,

50
src/fs_open_as.hpp

@ -0,0 +1,50 @@
#pragma once
#include "fs_open.hpp"
#if defined __linux__
#include "ugid.hpp"
namespace fs
{
static
inline
int
open_as(const ugid_t ugid_,
const fs::path &path_,
const int flags_,
const mode_t mode_)
{
const ugid::Set _(ugid_);
return fs::open(path_,flags_,mode_);
}
}
#elif defined __FreeBSD__
#include "fs_lchown.hpp"
namespace fs
{
static
inline
int
open_as(const ugid_t ugid_,
const fs::path &path_,
const int flags_,
const mode_t mode_)
{
int rv;
rv = fs::open(path_,flags_,mode_);
if(rv < 0)
return rv;
fs::fchown(rv,ugid_.uid,ugid_.gid);
return rv;
}
}
#else
#error "Not Supported!"
#endif

48
src/fs_symlink_as.hpp

@ -0,0 +1,48 @@
#pragma once
#include "fs_symlink.hpp"
#if defined __linux__
#include "ugid.hpp"
namespace fs
{
template<typename T>
static
inline
int
symlink_as(const ugid_t ugid_,
const char *target_,
const T &linkpath_)
{
const ugid::Set _(ugid_);
return fs::symlink(target_,linkpath_);
}
}
#elif defined __FreeBSD__
#include "fs_lchown.hpp"
template<typename T>
static
inline
int
symlink_as(const ugid_t ugid_,
const char *target_,
const T &linkpath_)
{
int rv;
rv = fs::symlink(target_,linkpath_);
if(rv < 0)
return rv;
fs::lchown(linkpath_,ugid_.uid,ugid_.gid);
return 0;
}
}
#else
#error "Not Supported!"
#endif

3
src/fuse_access.cpp

@ -54,8 +54,7 @@ FUSE::access(const fuse_req_ctx_t *ctx_,
const char *fusepath_,
int mask_)
{
const fs::path fusepath{fusepath_};
const ugid::Set ugid(ctx_->uid,ctx_->gid);
const fs::path fusepath{fusepath_};
return ::_access(cfg.func.access.policy,
cfg.branches,

1
src/fuse_chmod.cpp

@ -108,7 +108,6 @@ FUSE::chmod(const fuse_req_ctx_t *ctx_,
mode_t mode_)
{
const fs::path fusepath{fusepath_};
const ugid::Set ugid(ctx_->uid,ctx_->gid);
return ::_chmod(fusepath,mode_);
}

3
src/fuse_chown.cpp

@ -99,8 +99,7 @@ FUSE::chown(const fuse_req_ctx_t *ctx_,
uid_t uid_,
gid_t gid_)
{
const fs::path fusepath{fusepath_};
const ugid::Set ugid(ctx_->uid,ctx_->gid);
const fs::path fusepath{fusepath_};
return ::_chown(cfg.func.chown.policy,
cfg.func.getattr.policy,

33
src/fuse_create.cpp

@ -19,11 +19,15 @@
#include "state.hpp"
#include "config.hpp"
#include "fs_readlink.hpp"
#include "errno.hpp"
#include "fileinfo.hpp"
#include "fs_acl.hpp"
#include "fs_close.hpp"
#include "fs_clonepath.hpp"
#include "fs_open.hpp"
#include "fs_open_as.hpp"
#include "fs_openat.hpp"
#include "fs_path.hpp"
#include "fuse_passthrough.hpp"
#include "procfs.hpp"
@ -132,7 +136,8 @@ _config_to_ffi_flags(Config &cfg_,
static
int
_create_core(const fs::path &fullpath_,
_create_core(const ugid_t ugid_,
const fs::path &fullpath_,
mode_t mode_,
const mode_t umask_,
const int flags_)
@ -140,12 +145,13 @@ _create_core(const fs::path &fullpath_,
if(!fs::acl::dir_has_defaults(fullpath_))
mode_ &= ~umask_;
return fs::open(fullpath_,flags_,mode_);
return fs::open_as(ugid_,fullpath_,flags_,mode_);
}
static
int
_create_core(const Branch *branch_,
_create_core(const ugid_t ugid_,
const Branch *branch_,
const fs::path &fusepath_,
fuse_file_info_t *ffi_,
const mode_t mode_,
@ -157,7 +163,7 @@ _create_core(const Branch *branch_,
fullpath = branch_->path / fusepath_;
rv = ::_create_core(fullpath,mode_,umask_,ffi_->flags);
rv = ::_create_core(ugid_,fullpath,mode_,umask_,ffi_->flags);
if(rv < 0)
return rv;
@ -170,7 +176,8 @@ _create_core(const Branch *branch_,
static
int
_create(const Policy::Search &searchFunc_,
_create(const ugid_t ugid_,
const Policy::Search &searchFunc_,
const Policy::Create &createFunc_,
const Branches &branches_,
const fs::path &fusepath_,
@ -194,13 +201,14 @@ _create(const Policy::Search &searchFunc_,
if(rv < 0)
return rv;
rv = fs::clonepath_as_root(existingpaths[0]->path,
createpaths[0]->path,
fusedirpath);
rv = fs::clonepath(existingpaths[0]->path,
createpaths[0]->path,
fusedirpath);
if(rv < 0)
return rv;
return ::_create_core(createpaths[0],
return ::_create_core(ugid_,
createpaths[0],
fusepath_,
ffi_,
mode_,
@ -225,7 +233,6 @@ _create_for_insert_lambda(const fuse_req_ctx_t *ctx_,
{
int rv;
FileInfo *fi;
const ugid::Set ugid(ctx_->uid,ctx_->gid);
::_config_to_ffi_flags(cfg,ctx_->pid,ffi_);
if(cfg.cache_writeback)
@ -233,7 +240,8 @@ _create_for_insert_lambda(const fuse_req_ctx_t *ctx_,
ffi_->noflush = !::_calculate_flush(cfg.flushonclose,
ffi_->flags);
rv = ::_create(cfg.func.getattr.policy,
rv = ::_create(ctx_,
cfg.func.getattr.policy,
cfg.func.create.policy,
cfg.branches,
fusepath_,
@ -243,7 +251,8 @@ _create_for_insert_lambda(const fuse_req_ctx_t *ctx_,
if(rv == -EROFS)
{
cfg.branches.find_and_set_mode_ro();
rv = ::_create(cfg.func.getattr.policy,
rv = ::_create(ctx_,
cfg.func.getattr.policy,
cfg.func.create.policy,
cfg.branches,
fusepath_,

2
src/fuse_getattr.cpp

@ -213,8 +213,6 @@ FUSE::getattr(const fuse_req_ctx_t *ctx_,
struct stat *st_,
fuse_timeouts_t *timeout_)
{
const ugid::Set ugid(ctx_);
return FUSE::getattr(fusepath_,st_,timeout_);
}

2
src/fuse_getxattr.cpp

@ -193,8 +193,6 @@ FUSE::getxattr(const fuse_req_ctx_t *ctx_,
if(cfg.xattr.to_int())
return -cfg.xattr.to_int();
const ugid::Set ugid(ctx_->uid,ctx_->gid);
return ::_getxattr(cfg.func.getxattr.policy,
cfg.branches,
fusepath,

4
src/fuse_init.cpp

@ -16,6 +16,8 @@
#include "fuse_init.hpp"
#include "caps.hpp"
#include "config.hpp"
#include "fs_readahead.hpp"
#include "procfs.hpp"
@ -187,7 +189,7 @@ void *
FUSE::init(fuse_conn_info *conn_)
{
procfs::init();
ugid::init();
caps::setup();
cfg.readdir.initialize();
::_want_if_capable(conn_,FUSE_CAP_ASYNC_DIO);

6
src/fuse_ioctl.cpp

@ -113,8 +113,7 @@ _ioctl_file(const fuse_req_ctx_t *ctx_,
void *data_,
uint32_t *out_bufsz_)
{
FileInfo *fi = FileInfo::from_fh(ffi_->fh);
const ugid::Set ugid(ctx_);
FileInfo *fi = FileInfo::from_fh(ffi_->fh);
return ::_ioctl(fi->fd,cmd_,data_,out_bufsz_);
}
@ -162,8 +161,7 @@ _ioctl_dir(const fuse_req_ctx_t *ctx_,
void *data_,
uint32_t *out_bufsz_)
{
DirInfo *di = DirInfo::from_fh(ffi_->fh);
const ugid::Set ugid(ctx_);
DirInfo *di = DirInfo::from_fh(ffi_->fh);
return ::_ioctl_dir_base(cfg.func.open.policy,
cfg.branches,

9
src/fuse_link.cpp

@ -55,7 +55,9 @@ _link_create_path_loop(const std::vector<Branch*> &oldbranches_,
rv = fs::link(oldfullpath,newfullpath);
if(rv == -ENOENT)
{
rv = fs::clonepath_as_root(newbranch_->path,oldbranch->path,newfusedirpath_);
rv = fs::clonepath(newbranch_->path,
oldbranch->path,
newfusedirpath_);
if(rv == 0)
rv = fs::link(oldfullpath,newfullpath);
}
@ -328,9 +330,8 @@ FUSE::link(const fuse_req_ctx_t *ctx_,
fuse_timeouts_t *timeouts_)
{
int rv;
const fs::path oldpath{oldpath_};
const fs::path newpath{newpath_};
const ugid::Set ugid(ctx_);
const fs::path oldpath{oldpath_};
const fs::path newpath{newpath_};
rv = ::_link(ctx_,oldpath,newpath,st_,timeouts_);
if(rv == -EXDEV)

2
src/fuse_listxattr.cpp

@ -143,8 +143,6 @@ FUSE::listxattr(const fuse_req_ctx_t *ctx_,
return -ENOSYS;
}
const ugid::Set ugid(ctx_);
return ::_listxattr(cfg.func.listxattr.policy,
cfg.branches,
fusepath,

39
src/fuse_mkdir.cpp

@ -21,7 +21,7 @@
#include "error.hpp"
#include "fs_acl.hpp"
#include "fs_clonepath.hpp"
#include "fs_mkdir.hpp"
#include "fs_mkdir_as.hpp"
#include "fs_path.hpp"
#include "policy.hpp"
#include "ugid.hpp"
@ -33,19 +33,21 @@
static
int
_mkdir_core(const fs::path &fullpath_,
_mkdir_core(const ugid_t ugid_,
const fs::path &fullpath_,
mode_t mode_,
const mode_t umask_)
{
if(!fs::acl::dir_has_defaults(fullpath_))
mode_ &= ~umask_;
return fs::mkdir(fullpath_,mode_);
return fs::mkdir_as(ugid_,fullpath_,mode_);
}
static
int
_mkdir_loop_core(const fs::path &createpath_,
_mkdir_loop_core(const ugid_t ugid_,
const fs::path &createpath_,
const fs::path &fusepath_,
const mode_t mode_,
const mode_t umask_)
@ -55,14 +57,15 @@ _mkdir_loop_core(const fs::path &createpath_,
fullpath = createpath_ / fusepath_;
rv = ::_mkdir_core(fullpath,mode_,umask_);
rv = ::_mkdir_core(ugid_,fullpath,mode_,umask_);
return rv;
}
static
int
_mkdir_loop(const Branch *existingbranch_,
_mkdir_loop(const ugid_t ugid_,
const Branch *existingbranch_,
const std::vector<Branch*> &createbranches_,
const fs::path &fusepath_,
const fs::path &fusedirpath_,
@ -74,16 +77,17 @@ _mkdir_loop(const Branch *existingbranch_,
for(const auto &createbranch : createbranches_)
{
rv = fs::clonepath_as_root(existingbranch_->path,
createbranch->path,
fusedirpath_);
rv = fs::clonepath(existingbranch_->path,
createbranch->path,
fusedirpath_);
if(rv < 0)
{
err = rv;
continue;
}
err = ::_mkdir_loop_core(createbranch->path,
err = ::_mkdir_loop_core(ugid_,
createbranch->path,
fusepath_,
mode_,
umask_);
@ -94,7 +98,8 @@ _mkdir_loop(const Branch *existingbranch_,
static
int
_mkdir(const Policy::Search &getattrPolicy_,
_mkdir(const ugid_t ugid_,
const Policy::Search &getattrPolicy_,
const Policy::Create &mkdirPolicy_,
const Branches &branches_,
const fs::path &fusepath_,
@ -116,7 +121,8 @@ _mkdir(const Policy::Search &getattrPolicy_,
if(rv < 0)
return rv;
return ::_mkdir_loop(existingbranches[0],
return ::_mkdir_loop(ugid_,
existingbranches[0],
createbranches,
fusepath_,
fusedirpath,
@ -130,10 +136,10 @@ FUSE::mkdir(const fuse_req_ctx_t *ctx_,
mode_t mode_)
{
int rv;
const fs::path fusepath{fusepath_};
const ugid::Set ugid(ctx_);
const fs::path fusepath{fusepath_};
rv = ::_mkdir(cfg.func.getattr.policy,
rv = ::_mkdir(ctx_,
cfg.func.getattr.policy,
cfg.func.mkdir.policy,
cfg.branches,
fusepath,
@ -142,7 +148,8 @@ FUSE::mkdir(const fuse_req_ctx_t *ctx_,
if(rv == -EROFS)
{
cfg.branches.find_and_set_mode_ro();
rv = ::_mkdir(cfg.func.getattr.policy,
rv = ::_mkdir(ctx_,
cfg.func.getattr.policy,
cfg.func.mkdir.policy,
cfg.branches,
fusepath,

39
src/fuse_mknod.cpp

@ -20,7 +20,7 @@
#include "errno.hpp"
#include "error.hpp"
#include "fs_acl.hpp"
#include "fs_mknod.hpp"
#include "fs_mknod_as.hpp"
#include "fs_clonepath.hpp"
#include "fs_path.hpp"
#include "ugid.hpp"
@ -34,7 +34,8 @@
static
inline
int
_mknod_core(const fs::path &fullpath_,
_mknod_core(const ugid_t ugid_,
const fs::path &fullpath_,
mode_t mode_,
const mode_t umask_,
const dev_t dev_)
@ -42,12 +43,13 @@ _mknod_core(const fs::path &fullpath_,
if(!fs::acl::dir_has_defaults(fullpath_))
mode_ &= ~umask_;
return fs::mknod(fullpath_,mode_,dev_);
return fs::mknod_as(ugid_,fullpath_,mode_,dev_);
}
static
int
_mknod_loop_core(const fs::path &createbranch_,
_mknod_loop_core(const ugid_t ugid_,
const fs::path &createbranch_,
const fs::path &fusepath_,
const mode_t mode_,
const mode_t umask_,
@ -58,14 +60,15 @@ _mknod_loop_core(const fs::path &createbranch_,
fullpath = createbranch_ / fusepath_;
rv = ::_mknod_core(fullpath,mode_,umask_,dev_);
rv = ::_mknod_core(ugid_,fullpath,mode_,umask_,dev_);
return rv;
}
static
int
_mknod_loop(const fs::path &existingbranch_,
_mknod_loop(const ugid_t ugid_,
const fs::path &existingbranch_,
const std::vector<Branch*> &createbranches_,
const fs::path &fusepath_,
const fs::path &fusedirpath_,
@ -78,16 +81,17 @@ _mknod_loop(const fs::path &existingbranch_,
for(const auto &createbranch : createbranches_)
{
rv = fs::clonepath_as_root(existingbranch_,
createbranch->path,
fusedirpath_);
rv = fs::clonepath(existingbranch_,
createbranch->path,
fusedirpath_);
if(rv < 0)
{
err = rv;
continue;
}
err = ::_mknod_loop_core(createbranch->path,
err = ::_mknod_loop_core(ugid_,
createbranch->path,
fusepath_,
mode_,
umask_,
@ -99,7 +103,8 @@ _mknod_loop(const fs::path &existingbranch_,
static
int
_mknod(const Policy::Search &searchFunc_,
_mknod(const ugid_t ugid_,
const Policy::Search &searchFunc_,
const Policy::Create &createFunc_,
const Branches &branches_,
const fs::path &fusepath_,
@ -122,7 +127,8 @@ _mknod(const Policy::Search &searchFunc_,
if(rv < 0)
return rv;
return ::_mknod_loop(existingbranches[0]->path,
return ::_mknod_loop(ugid_,
existingbranches[0]->path,
createbranches,
fusepath_,
fusedirpath,
@ -138,10 +144,10 @@ FUSE::mknod(const fuse_req_ctx_t *ctx_,
dev_t rdev_)
{
int rv;
const fs::path fusepath{fusepath_};
const ugid::Set ugid(ctx_);
const fs::path fusepath{fusepath_};
rv = ::_mknod(cfg.func.getattr.policy,
rv = ::_mknod(ctx_,
cfg.func.getattr.policy,
cfg.func.mknod.policy,
cfg.branches,
fusepath,
@ -151,7 +157,8 @@ FUSE::mknod(const fuse_req_ctx_t *ctx_,
if(rv == -EROFS)
{
cfg.branches.find_and_set_mode_ro();
rv = ::_mknod(cfg.func.getattr.policy,
rv = ::_mknod(ctx_,
cfg.func.getattr.policy,
cfg.func.mknod.policy,
cfg.branches,
fusepath,

2
src/fuse_open.cpp

@ -281,7 +281,6 @@ _open_for_insert_lambda(const fuse_req_ctx_t *ctx_,
{
int rv;
FileInfo *fi;
const ugid::Set ugid(ctx_);
::_config_to_ffi_flags(cfg,ctx_->pid,ffi_);
@ -337,7 +336,6 @@ _open_for_update_lambda(const fuse_req_ctx_t *ctx_,
State::OpenFile *of_)
{
int rv;
const ugid::Set ugid(ctx_);
::_config_to_ffi_flags(cfg,ctx_->pid,ffi_);

4
src/fuse_passthrough.hpp

@ -14,8 +14,6 @@ namespace FUSE
int
passthrough_open(const int fd_)
{
const ugid::SetRootGuard _;
return fuse_passthrough_open(fd_);
}
@ -24,8 +22,6 @@ namespace FUSE
int
passthrough_close(const int backing_id_)
{
const ugid::SetRootGuard _;
return fuse_passthrough_close(backing_id_);
}
}

2
src/fuse_readdir_cor.cpp

@ -64,8 +64,6 @@ _concurrent_readdir(ThreadPool &tp_,
auto func =
[&,dirents_,uid_,gid_]()
{
const ugid::Set ugid(uid_,gid_);
return ::_readdir(branch.path,
rel_dirpath_,
names,

10
src/fuse_readdir_cosr.cpp

@ -45,16 +45,14 @@ int
_readdir(ThreadPool &tp_,
const Branches::Ptr &branches_,
const fs::path &rel_dirpath_,
fuse_dirents_t *dirents_,
uid_t const uid_,
gid_t const gid_)
fuse_dirents_t *dirents_)
{
int rv;
std::vector<std::future<DirRV>> futures;
fuse_dirents_reset(dirents_);
futures = ::_opendir(tp_,branches_,rel_dirpath_,uid_,gid_);
futures = ::_opendir(tp_,branches_,rel_dirpath_);
rv = ::_readdir(futures,rel_dirpath_,dirents_);
return rv;
@ -70,7 +68,5 @@ FUSE::ReadDirCOSR::operator()(const fuse_req_ctx_t *ctx_,
return ::_readdir(_tp,
cfg.branches,
di->fusepath,
dirents_,
ctx_->uid,
ctx_->gid);
dirents_);
}

7
src/fuse_readdir_cosr_getdents.icpp

@ -28,9 +28,7 @@ inline
std::vector<std::future<DirRV>>
_opendir(ThreadPool &tp_,
const Branches::Ptr &branches_,
const fs::path &rel_dirpath_,
uid_t const uid_,
gid_t const gid_)
const fs::path &rel_dirpath_)
{
std::vector<std::future<DirRV>> futures;
@ -39,11 +37,10 @@ _opendir(ThreadPool &tp_,
for(const auto &branch : *branches_)
{
auto func =
[&branch,&rel_dirpath_,uid_,gid_]()
[&branch,&rel_dirpath_]()
{
int fd;
fs::path abs_dirpath;
const ugid::Set ugid(uid_,gid_);
abs_dirpath = branch.path / rel_dirpath_;

7
src/fuse_readdir_cosr_readdir.icpp

@ -37,9 +37,7 @@ inline
std::vector<std::future<DirRV>>
_opendir(ThreadPool &tp_,
const Branches::Ptr &branches_,
const fs::path &rel_dirpath_,
uid_t const uid_,
gid_t const gid_)
const fs::path &rel_dirpath_)
{
std::vector<std::future<DirRV>> futures;
@ -48,11 +46,10 @@ _opendir(ThreadPool &tp_,
for(const auto &branch : *branches_)
{
auto func =
[&branch,&rel_dirpath_,uid_,gid_]()
[&branch,&rel_dirpath_]()
{
DIR *dir;
fs::path abs_dirpath;
const ugid::Set ugid(uid_,gid_);
abs_dirpath = branch.path / rel_dirpath_;

3
src/fuse_readdir_seq.cpp

@ -33,8 +33,7 @@ FUSE::ReadDirSeq::operator()(const fuse_req_ctx_t *ctx_,
const fuse_file_info_t *ffi_,
fuse_dirents_t *dirents_)
{
DirInfo *di = DirInfo::from_fh(ffi_->fh);
const ugid::Set ugid(ctx_);
DirInfo *di = DirInfo::from_fh(ffi_->fh);
return ::_readdir(cfg.branches,
di->fusepath,

3
src/fuse_readlink.cpp

@ -120,8 +120,7 @@ FUSE::readlink(const fuse_req_ctx_t *ctx_,
char *buf_,
size_t size_)
{
const fs::path fusepath{fusepath_};
const ugid::Set ugid(ctx_);
const fs::path fusepath{fusepath_};
return ::_readlink(cfg.func.readlink.policy,
cfg.branches,

2
src/fuse_removexattr.cpp

@ -101,8 +101,6 @@ FUSE::removexattr(const fuse_req_ctx_t *ctx_,
if(cfg.xattr.to_int())
return -cfg.xattr.to_int();
const ugid::Set ugid(ctx_);
return ::_removexattr(cfg.func.removexattr.policy,
cfg.func.getxattr.policy,
cfg.branches,

12
src/fuse_rename.cpp

@ -21,7 +21,7 @@
#include "errno.hpp"
#include "fs_clonepath.hpp"
#include "fs_link.hpp"
#include "fs_mkdir_as_root.hpp"
#include "fs_mkdir_as.hpp"
#include "fs_path.hpp"
#include "fs_remove.hpp"
#include "fs_rename.hpp"
@ -105,9 +105,9 @@ _rename_create_path(const Policy::Search &searchPolicy_,
rv = fs::rename(oldfullpath,newfullpath);
if(rv < 0)
{
rv = fs::clonepath_as_root(newbranches[0]->path,
branch.path,
newfusepath_.parent_path());
rv = fs::clonepath(newbranches[0]->path,
branch.path,
newfusepath_.parent_path());
if(rv >= 0)
rv = fs::rename(oldfullpath,newfullpath);
}
@ -209,7 +209,6 @@ _rename_exdev_rename_target(const Policy::Action &actionPolicy_,
if(rv < 0)
return rv;
ugid::SetRootGuard ugidGuard;
for(auto &branch : obranches_)
{
clonesrc = branch->path;
@ -219,7 +218,7 @@ _rename_exdev_rename_target(const Policy::Action &actionPolicy_,
rv = fs::clonepath(clonesrc,clonedst,oldfusepath_.parent_path());
if(rv == -ENOENT)
{
fs::mkdir(clonedst,01777);
fs::mkdir_as({0,0},clonedst,01777);
rv = fs::clonepath(clonesrc,clonedst,oldfusepath_.parent_path());
}
@ -355,7 +354,6 @@ FUSE::rename(const fuse_req_ctx_t *ctx_,
int rv;
const fs::path oldfusepath{oldfusepath_};
const fs::path newfusepath{newfusepath_};
const ugid::Set ugid(ctx_);
rv = ::_rename(oldfusepath,newfusepath);
if(rv == -EXDEV)

1
src/fuse_rmdir.cpp

@ -96,7 +96,6 @@ FUSE::rmdir(const fuse_req_ctx_t *ctx_,
const char *fusepath_)
{
const fs::path fusepath{fusepath_};
const ugid::Set ugid(ctx_);
return ::_rmdir(cfg.func.rmdir.policy,
cfg.branches,

2
src/fuse_setxattr.cpp

@ -194,8 +194,6 @@ _setxattr(const fuse_req_ctx_t *ctx_,
if(cfg.xattr.to_int())
return -cfg.xattr.to_int();
const ugid::Set ugid(ctx_);
return ::_setxattr(cfg.func.setxattr.policy,
cfg.func.getxattr.policy,
cfg.branches,

1
src/fuse_statfs.cpp

@ -147,7 +147,6 @@ FUSE::statfs(const fuse_req_ctx_t *ctx_,
struct statvfs *st_)
{
const fs::path fusepath{fusepath_};
const ugid::Set ugid(ctx_);
return ::_statfs(cfg.branches,
fusepath,

4
src/fuse_statx_supported.icpp

@ -213,8 +213,6 @@ FUSE::statx(const fuse_req_ctx_t *ctx_,
if(Config::is_ctrl_file(fusepath))
return ::_statx_controlfile(st_);
const ugid::Set ugid(ctx_);
return ::_statx(fusepath,
flags_|AT_STATX_DONT_SYNC,
mask_,
@ -247,8 +245,6 @@ FUSE::statx_fh(const fuse_req_ctx_t *ctx_,
FileInfo *fi = FileInfo::from_fh(fh);
const ugid::Set ugid(ctx_);
return ::_statx(fi->fusepath,
flags_|AT_STATX_DONT_SYNC,
mask_,

64
src/fuse_symlink.cpp

@ -23,7 +23,7 @@
#include "fs_lstat.hpp"
#include "fs_path.hpp"
#include "fs_inode.hpp"
#include "fs_symlink.hpp"
#include "fs_symlink_as.hpp"
#include "fuse_getattr.hpp"
#include "ugid.hpp"
@ -35,7 +35,8 @@
static
int
_symlink_loop_core(const fs::path &newbranch_,
_symlink_loop_core(const ugid_t ugid_,
const fs::path &newbranch_,
const char *target_,
const fs::path &linkpath_,
struct stat *st_)
@ -45,7 +46,7 @@ _symlink_loop_core(const fs::path &newbranch_,
fullnewpath = newbranch_ / linkpath_;
rv = fs::symlink(target_,fullnewpath);
rv = fs::symlink_as(ugid_,target_,fullnewpath);
if((rv >= 0) && (st_ != NULL) && (st_->st_ino == 0))
{
fs::lstat(fullnewpath,st_);
@ -60,7 +61,8 @@ _symlink_loop_core(const fs::path &newbranch_,
static
int
_symlink_loop(const fs::path &existingbranch_,
_symlink_loop(const ugid_t ugid_,
const fs::path &existingbranch_,
const std::vector<Branch*> &newbranches_,
const char *target_,
const fs::path &linkpath_,
@ -72,13 +74,14 @@ _symlink_loop(const fs::path &existingbranch_,
for(auto &newbranch :newbranches_)
{
rv = fs::clonepath_as_root(existingbranch_,
newbranch->path,
newdirpath_);
rv = fs::clonepath(existingbranch_,
newbranch->path,
newdirpath_);
if(rv < 0)
err = rv;
else
err = ::_symlink_loop_core(newbranch->path,
err = ::_symlink_loop_core(ugid_,
newbranch->path,
target_,
linkpath_,
st_);
@ -89,7 +92,8 @@ _symlink_loop(const fs::path &existingbranch_,
static
int
_symlink(const Policy::Search &searchFunc_,
_symlink(const ugid_t ugid_,
const Policy::Search &searchFunc_,
const Policy::Create &createFunc_,
const Branches &branches_,
const char *target_,
@ -111,7 +115,8 @@ _symlink(const Policy::Search &searchFunc_,
if(rv < 0)
return rv;
return ::_symlink_loop(existingbranches[0]->path,
return ::_symlink_loop(ugid_,
existingbranches[0]->path,
newbranches,
target_,
linkpath_,
@ -119,22 +124,6 @@ _symlink(const Policy::Search &searchFunc_,
st_);
}
int
FUSE::symlink(const fuse_req_ctx_t *ctx_,
const char *target_,
const char *linkpath_,
struct stat *st_,
fuse_timeouts_t *timeouts_)
{
const fs::path linkpath{linkpath_};
return FUSE::symlink(ctx_,
target_,
linkpath,
st_,
timeouts_);
}
int
FUSE::symlink(const fuse_req_ctx_t *ctx_,
const char *target_,
@ -143,9 +132,9 @@ FUSE::symlink(const fuse_req_ctx_t *ctx_,
fuse_timeouts_t *timeouts_)
{
int rv;
const ugid::Set ugid(ctx_);
rv = ::_symlink(cfg.func.getattr.policy,
rv = ::_symlink(ctx_,
cfg.func.getattr.policy,
cfg.func.symlink.policy,
cfg.branches,
target_,
@ -154,7 +143,8 @@ FUSE::symlink(const fuse_req_ctx_t *ctx_,
if(rv == -EROFS)
{
cfg.branches.find_and_set_mode_ro();
rv = ::_symlink(cfg.func.getattr.policy,
rv = ::_symlink(ctx_,
cfg.func.getattr.policy,
cfg.func.symlink.policy,
cfg.branches,
target_,
@ -181,3 +171,19 @@ FUSE::symlink(const fuse_req_ctx_t *ctx_,
return rv;
}
int
FUSE::symlink(const fuse_req_ctx_t *ctx_,
const char *target_,
const char *linkpath_,
struct stat *st_,
fuse_timeouts_t *timeouts_)
{
const fs::path linkpath{linkpath_};
return FUSE::symlink(ctx_,
target_,
linkpath,
st_,
timeouts_);
}

3
src/fuse_truncate.cpp

@ -94,8 +94,7 @@ FUSE::truncate(const fuse_req_ctx_t *ctx_,
const char *fusepath_,
off_t size_)
{
const fs::path fusepath{fusepath_};
const ugid::Set ugid(ctx_);
const fs::path fusepath{fusepath_};
return ::_truncate(cfg.func.truncate.policy,
cfg.func.getattr.policy,

3
src/fuse_unlink.cpp

@ -68,8 +68,7 @@ int
FUSE::unlink(const fuse_req_ctx_t *ctx_,
const char *fusepath_)
{
const fs::path fusepath{fusepath_};
const ugid::Set ugid(ctx_);
const fs::path fusepath{fusepath_};
return ::_unlink(cfg.func.unlink.policy,
cfg.branches,

3
src/fuse_utimens.cpp

@ -93,8 +93,7 @@ FUSE::utimens(const fuse_req_ctx_t *ctx_,
const char *fusepath_,
const timespec ts_[2])
{
const fs::path fusepath{fusepath_};
const ugid::Set ugid(ctx_);
const fs::path fusepath{fusepath_};
return ::_utimens(cfg.func.utimens.policy,
cfg.func.getattr.policy,

2
src/mergerfs.cpp

@ -18,6 +18,8 @@
#include "mergerfs_fsck.hpp"
#include "mergerfs_collect_info.hpp"
#include "caps.hpp"
#include "config.hpp"
#include "fs_path.hpp"
#include "fs_readahead.hpp"

2
src/policy_ff.cpp

@ -16,6 +16,8 @@
#include "policy_ff.hpp"
#include "ugid.hpp"
#include "errno.hpp"
#include "fs_exists.hpp"
#include "fs_info.hpp"

33
src/ugid.cpp

@ -1,33 +1,8 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "gidcache.hpp"
#if defined __linux__ and UGID_USE_RWLOCK == 0
#include "ugid_linux.icpp"
#else
#include "ugid_rwlock.icpp"
#endif
#include <unistd.h>
namespace ugid
{
void
initgroups(const uid_t uid_,
const gid_t gid_)
{
GIDCache::initgroups(uid_,gid_);
}
thread_local uid_t currentuid = 0;
thread_local gid_t currentgid = 0;
thread_local bool initialized = false;
}

113
src/ugid.hpp

@ -16,21 +16,116 @@
#pragma once
#include "fuse_req_ctx.h"
#include "fuse_kernel.h"
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <grp.h>
#include <pwd.h>
#include <map>
#include <vector>
#include "fuse_req_ctx.h"
namespace ugid
#include <sys/types.h>
#include <unistd.h>
#include <vector>
struct ugid_t
{
void init();
void initgroups(const uid_t uid, const gid_t gid);
}
ugid_t(const uid_t uid_,
const gid_t gid_)
: uid(uid_),
gid(gid_)
{
}
ugid_t(const fuse_req_ctx_t *ctx_)
: ugid_t(ctx_->uid,ctx_->gid)
{
}
uid_t uid;
gid_t gid;
};
#if defined SYS_setreuid32
#define SETREUID(R,E) (::syscall(SYS_setreuid32,(R),(E)))
#else
#define SETREUID(R,E) (::syscall(SYS_setreuid,(R),(E)))
#endif
#if defined SYS_setregid32
#define SETREGID(R,E) (::syscall(SYS_setregid32,(R),(E)))
#else
#define SETREGID(R,E) (::syscall(SYS_setregid,(R),(E)))
#endif
#if defined __linux__ and UGID_USE_RWLOCK == 0
#pragma message "using ugid_linux.hpp"
#include "ugid_linux.hpp"
#if defined SYS_geteuid32
#define GETEUID() (::syscall(SYS_geteuid32))
#else
#pragma message "using ugid_rwlock.hpp"
#include "ugid_rwlock.hpp"
#define GETEUID() (::syscall(SYS_geteuid))
#endif
#if defined SYS_getegid32
#define GETEGID() (::syscall(SYS_getegid32))
#else
#define GETEGID() (::syscall(SYS_getegid))
#endif
namespace ugid
{
extern thread_local uid_t currentuid;
extern thread_local gid_t currentgid;
extern thread_local bool initialized;
struct Set
{
Set(const uid_t newuid_,
const gid_t newgid_)
{
uid_t newuid;
gid_t newgid;
newuid = ((newuid_ == FUSE_INVALID_UIDGID) ? 0 : newuid_);
newgid = ((newgid_ == FUSE_INVALID_UIDGID) ? 0 : newgid_);
if(!initialized)
{
currentuid = GETEUID();
currentgid = GETEGID();
initialized = true;
}
if((newuid == currentuid) && (newgid == currentgid))
return;
SETREGID(-1,newgid);
SETREUID(-1,newuid);
currentuid = newuid;
currentgid = newgid;
}
Set(const fuse_req_ctx_t *ctx_)
: Set(ctx_->uid,ctx_->gid)
{
}
Set(const ugid_t ugid_)
: Set(ugid_.uid,ugid_.gid)
{
}
};
}
#undef SETREUID
#undef SETREGID
#undef GETEUID
#undef GETEGID

128
src/ugid_linux.hpp

@ -1,128 +0,0 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#pragma once
#include "fuse_req_ctx.h"
#include <assert.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <grp.h>
#include <pwd.h>
#include <map>
#include <vector>
#if defined SYS_setreuid32
#define SETREUID(R,E) (::syscall(SYS_setreuid32,(R),(E)))
#else
#define SETREUID(R,E) (::syscall(SYS_setreuid,(R),(E)))
#endif
#if defined SYS_setregid32
#define SETREGID(R,E) (::syscall(SYS_setregid32,(R),(E)))
#else
#define SETREGID(R,E) (::syscall(SYS_setregid,(R),(E)))
#endif
#if defined SYS_geteuid32
#define GETEUID() (::syscall(SYS_geteuid32))
#else
#define GETEUID() (::syscall(SYS_geteuid))
#endif
#if defined SYS_getegid32
#define GETEGID() (::syscall(SYS_getegid32))
#else
#define GETEGID() (::syscall(SYS_getegid))
#endif
namespace ugid
{
extern thread_local uid_t currentuid;
extern thread_local gid_t currentgid;
extern thread_local bool initialized;
struct Set
{
Set(const uid_t newuid_,
const gid_t newgid_)
{
assert((int)newuid_ != -1);
assert((int)newgid_ != -1);
if(!initialized)
{
currentuid = GETEUID();
currentgid = GETEGID();
initialized = true;
}
if((newuid_ == currentuid) && (newgid_ == currentgid))
return;
if(currentuid != 0)
{
SETREUID(-1,0);
SETREGID(-1,0);
}
if(newgid_)
{
SETREGID(-1,newgid_);
ugid::initgroups(newuid_,newgid_);
}
if(newuid_)
SETREUID(-1,newuid_);
currentuid = newuid_;
currentgid = newgid_;
}
Set(const fuse_req_ctx_t *ctx_)
: Set(ctx_->uid,ctx_->gid)
{
}
};
struct SetRootGuard
{
SetRootGuard() :
prevuid(currentuid),
prevgid(currentgid)
{
Set(0,0);
}
~SetRootGuard()
{
Set(prevuid,prevgid);
}
const uid_t prevuid;
const gid_t prevgid;
};
}
#undef SETREUID
#undef SETREGID
#undef GETEUID
#undef GETEGID

34
src/ugid_linux.icpp

@ -1,34 +0,0 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdlib.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>
namespace ugid
{
thread_local uid_t currentuid = 0;
thread_local gid_t currentgid = 0;
thread_local bool initialized = false;
void
init()
{
}
}

106
src/ugid_rwlock.hpp

@ -1,106 +0,0 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#pragma once
#include "fuse_req_ctx.h"
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
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(const fuse_req_ctx_t *ctx_)
: Set(ctx_->uid,ctx_->gid)
{
}
~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;
};
}

45
src/ugid_rwlock.icpp

@ -1,45 +0,0 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <pthread.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>
namespace ugid
{
uid_t currentuid;
gid_t currentgid;
pthread_rwlock_t rwlock;
void
init()
{
pthread_rwlockattr_t attr;
pthread_rwlockattr_init(&attr);
# if defined PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
pthread_rwlockattr_setkind_np(&attr,PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
# endif
pthread_rwlock_init(&rwlock,&attr);
currentuid = ::geteuid();
currentgid = ::getegid();
}
}
Loading…
Cancel
Save