diff options
-rw-r--r-- | src/firejail/firejail.h | 2 | ||||
-rw-r--r-- | src/firejail/main.c | 10 | ||||
-rw-r--r-- | src/firejail/netfilter.c | 55 | ||||
-rw-r--r-- | src/firejail/network_main.c | 6 | ||||
-rw-r--r-- | src/firejail/usage.c | 1 | ||||
-rw-r--r-- | src/firejail/util.c | 38 | ||||
-rw-r--r-- | src/man/firejail.txt | 17 |
7 files changed, 76 insertions, 53 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 3e55139b3..00c6cd8f3 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -376,6 +376,7 @@ void net_configure_veth_pair(Bridge *br, const char *ifname, pid_t child); | |||
376 | void net_check_cfg(void); | 376 | void net_check_cfg(void); |
377 | void net_dns_print(pid_t pid); | 377 | void net_dns_print(pid_t pid); |
378 | void network_main(pid_t child); | 378 | void network_main(pid_t child); |
379 | void net_print(pid_t pid); | ||
379 | 380 | ||
380 | // network.c | 381 | // network.c |
381 | int check_ip46_address(const char *addr); | 382 | int check_ip46_address(const char *addr); |
@@ -500,6 +501,7 @@ void disable_file_or_dir(const char *fname); | |||
500 | void disable_file_path(const char *path, const char *file); | 501 | void disable_file_path(const char *path, const char *file); |
501 | int safe_fd(const char *path, int flags); | 502 | int safe_fd(const char *path, int flags); |
502 | int invalid_sandbox(const pid_t pid); | 503 | int invalid_sandbox(const pid_t pid); |
504 | void enter_network_namespace(pid_t pid); | ||
503 | 505 | ||
504 | // Get info regarding the last kernel mount operation from /proc/self/mountinfo | 506 | // Get info regarding the last kernel mount operation from /proc/self/mountinfo |
505 | // The return value points to a static area, and will be overwritten by subsequent calls. | 507 | // The return value points to a static area, and will be overwritten by subsequent calls. |
diff --git a/src/firejail/main.c b/src/firejail/main.c index bc5360ba7..f5acaa603 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -524,6 +524,16 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { | |||
524 | else | 524 | else |
525 | exit_err_feature("networking"); | 525 | exit_err_feature("networking"); |
526 | } | 526 | } |
527 | else if (strncmp(argv[i], "--net.print=", 12) == 0) { | ||
528 | if (checkcfg(CFG_NETWORK)) { | ||
529 | // extract pid or sandbox name | ||
530 | pid_t pid = require_pid(argv[i] + 12); | ||
531 | net_print(pid); | ||
532 | exit(0); | ||
533 | } | ||
534 | else | ||
535 | exit_err_feature("networking"); | ||
536 | } | ||
527 | #endif | 537 | #endif |
528 | else if (strncmp(argv[i], "--join=", 7) == 0) { | 538 | else if (strncmp(argv[i], "--join=", 7) == 0) { |
529 | if (checkcfg(CFG_JOIN) || getuid() == 0) { | 539 | if (checkcfg(CFG_JOIN) || getuid() == 0) { |
diff --git a/src/firejail/netfilter.c b/src/firejail/netfilter.c index 8fbd11bba..ed2d019ab 100644 --- a/src/firejail/netfilter.c +++ b/src/firejail/netfilter.c | |||
@@ -132,63 +132,12 @@ void netfilter6(const char *fname) { | |||
132 | void netfilter_print(pid_t pid, int ipv6) { | 132 | void netfilter_print(pid_t pid, int ipv6) { |
133 | EUID_ASSERT(); | 133 | EUID_ASSERT(); |
134 | 134 | ||
135 | // verify sandbox | 135 | enter_network_namespace(pid); |
136 | EUID_ROOT(); | ||
137 | char *comm = pid_proc_comm(pid); | ||
138 | EUID_USER(); | ||
139 | if (!comm) { | ||
140 | fprintf(stderr, "Error: cannot find sandbox\n"); | ||
141 | exit(1); | ||
142 | } | ||
143 | |||
144 | // check for firejail sandbox | ||
145 | if (strcmp(comm, "firejail") != 0) { | ||
146 | fprintf(stderr, "Error: cannot find sandbox\n"); | ||
147 | exit(1); | ||
148 | } | ||
149 | free(comm); | ||
150 | |||
151 | // check privileges for non-root users | ||
152 | uid_t uid = getuid(); | ||
153 | if (uid != 0) { | ||
154 | uid_t sandbox_uid = pid_get_uid(pid); | ||
155 | if (uid != sandbox_uid) { | ||
156 | fprintf(stderr, "Error: permission is denied to join a sandbox created by a different user.\n"); | ||
157 | exit(1); | ||
158 | } | ||
159 | } | ||
160 | |||
161 | // check network namespace | ||
162 | char *name; | ||
163 | if (asprintf(&name, "/run/firejail/network/%d-netmap", pid) == -1) | ||
164 | errExit("asprintf"); | ||
165 | struct stat s; | ||
166 | if (stat(name, &s) == -1) { | ||
167 | fprintf(stderr, "Error: the sandbox doesn't use a new network namespace\n"); | ||
168 | exit(1); | ||
169 | } | ||
170 | |||
171 | // join the network namespace | ||
172 | pid_t child; | ||
173 | if (find_child(pid, &child) == 1) { | ||
174 | fprintf(stderr, "Error: cannot join the network namespace\n"); | ||
175 | exit(1); | ||
176 | } | ||
177 | |||
178 | if (invalid_sandbox(child)) { | ||
179 | fprintf(stderr, "Error: cannot join the network namespace\n"); | ||
180 | exit(1); | ||
181 | } | ||
182 | |||
183 | EUID_ROOT(); | ||
184 | if (join_namespace(child, "net")) { | ||
185 | fprintf(stderr, "Error: cannot join the network namespace\n"); | ||
186 | exit(1); | ||
187 | } | ||
188 | 136 | ||
189 | // find iptables executable | 137 | // find iptables executable |
190 | char *iptables = NULL; | 138 | char *iptables = NULL; |
191 | // char *iptables_restore = NULL; | 139 | // char *iptables_restore = NULL; |
140 | struct stat s; | ||
192 | if (ipv6) { | 141 | if (ipv6) { |
193 | if (stat("/sbin/ip6tables", &s) == 0) | 142 | if (stat("/sbin/ip6tables", &s) == 0) |
194 | iptables = "/sbin/ip6tables"; | 143 | iptables = "/sbin/ip6tables"; |
diff --git a/src/firejail/network_main.c b/src/firejail/network_main.c index e3c750767..17f242d91 100644 --- a/src/firejail/network_main.c +++ b/src/firejail/network_main.c | |||
@@ -372,3 +372,9 @@ void network_main(pid_t child) { | |||
372 | 372 | ||
373 | free(cstr); | 373 | free(cstr); |
374 | } | 374 | } |
375 | |||
376 | void net_print(pid_t pid) { | ||
377 | EUID_ASSERT(); | ||
378 | enter_network_namespace(pid); | ||
379 | sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 2, PATH_FNET, "printif"); | ||
380 | } | ||
diff --git a/src/firejail/usage.c b/src/firejail/usage.c index 740128273..5a48638a7 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c | |||
@@ -102,6 +102,7 @@ static char *usage_str = | |||
102 | " --net=ethernet_interface - enable network namespaces and connect to this\n" | 102 | " --net=ethernet_interface - enable network namespaces and connect to this\n" |
103 | "\tEthernet interface.\n" | 103 | "\tEthernet interface.\n" |
104 | " --net=none - enable a new, unconnected network namespace.\n" | 104 | " --net=none - enable a new, unconnected network namespace.\n" |
105 | " --net.print=name|pid - print network interface configuration.\n" | ||
105 | " --netfilter[=filename,arg1,arg2,arg3 ...] - enable firewall.\n" | 106 | " --netfilter[=filename,arg1,arg2,arg3 ...] - enable firewall.\n" |
106 | " --netfilter.print=name|pid - print the firewall.\n" | 107 | " --netfilter.print=name|pid - print the firewall.\n" |
107 | " --netfilter6=filename - enable IPv6 firewall.\n" | 108 | " --netfilter6=filename - enable IPv6 firewall.\n" |
diff --git a/src/firejail/util.c b/src/firejail/util.c index 6c1a89b56..112307ebc 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -1128,3 +1128,41 @@ int invalid_sandbox(const pid_t pid) { | |||
1128 | 1128 | ||
1129 | return 0; | 1129 | return 0; |
1130 | } | 1130 | } |
1131 | |||
1132 | void enter_network_namespace(pid_t pid) { | ||
1133 | // in case the pid is that of a firejail process, use the pid of the first child process | ||
1134 | pid_t child = switch_to_child(pid); | ||
1135 | |||
1136 | // now check if the pid belongs to a firejail sandbox | ||
1137 | if (invalid_sandbox(child)) { | ||
1138 | fprintf(stderr, "Error: no valid sandbox\n"); | ||
1139 | exit(1); | ||
1140 | } | ||
1141 | |||
1142 | // check privileges for non-root users | ||
1143 | uid_t uid = getuid(); | ||
1144 | if (uid != 0) { | ||
1145 | uid_t sandbox_uid = pid_get_uid(pid); | ||
1146 | if (uid != sandbox_uid) { | ||
1147 | fprintf(stderr, "Error: permission is denied to join a sandbox created by a different user.\n"); | ||
1148 | exit(1); | ||
1149 | } | ||
1150 | } | ||
1151 | |||
1152 | // check network namespace | ||
1153 | char *name; | ||
1154 | if (asprintf(&name, "/run/firejail/network/%d-netmap", pid) == -1) | ||
1155 | errExit("asprintf"); | ||
1156 | struct stat s; | ||
1157 | if (stat(name, &s) == -1) { | ||
1158 | fprintf(stderr, "Error: the sandbox doesn't use a new network namespace\n"); | ||
1159 | exit(1); | ||
1160 | } | ||
1161 | |||
1162 | // join the namespace | ||
1163 | EUID_ROOT(); | ||
1164 | if (join_namespace(child, "net")) { | ||
1165 | fprintf(stderr, "Error: cannot join the network namespace\n"); | ||
1166 | exit(1); | ||
1167 | } | ||
1168 | } | ||
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 1686dddc2..bb5c8d10a 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -781,6 +781,23 @@ Note: \-\-net=none can crash the application on some platforms. | |||
781 | In these cases, it can be replaced with \-\-protocol=unix. | 781 | In these cases, it can be replaced with \-\-protocol=unix. |
782 | 782 | ||
783 | .TP | 783 | .TP |
784 | \fB\-\-net.print=name|pid | ||
785 | If a new network namespace is enabled, print network interface configuration for the sandbox specified by name or PID. Example: | ||
786 | .br | ||
787 | |||
788 | .br | ||
789 | $ firejail --net.print=browser | ||
790 | .br | ||
791 | Switching to pid 1853, the first child process inside the sandbox | ||
792 | .br | ||
793 | Interface MAC IP Mask Status | ||
794 | .br | ||
795 | lo 127.0.0.1 255.0.0.0 UP | ||
796 | .br | ||
797 | eth0-1852 5e:fb:8e:27:29:26 192.168.1.186 255.255.255.0 UP | ||
798 | .br | ||
799 | |||
800 | .TP | ||
784 | \fB\-\-netfilter | 801 | \fB\-\-netfilter |
785 | Enable a default firewall if a new network namespace is created inside the sandbox. | 802 | Enable a default firewall if a new network namespace is created inside the sandbox. |
786 | This option has no effect for sandboxes using the system network namespace. | 803 | This option has no effect for sandboxes using the system network namespace. |