Skip to content

Commit

Permalink
reduce client capabilities to minimum
Browse files Browse the repository at this point in the history
  • Loading branch information
DrDaveD committed Dec 18, 2024
1 parent df5ddbd commit b9586f9
Show file tree
Hide file tree
Showing 24 changed files with 192 additions and 158 deletions.
17 changes: 13 additions & 4 deletions cvmfs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ if (BUILD_CVMFS OR BUILD_LIBCVMFS)
cache_stream.cc
cache_tiered.cc
cache_transport.cc
capabilities.cc
catalog.cc
catalog_counters.cc
catalog_mgr_client.cc
Expand Down Expand Up @@ -167,16 +168,16 @@ if (BUILD_CVMFS)
#
add_executable (cvmfs2
fuse_main.cc
capabilities.cc
util/exception.cc
util/logging.cc
util/posix.cc
util/string.cc
)
set_target_properties (cvmfs2 PROPERTIES
COMPILE_FLAGS "-DCVMFS_NAMESPACE_GUARD=stub -DCVMFS_FUSE_MODULE"
LINK_FLAGS "-ldl"
)
target_link_libraries(cvmfs2 pthread dl)
target_link_libraries(cvmfs2 pthread dl ${CAP_LIBRARIES})

#
# /usr/lib/libcvmfs_fuse_stub[3]
Expand All @@ -185,6 +186,7 @@ if (BUILD_CVMFS)
# libcvmfs-fuse.
#
set (CVMFS_STUB_SOURCES
capabilities.cc
globals.cc
loader.cc
loader_talk.cc
Expand Down Expand Up @@ -446,6 +448,7 @@ if (BUILD_LIBCVMFS_CACHE)
cache_plugin/libcvmfs_cache_options.cc
cache_plugin/channel.cc
cache_transport.cc
capabilities.cc
monitor.cc
options.cc
sanitizer.cc
Expand Down Expand Up @@ -474,6 +477,7 @@ if (BUILD_LIBCVMFS_CACHE)
target_link_libraries(cvmfs_cache
PUBLIC cvmfs_crypto
cvmfs_util
${CAP_LIBRARIES}
PRIVATE ${PROTOBUF_LITE_LIBRARY}
)

Expand All @@ -483,6 +487,7 @@ if (BUILD_LIBCVMFS_CACHE)
add_executable (cvmfs_cache_null cache_plugin/cvmfs_cache_null.cc)
target_link_libraries (cvmfs_cache_null
cvmfs_cache
${CAP_LIBRARIES}
${RT_LIBRARY}
pthread
)
Expand Down Expand Up @@ -573,6 +578,7 @@ if (BUILD_SERVER)
#
set (CVMFS_SWISSKNIFE_SOURCES
backoff.cc
capabilities.cc
catalog.cc
catalog_counters.cc
catalog_mgr_ro.cc
Expand Down Expand Up @@ -640,7 +646,6 @@ if (BUILD_SERVER)
supervisor.cc
swissknife.cc
swissknife_assistant.cc
swissknife_capabilities.cc
swissknife_check.cc
swissknife_gc.cc
swissknife_graft.cc
Expand Down Expand Up @@ -719,6 +724,7 @@ if (BUILD_SERVER)
#
set (LIBCVMFS_SERVER_SOURCES
backoff.cc
capabilities.cc
catalog.cc
catalog_counters.cc
catalog_rw.cc
Expand Down Expand Up @@ -837,6 +843,7 @@ if (BUILD_SERVER)
#
set (CVMFS_PUBLISH_SOURCES
backoff.cc
capabilities.cc
compression/compression.cc
directory_entry.cc
manifest.cc
Expand Down Expand Up @@ -1013,6 +1020,7 @@ if(BUILD_RECEIVER)
receiver/receiver.cc
receiver/session_token.cc
backoff.cc
capabilities.cc
catalog.cc
catalog_rw.cc
catalog_counters.cc
Expand Down Expand Up @@ -1085,6 +1093,7 @@ if(BUILD_RECEIVER)
${OPENSSL_LIBRARIES}
${ZLIB_LIBRARIES}
${RT_LIBRARY}
${CAP_LIBRARIES}
${LibArchive_LIBRARY}
pthread
dl
Expand Down Expand Up @@ -1136,7 +1145,6 @@ if (BUILD_SHRINKWRAP)
endif ()

add_executable (cvmfs_shrinkwrap
monitor.cc
shrinkwrap/fs_traversal.cc
shrinkwrap/fs_traversal_libcvmfs.cc
shrinkwrap/posix/data_dir_mgmt.cc
Expand All @@ -1156,6 +1164,7 @@ if (BUILD_SHRINKWRAP)
cvmfs_client
cvmfs_crypto
cvmfs_util
${CAP_LIBRARIES}
pthread
dl
)
Expand Down
68 changes: 43 additions & 25 deletions cvmfs/auto_umount.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <string>
#include <vector>

#include "capabilities.h"
#include "util/logging.h"
#include "util/platform.h"
#include "util/posix.h"
Expand All @@ -35,21 +36,28 @@ void SetMountpoint(const string &mountpoint) {
}


void UmountOnCrash() {
void UmountOnExit(const bool crashed) {
const char *cleanuptype = "exit";
if (crashed)
cleanuptype = "crash";

if (!mountpoint_) {
LogCvmfs(kLogCvmfs, kLogSyslogErr, "crash cleanup handler: no mountpoint");
LogCvmfs(kLogCvmfs, kLogSyslogErr,
"%s cleanup handler: no mountpoint", cleanuptype);
return;
}

std::vector<std::string> all_mountpoints = platform_mountlist();
if (all_mountpoints.empty()) {
LogCvmfs(kLogCvmfs, kLogSyslogErr, "crash cleanup handler: "
"failed to read mount point list");
LogCvmfs(kLogCvmfs, kLogSyslogErr, "%s cleanup handler: "
"failed to read mount point list", cleanuptype);
return;
}

// Mitigate auto-mount - crash - umount - auto-mount loops
SafeSleepMs(2000);
if (crashed) {
// Mitigate auto-mount - crash - umount - auto-mount loops
SafeSleepMs(2000);
}

// Check if *mountpoint_ is still mounted
// (we don't want to trigger a mount by immediately doing stat *mountpoint_)
Expand All @@ -61,42 +69,52 @@ void UmountOnCrash() {
}
}
if (!still_mounted) {
LogCvmfs(kLogCvmfs, kLogSyslog, "crash cleanup handler: %s not mounted",
mountpoint_->c_str());
int logtype = kLogDebug;
if (crashed)
logtype = kLogSyslog;
LogCvmfs(kLogCvmfs, logtype, "%s cleanup handler: %s not mounted",
cleanuptype, mountpoint_->c_str());
return;
}

// stat() might be served from caches. Opendir ensures fuse module is called.
int expected_error;
if (crashed) {
// stat() might be served from caches. Opendir ensures fuse module is called.
int expected_error;
#ifdef __APPLE__
expected_error = ENXIO;
expected_error = ENXIO;
#else
expected_error = ENOTCONN;
expected_error = ENOTCONN;
#endif
DIR *dirp = opendir(mountpoint_->c_str());
if (dirp || (errno != expected_error)) {
if (dirp) closedir(dirp);
LogCvmfs(kLogCvmfs, kLogSyslog, "crash cleanup handler: "
"%s seems not to be stalled (%d)", mountpoint_->c_str(), errno);
return;
DIR *dirp = opendir(mountpoint_->c_str());
if (dirp || (errno != expected_error)) {
if (dirp) closedir(dirp);
LogCvmfs(kLogCvmfs, kLogSyslog, "crash cleanup handler: "
"%s seems not to be stalled (%d)", mountpoint_->c_str(), errno);
return;
}
}

// sudo umount -l *mountpoint_
if (!SwitchCredentials(0, getegid(), true)) {
LogCvmfs(kLogCvmfs, kLogSyslogErr, "crash cleanup handler: "
"failed to re-gain root privileges");
if (!ObtainSysAdminCapability()) {
LogCvmfs(kLogCvmfs, kLogSyslogErr, "%s cleanup handler: "
"failed to re-gain sys_admin capability", cleanuptype);
return;
}
const bool lazy = true;
bool retval = platform_umount(mountpoint_->c_str(), lazy);
if (!retval) {
LogCvmfs(kLogCvmfs, kLogSyslogErr, "crash cleanup handler: "
"failed to unmount %s", mountpoint_->c_str());
LogCvmfs(kLogCvmfs, kLogSyslogErr, "%s cleanup handler: "
"failed to unmount %s", mountpoint_->c_str(), cleanuptype);
return;
}

LogCvmfs(kLogCvmfs, kLogSyslog, "crash cleanup handler unmounted stalled %s",
mountpoint_->c_str());
if (crashed) {
LogCvmfs(kLogCvmfs, kLogSyslog,
"crash cleanup handler unmounted stalled %s", mountpoint_->c_str());
} else {
LogCvmfs(kLogCvmfs, kLogSyslog,
"exit cleanup handler unmounted %s", mountpoint_->c_str());
}
}

} // namespace auto_umount
2 changes: 1 addition & 1 deletion cvmfs/auto_umount.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
namespace auto_umount {

void SetMountpoint(const std::string &mountpoint);
void UmountOnCrash();
void UmountOnExit(const bool crashed);

} // namespace auto_umount

Expand Down
File renamed without changes.
File renamed without changes.
6 changes: 4 additions & 2 deletions cvmfs/cvmfs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2323,7 +2323,7 @@ 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::UmountOnCrash);
cvmfs::watchdog_ = Watchdog::Create(auto_umount::UmountOnExit);
if (cvmfs::watchdog_ == NULL) {
*g_boot_error = "failed to initialize watchdog.";
return loader::kFailMonitor;
Expand Down Expand Up @@ -2509,7 +2509,7 @@ static void ShutdownMountpoint() {
delete cvmfs::notification_client_;
cvmfs::notification_client_ = NULL;

// The remonter has a reference to the mount point and the inode generation
// The remounter has a reference to the mount point and the inode generation
delete cvmfs::fuse_remounter_;
cvmfs::fuse_remounter_ = NULL;

Expand Down Expand Up @@ -2571,6 +2571,8 @@ static bool MaintenanceMode(const int fd_progress) {
"s)\n";
SendMsg2Socket(fd_progress, msg_progress);
cvmfs::fuse_remounter_->EnterMaintenanceMode();
// this keeps the watchdog from unmounting when it gets deleted
cvmfs::watchdog_->ClearOnExitFn();
return true;
}

Expand Down
44 changes: 40 additions & 4 deletions cvmfs/loader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <string>
#include <vector>

#include "capabilities.h"
#include "duplex_fuse.h"
#include "fence.h"
#include "fuse_main.h"
Expand Down Expand Up @@ -881,7 +882,8 @@ int FuseMain(int argc, char *argv[]) {
}
}

// Drop credentials
// Drop credentials, most likely temporarily since by default there is
// a watchdog
if ((uid_ != 0) || (gid_ != 0)) {
LogCvmfs(kLogCvmfs, kLogStdout, "CernVM-FS: running with credentials %d:%d",
uid_, gid_);
Expand All @@ -894,7 +896,9 @@ int FuseMain(int argc, char *argv[]) {
}
if (disable_watchdog_) {
LogCvmfs(kLogCvmfs, kLogDebug, "No watchdog, enabling core files");
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
retval = prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
if (retval != 0)
LogCvmfs(kLogCvmfs, kLogDebug, "Failed to set process dumpable");
}

// Only set usyslog now, otherwise file permissions are wrong
Expand Down Expand Up @@ -1055,15 +1059,41 @@ int FuseMain(int argc, char *argv[]) {
}
#endif

// drop credentials
if (suid_mode_) {
// Drop credentials again for now
const bool retrievable = !disable_watchdog_;
if (!SwitchCredentials(uid_, gid_, retrievable)) {
LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
"failed to drop permissions after mounting");
cvmfs_exports_->fnFini();
return kFailPermission;
}
} 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 (!retval) {
LogCvmfs(kLogCvmfs, kLogStderr,
"Failed to reduce to minimum capabilities");
return 1;
}
if (!disable_watchdog_) {
// allow ptracing by the watchdog
retval = prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
if (retval != 0)
LogCvmfs(kLogCvmfs, kLogDebug, "Failed to set process dumpable");
// but still disallow core dump
retval = SetLimitCore(0);
if (retval != 0)
LogCvmfs(kLogCvmfs, kLogDebug, "Failed to set core dump limit to 0");
}
} else {
LogCvmfs(kLogCvmfs, kLogDebug, "Not clearing capabilities, uid %d euid%d",
getuid(), geteuid());
}

// Determine device id
Expand Down Expand Up @@ -1135,6 +1165,11 @@ int FuseMain(int argc, char *argv[]) {
loader_talk::Fini();
cvmfs_exports_->fnFini();

if (!ObtainSysAdminCapability()) {
LogCvmfs(kLogCvmfs, kLogDebug,
"Failed to regain SYS_ADMIN capability");
}

// Unmount
#if CVMFS_USE_LIBFUSE == 2
fuse_remove_signal_handlers(session);
Expand All @@ -1155,7 +1190,8 @@ int FuseMain(int argc, char *argv[]) {

CloseLibrary();

LogCvmfs(kLogCvmfs, kLogSyslog, "CernVM-FS: unmounted %s (%s)",
LogCvmfs(kLogCvmfs, kLogSyslog,
"CernVM-FS: mount point %s (%s) session ended",
mount_point_->c_str(), repository_name_->c_str());

delete fence_reload_;
Expand Down
Loading

0 comments on commit b9586f9

Please sign in to comment.