From fd79cb3be6aa2e62d5a7ec45eee39dcd07a9d4f3 Mon Sep 17 00:00:00 2001 From: Glenn Washburn Date: Tue, 9 Oct 2018 04:39:22 -0500 Subject: rename expand_home -> expand_macros to better reflect usage and remove unneeded homedir argument. --- src/firejail/firejail.h | 2 +- src/firejail/fs.c | 6 ++---- src/firejail/fs_home.c | 4 ++-- src/firejail/fs_hostname.c | 2 +- src/firejail/fs_mkdir.c | 4 ++-- src/firejail/fs_whitelist.c | 2 +- src/firejail/macros.c | 7 +++---- src/firejail/main.c | 3 ++- src/firejail/profile.c | 2 +- 9 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 441042233..85a4fbddb 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -496,7 +496,7 @@ int arp_check(const char *dev, uint32_t destaddr); uint32_t arp_assign(const char *dev, Bridge *br); // macros.c -char *expand_home(const char *path, const char *homedir); +char *expand_macros(const char *path); char *resolve_macro(const char *name); void invalid_filename(const char *fname, int globbing); int is_macro(const char *name); diff --git a/src/firejail/fs.c b/src/firejail/fs.c index 9f0dac4e0..f70c5ac8a 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c @@ -257,8 +257,6 @@ static void globbing(OPERATION op, const char *pattern, const char *noblacklist[ // blacklist files or directories by mounting empty files on top of them void fs_blacklist(void) { - char *homedir = cfg.homedir; - assert(homedir); ProfileEntry *entry = cfg.profile; if (!entry) return; @@ -335,7 +333,7 @@ void fs_blacklist(void) { enames = calloc(2, sizeof(char *)); if (!enames) errExit("calloc"); - enames[0] = expand_home(entry->data + 12, homedir); + enames[0] = expand_macros(entry->data + 12); assert(enames[1] == 0); } @@ -401,7 +399,7 @@ void fs_blacklist(void) { } // replace home macro in blacklist array - char *new_name = expand_home(ptr, homedir); + char *new_name = expand_macros(ptr); ptr = new_name; // expand path macro - look for the file in /usr/local/bin, /usr/local/sbin, /bin, /usr/bin, /sbin and /usr/sbin directories diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index 42c67452c..47261d7c1 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c @@ -355,7 +355,7 @@ void fs_check_private_dir(void) { invalid_filename(cfg.home_private, 0); // no globbing // Expand the home directory - char *tmp = expand_home(cfg.home_private, cfg.homedir); + char *tmp = expand_macros(cfg.home_private); cfg.home_private = realpath(tmp, NULL); free(tmp); @@ -378,7 +378,7 @@ static char *check_dir_or_file(const char *name) { printf("Private home: checking %s\n", name); // expand home directory - char *fname = expand_home(name, cfg.homedir); + char *fname = expand_macros(name); assert(fname); // If it doesn't start with '/', it must be relative to homedir diff --git a/src/firejail/fs_hostname.c b/src/firejail/fs_hostname.c index 1884f6597..1fbb073f4 100644 --- a/src/firejail/fs_hostname.c +++ b/src/firejail/fs_hostname.c @@ -189,7 +189,7 @@ void fs_resolvconf(void) { char *fs_check_hosts_file(const char *fname) { assert(fname); invalid_filename(fname, 0); // no globbing - char *rv = expand_home(fname, cfg.homedir); + char *rv = expand_macros(fname); // no a link if (is_link(rv)) diff --git a/src/firejail/fs_mkdir.c b/src/firejail/fs_mkdir.c index b66068a95..913f7502d 100644 --- a/src/firejail/fs_mkdir.c +++ b/src/firejail/fs_mkdir.c @@ -60,7 +60,7 @@ void fs_mkdir(const char *name) { // check directory name invalid_filename(name, 0); // no globbing - char *expanded = expand_home(name, cfg.homedir); + char *expanded = expand_macros(name); if (strncmp(expanded, cfg.homedir, strlen(cfg.homedir)) != 0 && strncmp(expanded, "/tmp", 4) != 0) { fprintf(stderr, "Error: only directories in user home or /tmp are supported by mkdir\n"); @@ -100,7 +100,7 @@ void fs_mkfile(const char *name) { // check file name invalid_filename(name, 0); // no globbing - char *expanded = expand_home(name, cfg.homedir); + char *expanded = expand_macros(name); if (strncmp(expanded, cfg.homedir, strlen(cfg.homedir)) != 0 && strncmp(expanded, "/tmp", 4) != 0) { fprintf(stderr, "Error: only files in user home or /tmp are supported by mkfile\n"); diff --git a/src/firejail/fs_whitelist.c b/src/firejail/fs_whitelist.c index 454715a71..8ef948239 100644 --- a/src/firejail/fs_whitelist.c +++ b/src/firejail/fs_whitelist.c @@ -368,7 +368,7 @@ void fs_whitelist(void) { char *dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; // replace ~/ or ${HOME} into /home/username or resolve macro - new_name = expand_home(dataptr, cfg.homedir); + new_name = expand_macros(dataptr); assert(new_name); // mount empty home directory if resolving the macro was not successful diff --git a/src/firejail/macros.c b/src/firejail/macros.c index 4bf3d3589..59b5db3d8 100644 --- a/src/firejail/macros.c +++ b/src/firejail/macros.c @@ -192,9 +192,8 @@ char *resolve_macro(const char *name) { // directory (supplied). // The return value is allocated using malloc and must be freed by the caller. // The function returns NULL if there are any errors. -char *expand_home(const char *path, const char *homedir) { +char *expand_macros(const char *path) { assert(path); - assert(homedir); int called_as_root = 0; @@ -210,14 +209,14 @@ char *expand_home(const char *path, const char *homedir) { // Replace home macro char *new_name = NULL; if (strncmp(path, "${HOME}", 7) == 0) { - if (asprintf(&new_name, "%s%s", homedir, path + 7) == -1) + if (asprintf(&new_name, "%s%s", cfg.homedir, path + 7) == -1) errExit("asprintf"); if(called_as_root) EUID_ROOT(); return new_name; } else if (*path == '~') { - if (asprintf(&new_name, "%s%s", homedir, path + 1) == -1) + if (asprintf(&new_name, "%s%s", cfg.homedir, path + 1) == -1) errExit("asprintf"); if(called_as_root) EUID_ROOT(); diff --git a/src/firejail/main.c b/src/firejail/main.c index 315a7260a..e0a149085 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c @@ -868,6 +868,7 @@ int main(int argc, char **argv) { // check if the user is allowed to use firejail init_cfg(argc, argv); + assert(cfg.homedir); // get starting timestamp, process --quiet start_timestamp = getticks(); @@ -1480,7 +1481,7 @@ int main(int argc, char **argv) { exit(1); } - char *ppath = expand_home(argv[i] + 10, cfg.homedir); + char *ppath = expand_macros(argv[i] + 10); if (!ppath) errExit("strdup"); diff --git a/src/firejail/profile.c b/src/firejail/profile.c index db58d2e0b..f70c0c9d1 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c @@ -1327,7 +1327,7 @@ void profile_read(const char *fname) { char *newprofile = ptr + 8; // profile name // expand ${HOME}/ in front of the new profile file - char *newprofile2 = expand_home(newprofile, cfg.homedir); + char *newprofile2 = expand_macros(newprofile); // recursivity profile_read((newprofile2)? newprofile2:newprofile); -- cgit v1.2.3-54-g00ecf From ffd51a5c78549839465085ab6480bd5b6642d637 Mon Sep 17 00:00:00 2001 From: Glenn Washburn Date: Tue, 9 Oct 2018 05:41:17 -0500 Subject: Allow specifying a profile "name" with the profile option (eg. --profile=firefox). --- src/firejail/firejail.h | 3 ++- src/firejail/main.c | 57 ++++++++++++++++++++++++++----------------------- src/firejail/profile.c | 33 ++++++++++++++++++++++------ 3 files changed, 58 insertions(+), 35 deletions(-) diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 85a4fbddb..8145c1bb5 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -458,7 +458,8 @@ void fs_mnt(const int enforce); // profile.c // find and read the profile specified by name from dir directory -int profile_find(const char *name, const char *dir); +int profile_find(const char *name, const char *dir, int add_ext); +int profile_find_firejail(const char *name, int add_ext); // read a profile file void profile_read(const char *fname); // check profile line; if line == 0, this was generated from a command line option diff --git a/src/firejail/main.c b/src/firejail/main.c index e0a149085..680ce5800 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c @@ -1485,8 +1485,33 @@ int main(int argc, char **argv) { if (!ppath) errExit("strdup"); - profile_read(ppath); - custom_profile = 1; + if (access(ppath, R_OK)) { + char *ptr = ppath; + while (*ptr != '/' && *ptr != '.' && *ptr != '\0') + ptr++; + // profile path contains no / or . chars, + // assume its a profile name + if (*ptr != '\0') { + fprintf(stderr, "Error: inaccessible profile file: %s\n", ppath); + exit(1); + } + + // profile was not read in previously, try to see if + // we were given a profile name. + if (!profile_find_firejail(ppath, 1)) { + // do not fall through to default profile, + // because the user should be notified that + // given profile arg could not be used. + fprintf(stderr, "Error: no profile with name \"%s\" found.\n", ppath); + exit(1); + } + else + custom_profile = 1; + } + else { + profile_read(ppath); + custom_profile = 1; + } free(ppath); } else if (strcmp(argv[i], "--noprofile") == 0) { @@ -2327,21 +2352,8 @@ int main(int argc, char **argv) { // load the profile - if (!arg_noprofile) { - if (!custom_profile) { - // look for a profile in ~/.config/firejail directory - char *usercfgdir; - if (asprintf(&usercfgdir, "%s/.config/firejail", cfg.homedir) == -1) - errExit("asprintf"); - int rv = profile_find(cfg.command_name, usercfgdir); - free(usercfgdir); - custom_profile = rv; - } - if (!custom_profile) { - // look for a user profile in /etc/firejail directory - int rv = profile_find(cfg.command_name, SYSCONFDIR); - custom_profile = rv; - } + if (!arg_noprofile && !custom_profile) { + custom_profile = profile_find_firejail(cfg.command_name, 1); } // use default.profile as the default @@ -2352,16 +2364,7 @@ int main(int argc, char **argv) { if (arg_debug) printf("Attempting to find %s.profile...\n", profile_name); - // look for the profile in ~/.config/firejail directory - char *usercfgdir; - if (asprintf(&usercfgdir, "%s/.config/firejail", cfg.homedir) == -1) - errExit("asprintf"); - custom_profile = profile_find(profile_name, usercfgdir); - free(usercfgdir); - - if (!custom_profile) - // look for the profile in /etc/firejail directory - custom_profile = profile_find(profile_name, SYSCONFDIR); + custom_profile = profile_find_firejail(profile_name, 1); if (!custom_profile) { fprintf(stderr, "Error: no default.profile installed\n"); diff --git a/src/firejail/profile.c b/src/firejail/profile.c index f70c0c9d1..4fc710f39 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c @@ -25,26 +25,29 @@ extern char *xephyr_screen; #define MAX_READ 8192 // line buffer for profile files // find and read the profile specified by name from dir directory -int profile_find(const char *name, const char *dir) { +int profile_find(const char *name, const char *dir, int add_ext) { EUID_ASSERT(); assert(name); assert(dir); int rv = 0; DIR *dp; - char *pname; - if (asprintf(&pname, "%s.profile", name) == -1) - errExit("asprintf"); + char *pname = NULL; + if (add_ext) + if (asprintf(&pname, "%s.profile", name) == -1) + errExit("asprintf"); + else + name = pname; dp = opendir (dir); if (dp != NULL) { struct dirent *ep; while ((ep = readdir(dp)) != NULL) { - if (strcmp(ep->d_name, pname) == 0) { + if (strcmp(ep->d_name, name) == 0) { if (arg_debug) printf("Found %s profile in %s directory\n", name, dir); char *etcpname; - if (asprintf(&etcpname, "%s/%s", dir, pname) == -1) + if (asprintf(&etcpname, "%s/%s", dir, name) == -1) errExit("asprintf"); profile_read(etcpname); free(etcpname); @@ -55,10 +58,26 @@ int profile_find(const char *name, const char *dir) { (void) closedir (dp); } - free(pname); + if (pname) + free(pname); return rv; } +// search and read the profile specified by name from firejail directories +int profile_find_firejail(const char *name, int add_ext) { + // look for a profile in ~/.config/firejail directory + char *usercfgdir; + if (asprintf(&usercfgdir, "%s/.config/firejail", cfg.homedir) == -1) + errExit("asprintf"); + int rv = profile_find(name, usercfgdir, add_ext); + free(usercfgdir); + + if (!rv) + // look for a user profile in /etc/firejail directory + rv = profile_find(name, SYSCONFDIR, add_ext); + + return rv; +} //*************************************************** // run-time profiles -- cgit v1.2.3-54-g00ecf From eb42779f95a51aa00ffef62510a00dc5e7716b0d Mon Sep 17 00:00:00 2001 From: Glenn Washburn Date: Wed, 10 Oct 2018 01:08:43 -0500 Subject: Update man pages and usage to reflect --profile enhancement. --- src/firejail/usage.c | 2 +- src/man/firejail-profile.txt | 13 ++++++++++++- src/man/firejail.txt | 13 +++++++++++-- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/firejail/usage.c b/src/firejail/usage.c index f54e6f744..b8f8b4f2f 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c @@ -164,7 +164,7 @@ static char *usage_str = " --private-tmp - mount a tmpfs on top of /tmp directory.\n" " --private-opt=file,directory - build a new /opt in a temporary filesystem.\n" " --private-srv=file,directory - build a new /srv in a temporary filesystem.\n" - " --profile=filename - use a custom profile.\n" + " --profile=filename|profile_name - use a custom profile.\n" " --profile.print=name|pid - print the name of profile file.\n" " --profile-path=directory - use this directory to look for profile files.\n" " --protocol=protocol,protocol,protocol - enable protocol filter.\n" diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt index 17562c503..5daca8abd 100644 --- a/src/man/firejail-profile.txt +++ b/src/man/firejail-profile.txt @@ -5,12 +5,14 @@ profile \- Security profile file syntax for Firejail .SH USAGE .TP firejail \-\-profile=filename.profile +.RE +firejail \-\-profile=profile_name .SH DESCRIPTION Several command line options can be passed to the program using profile files. Firejail chooses the profile file as follows: -\fB1.\fR If a profile file is provided by the user with \-\-profile option, the profile file is loaded. +\fB1.\fR If a profile file is provided by the user with \-\-profile option, the profile file is loaded. If a profile name is given, it is searched for first in the ~/.config/firejail directory and if not found then in /etc/firejail directory. Profile names do not include the .profile suffix. Example: .PP .RS @@ -21,6 +23,15 @@ Reading profile /home/netblue/icecat.profile [...] .RE +.PP +.RS +$ firejail --profile=icecat icecat-wrapper.sh +.br +Reading profile /home/netblue/icecat.profile +.br +[...] +.RE + \fB2.\fR If a profile file with the same name as the application is present in ~/.config/firejail directory or in /etc/firejail, the profile is loaded. ~/.config/firejail takes precedence over /etc/firejail. Example: .PP diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 7427b1009..5a374ac55 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt @@ -1531,7 +1531,7 @@ drwxrwxrwt 2 nobody nogroup 4096 Apr 30 10:52 .X11-unix .TP -\fB\-\-profile=filename +\fB\-\-profile=filename_or_profilename Load a custom security profile from filename. For filename use an absolute path or a path relative to the current path. For more information, see \fBSECURITY PROFILES\fR section below. .br @@ -2701,7 +2701,7 @@ The owner of the sandbox. Several command line options can be passed to the program using profile files. Firejail chooses the profile file as follows: -1. If a profile file is provided by the user with --profile option, the profile file is loaded. +1. If a profile file is provided by the user with --profile option, the profile file is loaded. If a profile name is given, it is searched for first in the ~/.config/firejail directory and if not found then in /etc/firejail directory. Profile names do not include the .profile suffix. Example: .PP .RS @@ -2712,6 +2712,15 @@ Reading profile /home/netblue/icecat.profile [...] .RE +.PP +.RS +$ firejail --profile=icecat icecat-wrapper.sh +.br +Reading profile /home/netblue/icecat.profile +.br +[...] +.RE + 2. If a profile file with the same name as the application is present in ~/.config/firejail directory or in /etc/firejail, the profile is loaded. ~/.config/firejail takes precedence over /etc/firejail. Example: .PP -- cgit v1.2.3-54-g00ecf