aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--RELNOTES1
-rw-r--r--etc/firejail.config8
-rw-r--r--src/firejail/arp.c100
-rw-r--r--src/firejail/checkcfg.c10
-rw-r--r--src/firejail/firejail.h3
-rw-r--r--src/firejail/sandbox.c2
6 files changed, 114 insertions, 10 deletions
diff --git a/RELNOTES b/RELNOTES
index 6c4c94c6a..84e474e73 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -4,6 +4,7 @@ firejail (0.9.49) baseline; urgency=low
4 * feature: per-profile support to set X11 Xephyr screen size (--xephyr-screen) 4 * feature: per-profile support to set X11 Xephyr screen size (--xephyr-screen)
5 * enhancement: /proc/sys mounting 5 * enhancement: /proc/sys mounting
6 * enhancement: default seccomp list update 6 * enhancement: default seccomp list update
7 * enhancement: rework IP address assingment for --net options
7 * new profiles: curl, mplayer2, SMPlayer, Calibre, ebook-viewer, KWrite, 8 * new profiles: curl, mplayer2, SMPlayer, Calibre, ebook-viewer, KWrite,
8 * new profiles: Geary, Liferea, peek, silentarmy, IntelliJ IDEA, 9 * new profiles: Geary, Liferea, peek, silentarmy, IntelliJ IDEA,
9 * new profiles: Android Studio, electron, riot-web 10 * new profiles: Android Studio, electron, riot-web
diff --git a/etc/firejail.config b/etc/firejail.config
index 1db33edda..22ce77324 100644
--- a/etc/firejail.config
+++ b/etc/firejail.config
@@ -2,6 +2,14 @@
2# keyword-argument pairs, one per line. Most features are enabled by default. 2# keyword-argument pairs, one per line. Most features are enabled by default.
3# Use 'yes' or 'no' as configuration values. 3# Use 'yes' or 'no' as configuration values.
4 4
5
6# Number of ARP probes sent when assigning an IP address for --net option,
7# default 2. This is a partial implementation of RFC 5227. A 0.5 seconds
8# timeout is implemented for each probe. Increase this number to 4 if your
9# local layer 2 network uses RSTP (IEEE 802.1w). Permitted values are
10# between 1 and 30.
11# arp-probes 2
12
5# Enable or disable bind support, default enabled. 13# Enable or disable bind support, default enabled.
6# bind yes 14# bind yes
7 15
diff --git a/src/firejail/arp.c b/src/firejail/arp.c
index 6d21167f0..ffbc56841 100644
--- a/src/firejail/arp.c
+++ b/src/firejail/arp.c
@@ -41,6 +41,79 @@ typedef struct arp_hdr_t {
41} ArpHdr; 41} ArpHdr;
42 42
43 43
44// gracious arp announcing our address
45void arp_announce(const char *dev, Bridge *br) {
46 // RFC 5227 - using a source and destination IP address of the interface
47 uint32_t srcaddr = br->ipsandbox;
48 uint32_t destaddr = br->ipsandbox;
49
50 if (strlen(dev) > IFNAMSIZ) {
51 fprintf(stderr, "Error: invalid network device name %s\n", dev);
52 exit(1);
53 }
54
55 if (arg_debug)
56 printf("Announce %d.%d.%d.%d ...\n", PRINT_IP(destaddr));
57
58 // find interface address
59 int sock;
60 if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
61 errExit("socket");
62
63 srcaddr = htonl(srcaddr);
64 destaddr = htonl(destaddr);
65
66 // Find interface MAC address
67 struct ifreq ifr;
68 memset(&ifr, 0, sizeof (ifr));
69 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
70 if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
71 errExit("ioctl");
72 close(sock);
73
74 // configure layer2 socket address information
75 struct sockaddr_ll addr;
76 memset(&addr, 0, sizeof(addr));
77 if ((addr.sll_ifindex = if_nametoindex(dev)) == 0)
78 errExit("if_nametoindex");
79 addr.sll_family = AF_PACKET;
80 memcpy (addr.sll_addr, ifr.ifr_hwaddr.sa_data, 6);
81 addr.sll_halen = htons(6);
82
83 // build the arp packet header
84 ArpHdr hdr;
85 memset(&hdr, 0, sizeof(hdr));
86 hdr.htype = htons(1);
87 hdr.ptype = htons(ETH_P_IP);
88 hdr.hlen = 6;
89 hdr.plen = 4;
90 hdr.opcode = htons(1); //ARPOP_REQUEST
91 memcpy(hdr.sender_mac, ifr.ifr_hwaddr.sa_data, 6);
92 memcpy(hdr.sender_ip, (uint8_t *)&srcaddr, 4);
93 memcpy(hdr.target_ip, (uint8_t *)&destaddr, 4);
94
95 // build ethernet frame
96 uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc
97 memset(frame, 0, sizeof(frame));
98 frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff;
99 memcpy(frame + 6, ifr.ifr_hwaddr.sa_data, 6);
100 frame[12] = ETH_P_ARP / 256;
101 frame[13] = ETH_P_ARP % 256;
102 memcpy (frame + 14, &hdr, sizeof(hdr));
103
104 // open layer2 socket
105 if ((sock = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0)
106 errExit("socket");
107
108 int len;
109 if ((len = sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr))) <= 0)
110 errExit("send");
111 fflush(0);
112 close(sock);
113}
114
115
116
44// returns 0 if the address is not in use, -1 otherwise 117// returns 0 if the address is not in use, -1 otherwise
45int arp_check(const char *dev, uint32_t destaddr) { 118int arp_check(const char *dev, uint32_t destaddr) {
46 // RFC 5227 - using a source IP address of 0 for probing 119 // RFC 5227 - using a source IP address of 0 for probing
@@ -92,7 +165,7 @@ int arp_check(const char *dev, uint32_t destaddr) {
92 memcpy(hdr.target_ip, (uint8_t *)&destaddr, 4); 165 memcpy(hdr.target_ip, (uint8_t *)&destaddr, 4);
93 166
94 // build ethernet frame 167 // build ethernet frame
95 uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc 168 uint8_t frame[ETH_FRAME_LEN]; // includes eth header, vlan, and crc
96 memset(frame, 0, sizeof(frame)); 169 memset(frame, 0, sizeof(frame));
97 frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff; 170 frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff;
98 memcpy(frame + 6, ifr.ifr_hwaddr.sa_data, 6); 171 memcpy(frame + 6, ifr.ifr_hwaddr.sa_data, 6);
@@ -109,25 +182,34 @@ int arp_check(const char *dev, uint32_t destaddr) {
109 errExit("send"); 182 errExit("send");
110 fflush(0); 183 fflush(0);
111 184
112 // wait not more than one second for an answer 185 // send two probes at 0.5 seconds interva;
186 int cnt = checkcfg(CFG_ARP_PROBES);
187 uint8_t framerx[ETH_FRAME_LEN]; // includes eth header, vlan, and crc
113 fd_set fds; 188 fd_set fds;
114 FD_ZERO(&fds); 189 FD_ZERO(&fds);
115 FD_SET(sock, &fds); 190 FD_SET(sock, &fds);
116 int maxfd = sock; 191 int maxfd = sock;
117 struct timeval ts; 192 struct timeval ts;
118 ts.tv_sec = 1; // 1 second wait time 193 ts.tv_sec = 0; // 0.5 seconds wait time
119 ts.tv_usec = 0; 194 ts.tv_usec = 500000;
120 while (1) { 195 while (1) {
121 int nready = select(maxfd + 1, &fds, (fd_set *) 0, (fd_set *) 0, &ts); 196 int nready = select(maxfd + 1, &fds, (fd_set *) 0, (fd_set *) 0, &ts);
122 if (nready < 0) 197 if (nready < 0)
123 errExit("select"); 198 errExit("select");
124 else if (nready == 0) { // timeout 199 else if (nready == 0) { // timeout
125 close(sock); 200 if (--cnt <= 0) {
126 return 0; 201 close(sock);
202 return 0;
203 }
204 if ((len = sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr))) <= 0)
205 errExit("send");
206 ts.tv_sec = 0; // 0.5 seconds wait time
207 ts.tv_usec = 500000;
208 fflush(0);
127 } 209 }
128 else { 210 else {
129 // read the incoming packet 211 // read the incoming packet
130 int len = recvfrom(sock, frame, ETH_FRAME_LEN, 0, NULL, NULL); 212 int len = recvfrom(sock, framerx, ETH_FRAME_LEN, 0, NULL, NULL);
131 if (len < 0) { 213 if (len < 0) {
132 perror("recvfrom"); 214 perror("recvfrom");
133 close(sock); 215 close(sock);
@@ -137,9 +219,9 @@ int arp_check(const char *dev, uint32_t destaddr) {
137 // parse the incoming packet 219 // parse the incoming packet
138 if ((unsigned int) len < 14 + sizeof(ArpHdr)) 220 if ((unsigned int) len < 14 + sizeof(ArpHdr))
139 continue; 221 continue;
140 if (frame[12] != (ETH_P_ARP / 256) || frame[13] != (ETH_P_ARP % 256)) 222 if (framerx[12] != (ETH_P_ARP / 256) || framerx[13] != (ETH_P_ARP % 256))
141 continue; 223 continue;
142 memcpy(&hdr, frame + 14, sizeof(ArpHdr)); 224 memcpy(&hdr, framerx + 14, sizeof(ArpHdr));
143 if (hdr.opcode == htons(1)) 225 if (hdr.opcode == htons(1))
144 continue; 226 continue;
145 if (hdr.opcode == htons(2)) { 227 if (hdr.opcode == htons(2)) {
diff --git a/src/firejail/checkcfg.c b/src/firejail/checkcfg.c
index f4e28f084..9703c9a5b 100644
--- a/src/firejail/checkcfg.c
+++ b/src/firejail/checkcfg.c
@@ -49,6 +49,7 @@ int checkcfg(int val) {
49 cfg_val[CFG_FIREJAIL_PROMPT] = 0; 49 cfg_val[CFG_FIREJAIL_PROMPT] = 0;
50 cfg_val[CFG_FOLLOW_SYMLINK_PRIVATE_BIN] = 0; 50 cfg_val[CFG_FOLLOW_SYMLINK_PRIVATE_BIN] = 0;
51 cfg_val[CFG_DISABLE_MNT] = 0; 51 cfg_val[CFG_DISABLE_MNT] = 0;
52 cfg_val[CFG_ARP_PROBES] = DEFAULT_ARP_PROBES;
52 53
53 // open configuration file 54 // open configuration file
54 const char *fname = SYSCONFDIR "/firejail.config"; 55 const char *fname = SYSCONFDIR "/firejail.config";
@@ -267,7 +268,7 @@ int checkcfg(int val) {
267 } 268 }
268 269
269 // Xvfb screen size 270 // Xvfb screen size
270 else if (strncmp(ptr, "xvfb-screen ", 12) == 0) { 271 else if (strncmp(ptr, "xvfb-screen ", 12) == 0) {
271 // expecting three numbers separated by x's 272 // expecting three numbers separated by x's
272 unsigned int n1; 273 unsigned int n1;
273 unsigned int n2; 274 unsigned int n2;
@@ -346,6 +347,13 @@ int checkcfg(int val) {
346 else 347 else
347 goto errout; 348 goto errout;
348 } 349 }
350 // arp probes
351 else if (strncmp(ptr, "arp-probes ", 11) == 0) {
352 int arp_probes = atoi(ptr + 11);
353 if (arp_probes <= 1 || arp_probes > 30)
354 goto errout;
355 cfg_val[CFG_ARP_PROBES] = arp_probes;
356 }
349 else 357 else
350 goto errout; 358 goto errout;
351 359
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 5fd978f51..b90c8d8ed 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -446,6 +446,7 @@ void shut(pid_t pid);
446int restricted_shell(const char *user); 446int restricted_shell(const char *user);
447 447
448// arp.c 448// arp.c
449void arp_announce(const char *dev, Bridge *br);
449// returns 0 if the address is not in use, -1 otherwise 450// returns 0 if the address is not in use, -1 otherwise
450int arp_check(const char *dev, uint32_t destaddr); 451int arp_check(const char *dev, uint32_t destaddr);
451// assign an IP address using arp scanning 452// assign an IP address using arp scanning
@@ -672,6 +673,7 @@ enum {
672void sandboxfs(int op, pid_t pid, const char *path1, const char *path2); 673void sandboxfs(int op, pid_t pid, const char *path1, const char *path2);
673 674
674// checkcfg.c 675// checkcfg.c
676#define DEFAULT_ARP_PROBES 2
675enum { 677enum {
676 CFG_FILE_TRANSFER = 0, 678 CFG_FILE_TRANSFER = 0,
677 CFG_X11, 679 CFG_X11,
@@ -694,6 +696,7 @@ enum {
694 CFG_FOLLOW_SYMLINK_PRIVATE_BIN, 696 CFG_FOLLOW_SYMLINK_PRIVATE_BIN,
695 CFG_DISABLE_MNT, 697 CFG_DISABLE_MNT,
696 CFG_JOIN, 698 CFG_JOIN,
699 CFG_ARP_PROBES,
697 CFG_MAX // this should always be the last entry 700 CFG_MAX // this should always be the last entry
698}; 701};
699extern char *xephyr_screen; 702extern char *xephyr_screen;
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index 8c5c02d41..47c6b7a06 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -141,6 +141,7 @@ static void sandbox_if_up(Bridge *br) {
141 if (arg_debug) 141 if (arg_debug)
142 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev); 142 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev);
143 net_config_interface(dev, br->ipsandbox, br->mask, br->mtu); 143 net_config_interface(dev, br->ipsandbox, br->mask, br->mtu);
144 arp_announce(dev, br);
144 } 145 }
145 else if (br->arg_ip_none == 0 && br->macvlan == 1) { 146 else if (br->arg_ip_none == 0 && br->macvlan == 1) {
146 // reassign the macvlan address 147 // reassign the macvlan address
@@ -163,6 +164,7 @@ static void sandbox_if_up(Bridge *br) {
163 if (arg_debug) 164 if (arg_debug)
164 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev); 165 printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev);
165 net_config_interface(dev, br->ipsandbox, br->mask, br->mtu); 166 net_config_interface(dev, br->ipsandbox, br->mask, br->mtu);
167 arp_announce(dev, br);
166 } 168 }
167 169
168 if (br->ip6sandbox) 170 if (br->ip6sandbox)