Skip to content

Commit

Permalink
add CVMFS_INFO_HEADER
Browse files Browse the repository at this point in the history
  • Loading branch information
DrDaveD committed Dec 24, 2024
1 parent 19a54d0 commit 6d6e5ec
Show file tree
Hide file tree
Showing 20 changed files with 363 additions and 111 deletions.
2 changes: 1 addition & 1 deletion cvmfs/cache_plugin/libcvmfs_cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ void cvmcache_get_session(cvmcache_session *session) {
void cvmcache_spawn_watchdog(const char *crash_dump_file) {
if (g_watchdog != NULL)
return;
g_watchdog = Watchdog::Create(NULL);
g_watchdog = Watchdog::Create(NULL, false);
assert(g_watchdog != NULL);
g_watchdog->Spawn((crash_dump_file != NULL) ? string(crash_dump_file) : "");
}
Expand Down
2 changes: 1 addition & 1 deletion cvmfs/cache_stream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ int64_t StreamingCacheManager::Stream(

download::JobInfo download_job(&url, is_zipped, true /* probe_hosts */,
&info.object_id, &sink);
download_job.SetExtraInfo(&info.label.path);
download_job.SetPathInfo(&info.label.path);
download_job.SetRangeOffset(info.label.range_offset);
download_job.SetRangeSize(static_cast<int64_t>(info.label.size));
ClientCtx *ctx = ClientCtx::GetInstance();
Expand Down
56 changes: 53 additions & 3 deletions cvmfs/capabilities.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,21 @@ bool ClearPermittedCapabilities(int,
return true;
}

static uid_t old_uid;
static gid_t old_gid;

static bool obtainCapability(const cap_value_t, const char *) {
// there are no individual capabilities on OSX so switch back to root
old_uid = geteuid();
old_gid = getegid();
return (SwitchCredentials(0, getgid(), true));
}

static bool dropCapability(const cap_value_t, const char *) {
// there are no individual capabilities on OSX so temporarily back to user
return (SwitchCredentials(old_uid, old_gid, true));
}

#else

// Clear all CAP_PERMITTED capabilities except those requested.
Expand Down Expand Up @@ -174,9 +184,41 @@ static bool obtainCapability(const cap_value_t cap, const char *capname) {

if (retval != 0) {
LogCvmfs(kLogCvmfs, kLogStderr,
"Cannot reset capabilities for current process "
"(errno: %d)",
errno);
"Cannot set %s capability for current process (errno: %d)",
capname, errno);
return false;
}

return true;
}

static bool dropCapability(const cap_value_t cap, const char *capname) {
#ifdef CAP_IS_SUPPORTED
assert(CAP_IS_SUPPORTED(cap));
#endif

cap_t caps_proc = cap_get_proc();
assert(caps_proc != NULL);

cap_flag_value_t cap_state;
int retval = cap_get_flag(caps_proc, cap, CAP_EFFECTIVE, &cap_state);
assert(retval == 0);

if (cap_state == CAP_CLEAR) {
cap_free(caps_proc);
return true;
}

retval = cap_set_flag(caps_proc, CAP_EFFECTIVE, 1, &cap, CAP_CLEAR);
assert(retval == 0);

retval = cap_set_proc(caps_proc);
cap_free(caps_proc);

if (retval != 0) {
LogCvmfs(kLogCvmfs, kLogStderr,
"Cannot reset %s capability for current process (errno: %d)",
capname, errno);
return false;
}

Expand All @@ -189,6 +231,10 @@ bool ObtainDacReadSearchCapability() {
return obtainCapability(CAP_DAC_READ_SEARCH, "CAP_DAC_READ_SEARCH");
}

bool DropDacReadSearchCapability() {
return dropCapability(CAP_DAC_READ_SEARCH, "CAP_DAC_READ_SEARCH");
}

bool ObtainSysAdminCapability() {
return obtainCapability(CAP_SYS_ADMIN, "CAP_SYS_ADMIN");
}
Expand All @@ -197,6 +243,10 @@ bool ObtainSysPtraceCapability() {
return obtainCapability(CAP_SYS_PTRACE, "CAP_SYS_PTRACE");
}

bool DropSysPtraceCapability() {
return dropCapability(CAP_SYS_PTRACE, "CAP_SYS_PTRACE");
}


#ifdef CVMFS_NAMESPACE_GUARD
} // namespace CVMFS_NAMESPACE_GUARD
Expand Down
2 changes: 2 additions & 0 deletions cvmfs/capabilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ namespace CVMFS_NAMESPACE_GUARD {
#endif

bool ObtainDacReadSearchCapability();
bool DropDacReadSearchCapability();
bool ObtainSysAdminCapability();
bool ObtainSysPtraceCapability();
bool DropSysPtraceCapability();
bool ClearPermittedCapabilities(int nreservecaps,
const cap_value_t *reservecaps,
int ninheritablecaps,
Expand Down
9 changes: 8 additions & 1 deletion cvmfs/cvmfs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2308,6 +2308,11 @@ static unsigned CheckMaxOpenFiles() {
}


static bool NeedsReadEnviron() {
return MountPoint::needs_read_environ(cvmfs::options_mgr_);
}


static int Init(const loader::LoaderExports *loader_exports) {
g_boot_error = new string("unknown error");
cvmfs::loader_exports_ = loader_exports;
Expand All @@ -2323,7 +2328,8 @@ static int Init(const loader::LoaderExports *loader_exports) {
// Monitor, check for maximum number of open files
if (cvmfs::UseWatchdog()) {
auto_umount::SetMountpoint(loader_exports->mount_point);
cvmfs::watchdog_ = Watchdog::Create(auto_umount::UmountOnExit);
cvmfs::watchdog_ = Watchdog::Create(auto_umount::UmountOnExit,
NeedsReadEnviron());
if (cvmfs::watchdog_ == NULL) {
*g_boot_error = "failed to initialize watchdog.";
return loader::kFailMonitor;
Expand Down Expand Up @@ -3001,6 +3007,7 @@ static void __attribute__((constructor)) LibraryMain() {
g_cvmfs_exports->fnSaveState = SaveState;
g_cvmfs_exports->fnRestoreState = RestoreState;
g_cvmfs_exports->fnFreeSavedState = FreeSavedState;
g_cvmfs_exports->fnNeedsReadEnviron = NeedsReadEnviron;
cvmfs::SetCvmfsOperations(&g_cvmfs_exports->cvmfs_operations);
}

Expand Down
2 changes: 1 addition & 1 deletion cvmfs/fetch.cc
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ int Fetcher::Fetch(
tls->download_job.SetUrl(&url);
tls->download_job.SetSink(&sink);
tls->download_job.SetExpectedHash(&object.id);
tls->download_job.SetExtraInfo(&object.label.path);
tls->download_job.SetPathInfo(&object.label.path);
ClientCtx *ctx = ClientCtx::GetInstance();
if (ctx->IsSet()) {
ctx->Get(tls->download_job.GetUidPtr(),
Expand Down
14 changes: 9 additions & 5 deletions cvmfs/loader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1072,11 +1072,15 @@ int FuseMain(int argc, char *argv[]) {
} else if ((getuid() == 0) && (geteuid() != 0)) {
LogCvmfs(kLogCvmfs, kLogDebug, "Reducing to minimum capabilities");
// Have temporarily dropped credentials, now drop credentials permanently.
// CAP_DAC_READ_SEARCH will be sometimes needed for a future feature;
// for now reserve it all the time for testing.
cap_value_t reservecaps[] = {CAP_DAC_READ_SEARCH};
retval = ClearPermittedCapabilities(
sizeof(reservecaps)/sizeof(cap_value_t), reservecaps, 0, 0);

if (cvmfs_exports_->fnNeedsReadEnviron()) {
// Reserve the capabilities to read process environments
cap_value_t reservecaps[] = {CAP_DAC_READ_SEARCH, CAP_SYS_PTRACE};
retval = ClearPermittedCapabilities(
sizeof(reservecaps)/sizeof(cap_value_t), reservecaps, 0, 0);
} else {
retval = ClearPermittedCapabilities(0, 0, 0, 0);
}
if (!retval) {
LogCvmfs(kLogCvmfs, kLogStderr,
"Failed to reduce to minimum capabilities");
Expand Down
2 changes: 2 additions & 0 deletions cvmfs/loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ struct CvmfsExports {
fnSaveState = NULL;
fnRestoreState = NULL;
fnFreeSavedState = NULL;
fnNeedsReadEnviron = NULL;
memset(&cvmfs_operations, 0, sizeof(cvmfs_operations));
}

Expand All @@ -240,6 +241,7 @@ struct CvmfsExports {
bool (*fnRestoreState)(const int fd_progress, const StateList &saved_states);
void (*fnFreeSavedState)(const int fd_progress,
const StateList &saved_states);
bool (*fnNeedsReadEnviron)();
struct fuse_lowlevel_ops cvmfs_operations;
};

Expand Down
30 changes: 19 additions & 11 deletions cvmfs/monitor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ int Watchdog::g_crash_signals[] = { SIGQUIT, SIGILL, SIGABRT,
SIGFPE, SIGSEGV, SIGBUS,
SIGPIPE, SIGXFSZ };

Watchdog *Watchdog::Create(FnOnExit on_exit) {
Watchdog *Watchdog::Create(FnOnExit on_exit, bool needs_read_environ) {
assert(instance_ == NULL);
instance_ = new Watchdog(on_exit);
instance_->Fork();
instance_->Fork(needs_read_environ);
return instance_;
}

Expand Down Expand Up @@ -386,7 +386,7 @@ Watchdog::SigactionMap Watchdog::SetSignalHandlers(
/**
* Fork the watchdog process and put it on hold until Spawn() is called.
*/
void Watchdog::Fork() {
void Watchdog::Fork(bool needs_read_environ) {
Pipe<kPipeWatchdogPid> pipe_pid;
pipe_watchdog_ = new Pipe<kPipeWatchdog>();
pipe_listener_ = new Pipe<kPipeWatchdogSupervisor>();
Expand All @@ -406,14 +406,22 @@ void Watchdog::Fork() {
if (on_exit_) {
// Reduce to minimum capabilities, which unfortunately is
// still quite powerful.
// CAP_SYS_ADMIN is needed to unmount, and CAP_DAC_READ_SEARCH
// is needed because the main process might have it and ptrace
// is not allowed on a process with more capabilities.
cap_value_t reservecaps[] = {CAP_SYS_ADMIN, CAP_DAC_READ_SEARCH};
cap_value_t inheritablecaps[] = {CAP_DAC_READ_SEARCH};
assert(ClearPermittedCapabilities(
sizeof(reservecaps)/sizeof(cap_value_t), reservecaps,
sizeof(inheritablecaps)/sizeof(cap_value_t), inheritablecaps));
// CAP_SYS_ADMIN is needed to unmount, and CAP_SYS_PTRACE
// is needed when needs_read_environ is true because then
// the main Fuse process has elevated capabilities and
// ptrace (needed for collecting a stack trace) is not
// allowed on a process with more capabilities.
if (needs_read_environ) {
cap_value_t reservecaps[] = {CAP_SYS_ADMIN, CAP_SYS_PTRACE};
cap_value_t inheritcaps[] = {CAP_SYS_PTRACE};
assert(ClearPermittedCapabilities(
sizeof(reservecaps)/sizeof(cap_value_t), reservecaps,
sizeof(inheritcaps)/sizeof(cap_value_t), inheritcaps));
} else {
cap_value_t reservecaps[] = {CAP_SYS_ADMIN};
assert(ClearPermittedCapabilities(
sizeof(reservecaps)/sizeof(cap_value_t), reservecaps, 0, 0));
}
} else {
// Only need to be able to do the stack trace, and the
// main process needs no extra capabilities, so we can
Expand Down
4 changes: 2 additions & 2 deletions cvmfs/monitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class Watchdog : SingleCopy {
*/
typedef void (*FnOnExit)(const bool crashed);

static Watchdog *Create(FnOnExit on_exit);
static Watchdog *Create(FnOnExit on_exit, bool needs_read_environ);
static pid_t GetPid();
~Watchdog();
void Spawn(const std::string &crash_dump_path);
Expand Down Expand Up @@ -92,7 +92,7 @@ class Watchdog : SingleCopy {
static void SendTrace(int sig, siginfo_t *siginfo, void *context);

explicit Watchdog(FnOnExit on_exit);
void Fork();
void Fork(bool needs_read_environ);
bool WaitForSupervisee();
SigactionMap SetSignalHandlers(const SigactionMap &signal_handlers);
void Supervise();
Expand Down
19 changes: 18 additions & 1 deletion cvmfs/mountpoint.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2244,13 +2244,30 @@ void MountPoint::SetupHttpTuning() {
{
download_mgr_->EnableRedirects();
}
if (options_mgr_->GetValue("CVMFS_SEND_INFO_HEADER", &optarg) &&
if (options_mgr_->GetValue("CVMFS_INFO_HEADER", &optarg) && (optarg != ""))
{
download_mgr_->EnableInfoHeader();
download_mgr_->SetInfoHeaderTemplate(optarg);
} else if (options_mgr_->GetValue("CVMFS_SEND_INFO_HEADER", &optarg) &&
options_mgr_->IsOn(optarg))
{
download_mgr_->EnableInfoHeader();
download_mgr_->SetInfoHeaderTemplate("%{path}");
}
}

/*
* Check whether permission is needed to read from user process environment.
*/

bool MountPoint::needs_read_environ(OptionsManager *omgr) {
// This is a class (static) method because it is used early, before
// all the above initialization is done, so can't rely on mountpoint
// object data.
string info_header;
omgr->GetValue("CVMFS_INFO_HEADER", &info_header);
return (info_header.find("%{env:") != std::string::npos);
}

void MountPoint::SetupInodeAnnotation() {
string optarg;
Expand Down
6 changes: 3 additions & 3 deletions cvmfs/mountpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "gtest/gtest_prod.h"
#include "loader.h"
#include "magic_xattr.h"
#include "network/download.h"
#include "util/algorithm.h"
#include "util/pointer.h"

Expand All @@ -39,9 +40,6 @@ namespace cvmfs {
class Fetcher;
class Uuid;
}
namespace download {
class DownloadManager;
}
namespace glue {
class InodeTracker;
class DentryTracker;
Expand Down Expand Up @@ -493,6 +491,8 @@ class MountPoint : SingleCopy, public BootFactory {
OptionsManager *options_mgr = NULL);
~MountPoint();

static bool needs_read_environ(OptionsManager *omgr);

unsigned GetMaxTtlMn();
unsigned GetEffectiveTtlSec();
void SetMaxTtlMn(unsigned value_minutes);
Expand Down
Loading

0 comments on commit 6d6e5ec

Please sign in to comment.