From 6ee6b8c5db55ecfcc409dca6f243ec2e81371122 Mon Sep 17 00:00:00 2001 From: Sven Barth Date: Thu, 28 Mar 2024 11:58:57 +0100 Subject: [PATCH] Apply currently effective Linux capabilities to the Inheritable set and then apply all the capabilities in both the Effective and Inheritable sets to the Ambient set, so that the child process (which can be unaware of capabilities) can have its capabilities set accordingly. --- src/runtime/runtime.c | 97 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index 2fe0261..73c742a 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -61,6 +61,9 @@ extern int sqfs_opt_proc(void* data, const char* arg, int key, struct fuse_args* #include #include #include +#include +#include +#include typedef struct { uint32_t lo; @@ -1331,6 +1334,97 @@ char* appimage_hexlify(const char* bytes, const size_t numBytes) { return hexlified; } +int appimage_adjust_capabilities() +{ + struct __user_cap_header_struct hdr; + struct __user_cap_data_struct data[_LINUX_CAPABILITY_U32S_3]; + int res, datacnt; + unsigned long long capeff, capperm, capinh; + pid_t p; + + hdr.version = 0; + hdr.pid = 0; + res = syscall(SYS_capget, &hdr, NULL); + if (res) + { + if (errno != EINVAL || hdr.version == 0) + { + fprintf(stderr, "SYS_capget syscall failed with %d\n", errno); + return -1; + } + } + else if (hdr.version == 0) + { + fprintf(stderr, "Failed to query capability version\n"); + return -1; + } + + //fprintf(stderr, "Linux capability version: %x\n", hdr.version); + + switch (hdr.version) + { + case _LINUX_CAPABILITY_VERSION_1: + datacnt = _LINUX_CAPABILITY_U32S_1; + break; + case _LINUX_CAPABILITY_VERSION_2: + datacnt = _LINUX_CAPABILITY_U32S_2; + break; + case _LINUX_CAPABILITY_VERSION_3: + datacnt = _LINUX_CAPABILITY_U32S_3; + break; + default: + fprintf(stderr, "Unknown Linux capability version: %x; forcing version 3\n", hdr.version); + datacnt = _LINUX_CAPABILITY_U32S_3; + hdr.version = _LINUX_CAPABILITY_VERSION_3; + } + + res = syscall(SYS_capget, &hdr, &data); + if (res) + { + fprintf(stderr, "Failed to query capabilities; error: %d\n", errno); + return -1; + } + + //for (int i = 0; i < datacnt; ++i) + //{ + // fprintf(stderr, "Set %d: eff = %08x, perm = %08x, inh = %08x\n", i, data[i].effective, data[i].permitted, data[i].inheritable); + //} + + for (int i = 0; i < datacnt; ++i) + { + data[i].inheritable |= data[i].permitted; + } + + res = syscall(SYS_capset, &hdr, &data); + if (res) + { + fprintf(stderr, "Failed to set capabilities; error: %d\n", errno); + return -1; + } + + /* now we can set up the ambient set */ + for (int i = 0; i < datacnt; ++i) + { + for (int j = 0; j < 32; ++j) + { + int capval = i * 32 + j; + int capbit = 1 << j; + + if ((data[i].permitted & capbit) && (data[i].inheritable & capbit)) + { + res = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, capval, 0, 0); + if (res) + { + fprintf(stderr, "Failed to set ambient capability %d; error: %d\n", capval, errno); + return 1; + } + } + } + } + + return 0; +} + int main(int argc, char* argv[]) { char appimage_path[PATH_MAX]; char argv0_path[PATH_MAX]; @@ -1704,6 +1798,9 @@ int main(int argc, char* argv[]) { setenv("XDG_CONFIG_HOME", portable_config_dir, 1); } + /* Ensure that capabilities for the AppImage are applied to the children */ + appimage_adjust_capabilities(); + /* Original working directory */ char cwd[1024]; if (getcwd(cwd, sizeof(cwd)) != NULL) {