diff options
author | 2020-01-28 16:59:49 +0100 | |
---|---|---|
committer | 2020-01-28 16:59:49 +0100 | |
commit | 93cecca281c42fe7b96605b612f3c206d528cae2 (patch) | |
tree | cca6801d42fab82ab09f6e8d334c5d96ebdd86ce | |
parent | clarify dropping python2 support in meld.profile (#3167) (diff) | |
parent | Do not declare variable in for loop (diff) | |
download | firejail-93cecca281c42fe7b96605b612f3c206d528cae2.tar.gz firejail-93cecca281c42fe7b96605b612f3c206d528cae2.tar.zst firejail-93cecca281c42fe7b96605b612f3c206d528cae2.zip |
Merge pull request #3190 from kris7t/dhcp-client
DHCP client code quality fixes
-rw-r--r-- | src/firejail/dhcp.c | 205 | ||||
-rw-r--r-- | src/firejail/firejail.h | 4 | ||||
-rw-r--r-- | src/firejail/fs_hostname.c | 6 | ||||
-rw-r--r-- | src/firejail/main.c | 24 | ||||
-rw-r--r-- | src/firejail/network_main.c | 8 | ||||
-rw-r--r-- | src/firejail/profile.c | 26 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 8 | ||||
-rw-r--r-- | src/firejail/sbox.c | 47 | ||||
-rw-r--r-- | src/firejail/usage.c | 2 | ||||
-rw-r--r-- | src/fnet/interface.c | 194 | ||||
-rw-r--r-- | src/include/rundefs.h | 11 | ||||
-rw-r--r-- | src/man/firejail-profile.txt | 53 | ||||
-rw-r--r-- | src/man/firejail.txt | 49 |
13 files changed, 376 insertions, 261 deletions
diff --git a/src/firejail/dhcp.c b/src/firejail/dhcp.c index f7d417d3d..7593a47f2 100644 --- a/src/firejail/dhcp.c +++ b/src/firejail/dhcp.c | |||
@@ -29,130 +29,133 @@ pid_t dhclient4_pid = 0; | |||
29 | pid_t dhclient6_pid = 0; | 29 | pid_t dhclient6_pid = 0; |
30 | 30 | ||
31 | typedef struct { | 31 | typedef struct { |
32 | char *version_arg; | 32 | char *version_arg; |
33 | char *pid_file; | 33 | char *pid_file; |
34 | char *leases_file; | 34 | char *leases_file; |
35 | uint8_t generate_duid; | 35 | uint8_t generate_duid; |
36 | char *duid_leases_file; | 36 | char *duid_leases_file; |
37 | pid_t *pid; | 37 | pid_t *pid; |
38 | ptrdiff_t arg_offset; | 38 | ptrdiff_t arg_offset; |
39 | } Dhclient; | 39 | } Dhclient; |
40 | 40 | ||
41 | static const Dhclient dhclient4 = { .version_arg = "-4", | 41 | static const Dhclient dhclient4 = { |
42 | .pid_file = RUN_DHCLIENT_4_PID_FILE, | 42 | .version_arg = "-4", |
43 | .leases_file = RUN_DHCLIENT_4_LEASES_FILE, | 43 | .pid_file = RUN_DHCLIENT_4_PID_FILE, |
44 | .generate_duid = 1, | 44 | .leases_file = RUN_DHCLIENT_4_LEASES_FILE, |
45 | .pid = &dhclient4_pid, | 45 | .generate_duid = 1, |
46 | .arg_offset = offsetof(Bridge, arg_ip_dhcp) | 46 | .pid = &dhclient4_pid, |
47 | .arg_offset = offsetof(Bridge, arg_ip_dhcp) | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | static const Dhclient dhclient6 = { .version_arg = "-6", | 50 | static const Dhclient dhclient6 = { |
50 | .pid_file = RUN_DHCLIENT_6_PID_FILE, | 51 | .version_arg = "-6", |
51 | .leases_file = RUN_DHCLIENT_6_LEASES_FILE, | 52 | .pid_file = RUN_DHCLIENT_6_PID_FILE, |
52 | .duid_leases_file = RUN_DHCLIENT_4_LEASES_FILE, | 53 | .leases_file = RUN_DHCLIENT_6_LEASES_FILE, |
53 | .pid = &dhclient6_pid, | 54 | .duid_leases_file = RUN_DHCLIENT_4_LEASES_FILE, |
54 | .arg_offset = offsetof(Bridge, arg_ip6_dhcp) | 55 | .pid = &dhclient6_pid, |
56 | .arg_offset = offsetof(Bridge, arg_ip6_dhcp) | ||
55 | }; | 57 | }; |
56 | 58 | ||
57 | static void dhcp_run_dhclient(const Dhclient *client) { | 59 | static void dhcp_run_dhclient(const Dhclient *client) { |
58 | char *argv[256] = { "dhclient", | 60 | char *argv[256] = { |
59 | client->version_arg, | 61 | "dhclient", |
60 | "-pf", client->pid_file, | 62 | client->version_arg, |
61 | "-lf", client->leases_file, | 63 | "-pf", client->pid_file, |
62 | }; | 64 | "-lf", client->leases_file, |
63 | int i = 6; | 65 | }; |
64 | if (client->generate_duid) | 66 | int i = 6; |
65 | argv[i++] = "-i"; | 67 | if (client->generate_duid) |
66 | if (client->duid_leases_file) { | 68 | argv[i++] = "-i"; |
67 | argv[i++] = "-df"; | 69 | if (client->duid_leases_file) { |
68 | argv[i++] = client->duid_leases_file; | 70 | argv[i++] = "-df"; |
69 | } | 71 | argv[i++] = client->duid_leases_file; |
70 | if (arg_debug) | 72 | } |
71 | argv[i++] = "-v"; | 73 | if (arg_debug) |
72 | if (*(uint8_t *) ((char *) &cfg.bridge0 + client->arg_offset)) | 74 | argv[i++] = "-v"; |
73 | argv[i++] = cfg.bridge0.devsandbox; | 75 | if (*(uint8_t *)((char *)&cfg.bridge0 + client->arg_offset)) |
74 | if (*(uint8_t *) ((char *) &cfg.bridge1 + client->arg_offset)) | 76 | argv[i++] = cfg.bridge0.devsandbox; |
75 | argv[i++] = cfg.bridge1.devsandbox; | 77 | if (*(uint8_t *)((char *)&cfg.bridge1 + client->arg_offset)) |
76 | if (*(uint8_t *) ((char *) &cfg.bridge2 + client->arg_offset)) | 78 | argv[i++] = cfg.bridge1.devsandbox; |
77 | argv[i++] = cfg.bridge2.devsandbox; | 79 | if (*(uint8_t *)((char *)&cfg.bridge2 + client->arg_offset)) |
78 | if (*(uint8_t *) ((char *) &cfg.bridge3 + client->arg_offset)) | 80 | argv[i++] = cfg.bridge2.devsandbox; |
79 | argv[i++] = cfg.bridge3.devsandbox; | 81 | if (*(uint8_t *)((char *)&cfg.bridge3 + client->arg_offset)) |
82 | argv[i++] = cfg.bridge3.devsandbox; | ||
80 | 83 | ||
81 | sbox_run_v(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_CAPS_NET_SERVICE | SBOX_SECCOMP, argv); | 84 | sbox_run_v(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_CAPS_NET_SERVICE | SBOX_SECCOMP, argv); |
82 | } | 85 | } |
83 | 86 | ||
84 | static pid_t dhcp_read_pidfile(const Dhclient *client) { | 87 | static pid_t dhcp_read_pidfile(const Dhclient *client) { |
85 | // We have to run dhclient as a forking daemon (not pass the -d option), | 88 | // We have to run dhclient as a forking daemon (not pass the -d option), |
86 | // because we want to be notified of a successful DHCP lease by the parent process exit. | 89 | // because we want to be notified of a successful DHCP lease by the parent process exit. |
87 | // However, try to be extra paranoid with race conditions, | 90 | // However, try to be extra paranoid with race conditions, |
88 | // because dhclient only writes the daemon pid into the pidfile | 91 | // because dhclient only writes the daemon pid into the pidfile |
89 | // after its parent process has exited. | 92 | // after its parent process has exited. |
90 | int tries = 0; | 93 | int tries = 0; |
91 | pid_t found = 0; | 94 | pid_t found = 0; |
92 | while (found == 0 && tries < 10) { | 95 | while (found == 0 && tries < 10) { |
93 | if (tries >= 1) | 96 | if (tries >= 1) |
94 | usleep(100000); | 97 | usleep(100000); |
95 | FILE *pidfile = fopen(client->pid_file, "r"); | 98 | FILE *pidfile = fopen(client->pid_file, "r"); |
96 | if (pidfile) { | 99 | if (pidfile) { |
97 | long pid; | 100 | long pid; |
98 | if (fscanf(pidfile, "%ld", &pid) == 1) { | 101 | if (fscanf(pidfile, "%ld", &pid) == 1) { |
99 | char *pidname = pid_proc_comm((pid_t) pid); | 102 | char *pidname = pid_proc_comm((pid_t) pid); |
100 | if (pidname && strcmp(pidname, "dhclient") == 0) | 103 | if (pidname && strcmp(pidname, "dhclient") == 0) |
101 | found = (pid_t) pid; | 104 | found = (pid_t) pid; |
102 | } | 105 | } |
103 | fclose(pidfile); | 106 | fclose(pidfile); |
104 | } | 107 | } |
105 | ++tries; | 108 | ++tries; |
106 | } | 109 | } |
107 | if (found == 0) { | 110 | if (found == 0) { |
108 | fprintf(stderr, "Error: Cannot get dhclient %s PID from %s\n", | 111 | fprintf(stderr, "Error: Cannot get dhclient %s PID from %s\n", |
109 | client->version_arg, client->pid_file); | 112 | client->version_arg, client->pid_file); |
110 | exit(1); | 113 | exit(1); |
111 | } | 114 | } |
112 | return found; | 115 | return found; |
113 | } | 116 | } |
114 | 117 | ||
115 | static void dhcp_start_dhclient(const Dhclient *client) { | 118 | static void dhcp_start_dhclient(const Dhclient *client) { |
116 | dhcp_run_dhclient(client); | 119 | dhcp_run_dhclient(client); |
117 | *(client->pid) = dhcp_read_pidfile(client); | 120 | *(client->pid) = dhcp_read_pidfile(client); |
118 | } | 121 | } |
119 | 122 | ||
120 | static void dhcp_waitll(const char *ifname) { | 123 | static void dhcp_waitll(const char *ifname) { |
121 | sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 3, PATH_FNET, "waitll", ifname); | 124 | sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 3, PATH_FNET, "waitll", ifname); |
122 | } | 125 | } |
123 | 126 | ||
124 | static void dhcp_waitll_all() { | 127 | static void dhcp_waitll_all() { |
125 | if (cfg.bridge0.arg_ip6_dhcp) | 128 | if (cfg.bridge0.arg_ip6_dhcp) |
126 | dhcp_waitll(cfg.bridge0.devsandbox); | 129 | dhcp_waitll(cfg.bridge0.devsandbox); |
127 | if (cfg.bridge1.arg_ip6_dhcp) | 130 | if (cfg.bridge1.arg_ip6_dhcp) |
128 | dhcp_waitll(cfg.bridge1.devsandbox); | 131 | dhcp_waitll(cfg.bridge1.devsandbox); |
129 | if (cfg.bridge2.arg_ip6_dhcp) | 132 | if (cfg.bridge2.arg_ip6_dhcp) |
130 | dhcp_waitll(cfg.bridge2.devsandbox); | 133 | dhcp_waitll(cfg.bridge2.devsandbox); |
131 | if (cfg.bridge3.arg_ip6_dhcp) | 134 | if (cfg.bridge3.arg_ip6_dhcp) |
132 | dhcp_waitll(cfg.bridge3.devsandbox); | 135 | dhcp_waitll(cfg.bridge3.devsandbox); |
133 | } | 136 | } |
134 | 137 | ||
135 | void dhcp_start(void) { | 138 | void dhcp_start(void) { |
136 | if (!any_dhcp()) | 139 | if (!any_dhcp()) |
137 | return; | 140 | return; |
138 | 141 | ||
139 | EUID_ROOT(); | 142 | EUID_ROOT(); |
140 | if (mkdir(RUN_DHCLIENT_DIR, 0700)) | 143 | if (mkdir(RUN_DHCLIENT_DIR, 0700)) |
141 | errExit("mkdir"); | 144 | errExit("mkdir"); |
142 | 145 | ||
143 | if (any_ip_dhcp()) { | 146 | if (any_ip_dhcp()) { |
144 | dhcp_start_dhclient(&dhclient4); | 147 | dhcp_start_dhclient(&dhclient4); |
145 | if (arg_debug) | 148 | if (arg_debug) |
146 | printf("Running dhclient -4 in the background as pid %ld\n", (long) dhclient4_pid); | 149 | printf("Running dhclient -4 in the background as pid %ld\n", (long) dhclient4_pid); |
147 | } | 150 | } |
148 | if (any_ip6_dhcp()) { | 151 | if (any_ip6_dhcp()) { |
149 | dhcp_waitll_all(); | 152 | dhcp_waitll_all(); |
150 | dhcp_start_dhclient(&dhclient6); | 153 | dhcp_start_dhclient(&dhclient6); |
151 | if (arg_debug) | 154 | if (arg_debug) |
152 | printf("Running dhclient -6 in the background as pid %ld\n", (long) dhclient6_pid); | 155 | printf("Running dhclient -6 in the background as pid %ld\n", (long) dhclient6_pid); |
153 | if (dhclient4_pid == dhclient6_pid) { | 156 | if (dhclient4_pid == dhclient6_pid) { |
154 | fprintf(stderr, "Error: dhclient -4 and -6 have the same PID: %ld\n", (long) dhclient4_pid); | 157 | fprintf(stderr, "Error: dhclient -4 and -6 have the same PID: %ld\n", (long) dhclient4_pid); |
155 | exit(1); | 158 | exit(1); |
156 | } | 159 | } |
157 | } | 160 | } |
158 | } | 161 | } |
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 8f90152e6..4dc580a5e 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -103,8 +103,8 @@ typedef struct bridge_t { | |||
103 | 103 | ||
104 | // flags | 104 | // flags |
105 | uint8_t arg_ip_none; // --ip=none | 105 | uint8_t arg_ip_none; // --ip=none |
106 | uint8_t arg_ip_dhcp; | 106 | uint8_t arg_ip_dhcp; |
107 | uint8_t arg_ip6_dhcp; | 107 | uint8_t arg_ip6_dhcp; |
108 | uint8_t macvlan; // set by --net=eth0 (or eth1, ...); reset by --net=br0 (or br1, ...) | 108 | uint8_t macvlan; // set by --net=eth0 (or eth1, ...); reset by --net=br0 (or br1, ...) |
109 | uint8_t configured; | 109 | uint8_t configured; |
110 | uint8_t scan; // set by --scan | 110 | uint8_t scan; // set by --scan |
diff --git a/src/firejail/fs_hostname.c b/src/firejail/fs_hostname.c index 15e9f9ca9..fd5e1bbd3 100644 --- a/src/firejail/fs_hostname.c +++ b/src/firejail/fs_hostname.c | |||
@@ -171,10 +171,10 @@ void fs_resolvconf(void) { | |||
171 | } | 171 | } |
172 | 172 | ||
173 | if (cfg.dns1) { | 173 | if (cfg.dns1) { |
174 | if (any_dhcp()) | 174 | if (any_dhcp()) |
175 | fwarning("network setup uses DHCP, nameservers will likely be overwritten\n"); | 175 | fwarning("network setup uses DHCP, nameservers will likely be overwritten\n"); |
176 | fprintf(fp, "nameserver %s\n", cfg.dns1); | 176 | fprintf(fp, "nameserver %s\n", cfg.dns1); |
177 | } | 177 | } |
178 | if (cfg.dns2) | 178 | if (cfg.dns2) |
179 | fprintf(fp, "nameserver %s\n", cfg.dns2); | 179 | fprintf(fp, "nameserver %s\n", cfg.dns2); |
180 | if (cfg.dns3) | 180 | if (cfg.dns3) |
diff --git a/src/firejail/main.c b/src/firejail/main.c index d2784ed2c..78717ab41 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -2193,18 +2193,18 @@ int main(int argc, char **argv) { | |||
2193 | } | 2193 | } |
2194 | 2194 | ||
2195 | // configure this IP address for the last bridge defined | 2195 | // configure this IP address for the last bridge defined |
2196 | if (strcmp(argv[i] + 6, "dhcp") == 0) | 2196 | if (strcmp(argv[i] + 6, "dhcp") == 0) |
2197 | br->arg_ip6_dhcp = 1; | 2197 | br->arg_ip6_dhcp = 1; |
2198 | else { | 2198 | else { |
2199 | if (check_ip46_address(argv[i] + 6) == 0) { | 2199 | if (check_ip46_address(argv[i] + 6) == 0) { |
2200 | fprintf(stderr, "Error: invalid IPv6 address\n"); | 2200 | fprintf(stderr, "Error: invalid IPv6 address\n"); |
2201 | exit(1); | 2201 | exit(1); |
2202 | } | 2202 | } |
2203 | 2203 | ||
2204 | br->ip6sandbox = strdup(argv[i] + 6); | 2204 | br->ip6sandbox = strdup(argv[i] + 6); |
2205 | if (br->ip6sandbox == NULL) | 2205 | if (br->ip6sandbox == NULL) |
2206 | errExit("strdup"); | 2206 | errExit("strdup"); |
2207 | } | 2207 | } |
2208 | } | 2208 | } |
2209 | else | 2209 | else |
2210 | exit_err_feature("networking"); | 2210 | exit_err_feature("networking"); |
diff --git a/src/firejail/network_main.c b/src/firejail/network_main.c index b5ea63360..85896e528 100644 --- a/src/firejail/network_main.c +++ b/src/firejail/network_main.c | |||
@@ -246,10 +246,10 @@ void net_check_cfg(void) { | |||
246 | if (cfg.defaultgw) | 246 | if (cfg.defaultgw) |
247 | check_default_gw(cfg.defaultgw); | 247 | check_default_gw(cfg.defaultgw); |
248 | else { | 248 | else { |
249 | // if the first network has no assigned address, | 249 | // if the first network has no assigned address, |
250 | // do not try to set up a gateway, because it will fail | 250 | // do not try to set up a gateway, because it will fail |
251 | if (cfg.bridge0.arg_ip_none) | 251 | if (cfg.bridge0.arg_ip_none) |
252 | return; | 252 | return; |
253 | // first network is a regular bridge | 253 | // first network is a regular bridge |
254 | if (cfg.bridge0.macvlan == 0) | 254 | if (cfg.bridge0.macvlan == 0) |
255 | cfg.defaultgw = cfg.bridge0.ip; | 255 | cfg.defaultgw = cfg.bridge0.ip; |
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index b77d03d3f..969209869 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -701,19 +701,19 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
701 | exit(1); | 701 | exit(1); |
702 | } | 702 | } |
703 | 703 | ||
704 | // configure this IP address for the last bridge defined | 704 | // configure this IP address for the last bridge defined |
705 | if (strcmp(ptr + 4, "dhcp") == 0) | 705 | if (strcmp(ptr + 4, "dhcp") == 0) |
706 | br->arg_ip6_dhcp = 1; | 706 | br->arg_ip6_dhcp = 1; |
707 | else { | 707 | else { |
708 | if (check_ip46_address(ptr + 4) == 0) { | 708 | if (check_ip46_address(ptr + 4) == 0) { |
709 | fprintf(stderr, "Error: invalid IPv6 address\n"); | 709 | fprintf(stderr, "Error: invalid IPv6 address\n"); |
710 | exit(1); | 710 | exit(1); |
711 | } | 711 | } |
712 | 712 | ||
713 | br->ip6sandbox = strdup(ptr + 4); | 713 | br->ip6sandbox = strdup(ptr + 4); |
714 | if (br->ip6sandbox == NULL) | 714 | if (br->ip6sandbox == NULL) |
715 | errExit("strdup"); | 715 | errExit("strdup"); |
716 | } | 716 | } |
717 | } | 717 | } |
718 | else | 718 | else |
719 | warning_feature_disabled("networking"); | 719 | warning_feature_disabled("networking"); |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 58c30ec34..96ad30bed 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -337,8 +337,8 @@ static int monitor_application(pid_t app_pid) { | |||
337 | continue; | 337 | continue; |
338 | if (pid == 1) | 338 | if (pid == 1) |
339 | continue; | 339 | continue; |
340 | if (pid == dhclient4_pid || pid == dhclient6_pid) | 340 | if ((pid_t) pid == dhclient4_pid || (pid_t) pid == dhclient6_pid) |
341 | continue; | 341 | continue; |
342 | 342 | ||
343 | // todo: make this generic | 343 | // todo: make this generic |
344 | // Dillo browser leaves a dpid process running, we need to shut it down | 344 | // Dillo browser leaves a dpid process running, we need to shut it down |
@@ -995,7 +995,7 @@ int sandbox(void* sandbox_arg) { | |||
995 | fs_dev_disable_dvd(); | 995 | fs_dev_disable_dvd(); |
996 | 996 | ||
997 | if (arg_nou2f) | 997 | if (arg_nou2f) |
998 | fs_dev_disable_u2f(); | 998 | fs_dev_disable_u2f(); |
999 | 999 | ||
1000 | if (arg_novideo) | 1000 | if (arg_novideo) |
1001 | fs_dev_disable_video(); | 1001 | fs_dev_disable_video(); |
@@ -1020,7 +1020,7 @@ int sandbox(void* sandbox_arg) { | |||
1020 | //**************************** | 1020 | //**************************** |
1021 | // start dhcp client | 1021 | // start dhcp client |
1022 | //**************************** | 1022 | //**************************** |
1023 | dhcp_start(); | 1023 | dhcp_start(); |
1024 | 1024 | ||
1025 | //**************************** | 1025 | //**************************** |
1026 | // set application environment | 1026 | // set application environment |
diff --git a/src/firejail/sbox.c b/src/firejail/sbox.c index 1ead5a449..203c0fc03 100644 --- a/src/firejail/sbox.c +++ b/src/firejail/sbox.c | |||
@@ -128,11 +128,11 @@ int sbox_run_v(unsigned filtermask, char * const arg[]) { | |||
128 | 128 | ||
129 | if (arg_debug) { | 129 | if (arg_debug) { |
130 | printf("sbox run: "); | 130 | printf("sbox run: "); |
131 | int i = 0; | 131 | int i = 0; |
132 | while (arg[i]) { | 132 | while (arg[i]) { |
133 | printf("%s ", arg[i]); | 133 | printf("%s ", arg[i]); |
134 | i++; | 134 | i++; |
135 | } | 135 | } |
136 | printf("\n"); | 136 | printf("\n"); |
137 | } | 137 | } |
138 | 138 | ||
@@ -182,7 +182,8 @@ int sbox_run_v(unsigned filtermask, char * const arg[]) { | |||
182 | 182 | ||
183 | // close all other file descriptors | 183 | // close all other file descriptors |
184 | int max = 20; // getdtablesize() is overkill for a firejail process | 184 | int max = 20; // getdtablesize() is overkill for a firejail process |
185 | for (int i = 3; i < max; i++) | 185 | int i = 3; |
186 | for (i = 3; i < max; i++) | ||
186 | close(i); // close open files | 187 | close(i); // close open files |
187 | 188 | ||
188 | umask(027); | 189 | umask(027); |
@@ -191,33 +192,33 @@ int sbox_run_v(unsigned filtermask, char * const arg[]) { | |||
191 | if (filtermask & SBOX_CAPS_NONE) { | 192 | if (filtermask & SBOX_CAPS_NONE) { |
192 | caps_drop_all(); | 193 | caps_drop_all(); |
193 | } else { | 194 | } else { |
194 | uint64_t set = 0; | 195 | uint64_t set = 0; |
195 | if (filtermask & SBOX_CAPS_NETWORK) { | 196 | if (filtermask & SBOX_CAPS_NETWORK) { |
196 | #ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files | 197 | #ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files |
197 | set |= ((uint64_t) 1) << CAP_NET_ADMIN; | 198 | set |= ((uint64_t) 1) << CAP_NET_ADMIN; |
198 | set |= ((uint64_t) 1) << CAP_NET_RAW; | 199 | set |= ((uint64_t) 1) << CAP_NET_RAW; |
199 | #endif | 200 | #endif |
200 | } | 201 | } |
201 | if (filtermask & SBOX_CAPS_HIDEPID) { | 202 | if (filtermask & SBOX_CAPS_HIDEPID) { |
202 | #ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files | 203 | #ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files |
203 | set |= ((uint64_t) 1) << CAP_SYS_PTRACE; | 204 | set |= ((uint64_t) 1) << CAP_SYS_PTRACE; |
204 | set |= ((uint64_t) 1) << CAP_SYS_PACCT; | 205 | set |= ((uint64_t) 1) << CAP_SYS_PACCT; |
205 | #endif | 206 | #endif |
206 | } | 207 | } |
207 | if (filtermask & SBOX_CAPS_NET_SERVICE) { | 208 | if (filtermask & SBOX_CAPS_NET_SERVICE) { |
208 | #ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files | 209 | #ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files |
209 | set |= ((uint64_t) 1) << CAP_NET_BIND_SERVICE; | 210 | set |= ((uint64_t) 1) << CAP_NET_BIND_SERVICE; |
210 | set |= ((uint64_t) 1) << CAP_NET_BROADCAST; | 211 | set |= ((uint64_t) 1) << CAP_NET_BROADCAST; |
211 | #endif | 212 | #endif |
212 | } | 213 | } |
213 | if (set != 0) { // some SBOX_CAPS_ flag was specified, drop all other capabilities | 214 | if (set != 0) { // some SBOX_CAPS_ flag was specified, drop all other capabilities |
214 | #ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files | 215 | #ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files |
215 | caps_set(set); | 216 | caps_set(set); |
216 | #endif | 217 | #endif |
217 | } | 218 | } |
218 | } | 219 | } |
219 | 220 | ||
220 | if (filtermask & SBOX_SECCOMP) { | 221 | if (filtermask & SBOX_SECCOMP) { |
221 | if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { | 222 | if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { |
222 | perror("prctl(NO_NEW_PRIVS)"); | 223 | perror("prctl(NO_NEW_PRIVS)"); |
223 | } | 224 | } |
diff --git a/src/firejail/usage.c b/src/firejail/usage.c index c8dc39a04..52d4f7c03 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c | |||
@@ -82,7 +82,9 @@ static char *usage_str = | |||
82 | " --interface=name - move interface in sandbox.\n" | 82 | " --interface=name - move interface in sandbox.\n" |
83 | " --ip=address - set interface IP address.\n" | 83 | " --ip=address - set interface IP address.\n" |
84 | " --ip=none - no IP address and no default gateway are configured.\n" | 84 | " --ip=none - no IP address and no default gateway are configured.\n" |
85 | " --ip=dhcp - acquire IP address by running dhclient.\n" | ||
85 | " --ip6=address - set interface IPv6 address.\n" | 86 | " --ip6=address - set interface IPv6 address.\n" |
87 | " --ip6=dhcp - acquire IPv6 address by running dhclient.\n" | ||
86 | " --iprange=address,address - configure an IP address in this range.\n" | 88 | " --iprange=address,address - configure an IP address in this range.\n" |
87 | #endif | 89 | #endif |
88 | " --ipc-namespace - enable a new IPC namespace.\n" | 90 | " --ipc-namespace - enable a new IPC namespace.\n" |
diff --git a/src/fnet/interface.c b/src/fnet/interface.c index 3b44b70e3..62df0930e 100644 --- a/src/fnet/interface.c +++ b/src/fnet/interface.c | |||
@@ -374,81 +374,83 @@ void net_if_ip6(const char *ifname, const char *addr6) { | |||
374 | } | 374 | } |
375 | 375 | ||
376 | static int net_netlink_address_tentative(struct nlmsghdr *current_header) { | 376 | static int net_netlink_address_tentative(struct nlmsghdr *current_header) { |
377 | struct ifaddrmsg *msg = NLMSG_DATA(current_header); | 377 | struct ifaddrmsg *msg = NLMSG_DATA(current_header); |
378 | struct rtattr *rta = IFA_RTA(msg); | 378 | int has_flags = 0; |
379 | size_t msg_len = IFA_PAYLOAD(current_header); | 379 | #ifdef IFA_FLAGS |
380 | int has_flags = 0; | 380 | struct rtattr *rta = IFA_RTA(msg); |
381 | while (RTA_OK(rta, msg_len)) { | 381 | size_t msg_len = IFA_PAYLOAD(current_header); |
382 | if (rta->rta_type == IFA_FLAGS) { | 382 | while (RTA_OK(rta, msg_len)) { |
383 | has_flags = 1; | 383 | if (rta->rta_type == IFA_FLAGS) { |
384 | uint32_t *flags = RTA_DATA(rta); | 384 | has_flags = 1; |
385 | if (*flags & IFA_F_TENTATIVE) | 385 | uint32_t *flags = RTA_DATA(rta); |
386 | return 1; | 386 | if (*flags & IFA_F_TENTATIVE) |
387 | } | 387 | return 1; |
388 | rta = RTA_NEXT(rta, msg_len); | 388 | } |
389 | } | 389 | rta = RTA_NEXT(rta, msg_len); |
390 | // According to <linux/if_addr.h>, if an IFA_FLAGS attribute is present, | 390 | } |
391 | // the field ifa_flags should be ignored. | 391 | #endif |
392 | return !has_flags && (msg->ifa_flags & IFA_F_TENTATIVE); | 392 | // According to <linux/if_addr.h>, if an IFA_FLAGS attribute is present, |
393 | // the field ifa_flags should be ignored. | ||
394 | return !has_flags && (msg->ifa_flags & IFA_F_TENTATIVE); | ||
393 | } | 395 | } |
394 | 396 | ||
395 | static int net_netlink_if_has_ll(int sock, int index) { | 397 | static int net_netlink_if_has_ll(int sock, uint32_t index) { |
396 | struct { | 398 | struct { |
397 | struct nlmsghdr header; | 399 | struct nlmsghdr header; |
398 | struct ifaddrmsg message; | 400 | struct ifaddrmsg message; |
399 | } req; | 401 | } req; |
400 | memset(&req, 0, sizeof(req)); | 402 | memset(&req, 0, sizeof(req)); |
401 | req.header.nlmsg_len = NLMSG_LENGTH(sizeof(req.message)); | 403 | req.header.nlmsg_len = NLMSG_LENGTH(sizeof(req.message)); |
402 | req.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; | 404 | req.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; |
403 | req.header.nlmsg_type = RTM_GETADDR; | 405 | req.header.nlmsg_type = RTM_GETADDR; |
404 | req.message.ifa_family = AF_INET6; | 406 | req.message.ifa_family = AF_INET6; |
405 | if (send(sock, &req, req.header.nlmsg_len, 0) != req.header.nlmsg_len) | 407 | if (send(sock, &req, req.header.nlmsg_len, 0) != req.header.nlmsg_len) |
406 | errExit("send"); | 408 | errExit("send"); |
407 | 409 | ||
408 | int found = 0; | 410 | int found = 0; |
409 | int all_parts_processed = 0; | 411 | int all_parts_processed = 0; |
410 | while (!all_parts_processed) { | 412 | while (!all_parts_processed) { |
411 | char buf[16384]; | 413 | char buf[16384]; |
412 | ssize_t len = recv(sock, buf, sizeof(buf), 0); | 414 | ssize_t len = recv(sock, buf, sizeof(buf), 0); |
413 | if (len < 0) | 415 | if (len < 0) |
414 | errExit("recv"); | 416 | errExit("recv"); |
415 | if (len < sizeof(struct nlmsghdr)) { | 417 | if (len < (ssize_t) sizeof(struct nlmsghdr)) { |
416 | fprintf(stderr, "Received incomplete netlink message\n"); | 418 | fprintf(stderr, "Received incomplete netlink message\n"); |
417 | exit(1); | 419 | exit(1); |
418 | } | 420 | } |
419 | 421 | ||
420 | struct nlmsghdr *current_header = (struct nlmsghdr *) buf; | 422 | struct nlmsghdr *current_header = (struct nlmsghdr *) buf; |
421 | while (NLMSG_OK(current_header, len)) { | 423 | while (NLMSG_OK(current_header, len)) { |
422 | switch (current_header->nlmsg_type) { | 424 | switch (current_header->nlmsg_type) { |
423 | case RTM_NEWADDR: { | 425 | case RTM_NEWADDR: { |
424 | struct ifaddrmsg *msg = NLMSG_DATA(current_header); | 426 | struct ifaddrmsg *msg = NLMSG_DATA(current_header); |
425 | if (!found && msg->ifa_index == index && msg->ifa_scope == RT_SCOPE_LINK && | 427 | if (!found && msg->ifa_index == index && msg->ifa_scope == RT_SCOPE_LINK && |
426 | !net_netlink_address_tentative(current_header)) | 428 | !net_netlink_address_tentative(current_header)) |
427 | found = 1; | 429 | found = 1; |
428 | } | 430 | } |
429 | break; | 431 | break; |
430 | case NLMSG_NOOP: | 432 | case NLMSG_NOOP: |
431 | break; | 433 | break; |
432 | case NLMSG_DONE: | 434 | case NLMSG_DONE: |
433 | all_parts_processed = 1; | 435 | all_parts_processed = 1; |
434 | break; | 436 | break; |
435 | case NLMSG_ERROR: { | 437 | case NLMSG_ERROR: { |
436 | struct nlmsgerr *err = NLMSG_DATA(current_header); | 438 | struct nlmsgerr *err = NLMSG_DATA(current_header); |
437 | fprintf(stderr, "Netlink error: %d\n", err->error); | 439 | fprintf(stderr, "Netlink error: %d\n", err->error); |
438 | exit(1); | 440 | exit(1); |
439 | } | 441 | } |
440 | break; | 442 | break; |
441 | default: | 443 | default: |
442 | fprintf(stderr, "Unknown netlink message type: %u\n", current_header->nlmsg_type); | 444 | fprintf(stderr, "Unknown netlink message type: %u\n", current_header->nlmsg_type); |
443 | exit(1); | 445 | exit(1); |
444 | break; | 446 | break; |
445 | } | 447 | } |
446 | 448 | ||
447 | current_header = NLMSG_NEXT(current_header, len); | 449 | current_header = NLMSG_NEXT(current_header, len); |
448 | } | 450 | } |
449 | } | 451 | } |
450 | 452 | ||
451 | return found; | 453 | return found; |
452 | } | 454 | } |
453 | 455 | ||
454 | // wait for a link-local IPv6 address for DHCPv6 | 456 | // wait for a link-local IPv6 address for DHCPv6 |
@@ -468,27 +470,31 @@ void net_if_waitll(const char *ifname) { | |||
468 | perror("ioctl SIOGIFINDEX"); | 470 | perror("ioctl SIOGIFINDEX"); |
469 | exit(1); | 471 | exit(1); |
470 | } | 472 | } |
471 | close(inet6_sock); | 473 | close(inet6_sock); |
472 | int index = ifr.ifr_ifindex; | 474 | if (ifr.ifr_ifindex < 0) { |
475 | fprintf(stderr, "Error fnet: interface index is negative\n"); | ||
476 | exit(1); | ||
477 | } | ||
478 | uint32_t index = (uint32_t) ifr.ifr_ifindex; | ||
473 | 479 | ||
474 | // poll for link-local address | 480 | // poll for link-local address |
475 | int netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); | 481 | int netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); |
476 | if (netlink_sock < 0) | 482 | if (netlink_sock < 0) |
477 | errExit("socket"); | 483 | errExit("socket"); |
478 | int tries = 0; | 484 | int tries = 0; |
479 | int found = 0; | 485 | int found = 0; |
480 | while (tries < 60 && !found) { | 486 | while (tries < 60 && !found) { |
481 | if (tries >= 1) | 487 | if (tries >= 1) |
482 | usleep(500000); | 488 | usleep(500000); |
483 | 489 | ||
484 | found = net_netlink_if_has_ll(netlink_sock, index); | 490 | found = net_netlink_if_has_ll(netlink_sock, index); |
485 | 491 | ||
486 | tries++; | 492 | tries++; |
487 | } | 493 | } |
488 | close(netlink_sock); | 494 | close(netlink_sock); |
489 | 495 | ||
490 | if (!found) { | 496 | if (!found) { |
491 | fprintf(stderr, "Waiting for link-local IPv6 address of %s timed out\n", ifname); | 497 | fprintf(stderr, "Waiting for link-local IPv6 address of %s timed out\n", ifname); |
492 | exit(1); | 498 | exit(1); |
493 | } | 499 | } |
494 | } | 500 | } |
diff --git a/src/include/rundefs.h b/src/include/rundefs.h index b33d1f8c1..7f9c68be2 100644 --- a/src/include/rundefs.h +++ b/src/include/rundefs.h | |||
@@ -49,11 +49,12 @@ | |||
49 | #define RUN_LIB_DIR RUN_MNT_DIR "/lib" | 49 | #define RUN_LIB_DIR RUN_MNT_DIR "/lib" |
50 | #define RUN_LIB_FILE RUN_MNT_DIR "/libfiles" | 50 | #define RUN_LIB_FILE RUN_MNT_DIR "/libfiles" |
51 | #define RUN_DNS_ETC RUN_MNT_DIR "/dns-etc" | 51 | #define RUN_DNS_ETC RUN_MNT_DIR "/dns-etc" |
52 | #define RUN_DHCLIENT_DIR RUN_MNT_DIR "/dhclient" | 52 | #define RUN_DHCLIENT_DIR RUN_MNT_DIR "/dhclient" |
53 | #define RUN_DHCLIENT_4_LEASES_FILE RUN_DHCLIENT_DIR "/dhclient.leases" | 53 | #define RUN_DHCLIENT_4_LEASES_FILE RUN_DHCLIENT_DIR "/dhclient.leases" |
54 | #define RUN_DHCLIENT_6_LEASES_FILE RUN_DHCLIENT_DIR "/dhclient6.leases" | 54 | #define RUN_DHCLIENT_6_LEASES_FILE RUN_DHCLIENT_DIR "/dhclient6.leases" |
55 | #define RUN_DHCLIENT_4_PID_FILE RUN_DHCLIENT_DIR "/dhclient.pid" | 55 | #define RUN_DHCLIENT_4_LEASES_FILE RUN_DHCLIENT_DIR "/dhclient.leases" |
56 | #define RUN_DHCLIENT_6_PID_FILE RUN_DHCLIENT_DIR "/dhclient6.pid" | 56 | #define RUN_DHCLIENT_4_PID_FILE RUN_DHCLIENT_DIR "/dhclient.pid" |
57 | #define RUN_DHCLIENT_6_PID_FILE RUN_DHCLIENT_DIR "/dhclient6.pid" | ||
57 | 58 | ||
58 | #define RUN_SECCOMP_DIR RUN_MNT_DIR "/seccomp" | 59 | #define RUN_SECCOMP_DIR RUN_MNT_DIR "/seccomp" |
59 | #define RUN_SECCOMP_LIST RUN_SECCOMP_DIR "/seccomp.list" // list of seccomp files installed | 60 | #define RUN_SECCOMP_LIST RUN_SECCOMP_DIR "/seccomp.list" // list of seccomp files installed |
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt index 719a80c2c..84aed41a4 100644 --- a/src/man/firejail-profile.txt +++ b/src/man/firejail-profile.txt | |||
@@ -582,6 +582,33 @@ net eth0 | |||
582 | ip none | 582 | ip none |
583 | 583 | ||
584 | .TP | 584 | .TP |
585 | \fBip dhcp | ||
586 | Acquire an IP address and default gateway for the last interface defined by a | ||
587 | net command, as well as set the DNS servers according to the DHCP response. | ||
588 | This command requires the ISC dhclient DHCP client to be installed and will start | ||
589 | it automatically inside the sandbox. | ||
590 | .br | ||
591 | |||
592 | .br | ||
593 | Example: | ||
594 | .br | ||
595 | net br0 | ||
596 | .br | ||
597 | ip dhcp | ||
598 | .br | ||
599 | |||
600 | .br | ||
601 | This command should not be used in conjunction with the dns command if the | ||
602 | DHCP server is set to configure DNS servers for the clients, because the | ||
603 | manually specified DNS servers will be overwritten. | ||
604 | |||
605 | .br | ||
606 | The DHCP client will NOT release the DHCP lease when the sandbox terminates. | ||
607 | If your DHCP server requires leases to be explicitly released, consider running | ||
608 | a DHCP client and releasing the lease manually in conjunction with the | ||
609 | net none command. | ||
610 | |||
611 | .TP | ||
585 | \fBip6 address | 612 | \fBip6 address |
586 | Assign IPv6 addresses to the last network interface defined by a net command. | 613 | Assign IPv6 addresses to the last network interface defined by a net command. |
587 | .br | 614 | .br |
@@ -594,6 +621,32 @@ net eth0 | |||
594 | ip6 2001:0db8:0:f101::1/64 | 621 | ip6 2001:0db8:0:f101::1/64 |
595 | 622 | ||
596 | .TP | 623 | .TP |
624 | \fBip6 dhcp | ||
625 | Acquire an IPv6 address and default gateway for the last interface defined by a | ||
626 | net command, as well as set the DNS servers according to the DHCP response. | ||
627 | This command requires the ISC dhclient DHCP client to be installed and will start | ||
628 | it automatically inside the sandbox. | ||
629 | .br | ||
630 | |||
631 | .br | ||
632 | Example: | ||
633 | .br | ||
634 | net br0 | ||
635 | .br | ||
636 | ip6 dhcp | ||
637 | .br | ||
638 | |||
639 | .br | ||
640 | This command should not be used in conjunction with the dns command if the | ||
641 | DHCP server is set to configure DNS servers for the clients, because the | ||
642 | manually specified DNS servers will be overwritten. | ||
643 | |||
644 | .br | ||
645 | The DHCP client will NOT release the DHCP lease when the sandbox terminates. | ||
646 | If your DHCP server requires leases to be explicitly released, consider running | ||
647 | a DHCP client and releasing the lease manually. | ||
648 | |||
649 | .TP | ||
597 | \fBiprange address,address | 650 | \fBiprange address,address |
598 | Assign an IP address in the provided range to the last network | 651 | Assign an IP address in the provided range to the last network |
599 | interface defined by a net command. A default gateway is assigned by default. | 652 | interface defined by a net command. A default gateway is assigned by default. |
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index e5abcdcf5..4b1134686 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -567,6 +567,31 @@ If the corresponding interface doesn't have an IP address configured, this | |||
567 | option is enabled by default. | 567 | option is enabled by default. |
568 | 568 | ||
569 | .TP | 569 | .TP |
570 | \fB\-\-ip=dhcp | ||
571 | Acquire an IP address and default gateway for the last interface defined by a | ||
572 | \-\-net option, as well as set the DNS servers according to the DHCP response. | ||
573 | This option requires the ISC dhclient DHCP client to be installed and will start | ||
574 | it automatically inside the sandbox. | ||
575 | .br | ||
576 | |||
577 | .br | ||
578 | Example: | ||
579 | .br | ||
580 | $ firejail \-\-net=br0 \-\-ip=dhcp | ||
581 | .br | ||
582 | |||
583 | .br | ||
584 | This option should not be used in conjunction with the \-\-dns option if the | ||
585 | DHCP server is set to configure DNS servers for the clients, because the | ||
586 | manually specified DNS servers will be overwritten. | ||
587 | |||
588 | .br | ||
589 | The DHCP client will NOT release the DHCP lease when the sandbox terminates. | ||
590 | If your DHCP server requires leases to be explicitly released, consider running | ||
591 | a DHCP client and releasing the lease manually in conjunction with the | ||
592 | \-\-net=none option. | ||
593 | |||
594 | .TP | ||
570 | \fB\-\-ip6=address | 595 | \fB\-\-ip6=address |
571 | Assign IPv6 addresses to the last network interface defined by a \-\-net option. | 596 | Assign IPv6 addresses to the last network interface defined by a \-\-net option. |
572 | .br | 597 | .br |
@@ -579,6 +604,30 @@ $ firejail \-\-net=eth0 \-\-ip6=2001:0db8:0:f101::1/64 firefox | |||
579 | Note: you don't need this option if you obtain your ip6 address from router via SLAAC (your ip6 address and default route will be configured by kernel automatically). | 604 | Note: you don't need this option if you obtain your ip6 address from router via SLAAC (your ip6 address and default route will be configured by kernel automatically). |
580 | 605 | ||
581 | .TP | 606 | .TP |
607 | \fB\-\-ip6=dhcp | ||
608 | Acquire an IPv6 address and default gateway for the last interface defined by a | ||
609 | \-\-net option, as well as set the DNS servers according to the DHCP response. | ||
610 | This option requires the ISC dhclient DHCP client to be installed and will start | ||
611 | it automatically inside the sandbox. | ||
612 | .br | ||
613 | |||
614 | .br | ||
615 | Example: | ||
616 | .br | ||
617 | $ firejail \-\-net=br0 \-\-ip6=dhcp | ||
618 | .br | ||
619 | |||
620 | .br | ||
621 | This option should not be used in conjunction with the \-\-dns option if the | ||
622 | DHCP server is set to configure DNS servers for the clients, because the | ||
623 | manually specified DNS servers will be overwritten. | ||
624 | |||
625 | .br | ||
626 | The DHCP client will NOT release the DHCP lease when the sandbox terminates. | ||
627 | If your DHCP server requires leases to be explicitly released, consider running | ||
628 | a DHCP client and releasing the lease manually. | ||
629 | |||
630 | .TP | ||
582 | \fB\-\-iprange=address,address | 631 | \fB\-\-iprange=address,address |
583 | Assign an IP address in the provided range to the last network interface defined by a \-\-net option. A | 632 | Assign an IP address in the provided range to the last network interface defined by a \-\-net option. A |
584 | default gateway is assigned by default. | 633 | default gateway is assigned by default. |