From 807f1741fa2dd679171dc1c558dcab89a2a35eee Mon Sep 17 00:00:00 2001 From: Zack Weinberg Date: Fri, 20 Jan 2017 14:18:31 -0500 Subject: firejail/fs.c: include sys/wait.h for declaration of waitpid --- src/firejail/fs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/firejail/fs.c b/src/firejail/fs.c index 0da4cc111..a4d4db7fe 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c @@ -20,6 +20,7 @@ #include "firejail.h" #include #include +#include #include #include #include -- cgit v1.2.3-70-g09d2 From ef37be106728613dd032a235db1add2532774fed Mon Sep 17 00:00:00 2001 From: Zack Weinberg Date: Fri, 20 Jan 2017 17:38:51 -0500 Subject: Add support for joining a persistent, named network namespace. --- src/firejail/firejail.h | 6 +++ src/firejail/main.c | 10 +++++ src/firejail/netns.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++ src/firejail/sandbox.c | 11 +++++ src/man/firejail.txt | 5 +++ 5 files changed, 146 insertions(+) create mode 100644 src/firejail/netns.c diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 722d5c05e..94e66920b 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -317,6 +317,7 @@ extern int arg_netfilter; // enable netfilter extern int arg_netfilter6; // enable netfilter6 extern char *arg_netfilter_file; // netfilter file extern char *arg_netfilter6_file; // netfilter file +extern char *arg_netns; // "ip netns"-created network namespace to use extern int arg_doubledash; // double dash extern int arg_shell_none; // run the program directly without a shell extern int arg_private_dev; // private dev directory @@ -560,6 +561,11 @@ void check_netfilter_file(const char *fname); void netfilter(const char *fname); void netfilter6(const char *fname); +// netns.c +void check_netns(const char *nsname); +void netns(const char *nsname); +void netns_mounts(const char *nsname); + // bandwidth.c void bandwidth_del_run_file(pid_t pid); void bandwidth_pid(pid_t pid, const char *command, const char *dev, int down, int up); diff --git a/src/firejail/main.c b/src/firejail/main.c index 84bf5e8e6..9c6b6e001 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c @@ -85,6 +85,7 @@ int arg_netfilter; // enable netfilter int arg_netfilter6; // enable netfilter6 char *arg_netfilter_file = NULL; // netfilter file char *arg_netfilter6_file = NULL; // netfilter6 file +char *arg_netns = NULL; // "ip netns"-created network namespace to use int arg_doubledash = 0; // double dash int arg_shell_none = 0; // run the program directly without a shell int arg_private_dev = 0; // private dev directory @@ -1999,6 +2000,15 @@ int main(int argc, char **argv) { else exit_err_feature("networking"); } + + else if (strncmp(argv[i], "--netns=", 8) == 0) { + if (checkcfg(CFG_NETWORK)) { + arg_netns = argv[i] + 8; + check_netns(arg_netns); + } + else + exit_err_feature("networking"); + } #endif //************************************* // command diff --git a/src/firejail/netns.c b/src/firejail/netns.c new file mode 100644 index 000000000..477d56b3d --- /dev/null +++ b/src/firejail/netns.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2017 Firejail Authors + * + * 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. + */ +#include "firejail.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char *netns_control_file(const char *nsname) { + char *rv = 0; + if (asprintf(&rv, "/var/run/netns/%s", nsname) <= 0) + errExit("asprintf"); + return rv; +} + +static char *netns_etc_dir(const char *nsname) { + char *rv = 0; + if (asprintf(&rv, "/etc/netns/%s", nsname) <= 0) + errExit("asprintf"); + return rv; +} + +void check_netns(const char *nsname) { + if (strchr(nsname, '/') || strstr(nsname, "..")) { + fprintf(stderr, "Error: invalid netns name %s\n", nsname); + exit(1); + } + invalid_filename(nsname); + char *control_file = netns_control_file(nsname); + + EUID_ASSERT(); + + struct stat st; + if (lstat(control_file, &st)) { + fprintf(stderr, "Error: invalid netns '%s' (%s: %s)\n", + nsname, control_file, strerror(errno)); + exit(1); + } + if (!S_ISREG(st.st_mode)) { + fprintf(stderr, "Error: invalid netns '%s' (%s: not a regular file)\n", + nsname, control_file); + exit(1); + } + free(control_file); +} + +void netns(const char *nsname) { + char *control_file = netns_control_file(nsname); + int nsfd = open(control_file, O_RDONLY|O_CLOEXEC); + if (nsfd < 0) { + fprintf(stderr, "Error: cannot open netns '%s' (%s: %s)\n", + nsname, control_file, strerror(errno)); + exit(1); + } + if (syscall(__NR_setns, nsfd, CLONE_NEWNET) < 0) { + fprintf(stderr, "Error: cannot join netns '%s': %s\n", + nsname, strerror(errno)); + exit(1); + } + close(nsfd); + free(control_file); +} + +void netns_mounts(const char *nsname) { + char *etcdir = netns_etc_dir(nsname); + char *netns_name, *etc_name; + struct dirent *entry; + DIR *dir; + + dir = opendir(etcdir); + if (!dir) { + free(etcdir); + return; + } + while ((entry = readdir(dir))) { + if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) + continue; + if (asprintf(&netns_name, "%s/%s", etcdir, entry->d_name) < 0 || + asprintf(&etc_name, "/etc/%s", entry->d_name) < 0) + errExit("asprintf"); + if (mount(netns_name, etc_name, "none", MS_BIND, 0) < 0) { + fprintf(stderr, "Warning: bind %s -> %s failed: %s\n", + netns_name, etc_name, strerror(errno)); + } + free(netns_name); + free(etc_name); + } + closedir(dir); + free(etcdir); +} diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 493877db3..69cb8331e 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c @@ -467,6 +467,11 @@ int sandbox(void* sandbox_arg) { if (arg_debug) printf("Network namespace enabled, only loopback interface available\n"); } + else if (arg_netns) { + netns(arg_netns); + if (arg_debug) + printf("Network namespace '%s' activated\n", arg_netns); + } else if (any_bridge_configured() || any_interface_configured()) { // configure lo and eth0...eth3 net_if_up("lo"); @@ -729,6 +734,12 @@ int sandbox(void* sandbox_arg) { EUID_ROOT(); } } + + //**************************** + // /etc overrides from the network namespace + //**************************** + if (arg_netns) + netns_mounts(arg_netns); //**************************** // update /proc, /sys, /dev, /boot directorymy diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 1c0f7d55b..afd8e1e4e 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt @@ -760,6 +760,11 @@ Example: .br $ firejail \-\-net=none vlc +.TP +\fB\-\-netns=name +Run the program in a named, persistent network namespace. These can +be created and configured using "ip netns". + .TP \fB\-\-netfilter Enable a default client network filter in the new network namespace. -- cgit v1.2.3-70-g09d2