From 95c8e284d05a2ff3eb673dcd8ee6115d27fe1225 Mon Sep 17 00:00:00 2001 From: RD Projekt Date: Tue, 8 May 2018 16:24:16 +0200 Subject: Allow accessing /sys/module directory It is required for example by Blender, which Firejail supports. Blender needs read-only access to /sys/module/amdgpu in order to use AMD card with OpenCL. Now user can allow such access by specifying: noblacklist /sys/module whitelist /sys/module/amdgpu read-only /sys/module/amdgpu --- src/firejail/firejail.h | 2 ++ src/firejail/fs.c | 4 ++-- src/firejail/fs_whitelist.c | 46 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 8c0b3ba4e..efc0dfd8d 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -85,6 +85,7 @@ #define RUN_WHITELIST_SRV_DIR "/run/firejail/mnt/orig-srv" #define RUN_WHITELIST_ETC_DIR "/run/firejail/mnt/orig-etc" #define RUN_WHITELIST_SHARE_DIR "/run/firejail/mnt/orig-share" +#define RUN_WHITELIST_MODULE_DIR "/run/firejail/mnt/orig-module" #define RUN_XAUTHORITY_FILE "/run/firejail/mnt/.Xauthority" #define RUN_XAUTHORITY_SEC_FILE "/run/firejail/mnt/sec.Xauthority" @@ -204,6 +205,7 @@ typedef struct profile_entry_t { unsigned srv_dir:1; // whitelist in /srv directory unsigned etc_dir:1; // whitelist in /etc directory unsigned share_dir:1; // whitelist in /usr/share directory + unsigned module_dir:1; // whitelist in /sys/module directory }ProfileEntry; typedef struct config_t { diff --git a/src/firejail/fs.c b/src/firejail/fs.c index 88f92ad74..ea0631da5 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c @@ -565,12 +565,12 @@ void fs_proc_sys_dev_boot(void) { disable_file(BLACKLIST_FILE, "/sys/firmware"); disable_file(BLACKLIST_FILE, "/sys/hypervisor"); - { // allow user access to /sys/fs if "--noblacklist=/sys/fs" is present on the command line + { // allow user access to some directories in /sys/ by specifying 'noblacklist' option EUID_USER(); profile_add("blacklist /sys/fs"); + profile_add("blacklist /sys/module"); EUID_ROOT(); } - disable_file(BLACKLIST_FILE, "/sys/module"); disable_file(BLACKLIST_FILE, "/sys/power"); disable_file(BLACKLIST_FILE, "/sys/kernel/debug"); disable_file(BLACKLIST_FILE, "/sys/kernel/vmcoreinfo"); diff --git a/src/firejail/fs_whitelist.c b/src/firejail/fs_whitelist.c index b1b30cd5e..9ef80e5c3 100644 --- a/src/firejail/fs_whitelist.c +++ b/src/firejail/fs_whitelist.c @@ -283,6 +283,14 @@ static void whitelist_path(ProfileEntry *entry) { if (asprintf(&wfile, "%s/%s", RUN_WHITELIST_SHARE_DIR, fname) == -1) errExit("asprintf"); } + else if (entry->module_dir) { + fname = path + 12; // strlen("/sys/module/") + if (*fname == '\0') + goto errexit; + + if (asprintf(&wfile, "%s/%s", RUN_WHITELIST_MODULE_DIR, fname) == -1) + errExit("asprintf"); + } // check if the file exists assert(wfile); @@ -365,6 +373,7 @@ void fs_whitelist(void) { int srv_dir = 0; // /srv directory flag int etc_dir = 0; // /etc directory flag int share_dir = 0; // /usr/share directory flag + int module_dir = 0; // /sys/module directory flag size_t nowhitelist_c = 0; size_t nowhitelist_m = 32; @@ -471,6 +480,8 @@ void fs_whitelist(void) { etc_dir = 1; else if (strncmp(new_name, "/usr/share/", 11) == 0) share_dir = 1; + else if (strncmp(new_name, "/sys/module/", 12) == 0) + module_dir = 1; } entry->data = EMPTY_STRING; @@ -618,6 +629,13 @@ void fs_whitelist(void) { if (strncmp(fname, "/usr/share/", 11) != 0) goto errexit; } + else if (strncmp(new_name, "/sys/module/", 12) == 0) { + entry->module_dir = 1; + module_dir = 1; + // both path and absolute path are under /sys/module + if (strncmp(fname, "/sys/module/", 12) != 0) + goto errexit; + } else { goto errexit; } @@ -846,6 +864,27 @@ void fs_whitelist(void) { share_dir = 0; } + // /sys/module mountpoint + if (module_dir) { + // check if /sys/module directory exists + struct stat s; + if (stat("/sys/module", &s) == 0) { + // keep a copy of real /sys/module directory in RUN_WHITELIST_MODULE_DIR + mkdir_attr(RUN_WHITELIST_MODULE_DIR, 0755, 0, 0); + if (mount("/sys/module", RUN_WHITELIST_MODULE_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) + errExit("mount bind"); + + // mount tmpfs on /sys/module + if (arg_debug || arg_debug_whitelists) + printf("Mounting tmpfs on /sys/module directory\n"); + if (mount("tmpfs", "/sys/module", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) + errExit("mounting tmpfs on /sys/module"); + fs_logger("tmpfs /sys/module"); + } + else + module_dir = 0; + } + // go through profile rules again, and interpret whitelist commands entry = cfg.profile; @@ -967,6 +1006,13 @@ void fs_whitelist(void) { fs_logger2("tmpfs", RUN_WHITELIST_SHARE_DIR); } + // mask the real /sys/module directory, currently mounted on RUN_WHITELIST_MODULE_DIR + if (module_dir) { + if (mount("tmpfs", RUN_WHITELIST_MODULE_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) + errExit("mount tmpfs"); + fs_logger2("tmpfs", RUN_WHITELIST_MODULE_DIR); + } + if (new_name) free(new_name); -- cgit v1.2.3-54-g00ecf