From ac9283365224ed46ab2087c050ae1e2916a0dbf5 Mon Sep 17 00:00:00 2001 From: netblue30 Date: Mon, 4 Jun 2018 15:45:56 -0400 Subject: evaluate UID_MIN/GID_MID at runtime, remove compile time evaluation - fixes #1964 --- src/firejail/restrict_users.c | 14 +++++---- src/include/firejail_user.h | 2 ++ src/lib/firejail_user.c | 66 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 75 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/firejail/restrict_users.c b/src/firejail/restrict_users.c index 982dba5ac..d66deeb97 100644 --- a/src/firejail/restrict_users.c +++ b/src/firejail/restrict_users.c @@ -18,6 +18,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "firejail.h" +#include "../include/firejail_user.h" #include #include #include @@ -26,7 +27,6 @@ #include #include #include -#include "../../uids.h" #define MAXBUF 1024 @@ -115,8 +115,9 @@ static void sanitize_passwd(void) { struct stat s; if (stat("/etc/passwd", &s) == -1) return; + assert(uid_min); if (arg_debug) - printf("Sanitizing /etc/passwd, UID_MIN %d\n", UID_MIN); + printf("Sanitizing /etc/passwd, UID_MIN %d\n", uid_min); if (is_link("/etc/passwd")) { fprintf(stderr, "Error: invalid /etc/passwd\n"); exit(1); @@ -167,7 +168,8 @@ static void sanitize_passwd(void) { int rv = sscanf(ptr, "%d:", &uid); if (rv == 0 || uid < 0) goto errout; - if (uid < UID_MIN || uid == 65534) { // on Debian platforms user nobody is 65534 + assert(uid_min); + if (uid < uid_min || uid == 65534) { // on Debian platforms user nobody is 65534 fprintf(fpout, "%s", buf); continue; } @@ -248,8 +250,9 @@ static void sanitize_group(void) { struct stat s; if (stat("/etc/group", &s) == -1) return; + assert(gid_min); if (arg_debug) - printf("Sanitizing /etc/group, GID_MIN %d\n", GID_MIN); + printf("Sanitizing /etc/group, GID_MIN %d\n", gid_min); if (is_link("/etc/group")) { fprintf(stderr, "Error: invalid /etc/group\n"); exit(1); @@ -299,7 +302,8 @@ static void sanitize_group(void) { int rv = sscanf(ptr, "%d:", &gid); if (rv == 0 || gid < 0) goto errout; - if (gid < GID_MIN || gid == 65534) { // on Debian platforms 65534 is group nogroup + assert(gid_min); + if (gid < gid_min || gid == 65534) { // on Debian platforms 65534 is group nogroup if (copy_line(fpout, buf, ptr)) goto errout; continue; diff --git a/src/include/firejail_user.h b/src/include/firejail_user.h index a7d30225e..66e618fbe 100644 --- a/src/include/firejail_user.h +++ b/src/include/firejail_user.h @@ -20,6 +20,8 @@ #ifndef FIREJAIL_USER_H #define FIREJAIL_USER_H +extern int uid_min; +extern int gid_min; // returns 1 if the user is found in the database or if the database was not created int firejail_user_check(const char *name); diff --git a/src/lib/firejail_user.c b/src/lib/firejail_user.c index 0cc0ac6c1..c7af14254 100644 --- a/src/lib/firejail_user.c +++ b/src/lib/firejail_user.c @@ -26,11 +26,70 @@ // One username per line in the file #include "../include/common.h" +#include "../include/firejail_user.h" #include #include -#include "../../uids.h" #define MAXBUF 4098 + +// minimum values for uid and gid extracted from /etc/login.defs +int uid_min = 0; +int gid_min = 0; + +static void init_uid_gid_min(void) { + if (uid_min != 0 && gid_min != 0) + return; + + // read the real values from login.def + FILE *fp = fopen("/etc/login.defs", "r"); + if (!fp) + goto errexit; + + char buf[MAXBUF]; + while (fgets(buf, MAXBUF, fp)) { + // comments + if (*buf == '#') + continue; + // skip empty space + char *ptr = buf; + while (*ptr == ' ' || *ptr == '\t') + ptr++; + + if (strncmp(ptr, "UID_MIN", 7) == 0) { + int rv = sscanf(ptr + 7, "%d", &uid_min); + if (rv != 1 || uid_min < 0) { + fclose(fp); + goto errexit; + } + } + else if (strncmp(ptr, "GID_MIN", 7) == 0) { + int rv = sscanf(ptr + 7, "%d", &gid_min); + if (rv != 1 || gid_min < 0) { + fclose(fp); + goto errexit; + } + } + + if (uid_min != 0 && gid_min != 0) + break; + + } + fclose(fp); + + if (uid_min == 0 || gid_min == 0) + goto errexit; +//printf("uid_min %d, gid_min %d\n", uid_min, gid_min); + + return; + +errexit: + fprintf(stderr, "Error: cannot read UID_MIN and/or GID_MIN from /etc/login.defs, using 1000 by default\n"); + uid_min = 1000; + gid_min = 1000; +} + + + static inline char *get_fname(void) { char *fname; if (asprintf(&fname, "%s/firejail.users", SYSCONFDIR) == -1) @@ -38,9 +97,11 @@ static inline char *get_fname(void) { return fname; } + // returns 1 if the user is found in the database or if the database was not created int firejail_user_check(const char *name) { assert(name); + init_uid_gid_min(); // root is allowed to run firejail by default if (strcmp(name, "root") == 0) @@ -48,7 +109,8 @@ int firejail_user_check(const char *name) { // other system users will run the program as is uid_t uid = getuid(); - if ((uid < UID_MIN && uid != 0) || strcmp(name, "nobody") == 0) + assert(uid_min > 0); + if (((int) uid < uid_min && uid != 0) || strcmp(name, "nobody") == 0) return 0; // check file existence -- cgit v1.2.3-54-g00ecf