aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2016-10-30 15:54:05 -0400
committerLibravatar netblue30 <netblue30@yahoo.com>2016-10-30 15:54:05 -0400
commitf898290fd79e0e64d13ceef56fc5960da879d179 (patch)
tree7112345d8121d1d61f90995e09754bbfbfbf467f
parentMerge pull request #878 from msva/patch-1 (diff)
downloadfirejail-f898290fd79e0e64d13ceef56fc5960da879d179.tar.gz
firejail-f898290fd79e0e64d13ceef56fc5960da879d179.tar.zst
firejail-f898290fd79e0e64d13ceef56fc5960da879d179.zip
major cleanup
-rw-r--r--.gitignore1
-rw-r--r--README2
-rw-r--r--src/firejail/appimage.c5
-rw-r--r--src/firejail/arp.c186
-rw-r--r--src/firejail/firejail.h31
-rw-r--r--src/firejail/fs.c198
-rw-r--r--src/firejail/fs_bin.c1
-rw-r--r--src/firejail/fs_dev.c2
-rw-r--r--src/firejail/fs_etc.c1
-rw-r--r--src/firejail/fs_home.c6
-rw-r--r--src/firejail/fs_hostname.c2
-rw-r--r--src/firejail/fs_trace.c3
-rw-r--r--src/firejail/fs_var.c3
-rw-r--r--src/firejail/fs_whitelist.c4
-rw-r--r--src/firejail/main.c50
-rw-r--r--src/firejail/network.c303
-rw-r--r--src/firejail/network_main.c27
-rw-r--r--src/firejail/preproc.c110
-rw-r--r--src/firejail/protocol.c2
-rw-r--r--src/firejail/pulseaudio.c1
-rw-r--r--src/firejail/restrict_users.c3
-rw-r--r--src/firejail/sandbox.c285
-rw-r--r--src/firejail/sbox.c23
-rw-r--r--src/firejail/seccomp.c1
-rw-r--r--src/firejail/util.c34
-rw-r--r--src/fnet/arp.c208
-rw-r--r--src/fnet/fnet.h9
-rw-r--r--src/fnet/interface.c212
-rw-r--r--src/fnet/main.c39
-rw-r--r--src/fseccomp/main.c6
30 files changed, 869 insertions, 889 deletions
diff --git a/.gitignore b/.gitignore
index 6acb6775c..db523da59 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,4 +19,5 @@ src/ftee/ftee
19src/tags 19src/tags
20src/faudit/faudit 20src/faudit/faudit
21src/fnet/fnet 21src/fnet/fnet
22src/fseccomp/fseccomp
22uids.h 23uids.h
diff --git a/README b/README
index cbd15f02a..f0e2ea3e8 100644
--- a/README
+++ b/README
@@ -86,6 +86,8 @@ valoq (https://github.com/valoq)
86 - added support for /srv in --whitelist feature 86 - added support for /srv in --whitelist feature
87 - Eye of GNOME and Evolution profiles 87 - Eye of GNOME and Evolution profiles
88 - blacklist suid binaries in disable-common.inc 88 - blacklist suid binaries in disable-common.inc
89Vadim A. Misbakh-Soloviov (https://github.com/msva)
90 - profile fixes
89Rafael Cavalcanti (https://github.com/rccavalcanti) 91Rafael Cavalcanti (https://github.com/rccavalcanti)
90 - chromium profile fixes for Arch Linux 92 - chromium profile fixes for Arch Linux
91Deelvesh Bunjun (https://github.com/DeelveshBunjun) 93Deelvesh Bunjun (https://github.com/DeelveshBunjun)
diff --git a/src/firejail/appimage.c b/src/firejail/appimage.c
index 09b242964..322798ee5 100644
--- a/src/firejail/appimage.c
+++ b/src/firejail/appimage.c
@@ -60,11 +60,6 @@ void appimage_set(const char *appimage_path) {
60 exit(1); 60 exit(1);
61 } 61 }
62 62
63 // populate /run/firejail directory
64 EUID_ROOT();
65 fs_build_firejail_dir();
66 EUID_USER();
67
68 // find or allocate a free loop device to use 63 // find or allocate a free loop device to use
69 EUID_ROOT(); 64 EUID_ROOT();
70 int cfd = open("/dev/loop-control", O_RDWR); 65 int cfd = open("/dev/loop-control", O_RDWR);
diff --git a/src/firejail/arp.c b/src/firejail/arp.c
index fb5e426b0..ddb75905f 100644
--- a/src/firejail/arp.c
+++ b/src/firejail/arp.c
@@ -40,6 +40,7 @@ typedef struct arp_hdr_t {
40 uint8_t target_ip[4]; 40 uint8_t target_ip[4];
41} ArpHdr; 41} ArpHdr;
42 42
43
43// returns 0 if the address is not in use, -1 otherwise 44// returns 0 if the address is not in use, -1 otherwise
44int arp_check(const char *dev, uint32_t destaddr, uint32_t srcaddr) { 45int arp_check(const char *dev, uint32_t destaddr, uint32_t srcaddr) {
45 if (strlen(dev) > IFNAMSIZ) { 46 if (strlen(dev) > IFNAMSIZ) {
@@ -286,189 +287,4 @@ uint32_t arp_assign(const char *dev, Bridge *br) {
286 return ip; 287 return ip;
287} 288}
288 289
289// scan interface (--scan option)
290void arp_scan(const char *dev, uint32_t ifip, uint32_t ifmask) {
291 assert(dev);
292 assert(ifip);
293
294// printf("Scanning interface %s (%d.%d.%d.%d/%d)\n",
295// dev, PRINT_IP(ifip & ifmask), mask2bits(ifmask));
296
297 if (strlen(dev) > IFNAMSIZ) {
298 fprintf(stderr, "Error: invalid network device name %s\n", dev);
299 exit(1);
300 }
301
302 // find interface mac address
303 int sock;
304 if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
305 errExit("socket");
306 struct ifreq ifr;
307 memset(&ifr, 0, sizeof (ifr));
308 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
309 if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
310 errExit("ioctl");
311 close(sock);
312 uint8_t mac[6];
313 memcpy (mac, ifr.ifr_hwaddr.sa_data, 6);
314
315 // open layer2 socket
316 if ((sock = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0)
317 errExit("socket");
318
319 // try all possible ip addresses in ascending order
320 uint32_t range = ~ifmask + 1; // the number of potential addresses
321 // this software is not supported for /31 networks
322 if (range < 4) {
323 fprintf(stderr, "Warning: this option is not supported for /31 networks\n");
324 close(sock);
325 return;
326 }
327
328 uint32_t dest = (ifip & ifmask) + 1;
329 uint32_t last = dest + range - 1;
330 uint32_t src = htonl(ifip);
331
332 // wait not more than one second for an answer
333 int header_printed = 0;
334 uint32_t last_ip = 0;
335 struct timeval ts;
336 ts.tv_sec = 2; // 2 seconds receive timeout
337 ts.tv_usec = 0;
338
339 while (1) {
340 fd_set rfds;
341 FD_ZERO(&rfds);
342 FD_SET(sock, &rfds);
343 fd_set wfds;
344 FD_ZERO(&wfds);
345 FD_SET(sock, &wfds);
346 int maxfd = sock;
347
348 uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc
349 memset(frame, 0, ETH_FRAME_LEN);
350
351 int nready;
352 if (dest < last)
353 nready = select(maxfd + 1, &rfds, &wfds, (fd_set *) 0, NULL);
354 else
355 nready = select(maxfd + 1, &rfds, (fd_set *) 0, (fd_set *) 0, &ts);
356
357 if (nready < 0)
358 errExit("select");
359
360 if (nready == 0) { // timeout
361 break;
362 }
363
364 if (FD_ISSET(sock, &wfds) && dest < last) {
365 // configure layer2 socket address information
366 struct sockaddr_ll addr;
367 memset(&addr, 0, sizeof(addr));
368 if ((addr.sll_ifindex = if_nametoindex(dev)) == 0)
369 errExit("if_nametoindex");
370 addr.sll_family = AF_PACKET;
371 memcpy (addr.sll_addr, mac, 6);
372 addr.sll_halen = htons(6);
373
374 // build the arp packet header
375 ArpHdr hdr;
376 memset(&hdr, 0, sizeof(hdr));
377 hdr.htype = htons(1);
378 hdr.ptype = htons(ETH_P_IP);
379 hdr.hlen = 6;
380 hdr.plen = 4;
381 hdr.opcode = htons(1); //ARPOP_REQUEST
382 memcpy(hdr.sender_mac, mac, 6);
383 memcpy(hdr.sender_ip, (uint8_t *)&src, 4);
384 uint32_t dst = htonl(dest);
385 memcpy(hdr.target_ip, (uint8_t *)&dst, 4);
386
387 // build ethernet frame
388 uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc
389 memset(frame, 0, sizeof(frame));
390 frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff;
391 memcpy(frame + 6, mac, 6);
392 frame[12] = ETH_P_ARP / 256;
393 frame[13] = ETH_P_ARP % 256;
394 memcpy (frame + 14, &hdr, sizeof(hdr));
395
396 // send packet
397 int len;
398 if ((len = sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr))) <= 0)
399 errExit("send");
400//printf("send %d bytes to %d.%d.%d.%d\n", len, PRINT_IP(dest));
401 fflush(0);
402 dest++;
403 }
404
405 if (FD_ISSET(sock, &rfds)) {
406 // read the incoming packet
407 int len = recvfrom(sock, frame, ETH_FRAME_LEN, 0, NULL, NULL);
408 if (len < 0) {
409 perror("recvfrom");
410 }
411
412 // parse the incoming packet
413 if ((unsigned int) len < 14 + sizeof(ArpHdr))
414 continue;
415
416 // look only at ARP packets
417 if (frame[12] != (ETH_P_ARP / 256) || frame[13] != (ETH_P_ARP % 256))
418 continue;
419
420 ArpHdr hdr;
421 memcpy(&hdr, frame + 14, sizeof(ArpHdr));
422
423 if (hdr.opcode == htons(2)) {
424 // check my mac and my address
425 if (memcmp(mac, hdr.target_mac, 6) != 0)
426 continue;
427 uint32_t ip;
428 memcpy(&ip, hdr.target_ip, 4);
429 if (ip != src)
430 continue;
431 memcpy(&ip, hdr.sender_ip, 4);
432 ip = ntohl(ip);
433
434 if (ip == last_ip) // filter duplicates
435 continue;
436 last_ip = ip;
437
438 // printing
439 if (header_printed == 0) {
440 printf(" Network scan:\n");
441
442 // print parent interface
443 if (cfg.bridge0.configured && cfg.bridge0.ip && cfg.bridge0.macvlan &&
444 (cfg.bridge0.ip & cfg.bridge0.mask) == (ifip & cfg.bridge0.mask))
445 printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
446 PRINT_MAC(cfg.bridge0.mac), PRINT_IP(cfg.bridge0.ip));
447
448 if (cfg.bridge1.configured && cfg.bridge1.ip && cfg.bridge1.macvlan &&
449 (cfg.bridge1.ip & cfg.bridge1.mask) == (ifip & cfg.bridge1.mask))
450 printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
451 PRINT_MAC(cfg.bridge1.mac), PRINT_IP(cfg.bridge1.ip));
452
453 if (cfg.bridge2.configured && cfg.bridge2.ip && cfg.bridge2.macvlan &&
454 (cfg.bridge2.ip & cfg.bridge2.mask) == (ifip & cfg.bridge2.mask))
455 printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
456 PRINT_MAC(cfg.bridge2.mac), PRINT_IP(cfg.bridge2.ip));
457
458 if (cfg.bridge3.configured && cfg.bridge3.ip && cfg.bridge3.macvlan &&
459 (cfg.bridge3.ip & cfg.bridge3.mask) == (ifip & cfg.bridge3.mask))
460 printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
461 PRINT_MAC(cfg.bridge3.mac), PRINT_IP(cfg.bridge3.ip));
462
463 header_printed = 1;
464 }
465 printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
466 PRINT_MAC(hdr.sender_mac), PRINT_IP(ip));
467 }
468 }
469 }
470
471 close(sock);
472}
473
474 290
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 749656f8b..dcec160fb 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -363,20 +363,19 @@ void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu);
363void net_if_ip6(const char *ifname, const char *addr6); 363void net_if_ip6(const char *ifname, const char *addr6);
364int net_get_if_addr(const char *bridge, uint32_t *ip, uint32_t *mask, uint8_t mac[6], int *mtu); 364int net_get_if_addr(const char *bridge, uint32_t *ip, uint32_t *mask, uint8_t mac[6], int *mtu);
365int net_add_route(uint32_t dest, uint32_t mask, uint32_t gw); 365int net_add_route(uint32_t dest, uint32_t mask, uint32_t gw);
366void net_ifprint(void);
367uint32_t network_get_defaultgw(void); 366uint32_t network_get_defaultgw(void);
368int net_config_mac(const char *ifname, const unsigned char mac[6]); 367int net_config_mac(const char *ifname, const unsigned char mac[6]);
369int net_get_mac(const char *ifname, unsigned char mac[6]); 368int net_get_mac(const char *ifname, unsigned char mac[6]);
369void net_config_interface(const char *dev, uint32_t ip, uint32_t mask, int mtu);
370
371// preproc.c
372void preproc_build_firejail_dir(void);
373void preproc_mount_mnt_dir(void);
374void preproc_build_cp_command(void);
375void preproc_delete_cp_command(void) ;
376void preproc_remount_mnt_dir(void);
370 377
371// fs.c 378// fs.c
372// build /run/firejail directory
373void fs_build_firejail_dir(void);
374// build /run/firejail/mnt directory
375void fs_build_mnt_dir(void);
376// grab a copy of cp command
377void fs_build_cp_command(void);
378// delete the temporary cp command
379void fs_delete_cp_command(void) ;
380// blacklist files or directoies by mounting empty files on top of them 379// blacklist files or directoies by mounting empty files on top of them
381void fs_blacklist(void); 380void fs_blacklist(void);
382// remount a directory read-only 381// remount a directory read-only
@@ -393,7 +392,6 @@ void fs_overlayfs(void);
393// chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf 392// chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf
394void fs_chroot(const char *rootdir); 393void fs_chroot(const char *rootdir);
395int fs_check_chroot_dir(const char *rootdir); 394int fs_check_chroot_dir(const char *rootdir);
396void fs_private_tmp(void);
397 395
398// profile.c 396// profile.c
399// find and read the profile specified by name from dir directory 397// find and read the profile specified by name from dir directory
@@ -430,8 +428,6 @@ int restricted_shell(const char *user);
430int arp_check(const char *dev, uint32_t destaddr, uint32_t srcaddr); 428int arp_check(const char *dev, uint32_t destaddr, uint32_t srcaddr);
431// assign an IP address using arp scanning 429// assign an IP address using arp scanning
432uint32_t arp_assign(const char *dev, Bridge *br); 430uint32_t arp_assign(const char *dev, Bridge *br);
433// scan interface (--scan option)
434void arp_scan(const char *dev, uint32_t srcaddr, uint32_t srcmask);
435 431
436// util.c 432// util.c
437void drop_privs(int nogroups); 433void drop_privs(int nogroups);
@@ -459,6 +455,8 @@ void invalid_filename(const char *fname);
459uid_t get_group_id(const char *group); 455uid_t get_group_id(const char *group);
460int remove_directory(const char *path); 456int remove_directory(const char *path);
461void flush_stdin(void); 457void flush_stdin(void);
458void create_empty_dir_as_root(const char *dir, mode_t mode);
459void create_empty_file_as_root(const char *dir, mode_t mode);
462 460
463// fs_var.c 461// fs_var.c
464void fs_var_log(void); // mounting /var/log 462void fs_var_log(void); // mounting /var/log
@@ -687,10 +685,11 @@ void build_cmdline(char **command_line, char **window_title, int argc, char **ar
687#define PATH_FIREMON (PREFIX "/bin/firemon") 685#define PATH_FIREMON (PREFIX "/bin/firemon")
688#define PATH_FSECCOMP (LIBDIR "/firejail/fseccomp") 686#define PATH_FSECCOMP (LIBDIR "/firejail/fseccomp")
689// bitmapped filters for sbox_run 687// bitmapped filters for sbox_run
690#define SBOX_ROOT 1 688#define SBOX_ROOT (1 << 0)
691#define SBOX_USER 2 689#define SBOX_USER (1 << 1)
692#define SBOX_CAPS 4 690#define SBOX_SECCOMP (1 << 2)
693#define SBOX_SECCOMP 8 691#define SBOX_CAPS_NONE (1 << 3) // drop all capabilities
692#define SBOX_CAPS_NETWORK (1 << 4) // caps filter for programs running network programs
694// run sbox 693// run sbox
695int sbox_run(unsigned filter, int num, ...); 694int sbox_run(unsigned filter, int num, ...);
696 695
diff --git a/src/firejail/fs.c b/src/firejail/fs.c
index 572b08205..f7fc44c71 100644
--- a/src/firejail/fs.c
+++ b/src/firejail/fs.c
@@ -29,155 +29,8 @@
29 29
30static void fs_rdwr(const char *dir); 30static void fs_rdwr(const char *dir);
31 31
32static void create_dir_as_root(const char *dir, mode_t mode) {
33 assert(dir);
34 if (arg_debug)
35 printf("Creating %s directory\n", dir);
36
37 if (mkdir(dir, mode) == -1)
38 errExit("mkdir");
39 if (chmod(dir, mode) == -1)
40 errExit("chmod");
41
42 ASSERT_PERMS(dir, 0, 0, mode);
43}
44
45static void create_empty_dir(void) {
46 struct stat s;
47
48 if (stat(RUN_RO_DIR, &s)) {
49 /* coverity[toctou] */
50 if (mkdir(RUN_RO_DIR, S_IRUSR | S_IXUSR) == -1)
51 errExit("mkdir");
52 if (chmod(RUN_RO_DIR, S_IRUSR | S_IXUSR) == -1)
53 errExit("chmod");
54 ASSERT_PERMS(RUN_RO_DIR, 0, 0, S_IRUSR | S_IXUSR);
55 }
56}
57
58static void create_empty_file(void) {
59 struct stat s;
60
61 if (stat(RUN_RO_FILE, &s)) {
62 /* coverity[toctou] */
63 FILE *fp = fopen(RUN_RO_FILE, "w");
64 if (!fp)
65 errExit("fopen");
66
67 SET_PERMS_STREAM(fp, 0, 0, S_IRUSR);
68 fclose(fp);
69 }
70}
71
72// build /run/firejail directory
73void fs_build_firejail_dir(void) {
74 struct stat s;
75
76 // CentOS 6 doesn't have /run directory
77 if (stat(RUN_FIREJAIL_BASEDIR, &s)) {
78 create_dir_as_root(RUN_FIREJAIL_BASEDIR, 0755);
79 }
80
81 // check /run/firejail directory belongs to root end exit if doesn't!
82 if (stat(RUN_FIREJAIL_DIR, &s) == 0) {
83 if (s.st_uid != 0 || s.st_gid != 0) {
84 fprintf(stderr, "Error: non-root %s directory, exiting...\n", RUN_FIREJAIL_DIR);
85 exit(1);
86 }
87 }
88 else {
89 create_dir_as_root(RUN_FIREJAIL_DIR, 0755);
90 }
91
92 if (stat(RUN_FIREJAIL_NETWORK_DIR, &s)) {
93 create_dir_as_root(RUN_FIREJAIL_NETWORK_DIR, 0755);
94 }
95
96 if (stat(RUN_FIREJAIL_BANDWIDTH_DIR, &s)) {
97 create_dir_as_root(RUN_FIREJAIL_BANDWIDTH_DIR, 0755);
98 }
99
100 if (stat(RUN_FIREJAIL_NAME_DIR, &s)) {
101 create_dir_as_root(RUN_FIREJAIL_NAME_DIR, 0755);
102 }
103
104 if (stat(RUN_FIREJAIL_X11_DIR, &s)) {
105 create_dir_as_root(RUN_FIREJAIL_X11_DIR, 0755);
106 }
107
108 if (stat(RUN_FIREJAIL_APPIMAGE_DIR, &s)) {
109 create_dir_as_root(RUN_FIREJAIL_APPIMAGE_DIR, 0755);
110 }
111
112 create_empty_dir();
113 create_empty_file();
114}
115 32
116 33
117// build /run/firejail/mnt directory
118static int tmpfs_mounted = 0;
119#ifdef HAVE_CHROOT
120static void fs_build_remount_mnt_dir(void) {
121 tmpfs_mounted = 0;
122 fs_build_mnt_dir();
123}
124#endif
125
126void fs_build_mnt_dir(void) {
127 struct stat s;
128 fs_build_firejail_dir();
129
130 // create /run/firejail/mnt directory
131 if (stat(RUN_MNT_DIR, &s)) {
132 create_dir_as_root(RUN_MNT_DIR, 0755);
133 }
134
135 // ... and mount tmpfs on top of it
136 if (!tmpfs_mounted) {
137 // mount tmpfs on top of /run/firejail/mnt
138 if (arg_debug)
139 printf("Mounting tmpfs on %s directory\n", RUN_MNT_DIR);
140 if (mount("tmpfs", RUN_MNT_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
141 errExit("mounting /run/firejail/mnt");
142 tmpfs_mounted = 1;
143 fs_logger2("tmpfs", RUN_MNT_DIR);
144 }
145}
146
147// grab a copy of cp command
148void fs_build_cp_command(void) {
149 struct stat s;
150 fs_build_mnt_dir();
151 if (stat(RUN_CP_COMMAND, &s)) {
152 char* fname = realpath("/bin/cp", NULL);
153 if (fname == NULL) {
154 fprintf(stderr, "Error: /bin/cp not found\n");
155 exit(1);
156 }
157 if (stat(fname, &s)) {
158 fprintf(stderr, "Error: /bin/cp not found\n");
159 exit(1);
160 }
161 if (is_link(fname)) {
162 fprintf(stderr, "Error: invalid /bin/cp file\n");
163 exit(1);
164 }
165 int rv = copy_file(fname, RUN_CP_COMMAND, 0, 0, 0755);
166 if (rv) {
167 fprintf(stderr, "Error: cannot access /bin/cp\n");
168 exit(1);
169 }
170 ASSERT_PERMS(RUN_CP_COMMAND, 0, 0, 0755);
171
172 free(fname);
173 }
174}
175
176// delete the temporary cp command
177void fs_delete_cp_command(void) {
178 unlink(RUN_CP_COMMAND);
179}
180
181//*********************************************** 34//***********************************************
182// process profile file 35// process profile file
183//*********************************************** 36//***********************************************
@@ -202,9 +55,6 @@ static void disable_file(OPERATION op, const char *filename) {
202 assert(op <OPERATION_MAX); 55 assert(op <OPERATION_MAX);
203 last_disable = UNSUCCESSFUL; 56 last_disable = UNSUCCESSFUL;
204 57
205 // rebuild /run/firejail directory in case tmpfs was mounted on top of /run
206 fs_build_firejail_dir();
207
208 // Resolve all symlinks 58 // Resolve all symlinks
209 char* fname = realpath(filename, NULL); 59 char* fname = realpath(filename, NULL);
210 if (fname == NULL && errno != EACCES) { 60 if (fname == NULL && errno != EACCES) {
@@ -868,9 +718,6 @@ void fs_overlayfs(void) {
868 if (major == 3 && minor < 18) 718 if (major == 3 && minor < 18)
869 oldkernel = 1; 719 oldkernel = 1;
870 720
871 // build overlay directories
872 fs_build_mnt_dir();
873
874 char *oroot; 721 char *oroot;
875 if(asprintf(&oroot, "%s/oroot", RUN_MNT_DIR) == -1) 722 if(asprintf(&oroot, "%s/oroot", RUN_MNT_DIR) == -1)
876 errExit("asprintf"); 723 errExit("asprintf");
@@ -1194,17 +1041,33 @@ void fs_chroot(const char *rootdir) {
1194 free(newx11); 1041 free(newx11);
1195 } 1042 }
1196 1043
1197 // some older distros don't have a /run directory 1044 // create /run/firejail directory in chroot
1198 // create one by default
1199 // no exit on error, let the user deal with any problems
1200 char *rundir; 1045 char *rundir;
1201 if (asprintf(&rundir, "%s/run", rootdir) == -1) 1046 if (asprintf(&rundir, "%s/run", rootdir) == -1)
1202 errExit("asprintf"); 1047 errExit("asprintf");
1203 if (!is_dir(rundir)) { 1048 create_empty_dir_as_root(rundir, 0755);
1204 int rv = mkdir(rundir, 0755); 1049 free(rundir);
1205 (void) rv; 1050 if (asprintf(&rundir, "%s/run/firejail", rootdir) == -1)
1206 rv = chown(rundir, 0, 0); 1051 errExit("asprintf");
1207 (void) rv; 1052 create_empty_dir_as_root(rundir, 0755);
1053 free(rundir);
1054
1055 // create /run/firejail/mnt directory in chroot and mount a tmpfs
1056 if (asprintf(&rundir, "%s/run/firejail/mnt", rootdir) == -1)
1057 errExit("asprintf");
1058 create_empty_dir_as_root(rundir, 0755);
1059 if (mount("tmpfs", rundir, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
1060 errExit("mounting /run/firejail/mnt");
1061 fs_logger2("tmpfs", RUN_MNT_DIR);
1062 free(rundir);
1063
1064 // retrieve seccomp.protocol
1065 struct stat s;
1066 if (stat(RUN_SECCOMP_PROTOCOL, &s) == 0) {
1067 if (asprintf(&rundir, "%s%s", rootdir, RUN_SECCOMP_PROTOCOL) == -1)
1068 errExit("asprintf");
1069 copy_file(RUN_SECCOMP_PROTOCOL, rundir, getuid(), getgid(), 0644);
1070 free(rundir);
1208 } 1071 }
1209 1072
1210 // copy /etc/resolv.conf in chroot directory 1073 // copy /etc/resolv.conf in chroot directory
@@ -1228,8 +1091,9 @@ void fs_chroot(const char *rootdir) {
1228 printf("Chrooting into %s\n", rootdir); 1091 printf("Chrooting into %s\n", rootdir);
1229 if (chroot(rootdir) < 0) 1092 if (chroot(rootdir) < 0)
1230 errExit("chroot"); 1093 errExit("chroot");
1231 // mount a new tmpfs in /run/firejail/mnt - the old one was lost in chroot 1094
1232 fs_build_remount_mnt_dir(); 1095 // create all other /run/firejail files and directories
1096 preproc_build_firejail_dir();
1233 1097
1234 if (checkcfg(CFG_CHROOT_DESKTOP)) { 1098 if (checkcfg(CFG_CHROOT_DESKTOP)) {
1235 // update /var directory in order to support multiple sandboxes running on the same root directory 1099 // update /var directory in order to support multiple sandboxes running on the same root directory
@@ -1254,12 +1118,4 @@ void fs_chroot(const char *rootdir) {
1254} 1118}
1255#endif 1119#endif
1256 1120
1257void fs_private_tmp(void) {
1258 // mount tmpfs on top of /run/firejail/mnt
1259 if (arg_debug)
1260 printf("Mounting tmpfs on /tmp directory\n");
1261 if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=1777,gid=0") < 0)
1262 errExit("mounting tmpfs on /tmp directory");
1263 fs_logger2("tmpfs", "/tmp");
1264}
1265 1121
diff --git a/src/firejail/fs_bin.c b/src/firejail/fs_bin.c
index ba0633649..f59944735 100644
--- a/src/firejail/fs_bin.c
+++ b/src/firejail/fs_bin.c
@@ -211,7 +211,6 @@ void fs_private_bin_list(void) {
211 assert(private_list); 211 assert(private_list);
212 212
213 // create /run/firejail/mnt/bin directory 213 // create /run/firejail/mnt/bin directory
214 fs_build_mnt_dir();
215 if (mkdir(RUN_BIN_DIR, 0755) == -1) 214 if (mkdir(RUN_BIN_DIR, 0755) == -1)
216 errExit("mkdir"); 215 errExit("mkdir");
217 if (chmod(RUN_BIN_DIR, 0755) == -1) 216 if (chmod(RUN_BIN_DIR, 0755) == -1)
diff --git a/src/firejail/fs_dev.c b/src/firejail/fs_dev.c
index 0186c6f82..ef5d67b55 100644
--- a/src/firejail/fs_dev.c
+++ b/src/firejail/fs_dev.c
@@ -129,8 +129,6 @@ void fs_private_dev(void){
129 printf("Mounting tmpfs on /dev\n"); 129 printf("Mounting tmpfs on /dev\n");
130 130
131 // create DRI_DIR 131 // create DRI_DIR
132 fs_build_mnt_dir();
133
134 // keep a copy of dev directory 132 // keep a copy of dev directory
135 if (mkdir(RUN_DEV_DIR, 0755) == -1) 133 if (mkdir(RUN_DEV_DIR, 0755) == -1)
136 errExit("mkdir"); 134 errExit("mkdir");
diff --git a/src/firejail/fs_etc.c b/src/firejail/fs_etc.c
index de29c312e..b86d5eb74 100644
--- a/src/firejail/fs_etc.c
+++ b/src/firejail/fs_etc.c
@@ -131,7 +131,6 @@ void fs_private_etc_list(void) {
131 } 131 }
132 132
133 // create /run/firejail/mnt/etc directory 133 // create /run/firejail/mnt/etc directory
134 fs_build_mnt_dir();
135 if (mkdir(RUN_ETC_DIR, 0755) == -1) 134 if (mkdir(RUN_ETC_DIR, 0755) == -1)
136 errExit("mkdir"); 135 errExit("mkdir");
137 if (chmod(RUN_ETC_DIR, 0755) == -1) 136 if (chmod(RUN_ETC_DIR, 0755) == -1)
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c
index 75cc3e732..a2532c367 100644
--- a/src/firejail/fs_home.c
+++ b/src/firejail/fs_home.c
@@ -104,8 +104,6 @@ static void skel(const char *homedir, uid_t u, gid_t g) {
104 104
105static int store_xauthority(void) { 105static int store_xauthority(void) {
106 // put a copy of .Xauthority in XAUTHORITY_FILE 106 // put a copy of .Xauthority in XAUTHORITY_FILE
107 fs_build_mnt_dir();
108
109 char *src; 107 char *src;
110 char *dest = RUN_XAUTHORITY_FILE; 108 char *dest = RUN_XAUTHORITY_FILE;
111 if (asprintf(&src, "%s/.Xauthority", cfg.homedir) == -1) 109 if (asprintf(&src, "%s/.Xauthority", cfg.homedir) == -1)
@@ -130,9 +128,6 @@ static int store_xauthority(void) {
130} 128}
131 129
132static int store_asoundrc(void) { 130static int store_asoundrc(void) {
133 // put a copy of .Xauthority in XAUTHORITY_FILE
134 fs_build_mnt_dir();
135
136 char *src; 131 char *src;
137 char *dest = RUN_ASOUNDRC_FILE; 132 char *dest = RUN_ASOUNDRC_FILE;
138 if (asprintf(&src, "%s/.asoundrc", cfg.homedir) == -1) 133 if (asprintf(&src, "%s/.asoundrc", cfg.homedir) == -1)
@@ -592,7 +587,6 @@ void fs_private_home_list(void) {
592 } 587 }
593 588
594 // create /run/firejail/mnt/home directory 589 // create /run/firejail/mnt/home directory
595 fs_build_mnt_dir();
596 int rv = mkdir(RUN_HOME_DIR, 0755); 590 int rv = mkdir(RUN_HOME_DIR, 0755);
597 if (rv == -1) 591 if (rv == -1)
598 errExit("mkdir"); 592 errExit("mkdir");
diff --git a/src/firejail/fs_hostname.c b/src/firejail/fs_hostname.c
index 87d3742e4..04197eb8f 100644
--- a/src/firejail/fs_hostname.c
+++ b/src/firejail/fs_hostname.c
@@ -27,7 +27,6 @@
27 27
28void fs_hostname(const char *hostname) { 28void fs_hostname(const char *hostname) {
29 struct stat s; 29 struct stat s;
30 fs_build_mnt_dir();
31 30
32 // create a new /etc/hostname 31 // create a new /etc/hostname
33 if (stat("/etc/hostname", &s) == 0) { 32 if (stat("/etc/hostname", &s) == 0) {
@@ -100,7 +99,6 @@ void fs_resolvconf(void) {
100 return; 99 return;
101 100
102 struct stat s; 101 struct stat s;
103 fs_build_mnt_dir();
104 102
105 // create a new /etc/hostname 103 // create a new /etc/hostname
106 if (stat("/etc/resolv.conf", &s) == 0) { 104 if (stat("/etc/resolv.conf", &s) == 0) {
diff --git a/src/firejail/fs_trace.c b/src/firejail/fs_trace.c
index 37e899f12..719b55048 100644
--- a/src/firejail/fs_trace.c
+++ b/src/firejail/fs_trace.c
@@ -44,9 +44,6 @@ void fs_trace_preload(void) {
44} 44}
45 45
46void fs_trace(void) { 46void fs_trace(void) {
47 // create /run/firejail/mnt directory
48 fs_build_mnt_dir();
49
50 // create the new ld.so.preload file and mount-bind it 47 // create the new ld.so.preload file and mount-bind it
51 if (arg_debug) 48 if (arg_debug)
52 printf("Create the new ld.so.preload file\n"); 49 printf("Create the new ld.so.preload file\n");
diff --git a/src/firejail/fs_var.c b/src/firejail/fs_var.c
index 4468efb10..4ff00f3ba 100644
--- a/src/firejail/fs_var.c
+++ b/src/firejail/fs_var.c
@@ -317,9 +317,6 @@ void fs_var_utmp(void) {
317 return; 317 return;
318 } 318 }
319 319
320 // create /run/firejail/mnt directory
321 fs_build_mnt_dir();
322
323 // create a new utmp file 320 // create a new utmp file
324 if (arg_debug) 321 if (arg_debug)
325 printf("Create the new utmp file\n"); 322 printf("Create the new utmp file\n");
diff --git a/src/firejail/fs_whitelist.c b/src/firejail/fs_whitelist.c
index 8bbdbe5d3..9cd8f7681 100644
--- a/src/firejail/fs_whitelist.c
+++ b/src/firejail/fs_whitelist.c
@@ -529,10 +529,6 @@ void fs_whitelist(void) {
529 entry = entry->next; 529 entry = entry->next;
530 } 530 }
531 531
532 // create mount points
533 fs_build_mnt_dir();
534
535
536 // /home/user 532 // /home/user
537 if (home_dir) { 533 if (home_dir) {
538 // keep a copy of real home dir in RUN_WHITELIST_HOME_USER_DIR 534 // keep a copy of real home dir in RUN_WHITELIST_HOME_USER_DIR
diff --git a/src/firejail/main.c b/src/firejail/main.c
index e210ceb31..fc86f9651 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -404,7 +404,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
404#ifdef HAVE_SECCOMP 404#ifdef HAVE_SECCOMP
405 else if (strcmp(argv[i], "--debug-syscalls") == 0) { 405 else if (strcmp(argv[i], "--debug-syscalls") == 0) {
406 if (checkcfg(CFG_SECCOMP)) { 406 if (checkcfg(CFG_SECCOMP)) {
407 int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FSECCOMP, "debug-syscalls"); 407 int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FSECCOMP, "debug-syscalls");
408 exit(rv); 408 exit(rv);
409 } 409 }
410 else { 410 else {
@@ -414,7 +414,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
414 } 414 }
415 else if (strcmp(argv[i], "--debug-errnos") == 0) { 415 else if (strcmp(argv[i], "--debug-errnos") == 0) {
416 if (checkcfg(CFG_SECCOMP)) { 416 if (checkcfg(CFG_SECCOMP)) {
417 int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FSECCOMP, "debug-errnos"); 417 int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FSECCOMP, "debug-errnos");
418 exit(rv); 418 exit(rv);
419 } 419 }
420 else { 420 else {
@@ -439,7 +439,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
439 exit(0); 439 exit(0);
440 } 440 }
441 else if (strcmp(argv[i], "--debug-protocols") == 0) { 441 else if (strcmp(argv[i], "--debug-protocols") == 0) {
442 int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FSECCOMP, "debug-protocols"); 442 int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FSECCOMP, "debug-protocols");
443 exit(rv); 443 exit(rv);
444 } 444 }
445 else if (strncmp(argv[i], "--protocol.print=", 17) == 0) { 445 else if (strncmp(argv[i], "--protocol.print=", 17) == 0) {
@@ -499,15 +499,15 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
499 exit(0); 499 exit(0);
500 } 500 }
501 else if (strcmp(argv[i], "--list") == 0) { 501 else if (strcmp(argv[i], "--list") == 0) {
502 int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FIREMON, "--list"); 502 int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FIREMON, "--list");
503 exit(rv); 503 exit(rv);
504 } 504 }
505 else if (strcmp(argv[i], "--tree") == 0) { 505 else if (strcmp(argv[i], "--tree") == 0) {
506 int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FIREMON, "--tree"); 506 int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FIREMON, "--tree");
507 exit(rv); 507 exit(rv);
508 } 508 }
509 else if (strcmp(argv[i], "--top") == 0) { 509 else if (strcmp(argv[i], "--top") == 0) {
510 int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FIREMON, "--top"); 510 int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FIREMON, "--top");
511 exit(rv); 511 exit(rv);
512 } 512 }
513#ifdef HAVE_NETWORK 513#ifdef HAVE_NETWORK
@@ -516,9 +516,9 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
516 struct stat s; 516 struct stat s;
517 int rv; 517 int rv;
518 if (stat("/proc/sys/kernel/grsecurity", &s) == 0) 518 if (stat("/proc/sys/kernel/grsecurity", &s) == 0)
519 rv = sbox_run(SBOX_ROOT | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FIREMON, "--netstats"); 519 rv = sbox_run(SBOX_ROOT | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FIREMON, "--netstats");
520 else 520 else
521 rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FIREMON, "--netstats"); 521 rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FIREMON, "--netstats");
522 exit(rv); 522 exit(rv);
523 } 523 }
524 else { 524 else {
@@ -855,6 +855,9 @@ int main(int argc, char **argv) {
855 int highest_errno = errno_highest_nr(); 855 int highest_errno = errno_highest_nr();
856#endif 856#endif
857 857
858 // build /run/firejail directory structure
859 preproc_build_firejail_dir();
860
858 detect_quiet(argc, argv); 861 detect_quiet(argc, argv);
859 detect_allow_debuggers(argc, argv); 862 detect_allow_debuggers(argc, argv);
860 863
@@ -957,10 +960,8 @@ int main(int argc, char **argv) {
957 // initialize globals 960 // initialize globals
958 init_cfg(argc, argv); 961 init_cfg(argc, argv);
959 962
960
961 // check firejail directories 963 // check firejail directories
962 EUID_ROOT(); 964 EUID_ROOT();
963 fs_build_firejail_dir();
964 bandwidth_del_run_file(sandbox_pid); 965 bandwidth_del_run_file(sandbox_pid);
965 network_del_run_file(sandbox_pid); 966 network_del_run_file(sandbox_pid);
966 delete_name_file(sandbox_pid); 967 delete_name_file(sandbox_pid);
@@ -1462,35 +1463,6 @@ int main(int argc, char **argv) {
1462 } 1463 }
1463 1464
1464 } 1465 }
1465#if 0 // disabled for now, it could be used to overwrite system directories
1466 else if (strncmp(argv[i], "--overlay-path=", 15) == 0) {
1467 if (checkcfg(CFG_OVERLAYFS)) {
1468 if (cfg.chrootdir) {
1469 fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n");
1470 exit(1);
1471 }
1472 struct stat s;
1473 if (stat("/proc/sys/kernel/grsecurity", &s) == 0) {
1474 fprintf(stderr, "Error: --overlay option is not available on Grsecurity systems\n");
1475 exit(1);
1476 }
1477 arg_overlay = 1;
1478 arg_overlay_keep = 1;
1479 arg_overlay_reuse = 1;
1480
1481 char *dirname = argv[i] + 15;
1482 if (dirname == '\0') {
1483 fprintf(stderr, "Error: invalid overlay option\n");
1484 exit(1);
1485 }
1486 cfg.overlay_dir = expand_home(dirname, cfg.homedir);
1487 }
1488 else {
1489 fprintf(stderr, "Error: overlayfs feature is disabled in Firejail configuration file\n");
1490 exit(1);
1491 }
1492 }
1493#endif
1494 else if (strcmp(argv[i], "--overlay-tmpfs") == 0) { 1466 else if (strcmp(argv[i], "--overlay-tmpfs") == 0) {
1495 if (checkcfg(CFG_OVERLAYFS)) { 1467 if (checkcfg(CFG_OVERLAYFS)) {
1496 if (cfg.chrootdir) { 1468 if (cfg.chrootdir) {
diff --git a/src/firejail/network.c b/src/firejail/network.c
index ac0d86559..6d09d770f 100644
--- a/src/firejail/network.c
+++ b/src/firejail/network.c
@@ -28,70 +28,6 @@
28#include <net/route.h> 28#include <net/route.h>
29#include <linux/if_bridge.h> 29#include <linux/if_bridge.h>
30 30
31// scan interfaces in current namespace and print IP address/mask for each interface
32void net_ifprint(void) {
33 uint32_t ip;
34 uint32_t mask;
35 struct ifaddrs *ifaddr, *ifa;
36
37 if (getifaddrs(&ifaddr) == -1)
38 errExit("getifaddrs");
39
40 printf("%-17.17s%-19.19s%-17.17s%-17.17s%-6.6s\n",
41 "Interface", "MAC", "IP", "Mask", "Status");
42 // walk through the linked list
43 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
44 if (ifa->ifa_addr == NULL)
45 continue;
46
47 if (ifa->ifa_addr->sa_family == AF_INET) {
48 struct sockaddr_in *si = (struct sockaddr_in *) ifa->ifa_netmask;
49 mask = ntohl(si->sin_addr.s_addr);
50 si = (struct sockaddr_in *) ifa->ifa_addr;
51 ip = ntohl(si->sin_addr.s_addr);
52
53 // interface status
54 char *status;
55 if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP)
56 status = "UP";
57 else
58 status = "DOWN";
59
60 // ip address and mask
61 char ipstr[30];
62 sprintf(ipstr, "%d.%d.%d.%d", PRINT_IP(ip));
63 char maskstr[30];
64 sprintf(maskstr, "%d.%d.%d.%d", PRINT_IP(mask));
65
66 // mac address
67 unsigned char mac[6];
68 net_get_mac(ifa->ifa_name, mac);
69 char macstr[30];
70 if (strcmp(ifa->ifa_name, "lo") == 0)
71 macstr[0] = '\0';
72 else
73 sprintf(macstr, "%02x:%02x:%02x:%02x:%02x:%02x", PRINT_MAC(mac));
74
75 // print
76 printf("%-17.17s%-19.19s%-17.17s%-17.17s%-6.6s\n",
77 ifa->ifa_name, macstr, ipstr, maskstr, status);
78
79 // network scanning
80 if (!arg_scan) // scanning disabled
81 continue;
82 if (strcmp(ifa->ifa_name, "lo") == 0) // no loopbabck scanning
83 continue;
84 if (mask2bits(mask) < 16) // not scanning large networks
85 continue;
86 if (!ip) // if not configured
87 continue;
88 // only if the interface is up and running
89 if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP)
90 arp_scan(ifa->ifa_name, ip, mask);
91 }
92 }
93 freeifaddrs(ifaddr);
94}
95 31
96int net_get_mtu(const char *ifname) { 32int net_get_mtu(const char *ifname) {
97 int mtu = 0; 33 int mtu = 0;
@@ -190,101 +126,11 @@ void net_if_up(const char *ifname) {
190 fprintf(stderr, "Error: invalid network device name %s\n", ifname); 126 fprintf(stderr, "Error: invalid network device name %s\n", ifname);
191 exit(1); 127 exit(1);
192 } 128 }
193 129 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 3,
194 int sock = socket(AF_INET,SOCK_DGRAM,0); 130 PATH_FNET, "ifup", ifname);
195 if (sock < 0) 131}
196 errExit("socket");
197 132
198 // get the existing interface flags
199 struct ifreq ifr;
200 memset(&ifr, 0, sizeof(ifr));
201 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
202 ifr.ifr_addr.sa_family = AF_INET;
203 133
204 // read the existing flags
205 if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) {
206 close(sock);
207 printf("Error: cannot bring up interface %s\n", ifname);
208 errExit("ioctl");
209 }
210
211 ifr.ifr_flags |= IFF_UP;
212
213 // set the new flags
214 if (ioctl( sock, SIOCSIFFLAGS, &ifr ) < 0) {
215 close(sock);
216 printf("Error: cannot bring up interface %s\n", ifname);
217 errExit("ioctl");
218 }
219
220 // checking
221 // read the existing flags
222 if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) {
223 close(sock);
224 printf("Error: cannot bring up interface %s\n", ifname);
225 errExit("ioctl");
226 }
227
228 // wait not more than 500ms for the interface to come up
229 int cnt = 0;
230 while (cnt < 50) {
231 usleep(10000); // sleep 10ms
232
233 // read the existing flags
234 if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) {
235 close(sock);
236 printf("Error: cannot bring up interface %s\n", ifname);
237 errExit("ioctl");
238 }
239 if (ifr.ifr_flags & IFF_RUNNING)
240 break;
241 cnt++;
242 }
243
244 close(sock);
245}
246
247// bring interface up
248void net_if_down(const char *ifname) {
249 if (strlen(ifname) > IFNAMSIZ) {
250 fprintf(stderr, "Error: invalid network device name %s\n", ifname);
251 exit(1);
252 }
253
254 int sock = socket(AF_INET,SOCK_DGRAM,0);
255 if (sock < 0)
256 errExit("socket");
257
258 // get the existing interface flags
259 struct ifreq ifr;
260 memset(&ifr, 0, sizeof(ifr));
261 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
262 ifr.ifr_addr.sa_family = AF_INET;
263
264 // read the existing flags
265 if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) {
266 close(sock);
267 printf("Error: cannot shut down interface %s\n", ifname);
268 errExit("ioctl");
269 }
270
271 ifr.ifr_flags &= ~IFF_UP;
272
273 // set the new flags
274 if (ioctl( sock, SIOCSIFFLAGS, &ifr ) < 0) {
275 close(sock);
276 printf("Error: cannot shut down interface %s\n", ifname);
277 errExit("ioctl");
278 }
279
280 close(sock);
281}
282
283struct ifreq6 {
284 struct in6_addr ifr6_addr;
285 uint32_t ifr6_prefixlen;
286 unsigned int ifr6_ifindex;
287};
288// configure interface ipv6 address 134// configure interface ipv6 address
289// ex: firejail --net=eth0 --ip6=2001:0db8:0:f101::1/64 135// ex: firejail --net=eth0 --ip6=2001:0db8:0:f101::1/64
290void net_if_ip6(const char *ifname, const char *addr6) { 136void net_if_ip6(const char *ifname, const char *addr6) {
@@ -293,107 +139,11 @@ void net_if_ip6(const char *ifname, const char *addr6) {
293 exit(1); 139 exit(1);
294 } 140 }
295 141
296 // extract prefix 142 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 5,
297 unsigned long prefix; 143 PATH_FNET, "config", "ipv6", ifname, addr6);
298 char *ptr;
299 if ((ptr = strchr(addr6, '/'))) {
300 prefix = atol(ptr + 1);
301 if (prefix > 128) {
302 fprintf(stderr, "Error: invalid prefix for IPv6 address %s\n", addr6);
303 exit(1);
304 }
305 *ptr = '\0'; // mark the end of the address
306 }
307 else
308 prefix = 128;
309
310 // extract address
311 struct sockaddr_in6 sin6;
312 memset(&sin6, 0, sizeof(sin6));
313 sin6.sin6_family = AF_INET6;
314 int rv = inet_pton(AF_INET6, addr6, sin6.sin6_addr.s6_addr);
315 if (rv <= 0) {
316 fprintf(stderr, "Error: invalid IPv6 address %s\n", addr6);
317 exit(1);
318 }
319
320 // open socket
321 int sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
322 if (sock < 0) {
323 fprintf(stderr, "Error: IPv6 is not supported on this system\n");
324 exit(1);
325 }
326
327 // find interface index
328 struct ifreq ifr;
329 memset(&ifr, 0, sizeof(ifr));
330 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
331 ifr.ifr_addr.sa_family = AF_INET;
332 if (ioctl(sock, SIOGIFINDEX, &ifr) < 0) {
333 perror("ioctl SIOGIFINDEX");
334 exit(1);
335 }
336
337 // configure address
338 struct ifreq6 ifr6;
339 memset(&ifr6, 0, sizeof(ifr6));
340 ifr6.ifr6_prefixlen = prefix;
341 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
342 memcpy((char *) &ifr6.ifr6_addr, (char *) &sin6.sin6_addr, sizeof(struct in6_addr));
343 if (ioctl(sock, SIOCSIFADDR, &ifr6) < 0) {
344 perror("ioctl SIOCSIFADDR");
345 exit(1);
346 }
347
348 close(sock);
349}
350
351// configure interface ipv4 address
352void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu) {
353 if (strlen(ifname) > IFNAMSIZ) {
354 fprintf(stderr, "Error: invalid network device name %s\n", ifname);
355 exit(1);
356 }
357 if (arg_debug)
358 printf("configure interface %s\n", ifname);
359
360 int sock = socket(AF_INET,SOCK_DGRAM,0);
361 if (sock < 0)
362 errExit("socket");
363
364 struct ifreq ifr;
365 memset(&ifr, 0, sizeof(ifr));
366 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
367 ifr.ifr_addr.sa_family = AF_INET;
368
369 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(ip);
370 if (ioctl( sock, SIOCSIFADDR, &ifr ) < 0) {
371 close(sock);
372 errExit("ioctl");
373 }
374
375 if (ip != 0) {
376 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(mask);
377 if (ioctl( sock, SIOCSIFNETMASK, &ifr ) < 0) {
378 close(sock);
379 errExit("ioctl");
380 }
381 }
382
383 // configure mtu
384 if (mtu > 0) {
385 ifr.ifr_mtu = mtu;
386 if (ioctl( sock, SIOCSIFMTU, &ifr ) < 0) {
387 close(sock);
388 errExit("ioctl");
389 }
390 }
391 144
392 close(sock);
393 usleep(10000); // sleep 10ms
394} 145}
395 146
396
397// add an IP route, return -1 if error, 0 if the route was added 147// add an IP route, return -1 if error, 0 if the route was added
398int net_add_route(uint32_t ip, uint32_t mask, uint32_t gw) { 148int net_add_route(uint32_t ip, uint32_t mask, uint32_t gw) {
399 int sock; 149 int sock;
@@ -464,20 +214,15 @@ uint32_t network_get_defaultgw(void) {
464} 214}
465 215
466int net_config_mac(const char *ifname, const unsigned char mac[6]) { 216int net_config_mac(const char *ifname, const unsigned char mac[6]) {
467 struct ifreq ifr; 217 char *macstr;
468 int sock; 218 if (asprintf(&macstr, "%02x:%02x:%02x:%02x:%02x:%02x",
219 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]) == -1)
220 errExit("asprintf");
469 221
470 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) 222 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 5,
471 errExit("socket"); 223 PATH_FNET, "config", "mac", ifname, macstr);
472
473 memset(&ifr, 0, sizeof(ifr));
474 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
475 ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
476 memcpy(ifr.ifr_hwaddr.sa_data, mac, 6);
477 224
478 if (ioctl(sock, SIOCSIFHWADDR, &ifr) == -1) 225 free(macstr);
479 errExit("ioctl");
480 close(sock);
481 return 0; 226 return 0;
482} 227}
483 228
@@ -500,3 +245,27 @@ int net_get_mac(const char *ifname, unsigned char mac[6]) {
500 close(sock); 245 close(sock);
501 return 0; 246 return 0;
502} 247}
248
249void net_config_interface(const char *dev, uint32_t ip, uint32_t mask, int mtu) {
250 assert(dev);
251
252 char *ipstr;
253 if (asprintf(&ipstr, "%llu", (long long unsigned) ip) == -1)
254 errExit("asprintf");
255
256 char *maskstr;
257 if (asprintf(&maskstr, "%llu", (long long unsigned) mask) == -1)
258 errExit("asprintf");
259
260 char *mtustr;
261 if (asprintf(&mtustr, "%d", mtu) == -1)
262 errExit("asprintf");
263
264 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 7,
265 PATH_FNET, "config", "interface", dev, ipstr, maskstr, mtustr);
266
267 free(ipstr);
268 free(maskstr);
269 free(mtustr);
270}
271
diff --git a/src/firejail/network_main.c b/src/firejail/network_main.c
index 35d6dd214..8a9c47f0e 100644
--- a/src/firejail/network_main.c
+++ b/src/firejail/network_main.c
@@ -128,11 +128,10 @@ void net_configure_veth_pair(Bridge *br, const char *ifname, pid_t child) {
128 else 128 else
129 dev = br->veth_name; 129 dev = br->veth_name;
130 130
131// net_create_veth(dev, ifname, child);
132 char *cstr; 131 char *cstr;
133 if (asprintf(&cstr, "%d", child) == -1) 132 if (asprintf(&cstr, "%d", child) == -1)
134 errExit("asprintf"); 133 errExit("asprintf");
135 sbox_run(SBOX_ROOT | SBOX_SECCOMP, 7, PATH_FNET, "create", "veth", dev, ifname, br->dev, cstr); 134 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 7, PATH_FNET, "create", "veth", dev, ifname, br->dev, cstr);
136 free(cstr); 135 free(cstr);
137 136
138 char *msg; 137 char *msg;
@@ -300,50 +299,42 @@ void network_main(pid_t child) {
300 net_configure_veth_pair(&cfg.bridge0, "eth0", child); 299 net_configure_veth_pair(&cfg.bridge0, "eth0", child);
301 } 300 }
302 else 301 else
303// net_create_macvlan(cfg.bridge0.devsandbox, cfg.bridge0.dev, child); 302 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge0.devsandbox, cfg.bridge0.dev, cstr);
304 sbox_run(SBOX_ROOT | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge0.devsandbox, cfg.bridge0.dev, cstr);
305 } 303 }
306 304
307 if (cfg.bridge1.configured) { 305 if (cfg.bridge1.configured) {
308 if (cfg.bridge1.macvlan == 0) 306 if (cfg.bridge1.macvlan == 0)
309 net_configure_veth_pair(&cfg.bridge1, "eth1", child); 307 net_configure_veth_pair(&cfg.bridge1, "eth1", child);
310 else 308 else
311// net_create_macvlan(cfg.bridge1.devsandbox, cfg.bridge1.dev, child); 309 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge1.devsandbox, cfg.bridge1.dev, cstr);
312 sbox_run(SBOX_ROOT | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge1.devsandbox, cfg.bridge1.dev, cstr);
313 } 310 }
314 311
315 if (cfg.bridge2.configured) { 312 if (cfg.bridge2.configured) {
316 if (cfg.bridge2.macvlan == 0) 313 if (cfg.bridge2.macvlan == 0)
317 net_configure_veth_pair(&cfg.bridge2, "eth2", child); 314 net_configure_veth_pair(&cfg.bridge2, "eth2", child);
318 else 315 else
319// net_create_macvlan(cfg.bridge2.devsandbox, cfg.bridge2.dev, child); 316 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge2.devsandbox, cfg.bridge2.dev, cstr);
320 sbox_run(SBOX_ROOT | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge2.devsandbox, cfg.bridge2.dev, cstr);
321 } 317 }
322 318
323 if (cfg.bridge3.configured) { 319 if (cfg.bridge3.configured) {
324 if (cfg.bridge3.macvlan == 0) 320 if (cfg.bridge3.macvlan == 0)
325 net_configure_veth_pair(&cfg.bridge3, "eth3", child); 321 net_configure_veth_pair(&cfg.bridge3, "eth3", child);
326 else 322 else
327// net_create_macvlan(cfg.bridge3.devsandbox, cfg.bridge3.dev, child); 323 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge3.devsandbox, cfg.bridge3.dev, cstr);
328 sbox_run(SBOX_ROOT | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge3.devsandbox, cfg.bridge3.dev, cstr);
329 } 324 }
330 325
331 // move interfaces in sandbox 326 // move interfaces in sandbox
332 if (cfg.interface0.configured) { 327 if (cfg.interface0.configured) {
333// net_move_interface(cfg.interface0.dev, child); 328 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface0.dev, cstr);
334 sbox_run(SBOX_ROOT | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface0.dev, cstr);
335 } 329 }
336 if (cfg.interface1.configured) { 330 if (cfg.interface1.configured) {
337// net_move_interface(cfg.interface1.dev, child); 331 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface1.dev, cstr);
338 sbox_run(SBOX_ROOT | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface1.dev, cstr);
339 } 332 }
340 if (cfg.interface2.configured) { 333 if (cfg.interface2.configured) {
341// net_move_interface(cfg.interface2.dev, child); 334 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface3.dev, cstr);
342 sbox_run(SBOX_ROOT | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface3.dev, cstr);
343 } 335 }
344 if (cfg.interface3.configured) { 336 if (cfg.interface3.configured) {
345// net_move_interface(cfg.interface3.dev, child); 337 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface3.dev, cstr);
346 sbox_run(SBOX_ROOT | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface3.dev, cstr);
347 } 338 }
348 339
349 free(cstr); 340 free(cstr);
diff --git a/src/firejail/preproc.c b/src/firejail/preproc.c
new file mode 100644
index 000000000..6784ff5ac
--- /dev/null
+++ b/src/firejail/preproc.c
@@ -0,0 +1,110 @@
1/*
2 * Copyright (C) 2014-2016 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20#include "firejail.h"
21#include <sys/mount.h>
22#include <sys/stat.h>
23
24static int tmpfs_mounted = 0;
25
26// build /run/firejail directory
27void preproc_build_firejail_dir(void) {
28 struct stat s;
29
30 // CentOS 6 doesn't have /run directory
31 if (stat(RUN_FIREJAIL_BASEDIR, &s)) {
32 create_empty_dir_as_root(RUN_FIREJAIL_BASEDIR, 0755);
33 }
34
35 if (stat(RUN_FIREJAIL_DIR, &s)) {
36 create_empty_dir_as_root(RUN_FIREJAIL_DIR, 0755);
37 }
38
39 if (stat(RUN_FIREJAIL_NETWORK_DIR, &s)) {
40 create_empty_dir_as_root(RUN_FIREJAIL_NETWORK_DIR, 0755);
41 }
42
43 if (stat(RUN_FIREJAIL_BANDWIDTH_DIR, &s)) {
44 create_empty_dir_as_root(RUN_FIREJAIL_BANDWIDTH_DIR, 0755);
45 }
46
47 if (stat(RUN_FIREJAIL_NAME_DIR, &s)) {
48 create_empty_dir_as_root(RUN_FIREJAIL_NAME_DIR, 0755);
49 }
50
51 if (stat(RUN_FIREJAIL_X11_DIR, &s)) {
52 create_empty_dir_as_root(RUN_FIREJAIL_X11_DIR, 0755);
53 }
54
55 if (stat(RUN_FIREJAIL_APPIMAGE_DIR, &s)) {
56 create_empty_dir_as_root(RUN_FIREJAIL_APPIMAGE_DIR, 0755);
57 }
58
59 create_empty_file_as_root(RUN_RO_FILE, S_IRUSR);
60 create_empty_dir_as_root(RUN_RO_DIR, S_IRUSR);
61}
62
63// build /run/firejail/mnt directory
64void preproc_mount_mnt_dir(void) {
65 struct stat s;
66
67 // mount tmpfs on top of /run/firejail/mnt
68 if (!tmpfs_mounted) {
69 if (arg_debug)
70 printf("Mounting tmpfs on %s directory\n", RUN_MNT_DIR);
71 if (mount("tmpfs", RUN_MNT_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
72 errExit("mounting /run/firejail/mnt");
73 tmpfs_mounted = 1;
74 fs_logger2("tmpfs", RUN_MNT_DIR);
75 }
76}
77
78// grab a copy of cp command
79void preproc_build_cp_command(void) {
80 struct stat s;
81 preproc_mount_mnt_dir();
82 if (stat(RUN_CP_COMMAND, &s)) {
83 char* fname = realpath("/bin/cp", NULL);
84 if (fname == NULL) {
85 fprintf(stderr, "Error: /bin/cp not found\n");
86 exit(1);
87 }
88 if (stat(fname, &s)) {
89 fprintf(stderr, "Error: /bin/cp not found\n");
90 exit(1);
91 }
92 if (is_link(fname)) {
93 fprintf(stderr, "Error: invalid /bin/cp file\n");
94 exit(1);
95 }
96 int rv = copy_file(fname, RUN_CP_COMMAND, 0, 0, 0755);
97 if (rv) {
98 fprintf(stderr, "Error: cannot access /bin/cp\n");
99 exit(1);
100 }
101 ASSERT_PERMS(RUN_CP_COMMAND, 0, 0, 0755);
102
103 free(fname);
104 }
105}
106
107// delete the temporary cp command
108void preproc_delete_cp_command(void) {
109 unlink(RUN_CP_COMMAND);
110}
diff --git a/src/firejail/protocol.c b/src/firejail/protocol.c
index 43f30e30a..db6c6cad9 100644
--- a/src/firejail/protocol.c
+++ b/src/firejail/protocol.c
@@ -70,8 +70,6 @@ void protocol_filter(const char *fname) {
70 70
71void protocol_filter_save(void) { 71void protocol_filter_save(void) {
72 // save protocol filter configuration in PROTOCOL_CFG 72 // save protocol filter configuration in PROTOCOL_CFG
73 fs_build_mnt_dir();
74
75 FILE *fp = fopen(RUN_PROTOCOL_CFG, "w"); 73 FILE *fp = fopen(RUN_PROTOCOL_CFG, "w");
76 if (!fp) 74 if (!fp)
77 errExit("fopen"); 75 errExit("fopen");
diff --git a/src/firejail/pulseaudio.c b/src/firejail/pulseaudio.c
index 90997f934..e1a58c1c8 100644
--- a/src/firejail/pulseaudio.c
+++ b/src/firejail/pulseaudio.c
@@ -104,7 +104,6 @@ void pulseaudio_init(void) {
104 return; 104 return;
105 105
106 // create the new user pulseaudio directory 106 // create the new user pulseaudio directory
107 fs_build_mnt_dir();
108 int rv = mkdir(RUN_PULSE_DIR, 0700); 107 int rv = mkdir(RUN_PULSE_DIR, 0700);
109 (void) rv; // in --chroot mode the directory can already be there 108 (void) rv; // in --chroot mode the directory can already be there
110 if (chown(RUN_PULSE_DIR, getuid(), getgid()) < 0) 109 if (chown(RUN_PULSE_DIR, getuid(), getgid()) < 0)
diff --git a/src/firejail/restrict_users.c b/src/firejail/restrict_users.c
index 5ef9524d7..57e84e5cc 100644
--- a/src/firejail/restrict_users.c
+++ b/src/firejail/restrict_users.c
@@ -73,7 +73,6 @@ static void sanitize_home(void) {
73 return; 73 return;
74 } 74 }
75 75
76 fs_build_mnt_dir();
77 if (mkdir(RUN_WHITELIST_HOME_DIR, 0755) == -1) 76 if (mkdir(RUN_WHITELIST_HOME_DIR, 0755) == -1)
78 errExit("mkdir"); 77 errExit("mkdir");
79 78
@@ -127,7 +126,6 @@ static void sanitize_passwd(void) {
127 126
128 FILE *fpin = NULL; 127 FILE *fpin = NULL;
129 FILE *fpout = NULL; 128 FILE *fpout = NULL;
130 fs_build_mnt_dir();
131 129
132 // open files 130 // open files
133 /* coverity[toctou] */ 131 /* coverity[toctou] */
@@ -261,7 +259,6 @@ static void sanitize_group(void) {
261 259
262 FILE *fpin = NULL; 260 FILE *fpin = NULL;
263 FILE *fpout = NULL; 261 FILE *fpout = NULL;
264 fs_build_mnt_dir();
265 262
266 // open files 263 // open files
267 /* coverity[toctou] */ 264 /* coverity[toctou] */
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index 7a63461ef..a15003d03 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -122,7 +122,7 @@ static void sandbox_if_up(Bridge *br) {
122 assert(br); 122 assert(br);
123 if (!br->configured) 123 if (!br->configured)
124 return; 124 return;
125 125
126 char *dev = br->devsandbox; 126 char *dev = br->devsandbox;
127 net_if_up(dev); 127 net_if_up(dev);
128 128
@@ -137,8 +137,7 @@ static void sandbox_if_up(Bridge *br) {
137 assert(br->ipsandbox); 137 assert(br->ipsandbox);
138 if (arg_debug) 138 if (arg_debug)
139 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev); 139 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev);
140 net_if_ip(dev, br->ipsandbox, br->mask, br->mtu); 140 net_config_interface(dev, br->ipsandbox, br->mask, br->mtu);
141 net_if_up(dev);
142 } 141 }
143 else if (br->arg_ip_none == 0 && br->macvlan == 1) { 142 else if (br->arg_ip_none == 0 && br->macvlan == 1) {
144 // reassign the macvlan address 143 // reassign the macvlan address
@@ -160,8 +159,7 @@ static void sandbox_if_up(Bridge *br) {
160 159
161 if (arg_debug) 160 if (arg_debug)
162 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev); 161 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev);
163 net_if_ip(dev, br->ipsandbox, br->mask, br->mtu); 162 net_config_interface(dev, br->ipsandbox, br->mask, br->mtu);
164 net_if_up(dev);
165 } 163 }
166 164
167 if (br->ip6sandbox) 165 if (br->ip6sandbox)
@@ -256,32 +254,6 @@ static int monitor_application(pid_t app_pid) {
256 254
257 // return the latest exit status. 255 // return the latest exit status.
258 return status; 256 return status;
259
260#if 0
261// todo: find a way to shut down interfaces before closing the namespace
262// the problem is we don't have enough privileges to shutdown interfaces in this moment
263 // shut down bridge/macvlan interfaces
264 if (any_bridge_configured()) {
265
266 if (cfg.bridge0.configured) {
267 printf("Shutting down %s\n", cfg.bridge0.devsandbox);
268 net_if_down( cfg.bridge0.devsandbox);
269 }
270 if (cfg.bridge1.configured) {
271 printf("Shutting down %s\n", cfg.bridge1.devsandbox);
272 net_if_down( cfg.bridge1.devsandbox);
273 }
274 if (cfg.bridge2.configured) {
275 printf("Shutting down %s\n", cfg.bridge2.devsandbox);
276 net_if_down( cfg.bridge2.devsandbox);
277 }
278 if (cfg.bridge3.configured) {
279 printf("Shutting down %s\n", cfg.bridge3.devsandbox);
280 net_if_down( cfg.bridge3.devsandbox);
281 }
282 usleep(20000); // 20 ms sleep
283 }
284#endif
285} 257}
286 258
287void start_audit(void) { 259void start_audit(void) {
@@ -442,7 +414,8 @@ int sandbox(void* sandbox_arg) {
442 if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0) { 414 if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0) {
443 chk_chroot(); 415 chk_chroot();
444 } 416 }
445 417 // ... and mount a tmpfs on top of /run/firejail/mnt directory
418 preproc_mount_mnt_dir();
446 419
447 //**************************** 420 //****************************
448 // log sandbox data 421 // log sandbox data
@@ -459,7 +432,7 @@ int sandbox(void* sandbox_arg) {
459 fs_logger("install mount namespace"); 432 fs_logger("install mount namespace");
460 433
461 //**************************** 434 //****************************
462 // netfilter etc. 435 // netfilter
463 //**************************** 436 //****************************
464 if (arg_netfilter && any_bridge_configured()) { // assuming by default the client filter 437 if (arg_netfilter && any_bridge_configured()) { // assuming by default the client filter
465 netfilter(arg_netfilter_file); 438 netfilter(arg_netfilter_file);
@@ -468,6 +441,105 @@ int sandbox(void* sandbox_arg) {
468 netfilter6(arg_netfilter6_file); 441 netfilter6(arg_netfilter6_file);
469 } 442 }
470 443
444 //****************************
445 // networking
446 //****************************
447 int gw_cfg_failed = 0; // default gw configuration flag
448 if (arg_nonetwork) {
449 net_if_up("lo");
450 if (arg_debug)
451 printf("Network namespace enabled, only loopback interface available\n");
452 }
453 else if (any_bridge_configured() || any_interface_configured()) {
454 // configure lo and eth0...eth3
455 net_if_up("lo");
456
457 if (mac_not_zero(cfg.bridge0.macsandbox))
458 net_config_mac(cfg.bridge0.devsandbox, cfg.bridge0.macsandbox);
459 sandbox_if_up(&cfg.bridge0);
460
461 if (mac_not_zero(cfg.bridge1.macsandbox))
462 net_config_mac(cfg.bridge1.devsandbox, cfg.bridge1.macsandbox);
463 sandbox_if_up(&cfg.bridge1);
464
465 if (mac_not_zero(cfg.bridge2.macsandbox))
466 net_config_mac(cfg.bridge2.devsandbox, cfg.bridge2.macsandbox);
467 sandbox_if_up(&cfg.bridge2);
468
469 if (mac_not_zero(cfg.bridge3.macsandbox))
470 net_config_mac(cfg.bridge3.devsandbox, cfg.bridge3.macsandbox);
471 sandbox_if_up(&cfg.bridge3);
472
473
474// todo: this code seems to be dead!!!
475 // enable interfaces
476 if (cfg.interface0.configured && cfg.interface0.ip) {
477assert(0);
478 if (arg_debug)
479 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface0.ip), cfg.interface0.dev);
480 net_config_interface(cfg.interface0.dev, cfg.interface0.ip, cfg.interface0.mask, cfg.interface0.mtu);
481 }
482 if (cfg.interface1.configured && cfg.interface1.ip) {
483assert(0);
484 if (arg_debug)
485 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface1.ip), cfg.interface1.dev);
486 net_config_interface(cfg.interface1.dev, cfg.interface1.ip, cfg.interface1.mask, cfg.interface1.mtu);
487 }
488 if (cfg.interface2.configured && cfg.interface2.ip) {
489assert(0);
490 if (arg_debug)
491 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface2.ip), cfg.interface2.dev);
492 net_config_interface(cfg.interface2.dev, cfg.interface2.ip, cfg.interface2.mask, cfg.interface2.mtu);
493 }
494 if (cfg.interface3.configured && cfg.interface3.ip) {
495assert(0);
496 if (arg_debug)
497 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface3.ip), cfg.interface3.dev);
498 net_config_interface(cfg.interface3.dev, cfg.interface3.ip, cfg.interface3.mask, cfg.interface3.mtu);
499 }
500
501 // add a default route
502 if (cfg.defaultgw) {
503 // set the default route
504 if (net_add_route(0, 0, cfg.defaultgw)) {
505 fprintf(stderr, "Warning: cannot configure default route\n");
506 gw_cfg_failed = 1;
507 }
508 }
509
510 if (arg_debug)
511 printf("Network namespace enabled\n");
512 }
513
514
515 // print network configuration
516 if (!arg_quiet) {
517 if (any_bridge_configured() || any_interface_configured() || cfg.defaultgw || cfg.dns1) {
518 printf("\n");
519 if (any_bridge_configured() || any_interface_configured()) {
520// net_ifprint();
521 if (arg_scan)
522 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 3, PATH_FNET, "printif", "scan");
523 else
524 sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 2, PATH_FNET, "printif", "scan");
525
526 }
527 if (cfg.defaultgw != 0) {
528 if (gw_cfg_failed)
529 printf("Default gateway configuration failed\n");
530 else
531 printf("Default gateway %d.%d.%d.%d\n", PRINT_IP(cfg.defaultgw));
532 }
533 if (cfg.dns1 != 0)
534 printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns1));
535 if (cfg.dns2 != 0)
536 printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns2));
537 if (cfg.dns3 != 0)
538 printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns3));
539 printf("\n");
540 }
541 }
542
471 // load IBUS env variables 543 // load IBUS env variables
472 if (arg_nonetwork || any_bridge_configured() || any_interface_configured()) { 544 if (arg_nonetwork || any_bridge_configured() || any_interface_configured()) {
473 // do nothing - there are problems with ibus version 1.5.11 545 // do nothing - there are problems with ibus version 1.5.11
@@ -475,9 +547,34 @@ int sandbox(void* sandbox_arg) {
475 else 547 else
476 env_ibus_load(); 548 env_ibus_load();
477 549
478 // grab a copy of cp command 550 //****************************
479 fs_build_cp_command(); 551 // fs pre-processing:
480 552 // - copy some commands under /run
553 // - build seccomp filters
554 // - create an empty /etc/ld.so.preload
555 //****************************
556 preproc_build_cp_command();
557
558#ifdef HAVE_SECCOMP
559 if (cfg.protocol) {
560 if (arg_debug)
561 printf("Build protocol filter: %s\n", cfg.protocol);
562 // as root, create RUN_SECCOMP_PROTOCOL file
563 // this is where fseccomp program will store the protocol filter
564 create_empty_file_as_root(RUN_SECCOMP_PROTOCOL, 0644);
565 if (chown(RUN_SECCOMP_PROTOCOL, getuid(), getgid()) == -1)
566 errExit("chown");
567 if (chmod(RUN_SECCOMP_PROTOCOL, 0644) == -1)
568 errExit("chmod");
569
570 // build the seccomp filter as a regular user
571 int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 5,
572 PATH_FSECCOMP, "protocol", "build", cfg.protocol, RUN_SECCOMP_PROTOCOL);
573 if (rv)
574 exit(rv);
575 }
576#endif
577
481 // trace pre-install 578 // trace pre-install
482 if (arg_trace || arg_tracelog || mask_x11_abstract_socket) 579 if (arg_trace || arg_tracelog || mask_x11_abstract_socket)
483 fs_trace_preload(); 580 fs_trace_preload();
@@ -494,7 +591,7 @@ int sandbox(void* sandbox_arg) {
494 enforce_seccomp = 1; 591 enforce_seccomp = 1;
495#endif 592#endif
496 } 593 }
497 594
498#ifdef HAVE_CHROOT 595#ifdef HAVE_CHROOT
499 if (cfg.chrootdir) { 596 if (cfg.chrootdir) {
500 fs_chroot(cfg.chrootdir); 597 fs_chroot(cfg.chrootdir);
@@ -617,7 +714,6 @@ int sandbox(void* sandbox_arg) {
617 EUID_USER(); 714 EUID_USER();
618 profile_add("whitelist /tmp/.X11-unix"); 715 profile_add("whitelist /tmp/.X11-unix");
619 EUID_ROOT(); 716 EUID_ROOT();
620// fs_private_tmp();
621 } 717 }
622 } 718 }
623 719
@@ -664,102 +760,17 @@ int sandbox(void* sandbox_arg) {
664 fs_dev_disable_3d(); 760 fs_dev_disable_3d();
665 761
666 //**************************** 762 //****************************
667 // networking 763 // set dns
668 //**************************** 764 //****************************
669 int gw_cfg_failed = 0; // default gw configuration flag
670 if (arg_nonetwork) {
671 net_if_up("lo");
672 if (arg_debug)
673 printf("Network namespace enabled, only loopback interface available\n");
674 }
675 else if (any_bridge_configured() || any_interface_configured()) {
676 // configure lo and eth0...eth3
677 net_if_up("lo");
678
679 if (mac_not_zero(cfg.bridge0.macsandbox))
680 net_config_mac(cfg.bridge0.devsandbox, cfg.bridge0.macsandbox);
681 sandbox_if_up(&cfg.bridge0);
682
683 if (mac_not_zero(cfg.bridge1.macsandbox))
684 net_config_mac(cfg.bridge1.devsandbox, cfg.bridge1.macsandbox);
685 sandbox_if_up(&cfg.bridge1);
686
687 if (mac_not_zero(cfg.bridge2.macsandbox))
688 net_config_mac(cfg.bridge2.devsandbox, cfg.bridge2.macsandbox);
689 sandbox_if_up(&cfg.bridge2);
690
691 if (mac_not_zero(cfg.bridge3.macsandbox))
692 net_config_mac(cfg.bridge3.devsandbox, cfg.bridge3.macsandbox);
693 sandbox_if_up(&cfg.bridge3);
694
695 // enable interfaces
696 if (cfg.interface0.configured && cfg.interface0.ip) {
697 if (arg_debug)
698 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface0.ip), cfg.interface0.dev);
699 net_if_ip(cfg.interface0.dev, cfg.interface0.ip, cfg.interface0.mask, cfg.interface0.mtu);
700 net_if_up(cfg.interface0.dev);
701 }
702 if (cfg.interface1.configured && cfg.interface1.ip) {
703 if (arg_debug)
704 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface1.ip), cfg.interface1.dev);
705 net_if_ip(cfg.interface1.dev, cfg.interface1.ip, cfg.interface1.mask, cfg.interface1.mtu);
706 net_if_up(cfg.interface1.dev);
707 }
708 if (cfg.interface2.configured && cfg.interface2.ip) {
709 if (arg_debug)
710 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface2.ip), cfg.interface2.dev);
711 net_if_ip(cfg.interface2.dev, cfg.interface2.ip, cfg.interface2.mask, cfg.interface2.mtu);
712 net_if_up(cfg.interface2.dev);
713 }
714 if (cfg.interface3.configured && cfg.interface3.ip) {
715 if (arg_debug)
716 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface3.ip), cfg.interface3.dev);
717 net_if_ip(cfg.interface3.dev, cfg.interface3.ip, cfg.interface3.mask, cfg.interface3.mtu);
718 net_if_up(cfg.interface3.dev);
719 }
720
721 // add a default route
722 if (cfg.defaultgw) {
723 // set the default route
724 if (net_add_route(0, 0, cfg.defaultgw)) {
725 fprintf(stderr, "Warning: cannot configure default route\n");
726 gw_cfg_failed = 1;
727 }
728 }
729
730 if (arg_debug)
731 printf("Network namespace enabled\n");
732 }
733
734 // if any dns server is configured, it is time to set it now
735 fs_resolvconf(); 765 fs_resolvconf();
766
767 //****************************
768 // fs post-processing
769 //****************************
770 preproc_delete_cp_command();
736 fs_logger_print(); 771 fs_logger_print();
737 fs_logger_change_owner(); 772 fs_logger_change_owner();
738 773
739 // print network configuration
740 if (!arg_quiet) {
741 if (any_bridge_configured() || any_interface_configured() || cfg.defaultgw || cfg.dns1) {
742 printf("\n");
743 if (any_bridge_configured() || any_interface_configured())
744 net_ifprint();
745 if (cfg.defaultgw != 0) {
746 if (gw_cfg_failed)
747 printf("Default gateway configuration failed\n");
748 else
749 printf("Default gateway %d.%d.%d.%d\n", PRINT_IP(cfg.defaultgw));
750 }
751 if (cfg.dns1 != 0)
752 printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns1));
753 if (cfg.dns2 != 0)
754 printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns2));
755 if (cfg.dns3 != 0)
756 printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns3));
757 printf("\n");
758 }
759 }
760
761 fs_delete_cp_command();
762
763 //**************************** 774 //****************************
764 // set application environment 775 // set application environment
765 //**************************** 776 //****************************
@@ -820,21 +831,7 @@ int sandbox(void* sandbox_arg) {
820 // install protocol filter 831 // install protocol filter
821 if (cfg.protocol) { 832 if (cfg.protocol) {
822 if (arg_debug) 833 if (arg_debug)
823 printf("Set protocol filter: %s\n", cfg.protocol); 834 printf("Install protocol filter: %s\n", cfg.protocol);
824 // as root, create RUN_SECCOMP_PROTOCOL file
825 // this is where fseccomp program will store the protocol filter
826 int dst = open(RUN_SECCOMP_PROTOCOL, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
827 if (dst == -1)
828 errExit("open");
829 close(dst);
830 if (chown(RUN_SECCOMP_PROTOCOL, getuid(), getgid()) == -1)
831 errExit("chown");
832
833 // build the seccomp filter as a regular user
834 int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 5,
835 PATH_FSECCOMP, "protocol", "build", cfg.protocol, RUN_SECCOMP_PROTOCOL);
836 if (rv)
837 exit(rv);
838 protocol_filter(RUN_SECCOMP_PROTOCOL); // install filter 835 protocol_filter(RUN_SECCOMP_PROTOCOL); // install filter
839 protocol_filter_save(); // save filter in RUN_PROTOCOL_CFG 836 protocol_filter_save(); // save filter in RUN_PROTOCOL_CFG
840 } 837 }
diff --git a/src/firejail/sbox.c b/src/firejail/sbox.c
index d1225c3bc..6499b7005 100644
--- a/src/firejail/sbox.c
+++ b/src/firejail/sbox.c
@@ -125,21 +125,26 @@ int sbox_run(unsigned filter, int num, ...) {
125 arg[i] = NULL; 125 arg[i] = NULL;
126 va_end(valist); 126 va_end(valist);
127 127
128//#if 0 128 if (arg_debug) {
129{ 129 printf("sbox run: ");
130int i; 130 for (i = 0; i <= num; i++)
131for (i = 0; i <= num; i++) 131 printf("%s ", arg[i]);
132 printf("#%s# ", arg[i]); 132 printf("\n");
133printf("\n"); 133 }
134} 134
135//#endif
136 pid_t child = fork(); 135 pid_t child = fork();
137 if (child < 0) 136 if (child < 0)
138 errExit("fork"); 137 errExit("fork");
139 if (child == 0) { 138 if (child == 0) {
140 // apply filters 139 // apply filters
141 if (filter & SBOX_CAPS) 140 if (filter & SBOX_CAPS_NONE) {
142 caps_drop_all(); 141 caps_drop_all();
142 }
143 else if (filter & SBOX_CAPS_NETWORK) {
144 uint64_t set = ((uint64_t) 1) << CAP_NET_ADMIN;
145 set |= ((uint64_t) 1) << CAP_NET_RAW;
146 caps_set(set);
147 }
143 148
144 if (filter & SBOX_SECCOMP) { 149 if (filter & SBOX_SECCOMP) {
145 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 150 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c
index 09862ec20..69be04a03 100644
--- a/src/firejail/seccomp.c
+++ b/src/firejail/seccomp.c
@@ -275,7 +275,6 @@ static void filter_end_whitelist(void) {
275 275
276// save seccomp filter in /run/firejail/mnt/seccomp 276// save seccomp filter in /run/firejail/mnt/seccomp
277static void write_seccomp_file(void) { 277static void write_seccomp_file(void) {
278 fs_build_mnt_dir();
279 assert(sfilter); 278 assert(sfilter);
280 279
281 int fd = open(RUN_SECCOMP_CFG, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); 280 int fd = open(RUN_SECCOMP_CFG, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
diff --git a/src/firejail/util.c b/src/firejail/util.c
index 4b2e09953..4384c2b0b 100644
--- a/src/firejail/util.c
+++ b/src/firejail/util.c
@@ -696,3 +696,37 @@ void flush_stdin(void) {
696 } 696 }
697} 697}
698 698
699void create_empty_dir_as_root(const char *dir, mode_t mode) {
700 assert(dir);
701
702 struct stat s;
703 if (stat(dir, &s)) {
704 if (arg_debug)
705 printf("Creating empty %s directory\n", dir);
706 if (mkdir(dir, mode) == -1)
707 errExit("mkdir");
708 if (chmod(dir, mode) == -1)
709 errExit("chmod");
710 ASSERT_PERMS(dir, 0, 0, mode);
711 }
712
713}
714
715void create_empty_file_as_root(const char *fname, mode_t mode) {
716 assert(fname);
717 struct stat s;
718
719 if (stat(fname, &s)) {
720 if (arg_debug)
721 printf("Creating empty %s file\n", fname);
722
723 /* coverity[toctou] */
724 FILE *fp = fopen(fname, "w");
725 if (!fp)
726 errExit("fopen");
727
728 SET_PERMS_STREAM(fp, 0, 0, S_IRUSR);
729 fclose(fp);
730 }
731}
732
diff --git a/src/fnet/arp.c b/src/fnet/arp.c
new file mode 100644
index 000000000..96684fdf9
--- /dev/null
+++ b/src/fnet/arp.c
@@ -0,0 +1,208 @@
1/*
2 * Copyright (C) 2014-2016 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20#include "fnet.h"
21#include <sys/socket.h>
22#include <sys/ioctl.h>
23#include <linux/if_ether.h> //TCP/IP Protocol Suite for Linux
24#include <net/if.h>
25#include <netinet/in.h>
26#include <linux/ip.h>
27#include <linux/udp.h>
28#include <linux/tcp.h>
29#include <linux/if_packet.h>
30
31typedef struct arp_hdr_t {
32 uint16_t htype;
33 uint16_t ptype;
34 uint8_t hlen;
35 uint8_t plen;
36 uint16_t opcode;
37 uint8_t sender_mac[6];
38 uint8_t sender_ip[4];
39 uint8_t target_mac[6];
40 uint8_t target_ip[4];
41} ArpHdr;
42
43
44// scan interface (--scan option)
45void arp_scan(const char *dev, uint32_t ifip, uint32_t ifmask) {
46 assert(dev);
47 assert(ifip);
48
49// printf("Scanning interface %s (%d.%d.%d.%d/%d)\n",
50// dev, PRINT_IP(ifip & ifmask), mask2bits(ifmask));
51
52 if (strlen(dev) > IFNAMSIZ) {
53 fprintf(stderr, "Error: invalid network device name %s\n", dev);
54 exit(1);
55 }
56
57 // find interface mac address
58 int sock;
59 if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
60 errExit("socket");
61 struct ifreq ifr;
62 memset(&ifr, 0, sizeof (ifr));
63 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
64 if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
65 errExit("ioctl");
66 close(sock);
67 uint8_t mac[6];
68 memcpy (mac, ifr.ifr_hwaddr.sa_data, 6);
69
70 // open layer2 socket
71 if ((sock = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0)
72 errExit("socket");
73
74 // try all possible ip addresses in ascending order
75 uint32_t range = ~ifmask + 1; // the number of potential addresses
76 // this software is not supported for /31 networks
77 if (range < 4) {
78 fprintf(stderr, "Warning: this option is not supported for /31 networks\n");
79 close(sock);
80 return;
81 }
82
83 uint32_t dest = (ifip & ifmask) + 1;
84 uint32_t last = dest + range - 1;
85 uint32_t src = htonl(ifip);
86
87 // wait not more than one second for an answer
88 int header_printed = 0;
89 uint32_t last_ip = 0;
90 struct timeval ts;
91 ts.tv_sec = 2; // 2 seconds receive timeout
92 ts.tv_usec = 0;
93
94 while (1) {
95 fd_set rfds;
96 FD_ZERO(&rfds);
97 FD_SET(sock, &rfds);
98 fd_set wfds;
99 FD_ZERO(&wfds);
100 FD_SET(sock, &wfds);
101 int maxfd = sock;
102
103 uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc
104 memset(frame, 0, ETH_FRAME_LEN);
105
106 int nready;
107 if (dest < last)
108 nready = select(maxfd + 1, &rfds, &wfds, (fd_set *) 0, NULL);
109 else
110 nready = select(maxfd + 1, &rfds, (fd_set *) 0, (fd_set *) 0, &ts);
111
112 if (nready < 0)
113 errExit("select");
114
115 if (nready == 0) { // timeout
116 break;
117 }
118
119 if (FD_ISSET(sock, &wfds) && dest < last) {
120 // configure layer2 socket address information
121 struct sockaddr_ll addr;
122 memset(&addr, 0, sizeof(addr));
123 if ((addr.sll_ifindex = if_nametoindex(dev)) == 0)
124 errExit("if_nametoindex");
125 addr.sll_family = AF_PACKET;
126 memcpy (addr.sll_addr, mac, 6);
127 addr.sll_halen = htons(6);
128
129 // build the arp packet header
130 ArpHdr hdr;
131 memset(&hdr, 0, sizeof(hdr));
132 hdr.htype = htons(1);
133 hdr.ptype = htons(ETH_P_IP);
134 hdr.hlen = 6;
135 hdr.plen = 4;
136 hdr.opcode = htons(1); //ARPOP_REQUEST
137 memcpy(hdr.sender_mac, mac, 6);
138 memcpy(hdr.sender_ip, (uint8_t *)&src, 4);
139 uint32_t dst = htonl(dest);
140 memcpy(hdr.target_ip, (uint8_t *)&dst, 4);
141
142 // build ethernet frame
143 uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc
144 memset(frame, 0, sizeof(frame));
145 frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff;
146 memcpy(frame + 6, mac, 6);
147 frame[12] = ETH_P_ARP / 256;
148 frame[13] = ETH_P_ARP % 256;
149 memcpy (frame + 14, &hdr, sizeof(hdr));
150
151 // send packet
152 int len;
153 if ((len = sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr))) <= 0)
154 errExit("send");
155//printf("send %d bytes to %d.%d.%d.%d\n", len, PRINT_IP(dest));
156 fflush(0);
157 dest++;
158 }
159
160 if (FD_ISSET(sock, &rfds)) {
161 // read the incoming packet
162 int len = recvfrom(sock, frame, ETH_FRAME_LEN, 0, NULL, NULL);
163 if (len < 0) {
164 perror("recvfrom");
165 }
166
167 // parse the incoming packet
168 if ((unsigned int) len < 14 + sizeof(ArpHdr))
169 continue;
170
171 // look only at ARP packets
172 if (frame[12] != (ETH_P_ARP / 256) || frame[13] != (ETH_P_ARP % 256))
173 continue;
174
175 ArpHdr hdr;
176 memcpy(&hdr, frame + 14, sizeof(ArpHdr));
177
178 if (hdr.opcode == htons(2)) {
179 // check my mac and my address
180 if (memcmp(mac, hdr.target_mac, 6) != 0)
181 continue;
182 uint32_t ip;
183 memcpy(&ip, hdr.target_ip, 4);
184 if (ip != src)
185 continue;
186 memcpy(&ip, hdr.sender_ip, 4);
187 ip = ntohl(ip);
188
189 if (ip == last_ip) // filter duplicates
190 continue;
191 last_ip = ip;
192
193 // printing
194 if (header_printed == 0) {
195 printf(" Network scan:\n");
196 header_printed = 1;
197 }
198 printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n",
199 PRINT_MAC(hdr.sender_mac), PRINT_IP(ip));
200 }
201 }
202 }
203
204 close(sock);
205}
206
207
208
diff --git a/src/fnet/fnet.h b/src/fnet/fnet.h
index 58efbbed5..0c5e5baef 100644
--- a/src/fnet/fnet.h
+++ b/src/fnet/fnet.h
@@ -36,5 +36,14 @@ void net_bridge_add_interface(const char *bridge, const char *dev);
36void net_if_up(const char *ifname); 36void net_if_up(const char *ifname);
37int net_get_mtu(const char *ifname); 37int net_get_mtu(const char *ifname);
38void net_set_mtu(const char *ifname, int mtu); 38void net_set_mtu(const char *ifname, int mtu);
39void net_ifprint(int scan);
40int net_get_mac(const char *ifname, unsigned char mac[6]);
41void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu);
42int net_if_mac(const char *ifname, const unsigned char mac[6]);
43void net_if_ip6(const char *ifname, const char *addr6);
44
45
46// arp.c
47void arp_scan(const char *dev, uint32_t ifip, uint32_t ifmask);
39 48
40#endif 49#endif
diff --git a/src/fnet/interface.c b/src/fnet/interface.c
index b1903dd46..67af062bf 100644
--- a/src/fnet/interface.c
+++ b/src/fnet/interface.c
@@ -180,4 +180,216 @@ void net_set_mtu(const char *ifname, int mtu) {
180 close(s); 180 close(s);
181} 181}
182 182
183// scan interfaces in current namespace and print IP address/mask for each interface
184void net_ifprint(int scan) {
185 uint32_t ip;
186 uint32_t mask;
187 struct ifaddrs *ifaddr, *ifa;
183 188
189 if (getifaddrs(&ifaddr) == -1)
190 errExit("getifaddrs");
191
192 printf("%-17.17s%-19.19s%-17.17s%-17.17s%-6.6s\n",
193 "Interface", "MAC", "IP", "Mask", "Status");
194 // walk through the linked list
195 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
196 if (ifa->ifa_addr == NULL)
197 continue;
198
199 if (ifa->ifa_addr->sa_family == AF_INET) {
200 struct sockaddr_in *si = (struct sockaddr_in *) ifa->ifa_netmask;
201 mask = ntohl(si->sin_addr.s_addr);
202 si = (struct sockaddr_in *) ifa->ifa_addr;
203 ip = ntohl(si->sin_addr.s_addr);
204
205 // interface status
206 char *status;
207 if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP)
208 status = "UP";
209 else
210 status = "DOWN";
211
212 // ip address and mask
213 char ipstr[30];
214 sprintf(ipstr, "%d.%d.%d.%d", PRINT_IP(ip));
215 char maskstr[30];
216 sprintf(maskstr, "%d.%d.%d.%d", PRINT_IP(mask));
217
218 // mac address
219 unsigned char mac[6];
220 net_get_mac(ifa->ifa_name, mac);
221 char macstr[30];
222 if (strcmp(ifa->ifa_name, "lo") == 0)
223 macstr[0] = '\0';
224 else
225 sprintf(macstr, "%02x:%02x:%02x:%02x:%02x:%02x", PRINT_MAC(mac));
226
227 // print
228 printf("%-17.17s%-19.19s%-17.17s%-17.17s%-6.6s\n",
229 ifa->ifa_name, macstr, ipstr, maskstr, status);
230
231 // network scanning
232 if (!scan) // scanning disabled
233 continue;
234 if (strcmp(ifa->ifa_name, "lo") == 0) // no loopbabck scanning
235 continue;
236 if (mask2bits(mask) < 16) // not scanning large networks
237 continue;
238 if (!ip) // if not configured
239 continue;
240 // only if the interface is up and running
241 if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP)
242 arp_scan(ifa->ifa_name, ip, mask);
243 }
244 }
245 freeifaddrs(ifaddr);
246}
247
248int net_get_mac(const char *ifname, unsigned char mac[6]) {
249
250 struct ifreq ifr;
251 int sock;
252
253 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
254 errExit("socket");
255
256 memset(&ifr, 0, sizeof(ifr));
257 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
258 ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
259
260 if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1)
261 errExit("ioctl");
262 memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
263
264 close(sock);
265 return 0;
266}
267
268// configure interface ipv4 address
269void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu) {
270 if (strlen(ifname) > IFNAMSIZ) {
271 fprintf(stderr, "Error: invalid network device name %s\n", ifname);
272 exit(1);
273 }
274
275 int sock = socket(AF_INET,SOCK_DGRAM,0);
276 if (sock < 0)
277 errExit("socket");
278
279 struct ifreq ifr;
280 memset(&ifr, 0, sizeof(ifr));
281 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
282 ifr.ifr_addr.sa_family = AF_INET;
283
284 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(ip);
285 if (ioctl( sock, SIOCSIFADDR, &ifr ) < 0) {
286 close(sock);
287 errExit("ioctl");
288 }
289
290 if (ip != 0) {
291 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(mask);
292 if (ioctl( sock, SIOCSIFNETMASK, &ifr ) < 0) {
293 close(sock);
294 errExit("ioctl");
295 }
296 }
297
298 // configure mtu
299 if (mtu > 0) {
300 ifr.ifr_mtu = mtu;
301 if (ioctl( sock, SIOCSIFMTU, &ifr ) < 0) {
302 close(sock);
303 errExit("ioctl");
304 }
305 }
306
307 close(sock);
308 usleep(10000); // sleep 10ms
309}
310
311int net_if_mac(const char *ifname, const unsigned char mac[6]) {
312 struct ifreq ifr;
313 int sock;
314
315 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
316 errExit("socket");
317
318 memset(&ifr, 0, sizeof(ifr));
319 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
320 ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
321 memcpy(ifr.ifr_hwaddr.sa_data, mac, 6);
322
323 if (ioctl(sock, SIOCSIFHWADDR, &ifr) == -1)
324 errExit("ioctl");
325 close(sock);
326 return 0;
327}
328
329// configure interface ipv6 address
330// ex: firejail --net=eth0 --ip6=2001:0db8:0:f101::1/64
331struct ifreq6 {
332 struct in6_addr ifr6_addr;
333 uint32_t ifr6_prefixlen;
334 unsigned int ifr6_ifindex;
335};
336void net_if_ip6(const char *ifname, const char *addr6) {
337 if (strchr(addr6, ':') == NULL) {
338 fprintf(stderr, "Error fnet: invalid IPv6 address %s\n", addr6);
339 exit(1);
340 }
341
342 // extract prefix
343 unsigned long prefix;
344 char *ptr;
345 if ((ptr = strchr(addr6, '/'))) {
346 prefix = atol(ptr + 1);
347 if (prefix > 128) {
348 fprintf(stderr, "Error fnet: invalid prefix for IPv6 address %s\n", addr6);
349 exit(1);
350 }
351 *ptr = '\0'; // mark the end of the address
352 }
353 else
354 prefix = 128;
355
356 // extract address
357 struct sockaddr_in6 sin6;
358 memset(&sin6, 0, sizeof(sin6));
359 sin6.sin6_family = AF_INET6;
360 int rv = inet_pton(AF_INET6, addr6, sin6.sin6_addr.s6_addr);
361 if (rv <= 0) {
362 fprintf(stderr, "Error fnet: invalid IPv6 address %s\n", addr6);
363 exit(1);
364 }
365
366 // open socket
367 int sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
368 if (sock < 0) {
369 fprintf(stderr, "Error fnet: IPv6 is not supported on this system\n");
370 exit(1);
371 }
372
373 // find interface index
374 struct ifreq ifr;
375 memset(&ifr, 0, sizeof(ifr));
376 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
377 ifr.ifr_addr.sa_family = AF_INET;
378 if (ioctl(sock, SIOGIFINDEX, &ifr) < 0) {
379 perror("ioctl SIOGIFINDEX");
380 exit(1);
381 }
382
383 // configure address
384 struct ifreq6 ifr6;
385 memset(&ifr6, 0, sizeof(ifr6));
386 ifr6.ifr6_prefixlen = prefix;
387 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
388 memcpy((char *) &ifr6.ifr6_addr, (char *) &sin6.sin6_addr, sizeof(struct in6_addr));
389 if (ioctl(sock, SIOCSIFADDR, &ifr6) < 0) {
390 perror("ioctl SIOCSIFADDR");
391 exit(1);
392 }
393
394 close(sock);
395}
diff --git a/src/fnet/main.c b/src/fnet/main.c
index f17287cb9..4ae9eb6e3 100644
--- a/src/fnet/main.c
+++ b/src/fnet/main.c
@@ -24,12 +24,18 @@ static void usage(void) {
24 printf("\tfnet create veth dev1 dev2 bridge child\n"); 24 printf("\tfnet create veth dev1 dev2 bridge child\n");
25 printf("\tfnet create macvlan dev parent child\n"); 25 printf("\tfnet create macvlan dev parent child\n");
26 printf("\tfnet moveif dev proc\n"); 26 printf("\tfnet moveif dev proc\n");
27 printf("\tfnet printif\n");
28 printf("\tfnet printif scan\n");
29 printf("\tfnet config interface dev ip mask mtu\n");
30 printf("\tfnet config mac addr\n");
31 printf("\tfnet config ipv6 dev ipn");
32 printf("\tfmet ifup dev\n");
27} 33}
28 34
29int main(int argc, char **argv) { 35int main(int argc, char **argv) {
30#if 0 36#if 0
31{ 37{
32system("cat /proc/self/status"); 38//system("cat /proc/self/status");
33int i; 39int i;
34for (i = 0; i < argc; i++) 40for (i = 0; i < argc; i++)
35 printf("*%s* ", argv[i]); 41 printf("*%s* ", argv[i]);
@@ -45,22 +51,49 @@ printf("\n");
45 usage(); 51 usage();
46 return 0; 52 return 0;
47 } 53 }
54 else if (argc == 3 && strcmp(argv[1], "ifup") == 0) {
55 net_if_up(argv[2]);
56 }
57 else if (argc == 2 && strcmp(argv[1], "printif") == 0) {
58 net_ifprint(0);
59 }
60 else if (argc == 3 && strcmp(argv[1], "printif") == 0 && strcmp(argv[2], "scan") == 0) {
61 net_ifprint(1);
62 }
48 else if (argc == 7 && strcmp(argv[1], "create") == 0 && strcmp(argv[2], "veth") == 0) { 63 else if (argc == 7 && strcmp(argv[1], "create") == 0 && strcmp(argv[2], "veth") == 0) {
49 // create veth pair and move one end in the the namespace 64 // create veth pair and move one end in the the namespace
50 net_create_veth(argv[3], argv[4], atoi(argv[6])); 65 net_create_veth(argv[3], argv[4], atoi(argv[6]));
51
52 // connect the ohter veth end to the bridge ... 66 // connect the ohter veth end to the bridge ...
53 net_bridge_add_interface(argv[5], argv[3]); 67 net_bridge_add_interface(argv[5], argv[3]);
54
55 // ... and bring it up 68 // ... and bring it up
56 net_if_up(argv[3]); 69 net_if_up(argv[3]);
57 } 70 }
58 else if (argc == 6 && strcmp(argv[1], "create") == 0 && strcmp(argv[2], "macvlan") == 0) { 71 else if (argc == 6 && strcmp(argv[1], "create") == 0 && strcmp(argv[2], "macvlan") == 0) {
59 net_create_macvlan(argv[3], argv[4], atoi(argv[5])); 72 net_create_macvlan(argv[3], argv[4], atoi(argv[5]));
60 } 73 }
74 else if (argc == 7 && strcmp(argv[1], "config") == 0 && strcmp(argv[2], "interface") == 0) {
75 char *dev = argv[3];
76 uint32_t ip = (uint32_t) atoll(argv[4]);
77 uint32_t mask = (uint32_t) atoll(argv[5]);
78 int mtu = atoi(argv[6]);
79 // configure interface
80 net_if_ip(dev, ip, mask, mtu);
81 // ... and bring it up
82 net_if_up(dev);
83 }
84 else if (argc == 5 && strcmp(argv[1], "config") == 0 && strcmp(argv[2], "mac") == 0) {
85 unsigned char mac[6];
86 if (atomac(argv[4], mac)) {
87 fprintf(stderr, "Error fnet: invalid mac address %s\n", argv[4]);
88 }
89 net_if_mac(argv[3], mac);
90 }
61 else if (argc == 4 && strcmp(argv[1], "moveif") == 0) { 91 else if (argc == 4 && strcmp(argv[1], "moveif") == 0) {
62 net_move_interface(argv[2], atoi(argv[3])); 92 net_move_interface(argv[2], atoi(argv[3]));
63 } 93 }
94 else if (argc == 5 && strcmp(argv[1], "config") == 0 && strcmp(argv[2], "ipv6") == 0) {
95 net_if_ip6(argv[3], argv[4]);
96 }
64 else { 97 else {
65 fprintf(stderr, "Error fnet: invalid arguments\n"); 98 fprintf(stderr, "Error fnet: invalid arguments\n");
66 return 1; 99 return 1;
diff --git a/src/fseccomp/main.c b/src/fseccomp/main.c
index 59d426a78..f53e2ef8b 100644
--- a/src/fseccomp/main.c
+++ b/src/fseccomp/main.c
@@ -9,15 +9,15 @@ static void usage(void) {
9} 9}
10 10
11int main(int argc, char **argv) { 11int main(int argc, char **argv) {
12//#if 0 12#if 0
13{ 13{
14//system("cat /proc/self/status"); 14system("cat /proc/self/status");
15int i; 15int i;
16for (i = 0; i < argc; i++) 16for (i = 0; i < argc; i++)
17 printf("*%s* ", argv[i]); 17 printf("*%s* ", argv[i]);
18printf("\n"); 18printf("\n");
19} 19}
20//#endif 20#endif
21 if (argc < 2) 21 if (argc < 2)
22 return 1; 22 return 1;
23 23