From efabf8478a426f8f468beea3cfe18e73a849be47 Mon Sep 17 00:00:00 2001 From: netblue30 Date: Thu, 18 Feb 2016 20:14:09 -0500 Subject: euid switching --- src/firejail/firejail.h | 2 ++ src/firejail/join.c | 2 +- src/firejail/list.c | 12 ++++++++---- src/firejail/main.c | 35 +++++++++++++++++++++++++++++++--- src/include/euid_common.h | 48 +++++++++++++++++++++++++++++++++++++++++++++++ src/lib/common.c | 1 + 6 files changed, 92 insertions(+), 8 deletions(-) create mode 100644 src/include/euid_common.h (limited to 'src') diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 2662cc1d7..577c1a9ae 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -20,6 +20,8 @@ #ifndef FIREJAIL_H #define FIREJAIL_H #include "../include/common.h" +#include "../include/euid_common.h" + // filesystem #define RUN_FIREJAIL_BASEDIR "/run" diff --git a/src/firejail/join.c b/src/firejail/join.c index b05e25387..e471e4a21 100644 --- a/src/firejail/join.c +++ b/src/firejail/join.c @@ -183,12 +183,12 @@ void join_name(const char *name, const char *homedir, int argc, char **argv, int fprintf(stderr, "Error: invalid sandbox name\n"); exit(1); } + pid_t pid; if (name2pid(name, &pid)) { fprintf(stderr, "Error: cannot find sandbox %s\n", name); exit(1); } - join(pid, homedir, argc, argv, index); } diff --git a/src/firejail/list.c b/src/firejail/list.c index 7a3cf0aad..d5ef1ac2c 100644 --- a/src/firejail/list.c +++ b/src/firejail/list.c @@ -20,7 +20,8 @@ #include "firejail.h" void top(void) { - drop_privs(1); + if (getuid() != geteuid()) + drop_privs(1); char *arg[4]; arg[0] = "bash"; @@ -31,7 +32,8 @@ void top(void) { } void netstats(void) { - drop_privs(1); + if (getuid() != geteuid()) + drop_privs(1); char *arg[4]; arg[0] = "bash"; @@ -42,7 +44,8 @@ void netstats(void) { } void list(void) { - drop_privs(1); + if (getuid() != geteuid()) + drop_privs(1); char *arg[4]; arg[0] = "bash"; @@ -53,7 +56,8 @@ void list(void) { } void tree(void) { - drop_privs(1); + if (getuid() != geteuid()) + drop_privs(1); char *arg[4]; arg[0] = "bash"; diff --git a/src/firejail/main.c b/src/firejail/main.c index 6fd011868..688653ce2 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c @@ -45,6 +45,8 @@ printf("time %s:%d %u\n", __FILE__, __LINE__, (uint32_t) systick); } #endif +uid_t firejail_uid = 0; + #define STACK_SIZE (1024 * 1024) static char child_stack[STACK_SIZE]; // space for child's stack Config cfg; // configuration @@ -124,11 +126,13 @@ static void my_handler(int s){ static void extract_user_data(void) { // check suid + EUID_ROOT(); if (geteuid()) { fprintf(stderr, "Error: the sandbox is not setuid root\n"); exit(1); } - + EUID_USER(); + struct passwd *pw = getpwuid(getuid()); if (!pw) errExit("getpwuid"); @@ -315,6 +319,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { // extract pid or sandbox name pid_t pid; + EUID_ROOT(); if (read_pid(argv[i] + 12, &pid) == 0) bandwidth_pid(pid, cmd, dev, down, up); else @@ -337,6 +342,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { else if (strncmp(argv[i], "--seccomp.print=", 16) == 0) { // print seccomp filter for a sandbox specified by pid or by name pid_t pid; + EUID_ROOT(); if (read_pid(argv[i] + 16, &pid) == 0) seccomp_print_filter(pid); else @@ -350,6 +356,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { else if (strncmp(argv[i], "--protocol.print=", 17) == 0) { // print seccomp filter for a sandbox specified by pid or by name pid_t pid; + EUID_ROOT(); if (read_pid(argv[i] + 17, &pid) == 0) protocol_print_filter(pid); else @@ -360,6 +367,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { else if (strncmp(argv[i], "--caps.print=", 13) == 0) { // join sandbox by pid or by name pid_t pid; + EUID_ROOT(); if (read_pid(argv[i] + 13, &pid) == 0) caps_print_filter(pid); else @@ -369,6 +377,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { else if (strncmp(argv[i], "--fs.print=", 11) == 0) { // join sandbox by pid or by name pid_t pid; + EUID_ROOT(); if (read_pid(argv[i] + 11, &pid) == 0) fs_logger_print_log(pid); else @@ -378,6 +387,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { else if (strncmp(argv[i], "--dns.print=", 12) == 0) { // join sandbox by pid or by name pid_t pid; + EUID_ROOT(); if (read_pid(argv[i] + 12, &pid) == 0) net_dns_print(pid); else @@ -411,6 +421,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { // join sandbox by pid or by name pid_t pid; + EUID_ROOT(); if (read_pid(argv[i] + 7, &pid) == 0) join(pid, cfg.homedir, argc, argv, i + 1); else @@ -456,6 +467,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { // shutdown sandbox by pid or by name pid_t pid; + EUID_ROOT(); if (read_pid(argv[i] + 11, &pid) == 0) shut(pid); else @@ -480,6 +492,10 @@ int main(int argc, char **argv) { #ifdef HAVE_SECCOMP int highest_errno = errno_highest_nr(); #endif + + // drop permissions by default and rise them when required + EUID_INIT(); + EUID_USER(); // check argv[0] symlink wrapper if this is not a login shell if (*argv[0] != '-') @@ -517,10 +533,12 @@ int main(int argc, char **argv) { srand(t ^ sandbox_pid); // check firejail directories + EUID_ROOT(); fs_build_firejail_dir(); shm_create_firejail_dir(); bandwidth_shm_del_file(sandbox_pid); - + EUID_USER(); + // is this a login shell? if (*argv[0] == '-') { fullargc = restricted_shell(cfg.username); @@ -1449,6 +1467,7 @@ int main(int argc, char **argv) { // check and assign an IP address - for macvlan it will be done again in the sandbox! if (any_bridge_configured()) { + EUID_ROOT(); lockfd = open(RUN_NETWORK_LOCK_FILE, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); if (lockfd != -1) { int rv = fchown(lockfd, 0, 0); @@ -1463,6 +1482,7 @@ int main(int argc, char **argv) { // save network mapping in shared memory network_shm_set_file(sandbox_pid); + EUID_USER(); } // create the parent-child communication pipe @@ -1494,12 +1514,14 @@ int main(int argc, char **argv) { else if (arg_debug) printf("Using the local network stack\n"); + EUID_ROOT(); child = clone(sandbox, child_stack + STACK_SIZE, flags, NULL); if (child == -1) errExit("clone"); + EUID_USER(); if (!arg_command && !arg_quiet) { printf("Parent pid %u, child pid %u\n", sandbox_pid, child); @@ -1508,7 +1530,8 @@ int main(int argc, char **argv) { printf("The new log directory is /proc/%d/root/var/log\n", child); } - + + EUID_ROOT(); if (!arg_nonetwork) { // create veth pair or macvlan device if (cfg.bridge0.configured) { @@ -1554,6 +1577,7 @@ int main(int argc, char **argv) { net_move_interface(cfg.interface3.dev, child); } } + EUID_USER(); // close each end of the unused pipes close(parent_to_child_fds[0]); @@ -1576,7 +1600,9 @@ int main(int argc, char **argv) { uid_t uid = getuid(); if (asprintf(&map, "%d %d 1", uid, uid) == -1) errExit("asprintf"); + EUID_ROOT(); update_map(map, map_path); + EUID_USER(); free(map); free(map_path); @@ -1586,7 +1612,9 @@ int main(int argc, char **argv) { gid_t gid = getgid(); if (asprintf(&map, "%d %d 1", gid, gid) == -1) errExit("asprintf"); + EUID_ROOT(); update_map(map, map_path); + EUID_USER(); free(map); free(map_path); } @@ -1595,6 +1623,7 @@ int main(int argc, char **argv) { notify_other(parent_to_child_fds[1]); close(parent_to_child_fds[1]); + EUID_ROOT(); if (lockfd != -1) flock(lockfd, LOCK_UN); diff --git a/src/include/euid_common.h b/src/include/euid_common.h new file mode 100644 index 000000000..1cba548ab --- /dev/null +++ b/src/include/euid_common.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014-2016 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef EUID_COMMON_H +#define EUID_COMMON_H +#include +#include +#include + +extern uid_t firejail_uid; +extern uid_t firejail_uid_switch; + +static inline void EUID_ROOT(void) { + if (seteuid(0) == -1) + fprintf(stderr, "Error: cannot switch euid to root\n"); +} + +static inline void EUID_USER(void) { + if (seteuid(firejail_uid) == -1) + fprintf(stderr, "Error: cannot switch euid to user\n"); +} + +static inline void EUID_PRINT(void) { + printf("debug: uid %d, euid %d\n", getuid(), geteuid()); +} + +static inline void EUID_INIT(void) { + firejail_uid = getuid(); +} + +#endif diff --git a/src/lib/common.c b/src/lib/common.c index d23cd589e..099bb54d3 100644 --- a/src/lib/common.c +++ b/src/lib/common.c @@ -58,6 +58,7 @@ int join_namespace(pid_t pid, char *type) { } // return 1 if error +// this function requires root access - todo: fix it! int name2pid(const char *name, pid_t *pid) { pid_t parent = getpid(); -- cgit v1.2.3-54-g00ecf