mirror of
https://github.com/netblue30/firejail.git
synced 2026-05-21 06:45:29 -06:00
whitelist support for /tmp
This commit is contained in:
parent
14c94f18cc
commit
da90151010
5 changed files with 146 additions and 58 deletions
|
|
@ -8,6 +8,7 @@ blacklist /usr/bin/c9*
|
|||
blacklist /usr/bin/c8*
|
||||
blacklist /usr/bin/c++*
|
||||
blacklist /usr/bin/ld
|
||||
blacklist /usr/bin/gdb
|
||||
|
||||
# Valgrind
|
||||
blacklist /usr/bin/valgrind*
|
||||
|
|
|
|||
|
|
@ -9,3 +9,4 @@ blacklist ${HOME}/.gnupg
|
|||
blacklist ${HOME}/.local/share/recently-used.xbel
|
||||
blacklist ${HOME}/*.kdb
|
||||
blacklist ${HOME}/*.key
|
||||
blacklist /etc/shadow
|
||||
|
|
|
|||
|
|
@ -39,7 +39,8 @@
|
|||
#define DRI_DIR "/run/firejail/mnt/dri"
|
||||
#define PULSE_DIR "/run/firejail/mnt/pulse"
|
||||
#define DEVLOG_FILE "/run/firejail/mnt/devlog"
|
||||
#define WHITELIST_HOME_DIR "/run/firejail/mnt/whome"
|
||||
#define WHITELIST_HOME_DIR "/run/firejail/mnt/orig-home"
|
||||
#define WHITELIST_TMP_DIR "/run/firejail/mnt/orig-tmp"
|
||||
#define XAUTHORITY_FILE "/run/firejail/mnt/.Xauthority"
|
||||
#define HOSTNAME_FILE "/run/firejail/mnt/hostname"
|
||||
#define RESOLVCONF_FILE "/run/firejail/mnt/resolv.conf"
|
||||
|
|
@ -86,8 +87,12 @@ typedef struct interface_t {
|
|||
|
||||
typedef struct profile_entry_t {
|
||||
struct profile_entry_t *next;
|
||||
char *data; // expanded name of the file
|
||||
char *data; // command
|
||||
|
||||
// whitelist command parameters
|
||||
char *link; // link name - set if the file is a link
|
||||
unsigned home_dir:1; // whitelist in /home/user directory
|
||||
unsigned tmp_dir:1; // whitelist in /tmp directory
|
||||
}ProfileEntry;
|
||||
|
||||
typedef struct config_t {
|
||||
|
|
|
|||
|
|
@ -56,26 +56,40 @@ static int mkpath(const char* path, mode_t mode) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void whitelist_path(const char *path) {
|
||||
static void whitelist_path(ProfileEntry *entry) {
|
||||
assert(entry);
|
||||
char *path = entry->data + 10;
|
||||
assert(path);
|
||||
|
||||
// fname needs to start with /home/username
|
||||
if (strncmp(path, cfg.homedir, strlen(cfg.homedir))) {
|
||||
fprintf(stderr, "Error: file %s is not in user home directory, exiting...\n", path);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const char *fname = path + strlen(cfg.homedir);
|
||||
if (*fname == '\0') {
|
||||
fprintf(stderr, "Error: file %s is not in user home directory, exiting...\n", path);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const char *fname;
|
||||
char *wfile;
|
||||
if (asprintf(&wfile, "%s/%s", WHITELIST_HOME_DIR, fname) == -1)
|
||||
errExit("asprintf");
|
||||
|
||||
if (entry->home_dir) {
|
||||
printf("here %d\n", __LINE__);
|
||||
fname = path + strlen(cfg.homedir);
|
||||
if (*fname == '\0') {
|
||||
fprintf(stderr, "Error: file %s is not in user home directory, exiting...\n", path);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (asprintf(&wfile, "%s/%s", WHITELIST_HOME_DIR, fname) == -1)
|
||||
errExit("asprintf");
|
||||
}
|
||||
else if (entry->tmp_dir) {
|
||||
printf("here %d\n", __LINE__);
|
||||
fname = path + 4; // strlen("/tmp")
|
||||
if (*fname == '\0') {
|
||||
fprintf(stderr, "Error: file %s is not in /tmp directory, exiting...\n", path);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (asprintf(&wfile, "%s/%s", WHITELIST_TMP_DIR, fname) == -1)
|
||||
errExit("asprintf");
|
||||
}
|
||||
|
||||
// check if the file exists
|
||||
printf("here %d %s\n", __LINE__, wfile);
|
||||
system("ls -l /run/firejail/mnt/orig-tmp");
|
||||
|
||||
struct stat s;
|
||||
if (stat(wfile, &s) == 0) {
|
||||
if (arg_debug)
|
||||
|
|
@ -132,9 +146,12 @@ void fs_whitelist(void) {
|
|||
ProfileEntry *entry = cfg.profile;
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
// realpath function will fail with ENOENT if the file is not found
|
||||
// we need to expand the path before installing a new, empty home directory
|
||||
|
||||
char *new_name = NULL;
|
||||
int home_dir = 0; // /home/user directory flag
|
||||
int tmp_dir = 0; // /tmp directory flag
|
||||
|
||||
// verify whitelist files, extract symbolic links, etc.
|
||||
while (entry) {
|
||||
// handle only whitelist commands
|
||||
if (strncmp(entry->data, "whitelist ", 10)) {
|
||||
|
|
@ -142,10 +159,42 @@ void fs_whitelist(void) {
|
|||
continue;
|
||||
}
|
||||
|
||||
char *new_name = expand_home(entry->data + 10, cfg.homedir);
|
||||
|
||||
// replace ~/ or ${HOME} into /home/username
|
||||
new_name = expand_home(entry->data + 10, cfg.homedir);
|
||||
assert(new_name);
|
||||
|
||||
// extract the absolute path of the file
|
||||
// realpath function will fail with ENOENT if the file is not found
|
||||
char *fname = realpath(new_name, NULL);
|
||||
if (!fname) {
|
||||
// file not found, blank the entry in the list and continue
|
||||
if (arg_debug)
|
||||
printf("Removed whitelist path: %s\n", entry->data);
|
||||
*entry->data = '\0';
|
||||
continue;
|
||||
}
|
||||
|
||||
// valid path referenced to filesystem root
|
||||
if (*new_name != '/')
|
||||
goto errexit;
|
||||
|
||||
// check for home directory or tmp directory
|
||||
if (strncmp(new_name, cfg.homedir, strlen(cfg.homedir)) == 0) {
|
||||
entry->home_dir = 1;
|
||||
home_dir = 1;
|
||||
// both path and absolute path are under /home
|
||||
if (strncmp(fname, cfg.homedir, strlen(cfg.homedir)) != 0)
|
||||
goto errexit;
|
||||
}
|
||||
else if (strncmp(new_name, "/tmp/", 5) == 0) {
|
||||
entry->tmp_dir = 1;
|
||||
tmp_dir = 1;
|
||||
// both path and absolute path are under /tmp
|
||||
if (strncmp(fname, "/tmp/", 5) != 0)
|
||||
goto errexit;
|
||||
}
|
||||
else
|
||||
goto errexit;
|
||||
|
||||
// mark symbolic links
|
||||
if (is_link(new_name))
|
||||
|
|
@ -153,44 +202,60 @@ void fs_whitelist(void) {
|
|||
else
|
||||
free(new_name);
|
||||
|
||||
if (fname) {
|
||||
// change file name in entry->data
|
||||
if (strcmp(fname, entry->data + 10) != 0) {
|
||||
char *newdata;
|
||||
if (asprintf(&newdata, "whitelist %s", fname) == -1)
|
||||
errExit("asprintf");
|
||||
entry->data = newdata;
|
||||
if (arg_debug)
|
||||
printf("Replaced whitelist path: %s\n", entry->data);
|
||||
}
|
||||
|
||||
free(fname);
|
||||
}
|
||||
else {
|
||||
// file not found, blank the entry in the list
|
||||
// change file name in entry->data
|
||||
if (strcmp(fname, entry->data + 10) != 0) {
|
||||
char *newdata;
|
||||
if (asprintf(&newdata, "whitelist %s", fname) == -1)
|
||||
errExit("asprintf");
|
||||
entry->data = newdata;
|
||||
if (arg_debug)
|
||||
printf("Removed whitelist path: %s\n", entry->data);
|
||||
*entry->data = '\0';
|
||||
printf("Replaced whitelist path: %s\n", entry->data);
|
||||
}
|
||||
free(fname);
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
// create /tmp/firejail/mnt/whome directory
|
||||
// create mount points
|
||||
fs_build_mnt_dir();
|
||||
int rv = mkdir(WHITELIST_HOME_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
if (rv == -1)
|
||||
errExit("mkdir");
|
||||
if (chown(WHITELIST_HOME_DIR, getuid(), getgid()) < 0)
|
||||
errExit("chown");
|
||||
if (chmod(WHITELIST_HOME_DIR, 0755) < 0)
|
||||
errExit("chmod");
|
||||
|
||||
// keep a copy of real home dir in /tmp/firejail/mnt/whome
|
||||
if (mount(cfg.homedir, WHITELIST_HOME_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
|
||||
errExit("mount bind");
|
||||
|
||||
// start building the new home directory by mounting a tmpfs fielsystem
|
||||
fs_private();
|
||||
// /home/user
|
||||
if (home_dir) {
|
||||
// keep a copy of real home dir in WHITELIST_HOME_DIR
|
||||
int rv = mkdir(WHITELIST_HOME_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
if (rv == -1)
|
||||
errExit("mkdir");
|
||||
if (chown(WHITELIST_HOME_DIR, getuid(), getgid()) < 0)
|
||||
errExit("chown");
|
||||
if (chmod(WHITELIST_HOME_DIR, 0755) < 0)
|
||||
errExit("chmod");
|
||||
|
||||
if (mount(cfg.homedir, WHITELIST_HOME_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
|
||||
errExit("mount bind");
|
||||
|
||||
// mount a tmpfs and initialize /home/user
|
||||
fs_private();
|
||||
}
|
||||
|
||||
// /tmp mountpoint
|
||||
if (tmp_dir) {
|
||||
// keep a copy of real /tmp directory in WHITELIST_TMP_DIR
|
||||
int rv = mkdir(WHITELIST_TMP_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
if (rv == -1)
|
||||
errExit("mkdir");
|
||||
if (chown(WHITELIST_TMP_DIR, 0, 0) < 0)
|
||||
errExit("chown");
|
||||
if (chmod(WHITELIST_TMP_DIR, 0777) < 0)
|
||||
errExit("chmod");
|
||||
|
||||
if (mount("/tmp", WHITELIST_TMP_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
|
||||
errExit("mount bind");
|
||||
|
||||
// mount tmpfs on /tmp
|
||||
if (arg_debug)
|
||||
printf("Mounting tmpfs on /tmp directory\n");
|
||||
if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0)
|
||||
errExit("mounting tmpfs on /tmpt");
|
||||
}
|
||||
|
||||
// go through profile rules again, and interpret whitelist commands
|
||||
entry = cfg.profile;
|
||||
|
|
@ -201,8 +266,9 @@ void fs_whitelist(void) {
|
|||
continue;
|
||||
}
|
||||
|
||||
//printf("here %d#%s#\n", __LINE__, entry->data);
|
||||
// whitelist the real file
|
||||
whitelist_path(entry->data + 10);
|
||||
whitelist_path(entry);
|
||||
|
||||
// create the link if any
|
||||
if (entry->link) {
|
||||
|
|
@ -220,7 +286,21 @@ void fs_whitelist(void) {
|
|||
entry = entry->next;
|
||||
}
|
||||
|
||||
// mask the real home directory, currently mounted on /tmp/firejail/mnt/whome
|
||||
if (mount("tmpfs", WHITELIST_HOME_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
|
||||
errExit("mount tmpfs");
|
||||
// mask the real home directory, currently mounted on WHITELIST_HOME_DIR
|
||||
if (home_dir) {
|
||||
if (mount("tmpfs", WHITELIST_HOME_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
|
||||
errExit("mount tmpfs");
|
||||
}
|
||||
|
||||
// mask the real /tmp directory, currently mounted on WHITELIST_TMP_DIR
|
||||
if (tmp_dir) {
|
||||
if (mount("tmpfs", WHITELIST_TMP_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
|
||||
errExit("mount tmpfs");
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
errexit:
|
||||
fprintf(stderr, "Error: invalid whitelist path %s\n", new_name);
|
||||
exit(1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -398,6 +398,7 @@ void profile_add(char *str) {
|
|||
ProfileEntry *prf = malloc(sizeof(ProfileEntry));
|
||||
if (!prf)
|
||||
errExit("malloc");
|
||||
memset(prf, 0, sizeof(ProfileEntry));
|
||||
prf->next = NULL;
|
||||
prf->data = str;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue