aboutsummaryrefslogtreecommitdiffstats
path: root/src/file_util.cpp
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2022-06-25 06:19:55 +0200
committerSven Gothel <[email protected]>2022-06-25 06:19:55 +0200
commit510421f8c796adb2c6046b175de23901a027ebeb (patch)
treed87a01c0f8b73074370c73eafa7b0a74dd01987d /src/file_util.cpp
parentbebc60d7370a65489bf4c2c5af73e82585f62ecc (diff)
jau::fs::mount_image(), umount(): fork() to have child-process seteuid(0) for root-access only on loop-control and mount functions.
Diffstat (limited to 'src/file_util.cpp')
-rw-r--r--src/file_util.cpp245
1 files changed, 157 insertions, 88 deletions
diff --git a/src/file_util.cpp b/src/file_util.cpp
index bad1d53..88172aa 100644
--- a/src/file_util.cpp
+++ b/src/file_util.cpp
@@ -31,16 +31,17 @@
#include <jau/file_util.hpp>
extern "C" {
+ #include <unistd.h>
+ #include <dirent.h>
+ #include <fcntl.h>
#include <sys/stat.h>
+ #include <sys/types.h>
+ #include <sys/wait.h>
+ #include <sys/mount.h>
#ifdef __linux__
#include <sys/sendfile.h>
#include <linux/loop.h>
#endif
- #include <sys/types.h>
- #include <sys/mount.h>
- #include <dirent.h>
- #include <fcntl.h>
- #include <unistd.h>
}
#ifndef O_BINARY
@@ -1402,6 +1403,14 @@ bool jau::fs::copy(const std::string& source_path, const std::string& target_pat
return jau::fs::visit(source_stats, topts, pv);
}
+static bool set_effective_uid(::uid_t user_id) {
+ if( 0 != ::seteuid(user_id) ) {
+ ERR_PRINT("seteuid(%" PRIu32 ") failed", user_id);
+ return false;
+ }
+ return true;
+}
+
jau::fs::mount_ctx jau::fs::mount_image(const std::string& image_path, const std::string& mount_point, const std::string& fs_type,
const unsigned long mountflags, const std::string fs_options)
{
@@ -1415,71 +1424,106 @@ jau::fs::mount_ctx jau::fs::mount_image(const std::string& image_path, const std
}
int backingfile = ::open64(image_stats.path().c_str(), O_RDWR);
if( 0 > backingfile ) {
- jau::fprintf_td(stderr, "mount: Error: Couldn't open image-file '%s': res %d, errno %d (%s)\n",
- image_stats.to_string().c_str(), backingfile, errno, ::strerror(errno));
+ ERR_PRINT("Couldn't open image-file '%s': res %d", image_stats.to_string().c_str(), backingfile);
return mount_ctx();
}
#ifdef __linux__
+ const ::uid_t caller_uid = ::geteuid();
int loop_device_id = -1;
- int loop_ctl_fd = -1, loop_device_fd = -1;
- char loopname[4096];
- void* fs_options_cstr = nullptr;
- int mount_res = -1;
-
- loop_ctl_fd = ::open64("/dev/loop-control", O_RDWR);
- if( 0 > loop_ctl_fd ) {
- jau::fprintf_td(stderr, "mount: Error: Couldn't open loop-control: res %d, errno %d (%s)\n",
- loop_ctl_fd, errno, ::strerror(errno));
- goto errout;
- }
- loop_device_id = (int) ::ioctl(loop_ctl_fd, LOOP_CTL_GET_FREE);
- if( 0 > loop_device_id ) {
- jau::fprintf_td(stderr, "mount: Error: Couldn't get free loop-device: res %d, errno %d (%s)\n",
- loop_device_id, errno, ::strerror(errno));
- goto errout;
- }
- ::close(loop_ctl_fd);
- loop_ctl_fd = -1;
+ ::pid_t pid = ::fork();
+ if( 0 == pid ) {
+ int loop_ctl_fd = -1, loop_device_fd = -1;
+ char loopname[4096];
+ int mount_res = -1;
+ void* fs_options_cstr = nullptr;
- snprintf(loopname, sizeof(loopname), "/dev/loop%d", loop_device_id);
- jau::fprintf_td(stderr, "mount: Info: Using loop-device '%s'\n", loopname);
+ if( 0 != caller_uid ) {
+ if( !set_effective_uid(0) ) {
+ goto errout_child;
+ }
+ }
+ loop_ctl_fd = ::open64("/dev/loop-control", O_RDWR);
+ if( 0 > loop_ctl_fd ) {
+ ERR_PRINT("Couldn't open loop-control: res %d", loop_ctl_fd);
+ goto errout_child;
+ }
- loop_device_fd = ::open64(loopname, O_RDWR);
- if( 0 > loop_device_fd ) {
- jau::fprintf_td(stderr, "mount: Error: Couldn't open loop-device '%s': res %d, errno %d (%s)\n",
- loopname, loop_device_fd, errno, ::strerror(errno));
- goto errout;
- }
- if( 0 > ::ioctl(loop_device_fd, LOOP_SET_FD, backingfile) ) {
- jau::fprintf_td(stderr, "mount: Error: Couldn't attach image-file '%s' to loop-device '%s': errno %d (%s)\n",
- image_stats.to_string().c_str(), loopname, errno, ::strerror(errno));
- goto errout;
- }
- ::close(loop_device_fd);
- loop_device_fd = -1;
- ::close(backingfile);
- backingfile = -1;
+ loop_device_id = (int) ::ioctl(loop_ctl_fd, LOOP_CTL_GET_FREE);
+ if( 0 > loop_device_id ) {
+ ERR_PRINT("Couldn't get free loop-device: res %d", loop_device_id);
+ goto errout_child;
+ }
+ if( 254 < loop_device_id ) { // _exit() encoding
+ ERR_PRINT("loop-device %d out of valid range [0..254]", loop_device_id);
+ goto errout_child;
+ }
+ ::close(loop_ctl_fd);
+ loop_ctl_fd = -1;
- if( fs_options.size() > 0 ) {
- fs_options_cstr = (void*) fs_options.data();
- }
- mount_res = ::mount(loopname, target_stats.path().c_str(), fs_type.c_str(), mountflags, fs_options_cstr);
- if( 0 != mount_res ) {
- jau::fprintf_td(stderr, "mount: Error: source_path %s, target_path %s, fs_type %s, res %d, errno %d (%s)\n",
- image_path.c_str(), mount_point.c_str(), fs_type.c_str(), mount_res, errno, ::strerror(errno));
- ::ioctl(loop_device_fd, LOOP_CLR_FD, 0);
+ snprintf(loopname, sizeof(loopname), "/dev/loop%d", loop_device_id);
+ jau::INFO_PRINT("mount: Info: Using loop-device '%s'", loopname);
+
+ loop_device_fd = ::open64(loopname, O_RDWR);
+ if( 0 > loop_device_fd ) {
+ ERR_PRINT("Couldn't open loop-device '%s': res %d", loopname, loop_device_fd);
+ goto errout_child;
+ }
+ if( 0 > ::ioctl(loop_device_fd, LOOP_SET_FD, backingfile) ) {
+ ERR_PRINT("Couldn't attach image-file '%s' to loop-device '%s'", image_stats.to_string().c_str(), loopname);
+ goto errout_child;
+ }
+
+ if( fs_options.size() > 0 ) {
+ fs_options_cstr = (void*) fs_options.data();
+ }
+ mount_res = ::mount(loopname, target_stats.path().c_str(), fs_type.c_str(), mountflags, fs_options_cstr);
+ if( 0 != mount_res ) {
+ ERR_PRINT("source_path %s, target_path %s, fs_type %s, res %d", image_path.c_str(), mount_point.c_str(), fs_type.c_str(), mount_res);
+ ::ioctl(loop_device_fd, LOOP_CLR_FD, 0);
+ goto errout_child;
+ }
+ ::close(loop_device_fd);
+ loop_device_fd = -1;
+ ::_exit(loop_device_id+1);
+
+errout_child:
+ if( 0 <= loop_ctl_fd ) {
+ ::close(loop_ctl_fd);
+ }
+ if( 0 <= loop_device_fd ) {
+ ::close(loop_device_fd);
+ }
+ ::_exit(0);
+ } else if( 0 < pid ) {
+ int pid_status = 0;
+ ::pid_t child_pid = ::waitpid(pid, &pid_status, 0);
+ if( 0 > child_pid ) {
+ ERR_PRINT("wait(%d) failed: %d", pid, child_pid);
+ } else {
+ if( child_pid != pid ) {
+ WARN_PRINT("wait(%d) terminated pid %d", pid, child_pid);
+ }
+ if( !WIFEXITED(pid_status) ) {
+ goto errout;
+ }
+ loop_device_id = WEXITSTATUS(pid_status);
+ if( 0 >= loop_device_id ) {
+ goto errout;
+ }
+ --loop_device_id;
+ }
+ } else {
+ ERR_PRINT("Couldn't fork() process: res %d", pid);
goto errout;
}
+ if( 0 <= backingfile ) {
+ ::close(backingfile);
+ backingfile = -1;
+ }
return mount_ctx(mount_point, loop_device_id);
errout:
- if( 0 <= loop_ctl_fd ) {
- ::close(loop_ctl_fd);
- }
- if( 0 <= loop_device_fd ) {
- ::close(loop_device_fd);
- }
#else
(void)fs_type;
(void)mountflags;
@@ -1500,43 +1544,68 @@ bool jau::fs::umount(const mount_ctx& context)
if( !target_stats.is_dir()) {
return false;
}
- const int umount_res = ::umount(target_stats.path().c_str());
- if( 0 != umount_res ) {
- jau::fprintf_td(stderr, "umount: Error: Couldn't umount '%s': res %d, errno %d (%s)\n",
- target_stats.to_string().c_str(), umount_res, errno, ::strerror(errno));
- }
- if( 0 > context.loop_device_id ) {
- // mounted w/o loop-device, done
- return 0 == umount_res;
- }
+ const ::uid_t caller_uid = ::geteuid();
+
+ ::pid_t pid = ::fork();
+ if( 0 == pid ) {
+ if( 0 != caller_uid ) {
+ if( !set_effective_uid(0) ) {
+ ::_exit(EXIT_FAILURE);
+ }
+ }
+ const int umount_res = ::umount(target_stats.path().c_str());
+ if( 0 != umount_res ) {
+ ERR_PRINT("Couldn't umount '%s': res %d\n", target_stats.to_string().c_str(), umount_res);
+ }
+ if( 0 > context.loop_device_id ) {
+ // mounted w/o loop-device, done
+ ::_exit(0 == umount_res ? EXIT_SUCCESS : EXIT_FAILURE);
+ }
#ifdef __linux__
- int loop_device_fd = -1;
- char loopname[4096];
+ int loop_device_fd = -1;
+ char loopname[4096];
- snprintf(loopname, sizeof(loopname), "/dev/loop%d", context.loop_device_id);
- jau::fprintf_td(stderr, "umount: Info: Using loop-device '%s'\n", loopname);
+ snprintf(loopname, sizeof(loopname), "/dev/loop%d", context.loop_device_id);
+ jau::INFO_PRINT("umount: Info: Using loop-device '%s'", loopname);
- loop_device_fd = ::open64(loopname, O_RDWR);
- if( 0 > loop_device_fd ) {
- jau::fprintf_td(stderr, "umount: Error: Couldn't open loop-device '%s': res %d, errno %d (%s)\n",
- loopname, loop_device_fd, errno, ::strerror(errno));
- goto errout;
- }
- if( 0 > ::ioctl(loop_device_fd, LOOP_CLR_FD, 0) ) {
- jau::fprintf_td(stderr, "umount: Error: Couldn't deattach loop-device '%s': errno %d (%s)\n",
- loopname, errno, ::strerror(errno));
- goto errout;
- }
- ::close(loop_device_fd);
- loop_device_fd = -1;
+ loop_device_fd = ::open64(loopname, O_RDWR);
+ if( 0 > loop_device_fd ) {
+ ERR_PRINT("Couldn't open loop-device '%s': res %d", loopname, loop_device_fd);
+ goto errout_child;
+ }
+ if( 0 > ::ioctl(loop_device_fd, LOOP_CLR_FD, 0) ) {
+ ERR_PRINT("Couldn't detach loop-device '%s'", loopname);
+ goto errout_child;
+ }
+ ::close(loop_device_fd);
+ loop_device_fd = -1;
+#endif
- return 0 == umount_res;
+ ::_exit(0 == umount_res ? EXIT_SUCCESS : EXIT_FAILURE);
-errout:
- if( 0 <= loop_device_fd ) {
- ::close(loop_device_fd);
- }
+#ifdef __linux__
+errout_child:
+ if( 0 <= loop_device_fd ) {
+ ::close(loop_device_fd);
+ }
+ ::_exit(EXIT_FAILURE);
#endif
+ } else if( 0 < pid ) {
+ int pid_status = 0;
+ ::pid_t child_pid = ::waitpid(pid, &pid_status, 0);
+ if( 0 > child_pid ) {
+ ERR_PRINT("wait(%d) failed: %d", pid, child_pid);
+ } else {
+ if( child_pid != pid ) {
+ WARN_PRINT("wait(%d) terminated pid %d", pid, child_pid);
+ }
+ if( WIFEXITED(pid_status) && EXIT_SUCCESS == WEXITSTATUS(pid_status) ) {
+ return true;
+ }
+ }
+ } else {
+ ERR_PRINT("Couldn't fork() process: res %d", pid);
+ }
return false;
}