diff options
Diffstat (limited to 'src')
71 files changed, 21393 insertions, 0 deletions
diff --git a/src/firejail/Makefile.in b/src/firejail/Makefile.in new file mode 100644 index 000000000..1f7b563c4 --- /dev/null +++ b/src/firejail/Makefile.in | |||
@@ -0,0 +1,28 @@ | |||
1 | all: firejail | ||
2 | |||
3 | PREFIX=@prefix@ | ||
4 | VERSION=@PACKAGE_VERSION@ | ||
5 | NAME=@PACKAGE_NAME@ | ||
6 | HAVE_SECCOMP_H=@HAVE_SECCOMP_H@ | ||
7 | HAVE_SECCOMP=@HAVE_SECCOMP@ | ||
8 | HAVE_CHROOT=@HAVE_CHROOT@ | ||
9 | HAVE_BIND=@HAVE_BIND@ | ||
10 | |||
11 | H_FILE_LIST = $(wildcard *.[h]) | ||
12 | C_FILE_LIST = $(wildcard *.c) | ||
13 | OBJS = $(C_FILE_LIST:.c=.o) | ||
14 | BINOBJS = $(foreach file, $(OBJS), $file) | ||
15 | CFLAGS += -ggdb -O2 -DVERSION='"$(VERSION)"' -DPREFIX='"$(PREFIX)"' $(HAVE_SECCOMP) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_BIND) -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security | ||
16 | LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread | ||
17 | |||
18 | %.o : %.c $(H_FILE_LIST) | ||
19 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ | ||
20 | |||
21 | firejail: $(OBJS) ../lib/libnetlink.o ../lib/common.o | ||
22 | $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/libnetlink.o ../lib/common.o $(LIBS) | ||
23 | |||
24 | clean:; rm -f *.o firejail firejail.1 firejail.1.gz | ||
25 | |||
26 | distclean: clean | ||
27 | rm -fr Makefile | ||
28 | |||
diff --git a/src/firejail/arg-checking.txt b/src/firejail/arg-checking.txt new file mode 100644 index 000000000..c1ab2cb21 --- /dev/null +++ b/src/firejail/arg-checking.txt | |||
@@ -0,0 +1,85 @@ | |||
1 | arg checking: | ||
2 | |||
3 | 1. --output=filename | ||
4 | - not supported in profiles | ||
5 | - checking no "..", | ||
6 | - checking no link, | ||
7 | - checking no dir, | ||
8 | - checking same permissions, | ||
9 | - checking no hard links | ||
10 | - unit test | ||
11 | |||
12 | 2. --chroot=dirname | ||
13 | - not supported in profiles | ||
14 | - expand "~" | ||
15 | - checking no "..", | ||
16 | - checking is dir, | ||
17 | - checking no link | ||
18 | - checking directory structure | ||
19 | - unit test | ||
20 | |||
21 | 3. --bind=dirname1,dirname2, --bind=filename1,filenam2 | ||
22 | - supported in profiles | ||
23 | - accepted only when running as root | ||
24 | - checking string chars | ||
25 | - checking no ".." | ||
26 | - unit test non root | ||
27 | |||
28 | 4. --tmpfs=dirname | ||
29 | - supported in profiles | ||
30 | - checking string chars | ||
31 | - checking no ".." | ||
32 | - unit test | ||
33 | |||
34 | 5. --blacklist=filename, --blacklist=dirname | ||
35 | - supported in profiles | ||
36 | - checking string chars | ||
37 | - checking no ".." | ||
38 | - unit test | ||
39 | |||
40 | 6. --read-only=filename, --read-only=dirname | ||
41 | - supported in profiles | ||
42 | - checking string chars | ||
43 | - checking no ".." | ||
44 | - unit test | ||
45 | |||
46 | 7. --profile=filename | ||
47 | - check access as real GID/UID | ||
48 | - checking no dir | ||
49 | - checking no link | ||
50 | - checking no ".." | ||
51 | - unit test | ||
52 | |||
53 | 8. --private=dirname | ||
54 | - supported in profiles | ||
55 | - expand "~" | ||
56 | - check is dir | ||
57 | - check no link | ||
58 | - checking no ".." | ||
59 | - check same owner | ||
60 | - unit test | ||
61 | |||
62 | 9. --private.keep=filelist | ||
63 | - supported in profiles | ||
64 | - checking no ".." | ||
65 | - checking file found | ||
66 | - checking same owner | ||
67 | - checking no link | ||
68 | - unit test | ||
69 | |||
70 | 10. --netfilter=filename | ||
71 | - supported in profiles | ||
72 | - check access as real GID/UID | ||
73 | - checking no dir | ||
74 | - checking no link | ||
75 | - checking no ".." | ||
76 | - unit test | ||
77 | |||
78 | 11. --shell=filename | ||
79 | - not supported in profiles | ||
80 | - check access as real GID/UID | ||
81 | - checking no dir | ||
82 | - checking no link | ||
83 | - checking no ".." | ||
84 | - unit test | ||
85 | |||
diff --git a/src/firejail/arp.c b/src/firejail/arp.c new file mode 100644 index 000000000..37f8716e7 --- /dev/null +++ b/src/firejail/arp.c | |||
@@ -0,0 +1,474 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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/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 | |||
31 | typedef 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 | // returns 0 if the address is not in use, -1 otherwise | ||
44 | int arp_check(const char *dev, uint32_t destaddr, uint32_t srcaddr) { | ||
45 | if (strlen(dev) > IFNAMSIZ) { | ||
46 | fprintf(stderr, "Error: invalid network device name %s\n", dev); | ||
47 | exit(1); | ||
48 | } | ||
49 | |||
50 | if (arg_debug) | ||
51 | printf("Trying %d.%d.%d.%d ...\n", PRINT_IP(destaddr)); | ||
52 | |||
53 | // find interface address | ||
54 | int sock; | ||
55 | if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) | ||
56 | errExit("socket"); | ||
57 | |||
58 | srcaddr = htonl(srcaddr); | ||
59 | destaddr = htonl(destaddr); | ||
60 | |||
61 | // Find interface MAC address | ||
62 | struct ifreq ifr; | ||
63 | memset(&ifr, 0, sizeof (ifr)); | ||
64 | strncpy(ifr.ifr_name, dev, IFNAMSIZ); | ||
65 | if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) | ||
66 | errExit("ioctl"); | ||
67 | close(sock); | ||
68 | |||
69 | // configure layer2 socket address information | ||
70 | struct sockaddr_ll addr; | ||
71 | memset(&addr, 0, sizeof(addr)); | ||
72 | if ((addr.sll_ifindex = if_nametoindex(dev)) == 0) | ||
73 | errExit("if_nametoindex"); | ||
74 | addr.sll_family = AF_PACKET; | ||
75 | memcpy (addr.sll_addr, ifr.ifr_hwaddr.sa_data, 6); | ||
76 | addr.sll_halen = htons(6); | ||
77 | |||
78 | // build the arp packet header | ||
79 | ArpHdr hdr; | ||
80 | memset(&hdr, 0, sizeof(hdr)); | ||
81 | hdr.htype = htons(1); | ||
82 | hdr.ptype = htons(ETH_P_IP); | ||
83 | hdr.hlen = 6; | ||
84 | hdr.plen = 4; | ||
85 | hdr.opcode = htons(1); //ARPOP_REQUEST | ||
86 | memcpy(hdr.sender_mac, ifr.ifr_hwaddr.sa_data, 6); | ||
87 | memcpy(hdr.sender_ip, (uint8_t *)&srcaddr, 4); | ||
88 | memcpy(hdr.target_ip, (uint8_t *)&destaddr, 4); | ||
89 | |||
90 | // buiild ethernet frame | ||
91 | uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc | ||
92 | memset(frame, 0, sizeof(frame)); | ||
93 | frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff; | ||
94 | memcpy(frame + 6, ifr.ifr_hwaddr.sa_data, 6); | ||
95 | frame[12] = ETH_P_ARP / 256; | ||
96 | frame[13] = ETH_P_ARP % 256; | ||
97 | memcpy (frame + 14, &hdr, sizeof(hdr)); | ||
98 | |||
99 | // open layer2 socket | ||
100 | if ((sock = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) | ||
101 | errExit("socket"); | ||
102 | |||
103 | int len; | ||
104 | if ((len = sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr))) <= 0) | ||
105 | errExit("send"); | ||
106 | fflush(0); | ||
107 | |||
108 | // wait not more than one second for an answer | ||
109 | fd_set fds; | ||
110 | FD_ZERO(&fds); | ||
111 | FD_SET(sock, &fds); | ||
112 | int maxfd = sock; | ||
113 | struct timeval ts; | ||
114 | ts.tv_sec = 1; // 1 second wait time | ||
115 | ts.tv_usec = 0; | ||
116 | while (1) { | ||
117 | int nready = select(maxfd + 1, &fds, (fd_set *) 0, (fd_set *) 0, &ts); | ||
118 | if (nready < 0) | ||
119 | errExit("select"); | ||
120 | else if (nready == 0) { // timeout | ||
121 | close(sock); | ||
122 | return 0; | ||
123 | } | ||
124 | else { | ||
125 | // read the incoming packet | ||
126 | int len = recvfrom(sock, frame, ETH_FRAME_LEN, 0, NULL, NULL); | ||
127 | if (len < 0) { | ||
128 | perror("recvfrom"); | ||
129 | close(sock); | ||
130 | return -1; | ||
131 | } | ||
132 | |||
133 | // parse the incomming packet | ||
134 | if (len < 14 + sizeof(ArpHdr)) | ||
135 | continue; | ||
136 | if (frame[12] != (ETH_P_ARP / 256) || frame[13] != (ETH_P_ARP % 256)) | ||
137 | continue; | ||
138 | memcpy(&hdr, frame + 14, sizeof(ArpHdr)); | ||
139 | if (hdr.opcode == htons(1)) | ||
140 | continue; | ||
141 | if (hdr.opcode == htons(2)) { | ||
142 | // check my mac and my address | ||
143 | if (memcmp(ifr.ifr_hwaddr.sa_data, hdr.target_mac, 6) != 0) | ||
144 | continue; | ||
145 | uint32_t ip; | ||
146 | memcpy(&ip, hdr.target_ip, 4); | ||
147 | if (ip != srcaddr) { | ||
148 | continue; | ||
149 | } | ||
150 | close(sock); | ||
151 | return -1; | ||
152 | } | ||
153 | } | ||
154 | } | ||
155 | |||
156 | // it will never get here! | ||
157 | close(sock); | ||
158 | return -1; | ||
159 | } | ||
160 | |||
161 | // assign a random IP address and check it | ||
162 | // the address needs to be in the range if it --iprange was specified | ||
163 | static uint32_t arp_random(const char *dev, Bridge *br) { | ||
164 | assert(dev); | ||
165 | assert(br); | ||
166 | uint32_t ifip = br->ip; | ||
167 | uint32_t ifmask = br->mask; | ||
168 | assert(ifip); | ||
169 | assert(ifmask); | ||
170 | |||
171 | if (arg_debug) | ||
172 | printf("ARP-scan %s, %d.%d.%d.%d/%d\n", | ||
173 | dev, PRINT_IP(ifip), mask2bits(ifmask)); | ||
174 | |||
175 | // determine the range based on network address | ||
176 | uint32_t range = ~ifmask + 1; // the number of potential addresses | ||
177 | // this software is not supported for /31 networks | ||
178 | if (range < 4) | ||
179 | return 0; // the user will have to set the IP address manually | ||
180 | range -= 2; // subtract the network address and the broadcast address | ||
181 | uint32_t start = (ifip & ifmask) + 1; | ||
182 | |||
183 | // adjust range based on --iprange params | ||
184 | if (br->iprange_start && br->iprange_end) { | ||
185 | start = br->iprange_start; | ||
186 | range = br->iprange_end - br->iprange_start; | ||
187 | } | ||
188 | |||
189 | if (arg_debug) | ||
190 | printf("IP address range from %d.%d.%d.%d to %d.%d.%d.%d\n", | ||
191 | PRINT_IP(start), PRINT_IP(start + range)); | ||
192 | |||
193 | // generate a random address - 10 tries | ||
194 | uint32_t dest = 0; | ||
195 | int i = 0; | ||
196 | for (i = 0; i < 10; i++) { | ||
197 | dest = start + ((uint32_t) rand()) % range; | ||
198 | if (dest == ifip) // do not allow the interface address | ||
199 | continue; // try again | ||
200 | |||
201 | // if we've made it up to here, we have a valid address | ||
202 | break; | ||
203 | } | ||
204 | if (i == 10) // we failed 10 times | ||
205 | return 0; | ||
206 | |||
207 | // check address | ||
208 | uint32_t rv = arp_check(dev, dest, ifip); | ||
209 | if (!rv) | ||
210 | return dest; | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | // go sequentially trough all IP addresses and assign the first one not in use | ||
215 | static uint32_t arp_sequential(const char *dev, Bridge *br) { | ||
216 | assert(dev); | ||
217 | assert(br); | ||
218 | uint32_t ifip = br->ip; | ||
219 | uint32_t ifmask = br->mask; | ||
220 | assert(ifip); | ||
221 | assert(ifmask); | ||
222 | |||
223 | // range based on network address | ||
224 | uint32_t range = ~ifmask + 1; // the number of potential addresses | ||
225 | // this software is not supported for /31 networks | ||
226 | if (range < 4) | ||
227 | return 0; // the user will have to set the IP address manually | ||
228 | range -= 2; // subtract the network address and the broadcast address | ||
229 | |||
230 | // try all possible ip addresses in ascending order | ||
231 | // start address | ||
232 | uint32_t dest = (ifip & ifmask) + 1; | ||
233 | if (br->iprange_start) | ||
234 | dest = br->iprange_start; | ||
235 | // end address | ||
236 | uint32_t last = dest + range - 1; | ||
237 | if (br->iprange_end) | ||
238 | last = br->iprange_end; | ||
239 | |||
240 | if (arg_debug) | ||
241 | printf("Trying IP address range from %d.%d.%d.%d to %d.%d.%d.%d\n", | ||
242 | PRINT_IP(dest), PRINT_IP(last)); | ||
243 | |||
244 | // loop through addresses and stop as soon as you find an unused one | ||
245 | while (dest <= last) { | ||
246 | if (dest == ifip) { | ||
247 | dest++; | ||
248 | continue; | ||
249 | } | ||
250 | uint32_t rv = arp_check(dev, dest, ifip); | ||
251 | if (!rv) | ||
252 | return dest; | ||
253 | dest++; | ||
254 | } | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | // assign an IP address first trying some random addresses, and if this fails | ||
260 | // by doing an arp scan. | ||
261 | // | ||
262 | // dev is the name of the device to use in scanning, | ||
263 | // br is bridge structure holding the ip address and mask to use in | ||
264 | // arp packets. It also holds values for for the range of addresses | ||
265 | // if --iprange was set by the user | ||
266 | uint32_t arp_assign(const char *dev, Bridge *br) { | ||
267 | assert(br); | ||
268 | uint32_t ip = 0; | ||
269 | |||
270 | // try two random IP addresses | ||
271 | ip = arp_random(dev, br); | ||
272 | if (!ip) | ||
273 | ip = arp_random(dev, br); | ||
274 | |||
275 | // try all possible IP addresses one by one | ||
276 | if (!ip) | ||
277 | ip = arp_sequential(dev, br); | ||
278 | |||
279 | // print result | ||
280 | if (!ip) { | ||
281 | fprintf(stderr, "Error: cannot assign an IP address; it looks like all of them are in use.\n"); | ||
282 | logerr("Cannot assign an IP address; it looks like all of them are in use."); | ||
283 | exit(1); | ||
284 | } | ||
285 | |||
286 | return ip; | ||
287 | } | ||
288 | |||
289 | // scan interface (--scan option) | ||
290 | void 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 | int 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 | // buiild 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 incomming packet | ||
413 | if (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 | |||
diff --git a/src/firejail/bandwidth.c b/src/firejail/bandwidth.c new file mode 100644 index 000000000..25dd7a0fb --- /dev/null +++ b/src/firejail/bandwidth.c | |||
@@ -0,0 +1,483 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 | #define _GNU_SOURCE | ||
21 | #include <stdio.h> | ||
22 | #include <sys/types.h> | ||
23 | #include <sys/stat.h> | ||
24 | #include <unistd.h> | ||
25 | #include <net/if.h> | ||
26 | #include "firejail.h" | ||
27 | |||
28 | //*********************************** | ||
29 | // interface bandwidth linked list | ||
30 | //*********************************** | ||
31 | typedef struct ifbw_t { | ||
32 | struct ifbw_t *next; | ||
33 | char *txt; | ||
34 | } IFBW; | ||
35 | IFBW *ifbw = NULL; | ||
36 | |||
37 | |||
38 | #if 0 | ||
39 | static void ifbw_print(void) { | ||
40 | IFBW *ptr = ifbw; | ||
41 | while (ptr) { | ||
42 | printf("#%s#\n", ptr->txt); | ||
43 | ptr = ptr->next; | ||
44 | } | ||
45 | } | ||
46 | #endif | ||
47 | |||
48 | static void ifbw_add(IFBW *ptr) { | ||
49 | assert(ptr); | ||
50 | |||
51 | if (ifbw != NULL) | ||
52 | ptr->next = ifbw; | ||
53 | ifbw = ptr; | ||
54 | } | ||
55 | |||
56 | |||
57 | IFBW *ifbw_find(const char *dev) { | ||
58 | assert(dev); | ||
59 | int len = strlen(dev); | ||
60 | assert(len); | ||
61 | |||
62 | if (ifbw == NULL) | ||
63 | return NULL; | ||
64 | |||
65 | IFBW *ptr = ifbw; | ||
66 | while (ptr) { | ||
67 | if (strncmp(ptr->txt, dev, len) == 0 && ptr->txt[len] == ':') | ||
68 | return ptr; | ||
69 | ptr = ptr->next; | ||
70 | } | ||
71 | |||
72 | return NULL; | ||
73 | } | ||
74 | |||
75 | void ifbw_remove(IFBW *r) { | ||
76 | if (ifbw == NULL) | ||
77 | return; | ||
78 | |||
79 | // remove the first element | ||
80 | if (ifbw == r) { | ||
81 | ifbw = ifbw->next; | ||
82 | return; | ||
83 | } | ||
84 | |||
85 | // walk the list | ||
86 | IFBW *ptr = ifbw->next; | ||
87 | IFBW *prev = ifbw; | ||
88 | while (ptr) { | ||
89 | if (ptr == r) { | ||
90 | prev->next = ptr->next; | ||
91 | return; | ||
92 | } | ||
93 | |||
94 | prev = ptr; | ||
95 | ptr = ptr->next; | ||
96 | } | ||
97 | |||
98 | return; | ||
99 | } | ||
100 | |||
101 | int fibw_count(viod) { | ||
102 | int rv = 0; | ||
103 | IFBW *ptr = ifbw; | ||
104 | |||
105 | while (ptr) { | ||
106 | rv++; | ||
107 | ptr = ptr->next; | ||
108 | } | ||
109 | |||
110 | return rv; | ||
111 | } | ||
112 | |||
113 | |||
114 | //*********************************** | ||
115 | // shm file handling | ||
116 | //*********************************** | ||
117 | void shm_create_firejail_dir(void) { | ||
118 | struct stat s; | ||
119 | if (stat("/dev/shm/firejail", &s) == -1) { | ||
120 | /* coverity[toctou] */ | ||
121 | if (mkdir("/dev/shm/firejail", 0777) == -1) | ||
122 | errExit("mkdir"); | ||
123 | if (chown("/dev/shm/firejail", 0, 0) == -1) | ||
124 | errExit("chown"); | ||
125 | } | ||
126 | else { // check /dev/shm/firejail directory belongs to root end exit if doesn't! | ||
127 | if (s.st_uid != 0 || s.st_gid != 0) { | ||
128 | fprintf(stderr, "Error: non-root %s directory, exiting...\n", "/dev/shm/firejail"); | ||
129 | exit(1); | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | |||
134 | static void shm_create_bandwidth_file(pid_t pid) { | ||
135 | char *fname; | ||
136 | if (asprintf(&fname, "/dev/shm/firejail/%d-bandwidth", (int) pid) == -1) | ||
137 | errExit("asprintf"); | ||
138 | |||
139 | // if the file already exists, do nothing | ||
140 | struct stat s; | ||
141 | if (stat(fname, &s) == 0) { | ||
142 | free(fname); | ||
143 | return; | ||
144 | } | ||
145 | |||
146 | // create an empty file and set mod and ownership | ||
147 | /* coverity[toctou] */ | ||
148 | FILE *fp = fopen(fname, "w"); | ||
149 | if (fp) { | ||
150 | fclose(fp); | ||
151 | |||
152 | /* coverity[toctou] */ | ||
153 | if (chmod(fname, 0644) == -1) | ||
154 | errExit("chmod"); | ||
155 | /* coverity[toctou] */ | ||
156 | if (chown(fname, 0, 0) == -1) | ||
157 | errExit("chown"); | ||
158 | } | ||
159 | else { | ||
160 | fprintf(stderr, "Error: cannot create bandwidth file in /dev/shm/firejail directory\n"); | ||
161 | exit(1); | ||
162 | } | ||
163 | |||
164 | free(fname); | ||
165 | } | ||
166 | |||
167 | // delete shm bandwidth file | ||
168 | void bandwidth_shm_del_file(pid_t pid) { | ||
169 | char *fname; | ||
170 | if (asprintf(&fname, "/dev/shm/firejail/%d-bandwidth", (int) pid) == -1) | ||
171 | errExit("asprintf"); | ||
172 | unlink(fname); | ||
173 | free(fname); | ||
174 | } | ||
175 | |||
176 | void network_shm_del_file(pid_t pid) { | ||
177 | char *fname; | ||
178 | if (asprintf(&fname, "/dev/shm/firejail/%d-netmap", (int) pid) == -1) | ||
179 | errExit("asprintf"); | ||
180 | unlink(fname); | ||
181 | free(fname); | ||
182 | } | ||
183 | |||
184 | void network_shm_set_file(pid_t pid) { | ||
185 | char *fname; | ||
186 | if (asprintf(&fname, "/dev/shm/firejail/%d-netmap", (int) pid) == -1) | ||
187 | errExit("asprintf"); | ||
188 | |||
189 | // create an empty file and set mod and ownership | ||
190 | FILE *fp = fopen(fname, "w"); | ||
191 | if (fp) { | ||
192 | if (cfg.bridge0.configured) | ||
193 | fprintf(fp, "%s:%s\n", cfg.bridge0.dev, cfg.bridge0.devsandbox); | ||
194 | if (cfg.bridge1.configured) | ||
195 | fprintf(fp, "%s:%s\n", cfg.bridge1.dev, cfg.bridge1.devsandbox); | ||
196 | if (cfg.bridge2.configured) | ||
197 | fprintf(fp, "%s:%s\n", cfg.bridge2.dev, cfg.bridge2.devsandbox); | ||
198 | if (cfg.bridge3.configured) | ||
199 | fprintf(fp, "%s:%s\n", cfg.bridge3.dev, cfg.bridge3.devsandbox); | ||
200 | fclose(fp); | ||
201 | |||
202 | if (chmod(fname, 0644) == -1) | ||
203 | errExit("chmod"); | ||
204 | if (chown(fname, 0, 0) == -1) | ||
205 | errExit("chown"); | ||
206 | } | ||
207 | else { | ||
208 | fprintf(stderr, "Error: cannot create network map file in /dev/shm/firejail directory\n"); | ||
209 | exit(1); | ||
210 | } | ||
211 | |||
212 | free(fname); | ||
213 | } | ||
214 | |||
215 | |||
216 | void shm_read_bandwidth_file(pid_t pid) { | ||
217 | assert(ifbw == NULL); | ||
218 | |||
219 | char *fname; | ||
220 | if (asprintf(&fname, "/dev/shm/firejail/%d-bandwidth", (int) pid) == -1) | ||
221 | errExit("asprintf"); | ||
222 | |||
223 | FILE *fp = fopen(fname, "r"); | ||
224 | if (fp) { | ||
225 | char buf[1024]; | ||
226 | while (fgets(buf, 1024,fp)) { | ||
227 | // remove '\n' | ||
228 | char *ptr = strchr(buf, '\n'); | ||
229 | if (ptr) | ||
230 | *ptr = '\0'; | ||
231 | if (strlen(buf) == 0) | ||
232 | continue; | ||
233 | |||
234 | // create a new IFBW entry | ||
235 | IFBW *ifbw_new = malloc(sizeof(IFBW)); | ||
236 | if (!ifbw_new) | ||
237 | errExit("malloc"); | ||
238 | memset(ifbw_new, 0, sizeof(IFBW)); | ||
239 | ifbw_new->txt = strdup(buf); | ||
240 | if (!ifbw_new->txt) | ||
241 | errExit("strdup"); | ||
242 | |||
243 | // add it to the linked list | ||
244 | ifbw_add(ifbw_new); | ||
245 | } | ||
246 | |||
247 | fclose(fp); | ||
248 | } | ||
249 | } | ||
250 | |||
251 | void shm_write_bandwidth_file(pid_t pid) { | ||
252 | if (ifbw == NULL) | ||
253 | return; // nothing to do | ||
254 | |||
255 | char *fname; | ||
256 | if (asprintf(&fname, "/dev/shm/firejail/%d-bandwidth", (int) pid) == -1) | ||
257 | errExit("asprintf"); | ||
258 | |||
259 | FILE *fp = fopen(fname, "w"); | ||
260 | if (fp) { | ||
261 | IFBW *ptr = ifbw; | ||
262 | while (ptr) { | ||
263 | fprintf(fp, "%s\n", ptr->txt); | ||
264 | ptr = ptr->next; | ||
265 | } | ||
266 | fclose(fp); | ||
267 | } | ||
268 | else { | ||
269 | fprintf(stderr, "Error: cannot write bandwidht file %s\n", fname); | ||
270 | exit(1); | ||
271 | } | ||
272 | } | ||
273 | |||
274 | //*********************************** | ||
275 | // add or remove interfaces | ||
276 | //*********************************** | ||
277 | |||
278 | // remove interface from shm file | ||
279 | void bandwidth_shm_remove(pid_t pid, const char *dev) { | ||
280 | // create bandwidth directory & file in case they are not in the filesystem yet | ||
281 | shm_create_firejail_dir(); | ||
282 | shm_create_bandwidth_file(pid); | ||
283 | |||
284 | // read bandwidth file | ||
285 | shm_read_bandwidth_file(pid); | ||
286 | |||
287 | // find the element and remove it | ||
288 | IFBW *elem = ifbw_find(dev); | ||
289 | if (elem) { | ||
290 | ifbw_remove(elem); | ||
291 | shm_write_bandwidth_file(pid) ; | ||
292 | } | ||
293 | |||
294 | // remove the file if there are no entries in the list | ||
295 | if (ifbw == NULL) { | ||
296 | bandwidth_shm_del_file(pid); | ||
297 | } | ||
298 | } | ||
299 | |||
300 | // add interface to shm file | ||
301 | void bandwidth_shm_set(pid_t pid, const char *dev, int down, int up) { | ||
302 | // create bandwidth directory & file in case they are not in the filesystem yet | ||
303 | shm_create_firejail_dir(); | ||
304 | shm_create_bandwidth_file(pid); | ||
305 | |||
306 | // create the new text entry | ||
307 | char *txt; | ||
308 | if (asprintf(&txt, "%s: RX %dKB/s, TX %dKB/s", dev, down, up) == -1) | ||
309 | errExit("asprintf"); | ||
310 | |||
311 | // read bandwidth file | ||
312 | shm_read_bandwidth_file(pid); | ||
313 | |||
314 | // look for an existing entry and replace the text | ||
315 | IFBW *ptr = ifbw_find(dev); | ||
316 | if (ptr) { | ||
317 | assert(ptr->txt); | ||
318 | free(ptr->txt); | ||
319 | ptr->txt = txt; | ||
320 | } | ||
321 | // ... or add a new entry | ||
322 | else { | ||
323 | IFBW *ifbw_new = malloc(sizeof(IFBW)); | ||
324 | if (!ifbw_new) | ||
325 | errExit("malloc"); | ||
326 | memset(ifbw_new, 0, sizeof(IFBW)); | ||
327 | ifbw_new->txt = txt; | ||
328 | |||
329 | // add it to the linked list | ||
330 | ifbw_add(ifbw_new); | ||
331 | } | ||
332 | shm_write_bandwidth_file(pid) ; | ||
333 | } | ||
334 | |||
335 | |||
336 | //*********************************** | ||
337 | // command execution | ||
338 | //*********************************** | ||
339 | void bandwidth_name(const char *name, const char *command, const char *dev, int down, int up) { | ||
340 | if (!name || strlen(name) == 0) { | ||
341 | fprintf(stderr, "Error: invalid sandbox name\n"); | ||
342 | exit(1); | ||
343 | } | ||
344 | pid_t pid; | ||
345 | if (name2pid(name, &pid)) { | ||
346 | fprintf(stderr, "Error: cannot find sandbox %s\n", name); | ||
347 | exit(1); | ||
348 | } | ||
349 | |||
350 | bandwidth_pid(pid, command, dev, down, up); | ||
351 | } | ||
352 | |||
353 | void bandwidth_pid(pid_t pid, const char *command, const char *dev, int down, int up) { | ||
354 | //************************ | ||
355 | // verify sandbox | ||
356 | //************************ | ||
357 | char *comm = pid_proc_comm(pid); | ||
358 | if (!comm) { | ||
359 | fprintf(stderr, "Error: cannot find sandbox\n"); | ||
360 | exit(1); | ||
361 | } | ||
362 | |||
363 | // remove \n and check for firejail sandbox | ||
364 | char *ptr = strchr(comm, '\n'); | ||
365 | if (ptr) | ||
366 | *ptr = '\0'; | ||
367 | if (strcmp(comm, "firejail") != 0) { | ||
368 | fprintf(stderr, "Error: cannot find sandbox\n"); | ||
369 | exit(1); | ||
370 | } | ||
371 | free(comm); | ||
372 | |||
373 | // check network namespace | ||
374 | char *cmd = pid_proc_cmdline(pid); | ||
375 | if (!cmd || strstr(cmd, "--net") == NULL) { | ||
376 | fprintf(stderr, "Error: the sandbox doesn't use a new network namespace\n"); | ||
377 | exit(1); | ||
378 | } | ||
379 | free(cmd); | ||
380 | |||
381 | |||
382 | //************************ | ||
383 | // join the network namespace | ||
384 | //************************ | ||
385 | pid_t child; | ||
386 | if (find_child(pid, &child) == -1) { | ||
387 | fprintf(stderr, "Error: cannot join the network namespace\n"); | ||
388 | exit(1); | ||
389 | } | ||
390 | if (join_namespace(child, "net")) { | ||
391 | fprintf(stderr, "Error: cannot join the network namespace\n"); | ||
392 | exit(1); | ||
393 | } | ||
394 | |||
395 | // set shm file | ||
396 | if (strcmp(command, "set") == 0) | ||
397 | bandwidth_shm_set(pid, dev, down, up); | ||
398 | else if (strcmp(command, "clear") == 0) | ||
399 | bandwidth_shm_remove(pid, dev); | ||
400 | |||
401 | //************************ | ||
402 | // build command | ||
403 | //************************ | ||
404 | char *devname = NULL; | ||
405 | if (dev) { | ||
406 | // read shm network map file | ||
407 | char *fname; | ||
408 | if (asprintf(&fname, "/dev/shm/firejail/%d-netmap", (int) pid) == -1) | ||
409 | errExit("asprintf"); | ||
410 | FILE *fp = fopen(fname, "r"); | ||
411 | if (!fp) { | ||
412 | fprintf(stderr, "Error: cannot read netowk map filel %s\n", fname); | ||
413 | exit(1); | ||
414 | } | ||
415 | |||
416 | char buf[1024]; | ||
417 | int len = strlen(dev); | ||
418 | while (fgets(buf, 1024, fp)) { | ||
419 | // remove '\n' | ||
420 | char *ptr = strchr(buf, '\n'); | ||
421 | if (ptr) | ||
422 | *ptr = '\0'; | ||
423 | if (*buf == '\0') | ||
424 | break; | ||
425 | |||
426 | if (strncmp(buf, dev, len) == 0 && buf[len] == ':') { | ||
427 | devname = strdup(buf + len + 1); | ||
428 | if (!devname) | ||
429 | errExit("strdup"); | ||
430 | // check device in namespace | ||
431 | if (if_nametoindex(devname) == 0) { | ||
432 | fprintf(stderr, "Error: cannot find network device %s\n", devname); | ||
433 | exit(1); | ||
434 | } | ||
435 | break; | ||
436 | } | ||
437 | } | ||
438 | free(fname); | ||
439 | fclose(fp); | ||
440 | } | ||
441 | |||
442 | // build fshaper.sh command | ||
443 | cmd = NULL; | ||
444 | if (devname) { | ||
445 | if (strcmp(command, "set") == 0) { | ||
446 | if (asprintf(&cmd, "%s/lib/firejail/fshaper.sh --%s %s %d %d", | ||
447 | PREFIX, command, devname, down, up) == -1) | ||
448 | errExit("asprintf"); | ||
449 | } | ||
450 | else { | ||
451 | if (asprintf(&cmd, "%s/lib/firejail/fshaper.sh --%s %s", | ||
452 | PREFIX, command, devname) == -1) | ||
453 | errExit("asprintf"); | ||
454 | } | ||
455 | } | ||
456 | else { | ||
457 | if (asprintf(&cmd, "%s/lib/firejail/fshaper.sh --%s", PREFIX, command) == -1) | ||
458 | errExit("asprintf"); | ||
459 | } | ||
460 | assert(cmd); | ||
461 | |||
462 | // wipe out environment variables | ||
463 | environ = NULL; | ||
464 | |||
465 | //************************ | ||
466 | // build command | ||
467 | //************************ | ||
468 | // elevate privileges | ||
469 | if (setreuid(0, 0)) | ||
470 | errExit("setreuid"); | ||
471 | if (setregid(0, 0)) | ||
472 | errExit("setregid"); | ||
473 | |||
474 | char *arg[4]; | ||
475 | arg[0] = "/bin/bash"; | ||
476 | arg[1] = "-c"; | ||
477 | arg[2] = cmd; | ||
478 | arg[3] = NULL; | ||
479 | execvp("/bin/bash", arg); | ||
480 | |||
481 | // it will never get here | ||
482 | exit(0); | ||
483 | } | ||
diff --git a/src/firejail/caps.c b/src/firejail/caps.c new file mode 100644 index 000000000..d8777c0db --- /dev/null +++ b/src/firejail/caps.c | |||
@@ -0,0 +1,453 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 | |||
21 | #include "firejail.h" | ||
22 | #include <errno.h> | ||
23 | #include <linux/filter.h> | ||
24 | #include <stddef.h> | ||
25 | #include <linux/capability.h> | ||
26 | #include <linux/audit.h> | ||
27 | #include <sys/prctl.h> | ||
28 | #include <sys/types.h> | ||
29 | #include <sys/stat.h> | ||
30 | #include <unistd.h> | ||
31 | |||
32 | extern int capget(cap_user_header_t hdrp, cap_user_data_t datap); | ||
33 | extern int capset(cap_user_header_t hdrp, const cap_user_data_t datap); | ||
34 | |||
35 | |||
36 | typedef struct { | ||
37 | char *name; | ||
38 | int nr; | ||
39 | } CapsEntry; | ||
40 | |||
41 | static CapsEntry capslist[] = { | ||
42 | // | ||
43 | // code generated using tools/extract-caps | ||
44 | // updated manually based on kernel 3.18/include/linux/capability.h (added block suspend and audit_read | ||
45 | // | ||
46 | #ifdef CAP_CHOWN | ||
47 | {"chown", CAP_CHOWN }, | ||
48 | #endif | ||
49 | #ifdef CAP_DAC_OVERRIDE | ||
50 | {"dac_override", CAP_DAC_OVERRIDE }, | ||
51 | #endif | ||
52 | #ifdef CAP_DAC_READ_SEARCH | ||
53 | {"dac_read_search", CAP_DAC_READ_SEARCH }, | ||
54 | #endif | ||
55 | #ifdef CAP_FOWNER | ||
56 | {"fowner", CAP_FOWNER }, | ||
57 | #endif | ||
58 | #ifdef CAP_FSETID | ||
59 | {"fsetid", CAP_FSETID }, | ||
60 | #endif | ||
61 | #ifdef CAP_KILL | ||
62 | {"kill", CAP_KILL }, | ||
63 | #endif | ||
64 | #ifdef CAP_SETGID | ||
65 | {"setgid", CAP_SETGID }, | ||
66 | #endif | ||
67 | #ifdef CAP_SETUID | ||
68 | {"setuid", CAP_SETUID }, | ||
69 | #endif | ||
70 | #ifdef CAP_SETPCAP | ||
71 | {"setpcap", CAP_SETPCAP }, | ||
72 | #endif | ||
73 | #ifdef CAP_LINUX_IMMUTABLE | ||
74 | {"linux_immutable", CAP_LINUX_IMMUTABLE }, | ||
75 | #endif | ||
76 | #ifdef CAP_NET_BIND_SERVICE | ||
77 | {"net_bind_service", CAP_NET_BIND_SERVICE }, | ||
78 | #endif | ||
79 | #ifdef CAP_NET_BROADCAST | ||
80 | {"net_broadcast", CAP_NET_BROADCAST }, | ||
81 | #endif | ||
82 | #ifdef CAP_NET_ADMIN | ||
83 | {"net_admin", CAP_NET_ADMIN }, | ||
84 | #endif | ||
85 | #ifdef CAP_NET_RAW | ||
86 | {"net_raw", CAP_NET_RAW }, | ||
87 | #endif | ||
88 | #ifdef CAP_IPC_LOCK | ||
89 | {"ipc_lock", CAP_IPC_LOCK }, | ||
90 | #endif | ||
91 | #ifdef CAP_IPC_OWNER | ||
92 | {"ipc_owner", CAP_IPC_OWNER }, | ||
93 | #endif | ||
94 | #ifdef CAP_SYS_MODULE | ||
95 | {"sys_module", CAP_SYS_MODULE }, | ||
96 | #endif | ||
97 | #ifdef CAP_SYS_RAWIO | ||
98 | {"sys_rawio", CAP_SYS_RAWIO }, | ||
99 | #endif | ||
100 | #ifdef CAP_SYS_CHROOT | ||
101 | {"sys_chroot", CAP_SYS_CHROOT }, | ||
102 | #endif | ||
103 | #ifdef CAP_SYS_PTRACE | ||
104 | {"sys_ptrace", CAP_SYS_PTRACE }, | ||
105 | #endif | ||
106 | #ifdef CAP_SYS_PACCT | ||
107 | {"sys_pacct", CAP_SYS_PACCT }, | ||
108 | #endif | ||
109 | #ifdef CAP_SYS_ADMIN | ||
110 | {"sys_admin", CAP_SYS_ADMIN }, | ||
111 | #endif | ||
112 | #ifdef CAP_SYS_BOOT | ||
113 | {"sys_boot", CAP_SYS_BOOT }, | ||
114 | #endif | ||
115 | #ifdef CAP_SYS_NICE | ||
116 | {"sys_nice", CAP_SYS_NICE }, | ||
117 | #endif | ||
118 | #ifdef CAP_SYS_RESOURCE | ||
119 | {"sys_resource", CAP_SYS_RESOURCE }, | ||
120 | #endif | ||
121 | #ifdef CAP_SYS_TIME | ||
122 | {"sys_time", CAP_SYS_TIME }, | ||
123 | #endif | ||
124 | #ifdef CAP_SYS_TTY_CONFIG | ||
125 | {"sys_tty_config", CAP_SYS_TTY_CONFIG }, | ||
126 | #endif | ||
127 | #ifdef CAP_MKNOD | ||
128 | {"mknod", CAP_MKNOD }, | ||
129 | #endif | ||
130 | #ifdef CAP_LEASE | ||
131 | {"lease", CAP_LEASE }, | ||
132 | #endif | ||
133 | #ifdef CAP_AUDIT_WRITE | ||
134 | {"audit_write", CAP_AUDIT_WRITE }, | ||
135 | #endif | ||
136 | #ifdef CAP_AUDIT_CONTROL | ||
137 | {"audit_control", CAP_AUDIT_CONTROL }, | ||
138 | #endif | ||
139 | #ifdef CAP_SETFCAP | ||
140 | {"setfcap", CAP_SETFCAP }, | ||
141 | #endif | ||
142 | #ifdef CAP_MAC_OVERRIDE | ||
143 | {"mac_override", CAP_MAC_OVERRIDE }, | ||
144 | #endif | ||
145 | #ifdef CAP_MAC_ADMIN | ||
146 | {"mac_admin", CAP_MAC_ADMIN }, | ||
147 | #endif | ||
148 | #ifdef CAP_SYSLOG | ||
149 | {"syslog", CAP_SYSLOG }, | ||
150 | #endif | ||
151 | #ifdef CAP_WAKE_ALARM | ||
152 | {"wake_alarm", CAP_WAKE_ALARM }, | ||
153 | #endif | ||
154 | // not in Debian 7 | ||
155 | #ifdef CAP_BLOCK_SUSPEND | ||
156 | {"block_suspend", CAP_BLOCK_SUSPEND }, | ||
157 | #else | ||
158 | {"block_suspend", 36 }, | ||
159 | #endif | ||
160 | #ifdef CAP_AUDIT_READ | ||
161 | {"audit_read", CAP_AUDIT_READ }, | ||
162 | #else | ||
163 | {"audit_read", 37 }, | ||
164 | #endif | ||
165 | |||
166 | // | ||
167 | // end of generated code | ||
168 | // | ||
169 | }; // end of capslist | ||
170 | |||
171 | const char *caps_find_nr(int nr) { | ||
172 | int i; | ||
173 | int elems = sizeof(capslist) / sizeof(capslist[0]); | ||
174 | for (i = 0; i < elems; i++) { | ||
175 | if (nr == capslist[i].nr) | ||
176 | return capslist[i].name; | ||
177 | } | ||
178 | |||
179 | return "unknown"; | ||
180 | } | ||
181 | |||
182 | // return -1 if error, or syscall number | ||
183 | static int caps_find_name(const char *name) { | ||
184 | int i; | ||
185 | int elems = sizeof(capslist) / sizeof(capslist[0]); | ||
186 | for (i = 0; i < elems; i++) { | ||
187 | if (strcmp(name, capslist[i].name) == 0) | ||
188 | return capslist[i].nr; | ||
189 | } | ||
190 | |||
191 | return -1; | ||
192 | } | ||
193 | |||
194 | // return 1 if error, 0 if OK | ||
195 | int caps_check_list(const char *clist, void (*callback)(int)) { | ||
196 | // don't allow empty lists | ||
197 | if (clist == NULL || *clist == '\0') { | ||
198 | fprintf(stderr, "Error: empty capabilities lists are not allowed\n"); | ||
199 | return -1; | ||
200 | } | ||
201 | |||
202 | // work on a copy of the string | ||
203 | char *str = strdup(clist); | ||
204 | if (!str) | ||
205 | errExit("strdup"); | ||
206 | |||
207 | char *ptr = str; | ||
208 | char *start = str; | ||
209 | while (*ptr != '\0') { | ||
210 | if (islower(*ptr) || isdigit(*ptr) || *ptr == '_') | ||
211 | ; | ||
212 | else if (*ptr == ',') { | ||
213 | *ptr = '\0'; | ||
214 | int nr = caps_find_name(start); | ||
215 | if (nr == -1) { | ||
216 | fprintf(stderr, "Error: capability %s not found\n", start); | ||
217 | free(str); | ||
218 | return -1; | ||
219 | } | ||
220 | else if (callback != NULL) | ||
221 | callback(nr); | ||
222 | |||
223 | start = ptr + 1; | ||
224 | } | ||
225 | ptr++; | ||
226 | } | ||
227 | if (*start != '\0') { | ||
228 | int nr = caps_find_name(start); | ||
229 | if (nr == -1) { | ||
230 | fprintf(stderr, "Error: capability %s not found\n", start); | ||
231 | free(str); | ||
232 | return -1; | ||
233 | } | ||
234 | else if (callback != NULL) | ||
235 | callback(nr); | ||
236 | } | ||
237 | |||
238 | free(str); | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | void caps_print(void) { | ||
243 | int i; | ||
244 | int elems = sizeof(capslist) / sizeof(capslist[0]); | ||
245 | |||
246 | // check current caps supported by the kernel | ||
247 | int cnt = 0; | ||
248 | unsigned long cap; | ||
249 | for (cap=0; cap <= 63; cap++) { | ||
250 | int code = prctl(PR_CAPBSET_DROP, cap, 0, 0, 0); | ||
251 | if (code == 0) | ||
252 | cnt++; | ||
253 | } | ||
254 | printf("Your kernel supports %d capabilities.\n", cnt); | ||
255 | |||
256 | for (i = 0; i < elems; i++) { | ||
257 | printf("%d\t- %s\n", capslist[i].nr, capslist[i].name); | ||
258 | } | ||
259 | } | ||
260 | |||
261 | |||
262 | |||
263 | |||
264 | // enabled by default | ||
265 | int caps_default_filter(void) { | ||
266 | // drop capabilities | ||
267 | if (prctl(PR_CAPBSET_DROP, CAP_SYS_MODULE, 0, 0, 0) && arg_debug) | ||
268 | fprintf(stderr, "Warning: cannot drop CAP_SYS_MODULE"); | ||
269 | else if (arg_debug) | ||
270 | printf("Drop CAP_SYS_MODULE\n"); | ||
271 | |||
272 | if (prctl(PR_CAPBSET_DROP, CAP_SYS_RAWIO, 0, 0, 0) && arg_debug) | ||
273 | fprintf(stderr, "Warning: cannot drop CAP_SYS_RAWIO"); | ||
274 | else if (arg_debug) | ||
275 | printf("Drop CAP_SYS_RAWIO\n"); | ||
276 | |||
277 | if (prctl(PR_CAPBSET_DROP, CAP_SYS_BOOT, 0, 0, 0) && arg_debug) | ||
278 | fprintf(stderr, "Warning: cannot drop CAP_SYS_BOOT"); | ||
279 | else if (arg_debug) | ||
280 | printf("Drop CAP_SYS_BOOT\n"); | ||
281 | |||
282 | if (prctl(PR_CAPBSET_DROP, CAP_SYS_NICE, 0, 0, 0) && arg_debug) | ||
283 | fprintf(stderr, "Warning: cannot drop CAP_SYS_NICE"); | ||
284 | else if (arg_debug) | ||
285 | printf("Drop CAP_SYS_NICE\n"); | ||
286 | |||
287 | if (prctl(PR_CAPBSET_DROP, CAP_SYS_TTY_CONFIG, 0, 0, 0) && arg_debug) | ||
288 | fprintf(stderr, "Warning: cannot drop CAP_SYS_TTY_CONFIG"); | ||
289 | else if (arg_debug) | ||
290 | printf("Drop CAP_SYS_TTY_CONFIG\n"); | ||
291 | |||
292 | if (prctl(PR_CAPBSET_DROP, CAP_SYSLOG, 0, 0, 0) && arg_debug) | ||
293 | fprintf(stderr, "Warning: cannot drop CAP_SYSLOG"); | ||
294 | else if (arg_debug) | ||
295 | printf("Drop CAP_SYSLOG\n"); | ||
296 | |||
297 | if (prctl(PR_CAPBSET_DROP, CAP_MKNOD, 0, 0, 0) && arg_debug) | ||
298 | fprintf(stderr, "Warning: cannot drop CAP_MKNOD"); | ||
299 | else if (arg_debug) | ||
300 | printf("Drop CAP_MKNOD\n"); | ||
301 | |||
302 | if (prctl(PR_CAPBSET_DROP, CAP_SYS_ADMIN, 0, 0, 0) && arg_debug) | ||
303 | fprintf(stderr, "Warning: cannot drop CAP_SYS_ADMIN"); | ||
304 | else if (arg_debug) | ||
305 | printf("Drop CAP_SYS_ADMIN\n"); | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | void caps_drop_all(void) { | ||
311 | if (arg_debug) | ||
312 | printf("Droping all capabilities\n"); | ||
313 | |||
314 | unsigned long cap; | ||
315 | for (cap=0; cap <= 63; cap++) { | ||
316 | int code = prctl(PR_CAPBSET_DROP, cap, 0, 0, 0); | ||
317 | if (code == -1 && errno != EINVAL) | ||
318 | errExit("PR_CAPBSET_DROP"); | ||
319 | } | ||
320 | } | ||
321 | |||
322 | |||
323 | void caps_set(uint64_t caps) { | ||
324 | if (arg_debug) | ||
325 | printf("Set caps filter %llx\n", (unsigned long long) caps); | ||
326 | |||
327 | unsigned long i; | ||
328 | uint64_t mask = 1LLU; | ||
329 | for (i = 0; i < 64; i++, mask <<= 1) { | ||
330 | if ((mask & caps) == 0) { | ||
331 | int code = prctl(PR_CAPBSET_DROP, i, 0, 0, 0); | ||
332 | if (code == -1 && errno != EINVAL) | ||
333 | errExit("PR_CAPBSET_DROP"); | ||
334 | } | ||
335 | } | ||
336 | } | ||
337 | |||
338 | |||
339 | static uint64_t filter; | ||
340 | |||
341 | static void caps_set_bit(int nr) { | ||
342 | uint64_t mask = 1LLU << nr; | ||
343 | filter |= mask; | ||
344 | } | ||
345 | static void caps_reset_bit(int nr) { | ||
346 | uint64_t mask = 1LLU << nr; | ||
347 | filter &= ~mask; | ||
348 | } | ||
349 | |||
350 | void caps_drop_list(const char *clist) { | ||
351 | filter = 0; | ||
352 | filter--; | ||
353 | caps_check_list(clist, caps_reset_bit); | ||
354 | caps_set(filter); | ||
355 | } | ||
356 | |||
357 | void caps_keep_list(const char *clist) { | ||
358 | filter = 0; | ||
359 | caps_check_list(clist, caps_set_bit); | ||
360 | caps_set(filter); | ||
361 | } | ||
362 | |||
363 | #define MAXBUF 4098 | ||
364 | static uint64_t extract_caps(int pid) { | ||
365 | char *file; | ||
366 | if (asprintf(&file, "/proc/%d/status", pid) == -1) { | ||
367 | errExit("asprintf"); | ||
368 | exit(1); | ||
369 | } | ||
370 | |||
371 | FILE *fp = fopen(file, "r"); | ||
372 | if (!fp) { | ||
373 | printf("Error: cannot open %s\n", file); | ||
374 | free(file); | ||
375 | exit(1); | ||
376 | } | ||
377 | |||
378 | char buf[MAXBUF]; | ||
379 | while (fgets(buf, MAXBUF, fp)) { | ||
380 | if (strncmp(buf, "CapBnd:", 7) == 0) { | ||
381 | char *ptr = buf + 8; | ||
382 | unsigned long long val; | ||
383 | sscanf(ptr, "%llx", &val); | ||
384 | free(file); | ||
385 | fclose(fp); | ||
386 | return val; | ||
387 | } | ||
388 | } | ||
389 | fclose(fp); | ||
390 | free(file); | ||
391 | printf("Error: cannot read caps configuration\n"); | ||
392 | exit(1); | ||
393 | } | ||
394 | |||
395 | |||
396 | void caps_print_filter_name(const char *name) { | ||
397 | if (!name || strlen(name) == 0) { | ||
398 | fprintf(stderr, "Error: invalid sandbox name\n"); | ||
399 | exit(1); | ||
400 | } | ||
401 | pid_t pid; | ||
402 | if (name2pid(name, &pid)) { | ||
403 | fprintf(stderr, "Error: cannot find sandbox %s\n", name); | ||
404 | exit(1); | ||
405 | } | ||
406 | |||
407 | caps_print_filter(pid); | ||
408 | } | ||
409 | |||
410 | void caps_print_filter(pid_t pid) { | ||
411 | // if the pid is that of a firejail process, use the pid of the first child process | ||
412 | char *comm = pid_proc_comm(pid); | ||
413 | if (comm) { | ||
414 | // remove \n | ||
415 | char *ptr = strchr(comm, '\n'); | ||
416 | if (ptr) | ||
417 | *ptr = '\0'; | ||
418 | if (strcmp(comm, "firejail") == 0) { | ||
419 | pid_t child; | ||
420 | if (find_child(pid, &child) == 0) { | ||
421 | pid = child; | ||
422 | } | ||
423 | } | ||
424 | free(comm); | ||
425 | } | ||
426 | |||
427 | // check privileges for non-root users | ||
428 | uid_t uid = getuid(); | ||
429 | if (uid != 0) { | ||
430 | struct stat s; | ||
431 | char *dir; | ||
432 | if (asprintf(&dir, "/proc/%u/ns", pid) == -1) | ||
433 | errExit("asprintf"); | ||
434 | if (stat(dir, &s) < 0) | ||
435 | errExit("stat"); | ||
436 | if (s.st_uid != uid) { | ||
437 | printf("Error: permission denied.\n"); | ||
438 | exit(1); | ||
439 | } | ||
440 | } | ||
441 | |||
442 | uint64_t caps = extract_caps(pid); | ||
443 | drop_privs(1); | ||
444 | |||
445 | int i; | ||
446 | uint64_t mask; | ||
447 | int elems = sizeof(capslist) / sizeof(capslist[0]); | ||
448 | for (i = 0, mask = 1; i < elems; i++, mask <<= 1) { | ||
449 | printf("%-18.18s - %s\n", capslist[i].name, (mask & caps)? "enabled": "disabled"); | ||
450 | } | ||
451 | |||
452 | exit(0); | ||
453 | } | ||
diff --git a/src/firejail/cgroup.c b/src/firejail/cgroup.c new file mode 100644 index 000000000..7366a6699 --- /dev/null +++ b/src/firejail/cgroup.c | |||
@@ -0,0 +1,118 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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/stat.h> | ||
22 | |||
23 | #define MAXBUF 4096 | ||
24 | |||
25 | void save_cgroup(void) { | ||
26 | if (cfg.cgroup == NULL) | ||
27 | return; | ||
28 | |||
29 | char *fname; | ||
30 | if (asprintf(&fname, "%s/cgroup", MNT_DIR) == -1) | ||
31 | errExit(fname); | ||
32 | |||
33 | FILE *fp = fopen(fname, "w"); | ||
34 | if (fp) { | ||
35 | fprintf(fp, "%s", cfg.cgroup); | ||
36 | fflush(0); | ||
37 | fclose(fp); | ||
38 | if (chown(fname, 0, 0) < 0) | ||
39 | errExit("chown"); | ||
40 | } | ||
41 | else { | ||
42 | fprintf(stderr, "Error: cannot save cgroup\n"); | ||
43 | free(fname); | ||
44 | exit(1); | ||
45 | } | ||
46 | |||
47 | free(fname); | ||
48 | } | ||
49 | |||
50 | void load_cgroup(const char *fname) { | ||
51 | if (!fname) | ||
52 | return; | ||
53 | |||
54 | FILE *fp = fopen(fname, "r"); | ||
55 | if (fp) { | ||
56 | char buf[MAXBUF]; | ||
57 | if (fgets(buf, MAXBUF, fp)) { | ||
58 | cfg.cgroup = strdup(buf); | ||
59 | if (!cfg.cgroup) | ||
60 | errExit("strdup"); | ||
61 | } | ||
62 | else | ||
63 | goto errout; | ||
64 | |||
65 | fclose(fp); | ||
66 | return; | ||
67 | } | ||
68 | errout: | ||
69 | fprintf(stderr, "Warrning: cannot load control group\n"); | ||
70 | if (fp) | ||
71 | fclose(fp); | ||
72 | } | ||
73 | |||
74 | |||
75 | void set_cgroup(const char *path) { | ||
76 | // path starts with /sys/fs/cgroup | ||
77 | if (strncmp(path, "/sys/fs/cgroup", 14) != 0) | ||
78 | goto errout; | ||
79 | |||
80 | // path ends in tasks | ||
81 | char *ptr = strstr(path, "tasks"); | ||
82 | if (!ptr) | ||
83 | goto errout; | ||
84 | if (*(ptr + 5) != '\0') | ||
85 | goto errout; | ||
86 | |||
87 | // no .. traversal | ||
88 | ptr = strstr(path, ".."); | ||
89 | if (ptr) | ||
90 | goto errout; | ||
91 | |||
92 | // tasks file exists | ||
93 | struct stat s; | ||
94 | if (stat(path, &s) == -1) | ||
95 | goto errout; | ||
96 | |||
97 | // task file belongs to the user running the sandbox | ||
98 | if (s.st_uid != getuid() && s.st_gid != getgid()) | ||
99 | goto errout2; | ||
100 | |||
101 | // add the task to cgroup | ||
102 | /* coverity[toctou] */ | ||
103 | FILE *fp = fopen(path, "a"); | ||
104 | if (!fp) | ||
105 | goto errout; | ||
106 | pid_t pid = getpid(); | ||
107 | int rv = fprintf(fp, "%d\n", pid); | ||
108 | (void) rv; | ||
109 | fclose(fp); | ||
110 | return; | ||
111 | |||
112 | errout: | ||
113 | fprintf(stderr, "Error: invalid cgroup\n"); | ||
114 | exit(1); | ||
115 | errout2: | ||
116 | fprintf(stderr, "Error: you don't have permissions to use this control group\n"); | ||
117 | exit(1); | ||
118 | } | ||
diff --git a/src/firejail/cpu.c b/src/firejail/cpu.c new file mode 100644 index 000000000..633081a3f --- /dev/null +++ b/src/firejail/cpu.c | |||
@@ -0,0 +1,141 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 <sched.h> | ||
22 | |||
23 | // converts a numeric cpu value in the corresponding bit mask | ||
24 | static void set_cpu(const char *str) { | ||
25 | if (strlen(str) == 0) | ||
26 | return; | ||
27 | |||
28 | int val = atoi(str); | ||
29 | if (val < 0 || val >= 32) { | ||
30 | fprintf(stderr, "Error: invalid cpu number. Accepted values are between 0 and 31.\n"); | ||
31 | exit(1); | ||
32 | } | ||
33 | |||
34 | uint32_t mask = 1; | ||
35 | int i; | ||
36 | for (i = 0; i < val; i++, mask <<= 1); | ||
37 | cfg.cpus |= mask; | ||
38 | } | ||
39 | |||
40 | void read_cpu_list(const char *str) { | ||
41 | char *tmp = strdup(str); | ||
42 | if (tmp == NULL) | ||
43 | errExit("strdup"); | ||
44 | |||
45 | char *ptr = tmp; | ||
46 | while (*ptr != '\0') { | ||
47 | if (*ptr == ',' || isdigit(*ptr)) | ||
48 | ; | ||
49 | else { | ||
50 | fprintf(stderr, "Error: invalid cpu list\n"); | ||
51 | exit(1); | ||
52 | } | ||
53 | ptr++; | ||
54 | } | ||
55 | |||
56 | char *start = tmp; | ||
57 | ptr = tmp; | ||
58 | while (*ptr != '\0') { | ||
59 | if (*ptr == ',') { | ||
60 | *ptr = '\0'; | ||
61 | set_cpu(start); | ||
62 | start = ptr + 1; | ||
63 | } | ||
64 | ptr++; | ||
65 | } | ||
66 | set_cpu(start); | ||
67 | free(tmp); | ||
68 | } | ||
69 | |||
70 | void save_cpu(void) { | ||
71 | if (cfg.cpus == 0) | ||
72 | return; | ||
73 | |||
74 | char *fname; | ||
75 | if (asprintf(&fname, "%s/cpu", MNT_DIR) == -1) | ||
76 | errExit("asprintf"); | ||
77 | FILE *fp = fopen(fname, "w"); | ||
78 | if (fp) { | ||
79 | fprintf(fp, "%x\n", cfg.cpus); | ||
80 | fclose(fp); | ||
81 | if (chown(fname, 0, 0) < 0) | ||
82 | errExit("chown"); | ||
83 | } | ||
84 | else { | ||
85 | fprintf(stderr, "Error: cannot save cpu affinity mask\n"); | ||
86 | free(fname); | ||
87 | exit(1); | ||
88 | } | ||
89 | |||
90 | free(fname); | ||
91 | } | ||
92 | |||
93 | void load_cpu(const char *fname) { | ||
94 | if (!fname) | ||
95 | return; | ||
96 | |||
97 | FILE *fp = fopen(fname, "r"); | ||
98 | if (fp) { | ||
99 | unsigned tmp; | ||
100 | int rv = fscanf(fp, "%x", &tmp); | ||
101 | if (rv) | ||
102 | cfg.cpus = (uint32_t) tmp; | ||
103 | fclose(fp); | ||
104 | } | ||
105 | else | ||
106 | fprintf(stderr, "Warning: cannot load cpu affinity mask\n"); | ||
107 | } | ||
108 | |||
109 | void set_cpu_affinity(void) { | ||
110 | // set cpu affinity | ||
111 | cpu_set_t mask; | ||
112 | CPU_ZERO(&mask); | ||
113 | |||
114 | int i; | ||
115 | uint32_t m = 1; | ||
116 | for (i = 0; i < 32; i++, m <<= 1) { | ||
117 | if (cfg.cpus & m) | ||
118 | CPU_SET(i, &mask); | ||
119 | } | ||
120 | |||
121 | if (sched_setaffinity(0, sizeof(mask), &mask) == -1) { | ||
122 | fprintf(stderr, "Warning: cannot set cpu affinity\n"); | ||
123 | fprintf(stderr, " "); | ||
124 | perror("sched_setaffinity"); | ||
125 | } | ||
126 | |||
127 | // verify cpu affinity | ||
128 | cpu_set_t mask2; | ||
129 | CPU_ZERO(&mask2); | ||
130 | if (sched_getaffinity(0, sizeof(mask2), &mask2) == -1) { | ||
131 | fprintf(stderr, "Warning: cannot verify cpu affinity\n"); | ||
132 | fprintf(stderr, " "); | ||
133 | perror("sched_getaffinity"); | ||
134 | } | ||
135 | else { | ||
136 | if (CPU_EQUAL(&mask, &mask2)) | ||
137 | printf("CPU affinity set\n"); | ||
138 | else | ||
139 | printf("CPU affinity not set\n"); | ||
140 | } | ||
141 | } | ||
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h new file mode 100644 index 000000000..2ec6e54c9 --- /dev/null +++ b/src/firejail/firejail.h | |||
@@ -0,0 +1,354 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 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 | #ifndef FIREJAIL_H | ||
21 | #define FIREJAIL_H | ||
22 | #include "../include/common.h" | ||
23 | |||
24 | #define USELOCK | ||
25 | #define FIREJAIL_DIR "/tmp/firejail" | ||
26 | #define RO_DIR "/tmp/firejail/firejail.ro.dir" | ||
27 | #define RO_FILE "/tmp/firejail/firejail.ro.file" | ||
28 | #define MNT_DIR "/tmp/firejail/mnt" | ||
29 | #define OVERLAY_DIR "/tmp/firejail/overlay" | ||
30 | #define HOME_DIR "/tmp/firejail/mnt/home" | ||
31 | #define MAX_INCLUDE_LEVEL 6 | ||
32 | |||
33 | // main.c | ||
34 | typedef struct bridge_t { | ||
35 | // on the host | ||
36 | char *dev; // interface device name: bridge or regular ethernet | ||
37 | uint32_t ip; // interface device IP address | ||
38 | uint32_t mask; // interface device mask | ||
39 | uint8_t mac[6]; // interface mac address | ||
40 | |||
41 | // inside the sandbox | ||
42 | char *devsandbox; // name of the device inside the sandbox | ||
43 | uint32_t ipsandbox; // ip address inside the sandbox | ||
44 | uint8_t macsandbox[6]; // mac address inside the sandbox | ||
45 | uint32_t iprange_start;// iprange arp scan start range | ||
46 | uint32_t iprange_end; // iprange arp scan end range | ||
47 | |||
48 | // flags | ||
49 | uint8_t arg_ip_none; // --ip=none | ||
50 | uint8_t macvlan; // set by --net=eth0 (or eth1, ...); reset by --net=br0 (or br1, ...) | ||
51 | uint8_t configured; | ||
52 | uint8_t scan; // set by --scan | ||
53 | } Bridge; | ||
54 | |||
55 | typedef struct profile_entry_t { | ||
56 | struct profile_entry_t *next; | ||
57 | char *data; | ||
58 | }ProfileEntry; | ||
59 | |||
60 | typedef struct config_t { | ||
61 | // user data | ||
62 | char *username; | ||
63 | char *homedir; | ||
64 | |||
65 | // filesystem | ||
66 | ProfileEntry *profile; | ||
67 | char *chrootdir; // chroot directory | ||
68 | char *home_private; // private home directory | ||
69 | char *home_private_keep; // keep list for private home directory | ||
70 | char *cwd; // current working directory | ||
71 | |||
72 | // networking | ||
73 | char *hostname; | ||
74 | uint32_t defaultgw; // default gateway | ||
75 | Bridge bridge0; | ||
76 | Bridge bridge1; | ||
77 | Bridge bridge2; | ||
78 | Bridge bridge3; | ||
79 | uint32_t dns1; // up to 3 IP addresses for dns servers | ||
80 | uint32_t dns2; | ||
81 | uint32_t dns3; | ||
82 | |||
83 | // rlimits | ||
84 | unsigned rlimit_nofile; | ||
85 | unsigned rlimit_nproc; | ||
86 | unsigned rlimit_fsize; | ||
87 | unsigned rlimit_sigpending; | ||
88 | |||
89 | // cpu affinity and control groups | ||
90 | uint32_t cpus; | ||
91 | char *cgroup; | ||
92 | |||
93 | |||
94 | // command line | ||
95 | char *command_line; | ||
96 | char *command_name; | ||
97 | char *shell; | ||
98 | char **original_argv; | ||
99 | int original_argc; | ||
100 | int original_program_index; | ||
101 | } Config; | ||
102 | extern Config cfg; | ||
103 | |||
104 | static inline int any_bridge_configured(void) { | ||
105 | if (cfg.bridge3.configured || cfg.bridge2.configured || cfg.bridge1.configured || cfg.bridge0.configured) | ||
106 | return 1; | ||
107 | else | ||
108 | return 0; | ||
109 | } | ||
110 | extern int arg_private; // mount private /home and /tmp directory | ||
111 | extern int arg_debug; // print debug messages | ||
112 | extern int arg_nonetwork; // --net=none | ||
113 | extern int arg_command; // -c | ||
114 | extern int arg_overlay; // --overlay | ||
115 | extern int arg_zsh; // use zsh as default shell | ||
116 | extern int arg_csh; // use csh as default shell | ||
117 | |||
118 | extern int arg_seccomp; // enable default seccomp filter | ||
119 | extern char *arg_seccomp_list;// optional seccomp list on top of default filter | ||
120 | extern char *arg_seccomp_list_drop; // seccomp drop list | ||
121 | extern char *arg_seccomp_list_keep; // seccomp keep list | ||
122 | |||
123 | extern int arg_caps_default_filter; // enable default capabilities filter | ||
124 | extern int arg_caps_drop; // drop list | ||
125 | extern int arg_caps_drop_all; // drop all capabilities | ||
126 | extern int arg_caps_keep; // keep list | ||
127 | extern char *arg_caps_list; // optional caps list | ||
128 | |||
129 | extern int arg_trace; // syscall tracing support | ||
130 | extern int arg_rlimit_nofile; // rlimit nofile | ||
131 | extern int arg_rlimit_nproc; // rlimit nproc | ||
132 | extern int arg_rlimit_fsize; // rlimit fsize | ||
133 | extern int arg_rlimit_sigpending;// rlimit sigpending | ||
134 | extern int arg_nox11; // kill the program if x11 unix domain socket is accessed | ||
135 | extern int arg_nodbus; // kill the program if D-Bus is accessed | ||
136 | extern int arg_nogroups; // disable supplementary groups | ||
137 | extern int arg_noroot; // create a new user namespace and disable root user | ||
138 | extern int arg_netfilter; // enable netfilter | ||
139 | extern char *arg_netfilter_file; // netfilter file | ||
140 | extern int arg_doubledash; // double dash | ||
141 | extern int arg_shell_none; // run the program directly without a shell | ||
142 | extern int arg_private_dev; // private dev directory | ||
143 | extern int arg_scan; // arp-scan all interfaces | ||
144 | |||
145 | extern int parent_to_child_fds[2]; | ||
146 | extern int child_to_parent_fds[2]; | ||
147 | extern pid_t sandbox_pid; | ||
148 | |||
149 | |||
150 | |||
151 | #define MAX_ARGS 128 // maximum number of command arguments (argc) | ||
152 | extern char *fullargv[MAX_ARGS]; | ||
153 | extern int fullargc; | ||
154 | |||
155 | // main.c | ||
156 | void check_user_namespace(void); | ||
157 | |||
158 | // sandbox.c | ||
159 | int sandbox(void* sandbox_arg); | ||
160 | |||
161 | // network_main.c | ||
162 | void net_configure_bridge(Bridge *br, char *dev_name); | ||
163 | void net_configure_sandbox_ip(Bridge *br); | ||
164 | void net_configure_veth_pair(Bridge *br, const char *ifname, pid_t child); | ||
165 | void net_check_cfg(void); | ||
166 | void net_dns_print_name(const char *name); | ||
167 | void net_dns_print(pid_t pid); | ||
168 | |||
169 | // network.c | ||
170 | void net_if_up(const char *ifname); | ||
171 | void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask); | ||
172 | int net_get_if_addr(const char *bridge, uint32_t *ip, uint32_t *mask, uint8_t mac[6]); | ||
173 | int net_add_route(uint32_t dest, uint32_t mask, uint32_t gw); | ||
174 | void net_ifprint(void); | ||
175 | void net_bridge_add_interface(const char *bridge, const char *dev); | ||
176 | uint32_t network_get_defaultgw(void); | ||
177 | int net_config_mac(const char *ifname, const unsigned char mac[6]); | ||
178 | int net_get_mac(const char *ifname, unsigned char mac[6]); | ||
179 | |||
180 | // fs.c | ||
181 | // build /tmp/firejail directory | ||
182 | void fs_build_firejail_dir(void); | ||
183 | // build /tmp/firejail/mnt directory | ||
184 | void fs_build_mnt_dir(void); | ||
185 | // blacklist files or directoies by mounting empty files on top of them | ||
186 | void fs_blacklist(const char *homedir); | ||
187 | //void fs_blacklist(char **blacklist, const char *homedir); | ||
188 | // remount a directory read-only | ||
189 | void fs_rdonly(const char *dir); | ||
190 | // mount /proc and /sys directories | ||
191 | void fs_proc_sys_dev_boot(void); | ||
192 | // build a basic read-only filesystem | ||
193 | void fs_basic_fs(void); | ||
194 | // mount overlayfs on top of / directory | ||
195 | void fs_overlayfs(void); | ||
196 | // chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf | ||
197 | void fs_chroot(const char *rootdir); | ||
198 | int fs_check_chroot_dir(const char *rootdir); | ||
199 | |||
200 | // profile.c | ||
201 | // find and read the profile specified by name from dir directory | ||
202 | int profile_find(const char *name, const char *dir); | ||
203 | // read a profile file | ||
204 | void profile_read(const char *fname, const char *skip1, const char *skip2); | ||
205 | // check profile line; if line == 0, this was generated from a command line option | ||
206 | // return 1 if the command is to be added to the linked list of profile commands | ||
207 | // return 0 if the command was already executed inside the function | ||
208 | int profile_check_line(char *ptr, int lineno); | ||
209 | // add a profile entry in cfg.profile list; use str to populate the list | ||
210 | void profile_add(char *str); | ||
211 | |||
212 | // list.c | ||
213 | void list(void); | ||
214 | void tree(void); | ||
215 | void top(void); | ||
216 | void netstats(void); | ||
217 | |||
218 | // usage.c | ||
219 | void usage(void); | ||
220 | |||
221 | // join.c | ||
222 | void join(pid_t pid, const char *homedir, int argc, char **argv, int index); | ||
223 | void join_name(const char *name, const char *homedir, int argc, char **argv, int index); | ||
224 | void shut(pid_t pid); | ||
225 | void shut_name(const char *name); | ||
226 | |||
227 | // restricted_shell.c | ||
228 | extern char *restricted_user; | ||
229 | int restricted_shell(const char *user); | ||
230 | |||
231 | // arp.c | ||
232 | // returns 0 if the address is not in use, -1 otherwise | ||
233 | int arp_check(const char *dev, uint32_t destaddr, uint32_t srcaddr); | ||
234 | // assign an IP address using arp scanning | ||
235 | uint32_t arp_assign(const char *dev, Bridge *br); | ||
236 | // scan interface (--scan option) | ||
237 | void arp_scan(const char *dev, uint32_t srcaddr, uint32_t srcmask); | ||
238 | |||
239 | // veth.c | ||
240 | int net_create_veth(const char *dev, const char *nsdev, unsigned pid); | ||
241 | int net_create_macvlan(const char *dev, const char *parent, unsigned pid); | ||
242 | |||
243 | // util.c | ||
244 | void drop_privs(int nogroups); | ||
245 | void extract_command_name(const char *str); | ||
246 | void logsignal(int s); | ||
247 | void logmsg(const char *msg); | ||
248 | void logargs(int argc, char **argv) ; | ||
249 | void logerr(const char *msg); | ||
250 | int copy_file(const char *srcname, const char *destname); | ||
251 | char *get_link(const char *fname); | ||
252 | int is_dir(const char *fname); | ||
253 | int is_link(const char *fname); | ||
254 | char *line_remove_spaces(const char *buf); | ||
255 | char *split_comma(char *str); | ||
256 | int not_unsigned(const char *str); | ||
257 | int find_child(pid_t parent, pid_t *child); | ||
258 | void check_private_dir(void); | ||
259 | void update_map(char *mapping, char *map_file); | ||
260 | void wait_for_other(int fd); | ||
261 | void notify_other(int fd); | ||
262 | |||
263 | // fs_var.c | ||
264 | void fs_var_log(void); // mounting /var/log | ||
265 | void fs_var_lib(void); // various other fixes for software in /var directory | ||
266 | void fs_var_cache(void); // various other fixes for software in /var/cache directory | ||
267 | void fs_var_run(void); | ||
268 | void fs_var_lock(void); | ||
269 | void fs_var_tmp(void); | ||
270 | void fs_var_utmp(void); | ||
271 | void dbg_test_dir(const char *dir); | ||
272 | |||
273 | // fs_dev.c | ||
274 | void fs_dev_shm(void); | ||
275 | void fs_private_dev(void); | ||
276 | |||
277 | // fs_home.c | ||
278 | // private mode (--private) | ||
279 | void fs_private(void); | ||
280 | // private mode (--private=homedir) | ||
281 | void fs_private_homedir(void); | ||
282 | // private mode (--private.keep=list) | ||
283 | void fs_private_home_list(void); | ||
284 | // check directory linst specified by user (--private.keep option) - exit if it fails | ||
285 | void fs_check_home_list(void); | ||
286 | // check new private home directory (--private= option) - exit if it fails | ||
287 | void fs_check_private_dir(void); | ||
288 | |||
289 | |||
290 | // seccomp.c | ||
291 | int seccomp_filter_drop(void); | ||
292 | int seccomp_filter_keep(void); | ||
293 | void seccomp_set(void); | ||
294 | void seccomp_print_filter_name(const char *name); | ||
295 | void seccomp_print_filter(pid_t pid); | ||
296 | |||
297 | // caps.c | ||
298 | int caps_default_filter(void); | ||
299 | void caps_print(void); | ||
300 | void caps_drop_all(void); | ||
301 | void caps_set(uint64_t caps); | ||
302 | int caps_check_list(const char *clist, void (*callback)(int)); | ||
303 | void caps_drop_list(const char *clist); | ||
304 | void caps_keep_list(const char *clist); | ||
305 | void caps_print_filter(pid_t pid); | ||
306 | void caps_print_filter_name(const char *name); | ||
307 | |||
308 | // syscall.c | ||
309 | const char *syscall_find_nr(int nr); | ||
310 | // return -1 if error, 0 if no error | ||
311 | int syscall_check_list(const char *slist, void (*callback)(int)); | ||
312 | // print all available syscalls | ||
313 | void syscall_print(void); | ||
314 | |||
315 | // fs_trace.c | ||
316 | void fs_trace_preload(void); | ||
317 | void fs_trace(void); | ||
318 | |||
319 | // fs_hostname.c | ||
320 | void fs_hostname(const char *hostname); | ||
321 | void fs_resolvconf(void); | ||
322 | |||
323 | // rlimit.c | ||
324 | void set_rlimits(void); | ||
325 | |||
326 | // cpu.c | ||
327 | void read_cpu_list(const char *str); | ||
328 | void set_cpu_affinity(void); | ||
329 | void load_cpu(const char *fname); | ||
330 | void save_cpu(void); | ||
331 | |||
332 | // cgroup.c | ||
333 | void save_cgroup(void); | ||
334 | void load_cgroup(const char *fname); | ||
335 | void set_cgroup(const char *path); | ||
336 | |||
337 | // output.c | ||
338 | void check_output(int argc, char **argv); | ||
339 | |||
340 | // netfilter.c | ||
341 | void check_netfilter_file(const char *fname); | ||
342 | void netfilter(const char *fname); | ||
343 | |||
344 | // bandwidth.c | ||
345 | void shm_create_firejail_dir(void); | ||
346 | void bandwidth_shm_del_file(pid_t pid); | ||
347 | void bandwidth_shm_set(pid_t pid, const char *dev, int down, int up); | ||
348 | void bandwidth_name(const char *name, const char *command, const char *dev, int down, int up); | ||
349 | void bandwidth_pid(pid_t pid, const char *command, const char *dev, int down, int up); | ||
350 | void network_shm_del_file(pid_t pid); | ||
351 | void network_shm_set_file(pid_t pid); | ||
352 | |||
353 | |||
354 | #endif \ No newline at end of file | ||
diff --git a/src/firejail/fs.c b/src/firejail/fs.c new file mode 100644 index 000000000..1fc1c0942 --- /dev/null +++ b/src/firejail/fs.c | |||
@@ -0,0 +1,825 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 | #include <linux/limits.h> | ||
24 | #include <glob.h> | ||
25 | #include <dirent.h> | ||
26 | #include <fcntl.h> | ||
27 | #include <errno.h> | ||
28 | |||
29 | // build /tmp/firejail directory | ||
30 | void fs_build_firejail_dir(void) { | ||
31 | struct stat s; | ||
32 | |||
33 | if (stat(FIREJAIL_DIR, &s)) { | ||
34 | if (arg_debug) | ||
35 | printf("Creating %s directory\n", FIREJAIL_DIR); | ||
36 | /* coverity[toctou] */ | ||
37 | int rv = mkdir(FIREJAIL_DIR, S_IRWXU | S_IRWXG | S_IRWXO); | ||
38 | if (rv == -1) | ||
39 | errExit("mkdir"); | ||
40 | if (chown(FIREJAIL_DIR, 0, 0) < 0) | ||
41 | errExit("chown"); | ||
42 | if (chmod(FIREJAIL_DIR, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) | ||
43 | errExit("chmod"); | ||
44 | } | ||
45 | else { // check /tmp/firejail directory belongs to root end exit if doesn't! | ||
46 | if (s.st_uid != 0 || s.st_gid != 0) { | ||
47 | fprintf(stderr, "Error: non-root %s directory, exiting...\n", FIREJAIL_DIR); | ||
48 | exit(1); | ||
49 | } | ||
50 | } | ||
51 | } | ||
52 | |||
53 | |||
54 | // build /tmp/firejail/mnt directory | ||
55 | static int tmpfs_mounted = 0; | ||
56 | void fs_build_mnt_dir(void) { | ||
57 | struct stat s; | ||
58 | fs_build_firejail_dir(); | ||
59 | |||
60 | // create /tmp/firejail directory | ||
61 | if (stat(MNT_DIR, &s)) { | ||
62 | if (arg_debug) | ||
63 | printf("Creating %s directory\n", MNT_DIR); | ||
64 | /* coverity[toctou] */ | ||
65 | int rv = mkdir(MNT_DIR, S_IRWXU | S_IRWXG | S_IRWXO); | ||
66 | if (rv == -1) | ||
67 | errExit("mkdir"); | ||
68 | if (chown(MNT_DIR, 0, 0) < 0) | ||
69 | errExit("chown"); | ||
70 | if (chmod(MNT_DIR, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) | ||
71 | errExit("chmod"); | ||
72 | } | ||
73 | |||
74 | // ... and mount tmpfs on top of it | ||
75 | if (!tmpfs_mounted) { | ||
76 | // mount tmpfs on top of /tmp/firejail/mnt | ||
77 | if (arg_debug) | ||
78 | printf("Mounting tmpfs on %s directory\n", MNT_DIR); | ||
79 | if (mount("tmpfs", MNT_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) | ||
80 | errExit("mounting /tmp/firejail/mnt"); | ||
81 | tmpfs_mounted = 1; | ||
82 | } | ||
83 | } | ||
84 | |||
85 | // build /tmp/firejail/overlay directory | ||
86 | void fs_build_overlay_dir(void) { | ||
87 | struct stat s; | ||
88 | fs_build_firejail_dir(); | ||
89 | |||
90 | // create /tmp/firejail directory | ||
91 | if (stat(OVERLAY_DIR, &s)) { | ||
92 | if (arg_debug) | ||
93 | printf("Creating %s directory\n", MNT_DIR); | ||
94 | /* coverity[toctou] */ | ||
95 | int rv = mkdir(OVERLAY_DIR, S_IRWXU | S_IRWXG | S_IRWXO); | ||
96 | if (rv == -1) | ||
97 | errExit("mkdir"); | ||
98 | if (chown(OVERLAY_DIR, 0, 0) < 0) | ||
99 | errExit("chown"); | ||
100 | if (chmod(OVERLAY_DIR, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) | ||
101 | errExit("chmod"); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | |||
106 | |||
107 | |||
108 | |||
109 | //*********************************************** | ||
110 | // process profile file | ||
111 | //*********************************************** | ||
112 | typedef enum { | ||
113 | BLACKLIST_FILE, | ||
114 | MOUNT_READONLY, | ||
115 | MOUNT_TMPFS, | ||
116 | OPERATION_MAX | ||
117 | } OPERATION; | ||
118 | |||
119 | |||
120 | static char *create_empty_dir(void) { | ||
121 | struct stat s; | ||
122 | fs_build_firejail_dir(); | ||
123 | |||
124 | if (stat(RO_DIR, &s)) { | ||
125 | /* coverity[toctou] */ | ||
126 | int rv = mkdir(RO_DIR, S_IRUSR | S_IXUSR); | ||
127 | if (rv == -1) | ||
128 | errExit("mkdir"); | ||
129 | if (chown(RO_DIR, 0, 0) < 0) | ||
130 | errExit("chown"); | ||
131 | } | ||
132 | |||
133 | return RO_DIR; | ||
134 | } | ||
135 | |||
136 | static char *create_empty_file(void) { | ||
137 | struct stat s; | ||
138 | fs_build_firejail_dir(); | ||
139 | |||
140 | if (stat(RO_FILE, &s)) { | ||
141 | /* coverity[toctou] */ | ||
142 | FILE *fp = fopen(RO_FILE, "w"); | ||
143 | if (!fp) | ||
144 | errExit("fopen"); | ||
145 | fclose(fp); | ||
146 | if (chown(RO_FILE, 0, 0) < 0) | ||
147 | errExit("chown"); | ||
148 | if (chmod(RO_FILE, S_IRUSR) < 0) | ||
149 | errExit("chown"); | ||
150 | } | ||
151 | |||
152 | return RO_FILE; | ||
153 | } | ||
154 | |||
155 | static void disable_file(OPERATION op, const char *fname, const char *emptydir, const char *emptyfile) { | ||
156 | assert(fname); | ||
157 | assert(emptydir); | ||
158 | assert(emptyfile); | ||
159 | assert(op <OPERATION_MAX); | ||
160 | |||
161 | // if the file is a link, follow the link | ||
162 | char *lnk = NULL; | ||
163 | if (is_link(fname)) { | ||
164 | lnk = get_link(fname); | ||
165 | if (lnk) | ||
166 | fname = lnk; | ||
167 | else | ||
168 | fprintf(stderr, "Warning: cannot follow link %s, skipping...\n", fname); | ||
169 | } | ||
170 | |||
171 | // if the file is not present, do nothing | ||
172 | struct stat s; | ||
173 | if (stat(fname, &s) == -1) { | ||
174 | if (lnk) | ||
175 | free(lnk); | ||
176 | return; | ||
177 | } | ||
178 | |||
179 | // modify the file | ||
180 | if (op == BLACKLIST_FILE) { | ||
181 | if (arg_debug) | ||
182 | printf("Disable %s\n", fname); | ||
183 | if (S_ISDIR(s.st_mode)) { | ||
184 | if (mount(emptydir, fname, "none", MS_BIND, "mode=400,gid=0") < 0) | ||
185 | errExit("disable file"); | ||
186 | } | ||
187 | else { | ||
188 | if (mount(emptyfile, fname, "none", MS_BIND, "mode=400,gid=0") < 0) | ||
189 | errExit("disable file"); | ||
190 | } | ||
191 | } | ||
192 | else if (op == MOUNT_READONLY) { | ||
193 | if (arg_debug) | ||
194 | printf("Mounting read-only %s\n", fname); | ||
195 | fs_rdonly(fname); | ||
196 | } | ||
197 | else if (op == MOUNT_TMPFS) { | ||
198 | if (S_ISDIR(s.st_mode)) { | ||
199 | if (arg_debug) | ||
200 | printf("Mounting tmpfs on %s\n", fname); | ||
201 | // preserve owner and mode for the directory | ||
202 | if (mount("tmpfs", fname, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, 0) < 0) | ||
203 | errExit("mounting tmpfs"); | ||
204 | /* coverity[toctou] */ | ||
205 | if (chown(fname, s.st_uid, s.st_gid) == -1) | ||
206 | errExit("mounting tmpfs chmod"); | ||
207 | } | ||
208 | else | ||
209 | printf("Warning: %s is not a directory; cannot mount a tmpfs on top of it.\n", fname); | ||
210 | } | ||
211 | else | ||
212 | assert(0); | ||
213 | |||
214 | if (lnk) | ||
215 | free(lnk); | ||
216 | } | ||
217 | |||
218 | static void globbing(OPERATION op, const char *fname, const char *emptydir, const char *emptyfile) { | ||
219 | assert(fname); | ||
220 | assert(emptydir); | ||
221 | assert(emptyfile); | ||
222 | |||
223 | // filename globbing: expand * macro and continue processing for every single file | ||
224 | if (strchr(fname, '*')) { | ||
225 | glob_t globbuf; | ||
226 | globbuf.gl_offs = 0; | ||
227 | glob(fname, GLOB_DOOFFS, NULL, &globbuf); | ||
228 | int i; | ||
229 | for (i = 0; i < globbuf.gl_pathc; i++) { | ||
230 | assert(globbuf.gl_pathv[i]); | ||
231 | disable_file(op, globbuf.gl_pathv[i], emptydir, emptyfile); | ||
232 | } | ||
233 | } | ||
234 | else | ||
235 | disable_file(op, fname, emptydir, emptyfile); | ||
236 | } | ||
237 | |||
238 | static void expand_path(OPERATION op, const char *path, const char *fname, const char *emptydir, const char *emptyfile) { | ||
239 | assert(path); | ||
240 | assert(fname); | ||
241 | assert(emptydir); | ||
242 | assert(emptyfile); | ||
243 | char newname[strlen(path) + strlen(fname) + 1]; | ||
244 | sprintf(newname, "%s%s", path, fname); | ||
245 | |||
246 | globbing(op, newname, emptydir, emptyfile); | ||
247 | } | ||
248 | |||
249 | // blacklist files or directoies by mounting empty files on top of them | ||
250 | void fs_blacklist(const char *homedir) { | ||
251 | ProfileEntry *entry = cfg.profile; | ||
252 | if (!entry) | ||
253 | return; | ||
254 | |||
255 | char *emptydir = create_empty_dir(); | ||
256 | char *emptyfile = create_empty_file(); | ||
257 | |||
258 | while (entry) { | ||
259 | OPERATION op = OPERATION_MAX; | ||
260 | char *ptr; | ||
261 | |||
262 | // process blacklist command | ||
263 | if (strncmp(entry->data, "bind", 4) == 0) { | ||
264 | char *dname1 = entry->data + 5; | ||
265 | char *dname2 = split_comma(dname1); | ||
266 | if (dname2 == NULL) { | ||
267 | fprintf(stderr, "Error: second directory missing in bind command\n"); | ||
268 | entry = entry->next; | ||
269 | continue; | ||
270 | } | ||
271 | struct stat s; | ||
272 | if (stat(dname1, &s) == -1) { | ||
273 | fprintf(stderr, "Error: cannot find directories for bind command\n"); | ||
274 | entry = entry->next; | ||
275 | continue; | ||
276 | } | ||
277 | if (stat(dname2, &s) == -1) { | ||
278 | fprintf(stderr, "Error: cannot find directories for bind command\n"); | ||
279 | entry = entry->next; | ||
280 | continue; | ||
281 | } | ||
282 | |||
283 | // mount --bind olddir newdir | ||
284 | if (arg_debug) | ||
285 | printf("Mount-bind %s on top of %s\n", dname1, dname2); | ||
286 | // preserve dname2 mode and ownership | ||
287 | if (mount(dname1, dname2, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
288 | errExit("mount bind"); | ||
289 | /* coverity[toctou] */ | ||
290 | if (chown(dname2, s.st_uid, s.st_gid) == -1) | ||
291 | errExit("mount-bind chown"); | ||
292 | /* coverity[toctou] */ | ||
293 | if (chmod(dname2, s.st_mode) == -1) | ||
294 | errExit("mount-bind chmod"); | ||
295 | |||
296 | entry = entry->next; | ||
297 | continue; | ||
298 | } | ||
299 | |||
300 | // process blacklist command | ||
301 | if (strncmp(entry->data, "blacklist", 9) == 0) { | ||
302 | ptr = entry->data + 10; | ||
303 | op = BLACKLIST_FILE; | ||
304 | } | ||
305 | else if (strncmp(entry->data, "read-only", 9) == 0) { | ||
306 | ptr = entry->data + 10; | ||
307 | op = MOUNT_READONLY; | ||
308 | } | ||
309 | else if (strncmp(entry->data, "tmpfs", 5) == 0) { | ||
310 | ptr = entry->data + 6; | ||
311 | op = MOUNT_TMPFS; | ||
312 | } | ||
313 | else { | ||
314 | fprintf(stderr, "Error: invalid profile line %s\n", entry->data); | ||
315 | entry = entry->next; | ||
316 | continue; | ||
317 | } | ||
318 | |||
319 | // replace home macro in blacklist array | ||
320 | char *new_name = NULL; | ||
321 | if (strncmp(ptr, "${HOME}", 7) == 0) { | ||
322 | if (asprintf(&new_name, "%s%s", homedir, ptr + 7) == -1) | ||
323 | errExit("asprintf"); | ||
324 | ptr = new_name; | ||
325 | } | ||
326 | |||
327 | // expand path macro - look for the file in /bin, /usr/bin, /sbin and /usr/sbin directories | ||
328 | if (strncmp(ptr, "${PATH}", 7) == 0) { | ||
329 | expand_path(op, "/bin", ptr + 7, emptydir, emptyfile); | ||
330 | expand_path(op, "/sbin", ptr + 7, emptydir, emptyfile); | ||
331 | expand_path(op, "/usr/bin", ptr + 7, emptydir, emptyfile); | ||
332 | expand_path(op, "/usr/sbin", ptr + 7, emptydir, emptyfile); | ||
333 | } | ||
334 | else | ||
335 | globbing(op, ptr, emptydir, emptyfile); | ||
336 | |||
337 | if (new_name) | ||
338 | free(new_name); | ||
339 | entry = entry->next; | ||
340 | } | ||
341 | } | ||
342 | |||
343 | //*********************************************** | ||
344 | // mount namespace | ||
345 | //*********************************************** | ||
346 | |||
347 | // remount a directory read-only | ||
348 | void fs_rdonly(const char *dir) { | ||
349 | assert(dir); | ||
350 | // check directory exists | ||
351 | struct stat s; | ||
352 | int rv = stat(dir, &s); | ||
353 | if (rv == 0) { | ||
354 | // mount --bind /bin /bin | ||
355 | if (mount(dir, dir, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
356 | errExit("mount read-only"); | ||
357 | // mount --bind -o remount,ro /bin | ||
358 | if (mount(NULL, dir, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_REC, NULL) < 0) | ||
359 | errExit("mount read-only"); | ||
360 | } | ||
361 | } | ||
362 | void fs_rdonly_noexit(const char *dir) { | ||
363 | assert(dir); | ||
364 | // check directory exists | ||
365 | struct stat s; | ||
366 | int rv = stat(dir, &s); | ||
367 | if (rv == 0) { | ||
368 | int merr = 0; | ||
369 | // mount --bind /bin /bin | ||
370 | if (mount(dir, dir, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
371 | merr = 1; | ||
372 | // mount --bind -o remount,ro /bin | ||
373 | if (mount(NULL, dir, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_REC, NULL) < 0) | ||
374 | merr = 1; | ||
375 | if (merr) | ||
376 | fprintf(stderr, "Warning: cannot mount %s read-only\n", dir); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | // mount /proc and /sys directories | ||
381 | void fs_proc_sys_dev_boot(void) { | ||
382 | struct stat s; | ||
383 | |||
384 | if (arg_debug) | ||
385 | printf("Remounting /proc and /proc/sys filesystems\n"); | ||
386 | if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0) | ||
387 | errExit("mounting /proc"); | ||
388 | |||
389 | // remount /proc/sys readonly | ||
390 | if (mount("/proc/sys", "/proc/sys", NULL, MS_BIND | MS_REC, NULL) < 0) | ||
391 | errExit("mounting /proc/sys"); | ||
392 | |||
393 | if (mount(NULL, "/proc/sys", NULL, MS_BIND | MS_REMOUNT | MS_RDONLY | MS_REC, NULL) < 0) | ||
394 | errExit("mounting /proc/sys"); | ||
395 | |||
396 | |||
397 | /* Mount a version of /sys that describes the network namespace */ | ||
398 | if (arg_debug) | ||
399 | printf("Remounting /sys directory\n"); | ||
400 | if (umount2("/sys", MNT_DETACH) < 0) | ||
401 | fprintf(stderr, "Warning: failed to unmount /sys\n"); | ||
402 | if (mount("sysfs", "/sys", "sysfs", MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REC, NULL) < 0) | ||
403 | fprintf(stderr, "Warning: failed to mount /sys\n"); | ||
404 | |||
405 | // if (mount("sysfs", "/sys", "sysfs", MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REC, NULL) < 0) | ||
406 | // errExit("mounting /sys"); | ||
407 | |||
408 | |||
409 | // mounting firejail kernel module files | ||
410 | if (stat("/proc/firejail-uptime", &s) == 0) { | ||
411 | errno = 0; | ||
412 | FILE *fp = fopen("/proc/firejail", "w"); | ||
413 | int cnt = 0; | ||
414 | while (errno == EBUSY && cnt < 10) { | ||
415 | if (!fp) { | ||
416 | int s = random(); | ||
417 | s /= 200000; | ||
418 | usleep(s); | ||
419 | fp = fopen("/proc/firejail", "w"); | ||
420 | } | ||
421 | else | ||
422 | break; | ||
423 | } | ||
424 | if (!fp) { | ||
425 | fprintf(stderr, "Error: cannot register sandbox with firejail-lkm\n"); | ||
426 | exit(1); | ||
427 | } | ||
428 | if (fp) { | ||
429 | // registration | ||
430 | fprintf(fp, "register\n"); | ||
431 | fflush(0); | ||
432 | // filtering x11 connect calls | ||
433 | if (arg_nox11) { | ||
434 | fprintf(fp, "no connect unix /tmp/.X11\n"); | ||
435 | fflush(0); | ||
436 | printf("X11 access disabled\n"); | ||
437 | } | ||
438 | if (arg_nodbus) { | ||
439 | fprintf(fp, "no connect unix /var/run/dbus/system_bus_socket\n"); | ||
440 | fflush(0); | ||
441 | fprintf(fp, "no connect unix /tmp/dbus\n"); | ||
442 | fflush(0); | ||
443 | printf("D-Bus access disabled\n"); | ||
444 | } | ||
445 | fclose(fp); | ||
446 | if (mount("/proc/firejail-uptime", "/proc/uptime", NULL, MS_BIND|MS_REC, NULL) < 0) | ||
447 | fprintf(stderr, "Warning: cannot mount /proc/firejail-uptime\n"); | ||
448 | } | ||
449 | } | ||
450 | |||
451 | // Disable SysRq | ||
452 | // a linux box can be shut down easily using the following commands (as root): | ||
453 | // # echo 1 > /proc/sys/kernel/sysrq | ||
454 | // #echo b > /proc/sysrq-trigger | ||
455 | // for more information see https://www.kernel.org/doc/Documentation/sysrq.txt | ||
456 | if (arg_debug) | ||
457 | printf("Disable /proc/sysrq-trigger\n"); | ||
458 | fs_rdonly_noexit("/proc/sysrq-trigger"); | ||
459 | |||
460 | // disable hotplug and uevent_helper | ||
461 | if (arg_debug) | ||
462 | printf("Disable /proc/sys/kernel/hotplug\n"); | ||
463 | fs_rdonly_noexit("/proc/sys/kernel/hotplug"); | ||
464 | if (arg_debug) | ||
465 | printf("Disable /sys/kernel/uevent_helper\n"); | ||
466 | fs_rdonly_noexit("/sys/kernel/uevent_helper"); | ||
467 | |||
468 | // read-only /proc/irq and /proc/bus | ||
469 | if (arg_debug) | ||
470 | printf("Disable /proc/irq\n"); | ||
471 | fs_rdonly_noexit("/proc/irq"); | ||
472 | if (arg_debug) | ||
473 | printf("Disable /proc/bus\n"); | ||
474 | fs_rdonly_noexit("/proc/bus"); | ||
475 | |||
476 | // disable /proc/kcore | ||
477 | disable_file(BLACKLIST_FILE, "/proc/kcore", "not used", "/dev/null"); | ||
478 | |||
479 | // disable /proc/kallsyms | ||
480 | disable_file(BLACKLIST_FILE, "/proc/kallsyms", "not used", "/dev/null"); | ||
481 | |||
482 | // disable /boot | ||
483 | if (stat("/boot", &s) == 0) { | ||
484 | if (arg_debug) | ||
485 | printf("Mounting a new /boot directory\n"); | ||
486 | if (mount("tmpfs", "/boot", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) | ||
487 | errExit("mounting /boot directory"); | ||
488 | } | ||
489 | |||
490 | // disable /dev/port | ||
491 | if (stat("/dev/port", &s) == 0) { | ||
492 | disable_file(BLACKLIST_FILE, "/dev/port", "not used", "/dev/null"); | ||
493 | } | ||
494 | } | ||
495 | |||
496 | static void sanitize_home(void) { | ||
497 | // extract current /home directory data | ||
498 | struct dirent *dir; | ||
499 | DIR *d = opendir("/home"); | ||
500 | if (d == NULL) | ||
501 | return; | ||
502 | |||
503 | char *emptydir = create_empty_dir(); | ||
504 | while ((dir = readdir(d))) { | ||
505 | if(strcmp(dir->d_name, "." ) == 0 || strcmp(dir->d_name, ".." ) == 0) | ||
506 | continue; | ||
507 | |||
508 | if (dir->d_type == DT_DIR ) { | ||
509 | // get properties | ||
510 | struct stat s; | ||
511 | char *name; | ||
512 | if (asprintf(&name, "/home/%s", dir->d_name) == -1) | ||
513 | continue; | ||
514 | if (stat(name, &s) == -1) | ||
515 | continue; | ||
516 | if (S_ISLNK(s.st_mode)) { | ||
517 | free(name); | ||
518 | continue; | ||
519 | } | ||
520 | |||
521 | if (strcmp(name, cfg.homedir) == 0) | ||
522 | continue; | ||
523 | |||
524 | // printf("directory %u %u:%u #%s#\n", | ||
525 | // s.st_mode, | ||
526 | // s.st_uid, | ||
527 | // s.st_gid, | ||
528 | // name); | ||
529 | |||
530 | // disable directory | ||
531 | disable_file(BLACKLIST_FILE, name, emptydir, "not used"); | ||
532 | free(name); | ||
533 | } | ||
534 | } | ||
535 | closedir(d); | ||
536 | } | ||
537 | |||
538 | |||
539 | |||
540 | |||
541 | |||
542 | |||
543 | // build a basic read-only filesystem | ||
544 | void fs_basic_fs(void) { | ||
545 | if (arg_debug) | ||
546 | printf("Mounting read-only /bin, /sbin, /lib, /lib64, /usr, /etc, /var\n"); | ||
547 | fs_rdonly("/bin"); | ||
548 | fs_rdonly("/sbin"); | ||
549 | fs_rdonly("/lib"); | ||
550 | fs_rdonly("/lib64"); | ||
551 | fs_rdonly("/usr"); | ||
552 | fs_rdonly("/etc"); | ||
553 | fs_rdonly("/var"); | ||
554 | |||
555 | // update /var directory in order to support multiple sandboxes running on the same root directory | ||
556 | if (!arg_private_dev) | ||
557 | fs_dev_shm(); | ||
558 | fs_var_lock(); | ||
559 | fs_var_tmp(); | ||
560 | fs_var_log(); | ||
561 | fs_var_lib(); | ||
562 | fs_var_cache(); | ||
563 | fs_var_utmp(); | ||
564 | |||
565 | // only in user mode | ||
566 | if (getuid()) | ||
567 | sanitize_home(); | ||
568 | } | ||
569 | |||
570 | |||
571 | // mount overlayfs on top of / directory | ||
572 | // mounting an overlay and chrooting into it: | ||
573 | // | ||
574 | // Old Ubuntu kernel | ||
575 | // # cd ~ | ||
576 | // # mkdir -p overlay/root | ||
577 | // # mkdir -p overlay/diff | ||
578 | // # mount -t overlayfs -o lowerdir=/,upperdir=/root/overlay/diff overlayfs /root/overlay/root | ||
579 | // # chroot /root/overlay/root | ||
580 | // to shutdown, first exit the chroot and then unmount the overlay | ||
581 | // # exit | ||
582 | // # umount /root/overlay/root | ||
583 | // | ||
584 | // Kernels 3.18+ | ||
585 | // # cd ~ | ||
586 | // # mkdir -p overlay/root | ||
587 | // # mkdir -p overlay/diff | ||
588 | // # mkdir -p overlay/work | ||
589 | // # mount -t overlay -o lowerdir=/,upperdir=/root/overlay/diff,workdir=/root/overlay/work overlay /root/overlay/root | ||
590 | // # cat /etc/mtab | grep overlay | ||
591 | // /root/overlay /root/overlay/root overlay rw,relatime,lowerdir=/,upperdir=/root/overlay/diff,workdir=/root/overlay/work 0 0 | ||
592 | // # chroot /root/overlay/root | ||
593 | // to shutdown, first exit the chroot and then unmount the overlay | ||
594 | // # exit | ||
595 | // # umount /root/overlay/root | ||
596 | |||
597 | |||
598 | // to do: fix the code below; also, it might work without /dev; impose seccomp/caps filters when not root | ||
599 | #include <sys/utsname.h> | ||
600 | void fs_overlayfs(void) { | ||
601 | // check kernel version | ||
602 | struct utsname u; | ||
603 | int rv = uname(&u); | ||
604 | if (rv != 0) | ||
605 | errExit("uname"); | ||
606 | int major; | ||
607 | int minor; | ||
608 | if (2 != sscanf(u.release, "%d.%d", &major, &minor)) { | ||
609 | fprintf(stderr, "Error: cannot extract Linux kernel version: %s\n", u.version); | ||
610 | exit(1); | ||
611 | } | ||
612 | |||
613 | if (arg_debug) | ||
614 | printf("Linux kernel version %d.%d\n", major, minor); | ||
615 | int oldkernel = 0; | ||
616 | if (major < 3) { | ||
617 | fprintf(stderr, "Error: minimum kernel version required 3.x\n"); | ||
618 | exit(1); | ||
619 | } | ||
620 | if (major == 3 && minor < 18) | ||
621 | oldkernel = 1; | ||
622 | |||
623 | // build overlay directories | ||
624 | fs_build_mnt_dir(); | ||
625 | |||
626 | char *oroot; | ||
627 | if(asprintf(&oroot, "%s/oroot", MNT_DIR) == -1) | ||
628 | errExit("asprintf"); | ||
629 | if (mkdir(oroot, S_IRWXU | S_IRWXG | S_IRWXO)) | ||
630 | errExit("mkdir"); | ||
631 | if (chown(oroot, 0, 0) < 0) | ||
632 | errExit("chown"); | ||
633 | if (chmod(oroot, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) | ||
634 | errExit("chmod"); | ||
635 | |||
636 | char *odiff; | ||
637 | if(asprintf(&odiff, "%s/odiff", MNT_DIR) == -1) | ||
638 | errExit("asprintf"); | ||
639 | if (mkdir(odiff, S_IRWXU | S_IRWXG | S_IRWXO)) | ||
640 | errExit("mkdir"); | ||
641 | if (chown(odiff, 0, 0) < 0) | ||
642 | errExit("chown"); | ||
643 | if (chmod(odiff, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) | ||
644 | errExit("chmod"); | ||
645 | |||
646 | char *owork; | ||
647 | if(asprintf(&owork, "%s/owork", MNT_DIR) == -1) | ||
648 | errExit("asprintf"); | ||
649 | if (mkdir(owork, S_IRWXU | S_IRWXG | S_IRWXO)) | ||
650 | errExit("mkdir"); | ||
651 | if (chown(owork, 0, 0) < 0) | ||
652 | errExit("chown"); | ||
653 | if (chmod(owork, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) | ||
654 | errExit("chmod"); | ||
655 | |||
656 | // mount overlayfs | ||
657 | if (arg_debug) | ||
658 | printf("Mounting OverlayFS\n"); | ||
659 | char *option; | ||
660 | if (oldkernel) { // old Ubuntu/OpenSUSE kernels | ||
661 | if (asprintf(&option, "lowerdir=/,upperdir=%s", odiff) == -1) | ||
662 | errExit("asprintf"); | ||
663 | if (mount("overlayfs", oroot, "overlayfs", MS_MGC_VAL, option) < 0) | ||
664 | errExit("mounting overlayfs"); | ||
665 | } | ||
666 | else { // kernel 3.18 or newer | ||
667 | if (asprintf(&option, "lowerdir=/,upperdir=%s,workdir=%s", odiff, owork) == -1) | ||
668 | errExit("asprintf"); | ||
669 | if (mount("overlay", oroot, "overlay", MS_MGC_VAL, option) < 0) | ||
670 | errExit("mounting overlayfs"); | ||
671 | } | ||
672 | |||
673 | // mount-bind dev directory | ||
674 | if (arg_debug) | ||
675 | printf("Mounting /dev\n"); | ||
676 | char *dev; | ||
677 | if (asprintf(&dev, "%s/dev", oroot) == -1) | ||
678 | errExit("asprintf"); | ||
679 | if (mount("/dev", dev, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
680 | errExit("mounting /dev"); | ||
681 | |||
682 | // chroot in the new filesystem | ||
683 | if (chroot(oroot) == -1) | ||
684 | errExit("chroot"); | ||
685 | // update /var directory in order to support multiple sandboxes running on the same root directory | ||
686 | if (!arg_private_dev) | ||
687 | fs_dev_shm(); | ||
688 | fs_var_lock(); | ||
689 | fs_var_tmp(); | ||
690 | fs_var_log(); | ||
691 | fs_var_lib(); | ||
692 | fs_var_cache(); | ||
693 | fs_var_utmp(); | ||
694 | |||
695 | // only in user mode | ||
696 | if (getuid()) | ||
697 | sanitize_home(); | ||
698 | |||
699 | // cleanup and exit | ||
700 | free(option); | ||
701 | free(oroot); | ||
702 | free(odiff); | ||
703 | } | ||
704 | |||
705 | |||
706 | |||
707 | #ifdef HAVE_CHROOT | ||
708 | // return 1 if error | ||
709 | int fs_check_chroot_dir(const char *rootdir) { | ||
710 | assert(rootdir); | ||
711 | struct stat s; | ||
712 | char *name; | ||
713 | |||
714 | // check /dev | ||
715 | if (asprintf(&name, "%s/dev", rootdir) == -1) | ||
716 | errExit("asprintf"); | ||
717 | if (stat(name, &s) == -1) { | ||
718 | fprintf(stderr, "Error: cannot find /dev in chroot directory\n"); | ||
719 | return 1; | ||
720 | } | ||
721 | free(name); | ||
722 | |||
723 | // check /var/tmp | ||
724 | if (asprintf(&name, "%s/var/tmp", rootdir) == -1) | ||
725 | errExit("asprintf"); | ||
726 | if (stat(name, &s) == -1) { | ||
727 | fprintf(stderr, "Error: cannot find /var/tmp in chroot directory\n"); | ||
728 | return 1; | ||
729 | } | ||
730 | free(name); | ||
731 | |||
732 | // check /proc | ||
733 | if (asprintf(&name, "%s/proc", rootdir) == -1) | ||
734 | errExit("asprintf"); | ||
735 | if (stat(name, &s) == -1) { | ||
736 | fprintf(stderr, "Error: cannot find /proc in chroot directory\n"); | ||
737 | return 1; | ||
738 | } | ||
739 | free(name); | ||
740 | |||
741 | // check /proc | ||
742 | if (asprintf(&name, "%s/tmp", rootdir) == -1) | ||
743 | errExit("asprintf"); | ||
744 | if (stat(name, &s) == -1) { | ||
745 | fprintf(stderr, "Error: cannot find /tmp in chroot directory\n"); | ||
746 | return 1; | ||
747 | } | ||
748 | free(name); | ||
749 | |||
750 | // check /bin/bash | ||
751 | if (asprintf(&name, "%s/bin/bash", rootdir) == -1) | ||
752 | errExit("asprintf"); | ||
753 | if (stat(name, &s) == -1) { | ||
754 | fprintf(stderr, "Error: cannot find /bin/bash in chroot directory\n"); | ||
755 | return 1; | ||
756 | } | ||
757 | free(name); | ||
758 | |||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | // chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf | ||
763 | void fs_chroot(const char *rootdir) { | ||
764 | assert(rootdir); | ||
765 | |||
766 | //*********************************** | ||
767 | // mount-bind a /dev in rootdir | ||
768 | //*********************************** | ||
769 | // mount /dev | ||
770 | char *newdev; | ||
771 | if (asprintf(&newdev, "%s/dev", rootdir) == -1) | ||
772 | errExit("asprintf"); | ||
773 | if (arg_debug) | ||
774 | printf("Mounting /dev on %s\n", newdev); | ||
775 | if (mount("/dev", newdev, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
776 | errExit("mounting /dev"); | ||
777 | |||
778 | // some older distros don't have a /run directory | ||
779 | // create one by default | ||
780 | // no exit on error, let the user deal with any problems | ||
781 | char *rundir; | ||
782 | if (asprintf(&rundir, "%s/run", rootdir) == -1) | ||
783 | errExit("asprintf"); | ||
784 | if (!is_dir(rundir)) { | ||
785 | int rv = mkdir(rundir, S_IRWXU | S_IRWXG | S_IRWXO); | ||
786 | (void) rv; | ||
787 | rv = chown(rundir, 0, 0); | ||
788 | (void) rv; | ||
789 | } | ||
790 | |||
791 | // copy /etc/resolv.conf in chroot directory | ||
792 | // if resolv.conf in chroot is a symbolic link, this will fail | ||
793 | // no exit on error, let the user deal with the problem | ||
794 | char *fname; | ||
795 | if (asprintf(&fname, "%s/etc/resolv.conf", rootdir) == -1) | ||
796 | errExit("asprintf"); | ||
797 | if (arg_debug) | ||
798 | printf("Updating /etc/resolv.conf in %s\n", fname); | ||
799 | if (copy_file("/etc/resolv.conf", fname) == -1) | ||
800 | fprintf(stderr, "Warning: /etc/resolv.conf not initialized\n"); | ||
801 | |||
802 | // chroot into the new directory | ||
803 | if (arg_debug) | ||
804 | printf("Chrooting into %s\n", rootdir); | ||
805 | if (chroot(rootdir) < 0) | ||
806 | errExit("chroot"); | ||
807 | |||
808 | // update /var directory in order to support multiple sandboxes running on the same root directory | ||
809 | if (!arg_private_dev) | ||
810 | fs_dev_shm(); | ||
811 | fs_var_lock(); | ||
812 | fs_var_tmp(); | ||
813 | fs_var_log(); | ||
814 | fs_var_lib(); | ||
815 | fs_var_cache(); | ||
816 | fs_var_utmp(); | ||
817 | |||
818 | // only in user mode | ||
819 | if (getuid()) | ||
820 | sanitize_home(); | ||
821 | |||
822 | } | ||
823 | #endif | ||
824 | |||
825 | |||
diff --git a/src/firejail/fs_dev.c b/src/firejail/fs_dev.c new file mode 100644 index 000000000..80bd11582 --- /dev/null +++ b/src/firejail/fs_dev.c | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 | #include <linux/limits.h> | ||
24 | #include <glob.h> | ||
25 | #include <dirent.h> | ||
26 | #include <fcntl.h> | ||
27 | #include <pwd.h> | ||
28 | #ifndef _BSD_SOURCE | ||
29 | #define _BSD_SOURCE | ||
30 | #endif | ||
31 | #include <sys/types.h> | ||
32 | |||
33 | static void create_char_dev(const char *path, mode_t mode, int major, int minor) { | ||
34 | dev_t dev = makedev(major, minor); | ||
35 | int rv = mknod(path, S_IFCHR | mode, dev); | ||
36 | if (rv == -1) | ||
37 | goto errexit; | ||
38 | |||
39 | |||
40 | if (chmod(path, mode) < 0) | ||
41 | goto errexit; | ||
42 | if (chown(path, 0, 0) < 0) | ||
43 | goto errexit; | ||
44 | |||
45 | return; | ||
46 | |||
47 | errexit: | ||
48 | fprintf(stderr, "Error: cannot create %s device\n", path); | ||
49 | exit(1); | ||
50 | } | ||
51 | |||
52 | static void create_link(const char *oldpath, const char *newpath) { | ||
53 | if (symlink(oldpath, newpath) == -1) | ||
54 | goto errexit; | ||
55 | if (chown(newpath, 0, 0) < 0) | ||
56 | goto errexit; | ||
57 | return; | ||
58 | |||
59 | errexit: | ||
60 | fprintf(stderr, "Error: cannot create %s device\n", newpath); | ||
61 | exit(1); | ||
62 | } | ||
63 | |||
64 | void fs_private_dev(void){ | ||
65 | // install a new /dev directory | ||
66 | if (arg_debug) | ||
67 | printf("Mounting tmpfs on /dev\n"); | ||
68 | if (mount("tmpfs", "/dev", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) | ||
69 | errExit("mounting /dev"); | ||
70 | |||
71 | // create /dev/shm | ||
72 | if (arg_debug) | ||
73 | printf("Create /dev/shm directory\n"); | ||
74 | int rv = mkdir("/dev/shm", S_IRWXU | S_IRWXG | S_IRWXO); | ||
75 | if (rv == -1) | ||
76 | errExit("mkdir"); | ||
77 | if (chown("/dev/shm", 0, 0) < 0) | ||
78 | errExit("chown"); | ||
79 | if (chmod("/dev/shm", S_IRWXU | S_IRWXG | S_IRWXO) < 0) | ||
80 | errExit("chmod"); | ||
81 | |||
82 | // create devices | ||
83 | create_char_dev("/dev/zero", 0666, 1, 5); // mknod -m 666 /dev/zero c 1 5 | ||
84 | create_char_dev("/dev/null", 0666, 1, 3); // mknod -m 666 /dev/null c 1 3 | ||
85 | create_char_dev("/dev/full", 0666, 1, 7); // mknod -m 666 /dev/full c 1 7 | ||
86 | create_char_dev("/dev/random", 0666, 1, 8); // Mknod -m 666 /dev/random c 1 8 | ||
87 | create_char_dev("/dev/urandom", 0666, 1, 9); // mknod -m 666 /dev/urandom c 1 9 | ||
88 | create_char_dev("/dev/tty", 0666, 5, 0); // mknod -m 666 /dev/tty c 5 0 | ||
89 | #if 0 | ||
90 | create_dev("/dev/tty0", "mknod -m 666 /dev/tty0 c 4 0"); | ||
91 | create_dev("/dev/console", "mknod -m 622 /dev/console c 5 1"); | ||
92 | #endif | ||
93 | |||
94 | // pseudo-terminal | ||
95 | rv = mkdir("/dev/pts", 0755); | ||
96 | if (rv == -1) | ||
97 | errExit("mkdir"); | ||
98 | if (chown("/dev/pts", 0, 0) < 0) | ||
99 | errExit("chown"); | ||
100 | if (chmod("/dev/pts", 0755) < 0) | ||
101 | errExit("chmod"); | ||
102 | create_char_dev("/dev/pts/ptmx", 0666, 5, 2); //"mknod -m 666 /dev/pts/ptmx c 5 2"); | ||
103 | create_link("/dev/pts/ptmx", "/dev/ptmx"); | ||
104 | // mount -vt devpts -o newinstance -o ptmxmode=0666 devpts //dev/pts | ||
105 | if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL, "newinstance,ptmxmode=0666") < 0) | ||
106 | errExit("mounting /dev/pts"); | ||
107 | |||
108 | #if 0 | ||
109 | // stdin, stdout, stderr | ||
110 | create_link("/proc/self/fd", "/dev/fd"); | ||
111 | create_link("/proc/self/fd/0", "/dev/stdin"); | ||
112 | create_link("/proc/self/fd/1", "/dev/stdout"); | ||
113 | create_link("/proc/self/fd/2", "/dev/stderr"); | ||
114 | #endif | ||
115 | } | ||
116 | |||
117 | |||
118 | void fs_dev_shm(void) { | ||
119 | uid_t uid = getuid(); // set a new shm only if we started as root | ||
120 | if (uid) | ||
121 | return; | ||
122 | |||
123 | if (is_dir("/dev/shm")) { | ||
124 | if (arg_debug) | ||
125 | printf("Mounting tmpfs on /dev/shm\n"); | ||
126 | if (mount("tmpfs", "/dev/shm", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) | ||
127 | errExit("mounting /dev/shm"); | ||
128 | } | ||
129 | else { | ||
130 | char *lnk = get_link("/dev/shm"); | ||
131 | if (lnk) { | ||
132 | // convert a link such as "../shm" into "/shm" | ||
133 | char *lnk2 = lnk; | ||
134 | int cnt = 0; | ||
135 | while (strncmp(lnk2, "../", 3) == 0) { | ||
136 | cnt++; | ||
137 | lnk2 = lnk2 + 3; | ||
138 | } | ||
139 | if (cnt != 0) | ||
140 | lnk2 = lnk + (cnt - 1) * 3 + 2; | ||
141 | |||
142 | if (!is_dir(lnk2)) { | ||
143 | // create directory | ||
144 | if (mkdir(lnk2, S_IRWXU|S_IRWXG|S_IRWXO)) | ||
145 | errExit("mkdir"); | ||
146 | if (chown(lnk2, 0, 0)) | ||
147 | errExit("chown"); | ||
148 | if (chmod(lnk2, S_IRWXU|S_IRWXG|S_IRWXO)) | ||
149 | errExit("chmod"); | ||
150 | } | ||
151 | if (arg_debug) | ||
152 | printf("Mounting tmpfs on %s on behalf of /dev/shm\n", lnk2); | ||
153 | if (mount("tmpfs", lnk2, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) | ||
154 | errExit("mounting /var/tmp"); | ||
155 | free(lnk); | ||
156 | } | ||
157 | else { | ||
158 | fprintf(stderr, "Warning: /dev/shm not mounted\n"); | ||
159 | dbg_test_dir("/dev/shm"); | ||
160 | } | ||
161 | |||
162 | } | ||
163 | } | ||
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c new file mode 100644 index 000000000..853e3930b --- /dev/null +++ b/src/firejail/fs_home.c | |||
@@ -0,0 +1,494 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 <linux/limits.h> | ||
23 | #include <glob.h> | ||
24 | #include <dirent.h> | ||
25 | #include <fcntl.h> | ||
26 | #include <sys/stat.h> | ||
27 | #include <sys/types.h> | ||
28 | #include <sys/wait.h> | ||
29 | #include <unistd.h> | ||
30 | #include <grp.h> | ||
31 | |||
32 | static void skel(const char *homedir, uid_t u, gid_t g) { | ||
33 | char *fname; | ||
34 | // zsh | ||
35 | if (arg_zsh) { | ||
36 | // copy skel files | ||
37 | if (asprintf(&fname, "%s/.zshrc", homedir) == -1) | ||
38 | errExit("asprintf"); | ||
39 | struct stat s; | ||
40 | // don't copy it if we already have the file | ||
41 | if (stat(fname, &s) == 0) | ||
42 | return; | ||
43 | if (stat("/etc/skel/.zshrc", &s) == 0) { | ||
44 | if (copy_file("/etc/skel/.zshrc", fname) == 0) { | ||
45 | if (chown(fname, u, g) == -1) | ||
46 | errExit("chown"); | ||
47 | } | ||
48 | } | ||
49 | else { // | ||
50 | FILE *fp = fopen(fname, "w"); | ||
51 | if (fp) { | ||
52 | fprintf(fp, "\n"); | ||
53 | fclose(fp); | ||
54 | if (chown(fname, u, g) == -1) | ||
55 | errExit("chown"); | ||
56 | if (chmod(fname, S_IRUSR | S_IWUSR) < 0) | ||
57 | errExit("chown"); | ||
58 | } | ||
59 | } | ||
60 | free(fname); | ||
61 | } | ||
62 | // csh | ||
63 | else if (arg_csh) { | ||
64 | // copy skel files | ||
65 | if (asprintf(&fname, "%s/.cshrc", homedir) == -1) | ||
66 | errExit("asprintf"); | ||
67 | struct stat s; | ||
68 | // don't copy it if we already have the file | ||
69 | if (stat(fname, &s) == 0) | ||
70 | return; | ||
71 | if (stat("/etc/skel/.cshrc", &s) == 0) { | ||
72 | if (copy_file("/etc/skel/.cshrc", fname) == 0) { | ||
73 | if (chown(fname, u, g) == -1) | ||
74 | errExit("chown"); | ||
75 | } | ||
76 | } | ||
77 | else { // | ||
78 | /* coverity[toctou] */ | ||
79 | FILE *fp = fopen(fname, "w"); | ||
80 | if (fp) { | ||
81 | fprintf(fp, "\n"); | ||
82 | fclose(fp); | ||
83 | if (chown(fname, u, g) == -1) | ||
84 | errExit("chown"); | ||
85 | if (chmod(fname, S_IRUSR | S_IWUSR) < 0) | ||
86 | errExit("chown"); | ||
87 | } | ||
88 | } | ||
89 | free(fname); | ||
90 | } | ||
91 | // bash etc. | ||
92 | else { | ||
93 | // copy skel files | ||
94 | if (asprintf(&fname, "%s/.bashrc", homedir) == -1) | ||
95 | errExit("asprintf"); | ||
96 | struct stat s; | ||
97 | // don't copy it if we already have the file | ||
98 | if (stat(fname, &s) == 0) | ||
99 | return; | ||
100 | if (stat("/etc/skel/.bashrc", &s) == 0) { | ||
101 | if (copy_file("/etc/skel/.bashrc", fname) == 0) { | ||
102 | /* coverity[toctou] */ | ||
103 | if (chown(fname, u, g) == -1) | ||
104 | errExit("chown"); | ||
105 | } | ||
106 | } | ||
107 | free(fname); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | static int store_xauthority(void) { | ||
112 | // put a copy of .Xauthority in MNT_DIR | ||
113 | fs_build_mnt_dir(); | ||
114 | |||
115 | char *src; | ||
116 | char *dest; | ||
117 | if (asprintf(&src, "%s/.Xauthority", cfg.homedir) == -1) | ||
118 | errExit("asprintf"); | ||
119 | if (asprintf(&dest, "%s/.Xauthority", MNT_DIR) == -1) | ||
120 | errExit("asprintf"); | ||
121 | |||
122 | struct stat s; | ||
123 | if (stat(src, &s) == 0) { | ||
124 | int rv = copy_file(src, dest); | ||
125 | if (rv) { | ||
126 | fprintf(stderr, "Warning: cannot transfer .Xauthority in private home directory\n"); | ||
127 | return 0; | ||
128 | } | ||
129 | return 1; // file copied | ||
130 | } | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | static void copy_xauthority(void) { | ||
136 | // put a copy of .Xauthority in MNT_DIR | ||
137 | fs_build_mnt_dir(); | ||
138 | |||
139 | char *src; | ||
140 | char *dest; | ||
141 | if (asprintf(&dest, "%s/.Xauthority", cfg.homedir) == -1) | ||
142 | errExit("asprintf"); | ||
143 | if (asprintf(&src, "%s/.Xauthority", MNT_DIR) == -1) | ||
144 | errExit("asprintf"); | ||
145 | int rv = copy_file(src, dest); | ||
146 | if (rv) | ||
147 | fprintf(stderr, "Warning: cannot transfer .Xauthority in private home directory\n"); | ||
148 | |||
149 | // set permissions and ownership | ||
150 | if (chown(dest, getuid(), getgid()) < 0) | ||
151 | errExit("chown"); | ||
152 | if (chmod(dest, S_IRUSR | S_IWUSR) < 0) | ||
153 | errExit("chmod"); | ||
154 | |||
155 | // delete the temporary file | ||
156 | unlink(src); | ||
157 | } | ||
158 | |||
159 | // private mode (--private=homedir): | ||
160 | // mount homedir on top of /home/user, | ||
161 | // tmpfs on top of /root in nonroot mode, | ||
162 | // tmpfs on top of /tmp in root mode, | ||
163 | // set skel files, | ||
164 | // restore .Xauthority | ||
165 | void fs_private_homedir(void) { | ||
166 | char *homedir = cfg.homedir; | ||
167 | char *private_homedir = cfg.home_private; | ||
168 | assert(homedir); | ||
169 | assert(private_homedir); | ||
170 | |||
171 | int xflag = store_xauthority(); | ||
172 | |||
173 | uid_t u = getuid(); | ||
174 | gid_t g = getgid(); | ||
175 | struct stat s; | ||
176 | if (stat(homedir, &s) == -1) { | ||
177 | fprintf(stderr, "Error: cannot find user home directory\n"); | ||
178 | exit(1); | ||
179 | } | ||
180 | |||
181 | |||
182 | // mount bind private_homedir on top of homedir | ||
183 | if (arg_debug) | ||
184 | printf("Mount-bind %s on top of %s\n", private_homedir, homedir); | ||
185 | if (mount(private_homedir, homedir, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
186 | errExit("mount bind"); | ||
187 | // preserve mode and ownership | ||
188 | // if (chown(homedir, s.st_uid, s.st_gid) == -1) | ||
189 | // errExit("mount-bind chown"); | ||
190 | // if (chmod(homedir, s.st_mode) == -1) | ||
191 | // errExit("mount-bind chmod"); | ||
192 | |||
193 | if (u != 0) { | ||
194 | // mask /root | ||
195 | if (arg_debug) | ||
196 | printf("Mounting a new /root directory\n"); | ||
197 | if (mount("tmpfs", "/root", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=700,gid=0") < 0) | ||
198 | errExit("mounting home directory"); | ||
199 | } | ||
200 | else { | ||
201 | // mask /home | ||
202 | if (arg_debug) | ||
203 | printf("Mounting a new /home directory\n"); | ||
204 | if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) | ||
205 | errExit("mounting home directory"); | ||
206 | |||
207 | // mask /tmp only in root mode; KDE keeps all kind of sockets in /tmp! | ||
208 | if (arg_debug) | ||
209 | printf("Mounting a new /tmp directory\n"); | ||
210 | if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) | ||
211 | errExit("mounting tmp directory"); | ||
212 | } | ||
213 | |||
214 | |||
215 | skel(homedir, u, g); | ||
216 | if (xflag) | ||
217 | copy_xauthority(); | ||
218 | } | ||
219 | |||
220 | // private mode (--private): | ||
221 | // mount tmpfs over /home/user, | ||
222 | // tmpfs on top of /root in nonroot mode, | ||
223 | // tmpfs on top of /tmp in root mode | ||
224 | // set skel files, | ||
225 | // restore .Xauthority | ||
226 | void fs_private(void) { | ||
227 | char *homedir = cfg.homedir; | ||
228 | assert(homedir); | ||
229 | uid_t u = getuid(); | ||
230 | gid_t g = getgid(); | ||
231 | |||
232 | int xflag = store_xauthority(); | ||
233 | |||
234 | // mask /home | ||
235 | if (arg_debug) | ||
236 | printf("Mounting a new /home directory\n"); | ||
237 | if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) | ||
238 | errExit("mounting home directory"); | ||
239 | |||
240 | // mask /root | ||
241 | if (arg_debug) | ||
242 | printf("Mounting a new /root directory\n"); | ||
243 | if (mount("tmpfs", "/root", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=700,gid=0") < 0) | ||
244 | errExit("mounting home directory"); | ||
245 | |||
246 | if (u != 0) { | ||
247 | // create /home/user | ||
248 | if (arg_debug) | ||
249 | printf("Create a new user directory\n"); | ||
250 | int rv = mkdir(homedir, S_IRWXU); | ||
251 | if (rv == -1) | ||
252 | errExit("mkdir"); | ||
253 | if (chown(homedir, u, g) < 0) | ||
254 | errExit("chown"); | ||
255 | } | ||
256 | else { | ||
257 | // mask tmp only in root mode; KDE keeps all kind of sockets in /tmp! | ||
258 | if (arg_debug) | ||
259 | printf("Mounting a new /tmp directory\n"); | ||
260 | if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) | ||
261 | errExit("mounting tmp directory"); | ||
262 | } | ||
263 | |||
264 | skel(homedir, u, g); | ||
265 | if (xflag) | ||
266 | copy_xauthority(); | ||
267 | } | ||
268 | |||
269 | static void check_dir_or_file(const char *name) { | ||
270 | assert(name); | ||
271 | struct stat s; | ||
272 | char *fname; | ||
273 | if (asprintf(&fname, "%s/%s", cfg.homedir, name) == -1) | ||
274 | errExit("asprintf"); | ||
275 | if (arg_debug) | ||
276 | printf("***************Checking %s\n", fname); | ||
277 | if (stat(fname, &s) == -1) { | ||
278 | fprintf(stderr, "Error: file %s not found.\n", fname); | ||
279 | exit(1); | ||
280 | } | ||
281 | |||
282 | // check uid | ||
283 | uid_t uid = getuid(); | ||
284 | gid_t gid = getgid(); | ||
285 | if (s.st_uid != uid || s.st_gid != gid) { | ||
286 | fprintf(stderr, "Error: only files or directories created by the current user are allowed.\n"); | ||
287 | exit(1); | ||
288 | } | ||
289 | |||
290 | // dir or regular file | ||
291 | if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode)) { | ||
292 | free(fname); | ||
293 | return; | ||
294 | } | ||
295 | |||
296 | if (!is_link(fname)) { | ||
297 | free(fname); | ||
298 | return; | ||
299 | } | ||
300 | |||
301 | fprintf(stderr, "Error: invalid file type, %s.\n", fname); | ||
302 | exit(1); | ||
303 | } | ||
304 | |||
305 | // check directory linst specified by user (--private.keep option) - exit if it fails | ||
306 | void fs_check_home_list(void) { | ||
307 | if (strstr(cfg.home_private_keep, "..")) { | ||
308 | fprintf(stderr, "Error: invalid private.keep list\n"); | ||
309 | exit(1); | ||
310 | } | ||
311 | |||
312 | char *dlist = strdup(cfg.home_private_keep); | ||
313 | if (!dlist) | ||
314 | errExit("strdup"); | ||
315 | |||
316 | char *ptr = strtok(dlist, ","); | ||
317 | check_dir_or_file(ptr); | ||
318 | while ((ptr = strtok(NULL, ",")) != NULL) | ||
319 | check_dir_or_file(ptr); | ||
320 | |||
321 | free(dlist); | ||
322 | } | ||
323 | |||
324 | // check new private home directory (--private= option) - exit if it fails | ||
325 | void fs_check_private_dir(void) { | ||
326 | // if the directory starts with ~, expand the home directory | ||
327 | if (*cfg.home_private == '~') { | ||
328 | char *tmp; | ||
329 | if (asprintf(&tmp, "%s%s", cfg.homedir, cfg.home_private + 1) == -1) | ||
330 | errExit("asprintf"); | ||
331 | cfg.home_private = tmp; | ||
332 | } | ||
333 | |||
334 | if (!is_dir(cfg.home_private) || is_link(cfg.home_private) || strstr(cfg.home_private, "..")) { | ||
335 | fprintf(stderr, "Error: invalid private directory\n"); | ||
336 | exit(1); | ||
337 | } | ||
338 | |||
339 | // check home directory and chroot home directory have the same owner | ||
340 | struct stat s2; | ||
341 | int rv = stat(cfg.home_private, &s2); | ||
342 | if (rv < 0) { | ||
343 | fprintf(stderr, "Error: cannot find %s directory\n", cfg.home_private); | ||
344 | exit(1); | ||
345 | } | ||
346 | |||
347 | struct stat s1; | ||
348 | rv = stat(cfg.homedir, &s1); | ||
349 | if (rv < 0) { | ||
350 | fprintf(stderr, "Error: cannot find %s directory, full path name required\n", cfg.homedir); | ||
351 | exit(1); | ||
352 | } | ||
353 | if (s1.st_uid != s2.st_uid) { | ||
354 | printf("Error: the two home directories must have the same owner\n"); | ||
355 | exit(1); | ||
356 | } | ||
357 | } | ||
358 | |||
359 | #if 0 | ||
360 | static int mkpath(char* file_path, mode_t mode) { | ||
361 | assert(file_path && *file_path); | ||
362 | char* p; | ||
363 | for (p=strchr(file_path+1, '/'); p; p=strchr(p+1, '/')) { | ||
364 | *p='\0'; | ||
365 | if (mkdir(file_path, mode)==-1) { | ||
366 | if (errno!=EEXIST) { *p='/'; return -1; } | ||
367 | } | ||
368 | *p='/'; | ||
369 | } | ||
370 | return 0; | ||
371 | } | ||
372 | #endif | ||
373 | |||
374 | static void duplicate(char *fname) { | ||
375 | char *cmd; | ||
376 | |||
377 | // copy the file | ||
378 | if (asprintf(&cmd, "cp -a --parents %s/%s %s", cfg.homedir, fname, HOME_DIR) == -1) | ||
379 | errExit("asprintf"); | ||
380 | if (arg_debug) | ||
381 | printf("%s\n", cmd); | ||
382 | if (system(cmd)) | ||
383 | errExit("system cp -a --parents"); | ||
384 | free(cmd); | ||
385 | } | ||
386 | |||
387 | |||
388 | // private mode (--private.keep=list): | ||
389 | // mount homedir on top of /home/user, | ||
390 | // tmpfs on top of /root in nonroot mode, | ||
391 | // tmpfs on top of /tmp in root mode, | ||
392 | // set skel files, | ||
393 | // restore .Xauthority | ||
394 | void fs_private_home_list(void) { | ||
395 | char *homedir = cfg.homedir; | ||
396 | char *private_list = cfg.home_private_keep; | ||
397 | assert(homedir); | ||
398 | assert(private_list); | ||
399 | |||
400 | int xflag = store_xauthority(); | ||
401 | |||
402 | uid_t u = getuid(); | ||
403 | gid_t g = getgid(); | ||
404 | struct stat s; | ||
405 | if (stat(homedir, &s) == -1) { | ||
406 | fprintf(stderr, "Error: cannot find user home directory\n"); | ||
407 | exit(1); | ||
408 | } | ||
409 | |||
410 | // create /tmp/firejail/mnt/home directory | ||
411 | fs_build_mnt_dir(); | ||
412 | int rv = mkdir(HOME_DIR, S_IRWXU | S_IRWXG | S_IRWXO); | ||
413 | if (rv == -1) | ||
414 | errExit("mkdir"); | ||
415 | if (chown(HOME_DIR, u, g) < 0) | ||
416 | errExit("chown"); | ||
417 | if (chmod(HOME_DIR, 0755) < 0) | ||
418 | errExit("chmod"); | ||
419 | |||
420 | // copy the list of files in the new home directory | ||
421 | // using a new child process without root privileges | ||
422 | pid_t child = fork(); | ||
423 | if (child < 0) | ||
424 | errExit("fork"); | ||
425 | if (child == 0) { | ||
426 | if (arg_debug) | ||
427 | printf("Copying files in the new home:\n"); | ||
428 | |||
429 | // drop privileges | ||
430 | if (setgroups(0, NULL) < 0) | ||
431 | errExit("setgroups"); | ||
432 | if (setgid(getgid()) < 0) | ||
433 | errExit("setgid/getgid"); | ||
434 | if (setuid(getuid()) < 0) | ||
435 | errExit("setuid/getuid"); | ||
436 | |||
437 | // copy the list of files in the new home directory | ||
438 | char *dlist = strdup(cfg.home_private_keep); | ||
439 | if (!dlist) | ||
440 | errExit("strdup"); | ||
441 | |||
442 | char *ptr = strtok(dlist, ","); | ||
443 | duplicate(ptr); | ||
444 | |||
445 | while ((ptr = strtok(NULL, ",")) != NULL) | ||
446 | duplicate(ptr); | ||
447 | free(dlist); | ||
448 | exit(0); | ||
449 | } | ||
450 | // wait for the child to finish | ||
451 | waitpid(child, NULL, 0); | ||
452 | |||
453 | // mount bind private_homedir on top of homedir | ||
454 | char *newhome; | ||
455 | if (asprintf(&newhome, "%s%s", HOME_DIR, cfg.homedir) == -1) | ||
456 | errExit("asprintf"); | ||
457 | |||
458 | if (arg_debug) | ||
459 | printf("Mount-bind %s on top of %s\n", newhome, homedir); | ||
460 | if (mount(newhome, homedir, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
461 | errExit("mount bind"); | ||
462 | // preserve mode and ownership | ||
463 | // if (chown(homedir, s.st_uid, s.st_gid) == -1) | ||
464 | // errExit("mount-bind chown"); | ||
465 | // if (chmod(homedir, s.st_mode) == -1) | ||
466 | // errExit("mount-bind chmod"); | ||
467 | |||
468 | if (u != 0) { | ||
469 | // mask /root | ||
470 | if (arg_debug) | ||
471 | printf("Mounting a new /root directory\n"); | ||
472 | if (mount("tmpfs", "/root", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=700,gid=0") < 0) | ||
473 | errExit("mounting home directory"); | ||
474 | } | ||
475 | else { | ||
476 | // mask /home | ||
477 | if (arg_debug) | ||
478 | printf("Mounting a new /home directory\n"); | ||
479 | if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) | ||
480 | errExit("mounting home directory"); | ||
481 | |||
482 | // mask /tmp only in root mode; KDE keeps all kind of sockets in /tmp! | ||
483 | if (arg_debug) | ||
484 | printf("Mounting a new /tmp directory\n"); | ||
485 | if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) | ||
486 | errExit("mounting tmp directory"); | ||
487 | } | ||
488 | |||
489 | skel(homedir, u, g); | ||
490 | if (xflag) | ||
491 | copy_xauthority(); | ||
492 | |||
493 | } | ||
494 | |||
diff --git a/src/firejail/fs_hostname.c b/src/firejail/fs_hostname.c new file mode 100644 index 000000000..fb3fc530e --- /dev/null +++ b/src/firejail/fs_hostname.c | |||
@@ -0,0 +1,157 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 | #include <linux/limits.h> | ||
24 | #include <glob.h> | ||
25 | #include <dirent.h> | ||
26 | #include <fcntl.h> | ||
27 | |||
28 | void fs_hostname(const char *hostname) { | ||
29 | struct stat s; | ||
30 | fs_build_mnt_dir(); | ||
31 | |||
32 | // create a new /etc/hostname | ||
33 | if (stat("/etc/hostname", &s) == 0) { | ||
34 | if (arg_debug) | ||
35 | printf("Creating a new /etc/hostname file\n"); | ||
36 | char *fhost; | ||
37 | if (asprintf(&fhost, "%s/hostname", MNT_DIR) == -1) | ||
38 | errExit("asprintf"); | ||
39 | FILE *fp = fopen(fhost, "w"); | ||
40 | if (!fp) { | ||
41 | fprintf(stderr, "Error: cannot create %s\n", fhost); | ||
42 | free(fhost); | ||
43 | exit(1); | ||
44 | } | ||
45 | fprintf(fp, "%s\n", hostname); | ||
46 | fclose(fp); | ||
47 | |||
48 | // mode and owner | ||
49 | if (chown(fhost, 0, 0) < 0) | ||
50 | errExit("chown"); | ||
51 | if (chmod(fhost, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH ) < 0) | ||
52 | errExit("chmod"); | ||
53 | |||
54 | // bind-mount the file on top of /etc/hostname | ||
55 | if (mount(fhost, "/etc/hostname", NULL, MS_BIND|MS_REC, NULL) < 0) | ||
56 | errExit("mount bind /etc/hostname"); | ||
57 | free(fhost); | ||
58 | } | ||
59 | |||
60 | // create a new /etc/hosts | ||
61 | if (stat("/etc/hosts", &s) == 0) { | ||
62 | if (arg_debug) | ||
63 | printf("Creating a new /etc/hosts file\n"); | ||
64 | char *fhost; | ||
65 | if (asprintf(&fhost, "%s/hosts", MNT_DIR) == -1) | ||
66 | errExit("asprintf"); | ||
67 | // copy /etc/host into our new file, and modify it on the fly | ||
68 | /* coverity[toctou] */ | ||
69 | FILE *fp1 = fopen("/etc/hosts", "r"); | ||
70 | if (!fp1) { | ||
71 | fprintf(stderr, "Error: cannot open /etc/hosts\n"); | ||
72 | free(fhost); | ||
73 | exit(1); | ||
74 | } | ||
75 | FILE *fp2 = fopen(fhost, "w"); | ||
76 | if (!fp2) { | ||
77 | fprintf(stderr, "Error: cannot create %s\n", fhost); | ||
78 | free(fhost); | ||
79 | exit(1); | ||
80 | } | ||
81 | |||
82 | char buf[4096]; | ||
83 | while (fgets(buf, sizeof(buf), fp1)) { | ||
84 | // remove '\n' | ||
85 | char *ptr = strchr(buf, '\n'); | ||
86 | if (ptr) | ||
87 | *ptr = '\0'; | ||
88 | |||
89 | // copy line | ||
90 | if (strstr(buf, "127.0.0.1")) | ||
91 | fprintf(fp2, "%s %s\n", buf, hostname); | ||
92 | else | ||
93 | fprintf(fp2, "%s\n", buf); | ||
94 | } | ||
95 | fclose(fp1); | ||
96 | fclose(fp2); | ||
97 | |||
98 | // mode and owner | ||
99 | if (chown(fhost, 0, 0) < 0) | ||
100 | errExit("chown"); | ||
101 | if (chmod(fhost, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH ) < 0) | ||
102 | errExit("chmod"); | ||
103 | |||
104 | // bind-mount the file on top of /etc/hostname | ||
105 | if (mount(fhost, "/etc/hosts", NULL, MS_BIND|MS_REC, NULL) < 0) | ||
106 | errExit("mount bind /etc/hosts"); | ||
107 | free(fhost); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | void fs_resolvconf(void) { | ||
112 | if (cfg.dns1 == 0) | ||
113 | return; | ||
114 | |||
115 | struct stat s; | ||
116 | fs_build_mnt_dir(); | ||
117 | |||
118 | // create a new /etc/hostname | ||
119 | if (stat("/etc/resolv.conf", &s) == 0) { | ||
120 | if (arg_debug) | ||
121 | printf("Creating a new /etc/resolv.conf file\n"); | ||
122 | char *fname; | ||
123 | if (asprintf(&fname, "%s/resolv.conf", MNT_DIR) == -1) | ||
124 | errExit("asprintf"); | ||
125 | FILE *fp = fopen(fname, "w"); | ||
126 | if (!fp) { | ||
127 | fprintf(stderr, "Error: cannot create %s\n", fname); | ||
128 | free(fname); | ||
129 | exit(1); | ||
130 | } | ||
131 | |||
132 | if (cfg.dns1) | ||
133 | fprintf(fp, "nameserver %d.%d.%d.%d\n", PRINT_IP(cfg.dns1)); | ||
134 | if (cfg.dns2) | ||
135 | fprintf(fp, "nameserver %d.%d.%d.%d\n", PRINT_IP(cfg.dns2)); | ||
136 | if (cfg.dns3) | ||
137 | fprintf(fp, "nameserver %d.%d.%d.%d\n", PRINT_IP(cfg.dns3)); | ||
138 | fclose(fp); | ||
139 | |||
140 | // mode and owner | ||
141 | if (chown(fname, 0, 0) < 0) | ||
142 | errExit("chown"); | ||
143 | if (chmod(fname, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH ) < 0) | ||
144 | errExit("chmod"); | ||
145 | |||
146 | // bind-mount the file on top of /etc/hostname | ||
147 | if (mount(fname, "/etc/resolv.conf", NULL, MS_BIND|MS_REC, NULL) < 0) | ||
148 | errExit("mount bind /etc/resolv.conf"); | ||
149 | free(fname); | ||
150 | } | ||
151 | else { | ||
152 | fprintf(stderr, "Error: cannot set DNS servers, /etc/resolv.conf file is missing\n"); | ||
153 | exit(1); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | |||
diff --git a/src/firejail/fs_trace.c b/src/firejail/fs_trace.c new file mode 100644 index 000000000..1c7ef5cbe --- /dev/null +++ b/src/firejail/fs_trace.c | |||
@@ -0,0 +1,76 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 | #include <linux/limits.h> | ||
24 | #include <glob.h> | ||
25 | #include <dirent.h> | ||
26 | #include <fcntl.h> | ||
27 | #include <pwd.h> | ||
28 | |||
29 | void fs_trace_preload(void) { | ||
30 | struct stat s; | ||
31 | |||
32 | // create an empty /etc/ld.so.preload | ||
33 | if (stat("/etc/ld.so.preload", &s)) { | ||
34 | if (arg_debug) | ||
35 | printf("Creating an empty /etc/ld.so.preload file\n"); | ||
36 | /* coverity[toctou] */ | ||
37 | FILE *fp = fopen("/etc/ld.so.preload", "w"); | ||
38 | if (!fp) | ||
39 | errExit("fopen"); | ||
40 | fclose(fp); | ||
41 | if (chown("/etc/ld.so.preload", 0, 0) < 0) | ||
42 | errExit("chown"); | ||
43 | if (chmod("/etc/ld.so.preload", S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH ) < 0) | ||
44 | errExit("chmod"); | ||
45 | } | ||
46 | } | ||
47 | |||
48 | void fs_trace(void) { | ||
49 | // create /tmp/firejail/mnt directory | ||
50 | fs_build_mnt_dir(); | ||
51 | |||
52 | // create the new ld.so.preload file and mount-bind it | ||
53 | if (arg_debug) | ||
54 | printf("Create the new ld.so.preload file\n"); | ||
55 | char *preload; | ||
56 | if (asprintf(&preload, "%s/ld.so.preload", MNT_DIR) == -1) | ||
57 | errExit("asprintf"); | ||
58 | FILE *fp = fopen(preload, "w"); | ||
59 | if (!fp) | ||
60 | errExit("fopen"); | ||
61 | fprintf(fp, "%s/lib/firejail/libtrace.so\n", PREFIX); | ||
62 | fclose(fp); | ||
63 | if (chown(preload, 0, 0) < 0) | ||
64 | errExit("chown"); | ||
65 | if (chmod(preload, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH ) < 0) | ||
66 | errExit("chmod"); | ||
67 | |||
68 | // mount the new preload file | ||
69 | if (arg_debug) | ||
70 | printf("Mount the new ld.so.preload file\n"); | ||
71 | if (mount(preload, "/etc/ld.so.preload", NULL, MS_BIND|MS_REC, NULL) < 0) | ||
72 | errExit("mount bind ls.so.preload"); | ||
73 | } | ||
74 | |||
75 | |||
76 | \ No newline at end of file | ||
diff --git a/src/firejail/fs_var.c b/src/firejail/fs_var.c new file mode 100644 index 000000000..ee0f81828 --- /dev/null +++ b/src/firejail/fs_var.c | |||
@@ -0,0 +1,388 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 | #include <linux/limits.h> | ||
24 | #include <glob.h> | ||
25 | #include <dirent.h> | ||
26 | #include <fcntl.h> | ||
27 | #include <pwd.h> | ||
28 | #include <utmp.h> | ||
29 | #include <time.h> | ||
30 | |||
31 | typedef struct dirdata_t{ | ||
32 | struct dirdata_t *next; | ||
33 | char *name; | ||
34 | mode_t st_mode; | ||
35 | uid_t st_uid; | ||
36 | gid_t st_gid; | ||
37 | } DirData; | ||
38 | |||
39 | static DirData *dirlist = NULL; | ||
40 | |||
41 | static void release_all(void) { | ||
42 | DirData *ptr = dirlist; | ||
43 | while (ptr) { | ||
44 | DirData *next = ptr->next; | ||
45 | free(ptr->name); | ||
46 | free(ptr); | ||
47 | ptr = next; | ||
48 | } | ||
49 | dirlist = NULL; | ||
50 | } | ||
51 | |||
52 | static void build_list(const char *srcdir) { | ||
53 | // extract current /var/log directory data | ||
54 | struct dirent *dir; | ||
55 | DIR *d = opendir(srcdir); | ||
56 | if (d == NULL) | ||
57 | return; | ||
58 | |||
59 | while ((dir = readdir(d))) { | ||
60 | if(strcmp(dir->d_name, "." ) == 0 || strcmp(dir->d_name, ".." ) == 0) | ||
61 | continue; | ||
62 | |||
63 | if (dir->d_type == DT_DIR ) { | ||
64 | // get properties | ||
65 | struct stat s; | ||
66 | char *name; | ||
67 | if (asprintf(&name, "%s/%s", srcdir, dir->d_name) == -1) | ||
68 | continue; | ||
69 | if (stat(name, &s) == -1) | ||
70 | continue; | ||
71 | if (S_ISLNK(s.st_mode)) { | ||
72 | free(name); | ||
73 | continue; | ||
74 | } | ||
75 | |||
76 | // printf("directory %u %u:%u %s\n", | ||
77 | // s.st_mode, | ||
78 | // s.st_uid, | ||
79 | // s.st_gid, | ||
80 | // dir->d_name); | ||
81 | |||
82 | DirData *ptr = malloc(sizeof(DirData)); | ||
83 | if (ptr == NULL) | ||
84 | errExit("malloc"); | ||
85 | memset(ptr, 0, sizeof(DirData)); | ||
86 | ptr->name = name; | ||
87 | ptr->st_mode = s.st_mode; | ||
88 | ptr->st_uid = s.st_uid; | ||
89 | ptr->st_gid = s.st_gid; | ||
90 | ptr->next = dirlist; | ||
91 | dirlist = ptr; | ||
92 | } | ||
93 | } | ||
94 | closedir(d); | ||
95 | } | ||
96 | |||
97 | static void build_dirs(void) { | ||
98 | // create directories under /var/log | ||
99 | DirData *ptr = dirlist; | ||
100 | while (ptr) { | ||
101 | if (mkdir(ptr->name, ptr->st_mode)) | ||
102 | errExit("mkdir"); | ||
103 | if (chown(ptr->name, ptr->st_uid, ptr->st_gid)) | ||
104 | errExit("chown"); | ||
105 | ptr = ptr->next; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | void fs_var_log(void) { | ||
110 | build_list("/var/log"); | ||
111 | |||
112 | // create /var/log if it does't exit | ||
113 | if (is_dir("/var/log")) { | ||
114 | // extract group id for /var/log/wtmp | ||
115 | struct stat s; | ||
116 | gid_t wtmp_group = 0; | ||
117 | if (stat("/var/log/wtmp", &s) == 0) | ||
118 | wtmp_group = s.st_gid; | ||
119 | |||
120 | // mount a tmpfs on top of /var/log | ||
121 | if (arg_debug) | ||
122 | printf("Mounting tmpfs on /var/log\n"); | ||
123 | if (mount("tmpfs", "/var/log", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) | ||
124 | errExit("mounting /var/log"); | ||
125 | |||
126 | build_dirs(); | ||
127 | release_all(); | ||
128 | |||
129 | // create an empty /var/log/wtmp file | ||
130 | /* coverity[toctou] */ | ||
131 | FILE *fp = fopen("/var/log/wtmp", "w"); | ||
132 | if (fp) | ||
133 | fclose(fp); | ||
134 | if (chown("/var/log/wtmp", 0, wtmp_group) < 0) | ||
135 | errExit("chown"); | ||
136 | if (chmod("/var/log/wtmp", S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH ) < 0) | ||
137 | errExit("chmod"); | ||
138 | |||
139 | // create an empty /var/log/btmp file | ||
140 | fp = fopen("/var/log/btmp", "w"); | ||
141 | if (fp) | ||
142 | fclose(fp); | ||
143 | if (chown("/var/log/btmp", 0, wtmp_group) < 0) | ||
144 | errExit("chown"); | ||
145 | if (chmod("/var/log/btmp", S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP) < 0) | ||
146 | errExit("chmod"); | ||
147 | } | ||
148 | else | ||
149 | fprintf(stderr, "Warning: cannot mount tmpfs in top of /var/log\n"); | ||
150 | } | ||
151 | |||
152 | void fs_var_lib(void) { | ||
153 | struct stat s; | ||
154 | |||
155 | // ISC DHCP multiserver | ||
156 | if (stat("/var/lib/dhcp", &s) == 0) { | ||
157 | if (arg_debug) | ||
158 | printf("Mounting tmpfs on /var/lib/dhcp\n"); | ||
159 | if (mount("tmpfs", "/var/lib/dhcp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) | ||
160 | errExit("mounting /var/lib/dhcp"); | ||
161 | |||
162 | // isc dhcp server requires a /var/lib/dhcp/dhcpd.leases file | ||
163 | FILE *fp = fopen("/var/lib/dhcp/dhcpd.leases", "w"); | ||
164 | |||
165 | if (fp) { | ||
166 | fprintf(fp, "\n"); | ||
167 | fclose(fp); | ||
168 | if (chown("/var/lib/dhcp/dhcpd.leases", 0, 0) == -1) | ||
169 | errExit("chown"); | ||
170 | if (chmod("/var/lib/dhcp/dhcpd.leases", S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) | ||
171 | errExit("chmod"); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | // nginx multiserver | ||
176 | if (stat("/var/lib/nginx", &s) == 0) { | ||
177 | if (arg_debug) | ||
178 | printf("Mounting tmpfs on /var/lib/nginx\n"); | ||
179 | if (mount("tmpfs", "/var/lib/nginx", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) | ||
180 | errExit("mounting /var/lib/nginx"); | ||
181 | } | ||
182 | |||
183 | // net-snmp multiserver | ||
184 | if (stat("/var/lib/snmp", &s) == 0) { | ||
185 | if (arg_debug) | ||
186 | printf("Mounting tmpfs on /var/lib/snmp\n"); | ||
187 | if (mount("tmpfs", "/var/lib/snmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) | ||
188 | errExit("mounting /var/lib/snmp"); | ||
189 | } | ||
190 | |||
191 | // this is where sudo remembers its state | ||
192 | if (stat("/var/lib/sudo", &s) == 0) { | ||
193 | if (arg_debug) | ||
194 | printf("Mounting tmpfs on /var/lib/sudo\n"); | ||
195 | if (mount("tmpfs", "/var/lib/sudo", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) | ||
196 | errExit("mounting /var/lib/sudo"); | ||
197 | } | ||
198 | } | ||
199 | |||
200 | void fs_var_cache(void) { | ||
201 | struct stat s; | ||
202 | |||
203 | if (stat("/var/cache/apache2", &s) == 0) { | ||
204 | if (arg_debug) | ||
205 | printf("Mounting tmpfs on /var/cache/apache2\n"); | ||
206 | if (mount("tmpfs", "/var/cache/apache2", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) | ||
207 | errExit("mounting /var/cahce/apache2"); | ||
208 | } | ||
209 | |||
210 | if (stat("/var/cache/lighttpd", &s) == 0) { | ||
211 | if (arg_debug) | ||
212 | printf("Mounting tmpfs on /var/cache/lighttpd\n"); | ||
213 | if (mount("tmpfs", "/var/cache/lighttpd", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) | ||
214 | errExit("mounting /var/cache/lighttpd"); | ||
215 | |||
216 | struct passwd *p = getpwnam("www-data"); | ||
217 | uid_t uid = 0; | ||
218 | gid_t gid = 0; | ||
219 | if (p) { | ||
220 | uid = p->pw_uid; | ||
221 | gid = p->pw_gid; | ||
222 | } | ||
223 | |||
224 | int rv = mkdir("/var/cache/lighttpd/compress", S_IRWXU | S_IRWXG | S_IRWXO); | ||
225 | if (rv == -1) | ||
226 | errExit("mkdir"); | ||
227 | if (chown("/var/cache/lighttpd/compress", uid, gid) < 0) | ||
228 | errExit("chown"); | ||
229 | |||
230 | rv = mkdir("/var/cache/lighttpd/uploads", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); | ||
231 | if (rv == -1) | ||
232 | errExit("mkdir"); | ||
233 | if (chown("/var/cache/lighttpd/uploads", uid, gid) < 0) | ||
234 | errExit("chown"); | ||
235 | } | ||
236 | } | ||
237 | |||
238 | void dbg_test_dir(const char *dir) { | ||
239 | if (arg_debug) { | ||
240 | if (is_dir(dir)) | ||
241 | printf("%s is a directory\n", dir); | ||
242 | if (is_link(dir)) { | ||
243 | char *lnk = get_link(dir); | ||
244 | if (lnk) { | ||
245 | printf("%s is a symbolic link to %s\n", dir, lnk); | ||
246 | free(lnk); | ||
247 | } | ||
248 | } | ||
249 | } | ||
250 | } | ||
251 | |||
252 | |||
253 | void fs_var_lock(void) { | ||
254 | |||
255 | if (is_dir("/var/lock")) { | ||
256 | if (arg_debug) | ||
257 | printf("Mounting tmpfs on /var/lock\n"); | ||
258 | if (mount("tmpfs", "/var/lock", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) | ||
259 | errExit("mounting /lock"); | ||
260 | } | ||
261 | else { | ||
262 | char *lnk = get_link("/var/lock"); | ||
263 | if (lnk) { | ||
264 | // convert a link such as "../shm" into "/shm" | ||
265 | char *lnk2 = lnk; | ||
266 | int cnt = 0; | ||
267 | while (strncmp(lnk2, "../", 3) == 0) { | ||
268 | cnt++; | ||
269 | lnk2 = lnk2 + 3; | ||
270 | } | ||
271 | if (cnt != 0) | ||
272 | lnk2 = lnk + (cnt - 1) * 3 + 2; | ||
273 | |||
274 | if (!is_dir(lnk2)) { | ||
275 | // create directory | ||
276 | if (mkdir(lnk2, S_IRWXU|S_IRWXG|S_IRWXO)) | ||
277 | errExit("mkdir"); | ||
278 | if (chown(lnk2, 0, 0)) | ||
279 | errExit("chown"); | ||
280 | if (chmod(lnk2, S_IRWXU|S_IRWXG|S_IRWXO)) | ||
281 | errExit("chmod"); | ||
282 | } | ||
283 | if (arg_debug) | ||
284 | printf("Mounting tmpfs on %s on behalf of /var/lock\n", lnk2); | ||
285 | if (mount("tmpfs", lnk2, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) | ||
286 | errExit("mounting /var/lock"); | ||
287 | free(lnk); | ||
288 | } | ||
289 | else { | ||
290 | fprintf(stderr, "Warning: /var/lock not mounted\n"); | ||
291 | dbg_test_dir("/var/lock"); | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | |||
296 | void fs_var_tmp(void) { | ||
297 | |||
298 | if (!is_link("/var/tmp")) { | ||
299 | if (arg_debug) | ||
300 | printf("Mounting tmpfs on /var/tmp\n"); | ||
301 | if (mount("tmpfs", "/var/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) | ||
302 | errExit("mounting /var/tmp"); | ||
303 | } | ||
304 | else { | ||
305 | fprintf(stderr, "Warning: /var/tmp not mounted\n"); | ||
306 | dbg_test_dir("/var/tmp"); | ||
307 | } | ||
308 | } | ||
309 | |||
310 | void fs_var_utmp(void) { | ||
311 | struct stat s; | ||
312 | |||
313 | // extract utmp group id | ||
314 | gid_t utmp_group = 0; | ||
315 | if (stat("/var/run/utmp", &s) == 0) | ||
316 | utmp_group = s.st_gid; | ||
317 | else { | ||
318 | fprintf(stderr, "Warning: cannot find /var/run/utmp\n"); | ||
319 | return; | ||
320 | } | ||
321 | |||
322 | // create /tmp/firejail/mnt directory | ||
323 | fs_build_mnt_dir(); | ||
324 | |||
325 | // create a new utmp file | ||
326 | if (arg_debug) | ||
327 | printf("Create the new utmp file\n"); | ||
328 | char *utmp; | ||
329 | if (asprintf(&utmp, "%s/utmp", MNT_DIR) == -1) | ||
330 | errExit("asprintf"); | ||
331 | FILE *fp = fopen(utmp, "w"); | ||
332 | if (!fp) | ||
333 | errExit("fopen"); | ||
334 | |||
335 | // read current utmp | ||
336 | struct utmp *u; | ||
337 | struct utmp u_boot; | ||
338 | setutent(); | ||
339 | while ((u = getutent()) != NULL) { | ||
340 | if (u->ut_type == BOOT_TIME) { | ||
341 | memcpy(&u_boot, u, sizeof(u_boot)); | ||
342 | u_boot.ut_tv.tv_sec = (unsigned) time(NULL); | ||
343 | } | ||
344 | } | ||
345 | endutent(); | ||
346 | |||
347 | // save new utmp file | ||
348 | fwrite(&u_boot, sizeof(u_boot), 1, fp); | ||
349 | fclose(fp); | ||
350 | if (chown(utmp, 0, utmp_group) < 0) | ||
351 | errExit("chown"); | ||
352 | if (chmod(utmp, S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH ) < 0) | ||
353 | errExit("chmod"); | ||
354 | |||
355 | // mount the new utmp file | ||
356 | if (arg_debug) | ||
357 | printf("Mount the new utmp file\n"); | ||
358 | if (mount(utmp, "/var/run/utmp", NULL, MS_BIND|MS_REC, NULL) < 0) | ||
359 | errExit("mount bind utmp"); | ||
360 | } | ||
361 | |||
362 | |||
363 | #if 0 | ||
364 | Testing servers: | ||
365 | |||
366 | brctl addbr br0 | ||
367 | ifconfig br0 10.10.20.1/24 | ||
368 | |||
369 | apt-get install snmpd | ||
370 | insserv -r snmpd | ||
371 | sudo firejail --net=br0 --ip=10.10.20.10 "/etc/init.d/rsyslog start; /etc/init.d/ssh start; /etc/init.d/snmpd start; sleep inf" | ||
372 | |||
373 | apt-get install apache2 | ||
374 | insserv -r apache2 | ||
375 | sudo firejail --net=br0 --ip=10.10.20.10 "/etc/init.d/rsyslog start; /etc/init.d/ssh start; /etc/init.d/apache2 start; sleep inf" | ||
376 | |||
377 | apt-get install nginx | ||
378 | insserv -r nginx | ||
379 | sudo firejail --net=br0 --ip=10.10.20.10 "/etc/init.d/rsyslog start; /etc/init.d/ssh start; /etc/init.d/nginx start; sleep inf" | ||
380 | |||
381 | apt-get install lighttpd | ||
382 | insserv -r lighttpd | ||
383 | sudo firejail --net=br0 --ip=10.10.20.10 "/etc/init.d/rsyslog start; /etc/init.d/ssh start; /etc/init.d/lighttpd start; sleep inf" | ||
384 | |||
385 | apt-get install isc-dhcp-server | ||
386 | insserv -r isc-dhcp-server | ||
387 | sudo firejail --net=br0 --ip=10.10.20.10 "/etc/init.d/rsyslog start; /etc/init.d/ssh start; /etc/init.d/isc-dhcp-server start; sleep inf" | ||
388 | #endif | ||
diff --git a/src/firejail/join.c b/src/firejail/join.c new file mode 100644 index 000000000..e2d2ca7fc --- /dev/null +++ b/src/firejail/join.c | |||
@@ -0,0 +1,364 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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/stat.h> | ||
22 | #include <sys/wait.h> | ||
23 | #include <fcntl.h> | ||
24 | #include <unistd.h> | ||
25 | #include <sys/prctl.h> | ||
26 | |||
27 | static int apply_caps = 0; | ||
28 | static uint64_t caps = 0; | ||
29 | static int apply_seccomp = 0; | ||
30 | #define BUFLEN 4096 | ||
31 | |||
32 | static void extract_command(int argc, char **argv, int index) { | ||
33 | if (index >= argc) | ||
34 | return; | ||
35 | |||
36 | // doubledash followed by positional parameters | ||
37 | if (strcmp(argv[index], "--") == 0) { | ||
38 | arg_doubledash = 1; | ||
39 | index++; | ||
40 | if (index >= argc) | ||
41 | return; | ||
42 | } | ||
43 | |||
44 | // first argv needs to be a valid command | ||
45 | if (arg_doubledash == 0 && *argv[index] == '-') { | ||
46 | fprintf(stderr, "Error: invalid option %s after --join\n", argv[index]); | ||
47 | exit(1); | ||
48 | } | ||
49 | |||
50 | |||
51 | int len = 0; | ||
52 | int i; | ||
53 | // calculate command length | ||
54 | for (i = index; i < argc; i++) { | ||
55 | len += strlen(argv[i]) + 1; | ||
56 | } | ||
57 | assert(len > 0); | ||
58 | |||
59 | // build command | ||
60 | cfg.command_line = malloc(len + 1); | ||
61 | *cfg.command_line = '\0'; | ||
62 | for (i = index; i < argc; i++) { | ||
63 | strcat(cfg.command_line, argv[i]); | ||
64 | strcat(cfg.command_line, " "); | ||
65 | } | ||
66 | if (arg_debug) | ||
67 | printf("Extracted command #%s#\n", cfg.command_line); | ||
68 | } | ||
69 | |||
70 | static void extract_nogroups(pid_t pid) { | ||
71 | char *fname; | ||
72 | if (asprintf(&fname, "/proc/%d/root%s/groups", pid, MNT_DIR) == -1) | ||
73 | errExit("asprintf"); | ||
74 | |||
75 | struct stat s; | ||
76 | if (stat(fname, &s) == -1) | ||
77 | return; | ||
78 | |||
79 | arg_nogroups = 1; | ||
80 | free(fname); | ||
81 | } | ||
82 | |||
83 | static void extract_cpu(pid_t pid) { | ||
84 | char *fname; | ||
85 | if (asprintf(&fname, "/proc/%d/root%s/cpu", pid, MNT_DIR) == -1) | ||
86 | errExit("asprintf"); | ||
87 | |||
88 | struct stat s; | ||
89 | if (stat(fname, &s) == -1) | ||
90 | return; | ||
91 | |||
92 | // there is a cpu file in MNT_DIR; load the information from the file | ||
93 | load_cpu(fname); | ||
94 | free(fname); | ||
95 | } | ||
96 | |||
97 | static void extract_cgroup(pid_t pid) { | ||
98 | char *fname; | ||
99 | if (asprintf(&fname, "/proc/%d/root%s/cgroup", pid, MNT_DIR) == -1) | ||
100 | errExit("asprintf"); | ||
101 | |||
102 | struct stat s; | ||
103 | if (stat(fname, &s) == -1) | ||
104 | return; | ||
105 | |||
106 | // there is a cgroup file in MNT_DIR; load the information from the file | ||
107 | load_cgroup(fname); | ||
108 | free(fname); | ||
109 | } | ||
110 | |||
111 | static void extract_caps_seccomp(pid_t pid) { | ||
112 | // open stat file | ||
113 | char *file; | ||
114 | if (asprintf(&file, "/proc/%u/status", pid) == -1) { | ||
115 | perror("asprintf"); | ||
116 | exit(1); | ||
117 | } | ||
118 | FILE *fp = fopen(file, "r"); | ||
119 | if (!fp) { | ||
120 | free(file); | ||
121 | fprintf(stderr, "Error: cannot open stat file for process %u\n", pid); | ||
122 | exit(1); | ||
123 | } | ||
124 | |||
125 | char buf[BUFLEN]; | ||
126 | while (fgets(buf, BUFLEN - 1, fp)) { | ||
127 | if (strncmp(buf, "Seccomp:", 8) == 0) { | ||
128 | char *ptr = buf + 8; | ||
129 | int val; | ||
130 | sscanf(ptr, "%d", &val); | ||
131 | if (val == 2) | ||
132 | apply_seccomp = 1; | ||
133 | break; | ||
134 | } | ||
135 | else if (strncmp(buf, "CapBnd:", 7) == 0) { | ||
136 | char *ptr = buf + 8; | ||
137 | unsigned long long val; | ||
138 | sscanf(ptr, "%llx", &val); | ||
139 | apply_caps = 1; | ||
140 | caps = val; | ||
141 | } | ||
142 | } | ||
143 | fclose(fp); | ||
144 | free(file); | ||
145 | } | ||
146 | |||
147 | void extract_user_namespace(pid_t pid) { | ||
148 | // test user namespaces available in the kernel | ||
149 | struct stat s1; | ||
150 | struct stat s2; | ||
151 | struct stat s3; | ||
152 | if (stat("/proc/self/ns/user", &s1) == 0 && | ||
153 | stat("/proc/self/uid_map", &s2) == 0 && | ||
154 | stat("/proc/self/gid_map", &s3) == 0); | ||
155 | else | ||
156 | return; | ||
157 | |||
158 | // read uid map | ||
159 | char *uidmap; | ||
160 | if (asprintf(&uidmap, "/proc/%u/uid_map", pid) == -1) | ||
161 | errExit("asprintf"); | ||
162 | FILE *fp = fopen(uidmap, "r"); | ||
163 | if (!fp) { | ||
164 | free(uidmap); | ||
165 | return; | ||
166 | } | ||
167 | |||
168 | // check uid map | ||
169 | int u1; | ||
170 | int u2; | ||
171 | if (fscanf(fp, "%d %d", &u1, &u2) == 2) { | ||
172 | if (arg_debug) | ||
173 | printf("User namespace detected: %s, %d, %d\n", uidmap, u1, u2); | ||
174 | if (u1 != 0 || u2 != 0) | ||
175 | arg_noroot = 1; | ||
176 | } | ||
177 | fclose(fp); | ||
178 | free(uidmap); | ||
179 | } | ||
180 | |||
181 | void join_name(const char *name, const char *homedir, int argc, char **argv, int index) { | ||
182 | if (!name || strlen(name) == 0) { | ||
183 | fprintf(stderr, "Error: invalid sandbox name\n"); | ||
184 | exit(1); | ||
185 | } | ||
186 | pid_t pid; | ||
187 | if (name2pid(name, &pid)) { | ||
188 | fprintf(stderr, "Error: cannot find sandbox %s\n", name); | ||
189 | exit(1); | ||
190 | } | ||
191 | |||
192 | join(pid, homedir, argc, argv, index); | ||
193 | } | ||
194 | |||
195 | void join(pid_t pid, const char *homedir, int argc, char **argv, int index) { | ||
196 | extract_command(argc, argv, index); | ||
197 | |||
198 | // if the pid is that of a firejail process, use the pid of the first child process | ||
199 | char *comm = pid_proc_comm(pid); | ||
200 | if (comm) { | ||
201 | // remove \n | ||
202 | char *ptr = strchr(comm, '\n'); | ||
203 | if (ptr) | ||
204 | *ptr = '\0'; | ||
205 | if (strcmp(comm, "firejail") == 0) { | ||
206 | pid_t child; | ||
207 | if (find_child(pid, &child) == 0) { | ||
208 | pid = child; | ||
209 | printf("Switching to pid %u, the first child process inside the sandbox\n", (unsigned) pid); | ||
210 | } | ||
211 | } | ||
212 | free(comm); | ||
213 | } | ||
214 | |||
215 | // check privileges for non-root users | ||
216 | uid_t uid = getuid(); | ||
217 | if (uid != 0) { | ||
218 | struct stat s; | ||
219 | char *dir; | ||
220 | if (asprintf(&dir, "/proc/%u/ns", pid) == -1) | ||
221 | errExit("asprintf"); | ||
222 | if (stat(dir, &s) < 0) | ||
223 | errExit("stat"); | ||
224 | if (s.st_uid != uid) { | ||
225 | fprintf(stderr, "Error: permission is denied to join a sandbox created by a different user.\n"); | ||
226 | exit(1); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | // in user mode set caps seccomp, cpu, cgroup, etc | ||
231 | if (getuid() != 0) { | ||
232 | extract_caps_seccomp(pid); | ||
233 | extract_cpu(pid); | ||
234 | extract_cgroup(pid); | ||
235 | extract_nogroups(pid); | ||
236 | extract_user_namespace(pid); | ||
237 | } | ||
238 | |||
239 | // set cgroup | ||
240 | if (cfg.cgroup) | ||
241 | set_cgroup(cfg.cgroup); | ||
242 | |||
243 | // join namespaces | ||
244 | if (join_namespace(pid, "ipc")) | ||
245 | exit(1); | ||
246 | if (join_namespace(pid, "net")) | ||
247 | exit(1); | ||
248 | if (join_namespace(pid, "pid")) | ||
249 | exit(1); | ||
250 | if (join_namespace(pid, "uts")) | ||
251 | exit(1); | ||
252 | if (join_namespace(pid, "mnt")) | ||
253 | exit(1); | ||
254 | |||
255 | pid_t child = fork(); | ||
256 | if (child < 0) | ||
257 | errExit("fork"); | ||
258 | if (child == 0) { | ||
259 | // chroot into /proc/PID/root directory | ||
260 | char *rootdir; | ||
261 | if (asprintf(&rootdir, "/proc/%d/root", pid) == -1) | ||
262 | errExit("asprintf"); | ||
263 | |||
264 | int rv = chroot(rootdir); // this will fail for processes in sandboxes not started with --chroot option | ||
265 | if (rv == 0) | ||
266 | printf("changing root to %s\n", rootdir); | ||
267 | |||
268 | prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); // kill the child in case the parent died | ||
269 | if (chdir("/") < 0) | ||
270 | errExit("chdir"); | ||
271 | if (homedir) { | ||
272 | struct stat s; | ||
273 | if (stat(homedir, &s) == 0) { | ||
274 | /* coverity[toctou] */ | ||
275 | if (chdir(homedir) < 0) | ||
276 | errExit("chdir"); | ||
277 | } | ||
278 | } | ||
279 | |||
280 | // set cpu affinity | ||
281 | if (cfg.cpus) | ||
282 | set_cpu_affinity(); | ||
283 | |||
284 | // set caps filter | ||
285 | if (apply_caps == 1) | ||
286 | caps_set(caps); | ||
287 | #ifdef HAVE_SECCOMP | ||
288 | // set seccomp filter | ||
289 | if (apply_seccomp == 1) | ||
290 | seccomp_set(); | ||
291 | #endif | ||
292 | |||
293 | // fix qt 4.8 | ||
294 | if (setenv("QT_X11_NO_MITSHM", "1", 1) < 0) | ||
295 | errExit("setenv"); | ||
296 | if (setenv("container", "firejail", 1) < 0) // LXC sets container=lxc, | ||
297 | errExit("setenv"); | ||
298 | |||
299 | // mount user namespace or drop privileges | ||
300 | if (arg_noroot) { | ||
301 | if (arg_debug) | ||
302 | printf("Joining user namespace\n"); | ||
303 | if (join_namespace(1, "user")) | ||
304 | exit(1); | ||
305 | } | ||
306 | else | ||
307 | drop_privs(arg_nogroups); | ||
308 | |||
309 | // set prompt color to green | ||
310 | //export PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\] ' | ||
311 | if (setenv("PROMPT_COMMAND", "export PS1=\"\\[\\e[1;32m\\][\\u@\\h \\W]\\$\\[\\e[0m\\] \"", 1) < 0) | ||
312 | errExit("setenv"); | ||
313 | |||
314 | // run icmdline trough /bin/bash | ||
315 | if (cfg.command_line == NULL) | ||
316 | // replace the process with a regular bash session | ||
317 | execlp("/bin/bash", "/bin/bash", NULL); | ||
318 | else { | ||
319 | // run the command supplied by the user | ||
320 | int cwd = 0; | ||
321 | if (cfg.cwd) { | ||
322 | if (chdir(cfg.cwd) == 0) | ||
323 | cwd = 1; | ||
324 | } | ||
325 | |||
326 | if (!cwd) { | ||
327 | if (chdir("/") < 0) | ||
328 | errExit("chdir"); | ||
329 | if (cfg.homedir) { | ||
330 | struct stat s; | ||
331 | if (stat(cfg.homedir, &s) == 0) { | ||
332 | if (chdir(cfg.homedir) < 0) | ||
333 | errExit("chdir"); | ||
334 | } | ||
335 | } | ||
336 | } | ||
337 | |||
338 | char *arg[5]; | ||
339 | arg[0] = "/bin/bash"; | ||
340 | arg[1] = "-c"; | ||
341 | if (arg_debug) | ||
342 | printf("Starting %s\n", cfg.command_line); | ||
343 | if (!arg_doubledash) { | ||
344 | arg[2] = cfg.command_line; | ||
345 | arg[3] = NULL; | ||
346 | } | ||
347 | else { | ||
348 | arg[2] = "--"; | ||
349 | arg[3] = cfg.command_line; | ||
350 | arg[4] = NULL; | ||
351 | } | ||
352 | execvp("/bin/bash", arg); | ||
353 | } | ||
354 | |||
355 | // it will never get here!!! | ||
356 | } | ||
357 | |||
358 | // wait for the child to finish | ||
359 | waitpid(child, NULL, 0); | ||
360 | exit(0); | ||
361 | } | ||
362 | |||
363 | |||
364 | |||
diff --git a/src/firejail/list.c b/src/firejail/list.c new file mode 100644 index 000000000..c2c4e801f --- /dev/null +++ b/src/firejail/list.c | |||
@@ -0,0 +1,65 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 | |||
22 | void top(void) { | ||
23 | drop_privs(1); | ||
24 | |||
25 | char *arg[4]; | ||
26 | arg[0] = "bash"; | ||
27 | arg[1] = "-c"; | ||
28 | arg[2] = "firemon --top"; | ||
29 | arg[3] = NULL; | ||
30 | execvp("/bin/bash", arg); | ||
31 | } | ||
32 | |||
33 | void netstats(void) { | ||
34 | drop_privs(1); | ||
35 | |||
36 | char *arg[4]; | ||
37 | arg[0] = "bash"; | ||
38 | arg[1] = "-c"; | ||
39 | arg[2] = "firemon --netstats"; | ||
40 | arg[3] = NULL; | ||
41 | execvp("/bin/bash", arg); | ||
42 | } | ||
43 | |||
44 | void list(void) { | ||
45 | drop_privs(1); | ||
46 | |||
47 | char *arg[4]; | ||
48 | arg[0] = "bash"; | ||
49 | arg[1] = "-c"; | ||
50 | arg[2] = "firemon --list"; | ||
51 | arg[3] = NULL; | ||
52 | execvp("/bin/bash", arg); | ||
53 | } | ||
54 | |||
55 | void tree(void) { | ||
56 | drop_privs(1); | ||
57 | |||
58 | char *arg[4]; | ||
59 | arg[0] = "bash"; | ||
60 | arg[1] = "-c"; | ||
61 | arg[2] = "firemon --tree"; | ||
62 | arg[3] = NULL; | ||
63 | execvp("/bin/bash", arg); | ||
64 | } | ||
65 | |||
diff --git a/src/firejail/main.c b/src/firejail/main.c new file mode 100644 index 000000000..78971aa86 --- /dev/null +++ b/src/firejail/main.c | |||
@@ -0,0 +1,1168 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 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 "../include/pid.h" | ||
22 | #define _GNU_SOURCE | ||
23 | #include <sys/utsname.h> | ||
24 | #include <sched.h> | ||
25 | #include <sys/mount.h> | ||
26 | #include <sys/wait.h> | ||
27 | #include <sys/stat.h> | ||
28 | #include <fcntl.h> | ||
29 | #include <dirent.h> | ||
30 | #include <pwd.h> | ||
31 | #include <errno.h> | ||
32 | #include <limits.h> | ||
33 | #include <sys/file.h> | ||
34 | #include <sys/prctl.h> | ||
35 | #include <signal.h> | ||
36 | #include <time.h> | ||
37 | #include <net/if.h> | ||
38 | |||
39 | #if 0 | ||
40 | #include <sys/times.h> | ||
41 | { | ||
42 | struct tms tm; | ||
43 | clock_t systick = times(&tm); | ||
44 | printf("time %s:%d %u\n", __FILE__, __LINE__, (uint32_t) systick); | ||
45 | } | ||
46 | #endif | ||
47 | |||
48 | #define STACK_SIZE (1024 * 1024) | ||
49 | static char child_stack[STACK_SIZE]; // space for child's stack | ||
50 | Config cfg; // configuration | ||
51 | int arg_private = 0; // mount private /home and /tmp directoryu | ||
52 | int arg_debug = 0; // print debug messages | ||
53 | int arg_nonetwork = 0; // --net=none | ||
54 | int arg_command = 0; // -c | ||
55 | int arg_overlay = 0; // --overlay | ||
56 | int arg_zsh = 0; // use zsh as default shell | ||
57 | int arg_csh = 0; // use csh as default shell | ||
58 | |||
59 | int arg_seccomp = 0; // enable default seccomp filter | ||
60 | char *arg_seccomp_list = NULL; // optional seccomp list on top of default filter | ||
61 | char *arg_seccomp_list_drop = NULL; // seccomp drop list | ||
62 | char *arg_seccomp_list_keep = NULL; // seccomp keep list | ||
63 | |||
64 | int arg_caps_default_filter = 0; // enable default capabilities filter | ||
65 | int arg_caps_drop = 0; // drop list | ||
66 | int arg_caps_drop_all = 0; // drop all capabilities | ||
67 | int arg_caps_keep = 0; // keep list | ||
68 | char *arg_caps_list = NULL; // optional caps list | ||
69 | |||
70 | int arg_trace = 0; // syscall tracing support | ||
71 | int arg_rlimit_nofile = 0; // rlimit nofile | ||
72 | int arg_rlimit_nproc = 0; // rlimit nproc | ||
73 | int arg_rlimit_fsize = 0; // rlimit fsize | ||
74 | int arg_rlimit_sigpending = 0; // rlimit fsize | ||
75 | int arg_nox11 = 0; // kill the program if x11 unix domain socket is accessed | ||
76 | int arg_nodbus = 0; // kill the program if D-Bus is accessed | ||
77 | int arg_nogroups = 0; // disable supplementary groups | ||
78 | int arg_noroot = 0; // create a new user namespace and disable root user | ||
79 | int arg_netfilter; // enable netfilter | ||
80 | char *arg_netfilter_file = NULL; // netfilter file | ||
81 | int arg_doubledash = 0; // double dash | ||
82 | int arg_shell_none = 0; // run the program directly without a shell | ||
83 | int arg_private_dev = 0; // private dev directory | ||
84 | int arg_scan = 0; // arp-scan all interfaces | ||
85 | |||
86 | int parent_to_child_fds[2]; | ||
87 | int child_to_parent_fds[2]; | ||
88 | |||
89 | char *fullargv[MAX_ARGS]; // expanded argv for restricted shell | ||
90 | int fullargc = 0; | ||
91 | static pid_t child = 0; | ||
92 | pid_t sandbox_pid; | ||
93 | |||
94 | static void myexit(int rv) { | ||
95 | logmsg("exiting..."); | ||
96 | if (!arg_command) | ||
97 | printf("\nparent is shutting down, bye...\n"); | ||
98 | |||
99 | struct stat s; | ||
100 | if (stat("/proc/firejail", &s) == 0) { | ||
101 | /* coverity[toctou] */ | ||
102 | FILE *fp = fopen("/proc/firejail", "w"); | ||
103 | if (fp) { | ||
104 | // deregistration | ||
105 | fprintf(fp, "release\n"); | ||
106 | fflush(0); | ||
107 | fclose(fp); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | // delete sandbox files in shared memory | ||
112 | bandwidth_shm_del_file(sandbox_pid); // bandwidht file | ||
113 | network_shm_del_file(sandbox_pid); // network map file | ||
114 | |||
115 | exit(rv); | ||
116 | } | ||
117 | |||
118 | static void my_handler(int s){ | ||
119 | printf("\nSignal %d caught, shutting down the child process\n", s); | ||
120 | logsignal(s); | ||
121 | kill(child, SIGKILL); | ||
122 | myexit(1); | ||
123 | } | ||
124 | |||
125 | static void extract_user_data(void) { | ||
126 | // check suid | ||
127 | if (geteuid()) { | ||
128 | fprintf(stderr, "Error: the sandbox is not setuid root\n"); | ||
129 | exit(1); | ||
130 | } | ||
131 | |||
132 | struct passwd *pw = getpwuid(getuid()); | ||
133 | if (!pw) | ||
134 | errExit("getpwuid"); | ||
135 | cfg.username = strdup(pw->pw_name); | ||
136 | if (!cfg.username) | ||
137 | errExit("strdup"); | ||
138 | |||
139 | // build home directory name | ||
140 | cfg.homedir = NULL; | ||
141 | if (pw->pw_dir != NULL) { | ||
142 | cfg.homedir = strdup(pw->pw_dir); | ||
143 | if (!cfg.homedir) | ||
144 | errExit("strdup"); | ||
145 | } | ||
146 | else { | ||
147 | fprintf(stderr, "Error: user %s doesn't have a user directory assigned\n", cfg.username); | ||
148 | exit(1); | ||
149 | } | ||
150 | |||
151 | cfg.cwd = getcwd(NULL, 0); | ||
152 | } | ||
153 | |||
154 | |||
155 | |||
156 | |||
157 | static inline Bridge *last_bridge_configured(void) { | ||
158 | if (cfg.bridge3.configured) | ||
159 | return &cfg.bridge3; | ||
160 | else if (cfg.bridge2.configured) | ||
161 | return &cfg.bridge2; | ||
162 | else if (cfg.bridge1.configured) | ||
163 | return &cfg.bridge1; | ||
164 | else if (cfg.bridge0.configured) | ||
165 | return &cfg.bridge0; | ||
166 | else | ||
167 | return NULL; | ||
168 | } | ||
169 | |||
170 | |||
171 | |||
172 | // return 1 if error, 0 if a valid pid was found | ||
173 | static int read_pid(char *str, pid_t *pid) { | ||
174 | char *endptr; | ||
175 | errno = 0; | ||
176 | pid_t pidtmp = strtol(str, &endptr, 10); | ||
177 | if ((errno == ERANGE && (pidtmp == LONG_MAX || pidtmp == LONG_MIN)) | ||
178 | || (errno != 0 && pidtmp == 0)) { | ||
179 | return 1; | ||
180 | } | ||
181 | if (endptr == str) { | ||
182 | return 1; | ||
183 | } | ||
184 | *pid = pidtmp; | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static void init_cfg(void) { | ||
189 | memset(&cfg, 0, sizeof(cfg)); | ||
190 | |||
191 | cfg.bridge0.devsandbox = "eth0"; | ||
192 | cfg.bridge1.devsandbox = "eth1"; | ||
193 | cfg.bridge2.devsandbox = "eth2"; | ||
194 | cfg.bridge3.devsandbox = "eth3"; | ||
195 | |||
196 | extract_user_data(); | ||
197 | } | ||
198 | |||
199 | static void check_network(Bridge *br) { | ||
200 | assert(br); | ||
201 | if (br->macvlan == 0) // for bridge devices check network range or arp-scan and assign address | ||
202 | net_configure_sandbox_ip(br); | ||
203 | else if (br->ipsandbox) { // for macvlan check network range | ||
204 | char *rv = in_netrange(br->ipsandbox, br->ip, br->mask); | ||
205 | if (rv) { | ||
206 | fprintf(stderr, "%s", rv); | ||
207 | exit(1); | ||
208 | } | ||
209 | } | ||
210 | } | ||
211 | |||
212 | |||
213 | void check_user_namespace(void) { | ||
214 | if (getuid() == 0) { | ||
215 | fprintf(stderr, "Error: --noroot option cannot be used when starting the sandbox as root.\n"); | ||
216 | exit(1); | ||
217 | } | ||
218 | |||
219 | // test user namespaces available in the kernel | ||
220 | struct stat s1; | ||
221 | struct stat s2; | ||
222 | struct stat s3; | ||
223 | if (stat("/proc/self/ns/user", &s1) == 0 && | ||
224 | stat("/proc/self/uid_map", &s2) == 0 && | ||
225 | stat("/proc/self/gid_map", &s3) == 0) | ||
226 | arg_noroot = 1; | ||
227 | else { | ||
228 | fprintf(stderr, "Warning: user namespaces not available in the current kernel.\n"); | ||
229 | arg_noroot = 0; | ||
230 | } | ||
231 | } | ||
232 | |||
233 | //******************************************* | ||
234 | // Main program | ||
235 | //******************************************* | ||
236 | int main(int argc, char **argv) { | ||
237 | int i; | ||
238 | int prog_index = -1; // index in argv where the program command starts | ||
239 | int lockfd = -1; | ||
240 | int arg_ipc = 0; | ||
241 | int arg_cgroup = 0; | ||
242 | int custom_profile = 0; // custom profile loaded | ||
243 | |||
244 | // initialize globals | ||
245 | init_cfg(); | ||
246 | cfg.original_argv = argv; | ||
247 | cfg.original_argc = argc; | ||
248 | |||
249 | |||
250 | // initialize random number generator | ||
251 | sandbox_pid = getpid(); | ||
252 | time_t t = time(NULL); | ||
253 | srand(t ^ sandbox_pid); | ||
254 | |||
255 | // check firejail directories | ||
256 | fs_build_firejail_dir(); | ||
257 | shm_create_firejail_dir(); | ||
258 | bandwidth_shm_del_file(sandbox_pid); | ||
259 | |||
260 | // is this a login shell? | ||
261 | if (*argv[0] == '-') { | ||
262 | fullargc = restricted_shell(cfg.username); | ||
263 | if (fullargc) { | ||
264 | int j; | ||
265 | for (i = 1, j = fullargc; i < argc && j < MAX_ARGS; i++, j++, fullargc++) | ||
266 | fullargv[j] = argv[i]; | ||
267 | |||
268 | // replace argc/argv with fullargc/fullargv | ||
269 | argv = fullargv; | ||
270 | argc = j; | ||
271 | } | ||
272 | } | ||
273 | else { | ||
274 | // check --output option and execute it; | ||
275 | check_output(argc, argv); // the function will not return if --output option was found | ||
276 | } | ||
277 | |||
278 | // parse arguments | ||
279 | for (i = 1; i < argc; i++) { | ||
280 | //************************************* | ||
281 | // basic arguments | ||
282 | //************************************* | ||
283 | if (strcmp(argv[i], "--help") == 0 || | ||
284 | strcmp(argv[i], "-?") == 0) { | ||
285 | usage(); | ||
286 | exit(0); | ||
287 | } | ||
288 | else if (strcmp(argv[i], "--version") == 0) { | ||
289 | printf("firejail version %s\n", VERSION); | ||
290 | exit(0); | ||
291 | } | ||
292 | else if (strcmp(argv[i], "--debug") == 0) | ||
293 | arg_debug = 1; | ||
294 | |||
295 | else if (strncmp(argv[i], "--bandwidth=", 12) == 0) { | ||
296 | logargs(argc, argv); | ||
297 | |||
298 | // extract the command | ||
299 | if ((i + 1) == argc) { | ||
300 | fprintf(stderr, "Error: command expected after --bandwidth option\n"); | ||
301 | exit(1); | ||
302 | } | ||
303 | char *cmd = argv[i + 1]; | ||
304 | if (strcmp(cmd, "status") && strcmp(cmd, "clear") && strcmp(cmd, "set")) { | ||
305 | fprintf(stderr, "Error: invalid --bandwidth command\n"); | ||
306 | exit(1); | ||
307 | } | ||
308 | |||
309 | // extract network name | ||
310 | char *dev = NULL; | ||
311 | int down = 0; | ||
312 | int up = 0; | ||
313 | if (strcmp(cmd, "set") == 0 || strcmp(cmd, "clear") == 0) { | ||
314 | // extract device name | ||
315 | if ((i + 2) == argc) { | ||
316 | fprintf(stderr, "Error: network name expected after --bandwidth %s option\n", cmd); | ||
317 | exit(1); | ||
318 | } | ||
319 | dev = argv[i + 2]; | ||
320 | |||
321 | // check device name | ||
322 | if (if_nametoindex(dev) == 0) { | ||
323 | fprintf(stderr, "Error: network device %s not found\n", dev); | ||
324 | exit(1); | ||
325 | } | ||
326 | |||
327 | // extract bandwidth | ||
328 | if (strcmp(cmd, "set") == 0) { | ||
329 | if ((i + 4) >= argc) { | ||
330 | fprintf(stderr, "Error: invalid --bandwidth set command\n"); | ||
331 | exit(1); | ||
332 | } | ||
333 | |||
334 | down = atoi(argv[i + 3]); | ||
335 | if (down < 0) { | ||
336 | fprintf(stderr, "Error: invalid download speed\n"); | ||
337 | exit(1); | ||
338 | } | ||
339 | up = atoi(argv[i + 4]); | ||
340 | if (up < 0) { | ||
341 | fprintf(stderr, "Error: invalid upload speed\n"); | ||
342 | exit(1); | ||
343 | } | ||
344 | } | ||
345 | } | ||
346 | |||
347 | // extract pid or sandbox name | ||
348 | pid_t pid; | ||
349 | if (read_pid(argv[i] + 12, &pid) == 0) | ||
350 | bandwidth_pid(pid, cmd, dev, down, up); | ||
351 | else | ||
352 | bandwidth_name(argv[i] + 12, cmd, dev, down, up); | ||
353 | |||
354 | // it will never get here | ||
355 | exit(0); | ||
356 | } | ||
357 | |||
358 | //************************************* | ||
359 | // independent commands - the program will exit! | ||
360 | //************************************* | ||
361 | #ifdef HAVE_SECCOMP | ||
362 | else if (strcmp(argv[i], "--debug-syscalls") == 0) { | ||
363 | syscall_print(); | ||
364 | exit(0); | ||
365 | } | ||
366 | else if (strncmp(argv[i], "--seccomp.print=", 16) == 0) { | ||
367 | // join sandbox by pid or by name | ||
368 | pid_t pid; | ||
369 | if (read_pid(argv[i] + 16, &pid) == 0) | ||
370 | seccomp_print_filter(pid); | ||
371 | else | ||
372 | seccomp_print_filter_name(argv[i] + 16); | ||
373 | |||
374 | // it will never get here!!! | ||
375 | exit(0); | ||
376 | } | ||
377 | #endif | ||
378 | else if (strncmp(argv[i], "--caps.print=", 13) == 0) { | ||
379 | // join sandbox by pid or by name | ||
380 | pid_t pid; | ||
381 | if (read_pid(argv[i] + 13, &pid) == 0) | ||
382 | caps_print_filter(pid); | ||
383 | else | ||
384 | caps_print_filter_name(argv[i] + 13); | ||
385 | |||
386 | // it will never get here!!! | ||
387 | exit(0); | ||
388 | } | ||
389 | |||
390 | else if (strncmp(argv[i], "--dns.print=", 12) == 0) { | ||
391 | // join sandbox by pid or by name | ||
392 | pid_t pid; | ||
393 | if (read_pid(argv[i] + 12, &pid) == 0) | ||
394 | net_dns_print(pid); | ||
395 | else | ||
396 | net_dns_print_name(argv[i] + 12); | ||
397 | |||
398 | // it will never get here!!! | ||
399 | exit(0); | ||
400 | } | ||
401 | else if (strcmp(argv[i], "--debug-caps") == 0) { | ||
402 | caps_print(); | ||
403 | exit(0); | ||
404 | } | ||
405 | else if (strcmp(argv[i], "--list") == 0) { | ||
406 | list(); | ||
407 | exit(0); | ||
408 | } | ||
409 | else if (strcmp(argv[i], "--tree") == 0) { | ||
410 | tree(); | ||
411 | exit(0); | ||
412 | } | ||
413 | else if (strcmp(argv[i], "--top") == 0) { | ||
414 | top(); | ||
415 | exit(0); | ||
416 | } | ||
417 | else if (strcmp(argv[i], "--netstats") == 0) { | ||
418 | netstats(); | ||
419 | exit(0); | ||
420 | } | ||
421 | else if (strncmp(argv[i], "--join=", 7) == 0) { | ||
422 | logargs(argc, argv); | ||
423 | |||
424 | // join sandbox by pid or by name | ||
425 | pid_t pid; | ||
426 | if (read_pid(argv[i] + 7, &pid) == 0) | ||
427 | join(pid, cfg.homedir, argc, argv, i + 1); | ||
428 | else | ||
429 | join_name(argv[i] + 7, cfg.homedir, argc, argv, i + 1); | ||
430 | |||
431 | // it will never get here!!! | ||
432 | exit(0); | ||
433 | } | ||
434 | else if (strncmp(argv[i], "--shutdown=", 11) == 0) { | ||
435 | logargs(argc, argv); | ||
436 | |||
437 | // shutdown sandbox by pid or by name | ||
438 | pid_t pid; | ||
439 | if (read_pid(argv[i] + 11, &pid) == 0) | ||
440 | shut(pid); | ||
441 | else | ||
442 | shut_name(argv[i] + 11); | ||
443 | |||
444 | // it will never get here!!! | ||
445 | exit(0); | ||
446 | } | ||
447 | |||
448 | //************************************* | ||
449 | // filtering | ||
450 | //************************************* | ||
451 | #ifdef HAVE_SECCOMP | ||
452 | else if (strcmp(argv[i], "--seccomp") == 0) { | ||
453 | if (arg_seccomp) { | ||
454 | fprintf(stderr, "Error: seccomp already enabled\n"); | ||
455 | exit(1); | ||
456 | } | ||
457 | arg_seccomp = 1; | ||
458 | } | ||
459 | else if (strncmp(argv[i], "--seccomp=", 10) == 0) { | ||
460 | if (arg_seccomp) { | ||
461 | fprintf(stderr, "Error: seccomp already enabled\n"); | ||
462 | exit(1); | ||
463 | } | ||
464 | arg_seccomp = 1; | ||
465 | arg_seccomp_list = strdup(argv[i] + 10); | ||
466 | if (!arg_seccomp_list) | ||
467 | errExit("strdup"); | ||
468 | } | ||
469 | else if (strncmp(argv[i], "--seccomp.drop=", 15) == 0) { | ||
470 | if (arg_seccomp) { | ||
471 | fprintf(stderr, "Error: seccomp already enabled\n"); | ||
472 | exit(1); | ||
473 | } | ||
474 | arg_seccomp = 1; | ||
475 | arg_seccomp_list_drop = strdup(argv[i] + 15); | ||
476 | if (!arg_seccomp_list_drop) | ||
477 | errExit("strdup"); | ||
478 | } | ||
479 | else if (strncmp(argv[i], "--seccomp.keep=", 15) == 0) { | ||
480 | if (arg_seccomp) { | ||
481 | fprintf(stderr, "Error: seccomp already enabled\n"); | ||
482 | exit(1); | ||
483 | } | ||
484 | arg_seccomp = 1; | ||
485 | arg_seccomp_list_keep = strdup(argv[i] + 15); | ||
486 | if (!arg_seccomp_list_keep) | ||
487 | errExit("strdup"); | ||
488 | } | ||
489 | #endif | ||
490 | else if (strcmp(argv[i], "--caps") == 0) | ||
491 | arg_caps_default_filter = 1; | ||
492 | else if (strcmp(argv[i], "--caps.drop=all") == 0) | ||
493 | arg_caps_drop_all = 1; | ||
494 | else if (strncmp(argv[i], "--caps.drop=", 12) == 0) { | ||
495 | arg_caps_drop = 1; | ||
496 | arg_caps_list = strdup(argv[i] + 12); | ||
497 | if (!arg_caps_list) | ||
498 | errExit("strdup"); | ||
499 | // verify caps list and exit if problems | ||
500 | if (caps_check_list(arg_caps_list, NULL)) | ||
501 | return 1; | ||
502 | } | ||
503 | else if (strncmp(argv[i], "--caps.keep=", 12) == 0) { | ||
504 | arg_caps_keep = 1; | ||
505 | arg_caps_list = strdup(argv[i] + 12); | ||
506 | if (!arg_caps_list) | ||
507 | errExit("strdup"); | ||
508 | // verify caps list and exit if problems | ||
509 | if (caps_check_list(arg_caps_list, NULL)) | ||
510 | return 1; | ||
511 | } | ||
512 | |||
513 | |||
514 | else if (strcmp(argv[i], "--trace") == 0) | ||
515 | arg_trace = 1; | ||
516 | else if (strncmp(argv[i], "--rlimit-nofile=", 16) == 0) { | ||
517 | if (not_unsigned(argv[i] + 16)) { | ||
518 | fprintf(stderr, "Error: invalid rlimt nofile\n"); | ||
519 | exit(1); | ||
520 | } | ||
521 | sscanf(argv[i] + 16, "%u", &cfg.rlimit_nofile); | ||
522 | arg_rlimit_nofile = 1; | ||
523 | } | ||
524 | else if (strncmp(argv[i], "--rlimit-nproc=", 15) == 0) { | ||
525 | if (not_unsigned(argv[i] + 15)) { | ||
526 | fprintf(stderr, "Error: invalid rlimt nproc\n"); | ||
527 | exit(1); | ||
528 | } | ||
529 | sscanf(argv[i] + 15, "%u", &cfg.rlimit_nproc); | ||
530 | arg_rlimit_nproc = 1; | ||
531 | } | ||
532 | else if (strncmp(argv[i], "--rlimit-fsize=", 15) == 0) { | ||
533 | if (not_unsigned(argv[i] + 15)) { | ||
534 | fprintf(stderr, "Error: invalid rlimt fsize\n"); | ||
535 | exit(1); | ||
536 | } | ||
537 | sscanf(argv[i] + 15, "%u", &cfg.rlimit_fsize); | ||
538 | arg_rlimit_fsize = 1; | ||
539 | } | ||
540 | else if (strncmp(argv[i], "--rlimit-sigpending=", 20) == 0) { | ||
541 | if (not_unsigned(argv[i] + 20)) { | ||
542 | fprintf(stderr, "Error: invalid rlimt sigpending\n"); | ||
543 | exit(1); | ||
544 | } | ||
545 | sscanf(argv[i] + 20, "%u", &cfg.rlimit_sigpending); | ||
546 | arg_rlimit_sigpending = 1; | ||
547 | } | ||
548 | else if (strncmp(argv[i], "--ipc-namespace", 15) == 0) | ||
549 | arg_ipc = 1; | ||
550 | else if (strncmp(argv[i], "--cpu=", 6) == 0) | ||
551 | read_cpu_list(argv[i] + 6); | ||
552 | else if (strcmp(argv[i], "--nox11") == 0) { | ||
553 | // check if firejail lkm is present | ||
554 | struct stat s; | ||
555 | if (stat("/proc/firejail", &s) < 0) { | ||
556 | fprintf(stderr, "Error: firejail Linux kernel module not found. The module" | ||
557 | " is required for --nox11 option to work.\n"); | ||
558 | exit(1); | ||
559 | } | ||
560 | arg_nox11 = 1; | ||
561 | } | ||
562 | else if (strcmp(argv[i], "--nodbus") == 0) { | ||
563 | // check if firejail lkm is present | ||
564 | struct stat s; | ||
565 | if (stat("/proc/firejail", &s) < 0) { | ||
566 | fprintf(stderr, "Error: firejail Linux kernel module not found. The module" | ||
567 | " is required for --nodbus option to work.\n"); | ||
568 | exit(1); | ||
569 | } | ||
570 | arg_nodbus = 1; | ||
571 | } | ||
572 | else if (strncmp(argv[i], "--cgroup=", 9) == 0) { | ||
573 | if (arg_cgroup) { | ||
574 | fprintf(stderr, "Error: only a cgroup can be defined\n"); | ||
575 | exit(1); | ||
576 | } | ||
577 | arg_cgroup = 1; | ||
578 | cfg.cgroup = strdup(argv[i] + 9); | ||
579 | if (!cfg.cgroup) | ||
580 | errExit("strdup"); | ||
581 | set_cgroup(cfg.cgroup); | ||
582 | } | ||
583 | |||
584 | //************************************* | ||
585 | // filesystem | ||
586 | //************************************* | ||
587 | #ifdef HAVE_BIND | ||
588 | else if (strncmp(argv[i], "--bind=", 7) == 0) { | ||
589 | char *line; | ||
590 | if (asprintf(&line, "bind %s", argv[i] + 7) == -1) | ||
591 | errExit("asprintf"); | ||
592 | |||
593 | profile_check_line(line, 0); // will exit if something wrong | ||
594 | profile_add(line); | ||
595 | } | ||
596 | #endif | ||
597 | else if (strncmp(argv[i], "--tmpfs=", 8) == 0) { | ||
598 | char *line; | ||
599 | if (asprintf(&line, "tmpfs %s", argv[i] + 8) == -1) | ||
600 | errExit("asprintf"); | ||
601 | |||
602 | profile_check_line(line, 0); // will exit if something wrong | ||
603 | profile_add(line); | ||
604 | } | ||
605 | else if (strncmp(argv[i], "--blacklist=", 12) == 0) { | ||
606 | char *line; | ||
607 | if (asprintf(&line, "blacklist %s", argv[i] + 12) == -1) | ||
608 | errExit("asprintf"); | ||
609 | |||
610 | profile_check_line(line, 0); // will exit if something wrong | ||
611 | profile_add(line); | ||
612 | } | ||
613 | else if (strncmp(argv[i], "--read-only=", 12) == 0) { | ||
614 | char *line; | ||
615 | if (asprintf(&line, "read-only %s", argv[i] + 12) == -1) | ||
616 | errExit("asprintf"); | ||
617 | |||
618 | profile_check_line(line, 0); // will exit if something wrong | ||
619 | profile_add(line); | ||
620 | } | ||
621 | else if (strcmp(argv[i], "--overlay") == 0) { | ||
622 | if (cfg.chrootdir) { | ||
623 | fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); | ||
624 | exit(1); | ||
625 | } | ||
626 | arg_overlay = 1; | ||
627 | } | ||
628 | else if (strncmp(argv[i], "--profile=", 10) == 0) { | ||
629 | // multiple profile files are allowed! | ||
630 | char *ptr = argv[i] + 10; | ||
631 | if (is_dir(ptr) || is_link(ptr) || strstr(ptr, "..")) { | ||
632 | fprintf(stderr, "Error: invalid profile file\n"); | ||
633 | exit(1); | ||
634 | } | ||
635 | |||
636 | // access call checks as real UID/GID, not as effective UID/GID | ||
637 | if (access(argv[i] + 10, R_OK)) { | ||
638 | fprintf(stderr, "Error: cannot access profile file\n"); | ||
639 | return 1; | ||
640 | } | ||
641 | |||
642 | profile_read(argv[i] + 10, NULL, NULL); | ||
643 | custom_profile = 1; | ||
644 | } | ||
645 | #ifdef HAVE_CHROOT | ||
646 | else if (strncmp(argv[i], "--chroot=", 9) == 0) { | ||
647 | if (arg_overlay) { | ||
648 | fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); | ||
649 | exit(1); | ||
650 | } | ||
651 | |||
652 | // extract chroot dirname | ||
653 | cfg.chrootdir = argv[i] + 9; | ||
654 | // if the directory starts with ~, expand the home directory | ||
655 | if (*cfg.chrootdir == '~') { | ||
656 | char *tmp; | ||
657 | if (asprintf(&tmp, "%s%s", cfg.homedir, cfg.chrootdir + 1) == -1) | ||
658 | errExit("asprintf"); | ||
659 | cfg.chrootdir = tmp; | ||
660 | } | ||
661 | |||
662 | // check chroot dirname exists | ||
663 | if (strstr(cfg.chrootdir, "..") || !is_dir(cfg.chrootdir) || is_link(cfg.chrootdir)) { | ||
664 | fprintf(stderr, "Error: invalid directory %s\n", cfg.chrootdir); | ||
665 | return 1; | ||
666 | } | ||
667 | |||
668 | // check chroot directory structure | ||
669 | if (fs_check_chroot_dir(cfg.chrootdir)) { | ||
670 | fprintf(stderr, "Error: invalid chroot\n"); | ||
671 | exit(1); | ||
672 | } | ||
673 | } | ||
674 | #endif | ||
675 | else if (strcmp(argv[i], "--private") == 0) | ||
676 | arg_private = 1; | ||
677 | else if (strncmp(argv[i], "--private=", 10) == 0) { | ||
678 | if (cfg.home_private_keep) { | ||
679 | fprintf(stderr, "Error: a private list of files was already defined with --private.keep option.\n"); | ||
680 | exit(1); | ||
681 | } | ||
682 | |||
683 | // extract private home dirname | ||
684 | cfg.home_private = argv[i] + 10; | ||
685 | fs_check_private_dir(); | ||
686 | arg_private = 1; | ||
687 | } | ||
688 | else if (strncmp(argv[i], "--private.keep=", 15) == 0) { | ||
689 | if (cfg.home_private) { | ||
690 | fprintf(stderr, "Error: a private home directory was already defined with --private option.\n"); | ||
691 | exit(1); | ||
692 | } | ||
693 | |||
694 | // extract private home dirname | ||
695 | cfg.home_private_keep = argv[i] + 15; | ||
696 | fs_check_home_list(); | ||
697 | arg_private = 1; | ||
698 | } | ||
699 | else if (strcmp(argv[i], "--private-dev") == 0) { | ||
700 | arg_private_dev = 1; | ||
701 | } | ||
702 | |||
703 | |||
704 | |||
705 | //************************************* | ||
706 | // hostname, etc | ||
707 | //************************************* | ||
708 | else if (strncmp(argv[i], "--name=", 7) == 0) { | ||
709 | cfg.hostname = argv[i] + 7; | ||
710 | if (strlen(cfg.hostname) == 0) { | ||
711 | fprintf(stderr, "Error: please provide a name for sandbox\n"); | ||
712 | return 1; | ||
713 | } | ||
714 | } | ||
715 | else if (strcmp(argv[i], "--nogroups") == 0) | ||
716 | arg_nogroups = 1; | ||
717 | else if (strcmp(argv[i], "--noroot") == 0) { | ||
718 | check_user_namespace(); | ||
719 | } | ||
720 | |||
721 | //************************************* | ||
722 | // network | ||
723 | //************************************* | ||
724 | else if (strncmp(argv[i], "--net=", 6) == 0) { | ||
725 | if (strcmp(argv[i] + 6, "none") == 0) { | ||
726 | arg_nonetwork = 1; | ||
727 | cfg.bridge0.configured = 0; | ||
728 | cfg.bridge1.configured = 0; | ||
729 | cfg.bridge2.configured = 0; | ||
730 | cfg.bridge3.configured = 0; | ||
731 | continue; | ||
732 | } | ||
733 | if (strcmp(argv[i] + 6, "lo") == 0) { | ||
734 | fprintf(stderr, "Error: cannot attach to lo device\n"); | ||
735 | exit(1); | ||
736 | } | ||
737 | |||
738 | Bridge *br; | ||
739 | if (cfg.bridge0.configured == 0) | ||
740 | br = &cfg.bridge0; | ||
741 | else if (cfg.bridge1.configured == 0) | ||
742 | br = &cfg.bridge1; | ||
743 | else if (cfg.bridge2.configured == 0) | ||
744 | br = &cfg.bridge2; | ||
745 | else if (cfg.bridge3.configured == 0) | ||
746 | br = &cfg.bridge3; | ||
747 | else { | ||
748 | fprintf(stderr, "Error: maximum 4 network devices allowed\n"); | ||
749 | return 1; | ||
750 | } | ||
751 | net_configure_bridge(br, argv[i] + 6); | ||
752 | } | ||
753 | else if (strcmp(argv[i], "--scan") == 0) { | ||
754 | arg_scan = 1; | ||
755 | } | ||
756 | else if (strncmp(argv[i], "--iprange=", 10) == 0) { | ||
757 | Bridge *br = last_bridge_configured(); | ||
758 | if (br == NULL) { | ||
759 | fprintf(stderr, "Error: no network device configured\n"); | ||
760 | return 1; | ||
761 | } | ||
762 | if (br->iprange_start || br->iprange_end) { | ||
763 | fprintf(stderr, "Error: cannot configure the IP range twice for the same interface\n"); | ||
764 | return 1; | ||
765 | } | ||
766 | |||
767 | // parse option arguments | ||
768 | char *firstip = argv[i] + 10; | ||
769 | char *secondip = firstip; | ||
770 | while (*secondip != '\0') { | ||
771 | if (*secondip == ',') | ||
772 | break; | ||
773 | secondip++; | ||
774 | } | ||
775 | if (*secondip == '\0') { | ||
776 | fprintf(stderr, "Error: invalid IP range\n"); | ||
777 | return 1; | ||
778 | } | ||
779 | *secondip = '\0'; | ||
780 | secondip++; | ||
781 | |||
782 | // check addresses | ||
783 | if (atoip(firstip, &br->iprange_start) || atoip(secondip, &br->iprange_end) || | ||
784 | br->iprange_start >= br->iprange_end) { | ||
785 | fprintf(stderr, "Error: invalid IP range\n"); | ||
786 | return 1; | ||
787 | } | ||
788 | if (in_netrange(br->iprange_start, br->ip, br->mask) || in_netrange(br->iprange_end, br->ip, br->mask)) { | ||
789 | fprintf(stderr, "Error: IP range addresses not in network range\n"); | ||
790 | return 1; | ||
791 | } | ||
792 | } | ||
793 | else if (strncmp(argv[i], "--mac=", 6) == 0) { | ||
794 | Bridge *br = last_bridge_configured(); | ||
795 | if (br == NULL) { | ||
796 | fprintf(stderr, "Error: no network device configured\n"); | ||
797 | return 1; | ||
798 | } | ||
799 | if (mac_not_zero(br->macsandbox)) { | ||
800 | fprintf(stderr, "Error: cannot configure the MAC address twice for the same interface\n"); | ||
801 | return 1; | ||
802 | } | ||
803 | |||
804 | // read the address | ||
805 | if (atomac(argv[i] + 6, br->macsandbox)) { | ||
806 | fprintf(stderr, "Error: invalid MAC address\n"); | ||
807 | return 1; | ||
808 | } | ||
809 | } | ||
810 | else if (strncmp(argv[i], "--ip=", 5) == 0) { | ||
811 | Bridge *br = last_bridge_configured(); | ||
812 | if (br == NULL) { | ||
813 | fprintf(stderr, "Error: no network device configured\n"); | ||
814 | return 1; | ||
815 | } | ||
816 | if (br->arg_ip_none || br->ipsandbox) { | ||
817 | fprintf(stderr, "Error: cannot configure the IP address twice for the same interface\n"); | ||
818 | return 1; | ||
819 | } | ||
820 | |||
821 | // configure this IP address for the last bridge defined | ||
822 | if (strcmp(argv[i] + 5, "none") == 0) | ||
823 | br->arg_ip_none = 1; | ||
824 | else { | ||
825 | if (atoip(argv[i] + 5, &br->ipsandbox)) { | ||
826 | fprintf(stderr, "Error: invalid IP address\n"); | ||
827 | return 1; | ||
828 | } | ||
829 | } | ||
830 | } | ||
831 | else if (strncmp(argv[i], "--defaultgw=", 12) == 0) { | ||
832 | if (atoip(argv[i] + 12, &cfg.defaultgw)) { | ||
833 | fprintf(stderr, "Error: invalid IP address\n"); | ||
834 | return 1; | ||
835 | } | ||
836 | } | ||
837 | else if (strncmp(argv[i], "--dns=", 6) == 0) { | ||
838 | uint32_t dns; | ||
839 | if (atoip(argv[i] + 6, &dns)) { | ||
840 | fprintf(stderr, "Error: invalid DNS server IP address\n"); | ||
841 | return 1; | ||
842 | } | ||
843 | |||
844 | if (cfg.dns1 == 0) | ||
845 | cfg.dns1 = dns; | ||
846 | else if (cfg.dns2 == 0) | ||
847 | cfg.dns2 = dns; | ||
848 | else if (cfg.dns3 == 0) | ||
849 | cfg.dns3 = dns; | ||
850 | else { | ||
851 | fprintf(stderr, "Error: up to 3 DNS servers can be specified\n"); | ||
852 | return 1; | ||
853 | } | ||
854 | } | ||
855 | else if (strcmp(argv[i], "--netfilter") == 0) | ||
856 | arg_netfilter = 1; | ||
857 | else if (strncmp(argv[i], "--netfilter=", 12) == 0) { | ||
858 | arg_netfilter = 1; | ||
859 | arg_netfilter_file = argv[i] + 12; | ||
860 | check_netfilter_file(arg_netfilter_file); | ||
861 | } | ||
862 | |||
863 | //************************************* | ||
864 | // command | ||
865 | //************************************* | ||
866 | else if (strcmp(argv[i], "--csh") == 0) { | ||
867 | if (arg_shell_none) { | ||
868 | fprintf(stderr, "Error: --shell=none was already specified.\n"); | ||
869 | return 1; | ||
870 | } | ||
871 | if (arg_zsh || cfg.shell ) { | ||
872 | fprintf(stderr, "Error: only one default user shell can be specified\n"); | ||
873 | return 1; | ||
874 | } | ||
875 | arg_csh = 1; | ||
876 | } | ||
877 | else if (strcmp(argv[i], "--zsh") == 0) { | ||
878 | if (arg_shell_none) { | ||
879 | fprintf(stderr, "Error: --shell=none was already specified.\n"); | ||
880 | return 1; | ||
881 | } | ||
882 | if (arg_csh || cfg.shell ) { | ||
883 | fprintf(stderr, "Error: only one default user shell can be specified\n"); | ||
884 | return 1; | ||
885 | } | ||
886 | arg_zsh = 1; | ||
887 | } | ||
888 | else if (strcmp(argv[i], "--shell=none") == 0) { | ||
889 | arg_shell_none = 1; | ||
890 | if (arg_csh || arg_zsh || cfg.shell) { | ||
891 | fprintf(stderr, "Error: a shell was already specified\n"); | ||
892 | return 1; | ||
893 | } | ||
894 | } | ||
895 | else if (strncmp(argv[i], "--shell=", 8) == 0) { | ||
896 | if (arg_shell_none) { | ||
897 | fprintf(stderr, "Error: --shell=none was already specified.\n"); | ||
898 | return 1; | ||
899 | } | ||
900 | if (arg_csh || arg_zsh || cfg.shell) { | ||
901 | fprintf(stderr, "Error: only one user shell can be specified\n"); | ||
902 | return 1; | ||
903 | } | ||
904 | cfg.shell = argv[i] + 8; | ||
905 | |||
906 | if (is_dir(cfg.shell) || is_link(cfg.shell) || strstr(cfg.shell, "..")) { | ||
907 | fprintf(stderr, "Error: invalid shell\n"); | ||
908 | exit(1); | ||
909 | } | ||
910 | |||
911 | // access call checks as real UID/GID, not as effective UID/GID | ||
912 | if (access(cfg.shell, R_OK)) { | ||
913 | fprintf(stderr, "Error: cannot access shell file\n"); | ||
914 | exit(1); | ||
915 | } | ||
916 | } | ||
917 | else if (strcmp(argv[i], "-c") == 0) { | ||
918 | arg_command = 1; | ||
919 | if (i == (argc - 1)) { | ||
920 | fprintf(stderr, "Error: option -c requires an argument\n"); | ||
921 | return 1; | ||
922 | } | ||
923 | } | ||
924 | else if (strcmp(argv[i], "--") == 0) { | ||
925 | // double dash - positional params to follow | ||
926 | arg_doubledash = 1; | ||
927 | i++; | ||
928 | if (i >= argc) { | ||
929 | fprintf(stderr, "Error: program name not found\n"); | ||
930 | exit(1); | ||
931 | } | ||
932 | extract_command_name(argv[i]); | ||
933 | prog_index = i; | ||
934 | cfg.original_program_index = i; | ||
935 | break; | ||
936 | } | ||
937 | else { | ||
938 | // is this an invalid option? | ||
939 | if (*argv[i] == '-') { | ||
940 | fprintf(stderr, "Error: invalid %s command line option\n", argv[i]); | ||
941 | return 1; | ||
942 | } | ||
943 | |||
944 | // we have a program name coming | ||
945 | extract_command_name(argv[i]); | ||
946 | prog_index = i; | ||
947 | cfg.original_program_index = i; | ||
948 | break; | ||
949 | } | ||
950 | } | ||
951 | |||
952 | // check network configuration options - it will exit if anything went wrong | ||
953 | net_check_cfg(); | ||
954 | |||
955 | // check user namespace (--noroot) options | ||
956 | if (arg_noroot) { | ||
957 | if (arg_overlay) { | ||
958 | fprintf(stderr, "Error: --overlay and --noroot are mutually exclusive.\n"); | ||
959 | exit(1); | ||
960 | } | ||
961 | else if (cfg.chrootdir) { | ||
962 | fprintf(stderr, "Error: --chroot and --noroot are mutually exclusive.\n"); | ||
963 | exit(1); | ||
964 | } | ||
965 | } | ||
966 | |||
967 | // log command | ||
968 | logargs(argc, argv); | ||
969 | if (fullargc) { | ||
970 | char *msg; | ||
971 | if (asprintf(&msg, "user %s entering restricted shell", cfg.username) == -1) | ||
972 | errExit("asprintf"); | ||
973 | logmsg(msg); | ||
974 | free(msg); | ||
975 | } | ||
976 | |||
977 | // build the sandbox command | ||
978 | if (prog_index == -1 && arg_zsh) { | ||
979 | cfg.command_line = "/usr/bin/zsh"; | ||
980 | cfg.command_name = "zsh"; | ||
981 | } | ||
982 | else if (prog_index == -1 && arg_csh) { | ||
983 | cfg.command_line = "/bin/csh"; | ||
984 | cfg.command_name = "csh"; | ||
985 | } | ||
986 | else if (prog_index == -1 && cfg.shell) { | ||
987 | cfg.command_line = cfg.shell; | ||
988 | cfg.command_name = cfg.shell; | ||
989 | } | ||
990 | else if (prog_index == -1) { | ||
991 | cfg.command_line = "/bin/bash"; | ||
992 | cfg.command_name = "bash"; | ||
993 | } | ||
994 | else { | ||
995 | // calculate the length of the command | ||
996 | int i; | ||
997 | int len = 0; | ||
998 | int argcnt = argc - prog_index; | ||
999 | for (i = 0; i < argcnt; i++) | ||
1000 | len += strlen(argv[i + prog_index]) + 1; // + ' ' | ||
1001 | |||
1002 | // build the string | ||
1003 | cfg.command_line = malloc(len + 1); // + '\0' | ||
1004 | if (!cfg.command_line) | ||
1005 | errExit("malloc"); | ||
1006 | char *ptr = cfg.command_line; | ||
1007 | for (i = 0; i < argcnt; i++) { | ||
1008 | sprintf(ptr, "%s ", argv[i + prog_index]); | ||
1009 | ptr += strlen(ptr); | ||
1010 | } | ||
1011 | } | ||
1012 | |||
1013 | // load the profile | ||
1014 | { | ||
1015 | assert(cfg.command_name); | ||
1016 | if (arg_debug) | ||
1017 | printf("Command name #%s#\n", cfg.command_name); | ||
1018 | if (!custom_profile) { | ||
1019 | // look for a profile in ~/.config/firejail directory | ||
1020 | char *usercfgdir; | ||
1021 | if (asprintf(&usercfgdir, "%s/.config/firejail", cfg.homedir) == -1) | ||
1022 | errExit("asprintf"); | ||
1023 | int rv = profile_find(cfg.command_name, usercfgdir); | ||
1024 | free(usercfgdir); | ||
1025 | custom_profile = rv; | ||
1026 | } | ||
1027 | if (!custom_profile) { | ||
1028 | // look for a user profile in /etc/firejail directory | ||
1029 | int rv = profile_find(cfg.command_name, "/etc/firejail"); | ||
1030 | custom_profile = rv; | ||
1031 | } | ||
1032 | } | ||
1033 | |||
1034 | // check and assign an IP address - for macvlan it will be done again in the sandbox! | ||
1035 | if (any_bridge_configured()) { | ||
1036 | lockfd = open("/tmp/firejail/firejail.lock", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); | ||
1037 | if (lockfd != -1) { | ||
1038 | int rv = fchown(lockfd, 0, 0); | ||
1039 | (void) rv; | ||
1040 | flock(lockfd, LOCK_EX); | ||
1041 | } | ||
1042 | |||
1043 | check_network(&cfg.bridge0); | ||
1044 | check_network(&cfg.bridge1); | ||
1045 | check_network(&cfg.bridge2); | ||
1046 | check_network(&cfg.bridge3); | ||
1047 | |||
1048 | // save network mapping in shared memory | ||
1049 | network_shm_set_file(sandbox_pid); | ||
1050 | } | ||
1051 | |||
1052 | // create the parent-child communication pipe | ||
1053 | if (pipe(parent_to_child_fds) < 0) | ||
1054 | errExit("pipe"); | ||
1055 | if (pipe(child_to_parent_fds) < 0) | ||
1056 | errExit("pipe"); | ||
1057 | |||
1058 | // clone environment | ||
1059 | int flags = CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUTS | SIGCHLD; | ||
1060 | |||
1061 | // in root mode also enable CLONE_NEWIPC | ||
1062 | // in user mode CLONE_NEWIPC will break MIT Shared Memory Extension (MIT-SHM) | ||
1063 | if (getuid() == 0 || arg_ipc) | ||
1064 | flags |= CLONE_NEWIPC; | ||
1065 | |||
1066 | if (any_bridge_configured() || arg_nonetwork) { | ||
1067 | flags |= CLONE_NEWNET; | ||
1068 | } | ||
1069 | else if (arg_debug) | ||
1070 | printf("Using the local network stack\n"); | ||
1071 | |||
1072 | child = clone(sandbox, | ||
1073 | child_stack + STACK_SIZE, | ||
1074 | flags, | ||
1075 | NULL); | ||
1076 | if (child == -1) | ||
1077 | errExit("clone"); | ||
1078 | |||
1079 | if (!arg_command) { | ||
1080 | printf("Parent pid %u, child pid %u\n", sandbox_pid, child); | ||
1081 | // print the path of the new log directory | ||
1082 | if (getuid() == 0) // only for root | ||
1083 | printf("The new log directory is /proc/%d/root/var/log\n", child); | ||
1084 | } | ||
1085 | |||
1086 | |||
1087 | |||
1088 | // create veth pair or macvlan device | ||
1089 | if (cfg.bridge0.configured && !arg_nonetwork) { | ||
1090 | if (cfg.bridge0.macvlan == 0) | ||
1091 | net_configure_veth_pair(&cfg.bridge0, "eth0", child); | ||
1092 | else | ||
1093 | net_create_macvlan(cfg.bridge0.devsandbox, cfg.bridge0.dev, child); | ||
1094 | } | ||
1095 | |||
1096 | if (cfg.bridge1.configured && !arg_nonetwork) { | ||
1097 | if (cfg.bridge1.macvlan == 0) | ||
1098 | net_configure_veth_pair(&cfg.bridge1, "eth1", child); | ||
1099 | else | ||
1100 | net_create_macvlan(cfg.bridge1.devsandbox, cfg.bridge1.dev, child); | ||
1101 | } | ||
1102 | |||
1103 | if (cfg.bridge2.configured && !arg_nonetwork) { | ||
1104 | if (cfg.bridge2.macvlan == 0) | ||
1105 | net_configure_veth_pair(&cfg.bridge2, "eth2", child); | ||
1106 | else | ||
1107 | net_create_macvlan(cfg.bridge2.devsandbox, cfg.bridge2.dev, child); | ||
1108 | } | ||
1109 | |||
1110 | if (cfg.bridge3.configured && !arg_nonetwork) { | ||
1111 | if (cfg.bridge3.macvlan == 0) | ||
1112 | net_configure_veth_pair(&cfg.bridge3, "eth3", child); | ||
1113 | else | ||
1114 | net_create_macvlan(cfg.bridge3.devsandbox, cfg.bridge3.dev, child); | ||
1115 | } | ||
1116 | |||
1117 | // close each end of the unused pipes | ||
1118 | close(parent_to_child_fds[0]); | ||
1119 | close(child_to_parent_fds[1]); | ||
1120 | |||
1121 | // notify child that base setup is complete | ||
1122 | notify_other(parent_to_child_fds[1]); | ||
1123 | |||
1124 | // wait for child to create new user namespace with CLONE_NEWUSER | ||
1125 | wait_for_other(child_to_parent_fds[0]); | ||
1126 | close(child_to_parent_fds[0]); | ||
1127 | |||
1128 | if (arg_noroot) { | ||
1129 | // update the UID and GID maps in the new child user namespace | ||
1130 | // uid | ||
1131 | char *map_path; | ||
1132 | if (asprintf(&map_path, "/proc/%d/uid_map", child) == -1) | ||
1133 | errExit("asprintf"); | ||
1134 | char *map; | ||
1135 | uid_t uid = getuid(); | ||
1136 | if (asprintf(&map, "%d %d 1", uid, uid) == -1) | ||
1137 | errExit("asprintf"); | ||
1138 | update_map(map, map_path); | ||
1139 | free(map); | ||
1140 | free(map_path); | ||
1141 | |||
1142 | //gid | ||
1143 | if (asprintf(&map_path, "/proc/%d/gid_map", child) == -1) | ||
1144 | errExit("asprintf"); | ||
1145 | gid_t gid = getgid(); | ||
1146 | if (asprintf(&map, "%d %d 1", gid, gid) == -1) | ||
1147 | errExit("asprintf"); | ||
1148 | update_map(map, map_path); | ||
1149 | free(map); | ||
1150 | free(map_path); | ||
1151 | } | ||
1152 | |||
1153 | // notify child that UID/GID mapping is complete | ||
1154 | notify_other(parent_to_child_fds[1]); | ||
1155 | close(parent_to_child_fds[1]); | ||
1156 | |||
1157 | if (lockfd != -1) | ||
1158 | flock(lockfd, LOCK_UN); | ||
1159 | |||
1160 | // handle CTRL-C in parent | ||
1161 | signal (SIGINT, my_handler); | ||
1162 | signal (SIGTERM, my_handler); | ||
1163 | |||
1164 | // wait for the child to finish | ||
1165 | waitpid(child, NULL, 0); | ||
1166 | myexit(0); | ||
1167 | return 0; | ||
1168 | } | ||
diff --git a/src/firejail/netfilter.c b/src/firejail/netfilter.c new file mode 100644 index 000000000..dbed4ac30 --- /dev/null +++ b/src/firejail/netfilter.c | |||
@@ -0,0 +1,164 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 | #include <sys/types.h> | ||
24 | #include <sys/wait.h> | ||
25 | #include <fcntl.h> | ||
26 | |||
27 | static char *client_filter = | ||
28 | "*filter\n" | ||
29 | ":INPUT DROP [0:0]\n" | ||
30 | ":FORWARD DROP [0:0]\n" | ||
31 | ":OUTPUT ACCEPT [0:0]\n" | ||
32 | "-A INPUT -i lo -j ACCEPT\n" | ||
33 | "# echo replay is handled by -m state RELEATED/ESTABLISHED below\n" | ||
34 | "#-A INPUT -p icmp --icmp-type echo-reply -j ACCEPT\n" | ||
35 | "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n" | ||
36 | "-A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT\n" | ||
37 | "-A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT\n" | ||
38 | "-A INPUT -p icmp --icmp-type echo-request -j ACCEPT \n" | ||
39 | "COMMIT\n"; | ||
40 | |||
41 | void check_netfilter_file(const char *fname) { | ||
42 | if (is_dir(fname) || is_link(fname) || strstr(fname, "..")) { | ||
43 | fprintf(stderr, "Error: invalid network filter file\n"); | ||
44 | exit(1); | ||
45 | } | ||
46 | |||
47 | // access call checks as real UID/GID, not as effective UID/GID | ||
48 | if (access(fname, R_OK)) { | ||
49 | fprintf(stderr, "Error: cannot access network filter file\n"); | ||
50 | exit(1); | ||
51 | } | ||
52 | } | ||
53 | |||
54 | |||
55 | void netfilter(const char *fname) { | ||
56 | // default filter | ||
57 | char *filter = client_filter; | ||
58 | |||
59 | // custom filter | ||
60 | int allocated = 0; | ||
61 | if (fname) { | ||
62 | // buffer the filter | ||
63 | struct stat s; | ||
64 | if (stat(fname, &s) == -1) { | ||
65 | fprintf(stderr, "Error: cannot find network filter file\n"); | ||
66 | exit(1); | ||
67 | } | ||
68 | |||
69 | filter = malloc(s.st_size + 1); // + '\0' | ||
70 | memset(filter, 0, s.st_size + 1); | ||
71 | if (!filter) | ||
72 | errExit("malloc"); | ||
73 | |||
74 | /* coverity[toctou] */ | ||
75 | FILE *fp = fopen(fname, "r"); | ||
76 | if (!fp) { | ||
77 | fprintf(stderr, "Error: cannot open network filter file\n"); | ||
78 | exit(1); | ||
79 | } | ||
80 | |||
81 | size_t sz = fread(filter, 1, s.st_size, fp); | ||
82 | if (sz != s.st_size) { | ||
83 | fprintf(stderr, "Error: cannot read network filter file\n"); | ||
84 | exit(1); | ||
85 | } | ||
86 | fclose(fp); | ||
87 | allocated = 1; | ||
88 | } | ||
89 | |||
90 | // mount a tempfs on top of /tmp directory | ||
91 | if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) | ||
92 | errExit("mounting /tmp"); | ||
93 | |||
94 | // create the filter file | ||
95 | FILE *fp = fopen("/tmp/netfilter", "w"); | ||
96 | if (!fp) { | ||
97 | fprintf(stderr, "Error: cannot open /tmp/netfilter file\n"); | ||
98 | exit(1); | ||
99 | } | ||
100 | fprintf(fp, "%s\n", filter); | ||
101 | fclose(fp); | ||
102 | |||
103 | // find iptables command | ||
104 | struct stat s; | ||
105 | char *iptables = NULL; | ||
106 | char *iptables_restore = NULL; | ||
107 | if (stat("/sbin/iptables", &s) == 0) { | ||
108 | iptables = "/sbin/iptables"; | ||
109 | iptables_restore = "/sbin/iptables-restore"; | ||
110 | } | ||
111 | else if (stat("/usr/sbin/iptables", &s) == 0) { | ||
112 | iptables = "/usr/sbin/iptables"; | ||
113 | iptables_restore = "/usr/sbin/iptables-restore"; | ||
114 | } | ||
115 | if (iptables == NULL || iptables_restore == NULL) { | ||
116 | fprintf(stderr, "Error: iptables command not found\n"); | ||
117 | goto doexit; | ||
118 | } | ||
119 | |||
120 | // push filter | ||
121 | pid_t child = fork(); | ||
122 | if (child < 0) | ||
123 | errExit("fork"); | ||
124 | if (child == 0) { | ||
125 | if (arg_debug) | ||
126 | printf("Installing network filter:\n%s\n", filter); | ||
127 | |||
128 | int fd; | ||
129 | if((fd = open("/tmp/netfilter", O_RDONLY)) == -1) { | ||
130 | fprintf(stderr,"Error: cannot open /tmp/netfilter\n"); | ||
131 | exit(1); | ||
132 | } | ||
133 | dup2(fd,STDIN_FILENO); | ||
134 | close(fd); | ||
135 | |||
136 | // wipe out environment variables | ||
137 | environ = NULL; | ||
138 | execl(iptables_restore, iptables_restore, NULL); | ||
139 | // it will never get here!!! | ||
140 | } | ||
141 | // wait for the child to finish | ||
142 | waitpid(child, NULL, 0); | ||
143 | |||
144 | // debug | ||
145 | if (arg_debug) { | ||
146 | child = fork(); | ||
147 | if (child < 0) | ||
148 | errExit("fork"); | ||
149 | if (child == 0) { | ||
150 | environ = NULL; | ||
151 | execl(iptables, iptables, "-vL", NULL); | ||
152 | // it will never get here!!! | ||
153 | } | ||
154 | // wait for the child to finish | ||
155 | waitpid(child, NULL, 0); | ||
156 | } | ||
157 | |||
158 | doexit: | ||
159 | // unmount /tmp | ||
160 | umount("/tmp"); | ||
161 | |||
162 | if (allocated) | ||
163 | free(filter); | ||
164 | } | ||
diff --git a/src/firejail/network.c b/src/firejail/network.c new file mode 100644 index 000000000..6a1d52744 --- /dev/null +++ b/src/firejail/network.c | |||
@@ -0,0 +1,362 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 <arpa/inet.h> | ||
22 | #include <sys/socket.h> | ||
23 | #include <sys/ioctl.h> | ||
24 | #include <netdb.h> | ||
25 | #include <ifaddrs.h> | ||
26 | #include <net/if.h> | ||
27 | #include <net/if_arp.h> | ||
28 | #include <net/route.h> | ||
29 | #include <linux/if_bridge.h> | ||
30 | |||
31 | // scan interfaces in current namespace and print IP address/mask for each interface | ||
32 | void 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 | |||
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 | |||
96 | |||
97 | // return -1 if the interface was not found; if the interface was found retrn 0 and fill in IP address and mask | ||
98 | int net_get_if_addr(const char *bridge, uint32_t *ip, uint32_t *mask, uint8_t mac[6]) { | ||
99 | assert(bridge); | ||
100 | assert(ip); | ||
101 | assert(mask); | ||
102 | int rv = -1; | ||
103 | struct ifaddrs *ifaddr, *ifa; | ||
104 | |||
105 | if (getifaddrs(&ifaddr) == -1) | ||
106 | errExit("getifaddrs"); | ||
107 | |||
108 | // walk through the linked list; if the interface is found, extract IP address and mask | ||
109 | for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { | ||
110 | if (ifa->ifa_addr == NULL) | ||
111 | continue; | ||
112 | if (strcmp(ifa->ifa_name, bridge) != 0) | ||
113 | continue; | ||
114 | |||
115 | if (ifa->ifa_addr->sa_family == AF_INET) { | ||
116 | struct sockaddr_in *si = (struct sockaddr_in *) ifa->ifa_netmask; | ||
117 | *mask = ntohl(si->sin_addr.s_addr); | ||
118 | si = (struct sockaddr_in *) ifa->ifa_addr; | ||
119 | *ip = ntohl(si->sin_addr.s_addr); | ||
120 | if (strcmp(ifa->ifa_name, "lo") != 0) | ||
121 | net_get_mac(ifa->ifa_name, mac); | ||
122 | |||
123 | rv = 0; | ||
124 | break; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | freeifaddrs(ifaddr); | ||
129 | return rv; | ||
130 | } | ||
131 | |||
132 | // bring interface up | ||
133 | void net_if_up(const char *ifname) { | ||
134 | if (strlen(ifname) > IFNAMSIZ) { | ||
135 | fprintf(stderr, "Error: invalid network device name %s\n", ifname); | ||
136 | exit(1); | ||
137 | } | ||
138 | |||
139 | int sock = socket(AF_INET,SOCK_DGRAM,0); | ||
140 | if (sock < 0) | ||
141 | errExit("socket"); | ||
142 | |||
143 | // get the existing interface flags | ||
144 | struct ifreq ifr; | ||
145 | memset(&ifr, 0, sizeof(ifr)); | ||
146 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); | ||
147 | ifr.ifr_addr.sa_family = AF_INET; | ||
148 | |||
149 | // read the existing flags | ||
150 | if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) { | ||
151 | close(sock); | ||
152 | errExit("ioctl"); | ||
153 | } | ||
154 | |||
155 | ifr.ifr_flags |= IFF_UP; | ||
156 | |||
157 | // set the new flags | ||
158 | if (ioctl( sock, SIOCSIFFLAGS, &ifr ) < 0) { | ||
159 | close(sock); | ||
160 | errExit("ioctl"); | ||
161 | } | ||
162 | |||
163 | // checking | ||
164 | // read the existing flags | ||
165 | if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) { | ||
166 | close(sock); | ||
167 | errExit("ioctl"); | ||
168 | } | ||
169 | |||
170 | // wait not more than 500ms for the interface to come up | ||
171 | int cnt = 0; | ||
172 | while (cnt < 50) { | ||
173 | usleep(10000); // sleep 10ms | ||
174 | |||
175 | // read the existing flags | ||
176 | if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) { | ||
177 | close(sock); | ||
178 | errExit("ioctl"); | ||
179 | } | ||
180 | if (ifr.ifr_flags & IFF_RUNNING) | ||
181 | break; | ||
182 | cnt++; | ||
183 | } | ||
184 | |||
185 | close(sock); | ||
186 | } | ||
187 | |||
188 | // configure interface | ||
189 | void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask) { | ||
190 | if (strlen(ifname) > IFNAMSIZ) { | ||
191 | fprintf(stderr, "Error: invalid network device name %s\n", ifname); | ||
192 | exit(1); | ||
193 | } | ||
194 | |||
195 | int sock = socket(AF_INET,SOCK_DGRAM,0); | ||
196 | if (sock < 0) | ||
197 | errExit("socket"); | ||
198 | |||
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 | |||
204 | ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(ip); | ||
205 | if (ioctl( sock, SIOCSIFADDR, &ifr ) < 0) { | ||
206 | close(sock); | ||
207 | errExit("ioctl"); | ||
208 | } | ||
209 | |||
210 | if (ip != 0) { | ||
211 | ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(mask); | ||
212 | if (ioctl( sock, SIOCSIFNETMASK, &ifr ) < 0) { | ||
213 | close(sock); | ||
214 | errExit("ioctl"); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | close(sock); | ||
219 | usleep(10000); // sleep 10ms | ||
220 | } | ||
221 | |||
222 | |||
223 | // add an IP route, return -1 if error, 0 if the route was added | ||
224 | int net_add_route(uint32_t ip, uint32_t mask, uint32_t gw) { | ||
225 | int sock; | ||
226 | struct rtentry route; | ||
227 | struct sockaddr_in *addr; | ||
228 | int err = 0; | ||
229 | |||
230 | // create the socket | ||
231 | if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) | ||
232 | errExit("socket"); | ||
233 | |||
234 | memset(&route, 0, sizeof(route)); | ||
235 | |||
236 | addr = (struct sockaddr_in*) &route.rt_gateway; | ||
237 | addr->sin_family = AF_INET; | ||
238 | addr->sin_addr.s_addr = htonl(gw); | ||
239 | |||
240 | addr = (struct sockaddr_in*) &route.rt_dst; | ||
241 | addr->sin_family = AF_INET; | ||
242 | addr->sin_addr.s_addr = htonl(ip); | ||
243 | |||
244 | addr = (struct sockaddr_in*) &route.rt_genmask; | ||
245 | addr->sin_family = AF_INET; | ||
246 | addr->sin_addr.s_addr = htonl(mask); | ||
247 | |||
248 | route.rt_flags = RTF_UP | RTF_GATEWAY; | ||
249 | route.rt_metric = 0; | ||
250 | if ((err = ioctl(sock, SIOCADDRT, &route)) != 0) { | ||
251 | close(sock); | ||
252 | return -1; | ||
253 | } | ||
254 | |||
255 | close(sock); | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | |||
260 | // add a veth device to a bridge | ||
261 | void net_bridge_add_interface(const char *bridge, const char *dev) { | ||
262 | if (strlen(bridge) > IFNAMSIZ) { | ||
263 | fprintf(stderr, "Error: invalid network device name %s\n", bridge); | ||
264 | exit(1); | ||
265 | } | ||
266 | |||
267 | struct ifreq ifr; | ||
268 | int err; | ||
269 | int ifindex = if_nametoindex(dev); | ||
270 | |||
271 | if (ifindex <= 0) | ||
272 | errExit("if_nametoindex"); | ||
273 | |||
274 | int sock; | ||
275 | if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) | ||
276 | errExit("socket"); | ||
277 | |||
278 | memset(&ifr, 0, sizeof(ifr)); | ||
279 | strncpy(ifr.ifr_name, bridge, IFNAMSIZ); | ||
280 | #ifdef SIOCBRADDIF | ||
281 | ifr.ifr_ifindex = ifindex; | ||
282 | err = ioctl(sock, SIOCBRADDIF, &ifr); | ||
283 | if (err < 0) | ||
284 | #endif | ||
285 | { | ||
286 | unsigned long args[4] = { BRCTL_ADD_IF, ifindex, 0, 0 }; | ||
287 | |||
288 | ifr.ifr_data = (char *) args; | ||
289 | err = ioctl(sock, SIOCDEVPRIVATE, &ifr); | ||
290 | } | ||
291 | (void) err; | ||
292 | close(sock); | ||
293 | } | ||
294 | |||
295 | #define BUFSIZE 1024 | ||
296 | uint32_t network_get_defaultgw(void) { | ||
297 | FILE *fp = fopen("/proc/self/net/route", "r"); | ||
298 | if (!fp) | ||
299 | errExit("fopen"); | ||
300 | |||
301 | char buf[BUFSIZE]; | ||
302 | uint32_t retval = 0; | ||
303 | while (fgets(buf, BUFSIZE, fp)) { | ||
304 | if (strncmp(buf, "Iface", 5) == 0) | ||
305 | continue; | ||
306 | |||
307 | char *ptr = buf; | ||
308 | while (*ptr != ' ' && *ptr != '\t') | ||
309 | ptr++; | ||
310 | while (*ptr == ' ' || *ptr == '\t') | ||
311 | ptr++; | ||
312 | |||
313 | unsigned dest; | ||
314 | unsigned gw; | ||
315 | int rv = sscanf(ptr, "%x %x", &dest, &gw); | ||
316 | if (rv == 2 && dest == 0) { | ||
317 | retval = ntohl(gw); | ||
318 | break; | ||
319 | } | ||
320 | } | ||
321 | |||
322 | fclose(fp); | ||
323 | return retval; | ||
324 | } | ||
325 | |||
326 | int net_config_mac(const char *ifname, const unsigned char mac[6]) { | ||
327 | struct ifreq ifr; | ||
328 | int sock; | ||
329 | |||
330 | if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) | ||
331 | errExit("socket"); | ||
332 | |||
333 | memset(&ifr, 0, sizeof(ifr)); | ||
334 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); | ||
335 | ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; | ||
336 | memcpy(ifr.ifr_hwaddr.sa_data, mac, 6); | ||
337 | |||
338 | if (ioctl(sock, SIOCSIFHWADDR, &ifr) == -1) | ||
339 | errExit("ioctl"); | ||
340 | close(sock); | ||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | int net_get_mac(const char *ifname, unsigned char mac[6]) { | ||
345 | |||
346 | struct ifreq ifr; | ||
347 | int sock; | ||
348 | |||
349 | if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) | ||
350 | errExit("socket"); | ||
351 | |||
352 | memset(&ifr, 0, sizeof(ifr)); | ||
353 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); | ||
354 | ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; | ||
355 | |||
356 | if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) | ||
357 | errExit("ioctl"); | ||
358 | memcpy(mac, ifr.ifr_hwaddr.sa_data, 6); | ||
359 | |||
360 | close(sock); | ||
361 | return 0; | ||
362 | } | ||
diff --git a/src/firejail/network.txt b/src/firejail/network.txt new file mode 100644 index 000000000..673d5b941 --- /dev/null +++ b/src/firejail/network.txt | |||
@@ -0,0 +1,95 @@ | |||
1 | struct Bridge { | ||
2 | char *dev; // bridge device name | ||
3 | uint32_t ip; // bridge device IP address | ||
4 | uint32_t mask; // bridge device mask | ||
5 | uint32_t ipsandbox // sandbox interface IP address | ||
6 | } | ||
7 | |||
8 | net_configure_bridge(br, device) { | ||
9 | br->dev = devname; | ||
10 | br->ip = extracted from kernel device - using net_get_if_addr() in network.c | ||
11 | br->mask = extracted from kernel device - using net_get_if_addr() in network.c | ||
12 | check available network range; /31 networks are not supported | ||
13 | } | ||
14 | |||
15 | net_configure_sandbox_ip(br) { | ||
16 | if br->ip_snadbox | ||
17 | check br->ipsandbox inside the bridge network | ||
18 | arp_check(br->ipsandbox) // send an arp req to check if anybody else is using this address | ||
19 | else | ||
20 | br->ipsandbox = arp_assign(); | ||
21 | } | ||
22 | |||
23 | net_configure_veth_pair { | ||
24 | create a veth pair | ||
25 | place one interface end in the bridge | ||
26 | place the other end in the namespace of the child process | ||
27 | } | ||
28 | |||
29 | net_bridge_wait_ip { | ||
30 | arp_check br->ipsandbox address to come up | ||
31 | wait for not more than 5 seconds | ||
32 | } | ||
33 | |||
34 | main() { | ||
35 | |||
36 | foreach argv[i] { | ||
37 | if --net | ||
38 | br = next bridge available | ||
39 | net_configure_bridge(br, device name from argv[i]); | ||
40 | else if --ip | ||
41 | br = last bridge configured | ||
42 | br->ipsandbox = ip address extracted from argv[i] | ||
43 | else if --defaultgw | ||
44 | cfg.defaultgw = ip address extracted from argv[i] | ||
45 | } | ||
46 | |||
47 | net_check_cfg(); // check the validity of network configuration so far | ||
48 | |||
49 | if (any bridge configured) { | ||
50 | lock /var/lock/firejail.lock file | ||
51 | for each bridge | ||
52 | net_configure_sandbox_ip(br) | ||
53 | } | ||
54 | |||
55 | clone (new network namespace if any bridge configured or --net=none) | ||
56 | |||
57 | if (any bridge configured) { | ||
58 | for each bridge | ||
59 | net_configure_veth_pair | ||
60 | } | ||
61 | |||
62 | notify child init is done | ||
63 | |||
64 | if (any bridge configured) { | ||
65 | for each bridge | ||
66 | net_bridge_wait_ip | ||
67 | unlock /var/lock/firejail.lock file | ||
68 | } | ||
69 | |||
70 | wait on child | ||
71 | exit | ||
72 | } | ||
73 | |||
74 | |||
75 | ****************************************************** | ||
76 | * macvlan notes | ||
77 | ****************************************************** | ||
78 | Configure a macvlan interface | ||
79 | |||
80 | # ip link add virtual0 link eth0 type macvlan mode bridge | ||
81 | (you can configure it with # ifconfig virtual0 192.168.1.52/24 up) | ||
82 | |||
83 | Create a new network namespace and move the interface in the new network namespace | ||
84 | |||
85 | # ip netns add dummy0 | ||
86 | # ip link set virtual0 netns dummy0 | ||
87 | |||
88 | Join the namespace and configure the interfaces | ||
89 | |||
90 | # ip netns exec dummy0 bash | ||
91 | # ifconfig lo up | ||
92 | # ifconfig virtual0 192.168.1.52/24 | ||
93 | |||
94 | Investigate ipvlan interface - added to linux kernel 3.19 | ||
95 | https://github.com/torvalds/linux/blob/master/Documentation/networking/ipvlan.txt | ||
diff --git a/src/firejail/network_main.c b/src/firejail/network_main.c new file mode 100644 index 000000000..c2459b0cd --- /dev/null +++ b/src/firejail/network_main.c | |||
@@ -0,0 +1,268 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 | |||
21 | #include "firejail.h" | ||
22 | #include <sys/types.h> | ||
23 | #include <sys/stat.h> | ||
24 | #include <unistd.h> | ||
25 | #include <net/if.h> | ||
26 | |||
27 | // configure bridge structure | ||
28 | // - extract ip address and mask from the bridge interface | ||
29 | void net_configure_bridge(Bridge *br, char *dev_name) { | ||
30 | assert(br); | ||
31 | assert(dev_name); | ||
32 | |||
33 | br->dev = dev_name; | ||
34 | |||
35 | // check the bridge device exists | ||
36 | char sysbridge[30 + strlen(br->dev)]; | ||
37 | sprintf(sysbridge, "/sys/class/net/%s/bridge", br->dev); | ||
38 | struct stat s; | ||
39 | int rv = stat(sysbridge, &s); | ||
40 | if (rv == 0) { | ||
41 | // this is a bridge device | ||
42 | br->macvlan = 0; | ||
43 | } | ||
44 | else { | ||
45 | // is this a regular Ethernet interface | ||
46 | if (if_nametoindex(br->dev) > 0) { | ||
47 | br->macvlan = 1; | ||
48 | char *newname; | ||
49 | if (asprintf(&newname, "%s-%u", br->devsandbox, getpid()) == -1) | ||
50 | errExit("asprintf"); | ||
51 | br->devsandbox = newname; | ||
52 | } | ||
53 | else { | ||
54 | fprintf(stderr, "Error: cannot find network device %s\n", br->dev); | ||
55 | exit(1); | ||
56 | } | ||
57 | } | ||
58 | |||
59 | if (net_get_if_addr(br->dev, &br->ip, &br->mask, br->mac)) { | ||
60 | fprintf(stderr, "Error: interface %s is not configured\n", br->dev); | ||
61 | exit(1); | ||
62 | } | ||
63 | if (arg_debug) { | ||
64 | if (br->macvlan == 0) | ||
65 | printf("Bridge device %s at %d.%d.%d.%d/%d\n", | ||
66 | br->dev, PRINT_IP(br->ip), mask2bits(br->mask)); | ||
67 | else | ||
68 | printf("macvlan parent device %s at %d.%d.%d.%d/%d\n", | ||
69 | br->dev, PRINT_IP(br->ip), mask2bits(br->mask)); | ||
70 | } | ||
71 | |||
72 | uint32_t range = ~br->mask + 1; // the number of potential addresses | ||
73 | // this software is not supported for /31 networks | ||
74 | if (range < 4) { | ||
75 | fprintf(stderr, "Error: the software is not supported for /31 networks\n"); | ||
76 | exit(1); | ||
77 | } | ||
78 | br->configured = 1; | ||
79 | } | ||
80 | |||
81 | |||
82 | void net_configure_sandbox_ip(Bridge *br) { | ||
83 | assert(br); | ||
84 | if (br->configured == 0) | ||
85 | return; | ||
86 | |||
87 | if (br->arg_ip_none) | ||
88 | br->ipsandbox = 0; | ||
89 | else if (br->ipsandbox) { | ||
90 | // check network range | ||
91 | char *rv = in_netrange(br->ipsandbox, br->ip, br->mask); | ||
92 | if (rv) { | ||
93 | fprintf(stderr, "%s", rv); | ||
94 | exit(1); | ||
95 | } | ||
96 | // send an ARP request and check if there is anybody on this IP address | ||
97 | if (arp_check(br->dev, br->ipsandbox, br->ip)) { | ||
98 | fprintf(stderr, "Error: IP address %d.%d.%d.%d is already in use\n", PRINT_IP(br->ipsandbox)); | ||
99 | exit(1); | ||
100 | } | ||
101 | } | ||
102 | else | ||
103 | // ip address assigned by arp-scan for a bridge device | ||
104 | br->ipsandbox = arp_assign(br->dev, br); //br->ip, br->mask); | ||
105 | } | ||
106 | |||
107 | |||
108 | // create a veth pair | ||
109 | // - br - bridge device | ||
110 | // - ifname - interface name in sandbox namespace | ||
111 | // - child - child process running the namespace | ||
112 | |||
113 | void net_configure_veth_pair(Bridge *br, const char *ifname, pid_t child) { | ||
114 | assert(br); | ||
115 | if (br->configured == 0) | ||
116 | return; | ||
117 | |||
118 | // create a veth pair | ||
119 | char *dev; | ||
120 | if (asprintf(&dev, "veth%u%s", getpid(), ifname) < 0) | ||
121 | errExit("asprintf"); | ||
122 | net_create_veth(dev, ifname, child); | ||
123 | |||
124 | // bring up the interface | ||
125 | net_if_up(dev); | ||
126 | |||
127 | // add interface to the bridge | ||
128 | net_bridge_add_interface(br->dev, dev); | ||
129 | |||
130 | char *msg; | ||
131 | if (asprintf(&msg, "%d.%d.%d.%d address assigned to sandbox", PRINT_IP(br->ipsandbox)) == -1) | ||
132 | errExit("asprintf"); | ||
133 | logmsg(msg); | ||
134 | fflush(0); | ||
135 | free(msg); | ||
136 | } | ||
137 | |||
138 | // the default address should be in the range of at least on of the bridge devices | ||
139 | void check_default_gw(uint32_t defaultgw) { | ||
140 | assert(defaultgw); | ||
141 | |||
142 | if (cfg.bridge0.configured) { | ||
143 | char *rv = in_netrange(defaultgw, cfg.bridge0.ip, cfg.bridge0.mask); | ||
144 | if (rv == 0) | ||
145 | return; | ||
146 | } | ||
147 | if (cfg.bridge1.configured) { | ||
148 | char *rv = in_netrange(defaultgw, cfg.bridge1.ip, cfg.bridge1.mask); | ||
149 | if (rv == 0) | ||
150 | return; | ||
151 | } | ||
152 | if (cfg.bridge2.configured) { | ||
153 | char *rv = in_netrange(defaultgw, cfg.bridge2.ip, cfg.bridge2.mask); | ||
154 | if (rv == 0) | ||
155 | return; | ||
156 | } | ||
157 | if (cfg.bridge3.configured) { | ||
158 | char *rv = in_netrange(defaultgw, cfg.bridge3.ip, cfg.bridge3.mask); | ||
159 | if (rv == 0) | ||
160 | return; | ||
161 | } | ||
162 | |||
163 | fprintf(stderr, "Error: default gateway %d.%d.%d.%d is not in the range of any network\n", PRINT_IP(defaultgw)); | ||
164 | exit(1); | ||
165 | } | ||
166 | |||
167 | void net_check_cfg(void) { | ||
168 | int net_configured = 0; | ||
169 | if (cfg.bridge0.configured) | ||
170 | net_configured++; | ||
171 | if (cfg.bridge1.configured) | ||
172 | net_configured++; | ||
173 | if (cfg.bridge2.configured) | ||
174 | net_configured++; | ||
175 | if (cfg.bridge3.configured) | ||
176 | net_configured++; | ||
177 | |||
178 | // --defaultgw requires a network | ||
179 | if (cfg.defaultgw && net_configured == 0) { | ||
180 | fprintf(stderr, "Error: option --defaultgw requires at least one network to be configured\n"); | ||
181 | exit(1); | ||
182 | } | ||
183 | |||
184 | if (net_configured == 0) // nothing to check | ||
185 | return; | ||
186 | |||
187 | // --net=none | ||
188 | if (arg_nonetwork && net_configured) { | ||
189 | fprintf(stderr, "Error: --net and --net=none are mutually exclusive\n"); | ||
190 | exit(1); | ||
191 | } | ||
192 | |||
193 | // check default gateway address or assign one | ||
194 | assert(cfg.bridge0.configured); | ||
195 | if (cfg.defaultgw) | ||
196 | check_default_gw(cfg.defaultgw); | ||
197 | else { | ||
198 | // first network is a regular bridge | ||
199 | if (cfg.bridge0.macvlan == 0) | ||
200 | cfg.defaultgw = cfg.bridge0.ip; | ||
201 | // first network is a mac device | ||
202 | else { | ||
203 | // get the host default gw | ||
204 | uint32_t gw = network_get_defaultgw(); | ||
205 | // check the gateway is network range | ||
206 | if (in_netrange(gw, cfg.bridge0.ip, cfg.bridge0.mask)) | ||
207 | gw = 0; | ||
208 | cfg.defaultgw = gw; | ||
209 | } | ||
210 | } | ||
211 | } | ||
212 | |||
213 | |||
214 | |||
215 | void net_dns_print_name(const char *name) { | ||
216 | if (!name || strlen(name) == 0) { | ||
217 | fprintf(stderr, "Error: invalid sandbox name\n"); | ||
218 | exit(1); | ||
219 | } | ||
220 | pid_t pid; | ||
221 | if (name2pid(name, &pid)) { | ||
222 | fprintf(stderr, "Error: cannot find sandbox %s\n", name); | ||
223 | exit(1); | ||
224 | } | ||
225 | |||
226 | net_dns_print(pid); | ||
227 | } | ||
228 | |||
229 | #define MAXBUF 4096 | ||
230 | void net_dns_print(pid_t pid) { | ||
231 | // drop privileges - will not be able to read /etc/resolv.conf for --noroot option | ||
232 | // drop_privs(1); | ||
233 | |||
234 | // if the pid is that of a firejail process, use the pid of the first child process | ||
235 | char *comm = pid_proc_comm(pid); | ||
236 | if (comm) { | ||
237 | // remove \n | ||
238 | char *ptr = strchr(comm, '\n'); | ||
239 | if (ptr) | ||
240 | *ptr = '\0'; | ||
241 | if (strcmp(comm, "firejail") == 0) { | ||
242 | pid_t child; | ||
243 | if (find_child(pid, &child) == 0) { | ||
244 | pid = child; | ||
245 | } | ||
246 | } | ||
247 | free(comm); | ||
248 | } | ||
249 | |||
250 | char *fname; | ||
251 | if (asprintf(&fname, "/proc/%d/root/etc/resolv.conf", pid) == -1) | ||
252 | errExit("asprintf"); | ||
253 | |||
254 | // access /etc/resolv.conf | ||
255 | FILE *fp = fopen(fname, "r"); | ||
256 | if (!fp) { | ||
257 | fprintf(stderr, "Error: cannot access /etc/resolv.conf\n"); | ||
258 | exit(1); | ||
259 | } | ||
260 | |||
261 | char buf[MAXBUF]; | ||
262 | while (fgets(buf, MAXBUF, fp)) | ||
263 | printf("%s", buf); | ||
264 | printf("\n"); | ||
265 | fclose(fp); | ||
266 | free(fname); | ||
267 | exit(0); | ||
268 | } | ||
diff --git a/src/firejail/output.c b/src/firejail/output.c new file mode 100644 index 000000000..32adac108 --- /dev/null +++ b/src/firejail/output.c | |||
@@ -0,0 +1,84 @@ | |||
1 | #include "firejail.h" | ||
2 | #include <sys/types.h> | ||
3 | #include <sys/stat.h> | ||
4 | #include <unistd.h> | ||
5 | |||
6 | void check_output(int argc, char **argv) { | ||
7 | int i; | ||
8 | char *outfile = NULL; | ||
9 | // drop_privs(0); | ||
10 | |||
11 | int found = 0; | ||
12 | for (i = 1; i < argc; i++) { | ||
13 | if (strncmp(argv[i], "--output=", 9) == 0) { | ||
14 | found = 1; | ||
15 | outfile = argv[i] + 9; | ||
16 | |||
17 | // do not accept directories, links, and files with ".." | ||
18 | if (strstr(outfile, "..") || is_link(outfile) || is_dir(outfile)) { | ||
19 | fprintf(stderr, "Error: invalid output file. Links, directories and files with \"..\" are not allowed.\n"); | ||
20 | exit(1); | ||
21 | } | ||
22 | |||
23 | struct stat s; | ||
24 | if (stat(outfile, &s) == 0) { | ||
25 | // check permissions | ||
26 | if (s.st_uid != getuid() || s.st_gid != getgid()) { | ||
27 | fprintf(stderr, "Error: the output file needs to be owned by the current user.\n"); | ||
28 | exit(1); | ||
29 | } | ||
30 | |||
31 | // check hard links | ||
32 | if (s.st_nlink != 1) { | ||
33 | fprintf(stderr, "Error: no hard links allowed.\n"); | ||
34 | exit(1); | ||
35 | } | ||
36 | } | ||
37 | |||
38 | // drop privileges and try to open the file for writing | ||
39 | drop_privs(0); | ||
40 | /* coverity[toctou] */ | ||
41 | FILE *fp = fopen(outfile, "a"); | ||
42 | if (!fp) { | ||
43 | fprintf(stderr, "Error: cannot open output file %s\n", outfile); | ||
44 | exit(1); | ||
45 | } | ||
46 | fclose(fp); | ||
47 | break; | ||
48 | } | ||
49 | } | ||
50 | if (!found) | ||
51 | return; | ||
52 | |||
53 | |||
54 | // build the new command line | ||
55 | int len = 0; | ||
56 | for (i = 0; i < argc; i++) { | ||
57 | len += strlen(argv[i]) + 1; // + ' ' | ||
58 | } | ||
59 | len += 50 + strlen(outfile); // tee command | ||
60 | |||
61 | char *cmd = malloc(len + 1); // + '\0' | ||
62 | if (!cmd) | ||
63 | errExit("malloc"); | ||
64 | |||
65 | char *ptr = cmd; | ||
66 | for (i = 0; i < argc; i++) { | ||
67 | if (strncmp(argv[i], "--output=", 9) == 0) | ||
68 | continue; | ||
69 | ptr += sprintf(ptr, "%s ", argv[i]); | ||
70 | } | ||
71 | sprintf(ptr, "| %s/lib/firejail/ftee %s", PREFIX, outfile); | ||
72 | |||
73 | // run command | ||
74 | char *a[4]; | ||
75 | a[0] = "/bin/bash"; | ||
76 | a[1] = "-c"; | ||
77 | a[2] = cmd; | ||
78 | a[3] = NULL; | ||
79 | |||
80 | execvp(a[0], a); | ||
81 | |||
82 | perror("execvp"); | ||
83 | exit(1); | ||
84 | } | ||
diff --git a/src/firejail/profile.c b/src/firejail/profile.c new file mode 100644 index 000000000..343907584 --- /dev/null +++ b/src/firejail/profile.c | |||
@@ -0,0 +1,444 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 <dirent.h> | ||
22 | #include <sys/stat.h> | ||
23 | |||
24 | #define MAX_READ 8192 // line buffer for profile files | ||
25 | |||
26 | // find and read the profile specified by name from dir directory | ||
27 | int profile_find(const char *name, const char *dir) { | ||
28 | assert(name); | ||
29 | assert(dir); | ||
30 | |||
31 | int rv = 0; | ||
32 | DIR *dp; | ||
33 | char *pname; | ||
34 | if (asprintf(&pname, "%s.profile", name) == -1) | ||
35 | errExit("asprintf"); | ||
36 | |||
37 | dp = opendir (dir); | ||
38 | if (dp != NULL) { | ||
39 | struct dirent *ep; | ||
40 | while ((ep = readdir(dp)) != NULL) { | ||
41 | if (strcmp(ep->d_name, pname) == 0) { | ||
42 | if (arg_debug) | ||
43 | printf("Found %s profile in %s directory\n", name, dir); | ||
44 | char *etcpname; | ||
45 | if (asprintf(&etcpname, "%s/%s", dir, pname) == -1) | ||
46 | errExit("asprintf"); | ||
47 | profile_read(etcpname, NULL, NULL); | ||
48 | free(etcpname); | ||
49 | rv = 1; | ||
50 | break; | ||
51 | } | ||
52 | } | ||
53 | (void) closedir (dp); | ||
54 | } | ||
55 | |||
56 | free(pname); | ||
57 | return rv; | ||
58 | } | ||
59 | |||
60 | |||
61 | //*************************************************** | ||
62 | // run-time profiles | ||
63 | //*************************************************** | ||
64 | static void check_file_name(char *ptr, int lineno) { | ||
65 | if (strncmp(ptr, "${HOME}", 7) == 0) | ||
66 | ptr += 7; | ||
67 | else if (strncmp(ptr, "${PATH}", 7) == 0) | ||
68 | ptr += 7; | ||
69 | |||
70 | int len = strlen(ptr); | ||
71 | // file globbing ('*') is allowed | ||
72 | if (strcspn(ptr, "\\&!?\"'<>%^(){}[];, ") != len) { | ||
73 | if (lineno == 0) | ||
74 | fprintf(stderr, "Error: \"%s\" is an invalid filename\n", ptr); | ||
75 | else | ||
76 | fprintf(stderr, "Error: line %d in the custom profile is invalid\n", lineno); | ||
77 | exit(1); | ||
78 | } | ||
79 | } | ||
80 | |||
81 | |||
82 | // check profile line; if line == 0, this was generated from a command line option | ||
83 | // return 1 if the command is to be added to the linked list of profile commands | ||
84 | // return 0 if the command was already executed inside the function | ||
85 | int profile_check_line(char *ptr, int lineno) { | ||
86 | // seccomp, caps, private, user namespace | ||
87 | if (strcmp(ptr, "noroot") == 0) { | ||
88 | check_user_namespace(); | ||
89 | return 0; | ||
90 | } | ||
91 | else if (strcmp(ptr, "seccomp") == 0) { | ||
92 | arg_seccomp = 1; | ||
93 | return 0; | ||
94 | } | ||
95 | else if (strcmp(ptr, "caps") == 0) { | ||
96 | arg_caps_default_filter = 1; | ||
97 | return 0; | ||
98 | } | ||
99 | else if (strcmp(ptr, "caps.drop all") == 0) { | ||
100 | arg_caps_drop_all = 1; | ||
101 | return 0; | ||
102 | } | ||
103 | else if (strcmp(ptr, "shell none") == 0) { | ||
104 | arg_shell_none = 1; | ||
105 | return 0; | ||
106 | } | ||
107 | else if (strcmp(ptr, "private") == 0) { | ||
108 | arg_private = 1; | ||
109 | return 0; | ||
110 | } | ||
111 | else if (strcmp(ptr, "private-dev") == 0) { | ||
112 | arg_private_dev = 1; | ||
113 | return 0; | ||
114 | } | ||
115 | else if (strcmp(ptr, "nogroups") == 0) { | ||
116 | arg_nogroups = 1; | ||
117 | return 0; | ||
118 | } | ||
119 | else if (strcmp(ptr, "netfilter") == 0) { | ||
120 | arg_netfilter = 1; | ||
121 | return 0; | ||
122 | } | ||
123 | else if (strncmp(ptr, "netfilter ", 10) == 0) { | ||
124 | arg_netfilter = 1; | ||
125 | arg_netfilter_file = strdup(ptr + 10); | ||
126 | if (!arg_netfilter_file) | ||
127 | errExit("strdup"); | ||
128 | check_netfilter_file(arg_netfilter_file); | ||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | // seccomp drop list on top of default list | ||
133 | if (strncmp(ptr, "seccomp ", 8) == 0) { | ||
134 | arg_seccomp = 1; | ||
135 | #ifdef HAVE_SECCOMP | ||
136 | arg_seccomp_list = strdup(ptr + 8); | ||
137 | if (!arg_seccomp_list) | ||
138 | errExit("strdup"); | ||
139 | #endif | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | // seccomp drop list without default list | ||
144 | if (strncmp(ptr, "seccomp.drop ", 13) == 0) { | ||
145 | arg_seccomp = 1; | ||
146 | #ifdef HAVE_SECCOMP | ||
147 | arg_seccomp_list_drop = strdup(ptr + 13); | ||
148 | if (!arg_seccomp_list_drop) | ||
149 | errExit("strdup"); | ||
150 | #endif | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | // seccomp keep list | ||
155 | if (strncmp(ptr, "seccomp.keep ", 13) == 0) { | ||
156 | arg_seccomp = 1; | ||
157 | #ifdef HAVE_SECCOMP | ||
158 | arg_seccomp_list_keep= strdup(ptr + 13); | ||
159 | if (!arg_seccomp_list_keep) | ||
160 | errExit("strdup"); | ||
161 | #endif | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | // caps drop list | ||
166 | if (strncmp(ptr, "caps.drop ", 10) == 0) { | ||
167 | arg_caps_drop = 1; | ||
168 | arg_caps_list = strdup(ptr + 10); | ||
169 | if (!arg_caps_list) | ||
170 | errExit("strdup"); | ||
171 | // verify seccomp list and exit if problems | ||
172 | if (caps_check_list(arg_caps_list, NULL)) | ||
173 | exit(1); | ||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | // caps keep list | ||
178 | if (strncmp(ptr, "caps.keep ", 10) == 0) { | ||
179 | arg_caps_keep = 1; | ||
180 | arg_caps_list = strdup(ptr + 10); | ||
181 | if (!arg_caps_list) | ||
182 | errExit("strdup"); | ||
183 | // verify seccomp list and exit if problems | ||
184 | if (caps_check_list(arg_caps_list, NULL)) | ||
185 | exit(1); | ||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | // dns | ||
190 | if (strncmp(ptr, "dns ", 4) == 0) { | ||
191 | uint32_t dns; | ||
192 | if (atoip(ptr + 4, &dns)) { | ||
193 | fprintf(stderr, "Error: invalid DNS server IP address\n"); | ||
194 | return 1; | ||
195 | } | ||
196 | |||
197 | if (cfg.dns1 == 0) | ||
198 | cfg.dns1 = dns; | ||
199 | else if (cfg.dns2 == 0) | ||
200 | cfg.dns2 = dns; | ||
201 | else if (cfg.dns3 == 0) | ||
202 | cfg.dns3 = dns; | ||
203 | else { | ||
204 | fprintf(stderr, "Error: up to 3 DNS servers can be specified\n"); | ||
205 | return 1; | ||
206 | } | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | // cpu affinity | ||
211 | if (strncmp(ptr, "cpu ", 4) == 0) { | ||
212 | read_cpu_list(ptr + 4); | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | // cgroup | ||
217 | if (strncmp(ptr, "cgroup ", 7) == 0) { | ||
218 | set_cgroup(ptr + 7); | ||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | // private directory | ||
223 | if (strncmp(ptr, "private ", 8) == 0) { | ||
224 | cfg.home_private = ptr + 8; | ||
225 | fs_check_private_dir(); | ||
226 | arg_private = 1; | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | // private list of files and directories | ||
231 | if (strncmp(ptr, "private.keep ", 13) == 0) { | ||
232 | cfg.home_private_keep = ptr + 13; | ||
233 | fs_check_home_list(); | ||
234 | arg_private = 1; | ||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | // filesystem bind | ||
239 | if (strncmp(ptr, "bind ", 5) == 0) { | ||
240 | if (getuid() != 0) { | ||
241 | fprintf(stderr, "Error: --bind option is available only if running as root\n"); | ||
242 | exit(1); | ||
243 | } | ||
244 | |||
245 | // extract two directories | ||
246 | char *dname1 = ptr + 5; | ||
247 | char *dname2 = split_comma(dname1); // this inserts a '0 to separate the two dierctories | ||
248 | if (dname2 == NULL) { | ||
249 | fprintf(stderr, "Error: mising second directory for bind\n"); | ||
250 | exit(1); | ||
251 | } | ||
252 | |||
253 | // check directories | ||
254 | check_file_name(dname1, lineno); | ||
255 | check_file_name(dname2, lineno); | ||
256 | if (strstr(dname1, "..") || strstr(dname2, "..")) { | ||
257 | fprintf(stderr, "Error: invalid file name.\n"); | ||
258 | exit(1); | ||
259 | } | ||
260 | |||
261 | // insert comma back | ||
262 | *(dname2 - 1) = ','; | ||
263 | return 1; | ||
264 | } | ||
265 | |||
266 | // rlimit | ||
267 | if (strncmp(ptr, "rlimit", 6) == 0) { | ||
268 | if (strncmp(ptr, "rlimit-nofile ", 14) == 0) { | ||
269 | ptr += 14; | ||
270 | if (not_unsigned(ptr)) { | ||
271 | fprintf(stderr, "Invalid rlimit option on line %d\n", lineno); | ||
272 | exit(1); | ||
273 | } | ||
274 | sscanf(ptr, "%u", &cfg.rlimit_nofile); | ||
275 | arg_rlimit_nofile = 1; | ||
276 | } | ||
277 | else if (strncmp(ptr, "rlimit-nproc ", 13) == 0) { | ||
278 | ptr += 13; | ||
279 | if (not_unsigned(ptr)) { | ||
280 | fprintf(stderr, "Invalid rlimit option on line %d\n", lineno); | ||
281 | exit(1); | ||
282 | } | ||
283 | sscanf(ptr, "%u", &cfg.rlimit_nproc); | ||
284 | arg_rlimit_nproc = 1; | ||
285 | } | ||
286 | else if (strncmp(ptr, "rlimit-fsize ", 13) == 0) { | ||
287 | ptr += 13; | ||
288 | if (not_unsigned(ptr)) { | ||
289 | fprintf(stderr, "Invalid rlimit option on line %d\n", lineno); | ||
290 | exit(1); | ||
291 | } | ||
292 | sscanf(ptr, "%u", &cfg.rlimit_fsize); | ||
293 | arg_rlimit_fsize = 1; | ||
294 | } | ||
295 | else if (strncmp(ptr, "rlimit-sigpending ", 18) == 0) { | ||
296 | ptr += 18; | ||
297 | if (not_unsigned(ptr)) { | ||
298 | fprintf(stderr, "Invalid rlimit option on line %d\n", lineno); | ||
299 | exit(1); | ||
300 | } | ||
301 | sscanf(ptr, "%u", &cfg.rlimit_sigpending); | ||
302 | arg_rlimit_sigpending = 1; | ||
303 | } | ||
304 | else { | ||
305 | fprintf(stderr, "Invalid rlimit option on line %d\n", lineno); | ||
306 | exit(1); | ||
307 | } | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | // rest of filesystem | ||
313 | if (strncmp(ptr, "blacklist ", 10) == 0) | ||
314 | ptr += 10; | ||
315 | else if (strncmp(ptr, "read-only ", 10) == 0) | ||
316 | ptr += 10; | ||
317 | else if (strncmp(ptr, "tmpfs ", 6) == 0) | ||
318 | ptr += 6; | ||
319 | else { | ||
320 | if (lineno == 0) | ||
321 | fprintf(stderr, "Error: \"%s\" as a command line option is invalid\n", ptr); | ||
322 | else | ||
323 | fprintf(stderr, "Error: line %d in the custom profile is invalid\n", lineno); | ||
324 | exit(1); | ||
325 | } | ||
326 | |||
327 | // some characters just don't belong in filenames | ||
328 | check_file_name(ptr, lineno); | ||
329 | if (strstr(ptr, "..")) { | ||
330 | if (lineno == 0) | ||
331 | fprintf(stderr, "Error: \"%s\" is an invalid filename\n", ptr); | ||
332 | else | ||
333 | fprintf(stderr, "Error: line %d in the custom profile is invalid\n", lineno); | ||
334 | exit(1); | ||
335 | } | ||
336 | return 1; | ||
337 | } | ||
338 | |||
339 | // add a profile entry in cfg.profile list; use str to populate the list | ||
340 | void profile_add(char *str) { | ||
341 | ProfileEntry *prf = malloc(sizeof(ProfileEntry)); | ||
342 | if (!prf) | ||
343 | errExit("malloc"); | ||
344 | prf->next = NULL; | ||
345 | prf->data = str; | ||
346 | |||
347 | // add prf to the list | ||
348 | if (cfg.profile == NULL) { | ||
349 | cfg.profile = prf; | ||
350 | return; | ||
351 | } | ||
352 | ProfileEntry *ptr = cfg.profile; | ||
353 | while (ptr->next != NULL) | ||
354 | ptr = ptr->next; | ||
355 | ptr->next = prf; | ||
356 | } | ||
357 | |||
358 | // read a profile file | ||
359 | static int include_level = 0; | ||
360 | // skip1, skip2 - if the string is found in the line, the line is not interpreted | ||
361 | void profile_read(const char *fname, const char *skip1, const char *skip2) { | ||
362 | // exit program if maximum include level was reached | ||
363 | if (include_level > MAX_INCLUDE_LEVEL) { | ||
364 | fprintf(stderr, "Error: maximum profile include level was reached\n"); | ||
365 | exit(1); | ||
366 | } | ||
367 | |||
368 | if (strlen(fname) == 0) { | ||
369 | fprintf(stderr, "Error: invalid profile file\n"); | ||
370 | exit(1); | ||
371 | } | ||
372 | |||
373 | // open profile file: | ||
374 | FILE *fp = fopen(fname, "r"); | ||
375 | if (fp == NULL) { | ||
376 | fprintf(stderr, "Error: cannot open profile file\n"); | ||
377 | exit(1); | ||
378 | } | ||
379 | |||
380 | fprintf(stderr, "Reading profile %s\n", fname); | ||
381 | |||
382 | // read the file line by line | ||
383 | char buf[MAX_READ + 1]; | ||
384 | int lineno = 0; | ||
385 | while (fgets(buf, MAX_READ, fp)) { | ||
386 | ++lineno; | ||
387 | // remove empty space - ptr in allocated memory | ||
388 | char *ptr = line_remove_spaces(buf); | ||
389 | if (ptr == NULL) | ||
390 | continue; | ||
391 | |||
392 | // comments | ||
393 | if (*ptr == '#' || *ptr == '\0') { | ||
394 | free(ptr); | ||
395 | continue; | ||
396 | } | ||
397 | |||
398 | // process include | ||
399 | if (strncmp(ptr, "include ", 8) == 0) { | ||
400 | include_level++; | ||
401 | |||
402 | // extract profile filename and new skip params | ||
403 | char *newprofile = ptr + 8; // profile name | ||
404 | char *newskip1 = NULL; // new skip1 | ||
405 | char *newskip2 = NULL; // new skip2 | ||
406 | char *p = newprofile; | ||
407 | while (*p != '\0') { | ||
408 | if (*p == ' ') { | ||
409 | *p = '\0'; | ||
410 | if (newskip1 == NULL) | ||
411 | newskip1 = p + 1; | ||
412 | else if (newskip2 == NULL) | ||
413 | newskip2 = p + 1; | ||
414 | } | ||
415 | p++; | ||
416 | } | ||
417 | |||
418 | // recursivity | ||
419 | profile_read(newprofile, newskip1, newskip2); | ||
420 | include_level--; | ||
421 | free(ptr); | ||
422 | continue; | ||
423 | } | ||
424 | |||
425 | // skip | ||
426 | if (skip1) { | ||
427 | if (strstr(ptr, skip1)) { | ||
428 | free(ptr); | ||
429 | continue; | ||
430 | } | ||
431 | } | ||
432 | if (skip2) { | ||
433 | if (strstr(ptr, skip2)) { | ||
434 | free(ptr); | ||
435 | continue; | ||
436 | } | ||
437 | } | ||
438 | |||
439 | // verify syntax, exit in case of error | ||
440 | if (profile_check_line(ptr, lineno)) | ||
441 | profile_add(ptr); | ||
442 | } | ||
443 | fclose(fp); | ||
444 | } | ||
diff --git a/src/firejail/restricted_shell.c b/src/firejail/restricted_shell.c new file mode 100644 index 000000000..ba3aae759 --- /dev/null +++ b/src/firejail/restricted_shell.c | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 | |||
22 | #define MAX_READ 4096 // maximum line length | ||
23 | char *restricted_user = NULL; | ||
24 | |||
25 | |||
26 | int restricted_shell(const char *user) { | ||
27 | assert(user); | ||
28 | |||
29 | // open profile file: | ||
30 | FILE *fp = fopen("/etc/firejail/login.users", "r"); | ||
31 | if (fp == NULL) | ||
32 | return 0; | ||
33 | |||
34 | int lineno = 0; | ||
35 | char buf[MAX_READ]; | ||
36 | while (fgets(buf, MAX_READ, fp)) { | ||
37 | lineno++; | ||
38 | |||
39 | // remove empty spaces at the beginning of the line | ||
40 | char *ptr = buf; | ||
41 | while (*ptr == ' ' || *ptr == '\t') { | ||
42 | ptr++; | ||
43 | } | ||
44 | if (*ptr == '\n' || *ptr == '#') | ||
45 | continue; | ||
46 | |||
47 | // parse line | ||
48 | char *usr = ptr; | ||
49 | char *args = strchr(usr, ':'); | ||
50 | if (args == NULL) { | ||
51 | fprintf(stderr, "Error: users.conf line %d\n", lineno); | ||
52 | exit(1); | ||
53 | } | ||
54 | *args = '\0'; | ||
55 | args++; | ||
56 | ptr = strchr(args, '\n'); | ||
57 | if (ptr) | ||
58 | *ptr = '\0'; | ||
59 | |||
60 | if (strcmp(user, usr) == 0) { | ||
61 | restricted_user = strdup(user); | ||
62 | // extract program arguments | ||
63 | |||
64 | fullargv[0] = "firejail"; | ||
65 | int i; | ||
66 | ptr = args; | ||
67 | for (i = 1; i < MAX_ARGS; i++) { | ||
68 | fullargv[i] = ptr; | ||
69 | while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0') | ||
70 | ptr++; | ||
71 | if (*ptr != '\0') { | ||
72 | *ptr ='\0'; | ||
73 | fullargv[i] = strdup(fullargv[i]); | ||
74 | if (fullargv[i] == NULL) { | ||
75 | fprintf(stderr, "Error: cannot allocate memory\n"); | ||
76 | exit(1); | ||
77 | } | ||
78 | ptr++; | ||
79 | while (*ptr == ' ' || *ptr == '\t') | ||
80 | ptr++; | ||
81 | if (*ptr != '\0') | ||
82 | continue; | ||
83 | } | ||
84 | fullargv[i] = strdup(fullargv[i]); | ||
85 | fclose(fp); | ||
86 | return i + 1; | ||
87 | } | ||
88 | fprintf(stderr, "Error: too many program arguments in users.conf line %d\n", lineno); | ||
89 | exit(1); | ||
90 | } | ||
91 | } | ||
92 | fclose(fp); | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
diff --git a/src/firejail/rlimit.c b/src/firejail/rlimit.c new file mode 100644 index 000000000..6c755a08d --- /dev/null +++ b/src/firejail/rlimit.c | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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/time.h> | ||
22 | #include <sys/resource.h> | ||
23 | |||
24 | void set_rlimits(void) { | ||
25 | // resource limits | ||
26 | struct rlimit rl; | ||
27 | if (arg_rlimit_nofile) { | ||
28 | rl.rlim_cur = (rlim_t) cfg.rlimit_nofile; | ||
29 | rl.rlim_max = (rlim_t) cfg.rlimit_nofile; | ||
30 | if (setrlimit(RLIMIT_NOFILE, &rl) == -1) | ||
31 | errExit("setrlimit"); | ||
32 | if (arg_debug) | ||
33 | printf("Config rlimit: number of open file descriptors %u\n", cfg.rlimit_nofile); | ||
34 | } | ||
35 | |||
36 | if (arg_rlimit_nproc) { | ||
37 | rl.rlim_cur = (rlim_t) cfg.rlimit_nproc; | ||
38 | rl.rlim_max = (rlim_t) cfg.rlimit_nproc; | ||
39 | if (setrlimit(RLIMIT_NPROC, &rl) == -1) | ||
40 | errExit("setrlimit"); | ||
41 | if (arg_debug) | ||
42 | printf("Config rlimit: number of processes %u\n", cfg.rlimit_nproc); | ||
43 | } | ||
44 | |||
45 | if (arg_rlimit_fsize) { | ||
46 | rl.rlim_cur = (rlim_t) cfg.rlimit_fsize; | ||
47 | rl.rlim_max = (rlim_t) cfg.rlimit_fsize; | ||
48 | if (setrlimit(RLIMIT_FSIZE, &rl) == -1) | ||
49 | errExit("setrlimit"); | ||
50 | if (arg_debug) | ||
51 | printf("Config rlimit: maximum file size %u\n", cfg.rlimit_fsize); | ||
52 | } | ||
53 | |||
54 | if (arg_rlimit_sigpending) { | ||
55 | rl.rlim_cur = (rlim_t) cfg.rlimit_sigpending; | ||
56 | rl.rlim_max = (rlim_t) cfg.rlimit_sigpending; | ||
57 | if (setrlimit(RLIMIT_SIGPENDING, &rl) == -1) | ||
58 | errExit("setrlimit"); | ||
59 | if (arg_debug) | ||
60 | printf("Config rlimit: maximum number of signals pending %u\n", cfg.rlimit_sigpending); | ||
61 | } | ||
62 | } | ||
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c new file mode 100644 index 000000000..3f5fb51fa --- /dev/null +++ b/src/firejail/sandbox.c | |||
@@ -0,0 +1,490 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 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 | |||
21 | #include "firejail.h" | ||
22 | #include <sys/mount.h> | ||
23 | #include <sys/wait.h> | ||
24 | #include <sys/stat.h> | ||
25 | #include <sys/prctl.h> | ||
26 | #include <sys/time.h> | ||
27 | #include <sys/resource.h> | ||
28 | |||
29 | #include <sched.h> | ||
30 | #ifndef CLONE_NEWUSER | ||
31 | #define CLONE_NEWUSER 0x10000000 | ||
32 | #endif | ||
33 | |||
34 | static void set_caps(void) { | ||
35 | if (arg_caps_drop_all) | ||
36 | caps_drop_all(); | ||
37 | else if (arg_caps_drop) | ||
38 | caps_drop_list(arg_caps_list); | ||
39 | else if (arg_caps_keep) | ||
40 | caps_keep_list(arg_caps_list); | ||
41 | else if (arg_caps_default_filter) | ||
42 | caps_default_filter(); | ||
43 | } | ||
44 | |||
45 | void save_nogroups(void) { | ||
46 | if (arg_nogroups == 0) | ||
47 | return; | ||
48 | |||
49 | char *fname; | ||
50 | if (asprintf(&fname, "%s/groups", MNT_DIR) == -1) | ||
51 | errExit("asprintf"); | ||
52 | FILE *fp = fopen(fname, "w"); | ||
53 | if (fp) { | ||
54 | fprintf(fp, "\n"); | ||
55 | fclose(fp); | ||
56 | if (chown(fname, 0, 0) < 0) | ||
57 | errExit("chown"); | ||
58 | } | ||
59 | else { | ||
60 | fprintf(stderr, "Error: cannot save nogroups state\n"); | ||
61 | free(fname); | ||
62 | exit(1); | ||
63 | } | ||
64 | |||
65 | free(fname); | ||
66 | } | ||
67 | |||
68 | static void sandbox_if_up(Bridge *br) { | ||
69 | assert(br); | ||
70 | if (!br->configured) | ||
71 | return; | ||
72 | |||
73 | char *dev = br->devsandbox; | ||
74 | net_if_up(dev); | ||
75 | |||
76 | if (br->arg_ip_none == 1); // do nothing | ||
77 | else if (br->arg_ip_none == 0 && br->macvlan == 0) { | ||
78 | if (br->ipsandbox == br->ip) { | ||
79 | fprintf(stderr, "Error: %d.%d.%d.%d is interface %s address.\n", PRINT_IP(br->ipsandbox), br->dev); | ||
80 | exit(1); | ||
81 | } | ||
82 | |||
83 | // just assign the address | ||
84 | assert(br->ipsandbox); | ||
85 | if (arg_debug) | ||
86 | printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev); | ||
87 | net_if_ip(dev, br->ipsandbox, br->mask); | ||
88 | net_if_up(dev); | ||
89 | } | ||
90 | else if (br->arg_ip_none == 0 && br->macvlan == 1) { | ||
91 | // reassign the macvlan address | ||
92 | if (br->ipsandbox == 0) | ||
93 | // ip address assigned by arp-scan for a macvlan device | ||
94 | br->ipsandbox = arp_assign(dev, br); //br->ip, br->mask); | ||
95 | else { | ||
96 | if (br->ipsandbox == br->ip) { | ||
97 | fprintf(stderr, "Error: %d.%d.%d.%d is interface %s address.\n", PRINT_IP(br->ipsandbox), br->dev); | ||
98 | exit(1); | ||
99 | } | ||
100 | |||
101 | uint32_t rv = arp_check(dev, br->ipsandbox, br->ip); | ||
102 | if (rv) { | ||
103 | fprintf(stderr, "Error: the address %d.%d.%d.%d is already in use.\n", PRINT_IP(br->ipsandbox)); | ||
104 | exit(1); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | if (arg_debug) | ||
109 | printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev); | ||
110 | net_if_ip(dev, br->ipsandbox, br->mask); | ||
111 | net_if_up(dev); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | static void chk_chroot(void) { | ||
116 | // if we are starting firejail inside some other container technology, we don't care about this | ||
117 | char *mycont = getenv("container"); | ||
118 | if (mycont) | ||
119 | return; | ||
120 | |||
121 | // check if this is a regular chroot | ||
122 | struct stat s; | ||
123 | if (stat("/", &s) == 0) { | ||
124 | if (s.st_ino != 2) | ||
125 | return; | ||
126 | } | ||
127 | |||
128 | fprintf(stderr, "Error: cannot mount filesystem as slave\n"); | ||
129 | exit(1); | ||
130 | } | ||
131 | |||
132 | int sandbox(void* sandbox_arg) { | ||
133 | pid_t child_pid = getpid(); | ||
134 | if (arg_debug) | ||
135 | printf("Initializing child process\n"); | ||
136 | |||
137 | // close each end of the unused pipes | ||
138 | close(parent_to_child_fds[1]); | ||
139 | close(child_to_parent_fds[0]); | ||
140 | |||
141 | // wait for parent to do base setup | ||
142 | wait_for_other(parent_to_child_fds[0]); | ||
143 | |||
144 | if (arg_debug && child_pid == 1) | ||
145 | printf("PID namespace installed\n"); | ||
146 | |||
147 | //**************************** | ||
148 | // set hostname | ||
149 | //**************************** | ||
150 | if (cfg.hostname) { | ||
151 | if (sethostname(cfg.hostname, strlen(cfg.hostname)) < 0) | ||
152 | errExit("sethostname"); | ||
153 | } | ||
154 | |||
155 | //**************************** | ||
156 | // mount namespace | ||
157 | //**************************** | ||
158 | // mount events are not forwarded between the host the sandbox | ||
159 | if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0) { | ||
160 | chk_chroot(); | ||
161 | } | ||
162 | |||
163 | //**************************** | ||
164 | // netfilter | ||
165 | //**************************** | ||
166 | if (arg_netfilter && any_bridge_configured()) { // assuming by default the client filter | ||
167 | netfilter(arg_netfilter_file); | ||
168 | } | ||
169 | |||
170 | //**************************** | ||
171 | // trace pre-install | ||
172 | //**************************** | ||
173 | if (arg_trace) | ||
174 | fs_trace_preload(); | ||
175 | |||
176 | //**************************** | ||
177 | // configure filesystem | ||
178 | //**************************** | ||
179 | #ifdef HAVE_CHROOT | ||
180 | if (cfg.chrootdir) { | ||
181 | fs_chroot(cfg.chrootdir); | ||
182 | // force caps and seccomp if not started as root | ||
183 | if (getuid() != 0) { | ||
184 | // force default seccomp inside the chroot, no keep or drop list | ||
185 | // the list build on top of the default drop list is kept intact | ||
186 | arg_seccomp = 1; | ||
187 | if (arg_seccomp_list_drop) { | ||
188 | free(arg_seccomp_list_drop); | ||
189 | arg_seccomp_list_drop = NULL; | ||
190 | } | ||
191 | if (arg_seccomp_list_keep) { | ||
192 | free(arg_seccomp_list_keep); | ||
193 | arg_seccomp_list_keep = NULL; | ||
194 | } | ||
195 | |||
196 | // disable all capabilities | ||
197 | if (arg_caps_default_filter || arg_caps_list) | ||
198 | fprintf(stderr, "Warning: all capabilities disabled for a regular user during chroot\n"); | ||
199 | arg_caps_drop_all = 1; | ||
200 | |||
201 | // drop all supplementary groups; /etc/group file inside chroot | ||
202 | // is controlled by a regular usr | ||
203 | arg_nogroups = 1; | ||
204 | printf("Dropping all Linux capabilities and enforcing default seccomp filter\n"); | ||
205 | } | ||
206 | |||
207 | //**************************** | ||
208 | // trace pre-install, this time inside chroot | ||
209 | //**************************** | ||
210 | if (arg_trace) | ||
211 | fs_trace_preload(); | ||
212 | } | ||
213 | else | ||
214 | #endif | ||
215 | if (arg_overlay) | ||
216 | fs_overlayfs(); | ||
217 | else | ||
218 | fs_basic_fs(); | ||
219 | |||
220 | |||
221 | //**************************** | ||
222 | // set hostname in /etc/hostname | ||
223 | //**************************** | ||
224 | if (cfg.hostname) { | ||
225 | fs_hostname(cfg.hostname); | ||
226 | } | ||
227 | |||
228 | //**************************** | ||
229 | // apply the profile file | ||
230 | //**************************** | ||
231 | if (cfg.profile) | ||
232 | fs_blacklist(cfg.homedir); | ||
233 | |||
234 | //**************************** | ||
235 | // private mode | ||
236 | //**************************** | ||
237 | if (arg_private) { | ||
238 | if (cfg.home_private) // --private= | ||
239 | fs_private_homedir(); | ||
240 | else if (cfg.home_private_keep) // --private.keep= | ||
241 | fs_private_home_list(); | ||
242 | else // --private | ||
243 | fs_private(); | ||
244 | } | ||
245 | |||
246 | if (arg_private_dev) | ||
247 | fs_private_dev(); | ||
248 | |||
249 | //**************************** | ||
250 | // install trace | ||
251 | //**************************** | ||
252 | if (arg_trace) | ||
253 | fs_trace(); | ||
254 | |||
255 | //**************************** | ||
256 | // update /proc, /dev, /boot directorymy | ||
257 | //**************************** | ||
258 | fs_proc_sys_dev_boot(); | ||
259 | |||
260 | //**************************** | ||
261 | // networking | ||
262 | //**************************** | ||
263 | if (arg_nonetwork) { | ||
264 | net_if_up("lo"); | ||
265 | } | ||
266 | else if (any_bridge_configured()) { | ||
267 | // configure lo and eth0...eth3 | ||
268 | net_if_up("lo"); | ||
269 | |||
270 | if (mac_not_zero(cfg.bridge0.macsandbox)) | ||
271 | net_config_mac(cfg.bridge0.devsandbox, cfg.bridge0.macsandbox); | ||
272 | sandbox_if_up(&cfg.bridge0); | ||
273 | |||
274 | if (mac_not_zero(cfg.bridge1.macsandbox)) | ||
275 | net_config_mac(cfg.bridge1.devsandbox, cfg.bridge1.macsandbox); | ||
276 | sandbox_if_up(&cfg.bridge1); | ||
277 | |||
278 | if (mac_not_zero(cfg.bridge2.macsandbox)) | ||
279 | net_config_mac(cfg.bridge2.devsandbox, cfg.bridge2.macsandbox); | ||
280 | sandbox_if_up(&cfg.bridge2); | ||
281 | |||
282 | if (mac_not_zero(cfg.bridge3.macsandbox)) | ||
283 | net_config_mac(cfg.bridge3.devsandbox, cfg.bridge3.macsandbox); | ||
284 | sandbox_if_up(&cfg.bridge3); | ||
285 | |||
286 | // add a default route | ||
287 | if (cfg.defaultgw) { | ||
288 | // set the default route | ||
289 | if (net_add_route(0, 0, cfg.defaultgw)) | ||
290 | fprintf(stderr, "Warning: cannot configure default route\n"); | ||
291 | } | ||
292 | |||
293 | if (arg_debug) | ||
294 | printf("Network namespace enabled\n"); | ||
295 | } | ||
296 | |||
297 | // if any dns server is configured, it is time to set it now | ||
298 | fs_resolvconf(); | ||
299 | |||
300 | // print network configuration | ||
301 | if (any_bridge_configured() || cfg.defaultgw || cfg.dns1) { | ||
302 | printf("\n"); | ||
303 | if (any_bridge_configured()) | ||
304 | net_ifprint(); | ||
305 | if (cfg.defaultgw != 0) | ||
306 | printf("Default gateway %d.%d.%d.%d\n", PRINT_IP(cfg.defaultgw)); | ||
307 | if (cfg.dns1 != 0) | ||
308 | printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns1)); | ||
309 | if (cfg.dns2 != 0) | ||
310 | printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns2)); | ||
311 | if (cfg.dns3 != 0) | ||
312 | printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns3)); | ||
313 | printf("\n"); | ||
314 | } | ||
315 | |||
316 | |||
317 | |||
318 | //**************************** | ||
319 | // start executable | ||
320 | //**************************** | ||
321 | prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); // kill the child in case the parent died | ||
322 | int cwd = 0; | ||
323 | if (cfg.cwd) { | ||
324 | if (chdir(cfg.cwd) == 0) | ||
325 | cwd = 1; | ||
326 | } | ||
327 | |||
328 | if (!cwd) { | ||
329 | if (chdir("/") < 0) | ||
330 | errExit("chdir"); | ||
331 | if (cfg.homedir) { | ||
332 | struct stat s; | ||
333 | if (stat(cfg.homedir, &s) == 0) { | ||
334 | /* coverity[toctou] */ | ||
335 | if (chdir(cfg.homedir) < 0) | ||
336 | errExit("chdir"); | ||
337 | } | ||
338 | } | ||
339 | } | ||
340 | |||
341 | // set environment | ||
342 | // fix qt 4.8 | ||
343 | if (setenv("QT_X11_NO_MITSHM", "1", 1) < 0) | ||
344 | errExit("setenv"); | ||
345 | if (setenv("container", "firejail", 1) < 0) // LXC sets container=lxc, | ||
346 | errExit("setenv"); | ||
347 | if (arg_zsh && setenv("SHELL", "/usr/bin/zsh", 1) < 0) | ||
348 | errExit("setenv"); | ||
349 | if (arg_csh && setenv("SHELL", "/bin/csh", 1) < 0) | ||
350 | errExit("setenv"); | ||
351 | if (cfg.shell && setenv("SHELL", cfg.shell, 1) < 0) | ||
352 | errExit("setenv"); | ||
353 | // set prompt color to green | ||
354 | //export PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\] ' | ||
355 | if (setenv("PROMPT_COMMAND", "export PS1=\"\\[\\e[1;32m\\][\\u@\\h \\W]\\$\\[\\e[0m\\] \"", 1) < 0) | ||
356 | errExit("setenv"); | ||
357 | |||
358 | |||
359 | // set capabilities | ||
360 | if (!arg_noroot) | ||
361 | set_caps(); | ||
362 | |||
363 | // set rlimits | ||
364 | set_rlimits(); | ||
365 | |||
366 | // set seccomp | ||
367 | #ifdef HAVE_SECCOMP | ||
368 | // if a keep list is available, disregard the drop list | ||
369 | if (arg_seccomp == 1) { | ||
370 | if (arg_seccomp_list_keep) | ||
371 | seccomp_filter_keep(); // this will also save the fmyilter to MNT_DIR/seccomp file | ||
372 | else | ||
373 | seccomp_filter_drop(); // this will also save the filter to MNT_DIR/seccomp file | ||
374 | } | ||
375 | #endif | ||
376 | |||
377 | // set cpu affinity | ||
378 | if (cfg.cpus) { | ||
379 | save_cpu(); // save cpu affinity mask to MNT_DIR/cpu file | ||
380 | set_cpu_affinity(); | ||
381 | } | ||
382 | |||
383 | // save cgroup in MNT_DIR/cgroup file | ||
384 | if (cfg.cgroup) | ||
385 | save_cgroup(); | ||
386 | |||
387 | //**************************************** | ||
388 | // drop privileges or create a new user namespace | ||
389 | //**************************************** | ||
390 | save_nogroups(); | ||
391 | if (arg_noroot) { | ||
392 | int rv = unshare(CLONE_NEWUSER); | ||
393 | if (rv == -1) { | ||
394 | fprintf(stderr, "Warning: cannot mount a new user namespace\n"); | ||
395 | perror("unshare"); | ||
396 | drop_privs(arg_nogroups); | ||
397 | } | ||
398 | } | ||
399 | else | ||
400 | drop_privs(arg_nogroups); | ||
401 | |||
402 | // notify parent that new user namespace has been created so a proper | ||
403 | // UID/GID map can be setup | ||
404 | notify_other(child_to_parent_fds[1]); | ||
405 | close(child_to_parent_fds[1]); | ||
406 | |||
407 | // wait for parent to finish setting up a proper UID/GID map | ||
408 | wait_for_other(parent_to_child_fds[0]); | ||
409 | close(parent_to_child_fds[0]); | ||
410 | |||
411 | // somehow, the new user namespace resets capabilities; | ||
412 | // we need to do them again | ||
413 | if (arg_noroot) { | ||
414 | set_caps(); | ||
415 | if (arg_debug) | ||
416 | printf("User namespace (noroot) installed\n"); | ||
417 | } | ||
418 | |||
419 | |||
420 | //**************************************** | ||
421 | // start the program without using a shell | ||
422 | //**************************************** | ||
423 | if (arg_shell_none) { | ||
424 | if (arg_debug) { | ||
425 | int i; | ||
426 | for (i = cfg.original_program_index; i < cfg.original_argc; i++) { | ||
427 | if (cfg.original_argv[i] == NULL) | ||
428 | break; | ||
429 | printf("execvp argument %d: %s\n", i - cfg.original_program_index, cfg.original_argv[i]); | ||
430 | } | ||
431 | } | ||
432 | |||
433 | if (!arg_command) | ||
434 | printf("Child process initialized\n"); | ||
435 | execvp(cfg.original_argv[cfg.original_program_index], &cfg.original_argv[cfg.original_program_index + 1]); | ||
436 | } | ||
437 | //**************************************** | ||
438 | // start the program using a shell | ||
439 | //**************************************** | ||
440 | else { | ||
441 | // choose the shell requested by the user, or use bash as default | ||
442 | char *sh; | ||
443 | if (cfg.shell) | ||
444 | sh = cfg.shell; | ||
445 | else if (arg_zsh) | ||
446 | sh = "/usr/bin/zsh"; | ||
447 | else if (arg_csh) | ||
448 | sh = "/bin/csh"; | ||
449 | else | ||
450 | sh = "/bin/bash"; | ||
451 | |||
452 | char *arg[5]; | ||
453 | int index = 0; | ||
454 | arg[index++] = sh; | ||
455 | arg[index++] = "-c"; | ||
456 | assert(cfg.command_line); | ||
457 | if (arg_debug) | ||
458 | printf("Starting %s\n", cfg.command_line); | ||
459 | if (arg_doubledash) | ||
460 | arg[index++] = "--"; | ||
461 | arg[index++] = cfg.command_line; | ||
462 | arg[index] = NULL; | ||
463 | assert(index < 5); | ||
464 | |||
465 | if (arg_debug) { | ||
466 | char *msg; | ||
467 | if (asprintf(&msg, "sandbox %d, execvp into %s", sandbox_pid, cfg.command_line) == -1) | ||
468 | errExit("asprintf"); | ||
469 | logmsg(msg); | ||
470 | free(msg); | ||
471 | } | ||
472 | |||
473 | if (arg_debug) { | ||
474 | int i; | ||
475 | for (i = 0; i < 5; i++) { | ||
476 | if (arg[i] == NULL) | ||
477 | break; | ||
478 | printf("execvp argument %d: %s\n", i, arg[i]); | ||
479 | } | ||
480 | } | ||
481 | |||
482 | if (!arg_command) | ||
483 | printf("Child process initialized\n"); | ||
484 | execvp(sh, arg); | ||
485 | } | ||
486 | |||
487 | |||
488 | perror("execvp"); | ||
489 | return 0; | ||
490 | } | ||
diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c new file mode 100644 index 000000000..c03eb6848 --- /dev/null +++ b/src/firejail/seccomp.c | |||
@@ -0,0 +1,658 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 | |||
21 | /* default seccomp filter | ||
22 | // seccomp | ||
23 | struct sock_filter filter[] = { | ||
24 | VALIDATE_ARCHITECTURE, | ||
25 | EXAMINE_SYSCALL, | ||
26 | BLACKLIST(SYS_mount), // mount/unmount filesystems | ||
27 | BLACKLIST(SYS_umount2), | ||
28 | BLACKLIST(SYS_ptrace), // trace processes | ||
29 | BLACKLIST(SYS_kexec_load), // loading a different kernel | ||
30 | BLACKLIST(SYS_open_by_handle_at), // open by handle | ||
31 | BLACKLIST(SYS_init_module), // kernel module handling | ||
32 | #ifdef SYS_finit_module // introduced in 2013 | ||
33 | BLACKLIST(SYS_finit_module), | ||
34 | #endif | ||
35 | BLACKLIST(SYS_delete_module), | ||
36 | BLACKLIST(SYS_iopl), // io permisions | ||
37 | #ifdef SYS_ioperm | ||
38 | BLACKLIST(SYS_ioperm), | ||
39 | #endif | ||
40 | SYS_iopl | ||
41 | BLACKLIST(SYS_iopl), // io permisions | ||
42 | #endif | ||
43 | #ifdef SYS_ni_syscall), // new io permisions call on arm devices | ||
44 | BLACKLIST(SYS_ni_syscall), | ||
45 | #endif | ||
46 | BLACKLIST(SYS_swapon), // swap on/off | ||
47 | BLACKLIST(SYS_swapoff), | ||
48 | BLACKLIST(SYS_syslog), // kernel printk control | ||
49 | RETURN_ALLOW | ||
50 | }; | ||
51 | */ | ||
52 | #ifdef HAVE_SECCOMP | ||
53 | #include "firejail.h" | ||
54 | #include <errno.h> | ||
55 | #include <linux/filter.h> | ||
56 | #include <sys/syscall.h> | ||
57 | #include <linux/capability.h> | ||
58 | #include <linux/audit.h> | ||
59 | #include <sys/stat.h> | ||
60 | #include <fcntl.h> | ||
61 | |||
62 | #include <sys/prctl.h> | ||
63 | #ifndef PR_SET_NO_NEW_PRIVS | ||
64 | # define PR_SET_NO_NEW_PRIVS 38 | ||
65 | #endif | ||
66 | |||
67 | #if HAVE_SECCOMP_H | ||
68 | #include <linux/seccomp.h> | ||
69 | #else | ||
70 | #define SECCOMP_MODE_FILTER 2 | ||
71 | #define SECCOMP_RET_KILL 0x00000000U | ||
72 | #define SECCOMP_RET_TRAP 0x00030000U | ||
73 | #define SECCOMP_RET_ALLOW 0x7fff0000U | ||
74 | #define SECCOMP_RET_ERRNO 0x00050000U | ||
75 | #define SECCOMP_RET_DATA 0x0000ffffU | ||
76 | struct seccomp_data { | ||
77 | int nr; | ||
78 | __u32 arch; | ||
79 | __u64 instruction_pointer; | ||
80 | __u64 args[6]; | ||
81 | }; | ||
82 | #endif | ||
83 | |||
84 | #if defined(__i386__) | ||
85 | # define ARCH_NR AUDIT_ARCH_I386 | ||
86 | #elif defined(__x86_64__) | ||
87 | # define ARCH_NR AUDIT_ARCH_X86_64 | ||
88 | #elif defined(__arm__) | ||
89 | # define ARCH_NR AUDIT_ARCH_ARM | ||
90 | #else | ||
91 | # warning "Platform does not support seccomp filter yet" | ||
92 | # define ARCH_NR 0 | ||
93 | #endif | ||
94 | |||
95 | |||
96 | #define VALIDATE_ARCHITECTURE \ | ||
97 | BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, arch))), \ | ||
98 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \ | ||
99 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) | ||
100 | |||
101 | #define EXAMINE_SYSCALL BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ | ||
102 | (offsetof(struct seccomp_data, nr))) | ||
103 | |||
104 | #define BLACKLIST(syscall_nr) \ | ||
105 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), \ | ||
106 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) | ||
107 | |||
108 | #define WHITELIST(syscall_nr) \ | ||
109 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), \ | ||
110 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) | ||
111 | |||
112 | #define RETURN_ALLOW \ | ||
113 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) | ||
114 | |||
115 | #define KILL_PROCESS \ | ||
116 | BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) | ||
117 | |||
118 | #define SECSIZE 128 // initial filter size | ||
119 | static struct sock_filter *sfilter = NULL; | ||
120 | static int sfilter_alloc_size = 0; | ||
121 | static int sfilter_index = 0; | ||
122 | |||
123 | // debug filter | ||
124 | void filter_debug(void) { | ||
125 | // start filter | ||
126 | struct sock_filter filter[] = { | ||
127 | VALIDATE_ARCHITECTURE, | ||
128 | EXAMINE_SYSCALL | ||
129 | }; | ||
130 | |||
131 | // print sizes | ||
132 | printf("SECCOMP Filter:\n"); | ||
133 | if (sfilter == NULL) { | ||
134 | printf("SECCOMP filter not allocated\n"); | ||
135 | return; | ||
136 | } | ||
137 | if (sfilter_index < 4) | ||
138 | return; | ||
139 | |||
140 | // test the start of the filter | ||
141 | if (memcmp(sfilter, filter, sizeof(filter)) == 0) { | ||
142 | printf(" VALIDATE_ARCHITECTURE\n"); | ||
143 | printf(" EXAMINE_SYSCAL\n"); | ||
144 | } | ||
145 | |||
146 | // loop trough blacklists | ||
147 | int i = 4; | ||
148 | while (i < sfilter_index) { | ||
149 | // minimal parsing! | ||
150 | unsigned char *ptr = (unsigned char *) &sfilter[i]; | ||
151 | int *nr = (int *) (ptr + 4); | ||
152 | if (*ptr == 0x15 && *(ptr +14) == 0xff && *(ptr + 15) == 0x7f ) { | ||
153 | printf(" WHITELIST %d %s\n", *nr, syscall_find_nr(*nr)); | ||
154 | i += 2; | ||
155 | } | ||
156 | else if (*ptr == 0x15 && *(ptr +14) == 0 && *(ptr + 15) == 0) { | ||
157 | printf(" BLACKLIST %d %s\n", *nr, syscall_find_nr(*nr)); | ||
158 | i += 2; | ||
159 | } | ||
160 | else if (*ptr == 0x06 && *(ptr +6) == 0 && *(ptr + 7) == 0 ) { | ||
161 | printf(" KILL_PROCESS\n"); | ||
162 | i++; | ||
163 | } | ||
164 | else if (*ptr == 0x06 && *(ptr +6) == 0xff && *(ptr + 7) == 0x7f ) { | ||
165 | printf(" RETURN_ALLOW\n"); | ||
166 | i++; | ||
167 | } | ||
168 | else { | ||
169 | printf(" UNKNOWN ENTRY!!!\n"); | ||
170 | i++; | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | |||
175 | // initialize filter | ||
176 | static void filter_init(void) { | ||
177 | if (sfilter) { | ||
178 | assert(0); | ||
179 | return; | ||
180 | } | ||
181 | |||
182 | if (arg_debug) | ||
183 | printf("Initialize seccomp filter\n"); | ||
184 | // allocate a filter of SECSIZE | ||
185 | sfilter = malloc(sizeof(struct sock_filter) * SECSIZE); | ||
186 | if (!sfilter) | ||
187 | errExit("malloc"); | ||
188 | memset(sfilter, 0, sizeof(struct sock_filter) * SECSIZE); | ||
189 | sfilter_alloc_size = SECSIZE; | ||
190 | |||
191 | // copy the start entries | ||
192 | struct sock_filter filter[] = { | ||
193 | VALIDATE_ARCHITECTURE, | ||
194 | EXAMINE_SYSCALL | ||
195 | }; | ||
196 | sfilter_index = sizeof(filter) / sizeof(struct sock_filter); | ||
197 | memcpy(sfilter, filter, sizeof(filter)); | ||
198 | } | ||
199 | |||
200 | static void filter_realloc(void) { | ||
201 | assert(sfilter); | ||
202 | assert(sfilter_alloc_size); | ||
203 | assert(sfilter_index); | ||
204 | if (arg_debug) | ||
205 | printf("Allocating more seccomp filter entries\n"); | ||
206 | |||
207 | // allocate the new memory | ||
208 | struct sock_filter *old = sfilter; | ||
209 | sfilter = malloc(sizeof(struct sock_filter) * (sfilter_alloc_size + SECSIZE)); | ||
210 | if (!sfilter) | ||
211 | errExit("malloc"); | ||
212 | memset(sfilter, 0, sizeof(struct sock_filter) * (sfilter_alloc_size + SECSIZE)); | ||
213 | |||
214 | // copy old filter | ||
215 | memcpy(sfilter, old, sizeof(struct sock_filter) * sfilter_alloc_size); | ||
216 | sfilter_alloc_size += SECSIZE; | ||
217 | } | ||
218 | |||
219 | static void filter_add_whitelist(int syscall) { | ||
220 | assert(sfilter); | ||
221 | assert(sfilter_alloc_size); | ||
222 | assert(sfilter_index); | ||
223 | if (arg_debug) | ||
224 | printf("Whitelisting syscall %d %s\n", syscall, syscall_find_nr(syscall)); | ||
225 | |||
226 | if ((sfilter_index + 2) > sfilter_alloc_size) | ||
227 | filter_realloc(); | ||
228 | |||
229 | struct sock_filter filter[] = { | ||
230 | WHITELIST(syscall) | ||
231 | }; | ||
232 | #if 0 | ||
233 | { | ||
234 | int i; | ||
235 | unsigned char *ptr = (unsigned char *) &filter[0]; | ||
236 | for (i = 0; i < sizeof(filter); i++, ptr++) | ||
237 | printf("%x, ", (*ptr) & 0xff); | ||
238 | printf("\n"); | ||
239 | } | ||
240 | #endif | ||
241 | memcpy(&sfilter[sfilter_index], filter, sizeof(filter)); | ||
242 | sfilter_index += sizeof(filter) / sizeof(struct sock_filter); | ||
243 | } | ||
244 | |||
245 | static void filter_add_blacklist(int syscall) { | ||
246 | assert(sfilter); | ||
247 | assert(sfilter_alloc_size); | ||
248 | assert(sfilter_index); | ||
249 | if (arg_debug) | ||
250 | printf("Blacklisting syscall %d %s\n", syscall, syscall_find_nr(syscall)); | ||
251 | |||
252 | if ((sfilter_index + 2) > sfilter_alloc_size) | ||
253 | filter_realloc(); | ||
254 | |||
255 | struct sock_filter filter[] = { | ||
256 | BLACKLIST(syscall) | ||
257 | }; | ||
258 | #if 0 | ||
259 | { | ||
260 | int i; | ||
261 | unsigned char *ptr = (unsigned char *) &filter[0]; | ||
262 | for (i = 0; i < sizeof(filter); i++, ptr++) | ||
263 | printf("%x, ", (*ptr) & 0xff); | ||
264 | printf("\n"); | ||
265 | } | ||
266 | #endif | ||
267 | memcpy(&sfilter[sfilter_index], filter, sizeof(filter)); | ||
268 | sfilter_index += sizeof(filter) / sizeof(struct sock_filter); | ||
269 | } | ||
270 | |||
271 | static void filter_end_blacklist(void) { | ||
272 | assert(sfilter); | ||
273 | assert(sfilter_alloc_size); | ||
274 | assert(sfilter_index); | ||
275 | if (arg_debug) | ||
276 | printf("Ending syscall filter\n"); | ||
277 | |||
278 | if ((sfilter_index + 2) > sfilter_alloc_size) | ||
279 | filter_realloc(); | ||
280 | |||
281 | struct sock_filter filter[] = { | ||
282 | RETURN_ALLOW | ||
283 | }; | ||
284 | #if 0 | ||
285 | { | ||
286 | int i; | ||
287 | unsigned char *ptr = (unsigned char *) &filter[0]; | ||
288 | for (i = 0; i < sizeof(filter); i++, ptr++) | ||
289 | printf("%x, ", (*ptr) & 0xff); | ||
290 | printf("\n"); | ||
291 | } | ||
292 | #endif | ||
293 | memcpy(&sfilter[sfilter_index], filter, sizeof(filter)); | ||
294 | sfilter_index += sizeof(filter) / sizeof(struct sock_filter); | ||
295 | } | ||
296 | |||
297 | static void filter_end_whitelist(void) { | ||
298 | assert(sfilter); | ||
299 | assert(sfilter_alloc_size); | ||
300 | assert(sfilter_index); | ||
301 | if (arg_debug) | ||
302 | printf("Ending syscall filter\n"); | ||
303 | |||
304 | if ((sfilter_index + 2) > sfilter_alloc_size) | ||
305 | filter_realloc(); | ||
306 | |||
307 | struct sock_filter filter[] = { | ||
308 | KILL_PROCESS | ||
309 | }; | ||
310 | #if 0 | ||
311 | { | ||
312 | int i; | ||
313 | unsigned char *ptr = (unsigned char *) &filter[0]; | ||
314 | for (i = 0; i < sizeof(filter); i++, ptr++) | ||
315 | printf("%x, ", (*ptr) & 0xff); | ||
316 | printf("\n"); | ||
317 | } | ||
318 | #endif | ||
319 | memcpy(&sfilter[sfilter_index], filter, sizeof(filter)); | ||
320 | sfilter_index += sizeof(filter) / sizeof(struct sock_filter); | ||
321 | } | ||
322 | |||
323 | |||
324 | // save seccomp filter in /tmp/firejail/mnt/seccomp | ||
325 | static void write_seccomp_file(void) { | ||
326 | fs_build_mnt_dir(); | ||
327 | assert(sfilter); | ||
328 | |||
329 | char *fname; | ||
330 | if (asprintf(&fname, "%s/seccomp", MNT_DIR) == -1) | ||
331 | errExit("asprintf"); | ||
332 | int fd = open(fname, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); | ||
333 | if (fd == -1) | ||
334 | errExit("open"); | ||
335 | |||
336 | if (arg_debug) | ||
337 | printf("Save seccomp filter, size %lu bytes\n", sfilter_index * sizeof(struct sock_filter)); | ||
338 | errno = 0; | ||
339 | ssize_t sz = write(fd, sfilter, sfilter_index * sizeof(struct sock_filter)); | ||
340 | if (sz != (sfilter_index * sizeof(struct sock_filter))) { | ||
341 | fprintf(stderr, "Error: cannot save seccomp filter\n"); | ||
342 | exit(1); | ||
343 | } | ||
344 | close(fd); | ||
345 | if (chown(fname, 0, 0) < 0) | ||
346 | errExit("chown"); | ||
347 | free(fname); | ||
348 | } | ||
349 | |||
350 | // read seccomp filter from /tmp/firejail/mnt/seccomp | ||
351 | static void read_seccomp_file(char *file_name) { | ||
352 | assert(sfilter == NULL && sfilter_index == 0); | ||
353 | |||
354 | char *fname; | ||
355 | if (file_name) | ||
356 | fname = file_name; | ||
357 | else { | ||
358 | if (asprintf(&fname, "%s/seccomp", MNT_DIR) == -1) | ||
359 | errExit("asprintf"); | ||
360 | } | ||
361 | |||
362 | // check file | ||
363 | struct stat s; | ||
364 | if (stat(fname, &s) == -1) { | ||
365 | fprintf(stderr, "Error: seccomp file not found\n"); | ||
366 | exit(1); | ||
367 | } | ||
368 | ssize_t sz = s.st_size; | ||
369 | if (sz == 0 || (sz % sizeof(struct sock_filter)) != 0) { | ||
370 | fprintf(stderr, "Error: invalid seccomp file\n"); | ||
371 | exit(1); | ||
372 | } | ||
373 | sfilter = malloc(sz); | ||
374 | if (!sfilter) | ||
375 | errExit("malloc"); | ||
376 | |||
377 | // read file | ||
378 | /* coverity[toctou] */ | ||
379 | int fd = open(fname,O_RDONLY); | ||
380 | if (fd == -1) | ||
381 | errExit("open"); | ||
382 | errno = 0; | ||
383 | ssize_t size = read(fd, sfilter, sz); | ||
384 | if (size != sz) { | ||
385 | fprintf(stderr, "Error: invalid seccomp file\n"); | ||
386 | exit(1); | ||
387 | } | ||
388 | sfilter_index = sz / sizeof(struct sock_filter); | ||
389 | |||
390 | if (arg_debug) | ||
391 | printf("Read seccomp filter, size %lu bytes\n", sfilter_index * sizeof(struct sock_filter)); | ||
392 | |||
393 | close(fd); | ||
394 | free(fname); | ||
395 | |||
396 | if (arg_debug) | ||
397 | filter_debug(); | ||
398 | } | ||
399 | |||
400 | |||
401 | // drop filter for seccomp option | ||
402 | int seccomp_filter_drop(void) { | ||
403 | filter_init(); | ||
404 | |||
405 | // default seccomp | ||
406 | if (arg_seccomp_list_drop == NULL) { | ||
407 | #ifdef SYS_mount | ||
408 | filter_add_blacklist(SYS_mount); | ||
409 | #endif | ||
410 | #ifdef SYS_umount2 | ||
411 | filter_add_blacklist(SYS_umount2); | ||
412 | #endif | ||
413 | #ifdef SYS_ptrace | ||
414 | filter_add_blacklist(SYS_ptrace); | ||
415 | #endif | ||
416 | #ifdef SYS_kexec_load | ||
417 | filter_add_blacklist(SYS_kexec_load); | ||
418 | #endif | ||
419 | #ifdef SYS_open_by_handle_at | ||
420 | filter_add_blacklist(SYS_open_by_handle_at); | ||
421 | #endif | ||
422 | #ifdef SYS_init_module | ||
423 | filter_add_blacklist(SYS_init_module); | ||
424 | #endif | ||
425 | #ifdef SYS_finit_module // introduced in 2013 | ||
426 | filter_add_blacklist(SYS_finit_module); | ||
427 | #endif | ||
428 | #ifdef SYS_delete_module | ||
429 | filter_add_blacklist(SYS_delete_module); | ||
430 | #endif | ||
431 | #ifdef SYS_iopl | ||
432 | filter_add_blacklist(SYS_iopl); | ||
433 | #endif | ||
434 | #ifdef SYS_ioperm | ||
435 | filter_add_blacklist(SYS_ioperm); | ||
436 | #endif | ||
437 | #ifdef SYS_ni_syscall // new io permisions call on arm devices | ||
438 | filter_add_blacklist(SYS_ni_syscall); | ||
439 | #endif | ||
440 | #ifdef SYS_swapon | ||
441 | filter_add_blacklist(SYS_swapon); | ||
442 | #endif | ||
443 | #ifdef SYS_swapoff | ||
444 | filter_add_blacklist(SYS_swapoff); | ||
445 | #endif | ||
446 | #ifdef SYS_syslog | ||
447 | filter_add_blacklist(SYS_syslog); | ||
448 | #endif | ||
449 | #ifdef SYS_process_vm_readv | ||
450 | filter_add_blacklist(SYS_process_vm_readv); | ||
451 | #endif | ||
452 | #ifdef SYS_process_vm_writev | ||
453 | filter_add_blacklist(SYS_process_vm_writev); | ||
454 | #endif | ||
455 | #ifdef SYS_mknod | ||
456 | filter_add_blacklist(SYS_mknod); | ||
457 | #endif | ||
458 | |||
459 | // new syscalls in 0.9,23 | ||
460 | #ifdef SYS_sysfs | ||
461 | filter_add_blacklist(SYS_sysfs); | ||
462 | #endif | ||
463 | #ifdef SYS__sysctl | ||
464 | filter_add_blacklist(SYS__sysctl); | ||
465 | #endif | ||
466 | #ifdef SYS_adjtimex | ||
467 | filter_add_blacklist(SYS_adjtimex); | ||
468 | #endif | ||
469 | #ifdef SYS_clock_adjtime | ||
470 | filter_add_blacklist(SYS_clock_adjtime); | ||
471 | #endif | ||
472 | #ifdef SYS_lookup_dcookie | ||
473 | filter_add_blacklist(SYS_lookup_dcookie); | ||
474 | #endif | ||
475 | #ifdef SYS_perf_event_open | ||
476 | filter_add_blacklist(SYS_perf_event_open); | ||
477 | #endif | ||
478 | #ifdef SYS_fanotify_init | ||
479 | filter_add_blacklist(SYS_fanotify_init); | ||
480 | #endif | ||
481 | #ifdef SYS_kcmp | ||
482 | filter_add_blacklist(SYS_kcmp); | ||
483 | #endif | ||
484 | } | ||
485 | |||
486 | // default seccomp filter with additional drop list | ||
487 | if (arg_seccomp_list && arg_seccomp_list_drop == NULL) { | ||
488 | if (syscall_check_list(arg_seccomp_list, filter_add_blacklist)) { | ||
489 | fprintf(stderr, "Error: cannot load seccomp filter\n"); | ||
490 | exit(1); | ||
491 | } | ||
492 | } | ||
493 | // drop list | ||
494 | else if (arg_seccomp_list == NULL && arg_seccomp_list_drop) { | ||
495 | if (syscall_check_list(arg_seccomp_list_drop, filter_add_blacklist)) { | ||
496 | fprintf(stderr, "Error: cannot load seccomp filter\n"); | ||
497 | exit(1); | ||
498 | } | ||
499 | } | ||
500 | |||
501 | |||
502 | filter_end_blacklist(); | ||
503 | if (arg_debug) | ||
504 | filter_debug(); | ||
505 | |||
506 | // save seccomp filter in /tmp/firejail/mnt/seccomp | ||
507 | // in order to use it in --join operations | ||
508 | write_seccomp_file(); | ||
509 | |||
510 | |||
511 | struct sock_fprog prog = { | ||
512 | .len = sfilter_index, | ||
513 | .filter = sfilter, | ||
514 | }; | ||
515 | |||
516 | if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { | ||
517 | fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); | ||
518 | return 1; | ||
519 | } | ||
520 | else if (arg_debug) { | ||
521 | printf("seccomp enabled\n"); | ||
522 | } | ||
523 | |||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | // keep filter for seccomp option | ||
528 | int seccomp_filter_keep(void) { | ||
529 | filter_init(); | ||
530 | |||
531 | // these 4 syscalls are used by firejail after the seccomp filter is initialized | ||
532 | filter_add_whitelist(SYS_setuid); | ||
533 | filter_add_whitelist(SYS_setgid); | ||
534 | filter_add_whitelist(SYS_setgroups); | ||
535 | filter_add_whitelist(SYS_dup); | ||
536 | |||
537 | // apply keep list | ||
538 | if (arg_seccomp_list_keep) { | ||
539 | if (syscall_check_list(arg_seccomp_list_keep, filter_add_whitelist)) { | ||
540 | fprintf(stderr, "Error: cannot load seccomp filter\n"); | ||
541 | exit(1); | ||
542 | } | ||
543 | } | ||
544 | |||
545 | filter_end_whitelist(); | ||
546 | if (arg_debug) | ||
547 | filter_debug(); | ||
548 | |||
549 | // save seccomp filter in /tmp/firejail/mnt/seccomp | ||
550 | // in order to use it in --join operations | ||
551 | write_seccomp_file(); | ||
552 | |||
553 | |||
554 | struct sock_fprog prog = { | ||
555 | .len = sfilter_index, | ||
556 | .filter = sfilter, | ||
557 | }; | ||
558 | |||
559 | if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { | ||
560 | fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); | ||
561 | return 1; | ||
562 | } | ||
563 | else if (arg_debug) { | ||
564 | printf("seccomp enabled\n"); | ||
565 | } | ||
566 | |||
567 | return 0; | ||
568 | } | ||
569 | |||
570 | |||
571 | |||
572 | void seccomp_set(void) { | ||
573 | // read seccomp filter from /tmp/firejail/mnt/seccomp | ||
574 | read_seccomp_file(NULL); | ||
575 | |||
576 | // apply filter | ||
577 | struct sock_fprog prog = { | ||
578 | .len = sfilter_index, | ||
579 | .filter = sfilter, | ||
580 | }; | ||
581 | |||
582 | if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { | ||
583 | fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); | ||
584 | return; | ||
585 | } | ||
586 | else if (arg_debug) { | ||
587 | printf("seccomp enabled\n"); | ||
588 | } | ||
589 | } | ||
590 | |||
591 | void seccomp_print_filter_name(const char *name) { | ||
592 | if (!name || strlen(name) == 0) { | ||
593 | fprintf(stderr, "Error: invalid sandbox name\n"); | ||
594 | exit(1); | ||
595 | } | ||
596 | pid_t pid; | ||
597 | if (name2pid(name, &pid)) { | ||
598 | fprintf(stderr, "Error: cannot find sandbox %s\n", name); | ||
599 | exit(1); | ||
600 | } | ||
601 | |||
602 | seccomp_print_filter(pid); | ||
603 | } | ||
604 | |||
605 | void seccomp_print_filter(pid_t pid) { | ||
606 | // if the pid is that of a firejail process, use the pid of the first child process | ||
607 | char *comm = pid_proc_comm(pid); | ||
608 | if (comm) { | ||
609 | // remove \n | ||
610 | char *ptr = strchr(comm, '\n'); | ||
611 | if (ptr) | ||
612 | *ptr = '\0'; | ||
613 | if (strcmp(comm, "firejail") == 0) { | ||
614 | pid_t child; | ||
615 | if (find_child(pid, &child) == 0) { | ||
616 | pid = child; | ||
617 | } | ||
618 | } | ||
619 | free(comm); | ||
620 | } | ||
621 | |||
622 | // check privileges for non-root users | ||
623 | uid_t uid = getuid(); | ||
624 | if (uid != 0) { | ||
625 | struct stat s; | ||
626 | char *dir; | ||
627 | if (asprintf(&dir, "/proc/%u/ns", pid) == -1) | ||
628 | errExit("asprintf"); | ||
629 | if (stat(dir, &s) < 0) | ||
630 | errExit("stat"); | ||
631 | if (s.st_uid != uid) { | ||
632 | printf("Error: permission denied.\n"); | ||
633 | exit(1); | ||
634 | } | ||
635 | } | ||
636 | |||
637 | |||
638 | // find the seccomp filter | ||
639 | char *fname; | ||
640 | if (asprintf(&fname, "/proc/%d/root/tmp/firejail/mnt/seccomp", pid) == -1) | ||
641 | errExit("asprintf"); | ||
642 | |||
643 | struct stat s; | ||
644 | if (stat(fname, &s) == -1) { | ||
645 | printf("Cannot access seccomp filter.\n"); | ||
646 | exit(1); | ||
647 | } | ||
648 | |||
649 | // read and print the filter | ||
650 | read_seccomp_file(fname); | ||
651 | drop_privs(1); | ||
652 | filter_debug(); | ||
653 | |||
654 | exit(0); | ||
655 | } | ||
656 | |||
657 | #endif // HAVE_SECCOMP | ||
658 | |||
diff --git a/src/firejail/shutdown.c b/src/firejail/shutdown.c new file mode 100644 index 000000000..b666996df --- /dev/null +++ b/src/firejail/shutdown.c | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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/stat.h> | ||
22 | #include <sys/wait.h> | ||
23 | #include <fcntl.h> | ||
24 | #include <sys/prctl.h> | ||
25 | |||
26 | void shut_name(const char *name) { | ||
27 | if (!name || strlen(name) == 0) { | ||
28 | fprintf(stderr, "Error: invalid sandbox name\n"); | ||
29 | exit(1); | ||
30 | } | ||
31 | |||
32 | pid_t pid; | ||
33 | if (name2pid(name, &pid)) { | ||
34 | fprintf(stderr, "Error: cannot find sandbox %s\n", name); | ||
35 | exit(1); | ||
36 | } | ||
37 | |||
38 | shut(pid); | ||
39 | } | ||
40 | |||
41 | void shut(pid_t pid) { | ||
42 | pid_t parent = pid; | ||
43 | // if the pid is that of a firejail process, use the pid of a child process inside the sandbox | ||
44 | char *comm = pid_proc_comm(pid); | ||
45 | if (comm) { | ||
46 | // remove \n | ||
47 | char *ptr = strchr(comm, '\n'); | ||
48 | if (ptr) | ||
49 | *ptr = '\0'; | ||
50 | if (strcmp(comm, "firejail") == 0) { | ||
51 | pid_t child; | ||
52 | if (find_child(pid, &child) == 0) { | ||
53 | pid = child; | ||
54 | printf("Switching to pid %u, the first child process inside the sandbox\n", (unsigned) pid); | ||
55 | } | ||
56 | } | ||
57 | free(comm); | ||
58 | } | ||
59 | |||
60 | // check privileges for non-root users | ||
61 | uid_t uid = getuid(); | ||
62 | if (uid != 0) { | ||
63 | struct stat s; | ||
64 | char *dir; | ||
65 | if (asprintf(&dir, "/proc/%u/ns", pid) == -1) | ||
66 | errExit("asprintf"); | ||
67 | if (stat(dir, &s) < 0) | ||
68 | errExit("stat"); | ||
69 | if (s.st_uid != uid) { | ||
70 | fprintf(stderr, "Error: permission is denied to shutdown a sandbox created by a different user.\n"); | ||
71 | exit(1); | ||
72 | } | ||
73 | } | ||
74 | |||
75 | printf("Sending SIGTERM to %u\n", pid); | ||
76 | kill(pid, SIGTERM); | ||
77 | sleep(2); | ||
78 | |||
79 | // if the process is still running, terminate it using SIGKILL | ||
80 | // try to open stat file | ||
81 | char *file; | ||
82 | if (asprintf(&file, "/proc/%u/status", pid) == -1) { | ||
83 | perror("asprintf"); | ||
84 | exit(1); | ||
85 | } | ||
86 | FILE *fp = fopen(file, "r"); | ||
87 | if (!fp) | ||
88 | return; | ||
89 | fclose(fp); | ||
90 | |||
91 | // kill the process and also the parent | ||
92 | printf("Sending SIGKILL to %u\n", pid); | ||
93 | kill(pid, SIGKILL); | ||
94 | if (parent != pid) { | ||
95 | printf("Sending SIGKILL to %u\n", parent); | ||
96 | kill(parent, SIGKILL); | ||
97 | } | ||
98 | } | ||
diff --git a/src/firejail/syscall.c b/src/firejail/syscall.c new file mode 100644 index 000000000..50bff7f5a --- /dev/null +++ b/src/firejail/syscall.c | |||
@@ -0,0 +1,4942 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 | |||
21 | #ifdef HAVE_SECCOMP | ||
22 | #include "firejail.h" | ||
23 | #include <sys/syscall.h> | ||
24 | |||
25 | typedef struct { | ||
26 | char *name; | ||
27 | int nr; | ||
28 | } SyscallEntry; | ||
29 | |||
30 | static SyscallEntry syslist[] = { | ||
31 | // | ||
32 | // code generated using tools/extract-syscall | ||
33 | // | ||
34 | #ifndef _SYSCALL_H | ||
35 | #endif | ||
36 | #if !defined __x86_64__ | ||
37 | #ifdef SYS__llseek | ||
38 | #ifdef __NR__llseek | ||
39 | {"_llseek", __NR__llseek}, | ||
40 | #endif | ||
41 | #endif | ||
42 | #ifdef SYS__newselect | ||
43 | #ifdef __NR__newselect | ||
44 | {"_newselect", __NR__newselect}, | ||
45 | #endif | ||
46 | #endif | ||
47 | #ifdef SYS__sysctl | ||
48 | #ifdef __NR__sysctl | ||
49 | {"_sysctl", __NR__sysctl}, | ||
50 | #endif | ||
51 | #endif | ||
52 | #ifdef SYS_access | ||
53 | #ifdef __NR_access | ||
54 | {"access", __NR_access}, | ||
55 | #endif | ||
56 | #endif | ||
57 | #ifdef SYS_acct | ||
58 | #ifdef __NR_acct | ||
59 | {"acct", __NR_acct}, | ||
60 | #endif | ||
61 | #endif | ||
62 | #ifdef SYS_add_key | ||
63 | #ifdef __NR_add_key | ||
64 | {"add_key", __NR_add_key}, | ||
65 | #endif | ||
66 | #endif | ||
67 | #ifdef SYS_adjtimex | ||
68 | #ifdef __NR_adjtimex | ||
69 | {"adjtimex", __NR_adjtimex}, | ||
70 | #endif | ||
71 | #endif | ||
72 | #ifdef SYS_afs_syscall | ||
73 | #ifdef __NR_afs_syscall | ||
74 | {"afs_syscall", __NR_afs_syscall}, | ||
75 | #endif | ||
76 | #endif | ||
77 | #ifdef SYS_alarm | ||
78 | #ifdef __NR_alarm | ||
79 | {"alarm", __NR_alarm}, | ||
80 | #endif | ||
81 | #endif | ||
82 | #ifdef SYS_bdflush | ||
83 | #ifdef __NR_bdflush | ||
84 | {"bdflush", __NR_bdflush}, | ||
85 | #endif | ||
86 | #endif | ||
87 | #ifdef SYS_break | ||
88 | #ifdef __NR_break | ||
89 | {"break", __NR_break}, | ||
90 | #endif | ||
91 | #endif | ||
92 | #ifdef SYS_brk | ||
93 | #ifdef __NR_brk | ||
94 | {"brk", __NR_brk}, | ||
95 | #endif | ||
96 | #endif | ||
97 | #ifdef SYS_capget | ||
98 | #ifdef __NR_capget | ||
99 | {"capget", __NR_capget}, | ||
100 | #endif | ||
101 | #endif | ||
102 | #ifdef SYS_capset | ||
103 | #ifdef __NR_capset | ||
104 | {"capset", __NR_capset}, | ||
105 | #endif | ||
106 | #endif | ||
107 | #ifdef SYS_chdir | ||
108 | #ifdef __NR_chdir | ||
109 | {"chdir", __NR_chdir}, | ||
110 | #endif | ||
111 | #endif | ||
112 | #ifdef SYS_chmod | ||
113 | #ifdef __NR_chmod | ||
114 | {"chmod", __NR_chmod}, | ||
115 | #endif | ||
116 | #endif | ||
117 | #ifdef SYS_chown | ||
118 | #ifdef __NR_chown | ||
119 | {"chown", __NR_chown}, | ||
120 | #endif | ||
121 | #endif | ||
122 | #ifdef SYS_chown32 | ||
123 | #ifdef __NR_chown32 | ||
124 | {"chown32", __NR_chown32}, | ||
125 | #endif | ||
126 | #endif | ||
127 | #ifdef SYS_chroot | ||
128 | #ifdef __NR_chroot | ||
129 | {"chroot", __NR_chroot}, | ||
130 | #endif | ||
131 | #endif | ||
132 | #ifdef SYS_clock_adjtime | ||
133 | #ifdef __NR_clock_adjtime | ||
134 | {"clock_adjtime", __NR_clock_adjtime}, | ||
135 | #endif | ||
136 | #endif | ||
137 | #ifdef SYS_clock_getres | ||
138 | #ifdef __NR_clock_getres | ||
139 | {"clock_getres", __NR_clock_getres}, | ||
140 | #endif | ||
141 | #endif | ||
142 | #ifdef SYS_clock_gettime | ||
143 | #ifdef __NR_clock_gettime | ||
144 | {"clock_gettime", __NR_clock_gettime}, | ||
145 | #endif | ||
146 | #endif | ||
147 | #ifdef SYS_clock_nanosleep | ||
148 | #ifdef __NR_clock_nanosleep | ||
149 | {"clock_nanosleep", __NR_clock_nanosleep}, | ||
150 | #endif | ||
151 | #endif | ||
152 | #ifdef SYS_clock_settime | ||
153 | #ifdef __NR_clock_settime | ||
154 | {"clock_settime", __NR_clock_settime}, | ||
155 | #endif | ||
156 | #endif | ||
157 | #ifdef SYS_clone | ||
158 | #ifdef __NR_clone | ||
159 | {"clone", __NR_clone}, | ||
160 | #endif | ||
161 | #endif | ||
162 | #ifdef SYS_close | ||
163 | #ifdef __NR_close | ||
164 | {"close", __NR_close}, | ||
165 | #endif | ||
166 | #endif | ||
167 | #ifdef SYS_creat | ||
168 | #ifdef __NR_creat | ||
169 | {"creat", __NR_creat}, | ||
170 | #endif | ||
171 | #endif | ||
172 | #ifdef SYS_create_module | ||
173 | #ifdef __NR_create_module | ||
174 | {"create_module", __NR_create_module}, | ||
175 | #endif | ||
176 | #endif | ||
177 | #ifdef SYS_delete_module | ||
178 | #ifdef __NR_delete_module | ||
179 | {"delete_module", __NR_delete_module}, | ||
180 | #endif | ||
181 | #endif | ||
182 | #ifdef SYS_dup | ||
183 | #ifdef __NR_dup | ||
184 | {"dup", __NR_dup}, | ||
185 | #endif | ||
186 | #endif | ||
187 | #ifdef SYS_dup2 | ||
188 | #ifdef __NR_dup2 | ||
189 | {"dup2", __NR_dup2}, | ||
190 | #endif | ||
191 | #endif | ||
192 | #ifdef SYS_dup3 | ||
193 | #ifdef __NR_dup3 | ||
194 | {"dup3", __NR_dup3}, | ||
195 | #endif | ||
196 | #endif | ||
197 | #ifdef SYS_epoll_create | ||
198 | #ifdef __NR_epoll_create | ||
199 | {"epoll_create", __NR_epoll_create}, | ||
200 | #endif | ||
201 | #endif | ||
202 | #ifdef SYS_epoll_create1 | ||
203 | #ifdef __NR_epoll_create1 | ||
204 | {"epoll_create1", __NR_epoll_create1}, | ||
205 | #endif | ||
206 | #endif | ||
207 | #ifdef SYS_epoll_ctl | ||
208 | #ifdef __NR_epoll_ctl | ||
209 | {"epoll_ctl", __NR_epoll_ctl}, | ||
210 | #endif | ||
211 | #endif | ||
212 | #ifdef SYS_epoll_pwait | ||
213 | #ifdef __NR_epoll_pwait | ||
214 | {"epoll_pwait", __NR_epoll_pwait}, | ||
215 | #endif | ||
216 | #endif | ||
217 | #ifdef SYS_epoll_wait | ||
218 | #ifdef __NR_epoll_wait | ||
219 | {"epoll_wait", __NR_epoll_wait}, | ||
220 | #endif | ||
221 | #endif | ||
222 | #ifdef SYS_eventfd | ||
223 | #ifdef __NR_eventfd | ||
224 | {"eventfd", __NR_eventfd}, | ||
225 | #endif | ||
226 | #endif | ||
227 | #ifdef SYS_eventfd2 | ||
228 | #ifdef __NR_eventfd2 | ||
229 | {"eventfd2", __NR_eventfd2}, | ||
230 | #endif | ||
231 | #endif | ||
232 | #ifdef SYS_execve | ||
233 | #ifdef __NR_execve | ||
234 | {"execve", __NR_execve}, | ||
235 | #endif | ||
236 | #endif | ||
237 | #ifdef SYS_exit | ||
238 | #ifdef __NR_exit | ||
239 | {"exit", __NR_exit}, | ||
240 | #endif | ||
241 | #endif | ||
242 | #ifdef SYS_exit_group | ||
243 | #ifdef __NR_exit_group | ||
244 | {"exit_group", __NR_exit_group}, | ||
245 | #endif | ||
246 | #endif | ||
247 | #ifdef SYS_faccessat | ||
248 | #ifdef __NR_faccessat | ||
249 | {"faccessat", __NR_faccessat}, | ||
250 | #endif | ||
251 | #endif | ||
252 | #ifdef SYS_fadvise64 | ||
253 | #ifdef __NR_fadvise64 | ||
254 | {"fadvise64", __NR_fadvise64}, | ||
255 | #endif | ||
256 | #endif | ||
257 | #ifdef SYS_fadvise64_64 | ||
258 | #ifdef __NR_fadvise64_64 | ||
259 | {"fadvise64_64", __NR_fadvise64_64}, | ||
260 | #endif | ||
261 | #endif | ||
262 | #ifdef SYS_fallocate | ||
263 | #ifdef __NR_fallocate | ||
264 | {"fallocate", __NR_fallocate}, | ||
265 | #endif | ||
266 | #endif | ||
267 | #ifdef SYS_fanotify_init | ||
268 | #ifdef __NR_fanotify_init | ||
269 | {"fanotify_init", __NR_fanotify_init}, | ||
270 | #endif | ||
271 | #endif | ||
272 | #ifdef SYS_fanotify_mark | ||
273 | #ifdef __NR_fanotify_mark | ||
274 | {"fanotify_mark", __NR_fanotify_mark}, | ||
275 | #endif | ||
276 | #endif | ||
277 | #ifdef SYS_fchdir | ||
278 | #ifdef __NR_fchdir | ||
279 | {"fchdir", __NR_fchdir}, | ||
280 | #endif | ||
281 | #endif | ||
282 | #ifdef SYS_fchmod | ||
283 | #ifdef __NR_fchmod | ||
284 | {"fchmod", __NR_fchmod}, | ||
285 | #endif | ||
286 | #endif | ||
287 | #ifdef SYS_fchmodat | ||
288 | #ifdef __NR_fchmodat | ||
289 | {"fchmodat", __NR_fchmodat}, | ||
290 | #endif | ||
291 | #endif | ||
292 | #ifdef SYS_fchown | ||
293 | #ifdef __NR_fchown | ||
294 | {"fchown", __NR_fchown}, | ||
295 | #endif | ||
296 | #endif | ||
297 | #ifdef SYS_fchown32 | ||
298 | #ifdef __NR_fchown32 | ||
299 | {"fchown32", __NR_fchown32}, | ||
300 | #endif | ||
301 | #endif | ||
302 | #ifdef SYS_fchownat | ||
303 | #ifdef __NR_fchownat | ||
304 | {"fchownat", __NR_fchownat}, | ||
305 | #endif | ||
306 | #endif | ||
307 | #ifdef SYS_fcntl | ||
308 | #ifdef __NR_fcntl | ||
309 | {"fcntl", __NR_fcntl}, | ||
310 | #endif | ||
311 | #endif | ||
312 | #ifdef SYS_fcntl64 | ||
313 | #ifdef __NR_fcntl64 | ||
314 | {"fcntl64", __NR_fcntl64}, | ||
315 | #endif | ||
316 | #endif | ||
317 | #ifdef SYS_fdatasync | ||
318 | #ifdef __NR_fdatasync | ||
319 | {"fdatasync", __NR_fdatasync}, | ||
320 | #endif | ||
321 | #endif | ||
322 | #ifdef SYS_fgetxattr | ||
323 | #ifdef __NR_fgetxattr | ||
324 | {"fgetxattr", __NR_fgetxattr}, | ||
325 | #endif | ||
326 | #endif | ||
327 | #ifdef SYS_finit_module | ||
328 | #ifdef __NR_finit_module | ||
329 | {"finit_module", __NR_finit_module}, | ||
330 | #endif | ||
331 | #endif | ||
332 | #ifdef SYS_flistxattr | ||
333 | #ifdef __NR_flistxattr | ||
334 | {"flistxattr", __NR_flistxattr}, | ||
335 | #endif | ||
336 | #endif | ||
337 | #ifdef SYS_flock | ||
338 | #ifdef __NR_flock | ||
339 | {"flock", __NR_flock}, | ||
340 | #endif | ||
341 | #endif | ||
342 | #ifdef SYS_fork | ||
343 | #ifdef __NR_fork | ||
344 | {"fork", __NR_fork}, | ||
345 | #endif | ||
346 | #endif | ||
347 | #ifdef SYS_fremovexattr | ||
348 | #ifdef __NR_fremovexattr | ||
349 | {"fremovexattr", __NR_fremovexattr}, | ||
350 | #endif | ||
351 | #endif | ||
352 | #ifdef SYS_fsetxattr | ||
353 | #ifdef __NR_fsetxattr | ||
354 | {"fsetxattr", __NR_fsetxattr}, | ||
355 | #endif | ||
356 | #endif | ||
357 | #ifdef SYS_fstat | ||
358 | #ifdef __NR_fstat | ||
359 | {"fstat", __NR_fstat}, | ||
360 | #endif | ||
361 | #endif | ||
362 | #ifdef SYS_fstat64 | ||
363 | #ifdef __NR_fstat64 | ||
364 | {"fstat64", __NR_fstat64}, | ||
365 | #endif | ||
366 | #endif | ||
367 | #ifdef SYS_fstatat64 | ||
368 | #ifdef __NR_fstatat64 | ||
369 | {"fstatat64", __NR_fstatat64}, | ||
370 | #endif | ||
371 | #endif | ||
372 | #ifdef SYS_fstatfs | ||
373 | #ifdef __NR_fstatfs | ||
374 | {"fstatfs", __NR_fstatfs}, | ||
375 | #endif | ||
376 | #endif | ||
377 | #ifdef SYS_fstatfs64 | ||
378 | #ifdef __NR_fstatfs64 | ||
379 | {"fstatfs64", __NR_fstatfs64}, | ||
380 | #endif | ||
381 | #endif | ||
382 | #ifdef SYS_fsync | ||
383 | #ifdef __NR_fsync | ||
384 | {"fsync", __NR_fsync}, | ||
385 | #endif | ||
386 | #endif | ||
387 | #ifdef SYS_ftime | ||
388 | #ifdef __NR_ftime | ||
389 | {"ftime", __NR_ftime}, | ||
390 | #endif | ||
391 | #endif | ||
392 | #ifdef SYS_ftruncate | ||
393 | #ifdef __NR_ftruncate | ||
394 | {"ftruncate", __NR_ftruncate}, | ||
395 | #endif | ||
396 | #endif | ||
397 | #ifdef SYS_ftruncate64 | ||
398 | #ifdef __NR_ftruncate64 | ||
399 | {"ftruncate64", __NR_ftruncate64}, | ||
400 | #endif | ||
401 | #endif | ||
402 | #ifdef SYS_futex | ||
403 | #ifdef __NR_futex | ||
404 | {"futex", __NR_futex}, | ||
405 | #endif | ||
406 | #endif | ||
407 | #ifdef SYS_futimesat | ||
408 | #ifdef __NR_futimesat | ||
409 | {"futimesat", __NR_futimesat}, | ||
410 | #endif | ||
411 | #endif | ||
412 | #ifdef SYS_get_kernel_syms | ||
413 | #ifdef __NR_get_kernel_syms | ||
414 | {"get_kernel_syms", __NR_get_kernel_syms}, | ||
415 | #endif | ||
416 | #endif | ||
417 | #ifdef SYS_get_mempolicy | ||
418 | #ifdef __NR_get_mempolicy | ||
419 | {"get_mempolicy", __NR_get_mempolicy}, | ||
420 | #endif | ||
421 | #endif | ||
422 | #ifdef SYS_get_robust_list | ||
423 | #ifdef __NR_get_robust_list | ||
424 | {"get_robust_list", __NR_get_robust_list}, | ||
425 | #endif | ||
426 | #endif | ||
427 | #ifdef SYS_get_thread_area | ||
428 | #ifdef __NR_get_thread_area | ||
429 | {"get_thread_area", __NR_get_thread_area}, | ||
430 | #endif | ||
431 | #endif | ||
432 | #ifdef SYS_getcpu | ||
433 | #ifdef __NR_getcpu | ||
434 | {"getcpu", __NR_getcpu}, | ||
435 | #endif | ||
436 | #endif | ||
437 | #ifdef SYS_getcwd | ||
438 | #ifdef __NR_getcwd | ||
439 | {"getcwd", __NR_getcwd}, | ||
440 | #endif | ||
441 | #endif | ||
442 | #ifdef SYS_getdents | ||
443 | #ifdef __NR_getdents | ||
444 | {"getdents", __NR_getdents}, | ||
445 | #endif | ||
446 | #endif | ||
447 | #ifdef SYS_getdents64 | ||
448 | #ifdef __NR_getdents64 | ||
449 | {"getdents64", __NR_getdents64}, | ||
450 | #endif | ||
451 | #endif | ||
452 | #ifdef SYS_getegid | ||
453 | #ifdef __NR_getegid | ||
454 | {"getegid", __NR_getegid}, | ||
455 | #endif | ||
456 | #endif | ||
457 | #ifdef SYS_getegid32 | ||
458 | #ifdef __NR_getegid32 | ||
459 | {"getegid32", __NR_getegid32}, | ||
460 | #endif | ||
461 | #endif | ||
462 | #ifdef SYS_geteuid | ||
463 | #ifdef __NR_geteuid | ||
464 | {"geteuid", __NR_geteuid}, | ||
465 | #endif | ||
466 | #endif | ||
467 | #ifdef SYS_geteuid32 | ||
468 | #ifdef __NR_geteuid32 | ||
469 | {"geteuid32", __NR_geteuid32}, | ||
470 | #endif | ||
471 | #endif | ||
472 | #ifdef SYS_getgid | ||
473 | #ifdef __NR_getgid | ||
474 | {"getgid", __NR_getgid}, | ||
475 | #endif | ||
476 | #endif | ||
477 | #ifdef SYS_getgid32 | ||
478 | #ifdef __NR_getgid32 | ||
479 | {"getgid32", __NR_getgid32}, | ||
480 | #endif | ||
481 | #endif | ||
482 | #ifdef SYS_getgroups | ||
483 | #ifdef __NR_getgroups | ||
484 | {"getgroups", __NR_getgroups}, | ||
485 | #endif | ||
486 | #endif | ||
487 | #ifdef SYS_getgroups32 | ||
488 | #ifdef __NR_getgroups32 | ||
489 | {"getgroups32", __NR_getgroups32}, | ||
490 | #endif | ||
491 | #endif | ||
492 | #ifdef SYS_getitimer | ||
493 | #ifdef __NR_getitimer | ||
494 | {"getitimer", __NR_getitimer}, | ||
495 | #endif | ||
496 | #endif | ||
497 | #ifdef SYS_getpgid | ||
498 | #ifdef __NR_getpgid | ||
499 | {"getpgid", __NR_getpgid}, | ||
500 | #endif | ||
501 | #endif | ||
502 | #ifdef SYS_getpgrp | ||
503 | #ifdef __NR_getpgrp | ||
504 | {"getpgrp", __NR_getpgrp}, | ||
505 | #endif | ||
506 | #endif | ||
507 | #ifdef SYS_getpid | ||
508 | #ifdef __NR_getpid | ||
509 | {"getpid", __NR_getpid}, | ||
510 | #endif | ||
511 | #endif | ||
512 | #ifdef SYS_getpmsg | ||
513 | #ifdef __NR_getpmsg | ||
514 | {"getpmsg", __NR_getpmsg}, | ||
515 | #endif | ||
516 | #endif | ||
517 | #ifdef SYS_getppid | ||
518 | #ifdef __NR_getppid | ||
519 | {"getppid", __NR_getppid}, | ||
520 | #endif | ||
521 | #endif | ||
522 | #ifdef SYS_getpriority | ||
523 | #ifdef __NR_getpriority | ||
524 | {"getpriority", __NR_getpriority}, | ||
525 | #endif | ||
526 | #endif | ||
527 | #ifdef SYS_getresgid | ||
528 | #ifdef __NR_getresgid | ||
529 | {"getresgid", __NR_getresgid}, | ||
530 | #endif | ||
531 | #endif | ||
532 | #ifdef SYS_getresgid32 | ||
533 | #ifdef __NR_getresgid32 | ||
534 | {"getresgid32", __NR_getresgid32}, | ||
535 | #endif | ||
536 | #endif | ||
537 | #ifdef SYS_getresuid | ||
538 | #ifdef __NR_getresuid | ||
539 | {"getresuid", __NR_getresuid}, | ||
540 | #endif | ||
541 | #endif | ||
542 | #ifdef SYS_getresuid32 | ||
543 | #ifdef __NR_getresuid32 | ||
544 | {"getresuid32", __NR_getresuid32}, | ||
545 | #endif | ||
546 | #endif | ||
547 | #ifdef SYS_getrlimit | ||
548 | #ifdef __NR_getrlimit | ||
549 | {"getrlimit", __NR_getrlimit}, | ||
550 | #endif | ||
551 | #endif | ||
552 | #ifdef SYS_getrusage | ||
553 | #ifdef __NR_getrusage | ||
554 | {"getrusage", __NR_getrusage}, | ||
555 | #endif | ||
556 | #endif | ||
557 | #ifdef SYS_getsid | ||
558 | #ifdef __NR_getsid | ||
559 | {"getsid", __NR_getsid}, | ||
560 | #endif | ||
561 | #endif | ||
562 | #ifdef SYS_gettid | ||
563 | #ifdef __NR_gettid | ||
564 | {"gettid", __NR_gettid}, | ||
565 | #endif | ||
566 | #endif | ||
567 | #ifdef SYS_gettimeofday | ||
568 | #ifdef __NR_gettimeofday | ||
569 | {"gettimeofday", __NR_gettimeofday}, | ||
570 | #endif | ||
571 | #endif | ||
572 | #ifdef SYS_getuid | ||
573 | #ifdef __NR_getuid | ||
574 | {"getuid", __NR_getuid}, | ||
575 | #endif | ||
576 | #endif | ||
577 | #ifdef SYS_getuid32 | ||
578 | #ifdef __NR_getuid32 | ||
579 | {"getuid32", __NR_getuid32}, | ||
580 | #endif | ||
581 | #endif | ||
582 | #ifdef SYS_getxattr | ||
583 | #ifdef __NR_getxattr | ||
584 | {"getxattr", __NR_getxattr}, | ||
585 | #endif | ||
586 | #endif | ||
587 | #ifdef SYS_gtty | ||
588 | #ifdef __NR_gtty | ||
589 | {"gtty", __NR_gtty}, | ||
590 | #endif | ||
591 | #endif | ||
592 | #ifdef SYS_idle | ||
593 | #ifdef __NR_idle | ||
594 | {"idle", __NR_idle}, | ||
595 | #endif | ||
596 | #endif | ||
597 | #ifdef SYS_init_module | ||
598 | #ifdef __NR_init_module | ||
599 | {"init_module", __NR_init_module}, | ||
600 | #endif | ||
601 | #endif | ||
602 | #ifdef SYS_inotify_add_watch | ||
603 | #ifdef __NR_inotify_add_watch | ||
604 | {"inotify_add_watch", __NR_inotify_add_watch}, | ||
605 | #endif | ||
606 | #endif | ||
607 | #ifdef SYS_inotify_init | ||
608 | #ifdef __NR_inotify_init | ||
609 | {"inotify_init", __NR_inotify_init}, | ||
610 | #endif | ||
611 | #endif | ||
612 | #ifdef SYS_inotify_init1 | ||
613 | #ifdef __NR_inotify_init1 | ||
614 | {"inotify_init1", __NR_inotify_init1}, | ||
615 | #endif | ||
616 | #endif | ||
617 | #ifdef SYS_inotify_rm_watch | ||
618 | #ifdef __NR_inotify_rm_watch | ||
619 | {"inotify_rm_watch", __NR_inotify_rm_watch}, | ||
620 | #endif | ||
621 | #endif | ||
622 | #ifdef SYS_io_cancel | ||
623 | #ifdef __NR_io_cancel | ||
624 | {"io_cancel", __NR_io_cancel}, | ||
625 | #endif | ||
626 | #endif | ||
627 | #ifdef SYS_io_destroy | ||
628 | #ifdef __NR_io_destroy | ||
629 | {"io_destroy", __NR_io_destroy}, | ||
630 | #endif | ||
631 | #endif | ||
632 | #ifdef SYS_io_getevents | ||
633 | #ifdef __NR_io_getevents | ||
634 | {"io_getevents", __NR_io_getevents}, | ||
635 | #endif | ||
636 | #endif | ||
637 | #ifdef SYS_io_setup | ||
638 | #ifdef __NR_io_setup | ||
639 | {"io_setup", __NR_io_setup}, | ||
640 | #endif | ||
641 | #endif | ||
642 | #ifdef SYS_io_submit | ||
643 | #ifdef __NR_io_submit | ||
644 | {"io_submit", __NR_io_submit}, | ||
645 | #endif | ||
646 | #endif | ||
647 | #ifdef SYS_ioctl | ||
648 | #ifdef __NR_ioctl | ||
649 | {"ioctl", __NR_ioctl}, | ||
650 | #endif | ||
651 | #endif | ||
652 | #ifdef SYS_ioperm | ||
653 | #ifdef __NR_ioperm | ||
654 | {"ioperm", __NR_ioperm}, | ||
655 | #endif | ||
656 | #endif | ||
657 | #ifdef SYS_iopl | ||
658 | #ifdef __NR_iopl | ||
659 | {"iopl", __NR_iopl}, | ||
660 | #endif | ||
661 | #endif | ||
662 | #ifdef SYS_ioprio_get | ||
663 | #ifdef __NR_ioprio_get | ||
664 | {"ioprio_get", __NR_ioprio_get}, | ||
665 | #endif | ||
666 | #endif | ||
667 | #ifdef SYS_ioprio_set | ||
668 | #ifdef __NR_ioprio_set | ||
669 | {"ioprio_set", __NR_ioprio_set}, | ||
670 | #endif | ||
671 | #endif | ||
672 | #ifdef SYS_ipc | ||
673 | #ifdef __NR_ipc | ||
674 | {"ipc", __NR_ipc}, | ||
675 | #endif | ||
676 | #endif | ||
677 | #ifdef SYS_kcmp | ||
678 | #ifdef __NR_kcmp | ||
679 | {"kcmp", __NR_kcmp}, | ||
680 | #endif | ||
681 | #endif | ||
682 | #ifdef SYS_kexec_load | ||
683 | #ifdef __NR_kexec_load | ||
684 | {"kexec_load", __NR_kexec_load}, | ||
685 | #endif | ||
686 | #endif | ||
687 | #ifdef SYS_keyctl | ||
688 | #ifdef __NR_keyctl | ||
689 | {"keyctl", __NR_keyctl}, | ||
690 | #endif | ||
691 | #endif | ||
692 | #ifdef SYS_kill | ||
693 | #ifdef __NR_kill | ||
694 | {"kill", __NR_kill}, | ||
695 | #endif | ||
696 | #endif | ||
697 | #ifdef SYS_lchown | ||
698 | #ifdef __NR_lchown | ||
699 | {"lchown", __NR_lchown}, | ||
700 | #endif | ||
701 | #endif | ||
702 | #ifdef SYS_lchown32 | ||
703 | #ifdef __NR_lchown32 | ||
704 | {"lchown32", __NR_lchown32}, | ||
705 | #endif | ||
706 | #endif | ||
707 | #ifdef SYS_lgetxattr | ||
708 | #ifdef __NR_lgetxattr | ||
709 | {"lgetxattr", __NR_lgetxattr}, | ||
710 | #endif | ||
711 | #endif | ||
712 | #ifdef SYS_link | ||
713 | #ifdef __NR_link | ||
714 | {"link", __NR_link}, | ||
715 | #endif | ||
716 | #endif | ||
717 | #ifdef SYS_linkat | ||
718 | #ifdef __NR_linkat | ||
719 | {"linkat", __NR_linkat}, | ||
720 | #endif | ||
721 | #endif | ||
722 | #ifdef SYS_listxattr | ||
723 | #ifdef __NR_listxattr | ||
724 | {"listxattr", __NR_listxattr}, | ||
725 | #endif | ||
726 | #endif | ||
727 | #ifdef SYS_llistxattr | ||
728 | #ifdef __NR_llistxattr | ||
729 | {"llistxattr", __NR_llistxattr}, | ||
730 | #endif | ||
731 | #endif | ||
732 | #ifdef SYS_lock | ||
733 | #ifdef __NR_lock | ||
734 | {"lock", __NR_lock}, | ||
735 | #endif | ||
736 | #endif | ||
737 | #ifdef SYS_lookup_dcookie | ||
738 | #ifdef __NR_lookup_dcookie | ||
739 | {"lookup_dcookie", __NR_lookup_dcookie}, | ||
740 | #endif | ||
741 | #endif | ||
742 | #ifdef SYS_lremovexattr | ||
743 | #ifdef __NR_lremovexattr | ||
744 | {"lremovexattr", __NR_lremovexattr}, | ||
745 | #endif | ||
746 | #endif | ||
747 | #ifdef SYS_lseek | ||
748 | #ifdef __NR_lseek | ||
749 | {"lseek", __NR_lseek}, | ||
750 | #endif | ||
751 | #endif | ||
752 | #ifdef SYS_lsetxattr | ||
753 | #ifdef __NR_lsetxattr | ||
754 | {"lsetxattr", __NR_lsetxattr}, | ||
755 | #endif | ||
756 | #endif | ||
757 | #ifdef SYS_lstat | ||
758 | #ifdef __NR_lstat | ||
759 | {"lstat", __NR_lstat}, | ||
760 | #endif | ||
761 | #endif | ||
762 | #ifdef SYS_lstat64 | ||
763 | #ifdef __NR_lstat64 | ||
764 | {"lstat64", __NR_lstat64}, | ||
765 | #endif | ||
766 | #endif | ||
767 | #ifdef SYS_madvise | ||
768 | #ifdef __NR_madvise | ||
769 | {"madvise", __NR_madvise}, | ||
770 | #endif | ||
771 | #endif | ||
772 | #ifdef SYS_mbind | ||
773 | #ifdef __NR_mbind | ||
774 | {"mbind", __NR_mbind}, | ||
775 | #endif | ||
776 | #endif | ||
777 | #ifdef SYS_migrate_pages | ||
778 | #ifdef __NR_migrate_pages | ||
779 | {"migrate_pages", __NR_migrate_pages}, | ||
780 | #endif | ||
781 | #endif | ||
782 | #ifdef SYS_mincore | ||
783 | #ifdef __NR_mincore | ||
784 | {"mincore", __NR_mincore}, | ||
785 | #endif | ||
786 | #endif | ||
787 | #ifdef SYS_mkdir | ||
788 | #ifdef __NR_mkdir | ||
789 | {"mkdir", __NR_mkdir}, | ||
790 | #endif | ||
791 | #endif | ||
792 | #ifdef SYS_mkdirat | ||
793 | #ifdef __NR_mkdirat | ||
794 | {"mkdirat", __NR_mkdirat}, | ||
795 | #endif | ||
796 | #endif | ||
797 | #ifdef SYS_mknod | ||
798 | #ifdef __NR_mknod | ||
799 | {"mknod", __NR_mknod}, | ||
800 | #endif | ||
801 | #endif | ||
802 | #ifdef SYS_mknodat | ||
803 | #ifdef __NR_mknodat | ||
804 | {"mknodat", __NR_mknodat}, | ||
805 | #endif | ||
806 | #endif | ||
807 | #ifdef SYS_mlock | ||
808 | #ifdef __NR_mlock | ||
809 | {"mlock", __NR_mlock}, | ||
810 | #endif | ||
811 | #endif | ||
812 | #ifdef SYS_mlockall | ||
813 | #ifdef __NR_mlockall | ||
814 | {"mlockall", __NR_mlockall}, | ||
815 | #endif | ||
816 | #endif | ||
817 | #ifdef SYS_mmap | ||
818 | #ifdef __NR_mmap | ||
819 | {"mmap", __NR_mmap}, | ||
820 | #endif | ||
821 | #endif | ||
822 | #ifdef SYS_mmap2 | ||
823 | #ifdef __NR_mmap2 | ||
824 | {"mmap2", __NR_mmap2}, | ||
825 | #endif | ||
826 | #endif | ||
827 | #ifdef SYS_modify_ldt | ||
828 | #ifdef __NR_modify_ldt | ||
829 | {"modify_ldt", __NR_modify_ldt}, | ||
830 | #endif | ||
831 | #endif | ||
832 | #ifdef SYS_mount | ||
833 | #ifdef __NR_mount | ||
834 | {"mount", __NR_mount}, | ||
835 | #endif | ||
836 | #endif | ||
837 | #ifdef SYS_move_pages | ||
838 | #ifdef __NR_move_pages | ||
839 | {"move_pages", __NR_move_pages}, | ||
840 | #endif | ||
841 | #endif | ||
842 | #ifdef SYS_mprotect | ||
843 | #ifdef __NR_mprotect | ||
844 | {"mprotect", __NR_mprotect}, | ||
845 | #endif | ||
846 | #endif | ||
847 | #ifdef SYS_mpx | ||
848 | #ifdef __NR_mpx | ||
849 | {"mpx", __NR_mpx}, | ||
850 | #endif | ||
851 | #endif | ||
852 | #ifdef SYS_mq_getsetattr | ||
853 | #ifdef __NR_mq_getsetattr | ||
854 | {"mq_getsetattr", __NR_mq_getsetattr}, | ||
855 | #endif | ||
856 | #endif | ||
857 | #ifdef SYS_mq_notify | ||
858 | #ifdef __NR_mq_notify | ||
859 | {"mq_notify", __NR_mq_notify}, | ||
860 | #endif | ||
861 | #endif | ||
862 | #ifdef SYS_mq_open | ||
863 | #ifdef __NR_mq_open | ||
864 | {"mq_open", __NR_mq_open}, | ||
865 | #endif | ||
866 | #endif | ||
867 | #ifdef SYS_mq_timedreceive | ||
868 | #ifdef __NR_mq_timedreceive | ||
869 | {"mq_timedreceive", __NR_mq_timedreceive}, | ||
870 | #endif | ||
871 | #endif | ||
872 | #ifdef SYS_mq_timedsend | ||
873 | #ifdef __NR_mq_timedsend | ||
874 | {"mq_timedsend", __NR_mq_timedsend}, | ||
875 | #endif | ||
876 | #endif | ||
877 | #ifdef SYS_mq_unlink | ||
878 | #ifdef __NR_mq_unlink | ||
879 | {"mq_unlink", __NR_mq_unlink}, | ||
880 | #endif | ||
881 | #endif | ||
882 | #ifdef SYS_mremap | ||
883 | #ifdef __NR_mremap | ||
884 | {"mremap", __NR_mremap}, | ||
885 | #endif | ||
886 | #endif | ||
887 | #ifdef SYS_msync | ||
888 | #ifdef __NR_msync | ||
889 | {"msync", __NR_msync}, | ||
890 | #endif | ||
891 | #endif | ||
892 | #ifdef SYS_munlock | ||
893 | #ifdef __NR_munlock | ||
894 | {"munlock", __NR_munlock}, | ||
895 | #endif | ||
896 | #endif | ||
897 | #ifdef SYS_munlockall | ||
898 | #ifdef __NR_munlockall | ||
899 | {"munlockall", __NR_munlockall}, | ||
900 | #endif | ||
901 | #endif | ||
902 | #ifdef SYS_munmap | ||
903 | #ifdef __NR_munmap | ||
904 | {"munmap", __NR_munmap}, | ||
905 | #endif | ||
906 | #endif | ||
907 | #ifdef SYS_name_to_handle_at | ||
908 | #ifdef __NR_name_to_handle_at | ||
909 | {"name_to_handle_at", __NR_name_to_handle_at}, | ||
910 | #endif | ||
911 | #endif | ||
912 | #ifdef SYS_nanosleep | ||
913 | #ifdef __NR_nanosleep | ||
914 | {"nanosleep", __NR_nanosleep}, | ||
915 | #endif | ||
916 | #endif | ||
917 | #ifdef SYS_nfsservctl | ||
918 | #ifdef __NR_nfsservctl | ||
919 | {"nfsservctl", __NR_nfsservctl}, | ||
920 | #endif | ||
921 | #endif | ||
922 | #ifdef SYS_nice | ||
923 | #ifdef __NR_nice | ||
924 | {"nice", __NR_nice}, | ||
925 | #endif | ||
926 | #endif | ||
927 | #ifdef SYS_oldfstat | ||
928 | #ifdef __NR_oldfstat | ||
929 | {"oldfstat", __NR_oldfstat}, | ||
930 | #endif | ||
931 | #endif | ||
932 | #ifdef SYS_oldlstat | ||
933 | #ifdef __NR_oldlstat | ||
934 | {"oldlstat", __NR_oldlstat}, | ||
935 | #endif | ||
936 | #endif | ||
937 | #ifdef SYS_oldolduname | ||
938 | #ifdef __NR_oldolduname | ||
939 | {"oldolduname", __NR_oldolduname}, | ||
940 | #endif | ||
941 | #endif | ||
942 | #ifdef SYS_oldstat | ||
943 | #ifdef __NR_oldstat | ||
944 | {"oldstat", __NR_oldstat}, | ||
945 | #endif | ||
946 | #endif | ||
947 | #ifdef SYS_olduname | ||
948 | #ifdef __NR_olduname | ||
949 | {"olduname", __NR_olduname}, | ||
950 | #endif | ||
951 | #endif | ||
952 | #ifdef SYS_open | ||
953 | #ifdef __NR_open | ||
954 | {"open", __NR_open}, | ||
955 | #endif | ||
956 | #endif | ||
957 | #ifdef SYS_open_by_handle_at | ||
958 | #ifdef __NR_open_by_handle_at | ||
959 | {"open_by_handle_at", __NR_open_by_handle_at}, | ||
960 | #endif | ||
961 | #endif | ||
962 | #ifdef SYS_openat | ||
963 | #ifdef __NR_openat | ||
964 | {"openat", __NR_openat}, | ||
965 | #endif | ||
966 | #endif | ||
967 | #ifdef SYS_pause | ||
968 | #ifdef __NR_pause | ||
969 | {"pause", __NR_pause}, | ||
970 | #endif | ||
971 | #endif | ||
972 | #ifdef SYS_perf_event_open | ||
973 | #ifdef __NR_perf_event_open | ||
974 | {"perf_event_open", __NR_perf_event_open}, | ||
975 | #endif | ||
976 | #endif | ||
977 | #ifdef SYS_personality | ||
978 | #ifdef __NR_personality | ||
979 | {"personality", __NR_personality}, | ||
980 | #endif | ||
981 | #endif | ||
982 | #ifdef SYS_pipe | ||
983 | #ifdef __NR_pipe | ||
984 | {"pipe", __NR_pipe}, | ||
985 | #endif | ||
986 | #endif | ||
987 | #ifdef SYS_pipe2 | ||
988 | #ifdef __NR_pipe2 | ||
989 | {"pipe2", __NR_pipe2}, | ||
990 | #endif | ||
991 | #endif | ||
992 | #ifdef SYS_pivot_root | ||
993 | #ifdef __NR_pivot_root | ||
994 | {"pivot_root", __NR_pivot_root}, | ||
995 | #endif | ||
996 | #endif | ||
997 | #ifdef SYS_poll | ||
998 | #ifdef __NR_poll | ||
999 | {"poll", __NR_poll}, | ||
1000 | #endif | ||
1001 | #endif | ||
1002 | #ifdef SYS_ppoll | ||
1003 | #ifdef __NR_ppoll | ||
1004 | {"ppoll", __NR_ppoll}, | ||
1005 | #endif | ||
1006 | #endif | ||
1007 | #ifdef SYS_prctl | ||
1008 | #ifdef __NR_prctl | ||
1009 | {"prctl", __NR_prctl}, | ||
1010 | #endif | ||
1011 | #endif | ||
1012 | #ifdef SYS_pread64 | ||
1013 | #ifdef __NR_pread64 | ||
1014 | {"pread64", __NR_pread64}, | ||
1015 | #endif | ||
1016 | #endif | ||
1017 | #ifdef SYS_preadv | ||
1018 | #ifdef __NR_preadv | ||
1019 | {"preadv", __NR_preadv}, | ||
1020 | #endif | ||
1021 | #endif | ||
1022 | #ifdef SYS_prlimit64 | ||
1023 | #ifdef __NR_prlimit64 | ||
1024 | {"prlimit64", __NR_prlimit64}, | ||
1025 | #endif | ||
1026 | #endif | ||
1027 | #ifdef SYS_process_vm_readv | ||
1028 | #ifdef __NR_process_vm_readv | ||
1029 | {"process_vm_readv", __NR_process_vm_readv}, | ||
1030 | #endif | ||
1031 | #endif | ||
1032 | #ifdef SYS_process_vm_writev | ||
1033 | #ifdef __NR_process_vm_writev | ||
1034 | {"process_vm_writev", __NR_process_vm_writev}, | ||
1035 | #endif | ||
1036 | #endif | ||
1037 | #ifdef SYS_prof | ||
1038 | #ifdef __NR_prof | ||
1039 | {"prof", __NR_prof}, | ||
1040 | #endif | ||
1041 | #endif | ||
1042 | #ifdef SYS_profil | ||
1043 | #ifdef __NR_profil | ||
1044 | {"profil", __NR_profil}, | ||
1045 | #endif | ||
1046 | #endif | ||
1047 | #ifdef SYS_pselect6 | ||
1048 | #ifdef __NR_pselect6 | ||
1049 | {"pselect6", __NR_pselect6}, | ||
1050 | #endif | ||
1051 | #endif | ||
1052 | #ifdef SYS_ptrace | ||
1053 | #ifdef __NR_ptrace | ||
1054 | {"ptrace", __NR_ptrace}, | ||
1055 | #endif | ||
1056 | #endif | ||
1057 | #ifdef SYS_putpmsg | ||
1058 | #ifdef __NR_putpmsg | ||
1059 | {"putpmsg", __NR_putpmsg}, | ||
1060 | #endif | ||
1061 | #endif | ||
1062 | #ifdef SYS_pwrite64 | ||
1063 | #ifdef __NR_pwrite64 | ||
1064 | {"pwrite64", __NR_pwrite64}, | ||
1065 | #endif | ||
1066 | #endif | ||
1067 | #ifdef SYS_pwritev | ||
1068 | #ifdef __NR_pwritev | ||
1069 | {"pwritev", __NR_pwritev}, | ||
1070 | #endif | ||
1071 | #endif | ||
1072 | #ifdef SYS_query_module | ||
1073 | #ifdef __NR_query_module | ||
1074 | {"query_module", __NR_query_module}, | ||
1075 | #endif | ||
1076 | #endif | ||
1077 | #ifdef SYS_quotactl | ||
1078 | #ifdef __NR_quotactl | ||
1079 | {"quotactl", __NR_quotactl}, | ||
1080 | #endif | ||
1081 | #endif | ||
1082 | #ifdef SYS_read | ||
1083 | #ifdef __NR_read | ||
1084 | {"read", __NR_read}, | ||
1085 | #endif | ||
1086 | #endif | ||
1087 | #ifdef SYS_readahead | ||
1088 | #ifdef __NR_readahead | ||
1089 | {"readahead", __NR_readahead}, | ||
1090 | #endif | ||
1091 | #endif | ||
1092 | #ifdef SYS_readdir | ||
1093 | #ifdef __NR_readdir | ||
1094 | {"readdir", __NR_readdir}, | ||
1095 | #endif | ||
1096 | #endif | ||
1097 | #ifdef SYS_readlink | ||
1098 | #ifdef __NR_readlink | ||
1099 | {"readlink", __NR_readlink}, | ||
1100 | #endif | ||
1101 | #endif | ||
1102 | #ifdef SYS_readlinkat | ||
1103 | #ifdef __NR_readlinkat | ||
1104 | {"readlinkat", __NR_readlinkat}, | ||
1105 | #endif | ||
1106 | #endif | ||
1107 | #ifdef SYS_readv | ||
1108 | #ifdef __NR_readv | ||
1109 | {"readv", __NR_readv}, | ||
1110 | #endif | ||
1111 | #endif | ||
1112 | #ifdef SYS_reboot | ||
1113 | #ifdef __NR_reboot | ||
1114 | {"reboot", __NR_reboot}, | ||
1115 | #endif | ||
1116 | #endif | ||
1117 | #ifdef SYS_recvmmsg | ||
1118 | #ifdef __NR_recvmmsg | ||
1119 | {"recvmmsg", __NR_recvmmsg}, | ||
1120 | #endif | ||
1121 | #endif | ||
1122 | #ifdef SYS_remap_file_pages | ||
1123 | #ifdef __NR_remap_file_pages | ||
1124 | {"remap_file_pages", __NR_remap_file_pages}, | ||
1125 | #endif | ||
1126 | #endif | ||
1127 | #ifdef SYS_removexattr | ||
1128 | #ifdef __NR_removexattr | ||
1129 | {"removexattr", __NR_removexattr}, | ||
1130 | #endif | ||
1131 | #endif | ||
1132 | #ifdef SYS_rename | ||
1133 | #ifdef __NR_rename | ||
1134 | {"rename", __NR_rename}, | ||
1135 | #endif | ||
1136 | #endif | ||
1137 | #ifdef SYS_renameat | ||
1138 | #ifdef __NR_renameat | ||
1139 | {"renameat", __NR_renameat}, | ||
1140 | #endif | ||
1141 | #endif | ||
1142 | #ifdef SYS_request_key | ||
1143 | #ifdef __NR_request_key | ||
1144 | {"request_key", __NR_request_key}, | ||
1145 | #endif | ||
1146 | #endif | ||
1147 | #ifdef SYS_restart_syscall | ||
1148 | #ifdef __NR_restart_syscall | ||
1149 | {"restart_syscall", __NR_restart_syscall}, | ||
1150 | #endif | ||
1151 | #endif | ||
1152 | #ifdef SYS_rmdir | ||
1153 | #ifdef __NR_rmdir | ||
1154 | {"rmdir", __NR_rmdir}, | ||
1155 | #endif | ||
1156 | #endif | ||
1157 | #ifdef SYS_rt_sigaction | ||
1158 | #ifdef __NR_rt_sigaction | ||
1159 | {"rt_sigaction", __NR_rt_sigaction}, | ||
1160 | #endif | ||
1161 | #endif | ||
1162 | #ifdef SYS_rt_sigpending | ||
1163 | #ifdef __NR_rt_sigpending | ||
1164 | {"rt_sigpending", __NR_rt_sigpending}, | ||
1165 | #endif | ||
1166 | #endif | ||
1167 | #ifdef SYS_rt_sigprocmask | ||
1168 | #ifdef __NR_rt_sigprocmask | ||
1169 | {"rt_sigprocmask", __NR_rt_sigprocmask}, | ||
1170 | #endif | ||
1171 | #endif | ||
1172 | #ifdef SYS_rt_sigqueueinfo | ||
1173 | #ifdef __NR_rt_sigqueueinfo | ||
1174 | {"rt_sigqueueinfo", __NR_rt_sigqueueinfo}, | ||
1175 | #endif | ||
1176 | #endif | ||
1177 | #ifdef SYS_rt_sigreturn | ||
1178 | #ifdef __NR_rt_sigreturn | ||
1179 | {"rt_sigreturn", __NR_rt_sigreturn}, | ||
1180 | #endif | ||
1181 | #endif | ||
1182 | #ifdef SYS_rt_sigsuspend | ||
1183 | #ifdef __NR_rt_sigsuspend | ||
1184 | {"rt_sigsuspend", __NR_rt_sigsuspend}, | ||
1185 | #endif | ||
1186 | #endif | ||
1187 | #ifdef SYS_rt_sigtimedwait | ||
1188 | #ifdef __NR_rt_sigtimedwait | ||
1189 | {"rt_sigtimedwait", __NR_rt_sigtimedwait}, | ||
1190 | #endif | ||
1191 | #endif | ||
1192 | #ifdef SYS_rt_tgsigqueueinfo | ||
1193 | #ifdef __NR_rt_tgsigqueueinfo | ||
1194 | {"rt_tgsigqueueinfo", __NR_rt_tgsigqueueinfo}, | ||
1195 | #endif | ||
1196 | #endif | ||
1197 | #ifdef SYS_sched_get_priority_max | ||
1198 | #ifdef __NR_sched_get_priority_max | ||
1199 | {"sched_get_priority_max", __NR_sched_get_priority_max}, | ||
1200 | #endif | ||
1201 | #endif | ||
1202 | #ifdef SYS_sched_get_priority_min | ||
1203 | #ifdef __NR_sched_get_priority_min | ||
1204 | {"sched_get_priority_min", __NR_sched_get_priority_min}, | ||
1205 | #endif | ||
1206 | #endif | ||
1207 | #ifdef SYS_sched_getaffinity | ||
1208 | #ifdef __NR_sched_getaffinity | ||
1209 | {"sched_getaffinity", __NR_sched_getaffinity}, | ||
1210 | #endif | ||
1211 | #endif | ||
1212 | #ifdef SYS_sched_getparam | ||
1213 | #ifdef __NR_sched_getparam | ||
1214 | {"sched_getparam", __NR_sched_getparam}, | ||
1215 | #endif | ||
1216 | #endif | ||
1217 | #ifdef SYS_sched_getscheduler | ||
1218 | #ifdef __NR_sched_getscheduler | ||
1219 | {"sched_getscheduler", __NR_sched_getscheduler}, | ||
1220 | #endif | ||
1221 | #endif | ||
1222 | #ifdef SYS_sched_rr_get_interval | ||
1223 | #ifdef __NR_sched_rr_get_interval | ||
1224 | {"sched_rr_get_interval", __NR_sched_rr_get_interval}, | ||
1225 | #endif | ||
1226 | #endif | ||
1227 | #ifdef SYS_sched_setaffinity | ||
1228 | #ifdef __NR_sched_setaffinity | ||
1229 | {"sched_setaffinity", __NR_sched_setaffinity}, | ||
1230 | #endif | ||
1231 | #endif | ||
1232 | #ifdef SYS_sched_setparam | ||
1233 | #ifdef __NR_sched_setparam | ||
1234 | {"sched_setparam", __NR_sched_setparam}, | ||
1235 | #endif | ||
1236 | #endif | ||
1237 | #ifdef SYS_sched_setscheduler | ||
1238 | #ifdef __NR_sched_setscheduler | ||
1239 | {"sched_setscheduler", __NR_sched_setscheduler}, | ||
1240 | #endif | ||
1241 | #endif | ||
1242 | #ifdef SYS_sched_yield | ||
1243 | #ifdef __NR_sched_yield | ||
1244 | {"sched_yield", __NR_sched_yield}, | ||
1245 | #endif | ||
1246 | #endif | ||
1247 | #ifdef SYS_select | ||
1248 | #ifdef __NR_select | ||
1249 | {"select", __NR_select}, | ||
1250 | #endif | ||
1251 | #endif | ||
1252 | #ifdef SYS_sendfile | ||
1253 | #ifdef __NR_sendfile | ||
1254 | {"sendfile", __NR_sendfile}, | ||
1255 | #endif | ||
1256 | #endif | ||
1257 | #ifdef SYS_sendfile64 | ||
1258 | #ifdef __NR_sendfile64 | ||
1259 | {"sendfile64", __NR_sendfile64}, | ||
1260 | #endif | ||
1261 | #endif | ||
1262 | #ifdef SYS_sendmmsg | ||
1263 | #ifdef __NR_sendmmsg | ||
1264 | {"sendmmsg", __NR_sendmmsg}, | ||
1265 | #endif | ||
1266 | #endif | ||
1267 | #ifdef SYS_set_mempolicy | ||
1268 | #ifdef __NR_set_mempolicy | ||
1269 | {"set_mempolicy", __NR_set_mempolicy}, | ||
1270 | #endif | ||
1271 | #endif | ||
1272 | #ifdef SYS_set_robust_list | ||
1273 | #ifdef __NR_set_robust_list | ||
1274 | {"set_robust_list", __NR_set_robust_list}, | ||
1275 | #endif | ||
1276 | #endif | ||
1277 | #ifdef SYS_set_thread_area | ||
1278 | #ifdef __NR_set_thread_area | ||
1279 | {"set_thread_area", __NR_set_thread_area}, | ||
1280 | #endif | ||
1281 | #endif | ||
1282 | #ifdef SYS_set_tid_address | ||
1283 | #ifdef __NR_set_tid_address | ||
1284 | {"set_tid_address", __NR_set_tid_address}, | ||
1285 | #endif | ||
1286 | #endif | ||
1287 | #ifdef SYS_setdomainname | ||
1288 | #ifdef __NR_setdomainname | ||
1289 | {"setdomainname", __NR_setdomainname}, | ||
1290 | #endif | ||
1291 | #endif | ||
1292 | #ifdef SYS_setfsgid | ||
1293 | #ifdef __NR_setfsgid | ||
1294 | {"setfsgid", __NR_setfsgid}, | ||
1295 | #endif | ||
1296 | #endif | ||
1297 | #ifdef SYS_setfsgid32 | ||
1298 | #ifdef __NR_setfsgid32 | ||
1299 | {"setfsgid32", __NR_setfsgid32}, | ||
1300 | #endif | ||
1301 | #endif | ||
1302 | #ifdef SYS_setfsuid | ||
1303 | #ifdef __NR_setfsuid | ||
1304 | {"setfsuid", __NR_setfsuid}, | ||
1305 | #endif | ||
1306 | #endif | ||
1307 | #ifdef SYS_setfsuid32 | ||
1308 | #ifdef __NR_setfsuid32 | ||
1309 | {"setfsuid32", __NR_setfsuid32}, | ||
1310 | #endif | ||
1311 | #endif | ||
1312 | #ifdef SYS_setgid | ||
1313 | #ifdef __NR_setgid | ||
1314 | {"setgid", __NR_setgid}, | ||
1315 | #endif | ||
1316 | #endif | ||
1317 | #ifdef SYS_setgid32 | ||
1318 | #ifdef __NR_setgid32 | ||
1319 | {"setgid32", __NR_setgid32}, | ||
1320 | #endif | ||
1321 | #endif | ||
1322 | #ifdef SYS_setgroups | ||
1323 | #ifdef __NR_setgroups | ||
1324 | {"setgroups", __NR_setgroups}, | ||
1325 | #endif | ||
1326 | #endif | ||
1327 | #ifdef SYS_setgroups32 | ||
1328 | #ifdef __NR_setgroups32 | ||
1329 | {"setgroups32", __NR_setgroups32}, | ||
1330 | #endif | ||
1331 | #endif | ||
1332 | #ifdef SYS_sethostname | ||
1333 | #ifdef __NR_sethostname | ||
1334 | {"sethostname", __NR_sethostname}, | ||
1335 | #endif | ||
1336 | #endif | ||
1337 | #ifdef SYS_setitimer | ||
1338 | #ifdef __NR_setitimer | ||
1339 | {"setitimer", __NR_setitimer}, | ||
1340 | #endif | ||
1341 | #endif | ||
1342 | #ifdef SYS_setns | ||
1343 | #ifdef __NR_setns | ||
1344 | {"setns", __NR_setns}, | ||
1345 | #endif | ||
1346 | #endif | ||
1347 | #ifdef SYS_setpgid | ||
1348 | #ifdef __NR_setpgid | ||
1349 | {"setpgid", __NR_setpgid}, | ||
1350 | #endif | ||
1351 | #endif | ||
1352 | #ifdef SYS_setpriority | ||
1353 | #ifdef __NR_setpriority | ||
1354 | {"setpriority", __NR_setpriority}, | ||
1355 | #endif | ||
1356 | #endif | ||
1357 | #ifdef SYS_setregid | ||
1358 | #ifdef __NR_setregid | ||
1359 | {"setregid", __NR_setregid}, | ||
1360 | #endif | ||
1361 | #endif | ||
1362 | #ifdef SYS_setregid32 | ||
1363 | #ifdef __NR_setregid32 | ||
1364 | {"setregid32", __NR_setregid32}, | ||
1365 | #endif | ||
1366 | #endif | ||
1367 | #ifdef SYS_setresgid | ||
1368 | #ifdef __NR_setresgid | ||
1369 | {"setresgid", __NR_setresgid}, | ||
1370 | #endif | ||
1371 | #endif | ||
1372 | #ifdef SYS_setresgid32 | ||
1373 | #ifdef __NR_setresgid32 | ||
1374 | {"setresgid32", __NR_setresgid32}, | ||
1375 | #endif | ||
1376 | #endif | ||
1377 | #ifdef SYS_setresuid | ||
1378 | #ifdef __NR_setresuid | ||
1379 | {"setresuid", __NR_setresuid}, | ||
1380 | #endif | ||
1381 | #endif | ||
1382 | #ifdef SYS_setresuid32 | ||
1383 | #ifdef __NR_setresuid32 | ||
1384 | {"setresuid32", __NR_setresuid32}, | ||
1385 | #endif | ||
1386 | #endif | ||
1387 | #ifdef SYS_setreuid | ||
1388 | #ifdef __NR_setreuid | ||
1389 | {"setreuid", __NR_setreuid}, | ||
1390 | #endif | ||
1391 | #endif | ||
1392 | #ifdef SYS_setreuid32 | ||
1393 | #ifdef __NR_setreuid32 | ||
1394 | {"setreuid32", __NR_setreuid32}, | ||
1395 | #endif | ||
1396 | #endif | ||
1397 | #ifdef SYS_setrlimit | ||
1398 | #ifdef __NR_setrlimit | ||
1399 | {"setrlimit", __NR_setrlimit}, | ||
1400 | #endif | ||
1401 | #endif | ||
1402 | #ifdef SYS_setsid | ||
1403 | #ifdef __NR_setsid | ||
1404 | {"setsid", __NR_setsid}, | ||
1405 | #endif | ||
1406 | #endif | ||
1407 | #ifdef SYS_settimeofday | ||
1408 | #ifdef __NR_settimeofday | ||
1409 | {"settimeofday", __NR_settimeofday}, | ||
1410 | #endif | ||
1411 | #endif | ||
1412 | #ifdef SYS_setuid | ||
1413 | #ifdef __NR_setuid | ||
1414 | {"setuid", __NR_setuid}, | ||
1415 | #endif | ||
1416 | #endif | ||
1417 | #ifdef SYS_setuid32 | ||
1418 | #ifdef __NR_setuid32 | ||
1419 | {"setuid32", __NR_setuid32}, | ||
1420 | #endif | ||
1421 | #endif | ||
1422 | #ifdef SYS_setxattr | ||
1423 | #ifdef __NR_setxattr | ||
1424 | {"setxattr", __NR_setxattr}, | ||
1425 | #endif | ||
1426 | #endif | ||
1427 | #ifdef SYS_sgetmask | ||
1428 | #ifdef __NR_sgetmask | ||
1429 | {"sgetmask", __NR_sgetmask}, | ||
1430 | #endif | ||
1431 | #endif | ||
1432 | #ifdef SYS_sigaction | ||
1433 | #ifdef __NR_sigaction | ||
1434 | {"sigaction", __NR_sigaction}, | ||
1435 | #endif | ||
1436 | #endif | ||
1437 | #ifdef SYS_sigaltstack | ||
1438 | #ifdef __NR_sigaltstack | ||
1439 | {"sigaltstack", __NR_sigaltstack}, | ||
1440 | #endif | ||
1441 | #endif | ||
1442 | #ifdef SYS_signal | ||
1443 | #ifdef __NR_signal | ||
1444 | {"signal", __NR_signal}, | ||
1445 | #endif | ||
1446 | #endif | ||
1447 | #ifdef SYS_signalfd | ||
1448 | #ifdef __NR_signalfd | ||
1449 | {"signalfd", __NR_signalfd}, | ||
1450 | #endif | ||
1451 | #endif | ||
1452 | #ifdef SYS_signalfd4 | ||
1453 | #ifdef __NR_signalfd4 | ||
1454 | {"signalfd4", __NR_signalfd4}, | ||
1455 | #endif | ||
1456 | #endif | ||
1457 | #ifdef SYS_sigpending | ||
1458 | #ifdef __NR_sigpending | ||
1459 | {"sigpending", __NR_sigpending}, | ||
1460 | #endif | ||
1461 | #endif | ||
1462 | #ifdef SYS_sigprocmask | ||
1463 | #ifdef __NR_sigprocmask | ||
1464 | {"sigprocmask", __NR_sigprocmask}, | ||
1465 | #endif | ||
1466 | #endif | ||
1467 | #ifdef SYS_sigreturn | ||
1468 | #ifdef __NR_sigreturn | ||
1469 | {"sigreturn", __NR_sigreturn}, | ||
1470 | #endif | ||
1471 | #endif | ||
1472 | #ifdef SYS_sigsuspend | ||
1473 | #ifdef __NR_sigsuspend | ||
1474 | {"sigsuspend", __NR_sigsuspend}, | ||
1475 | #endif | ||
1476 | #endif | ||
1477 | #ifdef SYS_socketcall | ||
1478 | #ifdef __NR_socketcall | ||
1479 | {"socketcall", __NR_socketcall}, | ||
1480 | #endif | ||
1481 | #endif | ||
1482 | #ifdef SYS_splice | ||
1483 | #ifdef __NR_splice | ||
1484 | {"splice", __NR_splice}, | ||
1485 | #endif | ||
1486 | #endif | ||
1487 | #ifdef SYS_ssetmask | ||
1488 | #ifdef __NR_ssetmask | ||
1489 | {"ssetmask", __NR_ssetmask}, | ||
1490 | #endif | ||
1491 | #endif | ||
1492 | #ifdef SYS_stat | ||
1493 | #ifdef __NR_stat | ||
1494 | {"stat", __NR_stat}, | ||
1495 | #endif | ||
1496 | #endif | ||
1497 | #ifdef SYS_stat64 | ||
1498 | #ifdef __NR_stat64 | ||
1499 | {"stat64", __NR_stat64}, | ||
1500 | #endif | ||
1501 | #endif | ||
1502 | #ifdef SYS_statfs | ||
1503 | #ifdef __NR_statfs | ||
1504 | {"statfs", __NR_statfs}, | ||
1505 | #endif | ||
1506 | #endif | ||
1507 | #ifdef SYS_statfs64 | ||
1508 | #ifdef __NR_statfs64 | ||
1509 | {"statfs64", __NR_statfs64}, | ||
1510 | #endif | ||
1511 | #endif | ||
1512 | #ifdef SYS_stime | ||
1513 | #ifdef __NR_stime | ||
1514 | {"stime", __NR_stime}, | ||
1515 | #endif | ||
1516 | #endif | ||
1517 | #ifdef SYS_stty | ||
1518 | #ifdef __NR_stty | ||
1519 | {"stty", __NR_stty}, | ||
1520 | #endif | ||
1521 | #endif | ||
1522 | #ifdef SYS_swapoff | ||
1523 | #ifdef __NR_swapoff | ||
1524 | {"swapoff", __NR_swapoff}, | ||
1525 | #endif | ||
1526 | #endif | ||
1527 | #ifdef SYS_swapon | ||
1528 | #ifdef __NR_swapon | ||
1529 | {"swapon", __NR_swapon}, | ||
1530 | #endif | ||
1531 | #endif | ||
1532 | #ifdef SYS_symlink | ||
1533 | #ifdef __NR_symlink | ||
1534 | {"symlink", __NR_symlink}, | ||
1535 | #endif | ||
1536 | #endif | ||
1537 | #ifdef SYS_symlinkat | ||
1538 | #ifdef __NR_symlinkat | ||
1539 | {"symlinkat", __NR_symlinkat}, | ||
1540 | #endif | ||
1541 | #endif | ||
1542 | #ifdef SYS_sync | ||
1543 | #ifdef __NR_sync | ||
1544 | {"sync", __NR_sync}, | ||
1545 | #endif | ||
1546 | #endif | ||
1547 | #ifdef SYS_sync_file_range | ||
1548 | #ifdef __NR_sync_file_range | ||
1549 | {"sync_file_range", __NR_sync_file_range}, | ||
1550 | #endif | ||
1551 | #endif | ||
1552 | #ifdef SYS_syncfs | ||
1553 | #ifdef __NR_syncfs | ||
1554 | {"syncfs", __NR_syncfs}, | ||
1555 | #endif | ||
1556 | #endif | ||
1557 | #ifdef SYS_sysfs | ||
1558 | #ifdef __NR_sysfs | ||
1559 | {"sysfs", __NR_sysfs}, | ||
1560 | #endif | ||
1561 | #endif | ||
1562 | #ifdef SYS_sysinfo | ||
1563 | #ifdef __NR_sysinfo | ||
1564 | {"sysinfo", __NR_sysinfo}, | ||
1565 | #endif | ||
1566 | #endif | ||
1567 | #ifdef SYS_syslog | ||
1568 | #ifdef __NR_syslog | ||
1569 | {"syslog", __NR_syslog}, | ||
1570 | #endif | ||
1571 | #endif | ||
1572 | #ifdef SYS_tee | ||
1573 | #ifdef __NR_tee | ||
1574 | {"tee", __NR_tee}, | ||
1575 | #endif | ||
1576 | #endif | ||
1577 | #ifdef SYS_tgkill | ||
1578 | #ifdef __NR_tgkill | ||
1579 | {"tgkill", __NR_tgkill}, | ||
1580 | #endif | ||
1581 | #endif | ||
1582 | #ifdef SYS_time | ||
1583 | #ifdef __NR_time | ||
1584 | {"time", __NR_time}, | ||
1585 | #endif | ||
1586 | #endif | ||
1587 | #ifdef SYS_timer_create | ||
1588 | #ifdef __NR_timer_create | ||
1589 | {"timer_create", __NR_timer_create}, | ||
1590 | #endif | ||
1591 | #endif | ||
1592 | #ifdef SYS_timer_delete | ||
1593 | #ifdef __NR_timer_delete | ||
1594 | {"timer_delete", __NR_timer_delete}, | ||
1595 | #endif | ||
1596 | #endif | ||
1597 | #ifdef SYS_timer_getoverrun | ||
1598 | #ifdef __NR_timer_getoverrun | ||
1599 | {"timer_getoverrun", __NR_timer_getoverrun}, | ||
1600 | #endif | ||
1601 | #endif | ||
1602 | #ifdef SYS_timer_gettime | ||
1603 | #ifdef __NR_timer_gettime | ||
1604 | {"timer_gettime", __NR_timer_gettime}, | ||
1605 | #endif | ||
1606 | #endif | ||
1607 | #ifdef SYS_timer_settime | ||
1608 | #ifdef __NR_timer_settime | ||
1609 | {"timer_settime", __NR_timer_settime}, | ||
1610 | #endif | ||
1611 | #endif | ||
1612 | #ifdef SYS_timerfd_create | ||
1613 | #ifdef __NR_timerfd_create | ||
1614 | {"timerfd_create", __NR_timerfd_create}, | ||
1615 | #endif | ||
1616 | #endif | ||
1617 | #ifdef SYS_timerfd_gettime | ||
1618 | #ifdef __NR_timerfd_gettime | ||
1619 | {"timerfd_gettime", __NR_timerfd_gettime}, | ||
1620 | #endif | ||
1621 | #endif | ||
1622 | #ifdef SYS_timerfd_settime | ||
1623 | #ifdef __NR_timerfd_settime | ||
1624 | {"timerfd_settime", __NR_timerfd_settime}, | ||
1625 | #endif | ||
1626 | #endif | ||
1627 | #ifdef SYS_times | ||
1628 | #ifdef __NR_times | ||
1629 | {"times", __NR_times}, | ||
1630 | #endif | ||
1631 | #endif | ||
1632 | #ifdef SYS_tkill | ||
1633 | #ifdef __NR_tkill | ||
1634 | {"tkill", __NR_tkill}, | ||
1635 | #endif | ||
1636 | #endif | ||
1637 | #ifdef SYS_truncate | ||
1638 | #ifdef __NR_truncate | ||
1639 | {"truncate", __NR_truncate}, | ||
1640 | #endif | ||
1641 | #endif | ||
1642 | #ifdef SYS_truncate64 | ||
1643 | #ifdef __NR_truncate64 | ||
1644 | {"truncate64", __NR_truncate64}, | ||
1645 | #endif | ||
1646 | #endif | ||
1647 | #ifdef SYS_ugetrlimit | ||
1648 | #ifdef __NR_ugetrlimit | ||
1649 | {"ugetrlimit", __NR_ugetrlimit}, | ||
1650 | #endif | ||
1651 | #endif | ||
1652 | #ifdef SYS_ulimit | ||
1653 | #ifdef __NR_ulimit | ||
1654 | {"ulimit", __NR_ulimit}, | ||
1655 | #endif | ||
1656 | #endif | ||
1657 | #ifdef SYS_umask | ||
1658 | #ifdef __NR_umask | ||
1659 | {"umask", __NR_umask}, | ||
1660 | #endif | ||
1661 | #endif | ||
1662 | #ifdef SYS_umount | ||
1663 | #ifdef __NR_umount | ||
1664 | {"umount", __NR_umount}, | ||
1665 | #endif | ||
1666 | #endif | ||
1667 | #ifdef SYS_umount2 | ||
1668 | #ifdef __NR_umount2 | ||
1669 | {"umount2", __NR_umount2}, | ||
1670 | #endif | ||
1671 | #endif | ||
1672 | #ifdef SYS_uname | ||
1673 | #ifdef __NR_uname | ||
1674 | {"uname", __NR_uname}, | ||
1675 | #endif | ||
1676 | #endif | ||
1677 | #ifdef SYS_unlink | ||
1678 | #ifdef __NR_unlink | ||
1679 | {"unlink", __NR_unlink}, | ||
1680 | #endif | ||
1681 | #endif | ||
1682 | #ifdef SYS_unlinkat | ||
1683 | #ifdef __NR_unlinkat | ||
1684 | {"unlinkat", __NR_unlinkat}, | ||
1685 | #endif | ||
1686 | #endif | ||
1687 | #ifdef SYS_unshare | ||
1688 | #ifdef __NR_unshare | ||
1689 | {"unshare", __NR_unshare}, | ||
1690 | #endif | ||
1691 | #endif | ||
1692 | #ifdef SYS_uselib | ||
1693 | #ifdef __NR_uselib | ||
1694 | {"uselib", __NR_uselib}, | ||
1695 | #endif | ||
1696 | #endif | ||
1697 | #ifdef SYS_ustat | ||
1698 | #ifdef __NR_ustat | ||
1699 | {"ustat", __NR_ustat}, | ||
1700 | #endif | ||
1701 | #endif | ||
1702 | #ifdef SYS_utime | ||
1703 | #ifdef __NR_utime | ||
1704 | {"utime", __NR_utime}, | ||
1705 | #endif | ||
1706 | #endif | ||
1707 | #ifdef SYS_utimensat | ||
1708 | #ifdef __NR_utimensat | ||
1709 | {"utimensat", __NR_utimensat}, | ||
1710 | #endif | ||
1711 | #endif | ||
1712 | #ifdef SYS_utimes | ||
1713 | #ifdef __NR_utimes | ||
1714 | {"utimes", __NR_utimes}, | ||
1715 | #endif | ||
1716 | #endif | ||
1717 | #ifdef SYS_vfork | ||
1718 | #ifdef __NR_vfork | ||
1719 | {"vfork", __NR_vfork}, | ||
1720 | #endif | ||
1721 | #endif | ||
1722 | #ifdef SYS_vhangup | ||
1723 | #ifdef __NR_vhangup | ||
1724 | {"vhangup", __NR_vhangup}, | ||
1725 | #endif | ||
1726 | #endif | ||
1727 | #ifdef SYS_vm86 | ||
1728 | #ifdef __NR_vm86 | ||
1729 | {"vm86", __NR_vm86}, | ||
1730 | #endif | ||
1731 | #endif | ||
1732 | #ifdef SYS_vm86old | ||
1733 | #ifdef __NR_vm86old | ||
1734 | {"vm86old", __NR_vm86old}, | ||
1735 | #endif | ||
1736 | #endif | ||
1737 | #ifdef SYS_vmsplice | ||
1738 | #ifdef __NR_vmsplice | ||
1739 | {"vmsplice", __NR_vmsplice}, | ||
1740 | #endif | ||
1741 | #endif | ||
1742 | #ifdef SYS_vserver | ||
1743 | #ifdef __NR_vserver | ||
1744 | {"vserver", __NR_vserver}, | ||
1745 | #endif | ||
1746 | #endif | ||
1747 | #ifdef SYS_wait4 | ||
1748 | #ifdef __NR_wait4 | ||
1749 | {"wait4", __NR_wait4}, | ||
1750 | #endif | ||
1751 | #endif | ||
1752 | #ifdef SYS_waitid | ||
1753 | #ifdef __NR_waitid | ||
1754 | {"waitid", __NR_waitid}, | ||
1755 | #endif | ||
1756 | #endif | ||
1757 | #ifdef SYS_waitpid | ||
1758 | #ifdef __NR_waitpid | ||
1759 | {"waitpid", __NR_waitpid}, | ||
1760 | #endif | ||
1761 | #endif | ||
1762 | #ifdef SYS_write | ||
1763 | #ifdef __NR_write | ||
1764 | {"write", __NR_write}, | ||
1765 | #endif | ||
1766 | #endif | ||
1767 | #ifdef SYS_writev | ||
1768 | #ifdef __NR_writev | ||
1769 | {"writev", __NR_writev}, | ||
1770 | #endif | ||
1771 | #endif | ||
1772 | #endif | ||
1773 | #if defined __x86_64__ && defined __LP64__ | ||
1774 | #ifdef SYS__sysctl | ||
1775 | #ifdef __NR__sysctl | ||
1776 | {"_sysctl", __NR__sysctl}, | ||
1777 | #endif | ||
1778 | #endif | ||
1779 | #ifdef SYS_accept | ||
1780 | #ifdef __NR_accept | ||
1781 | {"accept", __NR_accept}, | ||
1782 | #endif | ||
1783 | #endif | ||
1784 | #ifdef SYS_accept4 | ||
1785 | #ifdef __NR_accept4 | ||
1786 | {"accept4", __NR_accept4}, | ||
1787 | #endif | ||
1788 | #endif | ||
1789 | #ifdef SYS_access | ||
1790 | #ifdef __NR_access | ||
1791 | {"access", __NR_access}, | ||
1792 | #endif | ||
1793 | #endif | ||
1794 | #ifdef SYS_acct | ||
1795 | #ifdef __NR_acct | ||
1796 | {"acct", __NR_acct}, | ||
1797 | #endif | ||
1798 | #endif | ||
1799 | #ifdef SYS_add_key | ||
1800 | #ifdef __NR_add_key | ||
1801 | {"add_key", __NR_add_key}, | ||
1802 | #endif | ||
1803 | #endif | ||
1804 | #ifdef SYS_adjtimex | ||
1805 | #ifdef __NR_adjtimex | ||
1806 | {"adjtimex", __NR_adjtimex}, | ||
1807 | #endif | ||
1808 | #endif | ||
1809 | #ifdef SYS_afs_syscall | ||
1810 | #ifdef __NR_afs_syscall | ||
1811 | {"afs_syscall", __NR_afs_syscall}, | ||
1812 | #endif | ||
1813 | #endif | ||
1814 | #ifdef SYS_alarm | ||
1815 | #ifdef __NR_alarm | ||
1816 | {"alarm", __NR_alarm}, | ||
1817 | #endif | ||
1818 | #endif | ||
1819 | #ifdef SYS_arch_prctl | ||
1820 | #ifdef __NR_arch_prctl | ||
1821 | {"arch_prctl", __NR_arch_prctl}, | ||
1822 | #endif | ||
1823 | #endif | ||
1824 | #ifdef SYS_bind | ||
1825 | #ifdef __NR_bind | ||
1826 | {"bind", __NR_bind}, | ||
1827 | #endif | ||
1828 | #endif | ||
1829 | #ifdef SYS_brk | ||
1830 | #ifdef __NR_brk | ||
1831 | {"brk", __NR_brk}, | ||
1832 | #endif | ||
1833 | #endif | ||
1834 | #ifdef SYS_capget | ||
1835 | #ifdef __NR_capget | ||
1836 | {"capget", __NR_capget}, | ||
1837 | #endif | ||
1838 | #endif | ||
1839 | #ifdef SYS_capset | ||
1840 | #ifdef __NR_capset | ||
1841 | {"capset", __NR_capset}, | ||
1842 | #endif | ||
1843 | #endif | ||
1844 | #ifdef SYS_chdir | ||
1845 | #ifdef __NR_chdir | ||
1846 | {"chdir", __NR_chdir}, | ||
1847 | #endif | ||
1848 | #endif | ||
1849 | #ifdef SYS_chmod | ||
1850 | #ifdef __NR_chmod | ||
1851 | {"chmod", __NR_chmod}, | ||
1852 | #endif | ||
1853 | #endif | ||
1854 | #ifdef SYS_chown | ||
1855 | #ifdef __NR_chown | ||
1856 | {"chown", __NR_chown}, | ||
1857 | #endif | ||
1858 | #endif | ||
1859 | #ifdef SYS_chroot | ||
1860 | #ifdef __NR_chroot | ||
1861 | {"chroot", __NR_chroot}, | ||
1862 | #endif | ||
1863 | #endif | ||
1864 | #ifdef SYS_clock_adjtime | ||
1865 | #ifdef __NR_clock_adjtime | ||
1866 | {"clock_adjtime", __NR_clock_adjtime}, | ||
1867 | #endif | ||
1868 | #endif | ||
1869 | #ifdef SYS_clock_getres | ||
1870 | #ifdef __NR_clock_getres | ||
1871 | {"clock_getres", __NR_clock_getres}, | ||
1872 | #endif | ||
1873 | #endif | ||
1874 | #ifdef SYS_clock_gettime | ||
1875 | #ifdef __NR_clock_gettime | ||
1876 | {"clock_gettime", __NR_clock_gettime}, | ||
1877 | #endif | ||
1878 | #endif | ||
1879 | #ifdef SYS_clock_nanosleep | ||
1880 | #ifdef __NR_clock_nanosleep | ||
1881 | {"clock_nanosleep", __NR_clock_nanosleep}, | ||
1882 | #endif | ||
1883 | #endif | ||
1884 | #ifdef SYS_clock_settime | ||
1885 | #ifdef __NR_clock_settime | ||
1886 | {"clock_settime", __NR_clock_settime}, | ||
1887 | #endif | ||
1888 | #endif | ||
1889 | #ifdef SYS_clone | ||
1890 | #ifdef __NR_clone | ||
1891 | {"clone", __NR_clone}, | ||
1892 | #endif | ||
1893 | #endif | ||
1894 | #ifdef SYS_close | ||
1895 | #ifdef __NR_close | ||
1896 | {"close", __NR_close}, | ||
1897 | #endif | ||
1898 | #endif | ||
1899 | #ifdef SYS_connect | ||
1900 | #ifdef __NR_connect | ||
1901 | {"connect", __NR_connect}, | ||
1902 | #endif | ||
1903 | #endif | ||
1904 | #ifdef SYS_creat | ||
1905 | #ifdef __NR_creat | ||
1906 | {"creat", __NR_creat}, | ||
1907 | #endif | ||
1908 | #endif | ||
1909 | #ifdef SYS_create_module | ||
1910 | #ifdef __NR_create_module | ||
1911 | {"create_module", __NR_create_module}, | ||
1912 | #endif | ||
1913 | #endif | ||
1914 | #ifdef SYS_delete_module | ||
1915 | #ifdef __NR_delete_module | ||
1916 | {"delete_module", __NR_delete_module}, | ||
1917 | #endif | ||
1918 | #endif | ||
1919 | #ifdef SYS_dup | ||
1920 | #ifdef __NR_dup | ||
1921 | {"dup", __NR_dup}, | ||
1922 | #endif | ||
1923 | #endif | ||
1924 | #ifdef SYS_dup2 | ||
1925 | #ifdef __NR_dup2 | ||
1926 | {"dup2", __NR_dup2}, | ||
1927 | #endif | ||
1928 | #endif | ||
1929 | #ifdef SYS_dup3 | ||
1930 | #ifdef __NR_dup3 | ||
1931 | {"dup3", __NR_dup3}, | ||
1932 | #endif | ||
1933 | #endif | ||
1934 | #ifdef SYS_epoll_create | ||
1935 | #ifdef __NR_epoll_create | ||
1936 | {"epoll_create", __NR_epoll_create}, | ||
1937 | #endif | ||
1938 | #endif | ||
1939 | #ifdef SYS_epoll_create1 | ||
1940 | #ifdef __NR_epoll_create1 | ||
1941 | {"epoll_create1", __NR_epoll_create1}, | ||
1942 | #endif | ||
1943 | #endif | ||
1944 | #ifdef SYS_epoll_ctl | ||
1945 | #ifdef __NR_epoll_ctl | ||
1946 | {"epoll_ctl", __NR_epoll_ctl}, | ||
1947 | #endif | ||
1948 | #endif | ||
1949 | #ifdef SYS_epoll_ctl_old | ||
1950 | #ifdef __NR_epoll_ctl_old | ||
1951 | {"epoll_ctl_old", __NR_epoll_ctl_old}, | ||
1952 | #endif | ||
1953 | #endif | ||
1954 | #ifdef SYS_epoll_pwait | ||
1955 | #ifdef __NR_epoll_pwait | ||
1956 | {"epoll_pwait", __NR_epoll_pwait}, | ||
1957 | #endif | ||
1958 | #endif | ||
1959 | #ifdef SYS_epoll_wait | ||
1960 | #ifdef __NR_epoll_wait | ||
1961 | {"epoll_wait", __NR_epoll_wait}, | ||
1962 | #endif | ||
1963 | #endif | ||
1964 | #ifdef SYS_epoll_wait_old | ||
1965 | #ifdef __NR_epoll_wait_old | ||
1966 | {"epoll_wait_old", __NR_epoll_wait_old}, | ||
1967 | #endif | ||
1968 | #endif | ||
1969 | #ifdef SYS_eventfd | ||
1970 | #ifdef __NR_eventfd | ||
1971 | {"eventfd", __NR_eventfd}, | ||
1972 | #endif | ||
1973 | #endif | ||
1974 | #ifdef SYS_eventfd2 | ||
1975 | #ifdef __NR_eventfd2 | ||
1976 | {"eventfd2", __NR_eventfd2}, | ||
1977 | #endif | ||
1978 | #endif | ||
1979 | #ifdef SYS_execve | ||
1980 | #ifdef __NR_execve | ||
1981 | {"execve", __NR_execve}, | ||
1982 | #endif | ||
1983 | #endif | ||
1984 | #ifdef SYS_exit | ||
1985 | #ifdef __NR_exit | ||
1986 | {"exit", __NR_exit}, | ||
1987 | #endif | ||
1988 | #endif | ||
1989 | #ifdef SYS_exit_group | ||
1990 | #ifdef __NR_exit_group | ||
1991 | {"exit_group", __NR_exit_group}, | ||
1992 | #endif | ||
1993 | #endif | ||
1994 | #ifdef SYS_faccessat | ||
1995 | #ifdef __NR_faccessat | ||
1996 | {"faccessat", __NR_faccessat}, | ||
1997 | #endif | ||
1998 | #endif | ||
1999 | #ifdef SYS_fadvise64 | ||
2000 | #ifdef __NR_fadvise64 | ||
2001 | {"fadvise64", __NR_fadvise64}, | ||
2002 | #endif | ||
2003 | #endif | ||
2004 | #ifdef SYS_fallocate | ||
2005 | #ifdef __NR_fallocate | ||
2006 | {"fallocate", __NR_fallocate}, | ||
2007 | #endif | ||
2008 | #endif | ||
2009 | #ifdef SYS_fanotify_init | ||
2010 | #ifdef __NR_fanotify_init | ||
2011 | {"fanotify_init", __NR_fanotify_init}, | ||
2012 | #endif | ||
2013 | #endif | ||
2014 | #ifdef SYS_fanotify_mark | ||
2015 | #ifdef __NR_fanotify_mark | ||
2016 | {"fanotify_mark", __NR_fanotify_mark}, | ||
2017 | #endif | ||
2018 | #endif | ||
2019 | #ifdef SYS_fchdir | ||
2020 | #ifdef __NR_fchdir | ||
2021 | {"fchdir", __NR_fchdir}, | ||
2022 | #endif | ||
2023 | #endif | ||
2024 | #ifdef SYS_fchmod | ||
2025 | #ifdef __NR_fchmod | ||
2026 | {"fchmod", __NR_fchmod}, | ||
2027 | #endif | ||
2028 | #endif | ||
2029 | #ifdef SYS_fchmodat | ||
2030 | #ifdef __NR_fchmodat | ||
2031 | {"fchmodat", __NR_fchmodat}, | ||
2032 | #endif | ||
2033 | #endif | ||
2034 | #ifdef SYS_fchown | ||
2035 | #ifdef __NR_fchown | ||
2036 | {"fchown", __NR_fchown}, | ||
2037 | #endif | ||
2038 | #endif | ||
2039 | #ifdef SYS_fchownat | ||
2040 | #ifdef __NR_fchownat | ||
2041 | {"fchownat", __NR_fchownat}, | ||
2042 | #endif | ||
2043 | #endif | ||
2044 | #ifdef SYS_fcntl | ||
2045 | #ifdef __NR_fcntl | ||
2046 | {"fcntl", __NR_fcntl}, | ||
2047 | #endif | ||
2048 | #endif | ||
2049 | #ifdef SYS_fdatasync | ||
2050 | #ifdef __NR_fdatasync | ||
2051 | {"fdatasync", __NR_fdatasync}, | ||
2052 | #endif | ||
2053 | #endif | ||
2054 | #ifdef SYS_fgetxattr | ||
2055 | #ifdef __NR_fgetxattr | ||
2056 | {"fgetxattr", __NR_fgetxattr}, | ||
2057 | #endif | ||
2058 | #endif | ||
2059 | #ifdef SYS_finit_module | ||
2060 | #ifdef __NR_finit_module | ||
2061 | {"finit_module", __NR_finit_module}, | ||
2062 | #endif | ||
2063 | #endif | ||
2064 | #ifdef SYS_flistxattr | ||
2065 | #ifdef __NR_flistxattr | ||
2066 | {"flistxattr", __NR_flistxattr}, | ||
2067 | #endif | ||
2068 | #endif | ||
2069 | #ifdef SYS_flock | ||
2070 | #ifdef __NR_flock | ||
2071 | {"flock", __NR_flock}, | ||
2072 | #endif | ||
2073 | #endif | ||
2074 | #ifdef SYS_fork | ||
2075 | #ifdef __NR_fork | ||
2076 | {"fork", __NR_fork}, | ||
2077 | #endif | ||
2078 | #endif | ||
2079 | #ifdef SYS_fremovexattr | ||
2080 | #ifdef __NR_fremovexattr | ||
2081 | {"fremovexattr", __NR_fremovexattr}, | ||
2082 | #endif | ||
2083 | #endif | ||
2084 | #ifdef SYS_fsetxattr | ||
2085 | #ifdef __NR_fsetxattr | ||
2086 | {"fsetxattr", __NR_fsetxattr}, | ||
2087 | #endif | ||
2088 | #endif | ||
2089 | #ifdef SYS_fstat | ||
2090 | #ifdef __NR_fstat | ||
2091 | {"fstat", __NR_fstat}, | ||
2092 | #endif | ||
2093 | #endif | ||
2094 | #ifdef SYS_fstatfs | ||
2095 | #ifdef __NR_fstatfs | ||
2096 | {"fstatfs", __NR_fstatfs}, | ||
2097 | #endif | ||
2098 | #endif | ||
2099 | #ifdef SYS_fsync | ||
2100 | #ifdef __NR_fsync | ||
2101 | {"fsync", __NR_fsync}, | ||
2102 | #endif | ||
2103 | #endif | ||
2104 | #ifdef SYS_ftruncate | ||
2105 | #ifdef __NR_ftruncate | ||
2106 | {"ftruncate", __NR_ftruncate}, | ||
2107 | #endif | ||
2108 | #endif | ||
2109 | #ifdef SYS_futex | ||
2110 | #ifdef __NR_futex | ||
2111 | {"futex", __NR_futex}, | ||
2112 | #endif | ||
2113 | #endif | ||
2114 | #ifdef SYS_futimesat | ||
2115 | #ifdef __NR_futimesat | ||
2116 | {"futimesat", __NR_futimesat}, | ||
2117 | #endif | ||
2118 | #endif | ||
2119 | #ifdef SYS_get_kernel_syms | ||
2120 | #ifdef __NR_get_kernel_syms | ||
2121 | {"get_kernel_syms", __NR_get_kernel_syms}, | ||
2122 | #endif | ||
2123 | #endif | ||
2124 | #ifdef SYS_get_mempolicy | ||
2125 | #ifdef __NR_get_mempolicy | ||
2126 | {"get_mempolicy", __NR_get_mempolicy}, | ||
2127 | #endif | ||
2128 | #endif | ||
2129 | #ifdef SYS_get_robust_list | ||
2130 | #ifdef __NR_get_robust_list | ||
2131 | {"get_robust_list", __NR_get_robust_list}, | ||
2132 | #endif | ||
2133 | #endif | ||
2134 | #ifdef SYS_get_thread_area | ||
2135 | #ifdef __NR_get_thread_area | ||
2136 | {"get_thread_area", __NR_get_thread_area}, | ||
2137 | #endif | ||
2138 | #endif | ||
2139 | #ifdef SYS_getcpu | ||
2140 | #ifdef __NR_getcpu | ||
2141 | {"getcpu", __NR_getcpu}, | ||
2142 | #endif | ||
2143 | #endif | ||
2144 | #ifdef SYS_getcwd | ||
2145 | #ifdef __NR_getcwd | ||
2146 | {"getcwd", __NR_getcwd}, | ||
2147 | #endif | ||
2148 | #endif | ||
2149 | #ifdef SYS_getdents | ||
2150 | #ifdef __NR_getdents | ||
2151 | {"getdents", __NR_getdents}, | ||
2152 | #endif | ||
2153 | #endif | ||
2154 | #ifdef SYS_getdents64 | ||
2155 | #ifdef __NR_getdents64 | ||
2156 | {"getdents64", __NR_getdents64}, | ||
2157 | #endif | ||
2158 | #endif | ||
2159 | #ifdef SYS_getegid | ||
2160 | #ifdef __NR_getegid | ||
2161 | {"getegid", __NR_getegid}, | ||
2162 | #endif | ||
2163 | #endif | ||
2164 | #ifdef SYS_geteuid | ||
2165 | #ifdef __NR_geteuid | ||
2166 | {"geteuid", __NR_geteuid}, | ||
2167 | #endif | ||
2168 | #endif | ||
2169 | #ifdef SYS_getgid | ||
2170 | #ifdef __NR_getgid | ||
2171 | {"getgid", __NR_getgid}, | ||
2172 | #endif | ||
2173 | #endif | ||
2174 | #ifdef SYS_getgroups | ||
2175 | #ifdef __NR_getgroups | ||
2176 | {"getgroups", __NR_getgroups}, | ||
2177 | #endif | ||
2178 | #endif | ||
2179 | #ifdef SYS_getitimer | ||
2180 | #ifdef __NR_getitimer | ||
2181 | {"getitimer", __NR_getitimer}, | ||
2182 | #endif | ||
2183 | #endif | ||
2184 | #ifdef SYS_getpeername | ||
2185 | #ifdef __NR_getpeername | ||
2186 | {"getpeername", __NR_getpeername}, | ||
2187 | #endif | ||
2188 | #endif | ||
2189 | #ifdef SYS_getpgid | ||
2190 | #ifdef __NR_getpgid | ||
2191 | {"getpgid", __NR_getpgid}, | ||
2192 | #endif | ||
2193 | #endif | ||
2194 | #ifdef SYS_getpgrp | ||
2195 | #ifdef __NR_getpgrp | ||
2196 | {"getpgrp", __NR_getpgrp}, | ||
2197 | #endif | ||
2198 | #endif | ||
2199 | #ifdef SYS_getpid | ||
2200 | #ifdef __NR_getpid | ||
2201 | {"getpid", __NR_getpid}, | ||
2202 | #endif | ||
2203 | #endif | ||
2204 | #ifdef SYS_getpmsg | ||
2205 | #ifdef __NR_getpmsg | ||
2206 | {"getpmsg", __NR_getpmsg}, | ||
2207 | #endif | ||
2208 | #endif | ||
2209 | #ifdef SYS_getppid | ||
2210 | #ifdef __NR_getppid | ||
2211 | {"getppid", __NR_getppid}, | ||
2212 | #endif | ||
2213 | #endif | ||
2214 | #ifdef SYS_getpriority | ||
2215 | #ifdef __NR_getpriority | ||
2216 | {"getpriority", __NR_getpriority}, | ||
2217 | #endif | ||
2218 | #endif | ||
2219 | #ifdef SYS_getresgid | ||
2220 | #ifdef __NR_getresgid | ||
2221 | {"getresgid", __NR_getresgid}, | ||
2222 | #endif | ||
2223 | #endif | ||
2224 | #ifdef SYS_getresuid | ||
2225 | #ifdef __NR_getresuid | ||
2226 | {"getresuid", __NR_getresuid}, | ||
2227 | #endif | ||
2228 | #endif | ||
2229 | #ifdef SYS_getrlimit | ||
2230 | #ifdef __NR_getrlimit | ||
2231 | {"getrlimit", __NR_getrlimit}, | ||
2232 | #endif | ||
2233 | #endif | ||
2234 | #ifdef SYS_getrusage | ||
2235 | #ifdef __NR_getrusage | ||
2236 | {"getrusage", __NR_getrusage}, | ||
2237 | #endif | ||
2238 | #endif | ||
2239 | #ifdef SYS_getsid | ||
2240 | #ifdef __NR_getsid | ||
2241 | {"getsid", __NR_getsid}, | ||
2242 | #endif | ||
2243 | #endif | ||
2244 | #ifdef SYS_getsockname | ||
2245 | #ifdef __NR_getsockname | ||
2246 | {"getsockname", __NR_getsockname}, | ||
2247 | #endif | ||
2248 | #endif | ||
2249 | #ifdef SYS_getsockopt | ||
2250 | #ifdef __NR_getsockopt | ||
2251 | {"getsockopt", __NR_getsockopt}, | ||
2252 | #endif | ||
2253 | #endif | ||
2254 | #ifdef SYS_gettid | ||
2255 | #ifdef __NR_gettid | ||
2256 | {"gettid", __NR_gettid}, | ||
2257 | #endif | ||
2258 | #endif | ||
2259 | #ifdef SYS_gettimeofday | ||
2260 | #ifdef __NR_gettimeofday | ||
2261 | {"gettimeofday", __NR_gettimeofday}, | ||
2262 | #endif | ||
2263 | #endif | ||
2264 | #ifdef SYS_getuid | ||
2265 | #ifdef __NR_getuid | ||
2266 | {"getuid", __NR_getuid}, | ||
2267 | #endif | ||
2268 | #endif | ||
2269 | #ifdef SYS_getxattr | ||
2270 | #ifdef __NR_getxattr | ||
2271 | {"getxattr", __NR_getxattr}, | ||
2272 | #endif | ||
2273 | #endif | ||
2274 | #ifdef SYS_init_module | ||
2275 | #ifdef __NR_init_module | ||
2276 | {"init_module", __NR_init_module}, | ||
2277 | #endif | ||
2278 | #endif | ||
2279 | #ifdef SYS_inotify_add_watch | ||
2280 | #ifdef __NR_inotify_add_watch | ||
2281 | {"inotify_add_watch", __NR_inotify_add_watch}, | ||
2282 | #endif | ||
2283 | #endif | ||
2284 | #ifdef SYS_inotify_init | ||
2285 | #ifdef __NR_inotify_init | ||
2286 | {"inotify_init", __NR_inotify_init}, | ||
2287 | #endif | ||
2288 | #endif | ||
2289 | #ifdef SYS_inotify_init1 | ||
2290 | #ifdef __NR_inotify_init1 | ||
2291 | {"inotify_init1", __NR_inotify_init1}, | ||
2292 | #endif | ||
2293 | #endif | ||
2294 | #ifdef SYS_inotify_rm_watch | ||
2295 | #ifdef __NR_inotify_rm_watch | ||
2296 | {"inotify_rm_watch", __NR_inotify_rm_watch}, | ||
2297 | #endif | ||
2298 | #endif | ||
2299 | #ifdef SYS_io_cancel | ||
2300 | #ifdef __NR_io_cancel | ||
2301 | {"io_cancel", __NR_io_cancel}, | ||
2302 | #endif | ||
2303 | #endif | ||
2304 | #ifdef SYS_io_destroy | ||
2305 | #ifdef __NR_io_destroy | ||
2306 | {"io_destroy", __NR_io_destroy}, | ||
2307 | #endif | ||
2308 | #endif | ||
2309 | #ifdef SYS_io_getevents | ||
2310 | #ifdef __NR_io_getevents | ||
2311 | {"io_getevents", __NR_io_getevents}, | ||
2312 | #endif | ||
2313 | #endif | ||
2314 | #ifdef SYS_io_setup | ||
2315 | #ifdef __NR_io_setup | ||
2316 | {"io_setup", __NR_io_setup}, | ||
2317 | #endif | ||
2318 | #endif | ||
2319 | #ifdef SYS_io_submit | ||
2320 | #ifdef __NR_io_submit | ||
2321 | {"io_submit", __NR_io_submit}, | ||
2322 | #endif | ||
2323 | #endif | ||
2324 | #ifdef SYS_ioctl | ||
2325 | #ifdef __NR_ioctl | ||
2326 | {"ioctl", __NR_ioctl}, | ||
2327 | #endif | ||
2328 | #endif | ||
2329 | #ifdef SYS_ioperm | ||
2330 | #ifdef __NR_ioperm | ||
2331 | {"ioperm", __NR_ioperm}, | ||
2332 | #endif | ||
2333 | #endif | ||
2334 | #ifdef SYS_iopl | ||
2335 | #ifdef __NR_iopl | ||
2336 | {"iopl", __NR_iopl}, | ||
2337 | #endif | ||
2338 | #endif | ||
2339 | #ifdef SYS_ioprio_get | ||
2340 | #ifdef __NR_ioprio_get | ||
2341 | {"ioprio_get", __NR_ioprio_get}, | ||
2342 | #endif | ||
2343 | #endif | ||
2344 | #ifdef SYS_ioprio_set | ||
2345 | #ifdef __NR_ioprio_set | ||
2346 | {"ioprio_set", __NR_ioprio_set}, | ||
2347 | #endif | ||
2348 | #endif | ||
2349 | #ifdef SYS_kcmp | ||
2350 | #ifdef __NR_kcmp | ||
2351 | {"kcmp", __NR_kcmp}, | ||
2352 | #endif | ||
2353 | #endif | ||
2354 | #ifdef SYS_kexec_load | ||
2355 | #ifdef __NR_kexec_load | ||
2356 | {"kexec_load", __NR_kexec_load}, | ||
2357 | #endif | ||
2358 | #endif | ||
2359 | #ifdef SYS_keyctl | ||
2360 | #ifdef __NR_keyctl | ||
2361 | {"keyctl", __NR_keyctl}, | ||
2362 | #endif | ||
2363 | #endif | ||
2364 | #ifdef SYS_kill | ||
2365 | #ifdef __NR_kill | ||
2366 | {"kill", __NR_kill}, | ||
2367 | #endif | ||
2368 | #endif | ||
2369 | #ifdef SYS_lchown | ||
2370 | #ifdef __NR_lchown | ||
2371 | {"lchown", __NR_lchown}, | ||
2372 | #endif | ||
2373 | #endif | ||
2374 | #ifdef SYS_lgetxattr | ||
2375 | #ifdef __NR_lgetxattr | ||
2376 | {"lgetxattr", __NR_lgetxattr}, | ||
2377 | #endif | ||
2378 | #endif | ||
2379 | #ifdef SYS_link | ||
2380 | #ifdef __NR_link | ||
2381 | {"link", __NR_link}, | ||
2382 | #endif | ||
2383 | #endif | ||
2384 | #ifdef SYS_linkat | ||
2385 | #ifdef __NR_linkat | ||
2386 | {"linkat", __NR_linkat}, | ||
2387 | #endif | ||
2388 | #endif | ||
2389 | #ifdef SYS_listen | ||
2390 | #ifdef __NR_listen | ||
2391 | {"listen", __NR_listen}, | ||
2392 | #endif | ||
2393 | #endif | ||
2394 | #ifdef SYS_listxattr | ||
2395 | #ifdef __NR_listxattr | ||
2396 | {"listxattr", __NR_listxattr}, | ||
2397 | #endif | ||
2398 | #endif | ||
2399 | #ifdef SYS_llistxattr | ||
2400 | #ifdef __NR_llistxattr | ||
2401 | {"llistxattr", __NR_llistxattr}, | ||
2402 | #endif | ||
2403 | #endif | ||
2404 | #ifdef SYS_lookup_dcookie | ||
2405 | #ifdef __NR_lookup_dcookie | ||
2406 | {"lookup_dcookie", __NR_lookup_dcookie}, | ||
2407 | #endif | ||
2408 | #endif | ||
2409 | #ifdef SYS_lremovexattr | ||
2410 | #ifdef __NR_lremovexattr | ||
2411 | {"lremovexattr", __NR_lremovexattr}, | ||
2412 | #endif | ||
2413 | #endif | ||
2414 | #ifdef SYS_lseek | ||
2415 | #ifdef __NR_lseek | ||
2416 | {"lseek", __NR_lseek}, | ||
2417 | #endif | ||
2418 | #endif | ||
2419 | #ifdef SYS_lsetxattr | ||
2420 | #ifdef __NR_lsetxattr | ||
2421 | {"lsetxattr", __NR_lsetxattr}, | ||
2422 | #endif | ||
2423 | #endif | ||
2424 | #ifdef SYS_lstat | ||
2425 | #ifdef __NR_lstat | ||
2426 | {"lstat", __NR_lstat}, | ||
2427 | #endif | ||
2428 | #endif | ||
2429 | #ifdef SYS_madvise | ||
2430 | #ifdef __NR_madvise | ||
2431 | {"madvise", __NR_madvise}, | ||
2432 | #endif | ||
2433 | #endif | ||
2434 | #ifdef SYS_mbind | ||
2435 | #ifdef __NR_mbind | ||
2436 | {"mbind", __NR_mbind}, | ||
2437 | #endif | ||
2438 | #endif | ||
2439 | #ifdef SYS_migrate_pages | ||
2440 | #ifdef __NR_migrate_pages | ||
2441 | {"migrate_pages", __NR_migrate_pages}, | ||
2442 | #endif | ||
2443 | #endif | ||
2444 | #ifdef SYS_mincore | ||
2445 | #ifdef __NR_mincore | ||
2446 | {"mincore", __NR_mincore}, | ||
2447 | #endif | ||
2448 | #endif | ||
2449 | #ifdef SYS_mkdir | ||
2450 | #ifdef __NR_mkdir | ||
2451 | {"mkdir", __NR_mkdir}, | ||
2452 | #endif | ||
2453 | #endif | ||
2454 | #ifdef SYS_mkdirat | ||
2455 | #ifdef __NR_mkdirat | ||
2456 | {"mkdirat", __NR_mkdirat}, | ||
2457 | #endif | ||
2458 | #endif | ||
2459 | #ifdef SYS_mknod | ||
2460 | #ifdef __NR_mknod | ||
2461 | {"mknod", __NR_mknod}, | ||
2462 | #endif | ||
2463 | #endif | ||
2464 | #ifdef SYS_mknodat | ||
2465 | #ifdef __NR_mknodat | ||
2466 | {"mknodat", __NR_mknodat}, | ||
2467 | #endif | ||
2468 | #endif | ||
2469 | #ifdef SYS_mlock | ||
2470 | #ifdef __NR_mlock | ||
2471 | {"mlock", __NR_mlock}, | ||
2472 | #endif | ||
2473 | #endif | ||
2474 | #ifdef SYS_mlockall | ||
2475 | #ifdef __NR_mlockall | ||
2476 | {"mlockall", __NR_mlockall}, | ||
2477 | #endif | ||
2478 | #endif | ||
2479 | #ifdef SYS_mmap | ||
2480 | #ifdef __NR_mmap | ||
2481 | {"mmap", __NR_mmap}, | ||
2482 | #endif | ||
2483 | #endif | ||
2484 | #ifdef SYS_modify_ldt | ||
2485 | #ifdef __NR_modify_ldt | ||
2486 | {"modify_ldt", __NR_modify_ldt}, | ||
2487 | #endif | ||
2488 | #endif | ||
2489 | #ifdef SYS_mount | ||
2490 | #ifdef __NR_mount | ||
2491 | {"mount", __NR_mount}, | ||
2492 | #endif | ||
2493 | #endif | ||
2494 | #ifdef SYS_move_pages | ||
2495 | #ifdef __NR_move_pages | ||
2496 | {"move_pages", __NR_move_pages}, | ||
2497 | #endif | ||
2498 | #endif | ||
2499 | #ifdef SYS_mprotect | ||
2500 | #ifdef __NR_mprotect | ||
2501 | {"mprotect", __NR_mprotect}, | ||
2502 | #endif | ||
2503 | #endif | ||
2504 | #ifdef SYS_mq_getsetattr | ||
2505 | #ifdef __NR_mq_getsetattr | ||
2506 | {"mq_getsetattr", __NR_mq_getsetattr}, | ||
2507 | #endif | ||
2508 | #endif | ||
2509 | #ifdef SYS_mq_notify | ||
2510 | #ifdef __NR_mq_notify | ||
2511 | {"mq_notify", __NR_mq_notify}, | ||
2512 | #endif | ||
2513 | #endif | ||
2514 | #ifdef SYS_mq_open | ||
2515 | #ifdef __NR_mq_open | ||
2516 | {"mq_open", __NR_mq_open}, | ||
2517 | #endif | ||
2518 | #endif | ||
2519 | #ifdef SYS_mq_timedreceive | ||
2520 | #ifdef __NR_mq_timedreceive | ||
2521 | {"mq_timedreceive", __NR_mq_timedreceive}, | ||
2522 | #endif | ||
2523 | #endif | ||
2524 | #ifdef SYS_mq_timedsend | ||
2525 | #ifdef __NR_mq_timedsend | ||
2526 | {"mq_timedsend", __NR_mq_timedsend}, | ||
2527 | #endif | ||
2528 | #endif | ||
2529 | #ifdef SYS_mq_unlink | ||
2530 | #ifdef __NR_mq_unlink | ||
2531 | {"mq_unlink", __NR_mq_unlink}, | ||
2532 | #endif | ||
2533 | #endif | ||
2534 | #ifdef SYS_mremap | ||
2535 | #ifdef __NR_mremap | ||
2536 | {"mremap", __NR_mremap}, | ||
2537 | #endif | ||
2538 | #endif | ||
2539 | #ifdef SYS_msgctl | ||
2540 | #ifdef __NR_msgctl | ||
2541 | {"msgctl", __NR_msgctl}, | ||
2542 | #endif | ||
2543 | #endif | ||
2544 | #ifdef SYS_msgget | ||
2545 | #ifdef __NR_msgget | ||
2546 | {"msgget", __NR_msgget}, | ||
2547 | #endif | ||
2548 | #endif | ||
2549 | #ifdef SYS_msgrcv | ||
2550 | #ifdef __NR_msgrcv | ||
2551 | {"msgrcv", __NR_msgrcv}, | ||
2552 | #endif | ||
2553 | #endif | ||
2554 | #ifdef SYS_msgsnd | ||
2555 | #ifdef __NR_msgsnd | ||
2556 | {"msgsnd", __NR_msgsnd}, | ||
2557 | #endif | ||
2558 | #endif | ||
2559 | #ifdef SYS_msync | ||
2560 | #ifdef __NR_msync | ||
2561 | {"msync", __NR_msync}, | ||
2562 | #endif | ||
2563 | #endif | ||
2564 | #ifdef SYS_munlock | ||
2565 | #ifdef __NR_munlock | ||
2566 | {"munlock", __NR_munlock}, | ||
2567 | #endif | ||
2568 | #endif | ||
2569 | #ifdef SYS_munlockall | ||
2570 | #ifdef __NR_munlockall | ||
2571 | {"munlockall", __NR_munlockall}, | ||
2572 | #endif | ||
2573 | #endif | ||
2574 | #ifdef SYS_munmap | ||
2575 | #ifdef __NR_munmap | ||
2576 | {"munmap", __NR_munmap}, | ||
2577 | #endif | ||
2578 | #endif | ||
2579 | #ifdef SYS_name_to_handle_at | ||
2580 | #ifdef __NR_name_to_handle_at | ||
2581 | {"name_to_handle_at", __NR_name_to_handle_at}, | ||
2582 | #endif | ||
2583 | #endif | ||
2584 | #ifdef SYS_nanosleep | ||
2585 | #ifdef __NR_nanosleep | ||
2586 | {"nanosleep", __NR_nanosleep}, | ||
2587 | #endif | ||
2588 | #endif | ||
2589 | #ifdef SYS_newfstatat | ||
2590 | #ifdef __NR_newfstatat | ||
2591 | {"newfstatat", __NR_newfstatat}, | ||
2592 | #endif | ||
2593 | #endif | ||
2594 | #ifdef SYS_nfsservctl | ||
2595 | #ifdef __NR_nfsservctl | ||
2596 | {"nfsservctl", __NR_nfsservctl}, | ||
2597 | #endif | ||
2598 | #endif | ||
2599 | #ifdef SYS_open | ||
2600 | #ifdef __NR_open | ||
2601 | {"open", __NR_open}, | ||
2602 | #endif | ||
2603 | #endif | ||
2604 | #ifdef SYS_open_by_handle_at | ||
2605 | #ifdef __NR_open_by_handle_at | ||
2606 | {"open_by_handle_at", __NR_open_by_handle_at}, | ||
2607 | #endif | ||
2608 | #endif | ||
2609 | #ifdef SYS_openat | ||
2610 | #ifdef __NR_openat | ||
2611 | {"openat", __NR_openat}, | ||
2612 | #endif | ||
2613 | #endif | ||
2614 | #ifdef SYS_pause | ||
2615 | #ifdef __NR_pause | ||
2616 | {"pause", __NR_pause}, | ||
2617 | #endif | ||
2618 | #endif | ||
2619 | #ifdef SYS_perf_event_open | ||
2620 | #ifdef __NR_perf_event_open | ||
2621 | {"perf_event_open", __NR_perf_event_open}, | ||
2622 | #endif | ||
2623 | #endif | ||
2624 | #ifdef SYS_personality | ||
2625 | #ifdef __NR_personality | ||
2626 | {"personality", __NR_personality}, | ||
2627 | #endif | ||
2628 | #endif | ||
2629 | #ifdef SYS_pipe | ||
2630 | #ifdef __NR_pipe | ||
2631 | {"pipe", __NR_pipe}, | ||
2632 | #endif | ||
2633 | #endif | ||
2634 | #ifdef SYS_pipe2 | ||
2635 | #ifdef __NR_pipe2 | ||
2636 | {"pipe2", __NR_pipe2}, | ||
2637 | #endif | ||
2638 | #endif | ||
2639 | #ifdef SYS_pivot_root | ||
2640 | #ifdef __NR_pivot_root | ||
2641 | {"pivot_root", __NR_pivot_root}, | ||
2642 | #endif | ||
2643 | #endif | ||
2644 | #ifdef SYS_poll | ||
2645 | #ifdef __NR_poll | ||
2646 | {"poll", __NR_poll}, | ||
2647 | #endif | ||
2648 | #endif | ||
2649 | #ifdef SYS_ppoll | ||
2650 | #ifdef __NR_ppoll | ||
2651 | {"ppoll", __NR_ppoll}, | ||
2652 | #endif | ||
2653 | #endif | ||
2654 | #ifdef SYS_prctl | ||
2655 | #ifdef __NR_prctl | ||
2656 | {"prctl", __NR_prctl}, | ||
2657 | #endif | ||
2658 | #endif | ||
2659 | #ifdef SYS_pread64 | ||
2660 | #ifdef __NR_pread64 | ||
2661 | {"pread64", __NR_pread64}, | ||
2662 | #endif | ||
2663 | #endif | ||
2664 | #ifdef SYS_preadv | ||
2665 | #ifdef __NR_preadv | ||
2666 | {"preadv", __NR_preadv}, | ||
2667 | #endif | ||
2668 | #endif | ||
2669 | #ifdef SYS_prlimit64 | ||
2670 | #ifdef __NR_prlimit64 | ||
2671 | {"prlimit64", __NR_prlimit64}, | ||
2672 | #endif | ||
2673 | #endif | ||
2674 | #ifdef SYS_process_vm_readv | ||
2675 | #ifdef __NR_process_vm_readv | ||
2676 | {"process_vm_readv", __NR_process_vm_readv}, | ||
2677 | #endif | ||
2678 | #endif | ||
2679 | #ifdef SYS_process_vm_writev | ||
2680 | #ifdef __NR_process_vm_writev | ||
2681 | {"process_vm_writev", __NR_process_vm_writev}, | ||
2682 | #endif | ||
2683 | #endif | ||
2684 | #ifdef SYS_pselect6 | ||
2685 | #ifdef __NR_pselect6 | ||
2686 | {"pselect6", __NR_pselect6}, | ||
2687 | #endif | ||
2688 | #endif | ||
2689 | #ifdef SYS_ptrace | ||
2690 | #ifdef __NR_ptrace | ||
2691 | {"ptrace", __NR_ptrace}, | ||
2692 | #endif | ||
2693 | #endif | ||
2694 | #ifdef SYS_putpmsg | ||
2695 | #ifdef __NR_putpmsg | ||
2696 | {"putpmsg", __NR_putpmsg}, | ||
2697 | #endif | ||
2698 | #endif | ||
2699 | #ifdef SYS_pwrite64 | ||
2700 | #ifdef __NR_pwrite64 | ||
2701 | {"pwrite64", __NR_pwrite64}, | ||
2702 | #endif | ||
2703 | #endif | ||
2704 | #ifdef SYS_pwritev | ||
2705 | #ifdef __NR_pwritev | ||
2706 | {"pwritev", __NR_pwritev}, | ||
2707 | #endif | ||
2708 | #endif | ||
2709 | #ifdef SYS_query_module | ||
2710 | #ifdef __NR_query_module | ||
2711 | {"query_module", __NR_query_module}, | ||
2712 | #endif | ||
2713 | #endif | ||
2714 | #ifdef SYS_quotactl | ||
2715 | #ifdef __NR_quotactl | ||
2716 | {"quotactl", __NR_quotactl}, | ||
2717 | #endif | ||
2718 | #endif | ||
2719 | #ifdef SYS_read | ||
2720 | #ifdef __NR_read | ||
2721 | {"read", __NR_read}, | ||
2722 | #endif | ||
2723 | #endif | ||
2724 | #ifdef SYS_readahead | ||
2725 | #ifdef __NR_readahead | ||
2726 | {"readahead", __NR_readahead}, | ||
2727 | #endif | ||
2728 | #endif | ||
2729 | #ifdef SYS_readlink | ||
2730 | #ifdef __NR_readlink | ||
2731 | {"readlink", __NR_readlink}, | ||
2732 | #endif | ||
2733 | #endif | ||
2734 | #ifdef SYS_readlinkat | ||
2735 | #ifdef __NR_readlinkat | ||
2736 | {"readlinkat", __NR_readlinkat}, | ||
2737 | #endif | ||
2738 | #endif | ||
2739 | #ifdef SYS_readv | ||
2740 | #ifdef __NR_readv | ||
2741 | {"readv", __NR_readv}, | ||
2742 | #endif | ||
2743 | #endif | ||
2744 | #ifdef SYS_reboot | ||
2745 | #ifdef __NR_reboot | ||
2746 | {"reboot", __NR_reboot}, | ||
2747 | #endif | ||
2748 | #endif | ||
2749 | #ifdef SYS_recvfrom | ||
2750 | #ifdef __NR_recvfrom | ||
2751 | {"recvfrom", __NR_recvfrom}, | ||
2752 | #endif | ||
2753 | #endif | ||
2754 | #ifdef SYS_recvmmsg | ||
2755 | #ifdef __NR_recvmmsg | ||
2756 | {"recvmmsg", __NR_recvmmsg}, | ||
2757 | #endif | ||
2758 | #endif | ||
2759 | #ifdef SYS_recvmsg | ||
2760 | #ifdef __NR_recvmsg | ||
2761 | {"recvmsg", __NR_recvmsg}, | ||
2762 | #endif | ||
2763 | #endif | ||
2764 | #ifdef SYS_remap_file_pages | ||
2765 | #ifdef __NR_remap_file_pages | ||
2766 | {"remap_file_pages", __NR_remap_file_pages}, | ||
2767 | #endif | ||
2768 | #endif | ||
2769 | #ifdef SYS_removexattr | ||
2770 | #ifdef __NR_removexattr | ||
2771 | {"removexattr", __NR_removexattr}, | ||
2772 | #endif | ||
2773 | #endif | ||
2774 | #ifdef SYS_rename | ||
2775 | #ifdef __NR_rename | ||
2776 | {"rename", __NR_rename}, | ||
2777 | #endif | ||
2778 | #endif | ||
2779 | #ifdef SYS_renameat | ||
2780 | #ifdef __NR_renameat | ||
2781 | {"renameat", __NR_renameat}, | ||
2782 | #endif | ||
2783 | #endif | ||
2784 | #ifdef SYS_request_key | ||
2785 | #ifdef __NR_request_key | ||
2786 | {"request_key", __NR_request_key}, | ||
2787 | #endif | ||
2788 | #endif | ||
2789 | #ifdef SYS_restart_syscall | ||
2790 | #ifdef __NR_restart_syscall | ||
2791 | {"restart_syscall", __NR_restart_syscall}, | ||
2792 | #endif | ||
2793 | #endif | ||
2794 | #ifdef SYS_rmdir | ||
2795 | #ifdef __NR_rmdir | ||
2796 | {"rmdir", __NR_rmdir}, | ||
2797 | #endif | ||
2798 | #endif | ||
2799 | #ifdef SYS_rt_sigaction | ||
2800 | #ifdef __NR_rt_sigaction | ||
2801 | {"rt_sigaction", __NR_rt_sigaction}, | ||
2802 | #endif | ||
2803 | #endif | ||
2804 | #ifdef SYS_rt_sigpending | ||
2805 | #ifdef __NR_rt_sigpending | ||
2806 | {"rt_sigpending", __NR_rt_sigpending}, | ||
2807 | #endif | ||
2808 | #endif | ||
2809 | #ifdef SYS_rt_sigprocmask | ||
2810 | #ifdef __NR_rt_sigprocmask | ||
2811 | {"rt_sigprocmask", __NR_rt_sigprocmask}, | ||
2812 | #endif | ||
2813 | #endif | ||
2814 | #ifdef SYS_rt_sigqueueinfo | ||
2815 | #ifdef __NR_rt_sigqueueinfo | ||
2816 | {"rt_sigqueueinfo", __NR_rt_sigqueueinfo}, | ||
2817 | #endif | ||
2818 | #endif | ||
2819 | #ifdef SYS_rt_sigreturn | ||
2820 | #ifdef __NR_rt_sigreturn | ||
2821 | {"rt_sigreturn", __NR_rt_sigreturn}, | ||
2822 | #endif | ||
2823 | #endif | ||
2824 | #ifdef SYS_rt_sigsuspend | ||
2825 | #ifdef __NR_rt_sigsuspend | ||
2826 | {"rt_sigsuspend", __NR_rt_sigsuspend}, | ||
2827 | #endif | ||
2828 | #endif | ||
2829 | #ifdef SYS_rt_sigtimedwait | ||
2830 | #ifdef __NR_rt_sigtimedwait | ||
2831 | {"rt_sigtimedwait", __NR_rt_sigtimedwait}, | ||
2832 | #endif | ||
2833 | #endif | ||
2834 | #ifdef SYS_rt_tgsigqueueinfo | ||
2835 | #ifdef __NR_rt_tgsigqueueinfo | ||
2836 | {"rt_tgsigqueueinfo", __NR_rt_tgsigqueueinfo}, | ||
2837 | #endif | ||
2838 | #endif | ||
2839 | #ifdef SYS_sched_get_priority_max | ||
2840 | #ifdef __NR_sched_get_priority_max | ||
2841 | {"sched_get_priority_max", __NR_sched_get_priority_max}, | ||
2842 | #endif | ||
2843 | #endif | ||
2844 | #ifdef SYS_sched_get_priority_min | ||
2845 | #ifdef __NR_sched_get_priority_min | ||
2846 | {"sched_get_priority_min", __NR_sched_get_priority_min}, | ||
2847 | #endif | ||
2848 | #endif | ||
2849 | #ifdef SYS_sched_getaffinity | ||
2850 | #ifdef __NR_sched_getaffinity | ||
2851 | {"sched_getaffinity", __NR_sched_getaffinity}, | ||
2852 | #endif | ||
2853 | #endif | ||
2854 | #ifdef SYS_sched_getparam | ||
2855 | #ifdef __NR_sched_getparam | ||
2856 | {"sched_getparam", __NR_sched_getparam}, | ||
2857 | #endif | ||
2858 | #endif | ||
2859 | #ifdef SYS_sched_getscheduler | ||
2860 | #ifdef __NR_sched_getscheduler | ||
2861 | {"sched_getscheduler", __NR_sched_getscheduler}, | ||
2862 | #endif | ||
2863 | #endif | ||
2864 | #ifdef SYS_sched_rr_get_interval | ||
2865 | #ifdef __NR_sched_rr_get_interval | ||
2866 | {"sched_rr_get_interval", __NR_sched_rr_get_interval}, | ||
2867 | #endif | ||
2868 | #endif | ||
2869 | #ifdef SYS_sched_setaffinity | ||
2870 | #ifdef __NR_sched_setaffinity | ||
2871 | {"sched_setaffinity", __NR_sched_setaffinity}, | ||
2872 | #endif | ||
2873 | #endif | ||
2874 | #ifdef SYS_sched_setparam | ||
2875 | #ifdef __NR_sched_setparam | ||
2876 | {"sched_setparam", __NR_sched_setparam}, | ||
2877 | #endif | ||
2878 | #endif | ||
2879 | #ifdef SYS_sched_setscheduler | ||
2880 | #ifdef __NR_sched_setscheduler | ||
2881 | {"sched_setscheduler", __NR_sched_setscheduler}, | ||
2882 | #endif | ||
2883 | #endif | ||
2884 | #ifdef SYS_sched_yield | ||
2885 | #ifdef __NR_sched_yield | ||
2886 | {"sched_yield", __NR_sched_yield}, | ||
2887 | #endif | ||
2888 | #endif | ||
2889 | #ifdef SYS_security | ||
2890 | #ifdef __NR_security | ||
2891 | {"security", __NR_security}, | ||
2892 | #endif | ||
2893 | #endif | ||
2894 | #ifdef SYS_select | ||
2895 | #ifdef __NR_select | ||
2896 | {"select", __NR_select}, | ||
2897 | #endif | ||
2898 | #endif | ||
2899 | #ifdef SYS_semctl | ||
2900 | #ifdef __NR_semctl | ||
2901 | {"semctl", __NR_semctl}, | ||
2902 | #endif | ||
2903 | #endif | ||
2904 | #ifdef SYS_semget | ||
2905 | #ifdef __NR_semget | ||
2906 | {"semget", __NR_semget}, | ||
2907 | #endif | ||
2908 | #endif | ||
2909 | #ifdef SYS_semop | ||
2910 | #ifdef __NR_semop | ||
2911 | {"semop", __NR_semop}, | ||
2912 | #endif | ||
2913 | #endif | ||
2914 | #ifdef SYS_semtimedop | ||
2915 | #ifdef __NR_semtimedop | ||
2916 | {"semtimedop", __NR_semtimedop}, | ||
2917 | #endif | ||
2918 | #endif | ||
2919 | #ifdef SYS_sendfile | ||
2920 | #ifdef __NR_sendfile | ||
2921 | {"sendfile", __NR_sendfile}, | ||
2922 | #endif | ||
2923 | #endif | ||
2924 | #ifdef SYS_sendmmsg | ||
2925 | #ifdef __NR_sendmmsg | ||
2926 | {"sendmmsg", __NR_sendmmsg}, | ||
2927 | #endif | ||
2928 | #endif | ||
2929 | #ifdef SYS_sendmsg | ||
2930 | #ifdef __NR_sendmsg | ||
2931 | {"sendmsg", __NR_sendmsg}, | ||
2932 | #endif | ||
2933 | #endif | ||
2934 | #ifdef SYS_sendto | ||
2935 | #ifdef __NR_sendto | ||
2936 | {"sendto", __NR_sendto}, | ||
2937 | #endif | ||
2938 | #endif | ||
2939 | #ifdef SYS_set_mempolicy | ||
2940 | #ifdef __NR_set_mempolicy | ||
2941 | {"set_mempolicy", __NR_set_mempolicy}, | ||
2942 | #endif | ||
2943 | #endif | ||
2944 | #ifdef SYS_set_robust_list | ||
2945 | #ifdef __NR_set_robust_list | ||
2946 | {"set_robust_list", __NR_set_robust_list}, | ||
2947 | #endif | ||
2948 | #endif | ||
2949 | #ifdef SYS_set_thread_area | ||
2950 | #ifdef __NR_set_thread_area | ||
2951 | {"set_thread_area", __NR_set_thread_area}, | ||
2952 | #endif | ||
2953 | #endif | ||
2954 | #ifdef SYS_set_tid_address | ||
2955 | #ifdef __NR_set_tid_address | ||
2956 | {"set_tid_address", __NR_set_tid_address}, | ||
2957 | #endif | ||
2958 | #endif | ||
2959 | #ifdef SYS_setdomainname | ||
2960 | #ifdef __NR_setdomainname | ||
2961 | {"setdomainname", __NR_setdomainname}, | ||
2962 | #endif | ||
2963 | #endif | ||
2964 | #ifdef SYS_setfsgid | ||
2965 | #ifdef __NR_setfsgid | ||
2966 | {"setfsgid", __NR_setfsgid}, | ||
2967 | #endif | ||
2968 | #endif | ||
2969 | #ifdef SYS_setfsuid | ||
2970 | #ifdef __NR_setfsuid | ||
2971 | {"setfsuid", __NR_setfsuid}, | ||
2972 | #endif | ||
2973 | #endif | ||
2974 | #ifdef SYS_setgid | ||
2975 | #ifdef __NR_setgid | ||
2976 | {"setgid", __NR_setgid}, | ||
2977 | #endif | ||
2978 | #endif | ||
2979 | #ifdef SYS_setgroups | ||
2980 | #ifdef __NR_setgroups | ||
2981 | {"setgroups", __NR_setgroups}, | ||
2982 | #endif | ||
2983 | #endif | ||
2984 | #ifdef SYS_sethostname | ||
2985 | #ifdef __NR_sethostname | ||
2986 | {"sethostname", __NR_sethostname}, | ||
2987 | #endif | ||
2988 | #endif | ||
2989 | #ifdef SYS_setitimer | ||
2990 | #ifdef __NR_setitimer | ||
2991 | {"setitimer", __NR_setitimer}, | ||
2992 | #endif | ||
2993 | #endif | ||
2994 | #ifdef SYS_setns | ||
2995 | #ifdef __NR_setns | ||
2996 | {"setns", __NR_setns}, | ||
2997 | #endif | ||
2998 | #endif | ||
2999 | #ifdef SYS_setpgid | ||
3000 | #ifdef __NR_setpgid | ||
3001 | {"setpgid", __NR_setpgid}, | ||
3002 | #endif | ||
3003 | #endif | ||
3004 | #ifdef SYS_setpriority | ||
3005 | #ifdef __NR_setpriority | ||
3006 | {"setpriority", __NR_setpriority}, | ||
3007 | #endif | ||
3008 | #endif | ||
3009 | #ifdef SYS_setregid | ||
3010 | #ifdef __NR_setregid | ||
3011 | {"setregid", __NR_setregid}, | ||
3012 | #endif | ||
3013 | #endif | ||
3014 | #ifdef SYS_setresgid | ||
3015 | #ifdef __NR_setresgid | ||
3016 | {"setresgid", __NR_setresgid}, | ||
3017 | #endif | ||
3018 | #endif | ||
3019 | #ifdef SYS_setresuid | ||
3020 | #ifdef __NR_setresuid | ||
3021 | {"setresuid", __NR_setresuid}, | ||
3022 | #endif | ||
3023 | #endif | ||
3024 | #ifdef SYS_setreuid | ||
3025 | #ifdef __NR_setreuid | ||
3026 | {"setreuid", __NR_setreuid}, | ||
3027 | #endif | ||
3028 | #endif | ||
3029 | #ifdef SYS_setrlimit | ||
3030 | #ifdef __NR_setrlimit | ||
3031 | {"setrlimit", __NR_setrlimit}, | ||
3032 | #endif | ||
3033 | #endif | ||
3034 | #ifdef SYS_setsid | ||
3035 | #ifdef __NR_setsid | ||
3036 | {"setsid", __NR_setsid}, | ||
3037 | #endif | ||
3038 | #endif | ||
3039 | #ifdef SYS_setsockopt | ||
3040 | #ifdef __NR_setsockopt | ||
3041 | {"setsockopt", __NR_setsockopt}, | ||
3042 | #endif | ||
3043 | #endif | ||
3044 | #ifdef SYS_settimeofday | ||
3045 | #ifdef __NR_settimeofday | ||
3046 | {"settimeofday", __NR_settimeofday}, | ||
3047 | #endif | ||
3048 | #endif | ||
3049 | #ifdef SYS_setuid | ||
3050 | #ifdef __NR_setuid | ||
3051 | {"setuid", __NR_setuid}, | ||
3052 | #endif | ||
3053 | #endif | ||
3054 | #ifdef SYS_setxattr | ||
3055 | #ifdef __NR_setxattr | ||
3056 | {"setxattr", __NR_setxattr}, | ||
3057 | #endif | ||
3058 | #endif | ||
3059 | #ifdef SYS_shmat | ||
3060 | #ifdef __NR_shmat | ||
3061 | {"shmat", __NR_shmat}, | ||
3062 | #endif | ||
3063 | #endif | ||
3064 | #ifdef SYS_shmctl | ||
3065 | #ifdef __NR_shmctl | ||
3066 | {"shmctl", __NR_shmctl}, | ||
3067 | #endif | ||
3068 | #endif | ||
3069 | #ifdef SYS_shmdt | ||
3070 | #ifdef __NR_shmdt | ||
3071 | {"shmdt", __NR_shmdt}, | ||
3072 | #endif | ||
3073 | #endif | ||
3074 | #ifdef SYS_shmget | ||
3075 | #ifdef __NR_shmget | ||
3076 | {"shmget", __NR_shmget}, | ||
3077 | #endif | ||
3078 | #endif | ||
3079 | #ifdef SYS_shutdown | ||
3080 | #ifdef __NR_shutdown | ||
3081 | {"shutdown", __NR_shutdown}, | ||
3082 | #endif | ||
3083 | #endif | ||
3084 | #ifdef SYS_sigaltstack | ||
3085 | #ifdef __NR_sigaltstack | ||
3086 | {"sigaltstack", __NR_sigaltstack}, | ||
3087 | #endif | ||
3088 | #endif | ||
3089 | #ifdef SYS_signalfd | ||
3090 | #ifdef __NR_signalfd | ||
3091 | {"signalfd", __NR_signalfd}, | ||
3092 | #endif | ||
3093 | #endif | ||
3094 | #ifdef SYS_signalfd4 | ||
3095 | #ifdef __NR_signalfd4 | ||
3096 | {"signalfd4", __NR_signalfd4}, | ||
3097 | #endif | ||
3098 | #endif | ||
3099 | #ifdef SYS_socket | ||
3100 | #ifdef __NR_socket | ||
3101 | {"socket", __NR_socket}, | ||
3102 | #endif | ||
3103 | #endif | ||
3104 | #ifdef SYS_socketpair | ||
3105 | #ifdef __NR_socketpair | ||
3106 | {"socketpair", __NR_socketpair}, | ||
3107 | #endif | ||
3108 | #endif | ||
3109 | #ifdef SYS_splice | ||
3110 | #ifdef __NR_splice | ||
3111 | {"splice", __NR_splice}, | ||
3112 | #endif | ||
3113 | #endif | ||
3114 | #ifdef SYS_stat | ||
3115 | #ifdef __NR_stat | ||
3116 | {"stat", __NR_stat}, | ||
3117 | #endif | ||
3118 | #endif | ||
3119 | #ifdef SYS_statfs | ||
3120 | #ifdef __NR_statfs | ||
3121 | {"statfs", __NR_statfs}, | ||
3122 | #endif | ||
3123 | #endif | ||
3124 | #ifdef SYS_swapoff | ||
3125 | #ifdef __NR_swapoff | ||
3126 | {"swapoff", __NR_swapoff}, | ||
3127 | #endif | ||
3128 | #endif | ||
3129 | #ifdef SYS_swapon | ||
3130 | #ifdef __NR_swapon | ||
3131 | {"swapon", __NR_swapon}, | ||
3132 | #endif | ||
3133 | #endif | ||
3134 | #ifdef SYS_symlink | ||
3135 | #ifdef __NR_symlink | ||
3136 | {"symlink", __NR_symlink}, | ||
3137 | #endif | ||
3138 | #endif | ||
3139 | #ifdef SYS_symlinkat | ||
3140 | #ifdef __NR_symlinkat | ||
3141 | {"symlinkat", __NR_symlinkat}, | ||
3142 | #endif | ||
3143 | #endif | ||
3144 | #ifdef SYS_sync | ||
3145 | #ifdef __NR_sync | ||
3146 | {"sync", __NR_sync}, | ||
3147 | #endif | ||
3148 | #endif | ||
3149 | #ifdef SYS_sync_file_range | ||
3150 | #ifdef __NR_sync_file_range | ||
3151 | {"sync_file_range", __NR_sync_file_range}, | ||
3152 | #endif | ||
3153 | #endif | ||
3154 | #ifdef SYS_syncfs | ||
3155 | #ifdef __NR_syncfs | ||
3156 | {"syncfs", __NR_syncfs}, | ||
3157 | #endif | ||
3158 | #endif | ||
3159 | #ifdef SYS_sysfs | ||
3160 | #ifdef __NR_sysfs | ||
3161 | {"sysfs", __NR_sysfs}, | ||
3162 | #endif | ||
3163 | #endif | ||
3164 | #ifdef SYS_sysinfo | ||
3165 | #ifdef __NR_sysinfo | ||
3166 | {"sysinfo", __NR_sysinfo}, | ||
3167 | #endif | ||
3168 | #endif | ||
3169 | #ifdef SYS_syslog | ||
3170 | #ifdef __NR_syslog | ||
3171 | {"syslog", __NR_syslog}, | ||
3172 | #endif | ||
3173 | #endif | ||
3174 | #ifdef SYS_tee | ||
3175 | #ifdef __NR_tee | ||
3176 | {"tee", __NR_tee}, | ||
3177 | #endif | ||
3178 | #endif | ||
3179 | #ifdef SYS_tgkill | ||
3180 | #ifdef __NR_tgkill | ||
3181 | {"tgkill", __NR_tgkill}, | ||
3182 | #endif | ||
3183 | #endif | ||
3184 | #ifdef SYS_time | ||
3185 | #ifdef __NR_time | ||
3186 | {"time", __NR_time}, | ||
3187 | #endif | ||
3188 | #endif | ||
3189 | #ifdef SYS_timer_create | ||
3190 | #ifdef __NR_timer_create | ||
3191 | {"timer_create", __NR_timer_create}, | ||
3192 | #endif | ||
3193 | #endif | ||
3194 | #ifdef SYS_timer_delete | ||
3195 | #ifdef __NR_timer_delete | ||
3196 | {"timer_delete", __NR_timer_delete}, | ||
3197 | #endif | ||
3198 | #endif | ||
3199 | #ifdef SYS_timer_getoverrun | ||
3200 | #ifdef __NR_timer_getoverrun | ||
3201 | {"timer_getoverrun", __NR_timer_getoverrun}, | ||
3202 | #endif | ||
3203 | #endif | ||
3204 | #ifdef SYS_timer_gettime | ||
3205 | #ifdef __NR_timer_gettime | ||
3206 | {"timer_gettime", __NR_timer_gettime}, | ||
3207 | #endif | ||
3208 | #endif | ||
3209 | #ifdef SYS_timer_settime | ||
3210 | #ifdef __NR_timer_settime | ||
3211 | {"timer_settime", __NR_timer_settime}, | ||
3212 | #endif | ||
3213 | #endif | ||
3214 | #ifdef SYS_timerfd_create | ||
3215 | #ifdef __NR_timerfd_create | ||
3216 | {"timerfd_create", __NR_timerfd_create}, | ||
3217 | #endif | ||
3218 | #endif | ||
3219 | #ifdef SYS_timerfd_gettime | ||
3220 | #ifdef __NR_timerfd_gettime | ||
3221 | {"timerfd_gettime", __NR_timerfd_gettime}, | ||
3222 | #endif | ||
3223 | #endif | ||
3224 | #ifdef SYS_timerfd_settime | ||
3225 | #ifdef __NR_timerfd_settime | ||
3226 | {"timerfd_settime", __NR_timerfd_settime}, | ||
3227 | #endif | ||
3228 | #endif | ||
3229 | #ifdef SYS_times | ||
3230 | #ifdef __NR_times | ||
3231 | {"times", __NR_times}, | ||
3232 | #endif | ||
3233 | #endif | ||
3234 | #ifdef SYS_tkill | ||
3235 | #ifdef __NR_tkill | ||
3236 | {"tkill", __NR_tkill}, | ||
3237 | #endif | ||
3238 | #endif | ||
3239 | #ifdef SYS_truncate | ||
3240 | #ifdef __NR_truncate | ||
3241 | {"truncate", __NR_truncate}, | ||
3242 | #endif | ||
3243 | #endif | ||
3244 | #ifdef SYS_tuxcall | ||
3245 | #ifdef __NR_tuxcall | ||
3246 | {"tuxcall", __NR_tuxcall}, | ||
3247 | #endif | ||
3248 | #endif | ||
3249 | #ifdef SYS_umask | ||
3250 | #ifdef __NR_umask | ||
3251 | {"umask", __NR_umask}, | ||
3252 | #endif | ||
3253 | #endif | ||
3254 | #ifdef SYS_umount2 | ||
3255 | #ifdef __NR_umount2 | ||
3256 | {"umount2", __NR_umount2}, | ||
3257 | #endif | ||
3258 | #endif | ||
3259 | #ifdef SYS_uname | ||
3260 | #ifdef __NR_uname | ||
3261 | {"uname", __NR_uname}, | ||
3262 | #endif | ||
3263 | #endif | ||
3264 | #ifdef SYS_unlink | ||
3265 | #ifdef __NR_unlink | ||
3266 | {"unlink", __NR_unlink}, | ||
3267 | #endif | ||
3268 | #endif | ||
3269 | #ifdef SYS_unlinkat | ||
3270 | #ifdef __NR_unlinkat | ||
3271 | {"unlinkat", __NR_unlinkat}, | ||
3272 | #endif | ||
3273 | #endif | ||
3274 | #ifdef SYS_unshare | ||
3275 | #ifdef __NR_unshare | ||
3276 | {"unshare", __NR_unshare}, | ||
3277 | #endif | ||
3278 | #endif | ||
3279 | #ifdef SYS_uselib | ||
3280 | #ifdef __NR_uselib | ||
3281 | {"uselib", __NR_uselib}, | ||
3282 | #endif | ||
3283 | #endif | ||
3284 | #ifdef SYS_ustat | ||
3285 | #ifdef __NR_ustat | ||
3286 | {"ustat", __NR_ustat}, | ||
3287 | #endif | ||
3288 | #endif | ||
3289 | #ifdef SYS_utime | ||
3290 | #ifdef __NR_utime | ||
3291 | {"utime", __NR_utime}, | ||
3292 | #endif | ||
3293 | #endif | ||
3294 | #ifdef SYS_utimensat | ||
3295 | #ifdef __NR_utimensat | ||
3296 | {"utimensat", __NR_utimensat}, | ||
3297 | #endif | ||
3298 | #endif | ||
3299 | #ifdef SYS_utimes | ||
3300 | #ifdef __NR_utimes | ||
3301 | {"utimes", __NR_utimes}, | ||
3302 | #endif | ||
3303 | #endif | ||
3304 | #ifdef SYS_vfork | ||
3305 | #ifdef __NR_vfork | ||
3306 | {"vfork", __NR_vfork}, | ||
3307 | #endif | ||
3308 | #endif | ||
3309 | #ifdef SYS_vhangup | ||
3310 | #ifdef __NR_vhangup | ||
3311 | {"vhangup", __NR_vhangup}, | ||
3312 | #endif | ||
3313 | #endif | ||
3314 | #ifdef SYS_vmsplice | ||
3315 | #ifdef __NR_vmsplice | ||
3316 | {"vmsplice", __NR_vmsplice}, | ||
3317 | #endif | ||
3318 | #endif | ||
3319 | #ifdef SYS_vserver | ||
3320 | #ifdef __NR_vserver | ||
3321 | {"vserver", __NR_vserver}, | ||
3322 | #endif | ||
3323 | #endif | ||
3324 | #ifdef SYS_wait4 | ||
3325 | #ifdef __NR_wait4 | ||
3326 | {"wait4", __NR_wait4}, | ||
3327 | #endif | ||
3328 | #endif | ||
3329 | #ifdef SYS_waitid | ||
3330 | #ifdef __NR_waitid | ||
3331 | {"waitid", __NR_waitid}, | ||
3332 | #endif | ||
3333 | #endif | ||
3334 | #ifdef SYS_write | ||
3335 | #ifdef __NR_write | ||
3336 | {"write", __NR_write}, | ||
3337 | #endif | ||
3338 | #endif | ||
3339 | #ifdef SYS_writev | ||
3340 | #ifdef __NR_writev | ||
3341 | {"writev", __NR_writev}, | ||
3342 | #endif | ||
3343 | #endif | ||
3344 | #endif | ||
3345 | #if defined __x86_64__ && defined __ILP32__ | ||
3346 | #ifdef SYS_accept | ||
3347 | #ifdef __NR_accept | ||
3348 | {"accept", __NR_accept}, | ||
3349 | #endif | ||
3350 | #endif | ||
3351 | #ifdef SYS_accept4 | ||
3352 | #ifdef __NR_accept4 | ||
3353 | {"accept4", __NR_accept4}, | ||
3354 | #endif | ||
3355 | #endif | ||
3356 | #ifdef SYS_access | ||
3357 | #ifdef __NR_access | ||
3358 | {"access", __NR_access}, | ||
3359 | #endif | ||
3360 | #endif | ||
3361 | #ifdef SYS_acct | ||
3362 | #ifdef __NR_acct | ||
3363 | {"acct", __NR_acct}, | ||
3364 | #endif | ||
3365 | #endif | ||
3366 | #ifdef SYS_add_key | ||
3367 | #ifdef __NR_add_key | ||
3368 | {"add_key", __NR_add_key}, | ||
3369 | #endif | ||
3370 | #endif | ||
3371 | #ifdef SYS_adjtimex | ||
3372 | #ifdef __NR_adjtimex | ||
3373 | {"adjtimex", __NR_adjtimex}, | ||
3374 | #endif | ||
3375 | #endif | ||
3376 | #ifdef SYS_afs_syscall | ||
3377 | #ifdef __NR_afs_syscall | ||
3378 | {"afs_syscall", __NR_afs_syscall}, | ||
3379 | #endif | ||
3380 | #endif | ||
3381 | #ifdef SYS_alarm | ||
3382 | #ifdef __NR_alarm | ||
3383 | {"alarm", __NR_alarm}, | ||
3384 | #endif | ||
3385 | #endif | ||
3386 | #ifdef SYS_arch_prctl | ||
3387 | #ifdef __NR_arch_prctl | ||
3388 | {"arch_prctl", __NR_arch_prctl}, | ||
3389 | #endif | ||
3390 | #endif | ||
3391 | #ifdef SYS_bind | ||
3392 | #ifdef __NR_bind | ||
3393 | {"bind", __NR_bind}, | ||
3394 | #endif | ||
3395 | #endif | ||
3396 | #ifdef SYS_brk | ||
3397 | #ifdef __NR_brk | ||
3398 | {"brk", __NR_brk}, | ||
3399 | #endif | ||
3400 | #endif | ||
3401 | #ifdef SYS_capget | ||
3402 | #ifdef __NR_capget | ||
3403 | {"capget", __NR_capget}, | ||
3404 | #endif | ||
3405 | #endif | ||
3406 | #ifdef SYS_capset | ||
3407 | #ifdef __NR_capset | ||
3408 | {"capset", __NR_capset}, | ||
3409 | #endif | ||
3410 | #endif | ||
3411 | #ifdef SYS_chdir | ||
3412 | #ifdef __NR_chdir | ||
3413 | {"chdir", __NR_chdir}, | ||
3414 | #endif | ||
3415 | #endif | ||
3416 | #ifdef SYS_chmod | ||
3417 | #ifdef __NR_chmod | ||
3418 | {"chmod", __NR_chmod}, | ||
3419 | #endif | ||
3420 | #endif | ||
3421 | #ifdef SYS_chown | ||
3422 | #ifdef __NR_chown | ||
3423 | {"chown", __NR_chown}, | ||
3424 | #endif | ||
3425 | #endif | ||
3426 | #ifdef SYS_chroot | ||
3427 | #ifdef __NR_chroot | ||
3428 | {"chroot", __NR_chroot}, | ||
3429 | #endif | ||
3430 | #endif | ||
3431 | #ifdef SYS_clock_adjtime | ||
3432 | #ifdef __NR_clock_adjtime | ||
3433 | {"clock_adjtime", __NR_clock_adjtime}, | ||
3434 | #endif | ||
3435 | #endif | ||
3436 | #ifdef SYS_clock_getres | ||
3437 | #ifdef __NR_clock_getres | ||
3438 | {"clock_getres", __NR_clock_getres}, | ||
3439 | #endif | ||
3440 | #endif | ||
3441 | #ifdef SYS_clock_gettime | ||
3442 | #ifdef __NR_clock_gettime | ||
3443 | {"clock_gettime", __NR_clock_gettime}, | ||
3444 | #endif | ||
3445 | #endif | ||
3446 | #ifdef SYS_clock_nanosleep | ||
3447 | #ifdef __NR_clock_nanosleep | ||
3448 | {"clock_nanosleep", __NR_clock_nanosleep}, | ||
3449 | #endif | ||
3450 | #endif | ||
3451 | #ifdef SYS_clock_settime | ||
3452 | #ifdef __NR_clock_settime | ||
3453 | {"clock_settime", __NR_clock_settime}, | ||
3454 | #endif | ||
3455 | #endif | ||
3456 | #ifdef SYS_clone | ||
3457 | #ifdef __NR_clone | ||
3458 | {"clone", __NR_clone}, | ||
3459 | #endif | ||
3460 | #endif | ||
3461 | #ifdef SYS_close | ||
3462 | #ifdef __NR_close | ||
3463 | {"close", __NR_close}, | ||
3464 | #endif | ||
3465 | #endif | ||
3466 | #ifdef SYS_connect | ||
3467 | #ifdef __NR_connect | ||
3468 | {"connect", __NR_connect}, | ||
3469 | #endif | ||
3470 | #endif | ||
3471 | #ifdef SYS_creat | ||
3472 | #ifdef __NR_creat | ||
3473 | {"creat", __NR_creat}, | ||
3474 | #endif | ||
3475 | #endif | ||
3476 | #ifdef SYS_delete_module | ||
3477 | #ifdef __NR_delete_module | ||
3478 | {"delete_module", __NR_delete_module}, | ||
3479 | #endif | ||
3480 | #endif | ||
3481 | #ifdef SYS_dup | ||
3482 | #ifdef __NR_dup | ||
3483 | {"dup", __NR_dup}, | ||
3484 | #endif | ||
3485 | #endif | ||
3486 | #ifdef SYS_dup2 | ||
3487 | #ifdef __NR_dup2 | ||
3488 | {"dup2", __NR_dup2}, | ||
3489 | #endif | ||
3490 | #endif | ||
3491 | #ifdef SYS_dup3 | ||
3492 | #ifdef __NR_dup3 | ||
3493 | {"dup3", __NR_dup3}, | ||
3494 | #endif | ||
3495 | #endif | ||
3496 | #ifdef SYS_epoll_create | ||
3497 | #ifdef __NR_epoll_create | ||
3498 | {"epoll_create", __NR_epoll_create}, | ||
3499 | #endif | ||
3500 | #endif | ||
3501 | #ifdef SYS_epoll_create1 | ||
3502 | #ifdef __NR_epoll_create1 | ||
3503 | {"epoll_create1", __NR_epoll_create1}, | ||
3504 | #endif | ||
3505 | #endif | ||
3506 | #ifdef SYS_epoll_ctl | ||
3507 | #ifdef __NR_epoll_ctl | ||
3508 | {"epoll_ctl", __NR_epoll_ctl}, | ||
3509 | #endif | ||
3510 | #endif | ||
3511 | #ifdef SYS_epoll_pwait | ||
3512 | #ifdef __NR_epoll_pwait | ||
3513 | {"epoll_pwait", __NR_epoll_pwait}, | ||
3514 | #endif | ||
3515 | #endif | ||
3516 | #ifdef SYS_epoll_wait | ||
3517 | #ifdef __NR_epoll_wait | ||
3518 | {"epoll_wait", __NR_epoll_wait}, | ||
3519 | #endif | ||
3520 | #endif | ||
3521 | #ifdef SYS_eventfd | ||
3522 | #ifdef __NR_eventfd | ||
3523 | {"eventfd", __NR_eventfd}, | ||
3524 | #endif | ||
3525 | #endif | ||
3526 | #ifdef SYS_eventfd2 | ||
3527 | #ifdef __NR_eventfd2 | ||
3528 | {"eventfd2", __NR_eventfd2}, | ||
3529 | #endif | ||
3530 | #endif | ||
3531 | #ifdef SYS_execve | ||
3532 | #ifdef __NR_execve | ||
3533 | {"execve", __NR_execve}, | ||
3534 | #endif | ||
3535 | #endif | ||
3536 | #ifdef SYS_exit | ||
3537 | #ifdef __NR_exit | ||
3538 | {"exit", __NR_exit}, | ||
3539 | #endif | ||
3540 | #endif | ||
3541 | #ifdef SYS_exit_group | ||
3542 | #ifdef __NR_exit_group | ||
3543 | {"exit_group", __NR_exit_group}, | ||
3544 | #endif | ||
3545 | #endif | ||
3546 | #ifdef SYS_faccessat | ||
3547 | #ifdef __NR_faccessat | ||
3548 | {"faccessat", __NR_faccessat}, | ||
3549 | #endif | ||
3550 | #endif | ||
3551 | #ifdef SYS_fadvise64 | ||
3552 | #ifdef __NR_fadvise64 | ||
3553 | {"fadvise64", __NR_fadvise64}, | ||
3554 | #endif | ||
3555 | #endif | ||
3556 | #ifdef SYS_fallocate | ||
3557 | #ifdef __NR_fallocate | ||
3558 | {"fallocate", __NR_fallocate}, | ||
3559 | #endif | ||
3560 | #endif | ||
3561 | #ifdef SYS_fanotify_init | ||
3562 | #ifdef __NR_fanotify_init | ||
3563 | {"fanotify_init", __NR_fanotify_init}, | ||
3564 | #endif | ||
3565 | #endif | ||
3566 | #ifdef SYS_fanotify_mark | ||
3567 | #ifdef __NR_fanotify_mark | ||
3568 | {"fanotify_mark", __NR_fanotify_mark}, | ||
3569 | #endif | ||
3570 | #endif | ||
3571 | #ifdef SYS_fchdir | ||
3572 | #ifdef __NR_fchdir | ||
3573 | {"fchdir", __NR_fchdir}, | ||
3574 | #endif | ||
3575 | #endif | ||
3576 | #ifdef SYS_fchmod | ||
3577 | #ifdef __NR_fchmod | ||
3578 | {"fchmod", __NR_fchmod}, | ||
3579 | #endif | ||
3580 | #endif | ||
3581 | #ifdef SYS_fchmodat | ||
3582 | #ifdef __NR_fchmodat | ||
3583 | {"fchmodat", __NR_fchmodat}, | ||
3584 | #endif | ||
3585 | #endif | ||
3586 | #ifdef SYS_fchown | ||
3587 | #ifdef __NR_fchown | ||
3588 | {"fchown", __NR_fchown}, | ||
3589 | #endif | ||
3590 | #endif | ||
3591 | #ifdef SYS_fchownat | ||
3592 | #ifdef __NR_fchownat | ||
3593 | {"fchownat", __NR_fchownat}, | ||
3594 | #endif | ||
3595 | #endif | ||
3596 | #ifdef SYS_fcntl | ||
3597 | #ifdef __NR_fcntl | ||
3598 | {"fcntl", __NR_fcntl}, | ||
3599 | #endif | ||
3600 | #endif | ||
3601 | #ifdef SYS_fdatasync | ||
3602 | #ifdef __NR_fdatasync | ||
3603 | {"fdatasync", __NR_fdatasync}, | ||
3604 | #endif | ||
3605 | #endif | ||
3606 | #ifdef SYS_fgetxattr | ||
3607 | #ifdef __NR_fgetxattr | ||
3608 | {"fgetxattr", __NR_fgetxattr}, | ||
3609 | #endif | ||
3610 | #endif | ||
3611 | #ifdef SYS_finit_module | ||
3612 | #ifdef __NR_finit_module | ||
3613 | {"finit_module", __NR_finit_module}, | ||
3614 | #endif | ||
3615 | #endif | ||
3616 | #ifdef SYS_flistxattr | ||
3617 | #ifdef __NR_flistxattr | ||
3618 | {"flistxattr", __NR_flistxattr}, | ||
3619 | #endif | ||
3620 | #endif | ||
3621 | #ifdef SYS_flock | ||
3622 | #ifdef __NR_flock | ||
3623 | {"flock", __NR_flock}, | ||
3624 | #endif | ||
3625 | #endif | ||
3626 | #ifdef SYS_fork | ||
3627 | #ifdef __NR_fork | ||
3628 | {"fork", __NR_fork}, | ||
3629 | #endif | ||
3630 | #endif | ||
3631 | #ifdef SYS_fremovexattr | ||
3632 | #ifdef __NR_fremovexattr | ||
3633 | {"fremovexattr", __NR_fremovexattr}, | ||
3634 | #endif | ||
3635 | #endif | ||
3636 | #ifdef SYS_fsetxattr | ||
3637 | #ifdef __NR_fsetxattr | ||
3638 | {"fsetxattr", __NR_fsetxattr}, | ||
3639 | #endif | ||
3640 | #endif | ||
3641 | #ifdef SYS_fstat | ||
3642 | #ifdef __NR_fstat | ||
3643 | {"fstat", __NR_fstat}, | ||
3644 | #endif | ||
3645 | #endif | ||
3646 | #ifdef SYS_fstatfs | ||
3647 | #ifdef __NR_fstatfs | ||
3648 | {"fstatfs", __NR_fstatfs}, | ||
3649 | #endif | ||
3650 | #endif | ||
3651 | #ifdef SYS_fsync | ||
3652 | #ifdef __NR_fsync | ||
3653 | {"fsync", __NR_fsync}, | ||
3654 | #endif | ||
3655 | #endif | ||
3656 | #ifdef SYS_ftruncate | ||
3657 | #ifdef __NR_ftruncate | ||
3658 | {"ftruncate", __NR_ftruncate}, | ||
3659 | #endif | ||
3660 | #endif | ||
3661 | #ifdef SYS_futex | ||
3662 | #ifdef __NR_futex | ||
3663 | {"futex", __NR_futex}, | ||
3664 | #endif | ||
3665 | #endif | ||
3666 | #ifdef SYS_futimesat | ||
3667 | #ifdef __NR_futimesat | ||
3668 | {"futimesat", __NR_futimesat}, | ||
3669 | #endif | ||
3670 | #endif | ||
3671 | #ifdef SYS_get_mempolicy | ||
3672 | #ifdef __NR_get_mempolicy | ||
3673 | {"get_mempolicy", __NR_get_mempolicy}, | ||
3674 | #endif | ||
3675 | #endif | ||
3676 | #ifdef SYS_get_robust_list | ||
3677 | #ifdef __NR_get_robust_list | ||
3678 | {"get_robust_list", __NR_get_robust_list}, | ||
3679 | #endif | ||
3680 | #endif | ||
3681 | #ifdef SYS_getcpu | ||
3682 | #ifdef __NR_getcpu | ||
3683 | {"getcpu", __NR_getcpu}, | ||
3684 | #endif | ||
3685 | #endif | ||
3686 | #ifdef SYS_getcwd | ||
3687 | #ifdef __NR_getcwd | ||
3688 | {"getcwd", __NR_getcwd}, | ||
3689 | #endif | ||
3690 | #endif | ||
3691 | #ifdef SYS_getdents | ||
3692 | #ifdef __NR_getdents | ||
3693 | {"getdents", __NR_getdents}, | ||
3694 | #endif | ||
3695 | #endif | ||
3696 | #ifdef SYS_getdents64 | ||
3697 | #ifdef __NR_getdents64 | ||
3698 | {"getdents64", __NR_getdents64}, | ||
3699 | #endif | ||
3700 | #endif | ||
3701 | #ifdef SYS_getegid | ||
3702 | #ifdef __NR_getegid | ||
3703 | {"getegid", __NR_getegid}, | ||
3704 | #endif | ||
3705 | #endif | ||
3706 | #ifdef SYS_geteuid | ||
3707 | #ifdef __NR_geteuid | ||
3708 | {"geteuid", __NR_geteuid}, | ||
3709 | #endif | ||
3710 | #endif | ||
3711 | #ifdef SYS_getgid | ||
3712 | #ifdef __NR_getgid | ||
3713 | {"getgid", __NR_getgid}, | ||
3714 | #endif | ||
3715 | #endif | ||
3716 | #ifdef SYS_getgroups | ||
3717 | #ifdef __NR_getgroups | ||
3718 | {"getgroups", __NR_getgroups}, | ||
3719 | #endif | ||
3720 | #endif | ||
3721 | #ifdef SYS_getitimer | ||
3722 | #ifdef __NR_getitimer | ||
3723 | {"getitimer", __NR_getitimer}, | ||
3724 | #endif | ||
3725 | #endif | ||
3726 | #ifdef SYS_getpeername | ||
3727 | #ifdef __NR_getpeername | ||
3728 | {"getpeername", __NR_getpeername}, | ||
3729 | #endif | ||
3730 | #endif | ||
3731 | #ifdef SYS_getpgid | ||
3732 | #ifdef __NR_getpgid | ||
3733 | {"getpgid", __NR_getpgid}, | ||
3734 | #endif | ||
3735 | #endif | ||
3736 | #ifdef SYS_getpgrp | ||
3737 | #ifdef __NR_getpgrp | ||
3738 | {"getpgrp", __NR_getpgrp}, | ||
3739 | #endif | ||
3740 | #endif | ||
3741 | #ifdef SYS_getpid | ||
3742 | #ifdef __NR_getpid | ||
3743 | {"getpid", __NR_getpid}, | ||
3744 | #endif | ||
3745 | #endif | ||
3746 | #ifdef SYS_getpmsg | ||
3747 | #ifdef __NR_getpmsg | ||
3748 | {"getpmsg", __NR_getpmsg}, | ||
3749 | #endif | ||
3750 | #endif | ||
3751 | #ifdef SYS_getppid | ||
3752 | #ifdef __NR_getppid | ||
3753 | {"getppid", __NR_getppid}, | ||
3754 | #endif | ||
3755 | #endif | ||
3756 | #ifdef SYS_getpriority | ||
3757 | #ifdef __NR_getpriority | ||
3758 | {"getpriority", __NR_getpriority}, | ||
3759 | #endif | ||
3760 | #endif | ||
3761 | #ifdef SYS_getresgid | ||
3762 | #ifdef __NR_getresgid | ||
3763 | {"getresgid", __NR_getresgid}, | ||
3764 | #endif | ||
3765 | #endif | ||
3766 | #ifdef SYS_getresuid | ||
3767 | #ifdef __NR_getresuid | ||
3768 | {"getresuid", __NR_getresuid}, | ||
3769 | #endif | ||
3770 | #endif | ||
3771 | #ifdef SYS_getrlimit | ||
3772 | #ifdef __NR_getrlimit | ||
3773 | {"getrlimit", __NR_getrlimit}, | ||
3774 | #endif | ||
3775 | #endif | ||
3776 | #ifdef SYS_getrusage | ||
3777 | #ifdef __NR_getrusage | ||
3778 | {"getrusage", __NR_getrusage}, | ||
3779 | #endif | ||
3780 | #endif | ||
3781 | #ifdef SYS_getsid | ||
3782 | #ifdef __NR_getsid | ||
3783 | {"getsid", __NR_getsid}, | ||
3784 | #endif | ||
3785 | #endif | ||
3786 | #ifdef SYS_getsockname | ||
3787 | #ifdef __NR_getsockname | ||
3788 | {"getsockname", __NR_getsockname}, | ||
3789 | #endif | ||
3790 | #endif | ||
3791 | #ifdef SYS_getsockopt | ||
3792 | #ifdef __NR_getsockopt | ||
3793 | {"getsockopt", __NR_getsockopt}, | ||
3794 | #endif | ||
3795 | #endif | ||
3796 | #ifdef SYS_gettid | ||
3797 | #ifdef __NR_gettid | ||
3798 | {"gettid", __NR_gettid}, | ||
3799 | #endif | ||
3800 | #endif | ||
3801 | #ifdef SYS_gettimeofday | ||
3802 | #ifdef __NR_gettimeofday | ||
3803 | {"gettimeofday", __NR_gettimeofday}, | ||
3804 | #endif | ||
3805 | #endif | ||
3806 | #ifdef SYS_getuid | ||
3807 | #ifdef __NR_getuid | ||
3808 | {"getuid", __NR_getuid}, | ||
3809 | #endif | ||
3810 | #endif | ||
3811 | #ifdef SYS_getxattr | ||
3812 | #ifdef __NR_getxattr | ||
3813 | {"getxattr", __NR_getxattr}, | ||
3814 | #endif | ||
3815 | #endif | ||
3816 | #ifdef SYS_init_module | ||
3817 | #ifdef __NR_init_module | ||
3818 | {"init_module", __NR_init_module}, | ||
3819 | #endif | ||
3820 | #endif | ||
3821 | #ifdef SYS_inotify_add_watch | ||
3822 | #ifdef __NR_inotify_add_watch | ||
3823 | {"inotify_add_watch", __NR_inotify_add_watch}, | ||
3824 | #endif | ||
3825 | #endif | ||
3826 | #ifdef SYS_inotify_init | ||
3827 | #ifdef __NR_inotify_init | ||
3828 | {"inotify_init", __NR_inotify_init}, | ||
3829 | #endif | ||
3830 | #endif | ||
3831 | #ifdef SYS_inotify_init1 | ||
3832 | #ifdef __NR_inotify_init1 | ||
3833 | {"inotify_init1", __NR_inotify_init1}, | ||
3834 | #endif | ||
3835 | #endif | ||
3836 | #ifdef SYS_inotify_rm_watch | ||
3837 | #ifdef __NR_inotify_rm_watch | ||
3838 | {"inotify_rm_watch", __NR_inotify_rm_watch}, | ||
3839 | #endif | ||
3840 | #endif | ||
3841 | #ifdef SYS_io_cancel | ||
3842 | #ifdef __NR_io_cancel | ||
3843 | {"io_cancel", __NR_io_cancel}, | ||
3844 | #endif | ||
3845 | #endif | ||
3846 | #ifdef SYS_io_destroy | ||
3847 | #ifdef __NR_io_destroy | ||
3848 | {"io_destroy", __NR_io_destroy}, | ||
3849 | #endif | ||
3850 | #endif | ||
3851 | #ifdef SYS_io_getevents | ||
3852 | #ifdef __NR_io_getevents | ||
3853 | {"io_getevents", __NR_io_getevents}, | ||
3854 | #endif | ||
3855 | #endif | ||
3856 | #ifdef SYS_io_setup | ||
3857 | #ifdef __NR_io_setup | ||
3858 | {"io_setup", __NR_io_setup}, | ||
3859 | #endif | ||
3860 | #endif | ||
3861 | #ifdef SYS_io_submit | ||
3862 | #ifdef __NR_io_submit | ||
3863 | {"io_submit", __NR_io_submit}, | ||
3864 | #endif | ||
3865 | #endif | ||
3866 | #ifdef SYS_ioctl | ||
3867 | #ifdef __NR_ioctl | ||
3868 | {"ioctl", __NR_ioctl}, | ||
3869 | #endif | ||
3870 | #endif | ||
3871 | #ifdef SYS_ioperm | ||
3872 | #ifdef __NR_ioperm | ||
3873 | {"ioperm", __NR_ioperm}, | ||
3874 | #endif | ||
3875 | #endif | ||
3876 | #ifdef SYS_iopl | ||
3877 | #ifdef __NR_iopl | ||
3878 | {"iopl", __NR_iopl}, | ||
3879 | #endif | ||
3880 | #endif | ||
3881 | #ifdef SYS_ioprio_get | ||
3882 | #ifdef __NR_ioprio_get | ||
3883 | {"ioprio_get", __NR_ioprio_get}, | ||
3884 | #endif | ||
3885 | #endif | ||
3886 | #ifdef SYS_ioprio_set | ||
3887 | #ifdef __NR_ioprio_set | ||
3888 | {"ioprio_set", __NR_ioprio_set}, | ||
3889 | #endif | ||
3890 | #endif | ||
3891 | #ifdef SYS_kcmp | ||
3892 | #ifdef __NR_kcmp | ||
3893 | {"kcmp", __NR_kcmp}, | ||
3894 | #endif | ||
3895 | #endif | ||
3896 | #ifdef SYS_kexec_load | ||
3897 | #ifdef __NR_kexec_load | ||
3898 | {"kexec_load", __NR_kexec_load}, | ||
3899 | #endif | ||
3900 | #endif | ||
3901 | #ifdef SYS_keyctl | ||
3902 | #ifdef __NR_keyctl | ||
3903 | {"keyctl", __NR_keyctl}, | ||
3904 | #endif | ||
3905 | #endif | ||
3906 | #ifdef SYS_kill | ||
3907 | #ifdef __NR_kill | ||
3908 | {"kill", __NR_kill}, | ||
3909 | #endif | ||
3910 | #endif | ||
3911 | #ifdef SYS_lchown | ||
3912 | #ifdef __NR_lchown | ||
3913 | {"lchown", __NR_lchown}, | ||
3914 | #endif | ||
3915 | #endif | ||
3916 | #ifdef SYS_lgetxattr | ||
3917 | #ifdef __NR_lgetxattr | ||
3918 | {"lgetxattr", __NR_lgetxattr}, | ||
3919 | #endif | ||
3920 | #endif | ||
3921 | #ifdef SYS_link | ||
3922 | #ifdef __NR_link | ||
3923 | {"link", __NR_link}, | ||
3924 | #endif | ||
3925 | #endif | ||
3926 | #ifdef SYS_linkat | ||
3927 | #ifdef __NR_linkat | ||
3928 | {"linkat", __NR_linkat}, | ||
3929 | #endif | ||
3930 | #endif | ||
3931 | #ifdef SYS_listen | ||
3932 | #ifdef __NR_listen | ||
3933 | {"listen", __NR_listen}, | ||
3934 | #endif | ||
3935 | #endif | ||
3936 | #ifdef SYS_listxattr | ||
3937 | #ifdef __NR_listxattr | ||
3938 | {"listxattr", __NR_listxattr}, | ||
3939 | #endif | ||
3940 | #endif | ||
3941 | #ifdef SYS_llistxattr | ||
3942 | #ifdef __NR_llistxattr | ||
3943 | {"llistxattr", __NR_llistxattr}, | ||
3944 | #endif | ||
3945 | #endif | ||
3946 | #ifdef SYS_lookup_dcookie | ||
3947 | #ifdef __NR_lookup_dcookie | ||
3948 | {"lookup_dcookie", __NR_lookup_dcookie}, | ||
3949 | #endif | ||
3950 | #endif | ||
3951 | #ifdef SYS_lremovexattr | ||
3952 | #ifdef __NR_lremovexattr | ||
3953 | {"lremovexattr", __NR_lremovexattr}, | ||
3954 | #endif | ||
3955 | #endif | ||
3956 | #ifdef SYS_lseek | ||
3957 | #ifdef __NR_lseek | ||
3958 | {"lseek", __NR_lseek}, | ||
3959 | #endif | ||
3960 | #endif | ||
3961 | #ifdef SYS_lsetxattr | ||
3962 | #ifdef __NR_lsetxattr | ||
3963 | {"lsetxattr", __NR_lsetxattr}, | ||
3964 | #endif | ||
3965 | #endif | ||
3966 | #ifdef SYS_lstat | ||
3967 | #ifdef __NR_lstat | ||
3968 | {"lstat", __NR_lstat}, | ||
3969 | #endif | ||
3970 | #endif | ||
3971 | #ifdef SYS_madvise | ||
3972 | #ifdef __NR_madvise | ||
3973 | {"madvise", __NR_madvise}, | ||
3974 | #endif | ||
3975 | #endif | ||
3976 | #ifdef SYS_mbind | ||
3977 | #ifdef __NR_mbind | ||
3978 | {"mbind", __NR_mbind}, | ||
3979 | #endif | ||
3980 | #endif | ||
3981 | #ifdef SYS_migrate_pages | ||
3982 | #ifdef __NR_migrate_pages | ||
3983 | {"migrate_pages", __NR_migrate_pages}, | ||
3984 | #endif | ||
3985 | #endif | ||
3986 | #ifdef SYS_mincore | ||
3987 | #ifdef __NR_mincore | ||
3988 | {"mincore", __NR_mincore}, | ||
3989 | #endif | ||
3990 | #endif | ||
3991 | #ifdef SYS_mkdir | ||
3992 | #ifdef __NR_mkdir | ||
3993 | {"mkdir", __NR_mkdir}, | ||
3994 | #endif | ||
3995 | #endif | ||
3996 | #ifdef SYS_mkdirat | ||
3997 | #ifdef __NR_mkdirat | ||
3998 | {"mkdirat", __NR_mkdirat}, | ||
3999 | #endif | ||
4000 | #endif | ||
4001 | #ifdef SYS_mknod | ||
4002 | #ifdef __NR_mknod | ||
4003 | {"mknod", __NR_mknod}, | ||
4004 | #endif | ||
4005 | #endif | ||
4006 | #ifdef SYS_mknodat | ||
4007 | #ifdef __NR_mknodat | ||
4008 | {"mknodat", __NR_mknodat}, | ||
4009 | #endif | ||
4010 | #endif | ||
4011 | #ifdef SYS_mlock | ||
4012 | #ifdef __NR_mlock | ||
4013 | {"mlock", __NR_mlock}, | ||
4014 | #endif | ||
4015 | #endif | ||
4016 | #ifdef SYS_mlockall | ||
4017 | #ifdef __NR_mlockall | ||
4018 | {"mlockall", __NR_mlockall}, | ||
4019 | #endif | ||
4020 | #endif | ||
4021 | #ifdef SYS_mmap | ||
4022 | #ifdef __NR_mmap | ||
4023 | {"mmap", __NR_mmap}, | ||
4024 | #endif | ||
4025 | #endif | ||
4026 | #ifdef SYS_modify_ldt | ||
4027 | #ifdef __NR_modify_ldt | ||
4028 | {"modify_ldt", __NR_modify_ldt}, | ||
4029 | #endif | ||
4030 | #endif | ||
4031 | #ifdef SYS_mount | ||
4032 | #ifdef __NR_mount | ||
4033 | {"mount", __NR_mount}, | ||
4034 | #endif | ||
4035 | #endif | ||
4036 | #ifdef SYS_move_pages | ||
4037 | #ifdef __NR_move_pages | ||
4038 | {"move_pages", __NR_move_pages}, | ||
4039 | #endif | ||
4040 | #endif | ||
4041 | #ifdef SYS_mprotect | ||
4042 | #ifdef __NR_mprotect | ||
4043 | {"mprotect", __NR_mprotect}, | ||
4044 | #endif | ||
4045 | #endif | ||
4046 | #ifdef SYS_mq_getsetattr | ||
4047 | #ifdef __NR_mq_getsetattr | ||
4048 | {"mq_getsetattr", __NR_mq_getsetattr}, | ||
4049 | #endif | ||
4050 | #endif | ||
4051 | #ifdef SYS_mq_notify | ||
4052 | #ifdef __NR_mq_notify | ||
4053 | {"mq_notify", __NR_mq_notify}, | ||
4054 | #endif | ||
4055 | #endif | ||
4056 | #ifdef SYS_mq_open | ||
4057 | #ifdef __NR_mq_open | ||
4058 | {"mq_open", __NR_mq_open}, | ||
4059 | #endif | ||
4060 | #endif | ||
4061 | #ifdef SYS_mq_timedreceive | ||
4062 | #ifdef __NR_mq_timedreceive | ||
4063 | {"mq_timedreceive", __NR_mq_timedreceive}, | ||
4064 | #endif | ||
4065 | #endif | ||
4066 | #ifdef SYS_mq_timedsend | ||
4067 | #ifdef __NR_mq_timedsend | ||
4068 | {"mq_timedsend", __NR_mq_timedsend}, | ||
4069 | #endif | ||
4070 | #endif | ||
4071 | #ifdef SYS_mq_unlink | ||
4072 | #ifdef __NR_mq_unlink | ||
4073 | {"mq_unlink", __NR_mq_unlink}, | ||
4074 | #endif | ||
4075 | #endif | ||
4076 | #ifdef SYS_mremap | ||
4077 | #ifdef __NR_mremap | ||
4078 | {"mremap", __NR_mremap}, | ||
4079 | #endif | ||
4080 | #endif | ||
4081 | #ifdef SYS_msgctl | ||
4082 | #ifdef __NR_msgctl | ||
4083 | {"msgctl", __NR_msgctl}, | ||
4084 | #endif | ||
4085 | #endif | ||
4086 | #ifdef SYS_msgget | ||
4087 | #ifdef __NR_msgget | ||
4088 | {"msgget", __NR_msgget}, | ||
4089 | #endif | ||
4090 | #endif | ||
4091 | #ifdef SYS_msgrcv | ||
4092 | #ifdef __NR_msgrcv | ||
4093 | {"msgrcv", __NR_msgrcv}, | ||
4094 | #endif | ||
4095 | #endif | ||
4096 | #ifdef SYS_msgsnd | ||
4097 | #ifdef __NR_msgsnd | ||
4098 | {"msgsnd", __NR_msgsnd}, | ||
4099 | #endif | ||
4100 | #endif | ||
4101 | #ifdef SYS_msync | ||
4102 | #ifdef __NR_msync | ||
4103 | {"msync", __NR_msync}, | ||
4104 | #endif | ||
4105 | #endif | ||
4106 | #ifdef SYS_munlock | ||
4107 | #ifdef __NR_munlock | ||
4108 | {"munlock", __NR_munlock}, | ||
4109 | #endif | ||
4110 | #endif | ||
4111 | #ifdef SYS_munlockall | ||
4112 | #ifdef __NR_munlockall | ||
4113 | {"munlockall", __NR_munlockall}, | ||
4114 | #endif | ||
4115 | #endif | ||
4116 | #ifdef SYS_munmap | ||
4117 | #ifdef __NR_munmap | ||
4118 | {"munmap", __NR_munmap}, | ||
4119 | #endif | ||
4120 | #endif | ||
4121 | #ifdef SYS_name_to_handle_at | ||
4122 | #ifdef __NR_name_to_handle_at | ||
4123 | {"name_to_handle_at", __NR_name_to_handle_at}, | ||
4124 | #endif | ||
4125 | #endif | ||
4126 | #ifdef SYS_nanosleep | ||
4127 | #ifdef __NR_nanosleep | ||
4128 | {"nanosleep", __NR_nanosleep}, | ||
4129 | #endif | ||
4130 | #endif | ||
4131 | #ifdef SYS_newfstatat | ||
4132 | #ifdef __NR_newfstatat | ||
4133 | {"newfstatat", __NR_newfstatat}, | ||
4134 | #endif | ||
4135 | #endif | ||
4136 | #ifdef SYS_open | ||
4137 | #ifdef __NR_open | ||
4138 | {"open", __NR_open}, | ||
4139 | #endif | ||
4140 | #endif | ||
4141 | #ifdef SYS_open_by_handle_at | ||
4142 | #ifdef __NR_open_by_handle_at | ||
4143 | {"open_by_handle_at", __NR_open_by_handle_at}, | ||
4144 | #endif | ||
4145 | #endif | ||
4146 | #ifdef SYS_openat | ||
4147 | #ifdef __NR_openat | ||
4148 | {"openat", __NR_openat}, | ||
4149 | #endif | ||
4150 | #endif | ||
4151 | #ifdef SYS_pause | ||
4152 | #ifdef __NR_pause | ||
4153 | {"pause", __NR_pause}, | ||
4154 | #endif | ||
4155 | #endif | ||
4156 | #ifdef SYS_perf_event_open | ||
4157 | #ifdef __NR_perf_event_open | ||
4158 | {"perf_event_open", __NR_perf_event_open}, | ||
4159 | #endif | ||
4160 | #endif | ||
4161 | #ifdef SYS_personality | ||
4162 | #ifdef __NR_personality | ||
4163 | {"personality", __NR_personality}, | ||
4164 | #endif | ||
4165 | #endif | ||
4166 | #ifdef SYS_pipe | ||
4167 | #ifdef __NR_pipe | ||
4168 | {"pipe", __NR_pipe}, | ||
4169 | #endif | ||
4170 | #endif | ||
4171 | #ifdef SYS_pipe2 | ||
4172 | #ifdef __NR_pipe2 | ||
4173 | {"pipe2", __NR_pipe2}, | ||
4174 | #endif | ||
4175 | #endif | ||
4176 | #ifdef SYS_pivot_root | ||
4177 | #ifdef __NR_pivot_root | ||
4178 | {"pivot_root", __NR_pivot_root}, | ||
4179 | #endif | ||
4180 | #endif | ||
4181 | #ifdef SYS_poll | ||
4182 | #ifdef __NR_poll | ||
4183 | {"poll", __NR_poll}, | ||
4184 | #endif | ||
4185 | #endif | ||
4186 | #ifdef SYS_ppoll | ||
4187 | #ifdef __NR_ppoll | ||
4188 | {"ppoll", __NR_ppoll}, | ||
4189 | #endif | ||
4190 | #endif | ||
4191 | #ifdef SYS_prctl | ||
4192 | #ifdef __NR_prctl | ||
4193 | {"prctl", __NR_prctl}, | ||
4194 | #endif | ||
4195 | #endif | ||
4196 | #ifdef SYS_pread64 | ||
4197 | #ifdef __NR_pread64 | ||
4198 | {"pread64", __NR_pread64}, | ||
4199 | #endif | ||
4200 | #endif | ||
4201 | #ifdef SYS_preadv | ||
4202 | #ifdef __NR_preadv | ||
4203 | {"preadv", __NR_preadv}, | ||
4204 | #endif | ||
4205 | #endif | ||
4206 | #ifdef SYS_prlimit64 | ||
4207 | #ifdef __NR_prlimit64 | ||
4208 | {"prlimit64", __NR_prlimit64}, | ||
4209 | #endif | ||
4210 | #endif | ||
4211 | #ifdef SYS_process_vm_readv | ||
4212 | #ifdef __NR_process_vm_readv | ||
4213 | {"process_vm_readv", __NR_process_vm_readv}, | ||
4214 | #endif | ||
4215 | #endif | ||
4216 | #ifdef SYS_process_vm_writev | ||
4217 | #ifdef __NR_process_vm_writev | ||
4218 | {"process_vm_writev", __NR_process_vm_writev}, | ||
4219 | #endif | ||
4220 | #endif | ||
4221 | #ifdef SYS_pselect6 | ||
4222 | #ifdef __NR_pselect6 | ||
4223 | {"pselect6", __NR_pselect6}, | ||
4224 | #endif | ||
4225 | #endif | ||
4226 | #ifdef SYS_ptrace | ||
4227 | #ifdef __NR_ptrace | ||
4228 | {"ptrace", __NR_ptrace}, | ||
4229 | #endif | ||
4230 | #endif | ||
4231 | #ifdef SYS_putpmsg | ||
4232 | #ifdef __NR_putpmsg | ||
4233 | {"putpmsg", __NR_putpmsg}, | ||
4234 | #endif | ||
4235 | #endif | ||
4236 | #ifdef SYS_pwrite64 | ||
4237 | #ifdef __NR_pwrite64 | ||
4238 | {"pwrite64", __NR_pwrite64}, | ||
4239 | #endif | ||
4240 | #endif | ||
4241 | #ifdef SYS_pwritev | ||
4242 | #ifdef __NR_pwritev | ||
4243 | {"pwritev", __NR_pwritev}, | ||
4244 | #endif | ||
4245 | #endif | ||
4246 | #ifdef SYS_quotactl | ||
4247 | #ifdef __NR_quotactl | ||
4248 | {"quotactl", __NR_quotactl}, | ||
4249 | #endif | ||
4250 | #endif | ||
4251 | #ifdef SYS_read | ||
4252 | #ifdef __NR_read | ||
4253 | {"read", __NR_read}, | ||
4254 | #endif | ||
4255 | #endif | ||
4256 | #ifdef SYS_readahead | ||
4257 | #ifdef __NR_readahead | ||
4258 | {"readahead", __NR_readahead}, | ||
4259 | #endif | ||
4260 | #endif | ||
4261 | #ifdef SYS_readlink | ||
4262 | #ifdef __NR_readlink | ||
4263 | {"readlink", __NR_readlink}, | ||
4264 | #endif | ||
4265 | #endif | ||
4266 | #ifdef SYS_readlinkat | ||
4267 | #ifdef __NR_readlinkat | ||
4268 | {"readlinkat", __NR_readlinkat}, | ||
4269 | #endif | ||
4270 | #endif | ||
4271 | #ifdef SYS_readv | ||
4272 | #ifdef __NR_readv | ||
4273 | {"readv", __NR_readv}, | ||
4274 | #endif | ||
4275 | #endif | ||
4276 | #ifdef SYS_reboot | ||
4277 | #ifdef __NR_reboot | ||
4278 | {"reboot", __NR_reboot}, | ||
4279 | #endif | ||
4280 | #endif | ||
4281 | #ifdef SYS_recvfrom | ||
4282 | #ifdef __NR_recvfrom | ||
4283 | {"recvfrom", __NR_recvfrom}, | ||
4284 | #endif | ||
4285 | #endif | ||
4286 | #ifdef SYS_recvmmsg | ||
4287 | #ifdef __NR_recvmmsg | ||
4288 | {"recvmmsg", __NR_recvmmsg}, | ||
4289 | #endif | ||
4290 | #endif | ||
4291 | #ifdef SYS_recvmsg | ||
4292 | #ifdef __NR_recvmsg | ||
4293 | {"recvmsg", __NR_recvmsg}, | ||
4294 | #endif | ||
4295 | #endif | ||
4296 | #ifdef SYS_remap_file_pages | ||
4297 | #ifdef __NR_remap_file_pages | ||
4298 | {"remap_file_pages", __NR_remap_file_pages}, | ||
4299 | #endif | ||
4300 | #endif | ||
4301 | #ifdef SYS_removexattr | ||
4302 | #ifdef __NR_removexattr | ||
4303 | {"removexattr", __NR_removexattr}, | ||
4304 | #endif | ||
4305 | #endif | ||
4306 | #ifdef SYS_rename | ||
4307 | #ifdef __NR_rename | ||
4308 | {"rename", __NR_rename}, | ||
4309 | #endif | ||
4310 | #endif | ||
4311 | #ifdef SYS_renameat | ||
4312 | #ifdef __NR_renameat | ||
4313 | {"renameat", __NR_renameat}, | ||
4314 | #endif | ||
4315 | #endif | ||
4316 | #ifdef SYS_request_key | ||
4317 | #ifdef __NR_request_key | ||
4318 | {"request_key", __NR_request_key}, | ||
4319 | #endif | ||
4320 | #endif | ||
4321 | #ifdef SYS_restart_syscall | ||
4322 | #ifdef __NR_restart_syscall | ||
4323 | {"restart_syscall", __NR_restart_syscall}, | ||
4324 | #endif | ||
4325 | #endif | ||
4326 | #ifdef SYS_rmdir | ||
4327 | #ifdef __NR_rmdir | ||
4328 | {"rmdir", __NR_rmdir}, | ||
4329 | #endif | ||
4330 | #endif | ||
4331 | #ifdef SYS_rt_sigaction | ||
4332 | #ifdef __NR_rt_sigaction | ||
4333 | {"rt_sigaction", __NR_rt_sigaction}, | ||
4334 | #endif | ||
4335 | #endif | ||
4336 | #ifdef SYS_rt_sigpending | ||
4337 | #ifdef __NR_rt_sigpending | ||
4338 | {"rt_sigpending", __NR_rt_sigpending}, | ||
4339 | #endif | ||
4340 | #endif | ||
4341 | #ifdef SYS_rt_sigprocmask | ||
4342 | #ifdef __NR_rt_sigprocmask | ||
4343 | {"rt_sigprocmask", __NR_rt_sigprocmask}, | ||
4344 | #endif | ||
4345 | #endif | ||
4346 | #ifdef SYS_rt_sigqueueinfo | ||
4347 | #ifdef __NR_rt_sigqueueinfo | ||
4348 | {"rt_sigqueueinfo", __NR_rt_sigqueueinfo}, | ||
4349 | #endif | ||
4350 | #endif | ||
4351 | #ifdef SYS_rt_sigreturn | ||
4352 | #ifdef __NR_rt_sigreturn | ||
4353 | {"rt_sigreturn", __NR_rt_sigreturn}, | ||
4354 | #endif | ||
4355 | #endif | ||
4356 | #ifdef SYS_rt_sigsuspend | ||
4357 | #ifdef __NR_rt_sigsuspend | ||
4358 | {"rt_sigsuspend", __NR_rt_sigsuspend}, | ||
4359 | #endif | ||
4360 | #endif | ||
4361 | #ifdef SYS_rt_sigtimedwait | ||
4362 | #ifdef __NR_rt_sigtimedwait | ||
4363 | {"rt_sigtimedwait", __NR_rt_sigtimedwait}, | ||
4364 | #endif | ||
4365 | #endif | ||
4366 | #ifdef SYS_rt_tgsigqueueinfo | ||
4367 | #ifdef __NR_rt_tgsigqueueinfo | ||
4368 | {"rt_tgsigqueueinfo", __NR_rt_tgsigqueueinfo}, | ||
4369 | #endif | ||
4370 | #endif | ||
4371 | #ifdef SYS_sched_get_priority_max | ||
4372 | #ifdef __NR_sched_get_priority_max | ||
4373 | {"sched_get_priority_max", __NR_sched_get_priority_max}, | ||
4374 | #endif | ||
4375 | #endif | ||
4376 | #ifdef SYS_sched_get_priority_min | ||
4377 | #ifdef __NR_sched_get_priority_min | ||
4378 | {"sched_get_priority_min", __NR_sched_get_priority_min}, | ||
4379 | #endif | ||
4380 | #endif | ||
4381 | #ifdef SYS_sched_getaffinity | ||
4382 | #ifdef __NR_sched_getaffinity | ||
4383 | {"sched_getaffinity", __NR_sched_getaffinity}, | ||
4384 | #endif | ||
4385 | #endif | ||
4386 | #ifdef SYS_sched_getparam | ||
4387 | #ifdef __NR_sched_getparam | ||
4388 | {"sched_getparam", __NR_sched_getparam}, | ||
4389 | #endif | ||
4390 | #endif | ||
4391 | #ifdef SYS_sched_getscheduler | ||
4392 | #ifdef __NR_sched_getscheduler | ||
4393 | {"sched_getscheduler", __NR_sched_getscheduler}, | ||
4394 | #endif | ||
4395 | #endif | ||
4396 | #ifdef SYS_sched_rr_get_interval | ||
4397 | #ifdef __NR_sched_rr_get_interval | ||
4398 | {"sched_rr_get_interval", __NR_sched_rr_get_interval}, | ||
4399 | #endif | ||
4400 | #endif | ||
4401 | #ifdef SYS_sched_setaffinity | ||
4402 | #ifdef __NR_sched_setaffinity | ||
4403 | {"sched_setaffinity", __NR_sched_setaffinity}, | ||
4404 | #endif | ||
4405 | #endif | ||
4406 | #ifdef SYS_sched_setparam | ||
4407 | #ifdef __NR_sched_setparam | ||
4408 | {"sched_setparam", __NR_sched_setparam}, | ||
4409 | #endif | ||
4410 | #endif | ||
4411 | #ifdef SYS_sched_setscheduler | ||
4412 | #ifdef __NR_sched_setscheduler | ||
4413 | {"sched_setscheduler", __NR_sched_setscheduler}, | ||
4414 | #endif | ||
4415 | #endif | ||
4416 | #ifdef SYS_sched_yield | ||
4417 | #ifdef __NR_sched_yield | ||
4418 | {"sched_yield", __NR_sched_yield}, | ||
4419 | #endif | ||
4420 | #endif | ||
4421 | #ifdef SYS_security | ||
4422 | #ifdef __NR_security | ||
4423 | {"security", __NR_security}, | ||
4424 | #endif | ||
4425 | #endif | ||
4426 | #ifdef SYS_select | ||
4427 | #ifdef __NR_select | ||
4428 | {"select", __NR_select}, | ||
4429 | #endif | ||
4430 | #endif | ||
4431 | #ifdef SYS_semctl | ||
4432 | #ifdef __NR_semctl | ||
4433 | {"semctl", __NR_semctl}, | ||
4434 | #endif | ||
4435 | #endif | ||
4436 | #ifdef SYS_semget | ||
4437 | #ifdef __NR_semget | ||
4438 | {"semget", __NR_semget}, | ||
4439 | #endif | ||
4440 | #endif | ||
4441 | #ifdef SYS_semop | ||
4442 | #ifdef __NR_semop | ||
4443 | {"semop", __NR_semop}, | ||
4444 | #endif | ||
4445 | #endif | ||
4446 | #ifdef SYS_semtimedop | ||
4447 | #ifdef __NR_semtimedop | ||
4448 | {"semtimedop", __NR_semtimedop}, | ||
4449 | #endif | ||
4450 | #endif | ||
4451 | #ifdef SYS_sendfile | ||
4452 | #ifdef __NR_sendfile | ||
4453 | {"sendfile", __NR_sendfile}, | ||
4454 | #endif | ||
4455 | #endif | ||
4456 | #ifdef SYS_sendmmsg | ||
4457 | #ifdef __NR_sendmmsg | ||
4458 | {"sendmmsg", __NR_sendmmsg}, | ||
4459 | #endif | ||
4460 | #endif | ||
4461 | #ifdef SYS_sendmsg | ||
4462 | #ifdef __NR_sendmsg | ||
4463 | {"sendmsg", __NR_sendmsg}, | ||
4464 | #endif | ||
4465 | #endif | ||
4466 | #ifdef SYS_sendto | ||
4467 | #ifdef __NR_sendto | ||
4468 | {"sendto", __NR_sendto}, | ||
4469 | #endif | ||
4470 | #endif | ||
4471 | #ifdef SYS_set_mempolicy | ||
4472 | #ifdef __NR_set_mempolicy | ||
4473 | {"set_mempolicy", __NR_set_mempolicy}, | ||
4474 | #endif | ||
4475 | #endif | ||
4476 | #ifdef SYS_set_robust_list | ||
4477 | #ifdef __NR_set_robust_list | ||
4478 | {"set_robust_list", __NR_set_robust_list}, | ||
4479 | #endif | ||
4480 | #endif | ||
4481 | #ifdef SYS_set_tid_address | ||
4482 | #ifdef __NR_set_tid_address | ||
4483 | {"set_tid_address", __NR_set_tid_address}, | ||
4484 | #endif | ||
4485 | #endif | ||
4486 | #ifdef SYS_setdomainname | ||
4487 | #ifdef __NR_setdomainname | ||
4488 | {"setdomainname", __NR_setdomainname}, | ||
4489 | #endif | ||
4490 | #endif | ||
4491 | #ifdef SYS_setfsgid | ||
4492 | #ifdef __NR_setfsgid | ||
4493 | {"setfsgid", __NR_setfsgid}, | ||
4494 | #endif | ||
4495 | #endif | ||
4496 | #ifdef SYS_setfsuid | ||
4497 | #ifdef __NR_setfsuid | ||
4498 | {"setfsuid", __NR_setfsuid}, | ||
4499 | #endif | ||
4500 | #endif | ||
4501 | #ifdef SYS_setgid | ||
4502 | #ifdef __NR_setgid | ||
4503 | {"setgid", __NR_setgid}, | ||
4504 | #endif | ||
4505 | #endif | ||
4506 | #ifdef SYS_setgroups | ||
4507 | #ifdef __NR_setgroups | ||
4508 | {"setgroups", __NR_setgroups}, | ||
4509 | #endif | ||
4510 | #endif | ||
4511 | #ifdef SYS_sethostname | ||
4512 | #ifdef __NR_sethostname | ||
4513 | {"sethostname", __NR_sethostname}, | ||
4514 | #endif | ||
4515 | #endif | ||
4516 | #ifdef SYS_setitimer | ||
4517 | #ifdef __NR_setitimer | ||
4518 | {"setitimer", __NR_setitimer}, | ||
4519 | #endif | ||
4520 | #endif | ||
4521 | #ifdef SYS_setns | ||
4522 | #ifdef __NR_setns | ||
4523 | {"setns", __NR_setns}, | ||
4524 | #endif | ||
4525 | #endif | ||
4526 | #ifdef SYS_setpgid | ||
4527 | #ifdef __NR_setpgid | ||
4528 | {"setpgid", __NR_setpgid}, | ||
4529 | #endif | ||
4530 | #endif | ||
4531 | #ifdef SYS_setpriority | ||
4532 | #ifdef __NR_setpriority | ||
4533 | {"setpriority", __NR_setpriority}, | ||
4534 | #endif | ||
4535 | #endif | ||
4536 | #ifdef SYS_setregid | ||
4537 | #ifdef __NR_setregid | ||
4538 | {"setregid", __NR_setregid}, | ||
4539 | #endif | ||
4540 | #endif | ||
4541 | #ifdef SYS_setresgid | ||
4542 | #ifdef __NR_setresgid | ||
4543 | {"setresgid", __NR_setresgid}, | ||
4544 | #endif | ||
4545 | #endif | ||
4546 | #ifdef SYS_setresuid | ||
4547 | #ifdef __NR_setresuid | ||
4548 | {"setresuid", __NR_setresuid}, | ||
4549 | #endif | ||
4550 | #endif | ||
4551 | #ifdef SYS_setreuid | ||
4552 | #ifdef __NR_setreuid | ||
4553 | {"setreuid", __NR_setreuid}, | ||
4554 | #endif | ||
4555 | #endif | ||
4556 | #ifdef SYS_setrlimit | ||
4557 | #ifdef __NR_setrlimit | ||
4558 | {"setrlimit", __NR_setrlimit}, | ||
4559 | #endif | ||
4560 | #endif | ||
4561 | #ifdef SYS_setsid | ||
4562 | #ifdef __NR_setsid | ||
4563 | {"setsid", __NR_setsid}, | ||
4564 | #endif | ||
4565 | #endif | ||
4566 | #ifdef SYS_setsockopt | ||
4567 | #ifdef __NR_setsockopt | ||
4568 | {"setsockopt", __NR_setsockopt}, | ||
4569 | #endif | ||
4570 | #endif | ||
4571 | #ifdef SYS_settimeofday | ||
4572 | #ifdef __NR_settimeofday | ||
4573 | {"settimeofday", __NR_settimeofday}, | ||
4574 | #endif | ||
4575 | #endif | ||
4576 | #ifdef SYS_setuid | ||
4577 | #ifdef __NR_setuid | ||
4578 | {"setuid", __NR_setuid}, | ||
4579 | #endif | ||
4580 | #endif | ||
4581 | #ifdef SYS_setxattr | ||
4582 | #ifdef __NR_setxattr | ||
4583 | {"setxattr", __NR_setxattr}, | ||
4584 | #endif | ||
4585 | #endif | ||
4586 | #ifdef SYS_shmat | ||
4587 | #ifdef __NR_shmat | ||
4588 | {"shmat", __NR_shmat}, | ||
4589 | #endif | ||
4590 | #endif | ||
4591 | #ifdef SYS_shmctl | ||
4592 | #ifdef __NR_shmctl | ||
4593 | {"shmctl", __NR_shmctl}, | ||
4594 | #endif | ||
4595 | #endif | ||
4596 | #ifdef SYS_shmdt | ||
4597 | #ifdef __NR_shmdt | ||
4598 | {"shmdt", __NR_shmdt}, | ||
4599 | #endif | ||
4600 | #endif | ||
4601 | #ifdef SYS_shmget | ||
4602 | #ifdef __NR_shmget | ||
4603 | {"shmget", __NR_shmget}, | ||
4604 | #endif | ||
4605 | #endif | ||
4606 | #ifdef SYS_shutdown | ||
4607 | #ifdef __NR_shutdown | ||
4608 | {"shutdown", __NR_shutdown}, | ||
4609 | #endif | ||
4610 | #endif | ||
4611 | #ifdef SYS_sigaltstack | ||
4612 | #ifdef __NR_sigaltstack | ||
4613 | {"sigaltstack", __NR_sigaltstack}, | ||
4614 | #endif | ||
4615 | #endif | ||
4616 | #ifdef SYS_signalfd | ||
4617 | #ifdef __NR_signalfd | ||
4618 | {"signalfd", __NR_signalfd}, | ||
4619 | #endif | ||
4620 | #endif | ||
4621 | #ifdef SYS_signalfd4 | ||
4622 | #ifdef __NR_signalfd4 | ||
4623 | {"signalfd4", __NR_signalfd4}, | ||
4624 | #endif | ||
4625 | #endif | ||
4626 | #ifdef SYS_socket | ||
4627 | #ifdef __NR_socket | ||
4628 | {"socket", __NR_socket}, | ||
4629 | #endif | ||
4630 | #endif | ||
4631 | #ifdef SYS_socketpair | ||
4632 | #ifdef __NR_socketpair | ||
4633 | {"socketpair", __NR_socketpair}, | ||
4634 | #endif | ||
4635 | #endif | ||
4636 | #ifdef SYS_splice | ||
4637 | #ifdef __NR_splice | ||
4638 | {"splice", __NR_splice}, | ||
4639 | #endif | ||
4640 | #endif | ||
4641 | #ifdef SYS_stat | ||
4642 | #ifdef __NR_stat | ||
4643 | {"stat", __NR_stat}, | ||
4644 | #endif | ||
4645 | #endif | ||
4646 | #ifdef SYS_statfs | ||
4647 | #ifdef __NR_statfs | ||
4648 | {"statfs", __NR_statfs}, | ||
4649 | #endif | ||
4650 | #endif | ||
4651 | #ifdef SYS_swapoff | ||
4652 | #ifdef __NR_swapoff | ||
4653 | {"swapoff", __NR_swapoff}, | ||
4654 | #endif | ||
4655 | #endif | ||
4656 | #ifdef SYS_swapon | ||
4657 | #ifdef __NR_swapon | ||
4658 | {"swapon", __NR_swapon}, | ||
4659 | #endif | ||
4660 | #endif | ||
4661 | #ifdef SYS_symlink | ||
4662 | #ifdef __NR_symlink | ||
4663 | {"symlink", __NR_symlink}, | ||
4664 | #endif | ||
4665 | #endif | ||
4666 | #ifdef SYS_symlinkat | ||
4667 | #ifdef __NR_symlinkat | ||
4668 | {"symlinkat", __NR_symlinkat}, | ||
4669 | #endif | ||
4670 | #endif | ||
4671 | #ifdef SYS_sync | ||
4672 | #ifdef __NR_sync | ||
4673 | {"sync", __NR_sync}, | ||
4674 | #endif | ||
4675 | #endif | ||
4676 | #ifdef SYS_sync_file_range | ||
4677 | #ifdef __NR_sync_file_range | ||
4678 | {"sync_file_range", __NR_sync_file_range}, | ||
4679 | #endif | ||
4680 | #endif | ||
4681 | #ifdef SYS_syncfs | ||
4682 | #ifdef __NR_syncfs | ||
4683 | {"syncfs", __NR_syncfs}, | ||
4684 | #endif | ||
4685 | #endif | ||
4686 | #ifdef SYS_sysfs | ||
4687 | #ifdef __NR_sysfs | ||
4688 | {"sysfs", __NR_sysfs}, | ||
4689 | #endif | ||
4690 | #endif | ||
4691 | #ifdef SYS_sysinfo | ||
4692 | #ifdef __NR_sysinfo | ||
4693 | {"sysinfo", __NR_sysinfo}, | ||
4694 | #endif | ||
4695 | #endif | ||
4696 | #ifdef SYS_syslog | ||
4697 | #ifdef __NR_syslog | ||
4698 | {"syslog", __NR_syslog}, | ||
4699 | #endif | ||
4700 | #endif | ||
4701 | #ifdef SYS_tee | ||
4702 | #ifdef __NR_tee | ||
4703 | {"tee", __NR_tee}, | ||
4704 | #endif | ||
4705 | #endif | ||
4706 | #ifdef SYS_tgkill | ||
4707 | #ifdef __NR_tgkill | ||
4708 | {"tgkill", __NR_tgkill}, | ||
4709 | #endif | ||
4710 | #endif | ||
4711 | #ifdef SYS_time | ||
4712 | #ifdef __NR_time | ||
4713 | {"time", __NR_time}, | ||
4714 | #endif | ||
4715 | #endif | ||
4716 | #ifdef SYS_timer_create | ||
4717 | #ifdef __NR_timer_create | ||
4718 | {"timer_create", __NR_timer_create}, | ||
4719 | #endif | ||
4720 | #endif | ||
4721 | #ifdef SYS_timer_delete | ||
4722 | #ifdef __NR_timer_delete | ||
4723 | {"timer_delete", __NR_timer_delete}, | ||
4724 | #endif | ||
4725 | #endif | ||
4726 | #ifdef SYS_timer_getoverrun | ||
4727 | #ifdef __NR_timer_getoverrun | ||
4728 | {"timer_getoverrun", __NR_timer_getoverrun}, | ||
4729 | #endif | ||
4730 | #endif | ||
4731 | #ifdef SYS_timer_gettime | ||
4732 | #ifdef __NR_timer_gettime | ||
4733 | {"timer_gettime", __NR_timer_gettime}, | ||
4734 | #endif | ||
4735 | #endif | ||
4736 | #ifdef SYS_timer_settime | ||
4737 | #ifdef __NR_timer_settime | ||
4738 | {"timer_settime", __NR_timer_settime}, | ||
4739 | #endif | ||
4740 | #endif | ||
4741 | #ifdef SYS_timerfd_create | ||
4742 | #ifdef __NR_timerfd_create | ||
4743 | {"timerfd_create", __NR_timerfd_create}, | ||
4744 | #endif | ||
4745 | #endif | ||
4746 | #ifdef SYS_timerfd_gettime | ||
4747 | #ifdef __NR_timerfd_gettime | ||
4748 | {"timerfd_gettime", __NR_timerfd_gettime}, | ||
4749 | #endif | ||
4750 | #endif | ||
4751 | #ifdef SYS_timerfd_settime | ||
4752 | #ifdef __NR_timerfd_settime | ||
4753 | {"timerfd_settime", __NR_timerfd_settime}, | ||
4754 | #endif | ||
4755 | #endif | ||
4756 | #ifdef SYS_times | ||
4757 | #ifdef __NR_times | ||
4758 | {"times", __NR_times}, | ||
4759 | #endif | ||
4760 | #endif | ||
4761 | #ifdef SYS_tkill | ||
4762 | #ifdef __NR_tkill | ||
4763 | {"tkill", __NR_tkill}, | ||
4764 | #endif | ||
4765 | #endif | ||
4766 | #ifdef SYS_truncate | ||
4767 | #ifdef __NR_truncate | ||
4768 | {"truncate", __NR_truncate}, | ||
4769 | #endif | ||
4770 | #endif | ||
4771 | #ifdef SYS_tuxcall | ||
4772 | #ifdef __NR_tuxcall | ||
4773 | {"tuxcall", __NR_tuxcall}, | ||
4774 | #endif | ||
4775 | #endif | ||
4776 | #ifdef SYS_umask | ||
4777 | #ifdef __NR_umask | ||
4778 | {"umask", __NR_umask}, | ||
4779 | #endif | ||
4780 | #endif | ||
4781 | #ifdef SYS_umount2 | ||
4782 | #ifdef __NR_umount2 | ||
4783 | {"umount2", __NR_umount2}, | ||
4784 | #endif | ||
4785 | #endif | ||
4786 | #ifdef SYS_uname | ||
4787 | #ifdef __NR_uname | ||
4788 | {"uname", __NR_uname}, | ||
4789 | #endif | ||
4790 | #endif | ||
4791 | #ifdef SYS_unlink | ||
4792 | #ifdef __NR_unlink | ||
4793 | {"unlink", __NR_unlink}, | ||
4794 | #endif | ||
4795 | #endif | ||
4796 | #ifdef SYS_unlinkat | ||
4797 | #ifdef __NR_unlinkat | ||
4798 | {"unlinkat", __NR_unlinkat}, | ||
4799 | #endif | ||
4800 | #endif | ||
4801 | #ifdef SYS_unshare | ||
4802 | #ifdef __NR_unshare | ||
4803 | {"unshare", __NR_unshare}, | ||
4804 | #endif | ||
4805 | #endif | ||
4806 | #ifdef SYS_ustat | ||
4807 | #ifdef __NR_ustat | ||
4808 | {"ustat", __NR_ustat}, | ||
4809 | #endif | ||
4810 | #endif | ||
4811 | #ifdef SYS_utime | ||
4812 | #ifdef __NR_utime | ||
4813 | {"utime", __NR_utime}, | ||
4814 | #endif | ||
4815 | #endif | ||
4816 | #ifdef SYS_utimensat | ||
4817 | #ifdef __NR_utimensat | ||
4818 | {"utimensat", __NR_utimensat}, | ||
4819 | #endif | ||
4820 | #endif | ||
4821 | #ifdef SYS_utimes | ||
4822 | #ifdef __NR_utimes | ||
4823 | {"utimes", __NR_utimes}, | ||
4824 | #endif | ||
4825 | #endif | ||
4826 | #ifdef SYS_vfork | ||
4827 | #ifdef __NR_vfork | ||
4828 | {"vfork", __NR_vfork}, | ||
4829 | #endif | ||
4830 | #endif | ||
4831 | #ifdef SYS_vhangup | ||
4832 | #ifdef __NR_vhangup | ||
4833 | {"vhangup", __NR_vhangup}, | ||
4834 | #endif | ||
4835 | #endif | ||
4836 | #ifdef SYS_vmsplice | ||
4837 | #ifdef __NR_vmsplice | ||
4838 | {"vmsplice", __NR_vmsplice}, | ||
4839 | #endif | ||
4840 | #endif | ||
4841 | #ifdef SYS_wait4 | ||
4842 | #ifdef __NR_wait4 | ||
4843 | {"wait4", __NR_wait4}, | ||
4844 | #endif | ||
4845 | #endif | ||
4846 | #ifdef SYS_waitid | ||
4847 | #ifdef __NR_waitid | ||
4848 | {"waitid", __NR_waitid}, | ||
4849 | #endif | ||
4850 | #endif | ||
4851 | #ifdef SYS_write | ||
4852 | #ifdef __NR_write | ||
4853 | {"write", __NR_write}, | ||
4854 | #endif | ||
4855 | #endif | ||
4856 | #ifdef SYS_writev | ||
4857 | #ifdef __NR_writev | ||
4858 | {"writev", __NR_writev}, | ||
4859 | #endif | ||
4860 | #endif | ||
4861 | #endif | ||
4862 | |||
4863 | // | ||
4864 | // end of generated code | ||
4865 | // | ||
4866 | }; // end of syslist | ||
4867 | |||
4868 | const char *syscall_find_nr(int nr) { | ||
4869 | int i; | ||
4870 | int elems = sizeof(syslist) / sizeof(syslist[0]); | ||
4871 | for (i = 0; i < elems; i++) { | ||
4872 | if (nr == syslist[i].nr) | ||
4873 | return syslist[i].name; | ||
4874 | } | ||
4875 | |||
4876 | return "unknown"; | ||
4877 | } | ||
4878 | |||
4879 | // return -1 if error, or syscall number | ||
4880 | static int syscall_find_name(const char *name) { | ||
4881 | int i; | ||
4882 | int elems = sizeof(syslist) / sizeof(syslist[0]); | ||
4883 | for (i = 0; i < elems; i++) { | ||
4884 | if (strcmp(name, syslist[i].name) == 0) | ||
4885 | return syslist[i].nr; | ||
4886 | } | ||
4887 | |||
4888 | return -1; | ||
4889 | } | ||
4890 | |||
4891 | // return 1 if error, 0 if OK | ||
4892 | int syscall_check_list(const char *slist, void (*callback)(int)) { | ||
4893 | // don't allow empty lists | ||
4894 | if (slist == NULL || *slist == '\0') { | ||
4895 | fprintf(stderr, "Error: empty syscall lists are not allowed\n"); | ||
4896 | return -1; | ||
4897 | } | ||
4898 | |||
4899 | // work on a copy of the string | ||
4900 | char *str = strdup(slist); | ||
4901 | if (!str) | ||
4902 | errExit("strdup"); | ||
4903 | |||
4904 | char *ptr = str; | ||
4905 | char *start = str; | ||
4906 | while (*ptr != '\0') { | ||
4907 | if (islower(*ptr) || isdigit(*ptr) || *ptr == '_') | ||
4908 | ; | ||
4909 | else if (*ptr == ',') { | ||
4910 | *ptr = '\0'; | ||
4911 | int nr = syscall_find_name(start); | ||
4912 | if (nr == -1) | ||
4913 | fprintf(stderr, "Warning: syscall %s not found\n", start); | ||
4914 | else if (callback != NULL) | ||
4915 | callback(nr); | ||
4916 | |||
4917 | start = ptr + 1; | ||
4918 | } | ||
4919 | ptr++; | ||
4920 | } | ||
4921 | if (*start != '\0') { | ||
4922 | int nr = syscall_find_name(start); | ||
4923 | if (nr == -1) | ||
4924 | fprintf(stderr, "Warning: syscall %s not found\n", start); | ||
4925 | else if (callback != NULL) | ||
4926 | callback(nr); | ||
4927 | } | ||
4928 | |||
4929 | free(str); | ||
4930 | return 0; | ||
4931 | } | ||
4932 | |||
4933 | void syscall_print(void) { | ||
4934 | int i; | ||
4935 | int elems = sizeof(syslist) / sizeof(syslist[0]); | ||
4936 | for (i = 0; i < elems; i++) { | ||
4937 | printf("%d\t- %s\n", syslist[i].nr, syslist[i].name); | ||
4938 | } | ||
4939 | printf("\n"); | ||
4940 | } | ||
4941 | |||
4942 | #endif // HAVE_SECCOMP | ||
diff --git a/src/firejail/usage.c b/src/firejail/usage.c new file mode 100644 index 000000000..71ae203ff --- /dev/null +++ b/src/firejail/usage.c | |||
@@ -0,0 +1,312 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 | |||
22 | void usage(void) { | ||
23 | printf("firejail - version %s\n\n", VERSION); | ||
24 | printf("Firejail is a SUID sandbox program that reduces the risk of security breaches by\n"); | ||
25 | printf("restricting the running environment of untrusted applications using Linux\n"); | ||
26 | printf("namespaces. It includes a sandbox profile for Mozilla Firefox.\n\n"); | ||
27 | printf("\n"); | ||
28 | printf("Usage: firejail [options] [program and arguments]\n\n"); | ||
29 | printf("\n"); | ||
30 | printf("Without any options, the sandbox consists of a filesystem chroot build from the\n"); | ||
31 | printf("current system directories mounted read-only, and new PID and IPC\n"); | ||
32 | printf("namespaces. If no program is specified as an argument, /bin/bash is started by\n"); | ||
33 | printf("default in the sandbox.\n\n"); | ||
34 | printf("\n"); | ||
35 | printf("Options:\n\n"); | ||
36 | printf("\t-- - signal the end of options and disables further option processing.\n\n"); | ||
37 | printf("\t--bandwidth=name - set bandwidth limits for the sandbox identified\n"); | ||
38 | printf("\t\tby name, see Traffic Shaping section for more details.\n\n"); | ||
39 | printf("\t--bandwidth=pid - set bandwidth limits for the sandbox identified\n"); | ||
40 | printf("\t\tby PID, see Traffic Shaping section for more details.\n\n"); | ||
41 | #ifdef HAVE_BIND | ||
42 | printf("\t--bind=dirname1,dirname2 - mount-bind dirname1 on top of dirname2.\n\n"); | ||
43 | printf("\t--bind=filename1,dirname2 - mount-bind filename1 on top of filename2.\n\n"); | ||
44 | #endif | ||
45 | printf("\t--blacklist=dirname_or_filename - blacklist directory or file.\n\n"); | ||
46 | printf("\t-c - execute command and exit.\n\n"); | ||
47 | printf("\t--caps - enable default Linux capabilities filter. The filter disables\n"); | ||
48 | printf("\t\tCAP_SYS_MODULE, CAP_SYS_RAWIO, CAP_SYS_BOOT, CAP_SYS_NICE,\n"); | ||
49 | printf("\t\tCAP_SYS_TTY_CONFIG, CAP_SYSLOG, CAP_MKNOD, CAP_SYS_ADMIN.\n\n"); | ||
50 | printf("\t--caps.drop=all - drop all capabilities.\n\n"); | ||
51 | printf("\t--caps.drop=capability,capability,capability - blacklist Linux\n"); | ||
52 | printf("\t\tcapabilities filter.\n\n"); | ||
53 | printf("\t--caps.keep=capability,capability,capability - whitelist Linux\n"); | ||
54 | printf("\t\tcapabilities filter.\n\n"); | ||
55 | printf("\t--caps.print=name - print the caps filter for the sandbox identified\n"); | ||
56 | printf("\t\tby name.\n\n"); | ||
57 | printf("\t--caps.print=pid - print the caps filter for the sandbox identified\n"); | ||
58 | printf("\t\tby PID.\n\n"); | ||
59 | printf("\t--cgroup=tasks-file - place the sandbox in the specified control group.\n"); | ||
60 | printf("\t\ttasks-file is the full path of cgroup tasks file.\n"); | ||
61 | printf("\t\tExample: --cgroup=/sys/fs/cgroup/g1/tasks\n\n"); | ||
62 | #ifdef HAVE_CHROOT | ||
63 | printf("\t--chroot=dirname - chroot into dirname directory.\n\n"); | ||
64 | #endif | ||
65 | printf("\t--cpu=cpu-number,cpu-number - set cpu affinity.\n"); | ||
66 | printf("\t\tExample: cpu=0,1,2\n\n"); | ||
67 | printf("\t--csh - use /bin/csh as default shell.\n\n"); | ||
68 | printf("\t--debug - print sandbox debug messages.\n\n"); | ||
69 | printf("\t--debug-syscalls - print all recognized system calls in the current\n"); | ||
70 | printf("\t\tFirejail software build and exit.\n\n"); | ||
71 | printf("\t--debug-caps - print all recognized capabilities in the current\n"); | ||
72 | printf("\t\tFirejail software build and exit.\n\n"); | ||
73 | printf("\t--defaultgw=address - use this address as default gateway in the new\n"); | ||
74 | printf("\t\tnetwork namespace.\n\n"); | ||
75 | printf("\t--dns=address - set a DNS server for the sandbox. Up to three DNS\n"); | ||
76 | printf("\t\tservers can be defined.\n\n"); | ||
77 | printf("\t--dns.print=name - print DNS configuration for the sandbox identified\n"); | ||
78 | printf("\t\tby name.\n\n"); | ||
79 | printf("\t--dns.print=pid - print DNS configuration of the sandbox identified.\n"); | ||
80 | printf("\t\tby PID.\n\n"); | ||
81 | printf("\t--help, -? - this help screen.\n\n"); | ||
82 | printf("\t--ip=address - set interface IP address.\n\n"); | ||
83 | printf("\t--ip=none - no IP address and no default gateway address are configured\n"); | ||
84 | printf("\t\tin the new network namespace. Use this option in case you intend\n"); | ||
85 | printf("\t\tto start an external DHCP client in the sandbox.\n\n"); | ||
86 | printf("\t--iprange=address,address - configure an IP address in this range\n\n"); | ||
87 | printf("\t--ipc-namespace - enable a new IPC namespace if the sandbox was started\n"); | ||
88 | printf("\t\tas a regular user. IPC namespace is enabled by default only if\n"); | ||
89 | printf("\t\tthe sandbox is started as root.\n\n"); | ||
90 | printf("\t--join=name - join the sandbox identified by name.\n\n"); | ||
91 | printf("\t--join=pid - join the sandbox identified by PID.\n\n"); | ||
92 | printf("\t--list - list all sandboxes.\n\n"); | ||
93 | printf("\t--mac=xx:xx:xx:xx:xx:xx - set interface MAC address.\n\n"); | ||
94 | printf("\t--name=name - set sandbox hostname.\n\n"); | ||
95 | printf("\t--net=bridgename - enable network namespaces and connect to this bridge\n"); | ||
96 | printf("\t\tdevice. Unless specified with option --ip and --defaultgw, an\n"); | ||
97 | printf("\t\tIP address and a default gateway will be assigned automatically\n"); | ||
98 | printf("\t\tto the sandbox. The IP address is checked using ARP before\n"); | ||
99 | printf("\t\tassignment. The IP address assigned as default gateway is the\n"); | ||
100 | printf("\t\tbridge device IP address. Up to four --net devices can\n"); | ||
101 | printf("\t\tbe defined. Mixing bridge and macvlan devices is allowed.\n\n"); | ||
102 | printf("\t--net=ethernet_interface - enable network namespaces and connect\n"); | ||
103 | printf("\t\tto this ethernet_interface using the standard Linux macvlan\n"); | ||
104 | printf("\t\tdriver. Unless specified with option --ip and --defaultgw, an\n"); | ||
105 | printf("\t\tIP address and a default gateway will be assigned automatically\n"); | ||
106 | printf("\t\tto the sandbox. The IP address is checked using ARP before\n"); | ||
107 | printf("\t\tassignment. The IP address assigned as default gateway is the\n"); | ||
108 | printf("\t\tdefault gateway of the host. Up to four --net devices can\n"); | ||
109 | printf("\t\tbe defined. Mixing bridge and macvlan devices is allowed.\n\n"); | ||
110 | printf("\t--net=none - enable a new, unconnected network namespace.\n\n"); | ||
111 | |||
112 | printf("\t--netfilter - enable the default client network filter in the new\n"); | ||
113 | printf("\t\tnetwork namespace:\n\n"); | ||
114 | printf("\t\t*filter\n"); | ||
115 | printf("\t\t:INPUT DROP [0:0]\n"); | ||
116 | printf("\t\t:FORWARD DROP [0:0]\n"); | ||
117 | printf("\t\t:OUTPUT ACCEPT [0:0]\n"); | ||
118 | printf("\t\t-A INPUT -i lo -j ACCEPT\n"); | ||
119 | printf("\t\t-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n"); | ||
120 | printf("\t\t-A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT\n"); | ||
121 | printf("\t\t-A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT\n"); | ||
122 | printf("\t\t-A INPUT -p icmp --icmp-type echo-request -j ACCEPT \n"); | ||
123 | printf("\t\tCOMMIT\n\n"); | ||
124 | printf("\t--netfilter=filename - enable the network filter specified by\n"); | ||
125 | printf("\t\tfilename in the new network namespace. The filter file format\n"); | ||
126 | printf("\t\tis the format of iptables-save and iptable-restore commands.\n\n"); | ||
127 | |||
128 | printf("\t--netstats - monitor network statistics for sandboxes creating a new\n"); | ||
129 | printf("\t\tnetwork namespace.\n\n"); | ||
130 | printf("\t--nogroups - disable supplementary groups. Without this option,\n"); | ||
131 | printf("\t\tsupplementary groups are enabled for the user starting the\n"); | ||
132 | printf("\t\tsandbox. For root user supplementary groups are always\n"); | ||
133 | printf("\t\tdisabled.\n\n"); | ||
134 | |||
135 | printf("\t--noroot - install a user namespace with a single user - the current\n"); | ||
136 | printf("\t\tuser. root user does not exist in the new namespace. This option\n"); | ||
137 | printf("\t\tis not supported for --chroot and --overlay configurations.\n\n"); | ||
138 | |||
139 | printf("\t--output=logfile - stdout logging and log rotation. Copy stdout to\n"); | ||
140 | printf("\t\tlogfile, and keep the size of the file under 500KB using log\n"); | ||
141 | printf("\t\trotation. Five files with prefixes .1 to .5 are used in\n"); | ||
142 | printf("\t\trotation.\n\n"); | ||
143 | printf("\t--overlay - mount a filesystem overlay on top of the current filesystem.\n"); | ||
144 | printf("\t\t(OverlayFS support is required in Linux kernel for this option\n"); | ||
145 | printf("\t\tto work)\n\n"); | ||
146 | |||
147 | printf("\t--private - mount new /root and /home/user directories in temporary\n"); | ||
148 | printf("\t\tfilesystems. All modifications are discarded when the sandbox is\n"); | ||
149 | printf("\t\tclosed.\n\n"); | ||
150 | printf("\t--private=directory - use directory as user home.\n\n"); | ||
151 | printf("\t--private.keep=file,directory - build a new user home in a temporary\n"); | ||
152 | printf("\t\tfilesystem, and copy the files and directories in the list in\n"); | ||
153 | printf("\t\tthe new home. All modifications are discarded when the sandbox\n"); | ||
154 | printf("\t\tis closed.\n\n"); | ||
155 | printf("\t--private-dev - create a new /dev directory. Only null, full, zero, tty,\n"); | ||
156 | printf("\t\tpst, ptms, random, urandom and shm devices are available.\n\n"); | ||
157 | |||
158 | printf("\t--profile=filename - use a custom profile.\n\n"); | ||
159 | printf("\t--read-only=dirname_or_filename - set directory or file read-only.\n\n"); | ||
160 | printf("\t--rlimit-fsize=number - set the maximum file size that can be created\n"); | ||
161 | printf("\t\tby a process.\n\n"); | ||
162 | printf("\t--rlimit-nofile=number - set the maximum number of files that can be\n"); | ||
163 | printf("\t\topened by a process.\n\n"); | ||
164 | printf("\t--rlimit-nproc=number - set the maximum number of processes that can be\n"); | ||
165 | printf("\t\tcreated for the real user ID of the calling process.\n\n"); | ||
166 | printf("\t--rlimit-sigpending=number - set the maximum number of pending signals\n"); | ||
167 | printf("\t\tfor a process.\n\n"); | ||
168 | |||
169 | printf("\t--scan - ARP-scan all the networks from inside a network namespace.\n"); | ||
170 | printf("\t\tThis makes it possible to detect macvlan kernel device drivers\n"); | ||
171 | printf("\t\trunning on the current host.\n\n"); | ||
172 | |||
173 | #ifdef HAVE_SECCOMP | ||
174 | printf("\t--seccomp - enable seccomp filter and blacklist the syscalls in the\n"); | ||
175 | printf("\t\tlist. The default list is as follows: mount, umount2,\n"); | ||
176 | printf("\t\tptrace, kexec_load, open_by_handle_at, init_module,\n"); | ||
177 | printf("\t\tfinit_module, delete_module, iopl, ioperm, swapon, swapoff,\n"); | ||
178 | printf("\t\tmknode, syslog, process_vm_readv and process_vm_writev\n"); | ||
179 | printf("\t\tsysfs,_sysctl, adjtimex, clock_adjtime, lookup_dcookie,\n"); | ||
180 | printf("\t\tperf_event_open, fanotify_init and kcmp.\n\n"); | ||
181 | |||
182 | printf("\t--seccomp=syscall,syscall,syscall - enable seccomp filter, blacklist the\n"); | ||
183 | printf("\t\tdefault syscall list and the syscalls specified by the command.\n\n"); | ||
184 | |||
185 | printf("\t--seccomp.drop=syscall,syscall,syscall - enable seccomp filter, and\n"); | ||
186 | printf("\t\tblacklist the syscalls specified by the command.\n\n"); | ||
187 | |||
188 | printf("\t--seccomp.keep=syscall,syscall,syscall - enable seccomp filter, and\n"); | ||
189 | printf("\t\twhitelist the syscalls specified by the command.\n\n"); | ||
190 | |||
191 | printf("\t--seccomp.print=name - print the seccomp filter for the sandbox\n"); | ||
192 | printf("\t\tidentified by name.\n\n"); | ||
193 | printf("\t--seccomp.print=pid - print the seccomp filter for the sandbox\n"); | ||
194 | printf("\t\tidentified by PID.\n\n"); | ||
195 | #endif | ||
196 | |||
197 | printf("\t--shell=none - run the program directly without a user shell.\n\n"); | ||
198 | printf("\t--shell=program - set default user shell.\n\n"); | ||
199 | printf("\t--shutdown=name - shutdown the sandbox identified by name.\n\n"); | ||
200 | printf("\t--shutdown=pid - shutdown the sandbox identified by PID.\n\n"); | ||
201 | printf("\t--tmpfs=dirname - mount a tmpfs filesystem on directory dirname.\n\n"); | ||
202 | printf("\t--top - monitor the most CPU-intensive sandboxes.\n\n"); | ||
203 | printf("\t--trace - trace open, access and connect system calls.\n\n"); | ||
204 | printf("\t--tree - print a tree of all sandboxed processes.\n\n"); | ||
205 | printf("\t--version - print program version and exit.\n\n"); | ||
206 | printf("\t--zsh - use /usr/bin/zsh as default shell.\n\n"); | ||
207 | printf("\n"); | ||
208 | printf("\n"); | ||
209 | |||
210 | |||
211 | printf("Traffic Shaping\n\n"); | ||
212 | |||
213 | printf("Network bandwidth is an expensive resource shared among all sandboxes\n"); | ||
214 | printf("running on a system. Traffic shaping allows the user to increase network\n"); | ||
215 | printf("performance by controlling the amount of data that flows into and out of the\n"); | ||
216 | printf("sandboxes. Firejail implements a simple rate-limiting shaper based on Linux\n"); | ||
217 | printf("command tc. The shaper works at sandbox level, and can be used only for\n"); | ||
218 | printf("sandboxes configured with new network namespaces.\n\n"); | ||
219 | |||
220 | printf("Set rate-limits:\n"); | ||
221 | printf("\tfirejail --bandwidth={name|pid} set network-name down-speed up-speed\n\n"); | ||
222 | printf("Clear rate-limits:\n"); | ||
223 | printf("\tfirejail --bandwidth={name|pid} clear network-name\n\n"); | ||
224 | printf("Status:\n"); | ||
225 | printf("\tfirejail --bandwidth={name|pid} status\n\n"); | ||
226 | printf("where:\n"); | ||
227 | printf("\tname - sandbox name\n"); | ||
228 | printf("\tpid - sandbox pid\n"); | ||
229 | printf("\tnetwork-name - network name as used by --net option\n"); | ||
230 | printf("\tdown-speed - download speed in KB/s (decimal kilobyte per second)\n"); | ||
231 | printf("\tup-speed - upload speed in KB/s (decimal kilobyte per second)\n"); | ||
232 | printf("\n"); | ||
233 | printf("Example:\n"); | ||
234 | printf("\t$ firejail --name=mybrowser --net=eth0 firefox &\n"); | ||
235 | printf("\t$ firejail --bandwidth=mybrowser set eth0 80 20\n"); | ||
236 | printf("\t$ firejail --bandwidth=mybrowser status\n"); | ||
237 | printf("\t$ firejail --bandwidth=mybrowser clear eth0\n"); | ||
238 | printf("\n"); | ||
239 | printf("\n"); | ||
240 | |||
241 | |||
242 | |||
243 | printf("Monitoring\n\n"); | ||
244 | |||
245 | printf("Option --list prints a list of all sandboxes. The format for each entry is as\n"); | ||
246 | printf("follows:\n\n"); | ||
247 | printf("\tPID:USER:Command\n\n"); | ||
248 | |||
249 | printf("Option --tree prints the tree of processes running in the sandbox. The format\n"); | ||
250 | printf("for each process entry is as follows:\n\n"); | ||
251 | printf("\tPID:USER:Command\n\n"); | ||
252 | |||
253 | printf("Option --top is similar to the UNIX top command, however it applies only to\n"); | ||
254 | printf("sandboxes. Listed below are the available fields (columns) in alphabetical\n"); | ||
255 | printf("order:\n\n"); | ||
256 | printf("\tCommand - command used to start the sandbox.\n"); | ||
257 | printf("\tCPU%% - CPU usage, the sandbox share of the elapsed CPU time since the\n"); | ||
258 | printf("\t last screen update\n"); | ||
259 | printf("\tPID - Unique process ID for the task controlling the sandbox.\n"); | ||
260 | printf("\tPrcs - number of processes running in sandbox, including the controlling\n"); | ||
261 | printf("\t process.\n"); | ||
262 | printf("\tRES - Resident Memory Size (KiB), sandbox non-swapped physical memory.\n"); | ||
263 | printf("\t It is a sum of the RES values for all processes running in the\n"); | ||
264 | printf("\t sandbox.\n"); | ||
265 | printf("\tSHR - Shared Memory Size (KiB), it reflects memory shared with other\n"); | ||
266 | printf("\t processes. It is a sum of the SHR values for all processes running\n"); | ||
267 | printf("\t in the sandbox, including the controlling process.\n"); | ||
268 | printf("\tUptime - sandbox running time in hours:minutes:seconds format.\n"); | ||
269 | printf("\tUser - The owner of the sandbox.\n"); | ||
270 | printf("\n"); | ||
271 | printf("\n"); | ||
272 | printf("Profile files\n\n"); | ||
273 | printf("Several command line configuration options can be passed to the program using\n"); | ||
274 | printf("profile files. Default Firejail profile files are stored in /etc/firejail\n"); | ||
275 | printf("directory, user profile files are stored in ~/.config/firejail directory. See\n"); | ||
276 | printf("man 5 firejail-profile for more information.\n\n"); | ||
277 | printf("\n"); | ||
278 | printf("Restricted shell\n\n"); | ||
279 | printf("To configure a restricted shell, replace /bin/bash with /usr/bin/firejail i\n"); | ||
280 | printf("/etc/password file for each user that needs to be restricted.\n"); | ||
281 | printf("Alternatively, you can specify /usr/bin/firejail in adduser command:\n\n"); | ||
282 | printf(" adduser --shell /usr/bin/firejail username\n\n"); | ||
283 | printf("Arguments to be passed to firejail executable upon login are declared in\n"); | ||
284 | printf("/etc/firejail/login.users file.\n\n"); | ||
285 | printf("\n"); | ||
286 | printf("Examples:\n\n"); | ||
287 | printf(" $ firejail\n"); | ||
288 | printf(" start a regular /bin/bash session in sandbox\n"); | ||
289 | printf(" $ firejail firefox\n"); | ||
290 | printf(" start Mozilla Firefox\n"); | ||
291 | printf(" $ firejail --seccomp firefox\n"); | ||
292 | printf(" start Mozilla Firefox in a seccomp sandbox\n"); | ||
293 | printf(" $ firejail --caps firefox\n"); | ||
294 | printf(" start Mozilla Firefox in a Linux capabilities sandbox\n"); | ||
295 | printf(" $ firejail --debug firefox\n"); | ||
296 | printf(" debug Firefox sandbox\n"); | ||
297 | printf(" $ firejail --private\n"); | ||
298 | printf(" start a /bin/bash session with a new tmpfs home directory\n"); | ||
299 | printf(" $ firejail --net=br0 ip=10.10.20.10\n"); | ||
300 | printf(" start a /bin/bash session in a new network namespace; the session is\n"); | ||
301 | printf(" connected to the main network using br0 bridge device, an IP address\n"); | ||
302 | printf(" of 10.10.20.10 is assigned to the sandbox\n"); | ||
303 | printf(" $ firejail --net=br0 --net=br1 --net=br2\n"); | ||
304 | printf(" start a /bin/bash session in a new network namespace and connect it\n"); | ||
305 | printf(" to br0, br1, and br2 host bridge devices\n"); | ||
306 | printf(" $ firejail --list\n"); | ||
307 | printf(" list all running sandboxes\n"); | ||
308 | printf("\n"); | ||
309 | printf("License GPL version 2 or later\n"); | ||
310 | printf("Homepage: http://firejail.sourceforge.net\n"); | ||
311 | printf("\n"); | ||
312 | } | ||
diff --git a/src/firejail/util.c b/src/firejail/util.c new file mode 100644 index 000000000..2c50caf17 --- /dev/null +++ b/src/firejail/util.c | |||
@@ -0,0 +1,480 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 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/stat.h> | ||
22 | #include <fcntl.h> | ||
23 | #include <syslog.h> | ||
24 | #include <errno.h> | ||
25 | #include <dirent.h> | ||
26 | #include <grp.h> | ||
27 | |||
28 | #define MAX_GROUPS 1024 | ||
29 | // drop privileges | ||
30 | // - for root group or if nogroups is set, supplementary groups are not configured | ||
31 | void drop_privs(int nogroups) { | ||
32 | gid_t gid = getgid(); | ||
33 | |||
34 | // configure supplementary groups | ||
35 | if (gid == 0 || nogroups) { | ||
36 | if (setgroups(0, NULL) < 0) | ||
37 | errExit("setgroups"); | ||
38 | if (arg_debug) | ||
39 | printf("Username %s, no supplementary groups\n", cfg.username); | ||
40 | } | ||
41 | else { | ||
42 | assert(cfg.username); | ||
43 | gid_t groups[MAX_GROUPS]; | ||
44 | int ngroups = MAX_GROUPS; | ||
45 | int rv = getgrouplist(cfg.username, gid, groups, &ngroups); | ||
46 | |||
47 | if (arg_debug && rv) { | ||
48 | printf("Username %s, groups ", cfg.username); | ||
49 | int i; | ||
50 | for (i = 0; i < ngroups; i++) | ||
51 | printf("%u, ", groups[i]); | ||
52 | printf("\n"); | ||
53 | } | ||
54 | |||
55 | if (rv == -1) { | ||
56 | fprintf(stderr, "Warning: cannot extract supplementary group list, dropping them\n"); | ||
57 | if (setgroups(0, NULL) < 0) | ||
58 | errExit("setgroups"); | ||
59 | } | ||
60 | else { | ||
61 | rv = setgroups(ngroups, groups); | ||
62 | if (rv) { | ||
63 | fprintf(stderr, "Warning: cannot set supplementary group list, dropping them\n"); | ||
64 | if (setgroups(0, NULL) < 0) | ||
65 | errExit("setgroups"); | ||
66 | } | ||
67 | } | ||
68 | } | ||
69 | |||
70 | // set uid/gid | ||
71 | if (setgid(getgid()) < 0) | ||
72 | errExit("setgid/getgid"); | ||
73 | if (setuid(getuid()) < 0) | ||
74 | errExit("setuid/getuid"); | ||
75 | } | ||
76 | |||
77 | |||
78 | void logsignal(int s) { | ||
79 | if (!arg_debug) | ||
80 | return; | ||
81 | |||
82 | openlog("firejail", LOG_NDELAY | LOG_PID, LOG_USER); | ||
83 | syslog(LOG_INFO, "Signal %d caught", s); | ||
84 | closelog(); | ||
85 | } | ||
86 | |||
87 | |||
88 | void logmsg(const char *msg) { | ||
89 | if (!arg_debug) | ||
90 | return; | ||
91 | |||
92 | openlog("firejail", LOG_NDELAY | LOG_PID, LOG_USER); | ||
93 | syslog(LOG_INFO, "%s\n", msg); | ||
94 | closelog(); | ||
95 | } | ||
96 | |||
97 | |||
98 | void logargs(int argc, char **argv) { | ||
99 | if (!arg_debug) | ||
100 | return; | ||
101 | |||
102 | int i; | ||
103 | int len = 0; | ||
104 | |||
105 | // calculate message length | ||
106 | for (i = 0; i < argc; i++) | ||
107 | len += strlen(argv[i]) + 1; // + ' ' | ||
108 | |||
109 | // build message | ||
110 | char msg[len + 1]; | ||
111 | char *ptr = msg; | ||
112 | for (i = 0; i < argc; i++) { | ||
113 | sprintf(ptr, "%s ", argv[i]); | ||
114 | ptr += strlen(ptr); | ||
115 | } | ||
116 | |||
117 | // log message | ||
118 | logmsg(msg); | ||
119 | } | ||
120 | |||
121 | |||
122 | void logerr(const char *msg) { | ||
123 | if (!arg_debug) | ||
124 | return; | ||
125 | |||
126 | openlog("firejail", LOG_NDELAY | LOG_PID, LOG_USER); | ||
127 | syslog(LOG_ERR, "%s\n", msg); | ||
128 | closelog(); | ||
129 | } | ||
130 | |||
131 | |||
132 | // return -1 if error, 0 if no error | ||
133 | int copy_file(const char *srcname, const char *destname) { | ||
134 | assert(srcname); | ||
135 | assert(destname); | ||
136 | |||
137 | // open source | ||
138 | int src = open(srcname, O_RDONLY); | ||
139 | if (src < 0) { | ||
140 | fprintf(stderr, "Warning: cannot open %s, file not copied\n", srcname); | ||
141 | return -1; | ||
142 | } | ||
143 | |||
144 | // open destination | ||
145 | int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | ||
146 | if (dst < 0) { | ||
147 | fprintf(stderr, "Warning: cannot open %s, file not copied\n", destname); | ||
148 | close(src); | ||
149 | return -1; | ||
150 | } | ||
151 | |||
152 | // copy | ||
153 | ssize_t len; | ||
154 | static const int BUFLEN = 1024; | ||
155 | unsigned char buf[BUFLEN]; | ||
156 | while ((len = read(src, buf, BUFLEN)) > 0) { | ||
157 | int done = 0; | ||
158 | while (done != len) { | ||
159 | int rv = write(dst, buf + done, len - done); | ||
160 | if (rv == -1) { | ||
161 | close(src); | ||
162 | close(dst); | ||
163 | return -1; | ||
164 | } | ||
165 | |||
166 | done += rv; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | close(src); | ||
171 | close(dst); | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | |||
176 | char *get_link(const char *fname) { | ||
177 | assert(fname); | ||
178 | struct stat sb; | ||
179 | char *linkname; | ||
180 | ssize_t r; | ||
181 | |||
182 | if (lstat(fname, &sb) == -1) | ||
183 | return NULL; | ||
184 | |||
185 | linkname = malloc(sb.st_size + 1); | ||
186 | if (linkname == NULL) | ||
187 | return NULL; | ||
188 | memset(linkname, 0, sb.st_size + 1); | ||
189 | |||
190 | r = readlink(fname, linkname, sb.st_size + 1); | ||
191 | if (r < 0) { | ||
192 | free(linkname); | ||
193 | return NULL; | ||
194 | } | ||
195 | return linkname; | ||
196 | } | ||
197 | |||
198 | |||
199 | // return 1 if the file is a directory | ||
200 | int is_dir(const char *fname) { | ||
201 | assert(fname); | ||
202 | if (*fname == '\0') | ||
203 | return 0; | ||
204 | |||
205 | // if fname doesn't end in '/', add one | ||
206 | int rv; | ||
207 | struct stat s; | ||
208 | if (fname[strlen(fname) - 1] == '/') | ||
209 | rv = stat(fname, &s); | ||
210 | else { | ||
211 | char *tmp; | ||
212 | if (asprintf(&tmp, "%s/", fname) == -1) { | ||
213 | fprintf(stderr, "Error: cannot allocate memory, %s:%d\n", __FILE__, __LINE__); | ||
214 | errExit("asprintf"); | ||
215 | } | ||
216 | rv = stat(tmp, &s); | ||
217 | free(tmp); | ||
218 | } | ||
219 | |||
220 | if (rv == -1) | ||
221 | return 0; | ||
222 | |||
223 | if (S_ISDIR(s.st_mode)) | ||
224 | return 1; | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | // return 1 if the file is a link | ||
230 | int is_link(const char *fname) { | ||
231 | assert(fname); | ||
232 | if (*fname == '\0') | ||
233 | return 0; | ||
234 | |||
235 | struct stat s; | ||
236 | if (lstat(fname, &s) == 0) { | ||
237 | if (S_ISLNK(s.st_mode)) | ||
238 | return 1; | ||
239 | } | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | |||
245 | // remove multiple spaces and return allocated memory | ||
246 | char *line_remove_spaces(const char *buf) { | ||
247 | assert(buf); | ||
248 | if (strlen(buf) == 0) | ||
249 | return NULL; | ||
250 | |||
251 | // allocate memory for the new string | ||
252 | char *rv = malloc(strlen(buf) + 1); | ||
253 | if (rv == NULL) | ||
254 | errExit("malloc"); | ||
255 | |||
256 | // remove space at start of line | ||
257 | const char *ptr1 = buf; | ||
258 | while (*ptr1 == ' ' || *ptr1 == '\t') | ||
259 | ptr1++; | ||
260 | |||
261 | // copy data and remove additional spaces | ||
262 | char *ptr2 = rv; | ||
263 | int state = 0; | ||
264 | while (*ptr1 != '\0') { | ||
265 | if (*ptr1 == '\n' || *ptr1 == '\r') | ||
266 | break; | ||
267 | |||
268 | if (state == 0) { | ||
269 | if (*ptr1 != ' ' && *ptr1 != '\t') | ||
270 | *ptr2++ = *ptr1++; | ||
271 | else { | ||
272 | *ptr2++ = ' '; | ||
273 | ptr1++; | ||
274 | state = 1; | ||
275 | } | ||
276 | } | ||
277 | else { // state == 1 | ||
278 | while (*ptr1 == ' ' || *ptr1 == '\t') | ||
279 | ptr1++; | ||
280 | state = 0; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | // strip last blank character if any | ||
285 | if (*(ptr2 - 1) == ' ') | ||
286 | --ptr2; | ||
287 | *ptr2 = '\0'; | ||
288 | // if (arg_debug) | ||
289 | // printf("Processing line #%s#\n", rv); | ||
290 | |||
291 | return rv; | ||
292 | } | ||
293 | |||
294 | |||
295 | char *split_comma(char *str) { | ||
296 | if (str == NULL || *str == '\0') | ||
297 | return NULL; | ||
298 | char *ptr = strchr(str, ','); | ||
299 | if (!ptr) | ||
300 | return NULL; | ||
301 | *ptr = '\0'; | ||
302 | ptr++; | ||
303 | if (*ptr == '\0') | ||
304 | return NULL; | ||
305 | return ptr; | ||
306 | } | ||
307 | |||
308 | |||
309 | int not_unsigned(const char *str) { | ||
310 | int rv = 0; | ||
311 | const char *ptr = str; | ||
312 | while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0') { | ||
313 | if (!isdigit(*ptr)) { | ||
314 | rv = 1; | ||
315 | break; | ||
316 | } | ||
317 | ptr++; | ||
318 | } | ||
319 | |||
320 | return rv; | ||
321 | } | ||
322 | |||
323 | |||
324 | #define BUFLEN 4096 | ||
325 | // find the first child for this parent; return 1 if error | ||
326 | int find_child(pid_t parent, pid_t *child) { | ||
327 | *child = 0; // use it to flag a found child | ||
328 | |||
329 | DIR *dir; | ||
330 | if (!(dir = opendir("/proc"))) { | ||
331 | // sleep 2 seconds and try again | ||
332 | sleep(2); | ||
333 | if (!(dir = opendir("/proc"))) { | ||
334 | fprintf(stderr, "Error: cannot open /proc directory\n"); | ||
335 | exit(1); | ||
336 | } | ||
337 | } | ||
338 | |||
339 | struct dirent *entry; | ||
340 | char *end; | ||
341 | while (*child == 0 && (entry = readdir(dir))) { | ||
342 | pid_t pid = strtol(entry->d_name, &end, 10); | ||
343 | if (end == entry->d_name || *end) | ||
344 | continue; | ||
345 | if (pid == parent) | ||
346 | continue; | ||
347 | |||
348 | // open stat file | ||
349 | char *file; | ||
350 | if (asprintf(&file, "/proc/%u/status", pid) == -1) { | ||
351 | perror("asprintf"); | ||
352 | exit(1); | ||
353 | } | ||
354 | FILE *fp = fopen(file, "r"); | ||
355 | if (!fp) { | ||
356 | free(file); | ||
357 | continue; | ||
358 | } | ||
359 | |||
360 | // look for firejail executable name | ||
361 | char buf[BUFLEN]; | ||
362 | while (fgets(buf, BUFLEN - 1, fp)) { | ||
363 | if (strncmp(buf, "PPid:", 5) == 0) { | ||
364 | char *ptr = buf + 5; | ||
365 | while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) { | ||
366 | ptr++; | ||
367 | } | ||
368 | if (*ptr == '\0') { | ||
369 | fprintf(stderr, "Error: cannot read /proc file\n"); | ||
370 | exit(1); | ||
371 | } | ||
372 | if (parent == atoi(ptr)) | ||
373 | *child = pid; | ||
374 | break; // stop reading the file | ||
375 | } | ||
376 | } | ||
377 | fclose(fp); | ||
378 | free(file); | ||
379 | } | ||
380 | closedir(dir); | ||
381 | |||
382 | return (*child)? 0:1; // 0 = found, 1 = not found | ||
383 | } | ||
384 | |||
385 | |||
386 | |||
387 | void extract_command_name(const char *str) { | ||
388 | assert(str); | ||
389 | cfg.command_name = strdup(str); | ||
390 | if (!cfg.command_name) | ||
391 | errExit("strdup"); | ||
392 | |||
393 | // restrict the command name to the first word | ||
394 | char *ptr = cfg.command_name; | ||
395 | while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0') | ||
396 | ptr++; | ||
397 | *ptr = '\0'; | ||
398 | |||
399 | // remove the path: /usr/bin/firefox becomes firefox | ||
400 | ptr = strrchr(cfg.command_name, '/'); | ||
401 | if (ptr) { | ||
402 | ptr++; | ||
403 | if (*ptr == '\0') { | ||
404 | fprintf(stderr, "Error: invalid command name\n"); | ||
405 | exit(1); | ||
406 | } | ||
407 | |||
408 | char *tmp = strdup(ptr); | ||
409 | if (!tmp) | ||
410 | errExit("strdup"); | ||
411 | free(cfg.command_name); | ||
412 | cfg.command_name = tmp; | ||
413 | } | ||
414 | } | ||
415 | |||
416 | |||
417 | void update_map(char *mapping, char *map_file) { | ||
418 | int fd, j; | ||
419 | size_t map_len; /* Length of 'mapping' */ | ||
420 | |||
421 | /* Replace commas in mapping string with newlines */ | ||
422 | |||
423 | map_len = strlen(mapping); | ||
424 | for (j = 0; j < map_len; j++) | ||
425 | if (mapping[j] == ',') | ||
426 | mapping[j] = '\n'; | ||
427 | |||
428 | fd = open(map_file, O_RDWR); | ||
429 | if (fd == -1) { | ||
430 | fprintf(stderr, "Error: cannot open %s: %s\n", map_file, strerror(errno)); | ||
431 | exit(EXIT_FAILURE); | ||
432 | } | ||
433 | |||
434 | if (write(fd, mapping, map_len) != map_len) { | ||
435 | fprintf(stderr, "Error: cannot write to %s: %s\n", map_file, strerror(errno)); | ||
436 | exit(EXIT_FAILURE); | ||
437 | } | ||
438 | |||
439 | close(fd); | ||
440 | } | ||
441 | |||
442 | |||
443 | void wait_for_other(int fd) { | ||
444 | //**************************** | ||
445 | // wait for the parent to be initialized | ||
446 | //**************************** | ||
447 | char childstr[BUFLEN + 1]; | ||
448 | int newfd = dup(fd); | ||
449 | if (newfd == -1) | ||
450 | errExit("dup"); | ||
451 | FILE* stream; | ||
452 | stream = fdopen(newfd, "r"); | ||
453 | *childstr = '\0'; | ||
454 | if (fgets(childstr, BUFLEN, stream)) { | ||
455 | // remove \n) | ||
456 | char *ptr = childstr; | ||
457 | while(*ptr !='\0' && *ptr != '\n') | ||
458 | ptr++; | ||
459 | if (*ptr == '\0') | ||
460 | errExit("fgets"); | ||
461 | *ptr = '\0'; | ||
462 | } | ||
463 | else { | ||
464 | fprintf(stderr, "Error: cannot establish communication with the parent, exiting...\n"); | ||
465 | exit(1); | ||
466 | } | ||
467 | fclose(stream); | ||
468 | } | ||
469 | |||
470 | |||
471 | void notify_other(int fd) { | ||
472 | FILE* stream; | ||
473 | int newfd = dup(fd); | ||
474 | if (newfd == -1) | ||
475 | errExit("dup"); | ||
476 | stream = fdopen(newfd, "w"); | ||
477 | fprintf(stream, "%u\n", getpid()); | ||
478 | fflush(stream); | ||
479 | fclose(stream); | ||
480 | } | ||
diff --git a/src/firejail/veth.c b/src/firejail/veth.c new file mode 100644 index 000000000..ecc31f18d --- /dev/null +++ b/src/firejail/veth.c | |||
@@ -0,0 +1,191 @@ | |||
1 | /* code based on iproute2 ip/iplink.c, modified to be included in firejail project | ||
2 | * | ||
3 | * Original source code: | ||
4 | * | ||
5 | * Information: | ||
6 | * http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2 | ||
7 | * | ||
8 | * Download: | ||
9 | * http://www.kernel.org/pub/linux/utils/net/iproute2/ | ||
10 | * | ||
11 | * Repository: | ||
12 | * git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git | ||
13 | * | ||
14 | * License: GPL v2 | ||
15 | * | ||
16 | * Original copyright header | ||
17 | * | ||
18 | * iplink.c "ip link". | ||
19 | * | ||
20 | * This program is free software; you can redistribute it and/or | ||
21 | * modify it under the terms of the GNU General Public License | ||
22 | * as published by the Free Software Foundation; either version | ||
23 | * 2 of the License, or (at your option) any later version. | ||
24 | * | ||
25 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | ||
26 | * | ||
27 | */ | ||
28 | /* | ||
29 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
30 | * | ||
31 | * This file is part of firejail project | ||
32 | * | ||
33 | * This program is free software; you can redistribute it and/or modify | ||
34 | * it under the terms of the GNU General Public License as published by | ||
35 | * the Free Software Foundation; either version 2 of the License, or | ||
36 | * (at your option) any later version. | ||
37 | * | ||
38 | * This program is distributed in the hope that it will be useful, | ||
39 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
40 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
41 | * GNU General Public License for more details. | ||
42 | * | ||
43 | * You should have received a copy of the GNU General Public License along | ||
44 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
45 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
46 | */ | ||
47 | |||
48 | #include "firejail.h" | ||
49 | #include "../include/libnetlink.h" | ||
50 | #include <linux/veth.h> | ||
51 | |||
52 | struct iplink_req | ||
53 | { | ||
54 | struct nlmsghdr n; | ||
55 | struct ifinfomsg i; | ||
56 | char buf[1024]; | ||
57 | }; | ||
58 | |||
59 | static struct rtnl_handle rth = { .fd = -1 }; | ||
60 | |||
61 | int net_create_veth(const char *dev, const char *nsdev, unsigned pid) { | ||
62 | int len; | ||
63 | struct iplink_req req; | ||
64 | |||
65 | if (arg_debug) | ||
66 | printf("create veth %s/%s/%u\n", dev, nsdev, pid); | ||
67 | assert(dev); | ||
68 | assert(nsdev); | ||
69 | assert(pid); | ||
70 | |||
71 | if (rtnl_open(&rth, 0) < 0) { | ||
72 | fprintf(stderr, "cannot open netlink\n"); | ||
73 | exit(1); | ||
74 | } | ||
75 | |||
76 | memset(&req, 0, sizeof(req)); | ||
77 | |||
78 | req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); | ||
79 | req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; | ||
80 | req.n.nlmsg_type = RTM_NEWLINK; | ||
81 | req.i.ifi_family = 0; | ||
82 | |||
83 | if (dev) { | ||
84 | len = strlen(dev) + 1; | ||
85 | addattr_l(&req.n, sizeof(req), IFLA_IFNAME, dev, len); | ||
86 | } | ||
87 | |||
88 | struct rtattr *linkinfo = NLMSG_TAIL(&req.n); | ||
89 | addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); | ||
90 | addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, "veth", strlen("veth")); | ||
91 | |||
92 | struct rtattr * data = NLMSG_TAIL(&req.n); | ||
93 | addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); | ||
94 | |||
95 | struct rtattr * peerdata = NLMSG_TAIL(&req.n); | ||
96 | addattr_l (&req.n, sizeof(req), VETH_INFO_PEER, NULL, 0); | ||
97 | req.n.nlmsg_len += sizeof(struct ifinfomsg); | ||
98 | |||
99 | // place the link in the child namespace | ||
100 | addattr_l (&req.n, sizeof(req), IFLA_NET_NS_PID, &pid, 4); | ||
101 | |||
102 | if (nsdev) { | ||
103 | int len = strlen(nsdev) + 1; | ||
104 | addattr_l(&req.n, sizeof(req), IFLA_IFNAME, nsdev, len); | ||
105 | } | ||
106 | peerdata->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)peerdata; | ||
107 | |||
108 | data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; | ||
109 | linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; | ||
110 | |||
111 | // send message | ||
112 | if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) | ||
113 | exit(2); | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | |||
119 | int net_create_macvlan(const char *dev, const char *parent, unsigned pid) { | ||
120 | int len; | ||
121 | struct iplink_req req; | ||
122 | if (arg_debug) | ||
123 | printf("create macvlan %s, parent %s\n", dev, parent); | ||
124 | assert(dev); | ||
125 | assert(parent); | ||
126 | |||
127 | if (rtnl_open(&rth, 0) < 0) { | ||
128 | fprintf(stderr, "cannot open netlink\n"); | ||
129 | exit(1); | ||
130 | } | ||
131 | |||
132 | memset(&req, 0, sizeof(req)); | ||
133 | |||
134 | req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); | ||
135 | req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; | ||
136 | req.n.nlmsg_type = RTM_NEWLINK; | ||
137 | req.i.ifi_family = 0; | ||
138 | |||
139 | // we start with the parent | ||
140 | int parent_ifindex = 2; | ||
141 | addattr_l(&req.n, sizeof(req), IFLA_LINK, &parent_ifindex, 4); | ||
142 | |||
143 | // add new interface name | ||
144 | len = strlen(dev) + 1; | ||
145 | addattr_l(&req.n, sizeof(req), IFLA_IFNAME, dev, len); | ||
146 | |||
147 | // place the interface in child namespace | ||
148 | addattr_l (&req.n, sizeof(req), IFLA_NET_NS_PID, &pid, 4); | ||
149 | |||
150 | |||
151 | // add link info for the new interface | ||
152 | struct rtattr *linkinfo = NLMSG_TAIL(&req.n); | ||
153 | addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); | ||
154 | addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, "macvlan", strlen("macvlan")); | ||
155 | |||
156 | // set macvlan bridge mode | ||
157 | struct rtattr * data = NLMSG_TAIL(&req.n); | ||
158 | addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); | ||
159 | int macvlan_type = MACVLAN_MODE_BRIDGE; | ||
160 | addattr_l (&req.n, sizeof(req), IFLA_INFO_KIND, &macvlan_type, 4); | ||
161 | |||
162 | data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; | ||
163 | // req.n.nlmsg_len += sizeof(struct ifinfomsg); | ||
164 | |||
165 | |||
166 | data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; | ||
167 | linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; | ||
168 | |||
169 | // send message | ||
170 | if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) | ||
171 | exit(2); | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | int main(int argc, char **argv) { | ||
178 | printf("Hello\n"); | ||
179 | |||
180 | |||
181 | char *dev = argv[3]; | ||
182 | char *nsdev = argv[8]; | ||
183 | unsigned pid; | ||
184 | sscanf(argv[10], "%u", &pid); | ||
185 | |||
186 | |||
187 | net_create_veth(dev, nsdev, pid); | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | */ \ No newline at end of file | ||
diff --git a/src/firemon/Makefile.in b/src/firemon/Makefile.in new file mode 100644 index 000000000..425289695 --- /dev/null +++ b/src/firemon/Makefile.in | |||
@@ -0,0 +1,24 @@ | |||
1 | all: firemon | ||
2 | |||
3 | PREFIX=@prefix@ | ||
4 | VERSION=@PACKAGE_VERSION@ | ||
5 | NAME=@PACKAGE_NAME@ | ||
6 | |||
7 | H_FILE_LIST = $(wildcard *.[h]) | ||
8 | C_FILE_LIST = $(wildcard *.c) | ||
9 | OBJS = $(C_FILE_LIST:.c=.o) | ||
10 | BINOBJS = $(foreach file, $(OBJS), $file) | ||
11 | CFLAGS += -ggdb -O2 -DVERSION='"$(VERSION)"' -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security | ||
12 | LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now | ||
13 | |||
14 | %.o : %.c $(H_FILE_LIST) | ||
15 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ | ||
16 | |||
17 | firemon: $(OBJS) ../lib/common.o ../lib/pid.o | ||
18 | $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/common.o ../lib/pid.o $(LIBS) | ||
19 | |||
20 | clean:; rm -f *.o firemon | ||
21 | |||
22 | distclean: clean | ||
23 | rm -fr Makefile | ||
24 | |||
diff --git a/src/firemon/arp.c b/src/firemon/arp.c new file mode 100644 index 000000000..71beb0630 --- /dev/null +++ b/src/firemon/arp.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 "firemon.h" | ||
21 | #define MAXBUF 4096 | ||
22 | |||
23 | static void print_arp(const char *fname) { | ||
24 | FILE *fp = fopen(fname, "r"); | ||
25 | if (!fp) | ||
26 | return; | ||
27 | |||
28 | printf(" ARP Table:\n"); | ||
29 | char buf[MAXBUF]; | ||
30 | while (fgets(buf, MAXBUF, fp)) { | ||
31 | // remove blanks, \n | ||
32 | char *ptr = buf; | ||
33 | while (*ptr == ' ' || *ptr == '\t') | ||
34 | ptr++; | ||
35 | char *start = ptr; | ||
36 | if (*start == '\0') | ||
37 | continue; | ||
38 | ptr = strchr(ptr, '\n'); | ||
39 | if (ptr) | ||
40 | *ptr = '\0'; | ||
41 | |||
42 | // remove table header | ||
43 | //IP address HW type Flags HW address Mask Device | ||
44 | if (strncmp(start, "IP address", 10) == 0) | ||
45 | continue; | ||
46 | |||
47 | // extract data | ||
48 | char ip[64]; | ||
49 | char type[64]; | ||
50 | char flags[64]; | ||
51 | char mac[64]; | ||
52 | char mask[64]; | ||
53 | char device[64]; | ||
54 | int rv = sscanf(start, "%s %s %s %s %s %s\n", ip, type, flags, mac, mask, device); | ||
55 | if (rv != 6) | ||
56 | continue; | ||
57 | |||
58 | // destination ip | ||
59 | unsigned a, b, c, d; | ||
60 | if (sscanf(ip, "%u.%u.%u.%u", &a, &b, &c, &d) != 4 || a > 255 || b > 255 || c > 255 || d > 255) | ||
61 | continue; | ||
62 | uint32_t destip = a * 0x1000000 + b * 0x10000 + c * 0x100 + d; | ||
63 | if (strcmp(flags, "0x0") == 0) | ||
64 | printf(" %d.%d.%d.%d dev %s FAILED\n", | ||
65 | PRINT_IP(destip), device); | ||
66 | else | ||
67 | printf(" %d.%d.%d.%d dev %s lladdr %s REACHABLE\n", | ||
68 | PRINT_IP(destip), device, mac); | ||
69 | } | ||
70 | |||
71 | fclose(fp); | ||
72 | |||
73 | } | ||
74 | |||
75 | void arp(pid_t pid) { | ||
76 | if (getuid() == 0) | ||
77 | firemon_drop_privs(); | ||
78 | |||
79 | pid_read(pid); | ||
80 | |||
81 | // print processes | ||
82 | int i; | ||
83 | for (i = 0; i < max_pids; i++) { | ||
84 | if (pids[i].level == 1) { | ||
85 | pid_print_list(i, 0); | ||
86 | int child = find_child(i); | ||
87 | if (child != -1) { | ||
88 | char *fname; | ||
89 | if (asprintf(&fname, "/proc/%d/net/arp", child) == -1) | ||
90 | errExit("asprintf"); | ||
91 | print_arp(fname); | ||
92 | free(fname); | ||
93 | printf("\n"); | ||
94 | } | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | |||
99 | |||
diff --git a/src/firemon/caps.c b/src/firemon/caps.c new file mode 100644 index 000000000..4ae9ab28d --- /dev/null +++ b/src/firemon/caps.c | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 "firemon.h" | ||
21 | #define MAXBUF 4098 | ||
22 | |||
23 | static void print_caps(int pid) { | ||
24 | char *file; | ||
25 | if (asprintf(&file, "/proc/%d/status", pid) == -1) { | ||
26 | errExit("asprintf"); | ||
27 | exit(1); | ||
28 | } | ||
29 | |||
30 | FILE *fp = fopen(file, "r"); | ||
31 | if (!fp) { | ||
32 | printf(" Error: cannot open %s\n", file); | ||
33 | free(file); | ||
34 | return; | ||
35 | } | ||
36 | |||
37 | char buf[MAXBUF]; | ||
38 | while (fgets(buf, MAXBUF, fp)) { | ||
39 | if (strncmp(buf, "CapBnd:", 7) == 0) { | ||
40 | printf(" %s", buf); | ||
41 | fflush(0); | ||
42 | free(file); | ||
43 | fclose(fp); | ||
44 | return; | ||
45 | } | ||
46 | } | ||
47 | fclose(fp); | ||
48 | free(file); | ||
49 | } | ||
50 | |||
51 | void caps(pid_t pid) { | ||
52 | if (getuid() == 0) | ||
53 | firemon_drop_privs(); | ||
54 | |||
55 | pid_read(pid); // include all processes | ||
56 | |||
57 | // print processes | ||
58 | int i; | ||
59 | for (i = 0; i < max_pids; i++) { | ||
60 | if (pids[i].level == 1) { | ||
61 | pid_print_list(i, 0); | ||
62 | int child = find_child(i); | ||
63 | if (child != -1) | ||
64 | print_caps(child); | ||
65 | } | ||
66 | } | ||
67 | printf("\n"); | ||
68 | } | ||
69 | |||
diff --git a/src/firemon/cgroup.c b/src/firemon/cgroup.c new file mode 100644 index 000000000..214aefaf9 --- /dev/null +++ b/src/firemon/cgroup.c | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 "firemon.h" | ||
21 | #define MAXBUF 4098 | ||
22 | |||
23 | static void print_cgroup(int pid) { | ||
24 | char *file; | ||
25 | if (asprintf(&file, "/proc/%d/cgroup", pid) == -1) { | ||
26 | errExit("asprintf"); | ||
27 | exit(1); | ||
28 | } | ||
29 | |||
30 | FILE *fp = fopen(file, "r"); | ||
31 | if (!fp) { | ||
32 | printf(" Error: cannot open %s\n", file); | ||
33 | free(file); | ||
34 | return; | ||
35 | } | ||
36 | |||
37 | char buf[MAXBUF]; | ||
38 | if (fgets(buf, MAXBUF, fp)) { | ||
39 | printf(" %s", buf); | ||
40 | fflush(0); | ||
41 | } | ||
42 | |||
43 | fclose(fp); | ||
44 | free(file); | ||
45 | } | ||
46 | |||
47 | void cgroup(pid_t pid) { | ||
48 | if (getuid() == 0) | ||
49 | firemon_drop_privs(); | ||
50 | |||
51 | pid_read(pid); | ||
52 | |||
53 | // print processes | ||
54 | int i; | ||
55 | for (i = 0; i < max_pids; i++) { | ||
56 | if (pids[i].level == 1) { | ||
57 | pid_print_list(i, 0); | ||
58 | int child = find_child(i); | ||
59 | if (child != -1) | ||
60 | print_cgroup(child); | ||
61 | } | ||
62 | } | ||
63 | } | ||
64 | |||
diff --git a/src/firemon/cpu.c b/src/firemon/cpu.c new file mode 100644 index 000000000..d5d20d1b8 --- /dev/null +++ b/src/firemon/cpu.c | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 "firemon.h" | ||
21 | #define MAXBUF 4098 | ||
22 | |||
23 | static void print_cpu(int pid) { | ||
24 | char *file; | ||
25 | if (asprintf(&file, "/proc/%d/status", pid) == -1) { | ||
26 | errExit("asprintf"); | ||
27 | exit(1); | ||
28 | } | ||
29 | |||
30 | FILE *fp = fopen(file, "r"); | ||
31 | if (!fp) { | ||
32 | printf(" Error: cannot open %s\n", file); | ||
33 | free(file); | ||
34 | return; | ||
35 | } | ||
36 | |||
37 | char buf[MAXBUF]; | ||
38 | while (fgets(buf, MAXBUF, fp)) { | ||
39 | if (strncmp(buf, "Cpus_allowed_list:", 18) == 0) { | ||
40 | printf(" %s", buf); | ||
41 | fflush(0); | ||
42 | free(file); | ||
43 | fclose(fp); | ||
44 | return; | ||
45 | } | ||
46 | } | ||
47 | fclose(fp); | ||
48 | free(file); | ||
49 | } | ||
50 | |||
51 | void cpu(pid_t pid) { | ||
52 | if (getuid() == 0) | ||
53 | firemon_drop_privs(); | ||
54 | |||
55 | pid_read(pid); | ||
56 | |||
57 | // print processes | ||
58 | int i; | ||
59 | for (i = 0; i < max_pids; i++) { | ||
60 | if (pids[i].level == 1) { | ||
61 | pid_print_list(i, 0); | ||
62 | int child = find_child(i); | ||
63 | if (child != -1) | ||
64 | print_cpu(child); | ||
65 | } | ||
66 | } | ||
67 | } | ||
68 | |||
diff --git a/src/firemon/firemon.c b/src/firemon/firemon.c new file mode 100644 index 000000000..d77d11a7a --- /dev/null +++ b/src/firemon/firemon.c | |||
@@ -0,0 +1,222 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 "firemon.h" | ||
21 | #include <signal.h> | ||
22 | #include <termios.h> | ||
23 | #include <sys/ioctl.h> | ||
24 | #include <sys/prctl.h> | ||
25 | #include <grp.h> | ||
26 | |||
27 | |||
28 | static int arg_route = 0; | ||
29 | static int arg_arp = 0; | ||
30 | static int arg_tree = 0; | ||
31 | static int arg_interface = 0; | ||
32 | static int arg_seccomp = 0; | ||
33 | static int arg_caps = 0; | ||
34 | static int arg_cpu = 0; | ||
35 | static int arg_cgroup = 0; | ||
36 | int arg_nowrap = 0; | ||
37 | |||
38 | static struct termios tlocal; // startup terminal setting | ||
39 | static struct termios twait; // no wait on key press | ||
40 | static int terminal_set = 0; | ||
41 | |||
42 | static void my_handler(int s){ | ||
43 | if (terminal_set) | ||
44 | tcsetattr(0, TCSANOW, &tlocal); | ||
45 | exit(0); | ||
46 | } | ||
47 | |||
48 | // find the first child process for the specified pid | ||
49 | // return -1 if not found | ||
50 | int find_child(int id) { | ||
51 | int i; | ||
52 | for (i = 0; i < max_pids; i++) { | ||
53 | if (pids[i].level == 2 && pids[i].parent == id) | ||
54 | return i; | ||
55 | } | ||
56 | |||
57 | return -1; | ||
58 | } | ||
59 | |||
60 | // drop privileges | ||
61 | void firemon_drop_privs(void) { | ||
62 | // drop privileges | ||
63 | if (setgroups(0, NULL) < 0) | ||
64 | errExit("setgroups"); | ||
65 | if (setgid(getgid()) < 0) | ||
66 | errExit("setgid/getgid"); | ||
67 | if (setuid(getuid()) < 0) | ||
68 | errExit("setuid/getuid"); | ||
69 | } | ||
70 | |||
71 | // sleep and wait for a key to be pressed | ||
72 | void firemon_sleep(int st) { | ||
73 | if (terminal_set == 0) { | ||
74 | tcgetattr(0, &twait); // get current terminal attirbutes; 0 is the file descriptor for stdin | ||
75 | memcpy(&tlocal, &twait, sizeof(tlocal)); | ||
76 | twait.c_lflag &= ~ICANON; // disable canonical mode | ||
77 | twait.c_lflag &= ~ECHO; // no echo | ||
78 | twait.c_cc[VMIN] = 1; // wait until at least one keystroke available | ||
79 | twait.c_cc[VTIME] = 0; // no timeout | ||
80 | terminal_set = 1; | ||
81 | } | ||
82 | tcsetattr(0, TCSANOW, &twait); | ||
83 | |||
84 | |||
85 | fd_set fds; | ||
86 | FD_ZERO(&fds); | ||
87 | FD_SET(0,&fds); | ||
88 | int maxfd = 1; | ||
89 | |||
90 | struct timeval ts; | ||
91 | ts.tv_sec = st; | ||
92 | ts.tv_usec = 0; | ||
93 | |||
94 | int ready = select(maxfd, &fds, (fd_set *) 0, (fd_set *) 0, &ts); | ||
95 | (void) ready; | ||
96 | if( FD_ISSET(0, &fds)) { | ||
97 | getchar(); | ||
98 | tcsetattr(0, TCSANOW, &tlocal); | ||
99 | printf("\n"); | ||
100 | exit(0); | ||
101 | } | ||
102 | tcsetattr(0, TCSANOW, &tlocal); | ||
103 | } | ||
104 | |||
105 | |||
106 | int main(int argc, char **argv) { | ||
107 | unsigned pid = 0; | ||
108 | int i; | ||
109 | |||
110 | // handle CTRL-C | ||
111 | signal (SIGINT, my_handler); | ||
112 | signal (SIGTERM, my_handler); | ||
113 | |||
114 | for (i = 1; i < argc; i++) { | ||
115 | // default options | ||
116 | if (strcmp(argv[i], "--help") == 0 || | ||
117 | strcmp(argv[i], "-?") == 0) { | ||
118 | usage(); | ||
119 | return 0; | ||
120 | } | ||
121 | else if (strcmp(argv[i], "--version") == 0) { | ||
122 | printf("firemon version %s\n\n", VERSION); | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | // options without a pid argument | ||
127 | else if (strcmp(argv[i], "--top") == 0) { | ||
128 | top(); // never to return | ||
129 | } | ||
130 | else if (strcmp(argv[i], "--list") == 0) { | ||
131 | list(); | ||
132 | return 0; | ||
133 | } | ||
134 | else if (strcmp(argv[i], "--netstats") == 0) { | ||
135 | netstats(); | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | |||
140 | // cumulative options with or without a pid argument | ||
141 | else if (strcmp(argv[i], "--cgroup") == 0) { | ||
142 | arg_cgroup = 1; | ||
143 | } | ||
144 | else if (strcmp(argv[i], "--cpu") == 0) { | ||
145 | arg_cpu = 1; | ||
146 | } | ||
147 | else if (strcmp(argv[i], "--seccomp") == 0) { | ||
148 | arg_seccomp = 1; | ||
149 | } | ||
150 | else if (strcmp(argv[i], "--caps") == 0) { | ||
151 | arg_caps = 1; | ||
152 | } | ||
153 | else if (strcmp(argv[i], "--tree") == 0) { | ||
154 | arg_tree = 1; | ||
155 | } | ||
156 | else if (strcmp(argv[i], "--interface") == 0) { | ||
157 | arg_interface = 1; | ||
158 | } | ||
159 | else if (strcmp(argv[i], "--route") == 0) { | ||
160 | arg_route = 1; | ||
161 | } | ||
162 | else if (strcmp(argv[i], "--arp") == 0) { | ||
163 | arg_arp = 1; | ||
164 | } | ||
165 | |||
166 | else if (strncmp(argv[i], "--name=", 7) == 0) { | ||
167 | char *name = argv[i] + 7; | ||
168 | if (name2pid(name, (pid_t *) &pid)) { | ||
169 | fprintf(stderr, "Error: cannot find sandbox %s\n", name); | ||
170 | return 1; | ||
171 | } | ||
172 | } | ||
173 | |||
174 | // etc | ||
175 | else if (strcmp(argv[i], "--nowrap") == 0) | ||
176 | arg_nowrap = 1; | ||
177 | |||
178 | // invalid option | ||
179 | else if (*argv[i] == '-') { | ||
180 | fprintf(stderr, "Error: invalid option\n"); | ||
181 | return 1; | ||
182 | } | ||
183 | |||
184 | // PID argument | ||
185 | else { | ||
186 | // this should be a pid number | ||
187 | char *ptr = argv[i]; | ||
188 | while (*ptr != '\0') { | ||
189 | if (!isdigit(*ptr)) { | ||
190 | fprintf(stderr, "Error: not a valid PID number\n"); | ||
191 | exit(1); | ||
192 | } | ||
193 | ptr++; | ||
194 | } | ||
195 | |||
196 | sscanf(argv[i], "%u", &pid); | ||
197 | break; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | if (arg_tree) | ||
202 | tree((pid_t) pid); | ||
203 | if (arg_interface) | ||
204 | interface((pid_t) pid); | ||
205 | if (arg_route) | ||
206 | route((pid_t) pid); | ||
207 | if (arg_arp) | ||
208 | arp((pid_t) pid); | ||
209 | if (arg_seccomp) | ||
210 | seccomp((pid_t) pid); | ||
211 | if (arg_caps) | ||
212 | caps((pid_t) pid); | ||
213 | if (arg_cpu) | ||
214 | cpu((pid_t) pid); | ||
215 | if (arg_cgroup) | ||
216 | cgroup((pid_t) pid); | ||
217 | |||
218 | if (!arg_route && !arg_arp && !arg_interface && !arg_tree && !arg_caps && !arg_seccomp) | ||
219 | procevent((pid_t) pid); // never to return | ||
220 | |||
221 | return 0; | ||
222 | } | ||
diff --git a/src/firemon/firemon.h b/src/firemon/firemon.h new file mode 100644 index 000000000..59b1f352c --- /dev/null +++ b/src/firemon/firemon.h | |||
@@ -0,0 +1,84 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 | #ifndef FIREMON_H | ||
21 | #define FIREMON_H | ||
22 | #define _GNU_SOURCE | ||
23 | #include <stdlib.h> | ||
24 | #include <stdio.h> | ||
25 | #include <ctype.h> | ||
26 | #include <string.h> | ||
27 | #include <errno.h> | ||
28 | #include <stdint.h> | ||
29 | #include "../include/pid.h" | ||
30 | #include "../include/common.h" | ||
31 | |||
32 | // clear screen | ||
33 | static inline void firemon_clrscr(void) { | ||
34 | printf("\033[2J\033[1;1H"); | ||
35 | fflush(0); | ||
36 | } | ||
37 | |||
38 | // firemon.c | ||
39 | extern int arg_nowrap; | ||
40 | int find_child(int id); | ||
41 | void firemon_drop_privs(void); | ||
42 | void firemon_sleep(int st); | ||
43 | |||
44 | |||
45 | // procevent.c | ||
46 | void procevent(pid_t pid); | ||
47 | |||
48 | // usage.c | ||
49 | void usage(void); | ||
50 | |||
51 | // top.c | ||
52 | void top(void); | ||
53 | |||
54 | // list.c | ||
55 | void list(void); | ||
56 | |||
57 | // interface.c | ||
58 | void interface(pid_t pid); | ||
59 | |||
60 | // arp.c | ||
61 | void arp(pid_t pid); | ||
62 | |||
63 | // route.c | ||
64 | void route(pid_t pid); | ||
65 | |||
66 | // caps.c | ||
67 | void caps(pid_t pid); | ||
68 | |||
69 | // seccomp.c | ||
70 | void seccomp(pid_t pid); | ||
71 | |||
72 | // cpu.c | ||
73 | void cpu(pid_t pid); | ||
74 | |||
75 | // cgroup.c | ||
76 | void cgroup(pid_t pid); | ||
77 | |||
78 | // tree.c | ||
79 | void tree(pid_t pid); | ||
80 | |||
81 | // netstats.c | ||
82 | void netstats(void); | ||
83 | |||
84 | #endif | ||
diff --git a/src/firemon/interface.c b/src/firemon/interface.c new file mode 100644 index 000000000..52a9c33cd --- /dev/null +++ b/src/firemon/interface.c | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 "firemon.h" | ||
21 | #include <sys/types.h> | ||
22 | #include <sys/wait.h> | ||
23 | #include <netdb.h> | ||
24 | #include <arpa/inet.h> | ||
25 | #include <ifaddrs.h> | ||
26 | #include <net/if.h> | ||
27 | #include <linux/connector.h> | ||
28 | #include <linux/netlink.h> | ||
29 | #include <linux/if_link.h> | ||
30 | #include <linux/sockios.h> | ||
31 | #include <sys/ioctl.h> | ||
32 | |||
33 | //#include <net/route.h> | ||
34 | //#include <linux/if_bridge.h> | ||
35 | |||
36 | // print IP addresses for all interfaces | ||
37 | static void net_ifprint(void) { | ||
38 | uint32_t ip; | ||
39 | uint32_t mask; | ||
40 | struct ifaddrs *ifaddr, *ifa; | ||
41 | |||
42 | int fd; | ||
43 | if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { | ||
44 | fprintf(stderr, "Error: cannot open AF_INET socket\n"); | ||
45 | exit(1); | ||
46 | } | ||
47 | |||
48 | if (getifaddrs(&ifaddr) == -1) | ||
49 | errExit("getifaddrs"); | ||
50 | |||
51 | // walk through the linked list | ||
52 | printf(" Link status:\n"); | ||
53 | for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { | ||
54 | if (ifa->ifa_addr == NULL) | ||
55 | continue; | ||
56 | |||
57 | if (ifa->ifa_addr->sa_family == AF_PACKET) { | ||
58 | if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP) { | ||
59 | if (ifa->ifa_data != NULL) { | ||
60 | struct rtnl_link_stats *stats = ifa->ifa_data; | ||
61 | |||
62 | // extract mac address | ||
63 | struct ifreq ifr; | ||
64 | memset(&ifr, 0, sizeof(ifr)); | ||
65 | strncpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ); | ||
66 | int rv = ioctl (fd, SIOCGIFHWADDR, &ifr); | ||
67 | |||
68 | if (rv == 0) | ||
69 | printf(" %s UP, %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
70 | ifa->ifa_name, PRINT_MAC((unsigned char *) &ifr.ifr_hwaddr.sa_data)); | ||
71 | else | ||
72 | printf(" %s UP\n", ifa->ifa_name); | ||
73 | |||
74 | printf(" tx/rx: %u/%u packets, %u/%u bytes\n", | ||
75 | stats->tx_packets, stats->rx_packets, | ||
76 | stats->tx_bytes, stats->rx_bytes); | ||
77 | } | ||
78 | } | ||
79 | else | ||
80 | printf(" %s DOWN\n", ifa->ifa_name); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | |||
85 | // walk through the linked list | ||
86 | printf(" IPv4 status:\n"); | ||
87 | for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { | ||
88 | if (ifa->ifa_addr == NULL) | ||
89 | continue; | ||
90 | |||
91 | if (ifa->ifa_addr->sa_family == AF_INET) { | ||
92 | struct sockaddr_in *si = (struct sockaddr_in *) ifa->ifa_netmask; | ||
93 | mask = ntohl(si->sin_addr.s_addr); | ||
94 | si = (struct sockaddr_in *) ifa->ifa_addr; | ||
95 | ip = ntohl(si->sin_addr.s_addr); | ||
96 | |||
97 | char *status; | ||
98 | if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP) | ||
99 | status = "UP"; | ||
100 | else | ||
101 | status = "DOWN"; | ||
102 | |||
103 | printf(" %s %s, %d.%d.%d.%d/%u\n", | ||
104 | ifa->ifa_name, status, PRINT_IP(ip), mask2bits(mask)); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | |||
109 | // walk through the linked list | ||
110 | printf(" IPv6 status:\n"); | ||
111 | for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { | ||
112 | if (ifa->ifa_addr == NULL) | ||
113 | continue; | ||
114 | |||
115 | if (ifa->ifa_addr->sa_family == AF_INET6) { | ||
116 | char host[NI_MAXHOST]; | ||
117 | int s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), | ||
118 | host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); | ||
119 | if (s == 0) { | ||
120 | char *ptr; | ||
121 | if ((ptr = strchr(host, '%')) != NULL) | ||
122 | *ptr = '\0'; | ||
123 | char *status; | ||
124 | if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP) | ||
125 | status = "UP"; | ||
126 | else | ||
127 | status = "DOWN"; | ||
128 | |||
129 | printf(" %s %s, %s\n", ifa->ifa_name, status, host); | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | |||
134 | freeifaddrs(ifaddr); | ||
135 | close(fd); | ||
136 | } | ||
137 | |||
138 | static void print_sandbox(pid_t pid) { | ||
139 | pid_t child = fork(); | ||
140 | if (child == -1) | ||
141 | return; | ||
142 | |||
143 | if (child == 0) { | ||
144 | int rv = join_namespace(pid, "net"); | ||
145 | if (rv) | ||
146 | return; | ||
147 | net_ifprint(); | ||
148 | printf("\n"); | ||
149 | exit(0); | ||
150 | } | ||
151 | |||
152 | // wait for the child to finish | ||
153 | waitpid(child, NULL, 0); | ||
154 | } | ||
155 | |||
156 | void interface(pid_t pid) { | ||
157 | if (getuid() != 0) { | ||
158 | fprintf(stderr, "Error: you need to be root to run this command\n"); | ||
159 | exit(1); | ||
160 | } | ||
161 | |||
162 | pid_read(pid); // a pid of 0 will include all processes | ||
163 | |||
164 | // print processes | ||
165 | int i; | ||
166 | for (i = 0; i < max_pids; i++) { | ||
167 | if (pids[i].level == 1) { | ||
168 | pid_print_list(i, 0); | ||
169 | int child = find_child(i); | ||
170 | if (child != -1) { | ||
171 | print_sandbox(child); | ||
172 | } | ||
173 | } | ||
174 | } | ||
175 | } | ||
176 | |||
diff --git a/src/firemon/list.c b/src/firemon/list.c new file mode 100644 index 000000000..6a997bde1 --- /dev/null +++ b/src/firemon/list.c | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 "firemon.h" | ||
21 | |||
22 | void list(void) { | ||
23 | if (getuid() == 0) | ||
24 | firemon_drop_privs(); | ||
25 | |||
26 | pid_read(0); // include all processes | ||
27 | |||
28 | // print processes | ||
29 | int i; | ||
30 | for (i = 0; i < max_pids; i++) { | ||
31 | if (pids[i].level == 1) | ||
32 | pid_print_list(i, 0); | ||
33 | } | ||
34 | } | ||
35 | |||
diff --git a/src/firemon/netstats.c b/src/firemon/netstats.c new file mode 100644 index 000000000..6c4a767f1 --- /dev/null +++ b/src/firemon/netstats.c | |||
@@ -0,0 +1,214 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 "firemon.h" | ||
21 | #include <termios.h> | ||
22 | #include <sys/ioctl.h> | ||
23 | #include <sys/types.h> | ||
24 | #include <sys/stat.h> | ||
25 | #include <unistd.h> | ||
26 | |||
27 | #define MAXBUF 4096 | ||
28 | |||
29 | static char *get_header(void) { | ||
30 | char *rv; | ||
31 | if (asprintf(&rv, "%-5.5s %-9.9s %-10.10s %-10.10s %s", | ||
32 | "PID", "User", "RX(KB/s)", "TX(KB/s)", "Command") == -1) | ||
33 | errExit("asprintf"); | ||
34 | |||
35 | return rv; | ||
36 | } | ||
37 | |||
38 | void get_stats(int parent) { | ||
39 | // find the first child | ||
40 | int child = -1; | ||
41 | for (child = parent + 1; child < max_pids; child++) { | ||
42 | if (pids[child].parent == parent) | ||
43 | break; | ||
44 | } | ||
45 | |||
46 | if (child == -1) | ||
47 | goto errexit; | ||
48 | |||
49 | // open /proc/child/net/dev file and read rx and tx | ||
50 | char *fname; | ||
51 | if (asprintf(&fname, "/proc/%d/net/dev", child) == -1) | ||
52 | errExit("asprintf"); | ||
53 | FILE *fp = fopen(fname, "r"); | ||
54 | if (!fp) { | ||
55 | free(fname); | ||
56 | goto errexit; | ||
57 | } | ||
58 | |||
59 | char buf[MAXBUF]; | ||
60 | long long unsigned rx = 0; | ||
61 | long long unsigned tx = 0; | ||
62 | while (fgets(buf, MAXBUF, fp)) { | ||
63 | if (strncmp(buf, "Inter", 5) == 0) | ||
64 | continue; | ||
65 | if (strncmp(buf, " face", 5) == 0) | ||
66 | continue; | ||
67 | |||
68 | char *ptr = buf; | ||
69 | while (*ptr != '\0' && *ptr != ':') { | ||
70 | ptr++; | ||
71 | } | ||
72 | |||
73 | if (*ptr == '\0') { | ||
74 | fclose(fp); | ||
75 | free(fname); | ||
76 | goto errexit; | ||
77 | } | ||
78 | ptr++; | ||
79 | |||
80 | long long unsigned rxval; | ||
81 | long long unsigned txval; | ||
82 | unsigned a, b, c, d, e, f, g; | ||
83 | sscanf(ptr, "%llu %u %u %u %u %u %u %u %llu", | ||
84 | &rxval, &a, &b, &c, &d, &e, &f, &g, &txval); | ||
85 | rx += rxval; | ||
86 | tx += txval; | ||
87 | } | ||
88 | |||
89 | // store data | ||
90 | pids[parent].rx_delta = rx - pids[parent].rx; | ||
91 | pids[parent].rx = rx; | ||
92 | pids[parent].tx_delta = tx - pids[parent].tx; | ||
93 | pids[parent].tx = tx; | ||
94 | |||
95 | |||
96 | free(fname); | ||
97 | fclose(fp); | ||
98 | return; | ||
99 | |||
100 | errexit: | ||
101 | pids[parent].rx = 0; | ||
102 | pids[parent].tx = 0; | ||
103 | pids[parent].rx_delta = 0; | ||
104 | pids[parent].tx_delta = 0; | ||
105 | } | ||
106 | |||
107 | |||
108 | static void print_proc(int index, int itv, int col) { | ||
109 | // command | ||
110 | char *cmd = pid_proc_cmdline(index); | ||
111 | char *ptrcmd; | ||
112 | if (cmd == NULL) { | ||
113 | if (pids[index].zombie) | ||
114 | ptrcmd = "(zombie)"; | ||
115 | else | ||
116 | ptrcmd = ""; | ||
117 | } | ||
118 | else | ||
119 | ptrcmd = cmd; | ||
120 | // if the command doesn't have a --net= option, don't print | ||
121 | if (strstr(ptrcmd, "--net=") == NULL) { | ||
122 | if (cmd) | ||
123 | free(cmd); | ||
124 | return; | ||
125 | } | ||
126 | |||
127 | // pid | ||
128 | char pidstr[10]; | ||
129 | snprintf(pidstr, 10, "%u", index); | ||
130 | |||
131 | // user | ||
132 | char *user = pid_get_user_name(pids[index].uid); | ||
133 | char *ptruser; | ||
134 | if (user) | ||
135 | ptruser = user; | ||
136 | else | ||
137 | ptruser = ""; | ||
138 | |||
139 | |||
140 | float rx_kbps = ((float) pids[index].rx_delta / 1000) / itv; | ||
141 | char ptrrx[15]; | ||
142 | sprintf(ptrrx, "%.03f", rx_kbps); | ||
143 | |||
144 | float tx_kbps = ((float) pids[index].tx_delta / 1000) / itv; | ||
145 | char ptrtx[15]; | ||
146 | sprintf(ptrtx, "%.03f", tx_kbps); | ||
147 | |||
148 | char buf[1024 + 1]; | ||
149 | snprintf(buf, 1024, "%-5.5s %-9.9s %-10.10s %-10.10s %s", | ||
150 | pidstr, ptruser, ptrrx, ptrtx, ptrcmd); | ||
151 | if (col < 1024) | ||
152 | buf[col] = '\0'; | ||
153 | printf("%s\n", buf); | ||
154 | |||
155 | if (cmd) | ||
156 | free(cmd); | ||
157 | if (user) | ||
158 | free(user); | ||
159 | |||
160 | } | ||
161 | |||
162 | void netstats(void) { | ||
163 | if (getuid() == 0) | ||
164 | firemon_drop_privs(); | ||
165 | |||
166 | pid_read(0); // include all processes | ||
167 | |||
168 | printf("Displaying network statistics only for sandboxes using a new network namespace.\n"); | ||
169 | |||
170 | // print processes | ||
171 | while (1) { | ||
172 | // set pid table | ||
173 | int i; | ||
174 | int itv = 5; // 5 second interval | ||
175 | pid_read(0); // todo: preserve the last calculation if any, so we don't have to do get_stats() | ||
176 | |||
177 | // start rx/tx measurements | ||
178 | for (i = 0; i < max_pids; i++) { | ||
179 | if (pids[i].level == 1) | ||
180 | get_stats(i); | ||
181 | } | ||
182 | |||
183 | // wait 5 seconds | ||
184 | firemon_sleep(itv); | ||
185 | |||
186 | // grab screen size | ||
187 | struct winsize sz; | ||
188 | int row = 24; | ||
189 | int col = 80; | ||
190 | if (!ioctl(0, TIOCGWINSZ, &sz)) { | ||
191 | col = sz.ws_col; | ||
192 | row = sz.ws_row; | ||
193 | } | ||
194 | |||
195 | // start printing | ||
196 | firemon_clrscr(); | ||
197 | char *header = get_header(); | ||
198 | if (strlen(header) > col) | ||
199 | header[col] = '\0'; | ||
200 | printf("%s\n", header); | ||
201 | if (row > 0) | ||
202 | row--; | ||
203 | free(header); | ||
204 | |||
205 | // start rx/tx measurements | ||
206 | for (i = 0; i < max_pids; i++) { | ||
207 | if (pids[i].level == 1) { | ||
208 | get_stats(i); | ||
209 | print_proc(i, itv, col); | ||
210 | } | ||
211 | } | ||
212 | } | ||
213 | } | ||
214 | |||
diff --git a/src/firemon/procevent.c b/src/firemon/procevent.c new file mode 100644 index 000000000..d2b5f7bbf --- /dev/null +++ b/src/firemon/procevent.c | |||
@@ -0,0 +1,377 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 "firemon.h" | ||
21 | #include <sys/socket.h> | ||
22 | #include <linux/connector.h> | ||
23 | #include <linux/netlink.h> | ||
24 | #include <linux/cn_proc.h> | ||
25 | #include <sys/types.h> | ||
26 | #include <sys/stat.h> | ||
27 | #include <unistd.h> | ||
28 | #include <arpa/inet.h> | ||
29 | #include <time.h> | ||
30 | #define PIDS_BUFLEN 4096 | ||
31 | #define SERVER_PORT 889 // 889-899 is left unassigned by IANA | ||
32 | |||
33 | static int pid_is_firejail(pid_t pid) { | ||
34 | uid_t rv = 0; | ||
35 | |||
36 | // open stat file | ||
37 | char *file; | ||
38 | if (asprintf(&file, "/proc/%u/status", pid) == -1) { | ||
39 | perror("asprintf"); | ||
40 | exit(1); | ||
41 | } | ||
42 | FILE *fp = fopen(file, "r"); | ||
43 | if (!fp) { | ||
44 | free(file); | ||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | // look for firejail executable name | ||
49 | char buf[PIDS_BUFLEN]; | ||
50 | while (fgets(buf, PIDS_BUFLEN - 1, fp)) { | ||
51 | if (strncmp(buf, "Name:", 5) == 0) { | ||
52 | char *ptr = buf + 5; | ||
53 | while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) { | ||
54 | ptr++; | ||
55 | } | ||
56 | if (*ptr == '\0') | ||
57 | goto doexit; | ||
58 | if (strncmp(ptr, "firejail", 8) == 0) | ||
59 | rv = 1; | ||
60 | // if (strncmp(ptr, "lxc-execute", 11) == 0) | ||
61 | // rv = 1; | ||
62 | break; | ||
63 | } | ||
64 | } | ||
65 | doexit: | ||
66 | fclose(fp); | ||
67 | free(file); | ||
68 | return rv; | ||
69 | } | ||
70 | |||
71 | |||
72 | static int procevent_netlink_setup(void) { | ||
73 | // open socket for process event connector | ||
74 | int sock; | ||
75 | if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR)) < 0) { | ||
76 | fprintf(stderr, "Error: cannot open netlink socket\n"); | ||
77 | exit(1); | ||
78 | } | ||
79 | |||
80 | // bind socket | ||
81 | struct sockaddr_nl addr; | ||
82 | memset(&addr, 0, sizeof(addr)); | ||
83 | addr.nl_pid = getpid(); | ||
84 | addr.nl_family = AF_NETLINK; | ||
85 | addr.nl_groups = CN_IDX_PROC; | ||
86 | if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { | ||
87 | fprintf(stderr, "Error: cannot bind to netlink socket\n"); | ||
88 | exit(1); | ||
89 | } | ||
90 | |||
91 | // send monitoring message | ||
92 | struct nlmsghdr nlmsghdr; | ||
93 | memset(&nlmsghdr, 0, sizeof(nlmsghdr)); | ||
94 | nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct cn_msg) + sizeof(enum proc_cn_mcast_op)); | ||
95 | nlmsghdr.nlmsg_pid = getpid(); | ||
96 | nlmsghdr.nlmsg_type = NLMSG_DONE; | ||
97 | |||
98 | struct cn_msg cn_msg; | ||
99 | memset(&cn_msg, 0, sizeof(cn_msg)); | ||
100 | cn_msg.id.idx = CN_IDX_PROC; | ||
101 | cn_msg.id.val = CN_VAL_PROC; | ||
102 | cn_msg.len = sizeof(enum proc_cn_mcast_op); | ||
103 | |||
104 | struct iovec iov[3]; | ||
105 | iov[0].iov_base = &nlmsghdr; | ||
106 | iov[0].iov_len = sizeof(nlmsghdr); | ||
107 | iov[1].iov_base = &cn_msg; | ||
108 | iov[1].iov_len = sizeof(cn_msg); | ||
109 | |||
110 | enum proc_cn_mcast_op op = PROC_CN_MCAST_LISTEN; | ||
111 | iov[2].iov_base = &op; | ||
112 | iov[2].iov_len = sizeof(op); | ||
113 | |||
114 | if (writev(sock, iov, 3) == -1) { | ||
115 | fprintf(stderr, "Error: cannot write to netlink socket\n"); | ||
116 | exit(1); | ||
117 | } | ||
118 | |||
119 | return sock; | ||
120 | } | ||
121 | |||
122 | |||
123 | static int procevent_monitor(const int sock, pid_t mypid) { | ||
124 | ssize_t len; | ||
125 | struct nlmsghdr *nlmsghdr; | ||
126 | |||
127 | // timeout in order to re-enable firejail module trace | ||
128 | struct timeval tv; | ||
129 | tv.tv_sec = 30; | ||
130 | tv.tv_usec = 0; | ||
131 | |||
132 | while (1) { | ||
133 | #define BUFFSIZE 4096 | ||
134 | char __attribute__ ((aligned(NLMSG_ALIGNTO)))buf[BUFFSIZE]; | ||
135 | |||
136 | fd_set readfds; | ||
137 | int max; | ||
138 | FD_ZERO(&readfds); | ||
139 | FD_SET(sock, &readfds); | ||
140 | max = sock; | ||
141 | max++; | ||
142 | |||
143 | int rv = select(max, &readfds, NULL, NULL, &tv); | ||
144 | if (rv == -1) { | ||
145 | fprintf(stderr, "recv: %s\n", strerror(errno)); | ||
146 | return -1; | ||
147 | } | ||
148 | |||
149 | // timeout | ||
150 | if (rv == 0) { | ||
151 | tv.tv_sec = 30; | ||
152 | tv.tv_usec = 0; | ||
153 | continue; | ||
154 | } | ||
155 | |||
156 | |||
157 | if ((len = recv(sock, buf, sizeof(buf), 0)) == 0) { | ||
158 | return 0; | ||
159 | } | ||
160 | if (len == -1) { | ||
161 | if (errno == EINTR) { | ||
162 | return 0; | ||
163 | } else { | ||
164 | fprintf(stderr,"recv: %s\n", strerror(errno)); | ||
165 | return -1; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | for (nlmsghdr = (struct nlmsghdr *)buf; | ||
170 | NLMSG_OK (nlmsghdr, len); | ||
171 | nlmsghdr = NLMSG_NEXT (nlmsghdr, len)) { | ||
172 | |||
173 | struct cn_msg *cn_msg; | ||
174 | struct proc_event *proc_ev; | ||
175 | struct tm tm; | ||
176 | time_t now; | ||
177 | |||
178 | if ((nlmsghdr->nlmsg_type == NLMSG_ERROR) || | ||
179 | (nlmsghdr->nlmsg_type == NLMSG_NOOP)) | ||
180 | continue; | ||
181 | |||
182 | cn_msg = NLMSG_DATA(nlmsghdr); | ||
183 | if ((cn_msg->id.idx != CN_IDX_PROC) || | ||
184 | (cn_msg->id.val != CN_VAL_PROC)) | ||
185 | continue; | ||
186 | |||
187 | (void)time(&now); | ||
188 | (void)localtime_r(&now, &tm); | ||
189 | char line[PIDS_BUFLEN]; | ||
190 | char *lineptr = line; | ||
191 | sprintf(lineptr, "%2.2d:%2.2d:%2.2d", tm.tm_hour, tm.tm_min, tm.tm_sec); | ||
192 | lineptr += strlen(lineptr); | ||
193 | |||
194 | proc_ev = (struct proc_event *)cn_msg->data; | ||
195 | pid_t pid = 0; | ||
196 | pid_t child = 0; | ||
197 | int remove_pid = 0; | ||
198 | switch (proc_ev->what) { | ||
199 | case PROC_EVENT_FORK: | ||
200 | if (proc_ev->event_data.fork.child_pid != | ||
201 | proc_ev->event_data.fork.child_tgid) | ||
202 | continue; // this is a thread, not a process | ||
203 | pid = proc_ev->event_data.fork.parent_tgid; | ||
204 | if (pids[pid].level > 0) { | ||
205 | child = proc_ev->event_data.fork.child_tgid; | ||
206 | child %= max_pids; | ||
207 | pids[child].level = pids[pid].level + 1; | ||
208 | pids[child].uid = pid_get_uid(child); | ||
209 | } | ||
210 | sprintf(lineptr, " fork"); | ||
211 | break; | ||
212 | case PROC_EVENT_EXEC: | ||
213 | pid = proc_ev->event_data.exec.process_tgid; | ||
214 | sprintf(lineptr, " exec"); | ||
215 | break; | ||
216 | |||
217 | case PROC_EVENT_EXIT: | ||
218 | if (proc_ev->event_data.exit.process_pid != | ||
219 | proc_ev->event_data.exit.process_tgid) | ||
220 | continue; // this is a thread, not a process | ||
221 | |||
222 | pid = proc_ev->event_data.exit.process_tgid; | ||
223 | remove_pid = 1; | ||
224 | sprintf(lineptr, " exit"); | ||
225 | break; | ||
226 | |||
227 | case PROC_EVENT_UID: | ||
228 | pid = proc_ev->event_data.id.process_tgid; | ||
229 | sprintf(lineptr, " uid "); | ||
230 | break; | ||
231 | |||
232 | case PROC_EVENT_GID: | ||
233 | pid = proc_ev->event_data.id.process_tgid; | ||
234 | sprintf(lineptr, " gid "); | ||
235 | break; | ||
236 | |||
237 | case PROC_EVENT_SID: | ||
238 | pid = proc_ev->event_data.sid.process_tgid; | ||
239 | sprintf(lineptr, " sid "); | ||
240 | break; | ||
241 | |||
242 | default: | ||
243 | sprintf(lineptr, "\n"); | ||
244 | continue; | ||
245 | } | ||
246 | |||
247 | int add_new = 0; | ||
248 | if (pids[pid].level < 0) // not a firejail process | ||
249 | continue; | ||
250 | else if (pids[pid].level == 0) { // new porcess, do we track it? | ||
251 | if (pid_is_firejail(pid) && mypid == 0) { | ||
252 | pids[pid].level = 1; | ||
253 | add_new = 1; | ||
254 | } | ||
255 | else { | ||
256 | pids[pid].level = -1; | ||
257 | continue; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | lineptr += strlen(lineptr); | ||
262 | sprintf(lineptr, " %u", pid); | ||
263 | lineptr += strlen(lineptr); | ||
264 | |||
265 | char *user = pids[pid].user; | ||
266 | if (!user) | ||
267 | user = pid_get_user_name(pids[pid].uid); | ||
268 | if (user) { | ||
269 | pids[pid].user = user; | ||
270 | sprintf(lineptr, " (%s)", user); | ||
271 | lineptr += strlen(lineptr); | ||
272 | } | ||
273 | |||
274 | |||
275 | int sandbox_closed = 0; // exit sandbox flag | ||
276 | char *cmd = pids[pid].cmd; | ||
277 | if (!cmd) { | ||
278 | cmd = pid_proc_cmdline(pid); | ||
279 | } | ||
280 | if (add_new) { | ||
281 | if (!cmd) | ||
282 | sprintf(lineptr, " NEW SANDBOX\n"); | ||
283 | else | ||
284 | sprintf(lineptr, " NEW SANDBOX: %s\n", cmd); | ||
285 | lineptr += strlen(lineptr); | ||
286 | } | ||
287 | else if (proc_ev->what == PROC_EVENT_EXIT && pids[pid].level == 1) { | ||
288 | sprintf(lineptr, " EXIT SANDBOX\n"); | ||
289 | lineptr += strlen(lineptr); | ||
290 | if (mypid == pid) | ||
291 | sandbox_closed = 1; | ||
292 | } | ||
293 | else { | ||
294 | if (!cmd) { | ||
295 | cmd = pid_proc_cmdline(pid); | ||
296 | } | ||
297 | if (cmd == NULL) | ||
298 | sprintf(lineptr, "\n"); | ||
299 | else { | ||
300 | sprintf(lineptr, " %s\n", cmd); | ||
301 | free(cmd); | ||
302 | } | ||
303 | lineptr += strlen(lineptr); | ||
304 | } | ||
305 | (void) lineptr; | ||
306 | |||
307 | // print the event | ||
308 | printf("%s", line); | ||
309 | fflush(0); | ||
310 | |||
311 | // unflag pid for exit events | ||
312 | if (remove_pid) { | ||
313 | if (pids[pid].user) | ||
314 | free(pids[pid].user); | ||
315 | if (pids[pid].cmd) | ||
316 | free(pids[pid].cmd); | ||
317 | memset(&pids[pid], 0, sizeof(Process)); | ||
318 | } | ||
319 | |||
320 | // print forked child | ||
321 | if (child) { | ||
322 | cmd = pid_proc_cmdline(child); | ||
323 | if (cmd) { | ||
324 | printf("\tchild %u %s\n", child, cmd); | ||
325 | free(cmd); | ||
326 | } | ||
327 | else | ||
328 | printf("\tchild %u\n", child); | ||
329 | } | ||
330 | |||
331 | // on uid events the uid is changing | ||
332 | if (proc_ev->what == PROC_EVENT_UID) { | ||
333 | if (pids[pid].user) | ||
334 | free(pids[pid].user); | ||
335 | pids[pid].user = 0; | ||
336 | pids[pid].uid = pid_get_uid(pid); | ||
337 | } | ||
338 | |||
339 | if (sandbox_closed) | ||
340 | exit(0); | ||
341 | } | ||
342 | } | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static void procevent_print_pids(void) { | ||
347 | // print files | ||
348 | int i; | ||
349 | for (i = 0; i < max_pids; i++) { | ||
350 | if (pids[i].level == 1) | ||
351 | pid_print_tree(i, 0, 1); | ||
352 | } | ||
353 | printf("\n"); | ||
354 | } | ||
355 | |||
356 | void procevent(pid_t pid) { | ||
357 | // need to be root for this | ||
358 | if (getuid() != 0) { | ||
359 | fprintf(stderr, "Error: you need to be root to get process events\n"); | ||
360 | exit(1); | ||
361 | } | ||
362 | |||
363 | // read and print sandboxed processes | ||
364 | pid_read(pid); | ||
365 | procevent_print_pids(); | ||
366 | |||
367 | // monitor using netlink | ||
368 | int sock = procevent_netlink_setup(); | ||
369 | if (sock < 0) { | ||
370 | fprintf(stderr, "Error: cannot open netlink socket\n"); | ||
371 | exit(1); | ||
372 | } | ||
373 | |||
374 | procevent_monitor(sock, pid); // it will never return from here | ||
375 | assert(0); | ||
376 | close(sock); // quiet static analyzers | ||
377 | } | ||
diff --git a/src/firemon/route.c b/src/firemon/route.c new file mode 100644 index 000000000..7f559c7b5 --- /dev/null +++ b/src/firemon/route.c | |||
@@ -0,0 +1,213 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 "firemon.h" | ||
21 | #include <assert.h> | ||
22 | #include <arpa/inet.h> | ||
23 | #define MAXBUF 4096 | ||
24 | |||
25 | typedef struct iflist_t { | ||
26 | struct iflist_t *next; | ||
27 | uint32_t ip; | ||
28 | } IfList; | ||
29 | static IfList *ifs = NULL; | ||
30 | static char last_start[MAXBUF + 1]; | ||
31 | |||
32 | static IfList *list_find(uint32_t ip, uint32_t mask) { | ||
33 | IfList *ptr = ifs; | ||
34 | while (ptr) { | ||
35 | if ((ptr->ip & mask) == (ip & mask)) | ||
36 | return ptr; | ||
37 | ptr = ptr->next; | ||
38 | } | ||
39 | |||
40 | return NULL; | ||
41 | } | ||
42 | |||
43 | static void extract_if(const char *fname) { | ||
44 | // clear interface list | ||
45 | while (ifs) { | ||
46 | IfList *tmp = ifs->next; | ||
47 | free(ifs); | ||
48 | ifs = tmp; | ||
49 | } | ||
50 | assert(ifs == NULL); | ||
51 | |||
52 | FILE *fp = fopen(fname, "r"); | ||
53 | if (!fp) | ||
54 | return; | ||
55 | |||
56 | char buf[MAXBUF]; | ||
57 | int state = 0; // 0 -wait for Local | ||
58 | // | ||
59 | while (fgets(buf, MAXBUF, fp)) { | ||
60 | // remove blanks, \n | ||
61 | char *ptr = buf; | ||
62 | while (*ptr == ' ' || *ptr == '\t') | ||
63 | ptr++; | ||
64 | char *start = ptr; | ||
65 | if (*start == '\0') | ||
66 | continue; | ||
67 | ptr = strchr(ptr, '\n'); | ||
68 | if (ptr) | ||
69 | *ptr = '\0'; | ||
70 | |||
71 | if (state == 0) { | ||
72 | if (strncmp(buf, "Local:", 6) == 0) { | ||
73 | state = 1; | ||
74 | continue; | ||
75 | } | ||
76 | } | ||
77 | else if (state == 1) { | ||
78 | // remove broadcast addresses | ||
79 | if (strstr(start,"BROADCAST")) | ||
80 | continue; | ||
81 | else if (*start == '+') | ||
82 | continue; | ||
83 | else if (*start == '|') { | ||
84 | memset(last_start, 0, MAXBUF + 1); | ||
85 | strncpy(last_start, start, MAXBUF); | ||
86 | continue; | ||
87 | } | ||
88 | else if (strstr(buf, "LOCAL")) { | ||
89 | // printf("%s %s\n", last_start, start); | ||
90 | unsigned mbits; | ||
91 | sscanf(start, "/%u", &mbits); | ||
92 | if (mbits != 32) | ||
93 | continue; | ||
94 | |||
95 | unsigned a, b, c, d; | ||
96 | if (sscanf(last_start, "|-- %u.%u.%u.%u", &a, &b, &c, &d) != 4 || a > 255 || b > 255 || c > 255 || d > 255) | ||
97 | continue; | ||
98 | |||
99 | IfList *newif = malloc(sizeof(IfList)); | ||
100 | if (!newif) | ||
101 | errExit("malloc"); | ||
102 | newif->ip = a * 0x1000000 + b * 0x10000 + c * 0x100 + d; | ||
103 | newif->next = ifs; | ||
104 | ifs = newif; | ||
105 | } | ||
106 | } | ||
107 | } | ||
108 | |||
109 | fclose(fp); | ||
110 | |||
111 | |||
112 | } | ||
113 | |||
114 | static void print_route(const char *fname) { | ||
115 | FILE *fp = fopen(fname, "r"); | ||
116 | if (!fp) | ||
117 | return; | ||
118 | |||
119 | printf(" Route table:\n"); | ||
120 | char buf[MAXBUF]; | ||
121 | while (fgets(buf, MAXBUF, fp)) { | ||
122 | // remove blanks, \n | ||
123 | char *ptr = buf; | ||
124 | while (*ptr == ' ' || *ptr == '\t') | ||
125 | ptr++; | ||
126 | char *start = ptr; | ||
127 | if (*start == '\0') | ||
128 | continue; | ||
129 | ptr = strchr(ptr, '\n'); | ||
130 | if (ptr) | ||
131 | *ptr = '\0'; | ||
132 | |||
133 | // remove table header | ||
134 | //Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT | ||
135 | if (strncmp(start, "Iface", 5) == 0) | ||
136 | continue; | ||
137 | |||
138 | // extract data | ||
139 | char ifname[64]; | ||
140 | char destination[64]; | ||
141 | char gateway[64]; | ||
142 | char flags[64]; | ||
143 | char refcnt[64]; | ||
144 | char use[64]; | ||
145 | char metric[64]; | ||
146 | char mask[64]; | ||
147 | int rv = sscanf(start, "%s %s %s %s %s %s %s %s\n", ifname, destination, gateway, flags, refcnt, use, metric, mask); | ||
148 | if (rv != 8) | ||
149 | continue; | ||
150 | |||
151 | // destination ip | ||
152 | uint32_t destip; | ||
153 | sscanf(destination, "%x", &destip); | ||
154 | destip = ntohl(destip); | ||
155 | uint32_t destmask; | ||
156 | sscanf(mask, "%x", &destmask); | ||
157 | destmask = ntohl(destmask); | ||
158 | uint32_t gw; | ||
159 | sscanf(gateway, "%x", &gw); | ||
160 | gw = ntohl(gw); | ||
161 | |||
162 | // printf("#%s# #%s# #%s# #%s# #%s# #%s# #%s# #%s#\n", ifname, destination, gateway, flags, refcnt, use, metric, mask); | ||
163 | if (gw != 0) | ||
164 | printf(" %u.%u.%u.%u/%u via %u.%u.%u.%u, dev %s, metric %s\n", | ||
165 | PRINT_IP(destip), mask2bits(destmask), | ||
166 | PRINT_IP(gw), | ||
167 | ifname, | ||
168 | metric); | ||
169 | else { // this is an interface | ||
170 | IfList *ifentry = list_find(destip, destmask); | ||
171 | if (ifentry) { | ||
172 | printf(" %u.%u.%u.%u/%u, dev %s, scope link src %d.%d.%d.%d\n", | ||
173 | PRINT_IP(destip), mask2bits(destmask), | ||
174 | ifname, | ||
175 | PRINT_IP(ifentry->ip)); | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | |||
180 | fclose(fp); | ||
181 | |||
182 | } | ||
183 | |||
184 | void route(pid_t pid) { | ||
185 | if (getuid() == 0) | ||
186 | firemon_drop_privs(); | ||
187 | |||
188 | pid_read(pid); | ||
189 | |||
190 | // print processes | ||
191 | int i; | ||
192 | for (i = 0; i < max_pids; i++) { | ||
193 | if (pids[i].level == 1) { | ||
194 | pid_print_list(i, 0); | ||
195 | int child = find_child(i); | ||
196 | if (child != -1) { | ||
197 | char *fname; | ||
198 | if (asprintf(&fname, "/proc/%d/net/fib_trie", child) == -1) | ||
199 | errExit("asprintf"); | ||
200 | extract_if(fname); | ||
201 | free(fname); | ||
202 | |||
203 | if (asprintf(&fname, "/proc/%d/net/route", child) == -1) | ||
204 | errExit("asprintf"); | ||
205 | print_route(fname); | ||
206 | free(fname); | ||
207 | printf("\n"); | ||
208 | } | ||
209 | } | ||
210 | } | ||
211 | } | ||
212 | |||
213 | |||
diff --git a/src/firemon/seccomp.c b/src/firemon/seccomp.c new file mode 100644 index 000000000..4ffc93f2e --- /dev/null +++ b/src/firemon/seccomp.c | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 "firemon.h" | ||
21 | |||
22 | #define MAXBUF 4098 | ||
23 | static void print_seccomp(int pid) { | ||
24 | char *file; | ||
25 | if (asprintf(&file, "/proc/%d/status", pid) == -1) { | ||
26 | errExit("asprintf"); | ||
27 | exit(1); | ||
28 | } | ||
29 | |||
30 | FILE *fp = fopen(file, "r"); | ||
31 | if (!fp) { | ||
32 | printf(" Error: cannot open %s\n", file); | ||
33 | free(file); | ||
34 | return; | ||
35 | } | ||
36 | |||
37 | char buf[MAXBUF]; | ||
38 | while (fgets(buf, MAXBUF, fp)) { | ||
39 | if (strncmp(buf, "Seccomp:", 8) == 0) { | ||
40 | printf(" %s", buf); | ||
41 | fflush(0); | ||
42 | fclose(fp); | ||
43 | free(file); | ||
44 | return; | ||
45 | } | ||
46 | } | ||
47 | fclose(fp); | ||
48 | free(file); | ||
49 | } | ||
50 | |||
51 | void seccomp(pid_t pid) { | ||
52 | if (getuid() == 0) | ||
53 | firemon_drop_privs(); | ||
54 | |||
55 | pid_read(pid); // include all processes | ||
56 | |||
57 | // print processes | ||
58 | int i; | ||
59 | for (i = 0; i < max_pids; i++) { | ||
60 | if (pids[i].level == 1) { | ||
61 | pid_print_list(i, 0); | ||
62 | int child = find_child(i); | ||
63 | if (child != -1) | ||
64 | print_seccomp(child); | ||
65 | } | ||
66 | } | ||
67 | printf("\n"); | ||
68 | } | ||
69 | |||
diff --git a/src/firemon/top.c b/src/firemon/top.c new file mode 100644 index 000000000..1eb753694 --- /dev/null +++ b/src/firemon/top.c | |||
@@ -0,0 +1,297 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 "firemon.h" | ||
21 | #include <termios.h> | ||
22 | #include <sys/ioctl.h> | ||
23 | #include <sys/types.h> | ||
24 | #include <sys/stat.h> | ||
25 | #include <unistd.h> | ||
26 | |||
27 | static unsigned pgs_rss = 0; | ||
28 | static unsigned pgs_shared = 0; | ||
29 | static unsigned clocktick = 0; | ||
30 | static unsigned long long sysuptime = 0; | ||
31 | |||
32 | static char *get_header(void) { | ||
33 | char *rv; | ||
34 | if (asprintf(&rv, "%-5.5s %-9.9s %-8.8s %-8.8s %-5.5s %-4.4s %-9.9s %s", | ||
35 | "PID", "User", "RES(KiB)", "SHR(KiB)", "CPU%", "Prcs", "Uptime", "Command") == -1) | ||
36 | errExit("asprintf"); | ||
37 | |||
38 | return rv; | ||
39 | } | ||
40 | |||
41 | |||
42 | // recursivity!!! | ||
43 | static char *print_top(unsigned index, unsigned parent, unsigned *utime, unsigned *stime, unsigned itv, float *cpu, int *cnt) { | ||
44 | char *rv = NULL; | ||
45 | |||
46 | char procdir[20]; | ||
47 | snprintf(procdir, 20, "/proc/%u", index); | ||
48 | struct stat s; | ||
49 | if (stat(procdir, &s) == -1) | ||
50 | return NULL; | ||
51 | |||
52 | if (pids[index].level == 1) { | ||
53 | pgs_rss = 0; | ||
54 | pgs_shared = 0; | ||
55 | *utime = 0; | ||
56 | *stime = 0; | ||
57 | *cnt = 0; | ||
58 | } | ||
59 | |||
60 | (*cnt)++; | ||
61 | pid_getmem(index, &pgs_rss, &pgs_shared); | ||
62 | unsigned utmp; | ||
63 | unsigned stmp; | ||
64 | pid_get_cpu_time(index, &utmp, &stmp); | ||
65 | *utime += utmp; | ||
66 | *stime += stmp; | ||
67 | |||
68 | |||
69 | int i; | ||
70 | for (i = index + 1; i < max_pids; i++) { | ||
71 | if (pids[i].parent == index) | ||
72 | print_top(i, index, utime, stime, itv, cpu, cnt); | ||
73 | } | ||
74 | |||
75 | if (pids[index].level == 1) { | ||
76 | // pid | ||
77 | char pidstr[10]; | ||
78 | snprintf(pidstr, 10, "%u", index); | ||
79 | |||
80 | // command | ||
81 | char *cmd = pid_proc_cmdline(index); | ||
82 | char *ptrcmd; | ||
83 | if (cmd == NULL) { | ||
84 | if (pids[index].zombie) | ||
85 | ptrcmd = "(zombie)"; | ||
86 | else | ||
87 | ptrcmd = ""; | ||
88 | } | ||
89 | else | ||
90 | ptrcmd = cmd; | ||
91 | |||
92 | // user | ||
93 | char *user = pid_get_user_name(pids[index].uid); | ||
94 | char *ptruser; | ||
95 | if (user) | ||
96 | ptruser = user; | ||
97 | else | ||
98 | ptruser = ""; | ||
99 | |||
100 | // memory | ||
101 | int pgsz = getpagesize(); | ||
102 | char rss[10]; | ||
103 | snprintf(rss, 10, "%u", pgs_rss * pgsz / 1024); | ||
104 | char shared[10]; | ||
105 | snprintf(shared, 10, "%u", pgs_shared * pgsz / 1024); | ||
106 | |||
107 | // uptime | ||
108 | unsigned long long uptime = pid_get_start_time(index); | ||
109 | if (clocktick == 0) | ||
110 | clocktick = sysconf(_SC_CLK_TCK); | ||
111 | uptime /= clocktick; | ||
112 | uptime = sysuptime - uptime; | ||
113 | unsigned sec = uptime % 60; | ||
114 | uptime -= sec; | ||
115 | uptime /= 60; | ||
116 | unsigned min = uptime % 60; | ||
117 | uptime -= min; | ||
118 | uptime /= 60; | ||
119 | unsigned hour = uptime; | ||
120 | char uptime_str[50]; | ||
121 | snprintf(uptime_str, 50, "%02u:%02u:%02u", hour, min, sec); | ||
122 | |||
123 | // cpu | ||
124 | itv *= clocktick; | ||
125 | float ud = (float) (*utime - pids[index].utime) / itv * 100; | ||
126 | float sd = (float) (*stime - pids[index].stime) / itv * 100; | ||
127 | float cd = ud + sd; | ||
128 | *cpu = cd; | ||
129 | char cpu_str[10]; | ||
130 | snprintf(cpu_str, 10, "%2.1f", cd); | ||
131 | |||
132 | // process count | ||
133 | char prcs_str[10]; | ||
134 | snprintf(prcs_str, 10, "%d", *cnt); | ||
135 | |||
136 | if (asprintf(&rv, "%-5.5s %-9.9s %-8.8s %-8.8s %-5.5s %-4.4s %-9.9s %s", | ||
137 | pidstr, ptruser, rss, shared, cpu_str, prcs_str, uptime_str, ptrcmd) == -1) | ||
138 | errExit("asprintf"); | ||
139 | |||
140 | if (cmd) | ||
141 | free(cmd); | ||
142 | if (user) | ||
143 | free(user); | ||
144 | |||
145 | } | ||
146 | |||
147 | return rv; | ||
148 | } | ||
149 | |||
150 | |||
151 | typedef struct node_t { | ||
152 | struct node_t *next; | ||
153 | char *line; | ||
154 | float cpu; | ||
155 | } Node; | ||
156 | |||
157 | static Node *head = NULL; | ||
158 | |||
159 | static void head_clear(void) { | ||
160 | Node *ptr = head; | ||
161 | while (ptr) { | ||
162 | if (ptr->line) | ||
163 | free(ptr->line); | ||
164 | Node *next = ptr->next; | ||
165 | free(ptr); | ||
166 | ptr = next; | ||
167 | } | ||
168 | |||
169 | head = NULL; | ||
170 | } | ||
171 | |||
172 | static void head_add(float cpu, char *line) { | ||
173 | // allocate a new node structure | ||
174 | Node *node = malloc(sizeof(Node)); | ||
175 | if (!node) | ||
176 | errExit("malloc"); | ||
177 | node->line = line; | ||
178 | node->cpu = cpu; | ||
179 | node->next = NULL; | ||
180 | |||
181 | // insert in first list position | ||
182 | if (head == NULL || head->cpu < cpu) { | ||
183 | node->next = head; | ||
184 | head = node; | ||
185 | return; | ||
186 | } | ||
187 | |||
188 | // insert in the right place | ||
189 | Node *ptr = head; | ||
190 | while (1) { | ||
191 | // last position | ||
192 | Node *current = ptr->next; | ||
193 | if (current == NULL) { | ||
194 | ptr->next = node; | ||
195 | return; | ||
196 | } | ||
197 | |||
198 | // current position | ||
199 | if (current->cpu < cpu) { | ||
200 | ptr->next = node; | ||
201 | node->next = current; | ||
202 | return; | ||
203 | } | ||
204 | |||
205 | ptr = current; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | void head_print(int col, int row) { | ||
210 | Node *ptr = head; | ||
211 | int current = 0; | ||
212 | while (ptr) { | ||
213 | if (current >= row) | ||
214 | break; | ||
215 | |||
216 | if (strlen(ptr->line) > col) | ||
217 | ptr->line[col] = '\0'; | ||
218 | |||
219 | if (ptr->next == NULL || current == (row - 1)) { | ||
220 | printf("%s", ptr->line); | ||
221 | fflush(0); | ||
222 | } | ||
223 | else | ||
224 | printf("%s\n", ptr->line); | ||
225 | |||
226 | ptr = ptr->next; | ||
227 | current++; | ||
228 | } | ||
229 | } | ||
230 | |||
231 | void top(void) { | ||
232 | if (getuid() == 0) | ||
233 | firemon_drop_privs(); | ||
234 | |||
235 | while (1) { | ||
236 | // clear linked list | ||
237 | head_clear(); | ||
238 | |||
239 | // set pid table | ||
240 | int i; | ||
241 | int itv = 5; // 5 second interval | ||
242 | pid_read(0); | ||
243 | |||
244 | // start cpu measurements | ||
245 | unsigned utime = 0; | ||
246 | unsigned stime = 0; | ||
247 | for (i = 0; i < max_pids; i++) { | ||
248 | if (pids[i].level == 1) | ||
249 | pid_store_cpu(i, 0, &utime, &stime); | ||
250 | } | ||
251 | |||
252 | // wait 5 seconds | ||
253 | firemon_sleep(itv); | ||
254 | |||
255 | // grab screen size | ||
256 | struct winsize sz; | ||
257 | int row = 24; | ||
258 | int col = 80; | ||
259 | if (!ioctl(0, TIOCGWINSZ, &sz)) { | ||
260 | col = sz.ws_col; | ||
261 | row = sz.ws_row; | ||
262 | } | ||
263 | |||
264 | // start printing | ||
265 | firemon_clrscr(); | ||
266 | char *header = get_header(); | ||
267 | if (strlen(header) > col) | ||
268 | header[col] = '\0'; | ||
269 | printf("%s\n", header); | ||
270 | if (row > 0) | ||
271 | row--; | ||
272 | free(header); | ||
273 | |||
274 | // find system uptime | ||
275 | FILE *fp = fopen("/proc/uptime", "r"); | ||
276 | if (fp) { | ||
277 | float f; | ||
278 | int rv = fscanf(fp, "%f", &f); | ||
279 | (void) rv; | ||
280 | sysuptime = (unsigned long long) f; | ||
281 | fclose(fp); | ||
282 | } | ||
283 | |||
284 | // print processes | ||
285 | for (i = 0; i < max_pids; i++) { | ||
286 | if (pids[i].level == 1) { | ||
287 | float cpu = 0; | ||
288 | int cnt = 0; // process count | ||
289 | char *line = print_top(i, 0, &utime, &stime, itv, &cpu, &cnt); | ||
290 | if (line) | ||
291 | head_add(cpu, line); | ||
292 | } | ||
293 | } | ||
294 | head_print(col, row); | ||
295 | } | ||
296 | } | ||
297 | |||
diff --git a/src/firemon/tree.c b/src/firemon/tree.c new file mode 100644 index 000000000..97e0e1f13 --- /dev/null +++ b/src/firemon/tree.c | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 "firemon.h" | ||
21 | |||
22 | void tree(pid_t pid) { | ||
23 | if (getuid() == 0) | ||
24 | firemon_drop_privs(); | ||
25 | |||
26 | pid_read(pid); // include all processes | ||
27 | |||
28 | // print processes | ||
29 | int i; | ||
30 | for (i = 0; i < max_pids; i++) { | ||
31 | if (pids[i].level == 1) | ||
32 | pid_print_tree(i, 0, arg_nowrap); | ||
33 | } | ||
34 | printf("\n"); | ||
35 | } | ||
36 | |||
diff --git a/src/firemon/usage.c b/src/firemon/usage.c new file mode 100644 index 000000000..52788807a --- /dev/null +++ b/src/firemon/usage.c | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 "firemon.h" | ||
21 | |||
22 | void usage(void) { | ||
23 | printf("firemon - version %s\n", VERSION); | ||
24 | printf("Usage: firemon [OPTIONS] [PID]\n\n"); | ||
25 | printf("Monitor processes started in a Firejail sandbox. Without any PID specified,\n"); | ||
26 | printf("all processes started by Firejail are monitored. Descendants of these processes\n"); | ||
27 | printf("are also being monitored.\n\n"); | ||
28 | printf("Options:\n"); | ||
29 | printf("\t--arp - print ARP table for each sandbox.\n\n"); | ||
30 | printf("\t--caps - print capabilities configuration for each sandbox.\n\n"); | ||
31 | printf("\t--cgroup - print control group information for each sandbox.\n\n"); | ||
32 | printf("\t--cpu - print CPU affinity for each sandbox.\n\n"); | ||
33 | printf("\t--help, -? - this help screen.\n\n"); | ||
34 | printf("\t--interface - print network interface information for each sandbox.\n\n"); | ||
35 | printf("\t--list - list all sandboxes.\n\n"); | ||
36 | printf("\t--name=name - print information only about named sandbox.\n\n"); | ||
37 | printf("\t--netstats - monitor network statistics for sandboxes creating a new\n"); | ||
38 | printf("\t\tnetwork namespace.\n\n"); | ||
39 | printf("\t--route - print route table for each sandbox.\n\n"); | ||
40 | printf("\t--seccomp - print seccomp configuration for each sandbox.\n\n"); | ||
41 | printf("\t--tree - print a tree of all sandboxed processes.\n\n"); | ||
42 | printf("\t--top - monitor the most CPU-intensive sandboxes.\n\n"); | ||
43 | printf("\t--version - print program version and exit.\n\n"); | ||
44 | |||
45 | printf("Without any options, firemon monitors all fork, exec, id change, and exit events\n"); | ||
46 | printf("in the sandbox. Monitoring a specific PID is also supported.\n\n"); | ||
47 | |||
48 | printf("Option --list prints a list of all sandboxes. The format for each entry is as\n"); | ||
49 | printf("follows:\n\n"); | ||
50 | printf("\tPID:USER:Command\n\n"); | ||
51 | |||
52 | printf("Option --tree prints the tree of processes running in the sandbox. The format\n"); | ||
53 | printf("for each process entry is as follows:\n\n"); | ||
54 | printf("\tPID:USER:Command\n\n"); | ||
55 | |||
56 | printf("Option --top is similar to the UNIX top command, however it applies only to\n"); | ||
57 | printf("sandboxes. Listed below are the available fields (columns) in alphabetical\n"); | ||
58 | printf("order:\n\n"); | ||
59 | printf("\tCommand - command used to start the sandbox.\n"); | ||
60 | printf("\tCPU%% - CPU usage, the sandbox share of the elapsed CPU time since the\n"); | ||
61 | printf("\t last screen update\n"); | ||
62 | printf("\tPID - Unique process ID for the task controlling the sandbox.\n"); | ||
63 | printf("\tPrcs - number of processes running in sandbox, including the controlling\n"); | ||
64 | printf("\t process.\n"); | ||
65 | printf("\tRES - Resident Memory Size (KiB), sandbox non-swapped physical memory.\n"); | ||
66 | printf("\t It is a sum of the RES values for all processes running in the\n"); | ||
67 | printf("\t sandbox.\n"); | ||
68 | printf("\tSHR - Shared Memory Size (KiB), it reflects memory shared with other\n"); | ||
69 | printf("\t processes. It is a sum of the SHR values for all processes running\n"); | ||
70 | printf("\t in the sandbox, including the controlling process.\n"); | ||
71 | printf("\tUptime - sandbox running time in hours:minutes:seconds format.\n"); | ||
72 | printf("\tUser - The owner of the sandbox.\n"); | ||
73 | printf("\n"); | ||
74 | printf("License GPL version 2 or later\n"); | ||
75 | printf("Homepage: http://firejail.sourceforge.net\n"); | ||
76 | printf("\n"); | ||
77 | } | ||
diff --git a/src/fshaper/fshaper.sh b/src/fshaper/fshaper.sh new file mode 100755 index 000000000..4045fd5a4 --- /dev/null +++ b/src/fshaper/fshaper.sh | |||
@@ -0,0 +1,69 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | usage() { | ||
4 | echo "Usage:" | ||
5 | echo " fshaper.sh --status" | ||
6 | echo " fshaper.sh --clear device" | ||
7 | echo " fshaper.sh --set device download-speed upload-speed" | ||
8 | } | ||
9 | |||
10 | if [ "$1" = "--status" ]; then | ||
11 | /sbin/tc -s qdisc ls | ||
12 | /sbin/tc -s class ls | ||
13 | exit | ||
14 | fi | ||
15 | |||
16 | if [ "$1" = "--clear" ]; then | ||
17 | if [ $# -ne 2 ]; then | ||
18 | echo "Error: invalid command" | ||
19 | usage | ||
20 | exit | ||
21 | fi | ||
22 | |||
23 | DEV=$2 | ||
24 | echo "Removing bandwith limits" | ||
25 | /sbin/tc qdisc del dev $DEV root 2> /dev/null > /dev/null | ||
26 | /sbin/tc qdisc del dev $DEV ingress 2> /dev/null > /dev/null | ||
27 | exit | ||
28 | |||
29 | fi | ||
30 | |||
31 | if [ "$1" = "--set" ]; then | ||
32 | DEV=$2 | ||
33 | echo "Removing bandwith limit" | ||
34 | /sbin/tc qdisc del dev $DEV ingress #2> /dev/null > /dev/null | ||
35 | |||
36 | if [ $# -ne 4 ]; then | ||
37 | echo "Error: missing parameters" | ||
38 | usage | ||
39 | exit | ||
40 | fi | ||
41 | |||
42 | DEV=$2 | ||
43 | echo "Configuring interface $DEV " | ||
44 | |||
45 | IN=$3 | ||
46 | IN=$((${IN} * 8)) | ||
47 | echo "Download speed ${IN}kbps" | ||
48 | |||
49 | OUT=$4 | ||
50 | OUT=$((${OUT} * 8)) | ||
51 | echo "Upload speed ${OUT}kbps" | ||
52 | |||
53 | echo "cleaning limits" | ||
54 | /sbin/tc qdisc del dev $DEV root 2> /dev/null > /dev/null | ||
55 | /sbin/tc qdisc del dev $DEV ingress 2> /dev/null > /dev/null | ||
56 | |||
57 | echo "configuring tc ingress" | ||
58 | /sbin/tc qdisc add dev $DEV handle ffff: ingress #2> /dev/null > /dev/null | ||
59 | /sbin/tc filter add dev $DEV parent ffff: protocol ip prio 50 u32 match ip src \ | ||
60 | 0.0.0.0/0 police rate ${IN}kbit burst 10k drop flowid :1 #2> /dev/null > /dev/null | ||
61 | |||
62 | echo "configuring tc egress" | ||
63 | /sbin/tc qdisc add dev $DEV root tbf rate ${OUT}kbit latency 25ms burst 10k #2> /dev/null > /dev/null | ||
64 | exit | ||
65 | fi | ||
66 | |||
67 | echo "Error: missing parameters" | ||
68 | usage | ||
69 | exit 1 | ||
diff --git a/src/ftee/Makefile.in b/src/ftee/Makefile.in new file mode 100644 index 000000000..6911f0a3c --- /dev/null +++ b/src/ftee/Makefile.in | |||
@@ -0,0 +1,24 @@ | |||
1 | all: ftee | ||
2 | |||
3 | PREFIX=@prefix@ | ||
4 | VERSION=@PACKAGE_VERSION@ | ||
5 | NAME=@PACKAGE_NAME@ | ||
6 | |||
7 | H_FILE_LIST = $(wildcard *.[h]) | ||
8 | C_FILE_LIST = $(wildcard *.c) | ||
9 | OBJS = $(C_FILE_LIST:.c=.o) | ||
10 | BINOBJS = $(foreach file, $(OBJS), $file) | ||
11 | CFLAGS += -ggdb -O2 -DVERSION='"$(VERSION)"' -DPREFIX='"$(PREFIX)"' -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security | ||
12 | LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread | ||
13 | |||
14 | %.o : %.c $(H_FILE_LIST) | ||
15 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ | ||
16 | |||
17 | ftee: $(OBJS) | ||
18 | $(CC) $(LDFLAGS) -o $@ $(OBJS) | ||
19 | |||
20 | clean:; rm -f *.o ftee | ||
21 | |||
22 | distclean: clean | ||
23 | rm -fr Makefile | ||
24 | |||
diff --git a/src/ftee/ftee.h b/src/ftee/ftee.h new file mode 100644 index 000000000..a28cc5bb5 --- /dev/null +++ b/src/ftee/ftee.h | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 | #ifndef FTEE_H | ||
21 | #define FTEE_H | ||
22 | #include "../include/common.h" | ||
23 | |||
24 | #endif \ No newline at end of file | ||
diff --git a/src/ftee/main.c b/src/ftee/main.c new file mode 100644 index 000000000..4dca3cf48 --- /dev/null +++ b/src/ftee/main.c | |||
@@ -0,0 +1,228 @@ | |||
1 | #include "ftee.h" | ||
2 | #include <errno.h> | ||
3 | #include <sys/types.h> | ||
4 | #include <sys/stat.h> | ||
5 | #include <unistd.h> | ||
6 | #define MAXBUF 512 | ||
7 | |||
8 | static unsigned char buf[MAXBUF]; | ||
9 | |||
10 | static FILE *out_fp = NULL; | ||
11 | static int out_cnt = 0; | ||
12 | static int out_max = 500 * 1024; | ||
13 | |||
14 | static void log_close(void) { | ||
15 | if (out_fp) { | ||
16 | fclose(out_fp); | ||
17 | out_fp = NULL; | ||
18 | } | ||
19 | } | ||
20 | |||
21 | static void log_rotate(const char *fname) { | ||
22 | struct stat s; | ||
23 | int index = strlen(fname); | ||
24 | char *name1 = malloc(index + 2 + 1); | ||
25 | char *name2 = malloc(index + 2 + 1); | ||
26 | if (!name1 || !name2) | ||
27 | errExit("malloc"); | ||
28 | strcpy(name1, fname); | ||
29 | strcpy(name2, fname); | ||
30 | fflush(0); | ||
31 | |||
32 | // delete filename.5 | ||
33 | sprintf(name1 + index, ".5"); | ||
34 | if (stat(name1, &s) == 0) { | ||
35 | int rv = unlink(name1); | ||
36 | if (rv == -1) | ||
37 | perror("unlink"); | ||
38 | } | ||
39 | |||
40 | // move files 1 to 4 down one position | ||
41 | sprintf(name2 + index, ".4"); | ||
42 | if (stat(name2, &s) == 0) { | ||
43 | int rv = rename(name2, name1); | ||
44 | if (rv == -1) | ||
45 | perror("rename"); | ||
46 | } | ||
47 | |||
48 | sprintf(name1 + index, ".3"); | ||
49 | if (stat(name1, &s) == 0) { | ||
50 | int rv = rename(name1, name2); | ||
51 | if (rv == -1) | ||
52 | perror("rename"); | ||
53 | } | ||
54 | |||
55 | sprintf(name2 + index, ".2"); | ||
56 | if (stat(name2, &s) == 0) { | ||
57 | /* coverity[toctou] */ | ||
58 | int rv = rename(name2, name1); | ||
59 | if (rv == -1) | ||
60 | perror("rename"); | ||
61 | } | ||
62 | |||
63 | sprintf(name1 + index, ".1"); | ||
64 | if (stat(name1, &s) == 0) { | ||
65 | int rv = rename(name1, name2); | ||
66 | if (rv == -1) | ||
67 | perror("rename"); | ||
68 | } | ||
69 | |||
70 | // move the first file | ||
71 | if (out_fp) | ||
72 | fclose(out_fp); | ||
73 | |||
74 | out_fp = NULL; | ||
75 | if (stat(fname, &s) == 0) { | ||
76 | int rv = rename(fname, name1); | ||
77 | if (rv == -1) | ||
78 | perror("rename"); | ||
79 | } | ||
80 | |||
81 | free(name1); | ||
82 | free(name2); | ||
83 | } | ||
84 | |||
85 | static void log_write(const unsigned char *str, int len, const char *fname) { | ||
86 | assert(fname); | ||
87 | |||
88 | if (out_fp == NULL) { | ||
89 | out_fp = fopen(fname, "w"); | ||
90 | if (!out_fp) { | ||
91 | fprintf(stderr, "Error: cannot open log file %s\n", fname); | ||
92 | exit(1); | ||
93 | } | ||
94 | out_cnt = 0; | ||
95 | } | ||
96 | |||
97 | // rotate files | ||
98 | out_cnt += len; | ||
99 | if (out_cnt >= out_max) { | ||
100 | log_rotate(fname); | ||
101 | |||
102 | // reopen the first file | ||
103 | if (out_fp) | ||
104 | fclose(out_fp); | ||
105 | out_fp = fopen(fname, "w"); | ||
106 | if (!out_fp) { | ||
107 | fprintf(stderr, "Error: cannot open log file %s\n", fname); | ||
108 | exit(1); | ||
109 | } | ||
110 | out_cnt = len; | ||
111 | } | ||
112 | |||
113 | fwrite(str, len, 1, out_fp); | ||
114 | fflush(0); | ||
115 | } | ||
116 | |||
117 | |||
118 | // return 1 if the file is a directory | ||
119 | static int is_dir(const char *fname) { | ||
120 | assert(fname); | ||
121 | if (*fname == '\0') | ||
122 | return 0; | ||
123 | |||
124 | // if fname doesn't end in '/', add one | ||
125 | int rv; | ||
126 | struct stat s; | ||
127 | if (fname[strlen(fname) - 1] == '/') | ||
128 | rv = stat(fname, &s); | ||
129 | else { | ||
130 | char *tmp; | ||
131 | if (asprintf(&tmp, "%s/", fname) == -1) { | ||
132 | fprintf(stderr, "Error: cannot allocate memory, %s:%d\n", __FILE__, __LINE__); | ||
133 | exit(1); | ||
134 | } | ||
135 | rv = stat(tmp, &s); | ||
136 | free(tmp); | ||
137 | } | ||
138 | |||
139 | if (rv == -1) | ||
140 | return 0; | ||
141 | |||
142 | if (S_ISDIR(s.st_mode)) | ||
143 | return 1; | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | // return 1 if the file is a link | ||
149 | static int is_link(const char *fname) { | ||
150 | assert(fname); | ||
151 | if (*fname == '\0') | ||
152 | return 0; | ||
153 | |||
154 | struct stat s; | ||
155 | if (lstat(fname, &s) == 0) { | ||
156 | if (S_ISLNK(s.st_mode)) | ||
157 | return 1; | ||
158 | } | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | |||
164 | |||
165 | |||
166 | |||
167 | static void usage(void) { | ||
168 | printf("Usage: ftee filename\n"); | ||
169 | } | ||
170 | |||
171 | int main(int argc, char **argv) { | ||
172 | if (argc < 2) { | ||
173 | fprintf(stderr, "Error: please provide a filename to store the program output\n"); | ||
174 | usage(); | ||
175 | exit(1); | ||
176 | } | ||
177 | char *fname = argv[1]; | ||
178 | |||
179 | |||
180 | // do not accept directories, links, and files with ".." | ||
181 | if (strstr(fname, "..") || is_link(fname) || is_dir(fname)) { | ||
182 | fprintf(stderr, "Error: invalid output file. Links, directories and files with \"..\" are not allowed.\n"); | ||
183 | exit(1); | ||
184 | } | ||
185 | |||
186 | struct stat s; | ||
187 | if (stat(fname, &s) == 0) { | ||
188 | // check permissions | ||
189 | if (s.st_uid != getuid() || s.st_gid != getgid()) { | ||
190 | fprintf(stderr, "Error: the output file needs to be owned by the current user.\n"); | ||
191 | exit(1); | ||
192 | } | ||
193 | |||
194 | // check hard links | ||
195 | if (s.st_nlink != 1) { | ||
196 | fprintf(stderr, "Error: no hard links allowed.\n"); | ||
197 | exit(1); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | // check if we can append to this file | ||
202 | /* coverity[toctou] */ | ||
203 | FILE *fp = fopen(fname, "a"); | ||
204 | if (!fp) { | ||
205 | fprintf(stderr, "Error: cannot open output file %s\n", fname); | ||
206 | exit(1); | ||
207 | } | ||
208 | fclose(fp); | ||
209 | |||
210 | |||
211 | // preserve the last log file | ||
212 | log_rotate(fname); | ||
213 | |||
214 | setvbuf (stdout, NULL, _IONBF, 0); | ||
215 | while(1) { | ||
216 | int n = read(0, buf, sizeof(buf)); | ||
217 | if (n < 0 && errno == EINTR) | ||
218 | continue; | ||
219 | if (n <= 0) | ||
220 | break; | ||
221 | |||
222 | fwrite(buf, n, 1, stdout); | ||
223 | log_write(buf, n, fname); | ||
224 | } | ||
225 | |||
226 | log_close(); | ||
227 | return 0; | ||
228 | } | ||
diff --git a/src/include/common.h b/src/include/common.h new file mode 100644 index 000000000..7ce1e9290 --- /dev/null +++ b/src/include/common.h | |||
@@ -0,0 +1,115 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 | |||
21 | #ifndef COMMON_H | ||
22 | #define COMMON_H | ||
23 | #define _GNU_SOURCE | ||
24 | #include <stdio.h> | ||
25 | #include <sys/types.h> | ||
26 | #include <unistd.h> | ||
27 | #include <stdlib.h> | ||
28 | #include <stdint.h> | ||
29 | #include <stddef.h> | ||
30 | #include <string.h> | ||
31 | #include <ctype.h> | ||
32 | #include <assert.h> | ||
33 | |||
34 | #define errExit(msg) do { char msgout[500]; sprintf(msgout, "Error %s:%s(%d)", msg, __FUNCTION__, __LINE__); perror(msgout); exit(1);} while (0) | ||
35 | |||
36 | // macro to print ip addresses in a printf statement | ||
37 | #define PRINT_IP(A) \ | ||
38 | ((int) (((A) >> 24) & 0xFF)), ((int) (((A) >> 16) & 0xFF)), ((int) (((A) >> 8) & 0xFF)), ((int) ( (A) & 0xFF)) | ||
39 | |||
40 | // macro to print a mac addresses in a printf statement | ||
41 | #define PRINT_MAC(A) \ | ||
42 | ((unsigned) (*(A)) & 0xff), ((unsigned) (*((A) + 1) & 0xff)), ((unsigned) (*((A) + 2) & 0xff)), \ | ||
43 | ((unsigned) (*((A) + 3)) & 0xff), ((unsigned) (*((A) + 4) & 0xff)), ((unsigned) (*((A) + 5)) & 0xff) | ||
44 | |||
45 | // the number of bits in a network mask | ||
46 | static inline uint8_t mask2bits(uint32_t mask) { | ||
47 | uint32_t tmp = 0x80000000; | ||
48 | int i; | ||
49 | uint8_t rv = 0; | ||
50 | |||
51 | for (i = 0; i < 32; i++, tmp >>= 1) { | ||
52 | if (tmp & mask) | ||
53 | rv++; | ||
54 | else | ||
55 | break; | ||
56 | } | ||
57 | return rv; | ||
58 | } | ||
59 | |||
60 | // read an IPv4 address and convert it to uint32_t | ||
61 | static inline int atoip(const char *str, uint32_t *ip) { | ||
62 | unsigned a, b, c, d; | ||
63 | |||
64 | if (sscanf(str, "%u.%u.%u.%u", &a, &b, &c, &d) != 4 || a > 255 || b > 255 || c > 255 || d > 255) | ||
65 | return 1; | ||
66 | |||
67 | *ip = a * 0x1000000 + b * 0x10000 + c * 0x100 + d; | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | // verify an ip address is in the network range given by ifip and mask | ||
72 | static inline char *in_netrange(uint32_t ip, uint32_t ifip, uint32_t ifmask) { | ||
73 | if ((ip & ifmask) != (ifip & ifmask)) | ||
74 | return "Error: the IP address is not in the interface range\n"; | ||
75 | else if ((ip & ifmask) == ip) | ||
76 | return "Error: the IP address is a network address\n"; | ||
77 | else if ((ip | ~ifmask) == ip) | ||
78 | return "Error: the IP address is a network address\n"; | ||
79 | return NULL; | ||
80 | } | ||
81 | |||
82 | // read a mac address | ||
83 | static inline int atomac(char *str, unsigned char macAddr[6]) { | ||
84 | unsigned mac[6]; | ||
85 | |||
86 | if (sscanf(str, "%2x:%2x:%2x:%2x:%2x:%2x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) != 6) | ||
87 | return 1; | ||
88 | |||
89 | int i; | ||
90 | for (i = 0; i < 6; i++) { | ||
91 | if (mac[i] > 0xff) | ||
92 | return 1; | ||
93 | |||
94 | macAddr[i] = (unsigned char) mac[i]; | ||
95 | } | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | // check a mac address is configured | ||
101 | static inline int mac_not_zero(const unsigned char mac[6]) { | ||
102 | int i; | ||
103 | for (i = 0; i < 6; i++) { | ||
104 | if (mac[i] != 0) | ||
105 | return 1; | ||
106 | } | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | int join_namespace(pid_t pid, char *type); | ||
112 | int name2pid(const char *name, pid_t *pid); | ||
113 | char *pid_proc_comm(const pid_t pid); | ||
114 | char *pid_proc_cmdline(const pid_t pid); | ||
115 | #endif | ||
diff --git a/src/include/libnetlink.h b/src/include/libnetlink.h new file mode 100644 index 000000000..e9cd6b186 --- /dev/null +++ b/src/include/libnetlink.h | |||
@@ -0,0 +1,163 @@ | |||
1 | /* file extracted from iproute2 software package | ||
2 | * | ||
3 | * Original source code: | ||
4 | * | ||
5 | * Information: | ||
6 | * http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2 | ||
7 | * | ||
8 | * Download: | ||
9 | * http://www.kernel.org/pub/linux/utils/net/iproute2/ | ||
10 | * | ||
11 | * Repository: | ||
12 | * git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git | ||
13 | * | ||
14 | * License: GPL v2 | ||
15 | */ | ||
16 | |||
17 | |||
18 | #ifndef __LIBNETLINK_H__ | ||
19 | #define __LIBNETLINK_H__ 1 | ||
20 | |||
21 | #define _GNU_SOURCE | ||
22 | #include <stdio.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <stdint.h> | ||
25 | #include <string.h> | ||
26 | #include <asm/types.h> | ||
27 | #include <linux/netlink.h> | ||
28 | #include <linux/rtnetlink.h> | ||
29 | #include <linux/if_link.h> | ||
30 | #include <linux/if_addr.h> | ||
31 | #include <linux/neighbour.h> | ||
32 | |||
33 | struct rtnl_handle | ||
34 | { | ||
35 | int fd; | ||
36 | struct sockaddr_nl local; | ||
37 | struct sockaddr_nl peer; | ||
38 | __u32 seq; | ||
39 | __u32 dump; | ||
40 | }; | ||
41 | |||
42 | extern int rcvbuf; | ||
43 | |||
44 | extern int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions); | ||
45 | extern int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, int protocol); | ||
46 | extern void rtnl_close(struct rtnl_handle *rth); | ||
47 | extern int rtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type); | ||
48 | extern int rtnl_wilddump_req_filter(struct rtnl_handle *rth, int fam, int type, | ||
49 | __u32 filt_mask); | ||
50 | extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len); | ||
51 | |||
52 | typedef int (*rtnl_filter_t)(const struct sockaddr_nl *, | ||
53 | struct nlmsghdr *n, void *); | ||
54 | |||
55 | struct rtnl_dump_filter_arg | ||
56 | { | ||
57 | rtnl_filter_t filter; | ||
58 | void *arg1; | ||
59 | }; | ||
60 | |||
61 | extern int rtnl_dump_filter_l(struct rtnl_handle *rth, | ||
62 | const struct rtnl_dump_filter_arg *arg); | ||
63 | extern int rtnl_dump_filter(struct rtnl_handle *rth, rtnl_filter_t filter, | ||
64 | void *arg); | ||
65 | extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, | ||
66 | unsigned groups, struct nlmsghdr *answer); | ||
67 | extern int rtnl_send(struct rtnl_handle *rth, const void *buf, int); | ||
68 | extern int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int); | ||
69 | |||
70 | extern int addattr(struct nlmsghdr *n, int maxlen, int type); | ||
71 | extern int addattr8(struct nlmsghdr *n, int maxlen, int type, __u8 data); | ||
72 | extern int addattr16(struct nlmsghdr *n, int maxlen, int type, __u16 data); | ||
73 | extern int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data); | ||
74 | extern int addattr64(struct nlmsghdr *n, int maxlen, int type, __u64 data); | ||
75 | extern int addattrstrz(struct nlmsghdr *n, int maxlen, int type, const char *data); | ||
76 | |||
77 | extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, int alen); | ||
78 | extern int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len); | ||
79 | extern struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type); | ||
80 | extern int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest); | ||
81 | extern struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type, const void *data, int len); | ||
82 | extern int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *nest); | ||
83 | extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data); | ||
84 | extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, const void *data, int alen); | ||
85 | |||
86 | extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len); | ||
87 | extern int parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta, | ||
88 | int len, unsigned short flags); | ||
89 | extern int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len); | ||
90 | extern int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta, int len); | ||
91 | |||
92 | #define parse_rtattr_nested(tb, max, rta) \ | ||
93 | (parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta))) | ||
94 | |||
95 | #define parse_rtattr_nested_compat(tb, max, rta, data, len) \ | ||
96 | ({ data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \ | ||
97 | __parse_rtattr_nested_compat(tb, max, rta, len); }) | ||
98 | |||
99 | static inline __u8 rta_getattr_u8(const struct rtattr *rta) | ||
100 | { | ||
101 | return *(__u8 *)RTA_DATA(rta); | ||
102 | } | ||
103 | static inline __u16 rta_getattr_u16(const struct rtattr *rta) | ||
104 | { | ||
105 | return *(__u16 *)RTA_DATA(rta); | ||
106 | } | ||
107 | static inline __u32 rta_getattr_u32(const struct rtattr *rta) | ||
108 | { | ||
109 | return *(__u32 *)RTA_DATA(rta); | ||
110 | } | ||
111 | static inline __u64 rta_getattr_u64(const struct rtattr *rta) | ||
112 | { | ||
113 | __u64 tmp; | ||
114 | memcpy(&tmp, RTA_DATA(rta), sizeof(__u64)); | ||
115 | return tmp; | ||
116 | } | ||
117 | static inline const char *rta_getattr_str(const struct rtattr *rta) | ||
118 | { | ||
119 | return (const char *)RTA_DATA(rta); | ||
120 | } | ||
121 | |||
122 | extern int rtnl_listen(struct rtnl_handle *, rtnl_filter_t handler, | ||
123 | void *jarg); | ||
124 | extern int rtnl_from_file(FILE *, rtnl_filter_t handler, | ||
125 | void *jarg); | ||
126 | |||
127 | #define NLMSG_TAIL(nmsg) \ | ||
128 | ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) | ||
129 | |||
130 | #ifndef IFA_RTA | ||
131 | #define IFA_RTA(r) \ | ||
132 | ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)))) | ||
133 | #endif | ||
134 | #ifndef IFA_PAYLOAD | ||
135 | #define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg)) | ||
136 | #endif | ||
137 | |||
138 | #ifndef IFLA_RTA | ||
139 | #define IFLA_RTA(r) \ | ||
140 | ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) | ||
141 | #endif | ||
142 | #ifndef IFLA_PAYLOAD | ||
143 | #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) | ||
144 | #endif | ||
145 | |||
146 | #ifndef NDA_RTA | ||
147 | #define NDA_RTA(r) \ | ||
148 | ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) | ||
149 | #endif | ||
150 | #ifndef NDA_PAYLOAD | ||
151 | #define NDA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndmsg)) | ||
152 | #endif | ||
153 | |||
154 | #ifndef NDTA_RTA | ||
155 | #define NDTA_RTA(r) \ | ||
156 | ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndtmsg)))) | ||
157 | #endif | ||
158 | #ifndef NDTA_PAYLOAD | ||
159 | #define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndtmsg)) | ||
160 | #endif | ||
161 | |||
162 | #endif /* __LIBNETLINK_H__ */ | ||
163 | |||
diff --git a/src/include/pid.h b/src/include/pid.h new file mode 100644 index 000000000..aaadaa542 --- /dev/null +++ b/src/include/pid.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 | #ifndef PID_H | ||
21 | #define PID_H | ||
22 | extern int max_pids; | ||
23 | |||
24 | |||
25 | #define _GNU_SOURCE | ||
26 | #include <stdio.h> | ||
27 | #include <sys/types.h> | ||
28 | #include <unistd.h> | ||
29 | typedef struct { | ||
30 | short level; // -1 not a firejail process, 0 not investigated yet, 1 firejail process, > 1 firejail child | ||
31 | unsigned char zombie; | ||
32 | pid_t parent; | ||
33 | uid_t uid; | ||
34 | char *user; | ||
35 | char *cmd; | ||
36 | unsigned utime; | ||
37 | unsigned stime; | ||
38 | unsigned long long rx; // network rx, bytes | ||
39 | unsigned long long tx; // networking tx, bytes | ||
40 | unsigned rx_delta; | ||
41 | unsigned tx_delta; | ||
42 | } Process; | ||
43 | //extern Process pids[max_pids]; | ||
44 | extern Process *pids; | ||
45 | |||
46 | // pid functions | ||
47 | void pid_getmem(unsigned pid, unsigned *rss, unsigned *shared); | ||
48 | void pid_get_cpu_time(unsigned pid, unsigned *utime, unsigned *stime); | ||
49 | unsigned long long pid_get_start_time(unsigned pid); | ||
50 | uid_t pid_get_uid(pid_t pid); | ||
51 | char *pid_get_user_name(uid_t uid); | ||
52 | // print functions | ||
53 | void pid_print_tree(unsigned index, unsigned parent, int nowrap); | ||
54 | void pid_print_list(unsigned index, int nowrap); | ||
55 | void pid_store_cpu(unsigned index, unsigned parent, unsigned *utime, unsigned *stime); | ||
56 | void pid_read(pid_t mon_pid); | ||
57 | |||
58 | #endif | ||
diff --git a/src/lib/Makefile.in b/src/lib/Makefile.in new file mode 100644 index 000000000..6e6be1910 --- /dev/null +++ b/src/lib/Makefile.in | |||
@@ -0,0 +1,20 @@ | |||
1 | PREFIX=@prefix@ | ||
2 | VERSION=@PACKAGE_VERSION@ | ||
3 | NAME=@PACKAGE_NAME@ | ||
4 | |||
5 | H_FILE_LIST = $(wildcard *.[h]) | ||
6 | C_FILE_LIST = $(wildcard *.c) | ||
7 | OBJS = $(C_FILE_LIST:.c=.o) | ||
8 | BINOBJS = $(foreach file, $(OBJS), $file) | ||
9 | CFLAGS += -ggdb -O2 -DVERSION='"$(VERSION)"' -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIC -Wformat -Wformat-security | ||
10 | LDFLAGS:=-pic -Wl,-z,relro -Wl,-z,now | ||
11 | |||
12 | all: $(OBJS) | ||
13 | |||
14 | %.o : %.c $(H_FILE_LIST) | ||
15 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ | ||
16 | |||
17 | clean:; rm -f $(OBJS) | ||
18 | |||
19 | distclean: clean | ||
20 | rm -fr Makefile | ||
diff --git a/src/lib/common.c b/src/lib/common.c new file mode 100644 index 000000000..6d928abbb --- /dev/null +++ b/src/lib/common.c | |||
@@ -0,0 +1,192 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 | #define _GNU_SOURCE | ||
21 | #include <stdio.h> | ||
22 | #include <sys/types.h> | ||
23 | #include <sys/stat.h> | ||
24 | #include <sys/wait.h> | ||
25 | #include <fcntl.h> | ||
26 | #include <sys/syscall.h> | ||
27 | #include <errno.h> | ||
28 | #include <unistd.h> | ||
29 | #include <sys/prctl.h> | ||
30 | #include <signal.h> | ||
31 | #include <dirent.h> | ||
32 | #include <string.h> | ||
33 | #include "../include/common.h" | ||
34 | |||
35 | int join_namespace(pid_t pid, char *type) { | ||
36 | char *path; | ||
37 | if (asprintf(&path, "/proc/%u/ns/%s", pid, type) == -1) | ||
38 | errExit("asprintf"); | ||
39 | |||
40 | int fd = open(path, O_RDONLY); | ||
41 | if (fd < 0) { | ||
42 | free(path); | ||
43 | fprintf(stderr, "Error: cannot open /proc/%u/ns/%s.\n", pid, type); | ||
44 | return -1; | ||
45 | } | ||
46 | |||
47 | if (syscall(__NR_setns, fd, 0) < 0) { | ||
48 | free(path); | ||
49 | fprintf(stderr, "Error: cannot join namespace %s.\n", type); | ||
50 | close(fd); | ||
51 | return -1; | ||
52 | } | ||
53 | |||
54 | close(fd); | ||
55 | free(path); | ||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | // return 1 if error | ||
60 | int name2pid(const char *name, pid_t *pid) { | ||
61 | pid_t parent = getpid(); | ||
62 | |||
63 | DIR *dir; | ||
64 | if (!(dir = opendir("/proc"))) { | ||
65 | // sleep 2 seconds and try again | ||
66 | sleep(2); | ||
67 | if (!(dir = opendir("/proc"))) { | ||
68 | fprintf(stderr, "Error: cannot open /proc directory\n"); | ||
69 | exit(1); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | struct dirent *entry; | ||
74 | char *end; | ||
75 | while ((entry = readdir(dir))) { | ||
76 | pid_t newpid = strtol(entry->d_name, &end, 10); | ||
77 | if (end == entry->d_name || *end) | ||
78 | continue; | ||
79 | if (newpid == parent) | ||
80 | continue; | ||
81 | |||
82 | // check if this is a firejail executable | ||
83 | char *comm = pid_proc_comm(newpid); | ||
84 | if (comm) { | ||
85 | // remove \n | ||
86 | char *ptr = strchr(comm, '\n'); | ||
87 | if (ptr) | ||
88 | *ptr = '\0'; | ||
89 | if (strcmp(comm, "firejail")) { | ||
90 | free(comm); | ||
91 | continue; | ||
92 | } | ||
93 | free(comm); | ||
94 | } | ||
95 | |||
96 | char *cmd = pid_proc_cmdline(newpid); | ||
97 | if (cmd) { | ||
98 | // mark the end of the name | ||
99 | char *ptr = strstr(cmd, "--name="); | ||
100 | char *start = ptr; | ||
101 | if (!ptr) { | ||
102 | free(cmd); | ||
103 | continue; | ||
104 | } | ||
105 | while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0') | ||
106 | ptr++; | ||
107 | *ptr = '\0'; | ||
108 | int rv = strcmp(start + 7, name); | ||
109 | if (rv == 0) { | ||
110 | free(cmd); | ||
111 | *pid = newpid; | ||
112 | closedir(dir); | ||
113 | return 0; | ||
114 | } | ||
115 | free(cmd); | ||
116 | } | ||
117 | } | ||
118 | closedir(dir); | ||
119 | return 1; | ||
120 | } | ||
121 | |||
122 | #define BUFLEN 4096 | ||
123 | char *pid_proc_comm(const pid_t pid) { | ||
124 | // open /proc/pid/cmdline file | ||
125 | char *fname; | ||
126 | int fd; | ||
127 | if (asprintf(&fname, "/proc/%d//comm", pid) == -1) | ||
128 | return NULL; | ||
129 | if ((fd = open(fname, O_RDONLY)) < 0) { | ||
130 | free(fname); | ||
131 | return NULL; | ||
132 | } | ||
133 | free(fname); | ||
134 | |||
135 | // read file | ||
136 | unsigned char buffer[BUFLEN]; | ||
137 | ssize_t len; | ||
138 | if ((len = read(fd, buffer, sizeof(buffer) - 1)) <= 0) { | ||
139 | close(fd); | ||
140 | return NULL; | ||
141 | } | ||
142 | buffer[len] = '\0'; | ||
143 | close(fd); | ||
144 | |||
145 | // return a malloc copy of the command line | ||
146 | char *rv = strdup((char *) buffer); | ||
147 | if (strlen(rv) == 0) { | ||
148 | free(rv); | ||
149 | return NULL; | ||
150 | } | ||
151 | return rv; | ||
152 | } | ||
153 | |||
154 | char *pid_proc_cmdline(const pid_t pid) { | ||
155 | // open /proc/pid/cmdline file | ||
156 | char *fname; | ||
157 | int fd; | ||
158 | if (asprintf(&fname, "/proc/%d/cmdline", pid) == -1) | ||
159 | return NULL; | ||
160 | if ((fd = open(fname, O_RDONLY)) < 0) { | ||
161 | free(fname); | ||
162 | return NULL; | ||
163 | } | ||
164 | free(fname); | ||
165 | |||
166 | // read file | ||
167 | unsigned char buffer[BUFLEN]; | ||
168 | ssize_t len; | ||
169 | if ((len = read(fd, buffer, sizeof(buffer) - 1)) <= 0) { | ||
170 | close(fd); | ||
171 | return NULL; | ||
172 | } | ||
173 | buffer[len] = '\0'; | ||
174 | close(fd); | ||
175 | |||
176 | // clean data | ||
177 | int i; | ||
178 | for (i = 0; i < len; i++) { | ||
179 | if (buffer[i] == '\0') | ||
180 | buffer[i] = ' '; | ||
181 | if (buffer[i] >= 0x80) // execv in progress!!! | ||
182 | return NULL; | ||
183 | } | ||
184 | |||
185 | // return a malloc copy of the command line | ||
186 | char *rv = strdup((char *) buffer); | ||
187 | if (strlen(rv) == 0) { | ||
188 | free(rv); | ||
189 | return NULL; | ||
190 | } | ||
191 | return rv; | ||
192 | } | ||
diff --git a/src/lib/libnetlink.c b/src/lib/libnetlink.c new file mode 100644 index 000000000..264632a01 --- /dev/null +++ b/src/lib/libnetlink.c | |||
@@ -0,0 +1,803 @@ | |||
1 | /* file extracted from iproute2 software package | ||
2 | * | ||
3 | * Original source code: | ||
4 | * | ||
5 | * Information: | ||
6 | * http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2 | ||
7 | * | ||
8 | * Download: | ||
9 | * http://www.kernel.org/pub/linux/utils/net/iproute2/ | ||
10 | * | ||
11 | * Repository: | ||
12 | * git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git | ||
13 | * | ||
14 | * License: GPL v2 | ||
15 | * | ||
16 | * Original copyright header | ||
17 | * | ||
18 | * libnetlink.c RTnetlink service routines. | ||
19 | * | ||
20 | * This program is free software; you can redistribute it and/or | ||
21 | * modify it under the terms of the GNU General Public License | ||
22 | * as published by the Free Software Foundation; either version | ||
23 | * 2 of the License, or (at your option) any later version. | ||
24 | * | ||
25 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | #include <stdio.h> | ||
30 | #include <stdlib.h> | ||
31 | #include <unistd.h> | ||
32 | #include <syslog.h> | ||
33 | #include <fcntl.h> | ||
34 | #include <net/if_arp.h> | ||
35 | #include <sys/socket.h> | ||
36 | #include <netinet/in.h> | ||
37 | #include <string.h> | ||
38 | #include <errno.h> | ||
39 | #include <time.h> | ||
40 | #include <sys/uio.h> | ||
41 | |||
42 | #include "../include/libnetlink.h" | ||
43 | |||
44 | int rcvbuf = 1024 * 1024; | ||
45 | |||
46 | void rtnl_close(struct rtnl_handle *rth) | ||
47 | { | ||
48 | if (rth->fd >= 0) { | ||
49 | close(rth->fd); | ||
50 | rth->fd = -1; | ||
51 | } | ||
52 | } | ||
53 | |||
54 | int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, | ||
55 | int protocol) | ||
56 | { | ||
57 | socklen_t addr_len; | ||
58 | int sndbuf = 32768; | ||
59 | |||
60 | memset(rth, 0, sizeof(*rth)); | ||
61 | |||
62 | rth->fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol); | ||
63 | if (rth->fd < 0) { | ||
64 | perror("Cannot open netlink socket"); | ||
65 | return -1; | ||
66 | } | ||
67 | |||
68 | if (setsockopt(rth->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) { | ||
69 | perror("SO_SNDBUF"); | ||
70 | return -1; | ||
71 | } | ||
72 | |||
73 | if (setsockopt(rth->fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf)) < 0) { | ||
74 | perror("SO_RCVBUF"); | ||
75 | return -1; | ||
76 | } | ||
77 | |||
78 | memset(&rth->local, 0, sizeof(rth->local)); | ||
79 | rth->local.nl_family = AF_NETLINK; | ||
80 | rth->local.nl_groups = subscriptions; | ||
81 | |||
82 | if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) { | ||
83 | perror("Cannot bind netlink socket"); | ||
84 | return -1; | ||
85 | } | ||
86 | addr_len = sizeof(rth->local); | ||
87 | if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) { | ||
88 | perror("Cannot getsockname"); | ||
89 | return -1; | ||
90 | } | ||
91 | if (addr_len != sizeof(rth->local)) { | ||
92 | fprintf(stderr, "Wrong address length %d\n", addr_len); | ||
93 | return -1; | ||
94 | } | ||
95 | if (rth->local.nl_family != AF_NETLINK) { | ||
96 | fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family); | ||
97 | return -1; | ||
98 | } | ||
99 | rth->seq = time(NULL); | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions) | ||
104 | { | ||
105 | return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE); | ||
106 | } | ||
107 | |||
108 | int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) | ||
109 | { | ||
110 | return rtnl_wilddump_req_filter(rth, family, type, RTEXT_FILTER_VF); | ||
111 | } | ||
112 | |||
113 | int rtnl_wilddump_req_filter(struct rtnl_handle *rth, int family, int type, | ||
114 | __u32 filt_mask) | ||
115 | { | ||
116 | struct { | ||
117 | struct nlmsghdr nlh; | ||
118 | struct ifinfomsg ifm; | ||
119 | /* attribute has to be NLMSG aligned */ | ||
120 | struct rtattr ext_req __attribute__ ((aligned(NLMSG_ALIGNTO))); | ||
121 | __u32 ext_filter_mask; | ||
122 | } req; | ||
123 | |||
124 | memset(&req, 0, sizeof(req)); | ||
125 | req.nlh.nlmsg_len = sizeof(req); | ||
126 | req.nlh.nlmsg_type = type; | ||
127 | req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST; | ||
128 | req.nlh.nlmsg_pid = 0; | ||
129 | req.nlh.nlmsg_seq = rth->dump = ++rth->seq; | ||
130 | req.ifm.ifi_family = family; | ||
131 | |||
132 | req.ext_req.rta_type = IFLA_EXT_MASK; | ||
133 | req.ext_req.rta_len = RTA_LENGTH(sizeof(__u32)); | ||
134 | req.ext_filter_mask = filt_mask; | ||
135 | |||
136 | return send(rth->fd, (void*)&req, sizeof(req), 0); | ||
137 | } | ||
138 | |||
139 | int rtnl_send(struct rtnl_handle *rth, const void *buf, int len) | ||
140 | { | ||
141 | return send(rth->fd, buf, len, 0); | ||
142 | } | ||
143 | |||
144 | int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len) | ||
145 | { | ||
146 | struct nlmsghdr *h; | ||
147 | int status; | ||
148 | char resp[1024]; | ||
149 | |||
150 | status = send(rth->fd, buf, len, 0); | ||
151 | if (status < 0) | ||
152 | return status; | ||
153 | |||
154 | /* Check for immediate errors */ | ||
155 | status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK); | ||
156 | if (status < 0) { | ||
157 | if (errno == EAGAIN) | ||
158 | return 0; | ||
159 | return -1; | ||
160 | } | ||
161 | |||
162 | for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status); | ||
163 | h = NLMSG_NEXT(h, status)) { | ||
164 | if (h->nlmsg_type == NLMSG_ERROR) { | ||
165 | struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); | ||
166 | if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) | ||
167 | fprintf(stderr, "ERROR truncated\n"); | ||
168 | else | ||
169 | errno = -err->error; | ||
170 | return -1; | ||
171 | } | ||
172 | } | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) | ||
178 | { | ||
179 | struct nlmsghdr nlh; | ||
180 | struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; | ||
181 | struct iovec iov[2] = { | ||
182 | { .iov_base = &nlh, .iov_len = sizeof(nlh) }, | ||
183 | { .iov_base = req, .iov_len = len } | ||
184 | }; | ||
185 | struct msghdr msg = { | ||
186 | .msg_name = &nladdr, | ||
187 | .msg_namelen = sizeof(nladdr), | ||
188 | .msg_iov = iov, | ||
189 | .msg_iovlen = 2, | ||
190 | }; | ||
191 | |||
192 | nlh.nlmsg_len = NLMSG_LENGTH(len); | ||
193 | nlh.nlmsg_type = type; | ||
194 | nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST; | ||
195 | nlh.nlmsg_pid = 0; | ||
196 | nlh.nlmsg_seq = rth->dump = ++rth->seq; | ||
197 | |||
198 | return sendmsg(rth->fd, &msg, 0); | ||
199 | } | ||
200 | |||
201 | int rtnl_dump_filter_l(struct rtnl_handle *rth, | ||
202 | const struct rtnl_dump_filter_arg *arg) | ||
203 | { | ||
204 | struct sockaddr_nl nladdr; | ||
205 | struct iovec iov; | ||
206 | struct msghdr msg = { | ||
207 | .msg_name = &nladdr, | ||
208 | .msg_namelen = sizeof(nladdr), | ||
209 | .msg_iov = &iov, | ||
210 | .msg_iovlen = 1, | ||
211 | }; | ||
212 | char buf[16384]; | ||
213 | int dump_intr = 0; | ||
214 | |||
215 | iov.iov_base = buf; | ||
216 | while (1) { | ||
217 | int status; | ||
218 | const struct rtnl_dump_filter_arg *a; | ||
219 | int found_done = 0; | ||
220 | int msglen = 0; | ||
221 | |||
222 | iov.iov_len = sizeof(buf); | ||
223 | status = recvmsg(rth->fd, &msg, 0); | ||
224 | |||
225 | if (status < 0) { | ||
226 | if (errno == EINTR || errno == EAGAIN) | ||
227 | continue; | ||
228 | fprintf(stderr, "netlink receive error %s (%d)\n", | ||
229 | strerror(errno), errno); | ||
230 | return -1; | ||
231 | } | ||
232 | |||
233 | if (status == 0) { | ||
234 | fprintf(stderr, "EOF on netlink\n"); | ||
235 | return -1; | ||
236 | } | ||
237 | |||
238 | for (a = arg; a->filter; a++) { | ||
239 | struct nlmsghdr *h = (struct nlmsghdr*)buf; | ||
240 | msglen = status; | ||
241 | |||
242 | while (NLMSG_OK(h, msglen)) { | ||
243 | int err; | ||
244 | |||
245 | if (nladdr.nl_pid != 0 || | ||
246 | h->nlmsg_pid != rth->local.nl_pid || | ||
247 | h->nlmsg_seq != rth->dump) | ||
248 | goto skip_it; | ||
249 | |||
250 | if (h->nlmsg_flags & NLM_F_DUMP_INTR) | ||
251 | dump_intr = 1; | ||
252 | |||
253 | if (h->nlmsg_type == NLMSG_DONE) { | ||
254 | found_done = 1; | ||
255 | break; /* process next filter */ | ||
256 | } | ||
257 | if (h->nlmsg_type == NLMSG_ERROR) { | ||
258 | struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); | ||
259 | if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { | ||
260 | fprintf(stderr, | ||
261 | "ERROR truncated\n"); | ||
262 | } else { | ||
263 | errno = -err->error; | ||
264 | perror("RTNETLINK answers"); | ||
265 | } | ||
266 | return -1; | ||
267 | } | ||
268 | err = a->filter(&nladdr, h, a->arg1); | ||
269 | if (err < 0) | ||
270 | return err; | ||
271 | |||
272 | skip_it: | ||
273 | h = NLMSG_NEXT(h, msglen); | ||
274 | } | ||
275 | } | ||
276 | |||
277 | if (found_done) { | ||
278 | if (dump_intr) | ||
279 | fprintf(stderr, | ||
280 | "Dump was interrupted and may be inconsistent.\n"); | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | if (msg.msg_flags & MSG_TRUNC) { | ||
285 | fprintf(stderr, "Message truncated\n"); | ||
286 | continue; | ||
287 | } | ||
288 | if (msglen) { | ||
289 | fprintf(stderr, "!!!Remnant of size %d\n", msglen); | ||
290 | exit(1); | ||
291 | } | ||
292 | } | ||
293 | } | ||
294 | |||
295 | int rtnl_dump_filter(struct rtnl_handle *rth, | ||
296 | rtnl_filter_t filter, | ||
297 | void *arg1) | ||
298 | { | ||
299 | const struct rtnl_dump_filter_arg a[2] = { | ||
300 | { .filter = filter, .arg1 = arg1, }, | ||
301 | { .filter = NULL, .arg1 = NULL, }, | ||
302 | }; | ||
303 | |||
304 | return rtnl_dump_filter_l(rth, a); | ||
305 | } | ||
306 | |||
307 | int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, | ||
308 | unsigned groups, struct nlmsghdr *answer) | ||
309 | { | ||
310 | int status; | ||
311 | unsigned seq; | ||
312 | struct nlmsghdr *h; | ||
313 | struct sockaddr_nl nladdr; | ||
314 | struct iovec iov = { | ||
315 | .iov_base = (void*) n, | ||
316 | .iov_len = n->nlmsg_len | ||
317 | }; | ||
318 | struct msghdr msg = { | ||
319 | .msg_name = &nladdr, | ||
320 | .msg_namelen = sizeof(nladdr), | ||
321 | .msg_iov = &iov, | ||
322 | .msg_iovlen = 1, | ||
323 | }; | ||
324 | char buf[16384]; | ||
325 | |||
326 | memset(&nladdr, 0, sizeof(nladdr)); | ||
327 | nladdr.nl_family = AF_NETLINK; | ||
328 | nladdr.nl_pid = peer; | ||
329 | nladdr.nl_groups = groups; | ||
330 | |||
331 | n->nlmsg_seq = seq = ++rtnl->seq; | ||
332 | |||
333 | if (answer == NULL) | ||
334 | n->nlmsg_flags |= NLM_F_ACK; | ||
335 | |||
336 | status = sendmsg(rtnl->fd, &msg, 0); | ||
337 | |||
338 | if (status < 0) { | ||
339 | perror("Cannot talk to rtnetlink"); | ||
340 | return -1; | ||
341 | } | ||
342 | |||
343 | memset(buf,0,sizeof(buf)); | ||
344 | |||
345 | iov.iov_base = buf; | ||
346 | |||
347 | while (1) { | ||
348 | iov.iov_len = sizeof(buf); | ||
349 | status = recvmsg(rtnl->fd, &msg, 0); | ||
350 | |||
351 | if (status < 0) { | ||
352 | if (errno == EINTR || errno == EAGAIN) | ||
353 | continue; | ||
354 | fprintf(stderr, "netlink receive error %s (%d)\n", | ||
355 | strerror(errno), errno); | ||
356 | return -1; | ||
357 | } | ||
358 | if (status == 0) { | ||
359 | fprintf(stderr, "EOF on netlink\n"); | ||
360 | return -1; | ||
361 | } | ||
362 | if (msg.msg_namelen != sizeof(nladdr)) { | ||
363 | fprintf(stderr, "sender address length == %d\n", msg.msg_namelen); | ||
364 | exit(1); | ||
365 | } | ||
366 | for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { | ||
367 | int len = h->nlmsg_len; | ||
368 | int l = len - sizeof(*h); | ||
369 | |||
370 | if (l < 0 || len>status) { | ||
371 | if (msg.msg_flags & MSG_TRUNC) { | ||
372 | fprintf(stderr, "Truncated message\n"); | ||
373 | return -1; | ||
374 | } | ||
375 | fprintf(stderr, "!!!malformed message: len=%d\n", len); | ||
376 | exit(1); | ||
377 | } | ||
378 | |||
379 | if (nladdr.nl_pid != peer || | ||
380 | h->nlmsg_pid != rtnl->local.nl_pid || | ||
381 | h->nlmsg_seq != seq) { | ||
382 | /* Don't forget to skip that message. */ | ||
383 | status -= NLMSG_ALIGN(len); | ||
384 | h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); | ||
385 | continue; | ||
386 | } | ||
387 | |||
388 | if (h->nlmsg_type == NLMSG_ERROR) { | ||
389 | struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); | ||
390 | if (l < sizeof(struct nlmsgerr)) { | ||
391 | fprintf(stderr, "ERROR truncated\n"); | ||
392 | } else { | ||
393 | if (!err->error) { | ||
394 | if (answer) | ||
395 | memcpy(answer, h, h->nlmsg_len); | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | fprintf(stderr, "RTNETLINK answers: %s\n", strerror(-err->error)); | ||
400 | errno = -err->error; | ||
401 | } | ||
402 | return -1; | ||
403 | } | ||
404 | if (answer) { | ||
405 | memcpy(answer, h, h->nlmsg_len); | ||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | fprintf(stderr, "Unexpected reply!!!\n"); | ||
410 | |||
411 | status -= NLMSG_ALIGN(len); | ||
412 | h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); | ||
413 | } | ||
414 | if (msg.msg_flags & MSG_TRUNC) { | ||
415 | fprintf(stderr, "Message truncated\n"); | ||
416 | continue; | ||
417 | } | ||
418 | if (status) { | ||
419 | fprintf(stderr, "!!!Remnant of size %d\n", status); | ||
420 | exit(1); | ||
421 | } | ||
422 | } | ||
423 | } | ||
424 | |||
425 | int rtnl_listen(struct rtnl_handle *rtnl, | ||
426 | rtnl_filter_t handler, | ||
427 | void *jarg) | ||
428 | { | ||
429 | int status; | ||
430 | struct nlmsghdr *h; | ||
431 | struct sockaddr_nl nladdr; | ||
432 | struct iovec iov; | ||
433 | struct msghdr msg = { | ||
434 | .msg_name = &nladdr, | ||
435 | .msg_namelen = sizeof(nladdr), | ||
436 | .msg_iov = &iov, | ||
437 | .msg_iovlen = 1, | ||
438 | }; | ||
439 | char buf[8192]; | ||
440 | |||
441 | memset(&nladdr, 0, sizeof(nladdr)); | ||
442 | nladdr.nl_family = AF_NETLINK; | ||
443 | nladdr.nl_pid = 0; | ||
444 | nladdr.nl_groups = 0; | ||
445 | |||
446 | iov.iov_base = buf; | ||
447 | while (1) { | ||
448 | iov.iov_len = sizeof(buf); | ||
449 | status = recvmsg(rtnl->fd, &msg, 0); | ||
450 | |||
451 | if (status < 0) { | ||
452 | if (errno == EINTR || errno == EAGAIN) | ||
453 | continue; | ||
454 | fprintf(stderr, "netlink receive error %s (%d)\n", | ||
455 | strerror(errno), errno); | ||
456 | if (errno == ENOBUFS) | ||
457 | continue; | ||
458 | return -1; | ||
459 | } | ||
460 | if (status == 0) { | ||
461 | fprintf(stderr, "EOF on netlink\n"); | ||
462 | return -1; | ||
463 | } | ||
464 | if (msg.msg_namelen != sizeof(nladdr)) { | ||
465 | fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen); | ||
466 | exit(1); | ||
467 | } | ||
468 | for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { | ||
469 | int err; | ||
470 | int len = h->nlmsg_len; | ||
471 | int l = len - sizeof(*h); | ||
472 | |||
473 | if (l<0 || len>status) { | ||
474 | if (msg.msg_flags & MSG_TRUNC) { | ||
475 | fprintf(stderr, "Truncated message\n"); | ||
476 | return -1; | ||
477 | } | ||
478 | fprintf(stderr, "!!!malformed message: len=%d\n", len); | ||
479 | exit(1); | ||
480 | } | ||
481 | |||
482 | err = handler(&nladdr, h, jarg); | ||
483 | if (err < 0) | ||
484 | return err; | ||
485 | |||
486 | status -= NLMSG_ALIGN(len); | ||
487 | h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); | ||
488 | } | ||
489 | if (msg.msg_flags & MSG_TRUNC) { | ||
490 | fprintf(stderr, "Message truncated\n"); | ||
491 | continue; | ||
492 | } | ||
493 | if (status) { | ||
494 | fprintf(stderr, "!!!Remnant of size %d\n", status); | ||
495 | exit(1); | ||
496 | } | ||
497 | } | ||
498 | } | ||
499 | |||
500 | int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler, | ||
501 | void *jarg) | ||
502 | { | ||
503 | int status; | ||
504 | struct sockaddr_nl nladdr; | ||
505 | char buf[8192]; | ||
506 | struct nlmsghdr *h = (void*)buf; | ||
507 | |||
508 | memset(&nladdr, 0, sizeof(nladdr)); | ||
509 | nladdr.nl_family = AF_NETLINK; | ||
510 | nladdr.nl_pid = 0; | ||
511 | nladdr.nl_groups = 0; | ||
512 | |||
513 | while (1) { | ||
514 | int err, len; | ||
515 | int l; | ||
516 | |||
517 | status = fread(&buf, 1, sizeof(*h), rtnl); | ||
518 | |||
519 | if (status < 0) { | ||
520 | if (errno == EINTR) | ||
521 | continue; | ||
522 | perror("rtnl_from_file: fread"); | ||
523 | return -1; | ||
524 | } | ||
525 | if (status == 0) | ||
526 | return 0; | ||
527 | |||
528 | len = h->nlmsg_len; | ||
529 | l = len - sizeof(*h); | ||
530 | |||
531 | if (l<0 || len>sizeof(buf)) { | ||
532 | fprintf(stderr, "!!!malformed message: len=%d @%lu\n", | ||
533 | len, ftell(rtnl)); | ||
534 | return -1; | ||
535 | } | ||
536 | |||
537 | status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl); | ||
538 | |||
539 | if (status < 0) { | ||
540 | perror("rtnl_from_file: fread"); | ||
541 | return -1; | ||
542 | } | ||
543 | if (status < l) { | ||
544 | fprintf(stderr, "rtnl-from_file: truncated message\n"); | ||
545 | return -1; | ||
546 | } | ||
547 | |||
548 | err = handler(&nladdr, h, jarg); | ||
549 | if (err < 0) | ||
550 | return err; | ||
551 | } | ||
552 | } | ||
553 | |||
554 | int addattr(struct nlmsghdr *n, int maxlen, int type) | ||
555 | { | ||
556 | return addattr_l(n, maxlen, type, NULL, 0); | ||
557 | } | ||
558 | |||
559 | int addattr8(struct nlmsghdr *n, int maxlen, int type, __u8 data) | ||
560 | { | ||
561 | return addattr_l(n, maxlen, type, &data, sizeof(__u8)); | ||
562 | } | ||
563 | |||
564 | int addattr16(struct nlmsghdr *n, int maxlen, int type, __u16 data) | ||
565 | { | ||
566 | return addattr_l(n, maxlen, type, &data, sizeof(__u16)); | ||
567 | } | ||
568 | |||
569 | int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data) | ||
570 | { | ||
571 | return addattr_l(n, maxlen, type, &data, sizeof(__u32)); | ||
572 | } | ||
573 | |||
574 | int addattr64(struct nlmsghdr *n, int maxlen, int type, __u64 data) | ||
575 | { | ||
576 | return addattr_l(n, maxlen, type, &data, sizeof(__u64)); | ||
577 | } | ||
578 | |||
579 | int addattrstrz(struct nlmsghdr *n, int maxlen, int type, const char *str) | ||
580 | { | ||
581 | return addattr_l(n, maxlen, type, str, strlen(str)+1); | ||
582 | } | ||
583 | |||
584 | |||
585 | |||
586 | int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, | ||
587 | int alen) | ||
588 | { | ||
589 | |||
590 | #if 0 | ||
591 | printf("%d: %s\n", __LINE__, __FUNCTION__); | ||
592 | printf("\ttype %d - ", type); | ||
593 | if (type == IFLA_LINK) { | ||
594 | printf("IFLA_LINK\n"); | ||
595 | int i; | ||
596 | printf("\tdata - "); | ||
597 | for (i = 0; i < alen; i++) | ||
598 | printf("%02x, ", *((unsigned char *)data + i)); | ||
599 | printf("\n"); | ||
600 | } | ||
601 | else if (type == IFLA_IFNAME) { | ||
602 | printf("IFLA_IFNAME\n"); | ||
603 | printf("\tdata - #%s#\n", data); | ||
604 | } | ||
605 | else if (type == IFLA_LINKINFO) printf("IFLA_LINKINFO\n"); | ||
606 | else if (type == IFLA_ADDRESS) { | ||
607 | printf("IFLA_ADDRESS or IFLA_INFO_KIND\n"); | ||
608 | int i; | ||
609 | printf("\tdata - "); | ||
610 | for (i = 0; i < alen; i++) | ||
611 | printf("%02x, ", *((unsigned char *)data + i)); | ||
612 | printf("\n"); | ||
613 | } | ||
614 | else if (type == IFLA_BROADCAST) printf("IFLA_BROADCAST or IFLA_INFO_DATA\n"); | ||
615 | |||
616 | printf("\tdata length: %d\n", alen); | ||
617 | #endif | ||
618 | |||
619 | int len = RTA_LENGTH(alen); | ||
620 | struct rtattr *rta; | ||
621 | |||
622 | if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { | ||
623 | fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen); | ||
624 | return -1; | ||
625 | } | ||
626 | rta = NLMSG_TAIL(n); | ||
627 | rta->rta_type = type; | ||
628 | rta->rta_len = len; | ||
629 | memcpy(RTA_DATA(rta), data, alen); | ||
630 | n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); | ||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | #if 0 | ||
635 | int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, | ||
636 | int alen) | ||
637 | { | ||
638 | printf("%s: adding type %d, length %d ", __FUNCTION__, type, alen); | ||
639 | if (type == IFLA_INFO_KIND) { | ||
640 | if (alen) | ||
641 | printf("(IFLA_INFO_KIND %s)\n", (char *)data); | ||
642 | else | ||
643 | printf("(VETH_INFO_PEER)\n"); | ||
644 | } | ||
645 | else if (type == IFLA_IFNAME) { | ||
646 | printf("(IFLA_IFNAME %s)\n", (char *) data); | ||
647 | } | ||
648 | else if (type == IFLA_NET_NS_PID) { | ||
649 | printf("(IFLA_NET_NS_PID %u)\n", *((unsigned *) data)); | ||
650 | } | ||
651 | else if (type == IFLA_LINKINFO) | ||
652 | printf("(IFLA_LINKINFO)\n"); | ||
653 | else if (type == IFLA_INFO_DATA) | ||
654 | printf("(IFLA_INFO_DATA)\n"); | ||
655 | else | ||
656 | printf("\n"); | ||
657 | |||
658 | int len = RTA_LENGTH(alen); | ||
659 | struct rtattr *rta; | ||
660 | |||
661 | if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { | ||
662 | fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen); | ||
663 | return -1; | ||
664 | } | ||
665 | rta = NLMSG_TAIL(n); | ||
666 | rta->rta_type = type; | ||
667 | rta->rta_len = len; | ||
668 | memcpy(RTA_DATA(rta), data, alen); | ||
669 | n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); | ||
670 | return 0; | ||
671 | } | ||
672 | #endif | ||
673 | |||
674 | int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len) | ||
675 | { | ||
676 | if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) { | ||
677 | fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen); | ||
678 | return -1; | ||
679 | } | ||
680 | |||
681 | memcpy(NLMSG_TAIL(n), data, len); | ||
682 | memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len); | ||
683 | n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len); | ||
684 | return 0; | ||
685 | } | ||
686 | |||
687 | struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type) | ||
688 | { | ||
689 | struct rtattr *nest = NLMSG_TAIL(n); | ||
690 | |||
691 | addattr_l(n, maxlen, type, NULL, 0); | ||
692 | return nest; | ||
693 | } | ||
694 | |||
695 | int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest) | ||
696 | { | ||
697 | nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest; | ||
698 | return n->nlmsg_len; | ||
699 | } | ||
700 | |||
701 | struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type, | ||
702 | const void *data, int len) | ||
703 | { | ||
704 | struct rtattr *start = NLMSG_TAIL(n); | ||
705 | |||
706 | addattr_l(n, maxlen, type, data, len); | ||
707 | addattr_nest(n, maxlen, type); | ||
708 | return start; | ||
709 | } | ||
710 | |||
711 | int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start) | ||
712 | { | ||
713 | struct rtattr *nest = (void *)start + NLMSG_ALIGN(start->rta_len); | ||
714 | |||
715 | start->rta_len = (void *)NLMSG_TAIL(n) - (void *)start; | ||
716 | addattr_nest_end(n, nest); | ||
717 | return n->nlmsg_len; | ||
718 | } | ||
719 | |||
720 | int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data) | ||
721 | { | ||
722 | int len = RTA_LENGTH(4); | ||
723 | struct rtattr *subrta; | ||
724 | |||
725 | if (RTA_ALIGN(rta->rta_len) + len > maxlen) { | ||
726 | fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen); | ||
727 | return -1; | ||
728 | } | ||
729 | subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); | ||
730 | subrta->rta_type = type; | ||
731 | subrta->rta_len = len; | ||
732 | memcpy(RTA_DATA(subrta), &data, 4); | ||
733 | rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len; | ||
734 | return 0; | ||
735 | } | ||
736 | |||
737 | int rta_addattr_l(struct rtattr *rta, int maxlen, int type, | ||
738 | const void *data, int alen) | ||
739 | { | ||
740 | struct rtattr *subrta; | ||
741 | int len = RTA_LENGTH(alen); | ||
742 | |||
743 | if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) { | ||
744 | fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen); | ||
745 | return -1; | ||
746 | } | ||
747 | subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); | ||
748 | subrta->rta_type = type; | ||
749 | subrta->rta_len = len; | ||
750 | memcpy(RTA_DATA(subrta), data, alen); | ||
751 | rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len); | ||
752 | return 0; | ||
753 | } | ||
754 | |||
755 | int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) | ||
756 | { | ||
757 | return parse_rtattr_flags(tb, max, rta, len, 0); | ||
758 | } | ||
759 | |||
760 | int parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta, | ||
761 | int len, unsigned short flags) | ||
762 | { | ||
763 | unsigned short type; | ||
764 | |||
765 | memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); | ||
766 | while (RTA_OK(rta, len)) { | ||
767 | type = rta->rta_type & ~flags; | ||
768 | if ((type <= max) && (!tb[type])) | ||
769 | tb[type] = rta; | ||
770 | rta = RTA_NEXT(rta,len); | ||
771 | } | ||
772 | if (len) | ||
773 | fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); | ||
774 | return 0; | ||
775 | } | ||
776 | |||
777 | int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len) | ||
778 | { | ||
779 | int i = 0; | ||
780 | |||
781 | memset(tb, 0, sizeof(struct rtattr *) * max); | ||
782 | while (RTA_OK(rta, len)) { | ||
783 | if (rta->rta_type <= max && i < max) | ||
784 | tb[i++] = rta; | ||
785 | rta = RTA_NEXT(rta,len); | ||
786 | } | ||
787 | if (len) | ||
788 | fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); | ||
789 | return i; | ||
790 | } | ||
791 | |||
792 | int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta, | ||
793 | int len) | ||
794 | { | ||
795 | if (RTA_PAYLOAD(rta) < len) | ||
796 | return -1; | ||
797 | if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) { | ||
798 | rta = RTA_DATA(rta) + RTA_ALIGN(len); | ||
799 | return parse_rtattr_nested(tb, max, rta); | ||
800 | } | ||
801 | memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); | ||
802 | return 0; | ||
803 | } | ||
diff --git a/src/lib/pid.c b/src/lib/pid.c new file mode 100644 index 000000000..a0261ead2 --- /dev/null +++ b/src/lib/pid.c | |||
@@ -0,0 +1,392 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 "../include/common.h" | ||
21 | #include "../include/pid.h" | ||
22 | #include <string.h> | ||
23 | #include <sys/types.h> | ||
24 | #include <pwd.h> | ||
25 | #include <sys/ioctl.h> | ||
26 | #include <dirent.h> | ||
27 | |||
28 | #define PIDS_BUFLEN 4096 | ||
29 | //Process pids[max_pids]; | ||
30 | Process *pids = NULL; | ||
31 | int max_pids=32769; | ||
32 | #define PIDS_BUFLEN 4096 | ||
33 | |||
34 | // get the memory associated with this pid | ||
35 | void pid_getmem(unsigned pid, unsigned *rss, unsigned *shared) { | ||
36 | // open stat file | ||
37 | char *file; | ||
38 | if (asprintf(&file, "/proc/%u/statm", pid) == -1) { | ||
39 | perror("asprintf"); | ||
40 | exit(1); | ||
41 | } | ||
42 | FILE *fp = fopen(file, "r"); | ||
43 | if (!fp) { | ||
44 | free(file); | ||
45 | return; | ||
46 | } | ||
47 | free(file); | ||
48 | |||
49 | unsigned a, b, c; | ||
50 | if (3 != fscanf(fp, "%u %u %u", &a, &b, &c)) { | ||
51 | fclose(fp); | ||
52 | return; | ||
53 | } | ||
54 | *rss += b; | ||
55 | *shared += c; | ||
56 | fclose(fp); | ||
57 | } | ||
58 | |||
59 | |||
60 | void pid_get_cpu_time(unsigned pid, unsigned *utime, unsigned *stime) { | ||
61 | // open stat file | ||
62 | char *file; | ||
63 | if (asprintf(&file, "/proc/%u/stat", pid) == -1) { | ||
64 | perror("asprintf"); | ||
65 | exit(1); | ||
66 | } | ||
67 | FILE *fp = fopen(file, "r"); | ||
68 | if (!fp) { | ||
69 | free(file); | ||
70 | return; | ||
71 | } | ||
72 | free(file); | ||
73 | |||
74 | char line[PIDS_BUFLEN]; | ||
75 | if (fgets(line, PIDS_BUFLEN - 1, fp)) { | ||
76 | char *ptr = line; | ||
77 | // jump 13 fields | ||
78 | int i; | ||
79 | for (i = 0; i < 13; i++) { | ||
80 | while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0') | ||
81 | ptr++; | ||
82 | if (*ptr == '\0') | ||
83 | goto myexit; | ||
84 | ptr++; | ||
85 | } | ||
86 | if (2 != sscanf(ptr, "%u %u", utime, stime)) | ||
87 | goto myexit; | ||
88 | } | ||
89 | |||
90 | myexit: | ||
91 | fclose(fp); | ||
92 | } | ||
93 | |||
94 | unsigned long long pid_get_start_time(unsigned pid) { | ||
95 | // open stat file | ||
96 | char *file; | ||
97 | if (asprintf(&file, "/proc/%u/stat", pid) == -1) { | ||
98 | perror("asprintf"); | ||
99 | exit(1); | ||
100 | } | ||
101 | FILE *fp = fopen(file, "r"); | ||
102 | if (!fp) { | ||
103 | free(file); | ||
104 | return 0; | ||
105 | } | ||
106 | free(file); | ||
107 | |||
108 | char line[PIDS_BUFLEN]; | ||
109 | unsigned long long retval = 0; | ||
110 | if (fgets(line, PIDS_BUFLEN - 1, fp)) { | ||
111 | char *ptr = line; | ||
112 | // jump 21 fields | ||
113 | int i; | ||
114 | for (i = 0; i < 21; i++) { | ||
115 | while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0') | ||
116 | ptr++; | ||
117 | if (*ptr == '\0') | ||
118 | goto myexit; | ||
119 | ptr++; | ||
120 | } | ||
121 | if (1 != sscanf(ptr, "%llu", &retval)) | ||
122 | goto myexit; | ||
123 | } | ||
124 | |||
125 | myexit: | ||
126 | fclose(fp); | ||
127 | return retval; | ||
128 | } | ||
129 | |||
130 | char *pid_get_user_name(uid_t uid) { | ||
131 | struct passwd *pw = getpwuid(uid); | ||
132 | if (pw) | ||
133 | return strdup(pw->pw_name); | ||
134 | return NULL; | ||
135 | } | ||
136 | |||
137 | uid_t pid_get_uid(pid_t pid) { | ||
138 | uid_t rv = 0; | ||
139 | |||
140 | // open stat file | ||
141 | char *file; | ||
142 | if (asprintf(&file, "/proc/%u/status", pid) == -1) { | ||
143 | perror("asprintf"); | ||
144 | exit(1); | ||
145 | } | ||
146 | FILE *fp = fopen(file, "r"); | ||
147 | if (!fp) { | ||
148 | free(file); | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | // look for firejail executable name | ||
153 | char buf[PIDS_BUFLEN]; | ||
154 | while (fgets(buf, PIDS_BUFLEN - 1, fp)) { | ||
155 | if (strncmp(buf, "Uid:", 4) == 0) { | ||
156 | char *ptr = buf + 5; | ||
157 | while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) { | ||
158 | ptr++; | ||
159 | } | ||
160 | if (*ptr == '\0') | ||
161 | goto doexit; | ||
162 | |||
163 | rv = atoi(ptr); | ||
164 | break; // break regardless! | ||
165 | } | ||
166 | } | ||
167 | doexit: | ||
168 | fclose(fp); | ||
169 | free(file); | ||
170 | return rv; | ||
171 | } | ||
172 | |||
173 | static void print_elem(unsigned index, int nowrap) { | ||
174 | // get terminal size | ||
175 | struct winsize sz; | ||
176 | int col = 0; | ||
177 | if (isatty(STDIN_FILENO)) { | ||
178 | if (!ioctl(0, TIOCGWINSZ, &sz)) | ||
179 | col = sz.ws_col; | ||
180 | } | ||
181 | |||
182 | // indent | ||
183 | char indent[(pids[index].level - 1) * 2 + 1]; | ||
184 | memset(indent, ' ', sizeof(indent)); | ||
185 | indent[(pids[index].level - 1) * 2] = '\0'; | ||
186 | |||
187 | // get data | ||
188 | uid_t uid = pids[index].uid; | ||
189 | char *cmd = pid_proc_cmdline(index); | ||
190 | char *user = pid_get_user_name(uid); | ||
191 | char *allocated = user; | ||
192 | if (user ==NULL) | ||
193 | user = ""; | ||
194 | if (cmd) { | ||
195 | if (col < 4 || nowrap) | ||
196 | printf("%s%u:%s:%s\n", indent, index, user, cmd); | ||
197 | else { | ||
198 | char *out; | ||
199 | if (asprintf(&out, "%s%u:%s:%s\n", indent, index, user, cmd) == -1) | ||
200 | errExit("asprintf"); | ||
201 | int len = strlen(out); | ||
202 | if (len > col) { | ||
203 | out[col] = '\0'; | ||
204 | out[col - 1] = '\n'; | ||
205 | } | ||
206 | printf("%s", out); | ||
207 | free(out); | ||
208 | } | ||
209 | |||
210 | free(cmd); | ||
211 | } | ||
212 | else { | ||
213 | if (pids[index].zombie) | ||
214 | printf("%s%u: (zombie)\n", indent, index); | ||
215 | else | ||
216 | printf("%s%u:\n", indent, index); | ||
217 | } | ||
218 | if (allocated) | ||
219 | free(allocated); | ||
220 | } | ||
221 | |||
222 | // recursivity!!! | ||
223 | void pid_print_tree(unsigned index, unsigned parent, int nowrap) { | ||
224 | print_elem(index, nowrap); | ||
225 | |||
226 | int i; | ||
227 | for (i = index + 1; i < max_pids; i++) { | ||
228 | if (pids[i].parent == index) | ||
229 | pid_print_tree(i, index, nowrap); | ||
230 | } | ||
231 | |||
232 | for (i = 0; i < index; i++) { | ||
233 | if (pids[i].parent == index) | ||
234 | pid_print_tree(i, index, nowrap); | ||
235 | } | ||
236 | } | ||
237 | |||
238 | void pid_print_list(unsigned index, int nowrap) { | ||
239 | print_elem(index, nowrap); | ||
240 | } | ||
241 | |||
242 | // recursivity!!! | ||
243 | void pid_store_cpu(unsigned index, unsigned parent, unsigned *utime, unsigned *stime) { | ||
244 | if (pids[index].level == 1) { | ||
245 | *utime = 0; | ||
246 | *stime = 0; | ||
247 | } | ||
248 | |||
249 | unsigned utmp = 0; | ||
250 | unsigned stmp = 0; | ||
251 | pid_get_cpu_time(index, &utmp, &stmp); | ||
252 | *utime += utmp; | ||
253 | *stime += stmp; | ||
254 | |||
255 | int i; | ||
256 | for (i = index + 1; i < max_pids; i++) { | ||
257 | if (pids[i].parent == index) | ||
258 | pid_store_cpu(i, index, utime, stime); | ||
259 | } | ||
260 | |||
261 | if (pids[index].level == 1) { | ||
262 | pids[index].utime = *utime; | ||
263 | pids[index].stime = *stime; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | // mon_pid: pid of sandbox to be monitored, 0 if all sandboxes are included | ||
268 | void pid_read(pid_t mon_pid) { | ||
269 | if (pids == NULL) { | ||
270 | FILE *fp = fopen("/proc/sys/kernel/pid_max", "r"); | ||
271 | if (fp) { | ||
272 | int val; | ||
273 | if (fscanf(fp, "%d", &val) == 1) { | ||
274 | if (val >= max_pids) | ||
275 | max_pids = val + 1; | ||
276 | } | ||
277 | fclose(fp); | ||
278 | } | ||
279 | pids = malloc(sizeof(Process) * max_pids); | ||
280 | if (pids == NULL) | ||
281 | errExit("malloc"); | ||
282 | } | ||
283 | memset(pids, 0, sizeof(Process) * max_pids); | ||
284 | pid_t mypid = getpid(); | ||
285 | |||
286 | DIR *dir; | ||
287 | if (!(dir = opendir("/proc"))) { | ||
288 | // sleep 2 seconds and try again | ||
289 | sleep(2); | ||
290 | if (!(dir = opendir("/proc"))) { | ||
291 | fprintf(stderr, "Error: cannot open /proc directory\n"); | ||
292 | exit(1); | ||
293 | } | ||
294 | } | ||
295 | |||
296 | pid_t child = -1; | ||
297 | struct dirent *entry; | ||
298 | char *end; | ||
299 | while (child < 0 && (entry = readdir(dir))) { | ||
300 | pid_t pid = strtol(entry->d_name, &end, 10); | ||
301 | pid %= max_pids; | ||
302 | if (end == entry->d_name || *end) | ||
303 | continue; | ||
304 | if (pid == mypid) | ||
305 | continue; | ||
306 | |||
307 | // open stat file | ||
308 | char *file; | ||
309 | if (asprintf(&file, "/proc/%u/status", pid) == -1) { | ||
310 | perror("asprintf"); | ||
311 | exit(1); | ||
312 | } | ||
313 | FILE *fp = fopen(file, "r"); | ||
314 | if (!fp) { | ||
315 | free(file); | ||
316 | continue; | ||
317 | } | ||
318 | |||
319 | // look for firejail executable name | ||
320 | char buf[PIDS_BUFLEN]; | ||
321 | while (fgets(buf, PIDS_BUFLEN - 1, fp)) { | ||
322 | if (strncmp(buf, "Name:", 5) == 0) { | ||
323 | char *ptr = buf + 5; | ||
324 | while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) { | ||
325 | ptr++; | ||
326 | } | ||
327 | if (*ptr == '\0') { | ||
328 | fprintf(stderr, "Error: cannot read /proc file\n"); | ||
329 | exit(1); | ||
330 | } | ||
331 | |||
332 | if (mon_pid == 0 && strncmp(ptr, "firejail", 8) == 0) { | ||
333 | pids[pid].level = 1; | ||
334 | } | ||
335 | else if (mon_pid == pid && strncmp(ptr, "firejail", 8) == 0) { | ||
336 | pids[pid].level = 1; | ||
337 | } | ||
338 | // else if (mon_pid == 0 && strncmp(ptr, "lxc-execute", 11) == 0) { | ||
339 | // pids[pid].level = 1; | ||
340 | // } | ||
341 | // else if (mon_pid == pid && strncmp(ptr, "lxc-execute", 11) == 0) { | ||
342 | // pids[pid].level = 1; | ||
343 | // } | ||
344 | else | ||
345 | pids[pid].level = -1; | ||
346 | } | ||
347 | if (strncmp(buf, "State:", 6) == 0) { | ||
348 | if (strstr(buf, "(zombie)")) | ||
349 | pids[pid].zombie = 1; | ||
350 | } | ||
351 | else if (strncmp(buf, "PPid:", 5) == 0) { | ||
352 | char *ptr = buf + 5; | ||
353 | while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) { | ||
354 | ptr++; | ||
355 | } | ||
356 | if (*ptr == '\0') { | ||
357 | fprintf(stderr, "Error: cannot read /proc file\n"); | ||
358 | exit(1); | ||
359 | } | ||
360 | unsigned parent = atoi(ptr); | ||
361 | parent %= max_pids; | ||
362 | if (pids[parent].level > 0) { | ||
363 | pids[pid].level = pids[parent].level + 1; | ||
364 | } | ||
365 | pids[pid].parent = parent; | ||
366 | } | ||
367 | else if (strncmp(buf, "Uid:", 4) == 0) { | ||
368 | char *ptr = buf + 5; | ||
369 | while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) { | ||
370 | ptr++; | ||
371 | } | ||
372 | if (*ptr == '\0') { | ||
373 | fprintf(stderr, "Error: cannot read /proc file\n"); | ||
374 | exit(1); | ||
375 | } | ||
376 | pids[pid].uid = atoi(ptr); | ||
377 | break; | ||
378 | } | ||
379 | } | ||
380 | fclose(fp); | ||
381 | free(file); | ||
382 | } | ||
383 | closedir(dir); | ||
384 | |||
385 | pid_t pid; | ||
386 | for (pid = 0; pid < max_pids; pid++) { | ||
387 | int parent = pids[pid].parent; | ||
388 | if (pids[parent].level > 0) { | ||
389 | pids[pid].level = pids[parent].level + 1; | ||
390 | } | ||
391 | } | ||
392 | } | ||
diff --git a/src/libtrace/Makefile.in b/src/libtrace/Makefile.in new file mode 100644 index 000000000..8848fc08c --- /dev/null +++ b/src/libtrace/Makefile.in | |||
@@ -0,0 +1,25 @@ | |||
1 | PREFIX=@prefix@ | ||
2 | VERSION=@PACKAGE_VERSION@ | ||
3 | NAME=@PACKAGE_NAME@ | ||
4 | |||
5 | H_FILE_LIST = $(wildcard *.[h]) | ||
6 | C_FILE_LIST = $(wildcard *.c) | ||
7 | OBJS = $(C_FILE_LIST:.c=.o) | ||
8 | BINOBJS = $(foreach file, $(OBJS), $file) | ||
9 | CFLAGS += -ggdb -O2 -DVERSION='"$(VERSION)"' -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIC -Wformat -Wformat-security | ||
10 | LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now | ||
11 | |||
12 | all: libtrace.so | ||
13 | |||
14 | %.o : %.c $(H_FILE_LIST) | ||
15 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ | ||
16 | |||
17 | # gcc -shared -fPIC -ldl traceopen.c -o traceopen.so | ||
18 | libtrace.so: $(OBJS) | ||
19 | $(CC) $(LDFLAGS) -shared -fPIC -z relro -o $@ $(OBJS) -ldl | ||
20 | |||
21 | |||
22 | clean:; rm -f $(OBJS) libtrace.so | ||
23 | |||
24 | distclean: clean | ||
25 | rm -fr Makefile | ||
diff --git a/src/libtrace/libtrace.c b/src/libtrace/libtrace.c new file mode 100644 index 000000000..a785ec698 --- /dev/null +++ b/src/libtrace/libtrace.c | |||
@@ -0,0 +1,609 @@ | |||
1 | #define _GNU_SOURCE | ||
2 | #include <stdio.h> | ||
3 | #include <stdlib.h> | ||
4 | #include <string.h> | ||
5 | #include <dlfcn.h> | ||
6 | #include <sys/types.h> | ||
7 | #include <unistd.h> | ||
8 | #include <sys/socket.h> | ||
9 | #include <netinet/in.h> | ||
10 | #include <arpa/inet.h> | ||
11 | #include <sys/un.h> | ||
12 | #include <sys/stat.h> | ||
13 | |||
14 | // break recursivity on fopen call | ||
15 | typedef FILE *(*orig_fopen_t)(const char *pathname, const char *mode); | ||
16 | static orig_fopen_t orig_fopen = NULL; | ||
17 | typedef FILE *(*orig_fopen64_t)(const char *pathname, const char *mode); | ||
18 | static orig_fopen64_t orig_fopen64 = NULL; | ||
19 | |||
20 | // | ||
21 | // pid | ||
22 | // | ||
23 | static pid_t mypid = 0; | ||
24 | static inline pid_t pid(void) { | ||
25 | if (!mypid) | ||
26 | mypid = getpid(); | ||
27 | return mypid; | ||
28 | } | ||
29 | |||
30 | // | ||
31 | // process name | ||
32 | // | ||
33 | #define MAXNAME 16 | ||
34 | static char myname[MAXNAME]; | ||
35 | static int nameinit = 0; | ||
36 | static char *name(void) { | ||
37 | if (!nameinit) { | ||
38 | // initialize the name of the process based on /proc/PID/comm | ||
39 | memset(myname, 0, MAXNAME); | ||
40 | |||
41 | pid_t p = pid(); | ||
42 | char *fname; | ||
43 | if (asprintf(&fname, "/proc/%u/comm", p) == -1) | ||
44 | return "unknown"; | ||
45 | |||
46 | // read file | ||
47 | if (!orig_fopen) | ||
48 | orig_fopen = (orig_fopen_t)dlsym(RTLD_NEXT, "fopen"); | ||
49 | FILE *fp = orig_fopen(fname, "r"); | ||
50 | if (!fp) | ||
51 | return "unknown"; | ||
52 | if (fgets(myname, MAXNAME, fp) == NULL) { | ||
53 | fclose(fp); | ||
54 | free(fname); | ||
55 | return "unknown"; | ||
56 | } | ||
57 | |||
58 | // clean '\n' | ||
59 | char *ptr = strchr(myname, '\n'); | ||
60 | if (ptr) | ||
61 | *ptr = '\0'; | ||
62 | |||
63 | fclose(fp); | ||
64 | free(fname); | ||
65 | nameinit = 1; | ||
66 | } | ||
67 | |||
68 | return myname; | ||
69 | } | ||
70 | |||
71 | // | ||
72 | // network | ||
73 | // | ||
74 | typedef struct { | ||
75 | int val; | ||
76 | char *name; | ||
77 | } XTable; | ||
78 | |||
79 | static XTable socket_type[] = { | ||
80 | #ifdef SOCK_STREAM | ||
81 | { SOCK_STREAM, "SOCK_STREAM" }, | ||
82 | #endif | ||
83 | #ifdef SOCK_DGRAM | ||
84 | { SOCK_DGRAM, "SOCK_DGRAM" }, | ||
85 | #endif | ||
86 | #ifdef SOCK_RAW | ||
87 | { SOCK_RAW, "SOCK_RAW" }, | ||
88 | #endif | ||
89 | #ifdef SOCK_RDM | ||
90 | { SOCK_RDM, "SOCK_RDM" }, | ||
91 | #endif | ||
92 | #ifdef SOCK_SEQPACKET | ||
93 | { SOCK_SEQPACKET, "SOCK_SEQPACKET" }, | ||
94 | #endif | ||
95 | #ifdef SOCK_DCCP | ||
96 | { SOCK_DCCP, "SOCK_DCCP" }, | ||
97 | #endif | ||
98 | { 0, NULL} // NULL terminated | ||
99 | }; | ||
100 | |||
101 | static XTable socket_domain[] = { | ||
102 | #ifdef AF_INET | ||
103 | { AF_INET, "AF_INET" }, | ||
104 | #endif | ||
105 | #ifdef AF_INET6 | ||
106 | { AF_INET6, "AF_INET6" }, | ||
107 | #endif | ||
108 | #ifdef AF_LOCAL | ||
109 | { AF_LOCAL, "AF_LOCAL" }, | ||
110 | #endif | ||
111 | #ifdef AF_PACKET | ||
112 | { AF_PACKET, "AF_PACKET" }, | ||
113 | #endif | ||
114 | #ifdef AF_IPX | ||
115 | { AF_IPX, "AF_IPX" }, | ||
116 | #endif | ||
117 | #ifdef AF_NETLINK | ||
118 | { AF_NETLINK, "AF_NETLINK" }, | ||
119 | #endif | ||
120 | #ifdef AF_X25 | ||
121 | { AF_X25, "AF_X25" }, | ||
122 | #endif | ||
123 | #ifdef AF_AX25 | ||
124 | { AF_AX25, "AF_AX25" }, | ||
125 | #endif | ||
126 | #ifdef AF_ATMPVC | ||
127 | { AF_ATMPVC, "AF_ATMPVC" }, | ||
128 | #endif | ||
129 | #ifdef AF_APPLETALK | ||
130 | { AF_APPLETALK, "AF_APPLETALK" }, | ||
131 | #endif | ||
132 | { 0, NULL} // NULL terminated | ||
133 | }; | ||
134 | |||
135 | static XTable socket_protocol[] = { | ||
136 | #ifdef IPPROTO_IP | ||
137 | { IPPROTO_IP, "IPPROTO_IP" }, | ||
138 | #endif | ||
139 | #ifdef IPPROTO_ICMP | ||
140 | { IPPROTO_ICMP, "IPPROTO_ICMP" }, | ||
141 | #endif | ||
142 | #ifdef IPPROTO_IGMP | ||
143 | { IPPROTO_IGMP, "IPPROTO_IGMP" }, | ||
144 | #endif | ||
145 | #ifdef IPPROTO_IPIP | ||
146 | { IPPROTO_IPIP, "IPPROTO_IPIP" }, | ||
147 | #endif | ||
148 | #ifdef IPPROTO_TCP | ||
149 | { IPPROTO_TCP, "IPPROTO_TCP" }, | ||
150 | #endif | ||
151 | #ifdef IPPROTO_EGP | ||
152 | { IPPROTO_EGP, "IPPROTO_EGP" }, | ||
153 | #endif | ||
154 | #ifdef IPPROTO_PUP | ||
155 | { IPPROTO_PUP, "IPPROTO_PUP" }, | ||
156 | #endif | ||
157 | #ifdef IPPROTO_UDP | ||
158 | { IPPROTO_UDP, "IPPROTO_UDP" }, | ||
159 | #endif | ||
160 | #ifdef IPPROTO_IDP | ||
161 | { IPPROTO_IDP, "IPPROTO_IDP" }, | ||
162 | #endif | ||
163 | #ifdef IPPROTO_DCCP | ||
164 | { IPPROTO_DCCP, "IPPROTO_DCCP" }, | ||
165 | #endif | ||
166 | #ifdef IPPROTO_RSVP | ||
167 | { IPPROTO_RSVP, "IPPROTO_RSVP" }, | ||
168 | #endif | ||
169 | #ifdef IPPROTO_GRE | ||
170 | { IPPROTO_GRE, "IPPROTO_GRE" }, | ||
171 | #endif | ||
172 | #ifdef IPPROTO_IPV6 | ||
173 | { IPPROTO_IPV6, "IPPROTO_IPV6" }, | ||
174 | #endif | ||
175 | #ifdef IPPROTO_ESP | ||
176 | { IPPROTO_ESP, "IPPROTO_ESP" }, | ||
177 | #endif | ||
178 | #ifdef IPPROTO_AH | ||
179 | { IPPROTO_AH, "IPPROTO_AH" }, | ||
180 | #endif | ||
181 | #ifdef IPPROTO_BEETPH | ||
182 | { IPPROTO_BEETPH, "IPPROTO_BEETPH" }, | ||
183 | #endif | ||
184 | #ifdef IPPROTO_PIM | ||
185 | { IPPROTO_PIM, "IPPROTO_PIM" }, | ||
186 | #endif | ||
187 | #ifdef IPPROTO_COMP | ||
188 | { IPPROTO_COMP, "IPPROTO_COMP" }, | ||
189 | #endif | ||
190 | #ifdef IPPROTO_SCTP | ||
191 | { IPPROTO_SCTP, "IPPROTO_SCTP" }, | ||
192 | #endif | ||
193 | #ifdef IPPROTO_UDPLITE | ||
194 | { IPPROTO_UDPLITE, "IPPROTO_UDPLITE" }, | ||
195 | #endif | ||
196 | #ifdef IPPROTO_RAW | ||
197 | { IPPROTO_RAW, "IPPROTO_RAW" }, | ||
198 | #endif | ||
199 | { 0, NULL} // NULL terminated | ||
200 | }; | ||
201 | |||
202 | static char *translate(XTable *table, int val) { | ||
203 | while (table->name != NULL) { | ||
204 | if (val == table->val) | ||
205 | return table->name; | ||
206 | table++; | ||
207 | } | ||
208 | |||
209 | return NULL; | ||
210 | } | ||
211 | |||
212 | static void print_sockaddr(const char *call, const struct sockaddr *addr) { | ||
213 | if (addr->sa_family == AF_INET) { | ||
214 | struct sockaddr_in *a = (struct sockaddr_in *) addr; | ||
215 | printf("%u:%s:%s %s:%u\n", pid(), name(), call, inet_ntoa(a->sin_addr), ntohs(a->sin_port)); | ||
216 | } | ||
217 | else if (addr->sa_family == AF_INET6) { | ||
218 | struct sockaddr_in6 *a = (struct sockaddr_in6 *) addr; | ||
219 | char str[INET6_ADDRSTRLEN]; | ||
220 | inet_ntop(AF_INET6, &(a->sin6_addr), str, INET6_ADDRSTRLEN); | ||
221 | printf("%u:%s:%s %s\n", pid(), name(), call, str); | ||
222 | } | ||
223 | else if (addr->sa_family == AF_UNIX) { | ||
224 | struct sockaddr_un *a = (struct sockaddr_un *) addr; | ||
225 | if (a->sun_path[0]) | ||
226 | printf("%u:%s:%s %s\n", pid(), name(), call, a->sun_path); | ||
227 | else | ||
228 | printf("%u:%s:%s @%s\n", pid(), name(), call, a->sun_path + 1); | ||
229 | } | ||
230 | else { | ||
231 | printf("%u:%s:%s family %d\n", pid(), name(), call, addr->sa_family); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | // | ||
236 | // syscalls | ||
237 | // | ||
238 | |||
239 | // open | ||
240 | typedef int (*orig_open_t)(const char *pathname, int flags, mode_t mode); | ||
241 | static orig_open_t orig_open = NULL; | ||
242 | int open(const char *pathname, int flags, mode_t mode) { | ||
243 | if (!orig_open) | ||
244 | orig_open = (orig_open_t)dlsym(RTLD_NEXT, "open"); | ||
245 | |||
246 | int rv = orig_open(pathname, flags, mode); | ||
247 | printf("%u:%s:open %s\n", pid(), name(), pathname); | ||
248 | return rv; | ||
249 | } | ||
250 | |||
251 | typedef int (*orig_open64_t)(const char *pathname, int flags, mode_t mode); | ||
252 | static orig_open64_t orig_open64 = NULL; | ||
253 | int open64(const char *pathname, int flags, mode_t mode) { | ||
254 | if (!orig_open64) | ||
255 | orig_open64 = (orig_open64_t)dlsym(RTLD_NEXT, "open64"); | ||
256 | |||
257 | int rv = orig_open64(pathname, flags, mode); | ||
258 | printf("%u:%s:open64 %s\n", pid(), name(), pathname); | ||
259 | return rv; | ||
260 | } | ||
261 | |||
262 | // openat | ||
263 | typedef int (*orig_openat_t)(int dirfd, const char *pathname, int flags, mode_t mode); | ||
264 | static orig_openat_t orig_openat = NULL; | ||
265 | int openat(int dirfd, const char *pathname, int flags, mode_t mode) { | ||
266 | if (!orig_openat) | ||
267 | orig_openat = (orig_openat_t)dlsym(RTLD_NEXT, "openat"); | ||
268 | |||
269 | int rv = orig_openat(dirfd, pathname, flags, mode); | ||
270 | printf("%u:%s:openat %s\n", pid(), name(), pathname); | ||
271 | return rv; | ||
272 | } | ||
273 | |||
274 | typedef int (*orig_openat64_t)(int dirfd, const char *pathname, int flags, mode_t mode); | ||
275 | static orig_openat64_t orig_openat64 = NULL; | ||
276 | int openat64(int dirfd, const char *pathname, int flags, mode_t mode) { | ||
277 | if (!orig_openat64) | ||
278 | orig_openat64 = (orig_openat64_t)dlsym(RTLD_NEXT, "openat64"); | ||
279 | |||
280 | int rv = orig_openat64(dirfd, pathname, flags, mode); | ||
281 | printf("%u:%s:openat64 %s\n", pid(), name(), pathname); | ||
282 | return rv; | ||
283 | } | ||
284 | |||
285 | |||
286 | // fopen | ||
287 | FILE *fopen(const char *pathname, const char *mode) { | ||
288 | if (!orig_fopen) | ||
289 | orig_fopen = (orig_fopen_t)dlsym(RTLD_NEXT, "fopen"); | ||
290 | |||
291 | FILE *rv = orig_fopen(pathname, mode); | ||
292 | printf("%u:%s:fopen %s\n", pid(), name(), pathname); | ||
293 | return rv; | ||
294 | } | ||
295 | |||
296 | FILE *fopen64(const char *pathname, const char *mode) { | ||
297 | if (!orig_fopen64) | ||
298 | orig_fopen64 = (orig_fopen_t)dlsym(RTLD_NEXT, "fopen64"); | ||
299 | |||
300 | FILE *rv = orig_fopen64(pathname, mode); | ||
301 | printf("%u:%s:fopen64 %s\n", pid(), name(), pathname); | ||
302 | return rv; | ||
303 | } | ||
304 | |||
305 | |||
306 | // freopen | ||
307 | typedef FILE *(*orig_freopen_t)(const char *pathname, const char *mode, FILE *stream); | ||
308 | static orig_freopen_t orig_freopen = NULL; | ||
309 | FILE *freopen(const char *pathname, const char *mode, FILE *stream) { | ||
310 | if (!orig_freopen) | ||
311 | orig_freopen = (orig_freopen_t)dlsym(RTLD_NEXT, "freopen"); | ||
312 | |||
313 | FILE *rv = orig_freopen(pathname, mode, stream); | ||
314 | printf("%u:%s:freopen %s\n", pid(), name(), pathname); | ||
315 | return rv; | ||
316 | } | ||
317 | |||
318 | typedef FILE *(*orig_freopen64_t)(const char *pathname, const char *mode, FILE *stream); | ||
319 | static orig_freopen64_t orig_freopen64 = NULL; | ||
320 | FILE *freopen64(const char *pathname, const char *mode, FILE *stream) { | ||
321 | if (!orig_freopen64) | ||
322 | orig_freopen64 = (orig_freopen64_t)dlsym(RTLD_NEXT, "freopen64"); | ||
323 | |||
324 | FILE *rv = orig_freopen64(pathname, mode, stream); | ||
325 | printf("%u:%s:freopen64 %s\n", pid(), name(), pathname); | ||
326 | return rv; | ||
327 | } | ||
328 | |||
329 | // unlink | ||
330 | typedef int (*orig_unlink_t)(const char *pathname); | ||
331 | static orig_unlink_t orig_unlink = NULL; | ||
332 | int unlink(const char *pathname) { | ||
333 | if (!orig_unlink) | ||
334 | orig_unlink = (orig_unlink_t)dlsym(RTLD_NEXT, "unlink"); | ||
335 | |||
336 | int rv = orig_unlink(pathname); | ||
337 | printf("%u:%s:unlink %s\n", pid(), name(), pathname); | ||
338 | return rv; | ||
339 | } | ||
340 | |||
341 | typedef int (*orig_unlinkat_t)(int dirfd, const char *pathname, int flags); | ||
342 | static orig_unlinkat_t orig_unlinkat = NULL; | ||
343 | int unlinkat(int dirfd, const char *pathname, int flags) { | ||
344 | if (!orig_unlinkat) | ||
345 | orig_unlinkat = (orig_unlinkat_t)dlsym(RTLD_NEXT, "unlinkat"); | ||
346 | |||
347 | int rv = orig_unlinkat(dirfd, pathname, flags); | ||
348 | printf("%u:%s:unlinkat %s\n", pid(), name(), pathname); | ||
349 | return rv; | ||
350 | } | ||
351 | |||
352 | // mkdir/mkdirat/rmdir | ||
353 | typedef int (*orig_mkdir_t)(const char *pathname, mode_t mode); | ||
354 | static orig_mkdir_t orig_mkdir = NULL; | ||
355 | int mkdir(const char *pathname, mode_t mode) { | ||
356 | if (!orig_mkdir) | ||
357 | orig_mkdir = (orig_mkdir_t)dlsym(RTLD_NEXT, "mkdir"); | ||
358 | |||
359 | int rv = orig_mkdir(pathname, mode); | ||
360 | printf("%u:%s:mkdir %s\n", pid(), name(), pathname); | ||
361 | return rv; | ||
362 | } | ||
363 | |||
364 | typedef int (*orig_mkdirat_t)(int dirfd, const char *pathname, mode_t mode); | ||
365 | static orig_mkdirat_t orig_mkdirat = NULL; | ||
366 | int mkdirat(int dirfd, const char *pathname, mode_t mode) { | ||
367 | if (!orig_mkdirat) | ||
368 | orig_mkdirat = (orig_mkdirat_t)dlsym(RTLD_NEXT, "mkdirat"); | ||
369 | |||
370 | int rv = orig_mkdirat(dirfd, pathname, mode); | ||
371 | printf("%u:%s:mkdirat %s\n", pid(), name(), pathname); | ||
372 | return rv; | ||
373 | } | ||
374 | |||
375 | typedef int (*orig_rmdir_t)(const char *pathname); | ||
376 | static orig_rmdir_t orig_rmdir = NULL; | ||
377 | int rmdir(const char *pathname) { | ||
378 | if (!orig_rmdir) | ||
379 | orig_rmdir = (orig_rmdir_t)dlsym(RTLD_NEXT, "rmdir"); | ||
380 | |||
381 | int rv = orig_rmdir(pathname); | ||
382 | printf("%u:%s:rmdir %s\n", pid(), name(), pathname); | ||
383 | return rv; | ||
384 | } | ||
385 | |||
386 | // stat | ||
387 | typedef int (*orig_stat_t)(const char *pathname, struct stat *buf); | ||
388 | static orig_stat_t orig_stat = NULL; | ||
389 | int stat(const char *pathname, struct stat *buf) { | ||
390 | if (!orig_stat) | ||
391 | orig_stat = (orig_stat_t)dlsym(RTLD_NEXT, "stat"); | ||
392 | |||
393 | int rv = orig_stat(pathname, buf); | ||
394 | printf("%u:%s:stat %s\n", pid(), name(), pathname); | ||
395 | return rv; | ||
396 | } | ||
397 | |||
398 | typedef int (*orig_stat64_t)(const char *pathname, struct stat64 *buf); | ||
399 | static orig_stat64_t orig_stat64 = NULL; | ||
400 | int stat64(const char *pathname, struct stat64 *buf) { | ||
401 | if (!orig_stat) | ||
402 | orig_stat64 = (orig_stat64_t)dlsym(RTLD_NEXT, "stat"); | ||
403 | |||
404 | int rv = orig_stat64(pathname, buf); | ||
405 | printf("%u:%s:stat %s\n", pid(), name(), pathname); | ||
406 | return rv; | ||
407 | } | ||
408 | |||
409 | |||
410 | // access | ||
411 | typedef int (*orig_access_t)(const char *pathname, int mode); | ||
412 | static orig_access_t orig_access = NULL; | ||
413 | int access(const char *pathname, int mode) { | ||
414 | if (!orig_access) | ||
415 | orig_access = (orig_access_t)dlsym(RTLD_NEXT, "access"); | ||
416 | |||
417 | int rv = orig_access(pathname, mode); | ||
418 | printf("%u:%s:access %s\n", pid(), name(), pathname); | ||
419 | return rv; | ||
420 | } | ||
421 | |||
422 | |||
423 | // connect | ||
424 | typedef int (*orig_connect_t)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); | ||
425 | static orig_connect_t orig_connect = NULL; | ||
426 | int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { | ||
427 | if (!orig_connect) | ||
428 | orig_connect = (orig_connect_t)dlsym(RTLD_NEXT, "connect"); | ||
429 | |||
430 | int rv = orig_connect(sockfd, addr, addrlen); | ||
431 | print_sockaddr("connect", addr); | ||
432 | |||
433 | return rv; | ||
434 | } | ||
435 | |||
436 | // socket | ||
437 | typedef int (*orig_socket_t)(int domain, int type, int protocol); | ||
438 | static orig_socket_t orig_socket = NULL; | ||
439 | static char buf[1024]; | ||
440 | int socket(int domain, int type, int protocol) { | ||
441 | if (!orig_socket) | ||
442 | orig_socket = (orig_socket_t)dlsym(RTLD_NEXT, "socket"); | ||
443 | |||
444 | int rv = orig_socket(domain, type, protocol); | ||
445 | char *ptr = buf; | ||
446 | ptr += sprintf(ptr, "%u:%s:socket ", pid(), name()); | ||
447 | char *str = translate(socket_domain, domain); | ||
448 | if (str == NULL) | ||
449 | ptr += sprintf(ptr, "%d ", domain); | ||
450 | else | ||
451 | ptr += sprintf(ptr, "%s ", str); | ||
452 | |||
453 | int t = type; // glibc uses higher bits for various other purposes | ||
454 | #ifdef SOCK_CLOEXEC | ||
455 | t &= ~SOCK_CLOEXEC; | ||
456 | #endif | ||
457 | #ifdef SOCK_NONBLOCK | ||
458 | t &= ~SOCK_NONBLOCK; | ||
459 | #endif | ||
460 | str = translate(socket_type, t); | ||
461 | if (str == NULL) | ||
462 | ptr += sprintf(ptr, "%d ", type); | ||
463 | else | ||
464 | ptr += sprintf(ptr, "%s ", str); | ||
465 | |||
466 | str = translate(socket_protocol, protocol); | ||
467 | if (str == NULL) | ||
468 | ptr += sprintf(ptr, "%d", protocol); | ||
469 | else | ||
470 | ptr += sprintf(ptr, "%s", str); | ||
471 | |||
472 | printf("%s\n", buf); | ||
473 | return rv; | ||
474 | } | ||
475 | |||
476 | // bind | ||
477 | typedef int (*orig_bind_t)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); | ||
478 | static orig_bind_t orig_bind = NULL; | ||
479 | int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { | ||
480 | if (!orig_bind) | ||
481 | orig_bind = (orig_bind_t)dlsym(RTLD_NEXT, "bind"); | ||
482 | |||
483 | int rv = orig_bind(sockfd, addr, addrlen); | ||
484 | print_sockaddr("bind", addr); | ||
485 | |||
486 | return rv; | ||
487 | } | ||
488 | |||
489 | #if 0 //todo: fix compilation problems | ||
490 | typedef int (*orig_accept_t)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); | ||
491 | static orig_accept_t orig_accept = NULL; | ||
492 | int accept(int sockfd, struct sockaddr *addr, socklen_t addrlen) { | ||
493 | if (!orig_accept) | ||
494 | orig_accept = (orig_accept_t)dlsym(RTLD_NEXT, "accept"); | ||
495 | |||
496 | int rv = orig_accept(sockfd, addr, addrlen); | ||
497 | print_sockaddr("accept", addr); | ||
498 | |||
499 | return rv; | ||
500 | } | ||
501 | #endif | ||
502 | |||
503 | typedef int (*orig_system_t)(const char *command); | ||
504 | static orig_system_t orig_system = NULL; | ||
505 | int system(const char *command) { | ||
506 | if (!orig_system) | ||
507 | orig_system = (orig_system_t)dlsym(RTLD_NEXT, "system"); | ||
508 | |||
509 | int rv = orig_system(command); | ||
510 | printf("%u:%s:system %s\n", pid(), name(), command); | ||
511 | |||
512 | return rv; | ||
513 | } | ||
514 | |||
515 | typedef int (*orig_setuid_t)(uid_t uid); | ||
516 | static orig_setuid_t orig_setuid = NULL; | ||
517 | int setuid(uid_t uid) { | ||
518 | if (!orig_setuid) | ||
519 | orig_setuid = (orig_setuid_t)dlsym(RTLD_NEXT, "setuid"); | ||
520 | |||
521 | int rv = orig_setuid(uid); | ||
522 | printf("%u:%s:setuid %d\n", pid(), name(), uid); | ||
523 | |||
524 | return rv; | ||
525 | } | ||
526 | |||
527 | typedef int (*orig_setgid_t)(gid_t gid); | ||
528 | static orig_setgid_t orig_setgid = NULL; | ||
529 | int setgid(gid_t gid) { | ||
530 | if (!orig_setgid) | ||
531 | orig_setgid = (orig_setgid_t)dlsym(RTLD_NEXT, "setgid"); | ||
532 | |||
533 | int rv = orig_setgid(gid); | ||
534 | printf("%u:%s:setgid %d\n", pid(), name(), gid); | ||
535 | |||
536 | return rv; | ||
537 | } | ||
538 | |||
539 | typedef int (*orig_setfsuid_t)(uid_t uid); | ||
540 | static orig_setfsuid_t orig_setfsuid = NULL; | ||
541 | int setfsuid(uid_t uid) { | ||
542 | if (!orig_setfsuid) | ||
543 | orig_setfsuid = (orig_setfsuid_t)dlsym(RTLD_NEXT, "setfsuid"); | ||
544 | |||
545 | int rv = orig_setfsuid(uid); | ||
546 | printf("%u:%s:setfsuid %d\n", pid(), name(), uid); | ||
547 | |||
548 | return rv; | ||
549 | } | ||
550 | |||
551 | typedef int (*orig_setfsgid_t)(gid_t gid); | ||
552 | static orig_setfsgid_t orig_setfsgid = NULL; | ||
553 | int setfsgid(gid_t gid) { | ||
554 | if (!orig_setfsgid) | ||
555 | orig_setfsgid = (orig_setfsgid_t)dlsym(RTLD_NEXT, "setfsgid"); | ||
556 | |||
557 | int rv = orig_setfsgid(gid); | ||
558 | printf("%u:%s:setfsgid %d\n", pid(), name(), gid); | ||
559 | |||
560 | return rv; | ||
561 | } | ||
562 | |||
563 | typedef int (*orig_setreuid_t)(uid_t ruid, uid_t euid); | ||
564 | static orig_setreuid_t orig_setreuid = NULL; | ||
565 | int setreuid(uid_t ruid, uid_t euid) { | ||
566 | if (!orig_setreuid) | ||
567 | orig_setreuid = (orig_setreuid_t)dlsym(RTLD_NEXT, "setreuid"); | ||
568 | |||
569 | int rv = orig_setreuid(ruid, euid); | ||
570 | printf("%u:%s:setreuid %d %d\n", pid(), name(), ruid, euid); | ||
571 | |||
572 | return rv; | ||
573 | } | ||
574 | |||
575 | typedef int (*orig_setregid_t)(gid_t rgid, gid_t egid); | ||
576 | static orig_setregid_t orig_setregid = NULL; | ||
577 | int setregid(gid_t rgid, gid_t egid) { | ||
578 | if (!orig_setregid) | ||
579 | orig_setregid = (orig_setregid_t)dlsym(RTLD_NEXT, "setregid"); | ||
580 | |||
581 | int rv = orig_setregid(rgid, egid); | ||
582 | printf("%u:%s:setregid %d %d\n", pid(), name(), rgid, egid); | ||
583 | |||
584 | return rv; | ||
585 | } | ||
586 | |||
587 | typedef int (*orig_setresuid_t)(uid_t ruid, uid_t euid, uid_t suid); | ||
588 | static orig_setresuid_t orig_setresuid = NULL; | ||
589 | int setresuid(uid_t ruid, uid_t euid, uid_t suid) { | ||
590 | if (!orig_setresuid) | ||
591 | orig_setresuid = (orig_setresuid_t)dlsym(RTLD_NEXT, "setresuid"); | ||
592 | |||
593 | int rv = orig_setresuid(ruid, euid, suid); | ||
594 | printf("%u:%s:setresuid %d %d %d\n", pid(), name(), ruid, euid, suid); | ||
595 | |||
596 | return rv; | ||
597 | } | ||
598 | |||
599 | typedef int (*orig_setresgid_t)(gid_t rgid, gid_t egid, gid_t sgid); | ||
600 | static orig_setresgid_t orig_setresgid = NULL; | ||
601 | int setresgid(gid_t rgid, gid_t egid, gid_t sgid) { | ||
602 | if (!orig_setresgid) | ||
603 | orig_setresgid = (orig_setresgid_t)dlsym(RTLD_NEXT, "setresgid"); | ||
604 | |||
605 | int rv = orig_setresgid(rgid, egid, sgid); | ||
606 | printf("%u:%s:setresgid %d %d %d\n", pid(), name(), rgid, egid, sgid); | ||
607 | |||
608 | return rv; | ||
609 | } \ No newline at end of file | ||
diff --git a/src/man/firejail-login.txt b/src/man/firejail-login.txt new file mode 100644 index 000000000..6613dc044 --- /dev/null +++ b/src/man/firejail-login.txt | |||
@@ -0,0 +1,36 @@ | |||
1 | .TH man 5 "MONTH YEAR" "VERSION" "firejail login.users man page" | ||
2 | .SH NAME | ||
3 | login.users \- Login file syntax for Firejail | ||
4 | |||
5 | .SH DESCRIPTION | ||
6 | /etc/firejail/login.users file describes additional arguments passed to firejail executable | ||
7 | upon user logging into a Firejail restircted shell. Each user entry in the file consists of | ||
8 | a user name followed by the arguments passed to firejail. The format is as follows: | ||
9 | |||
10 | user_name: arguments | ||
11 | |||
12 | Example: | ||
13 | |||
14 | netblue:--debug --net=none | ||
15 | |||
16 | .SH RESTRICTED SHELL | ||
17 | To configure a restricted shell, replace /bin/bash with /usr/bin/firejail in | ||
18 | /etc/password file for each user that needs to be restricted. Alternatively, | ||
19 | you can specify /usr/bin/firejail in adduser command: | ||
20 | |||
21 | adduser \-\-shell /usr/bin/firejail username | ||
22 | |||
23 | .SH FILES | ||
24 | /etc/firejail/login.users | ||
25 | |||
26 | .SH LICENSE | ||
27 | Firejail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. | ||
28 | .PP | ||
29 | Homepage: http://firejail.sourceforge.net | ||
30 | .SH SEE ALSO | ||
31 | \&\flfirejail\fR\|(1), | ||
32 | \&\flfiremon\fR\|(1), | ||
33 | \&\flfirejail-profile\fR\|(5) | ||
34 | |||
35 | |||
36 | |||
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt new file mode 100644 index 000000000..46da19ecd --- /dev/null +++ b/src/man/firejail-profile.txt | |||
@@ -0,0 +1,181 @@ | |||
1 | .TH man 5 "MONTH YEAR" "VERSION" "firejail profiles man page" | ||
2 | .SH NAME | ||
3 | profile \- Profile file syntax for Firejail | ||
4 | |||
5 | .SH USAGE | ||
6 | .TP | ||
7 | firejail \-\-profile=filename.profile | ||
8 | |||
9 | .SH DESCRIPTION | ||
10 | Several Firejail command line configuration options can be passed to the program using | ||
11 | profile files. Default Firejail profile files are stored in /etc/firejail | ||
12 | directory and ~/.config/firejail directory. | ||
13 | |||
14 | .SH Scripting | ||
15 | Include and comment support: | ||
16 | |||
17 | .TP | ||
18 | \f\include other.profile | ||
19 | Include other.profile file. | ||
20 | .TP | ||
21 | # this is a comment | ||
22 | |||
23 | .SH Filesystem | ||
24 | These profile entries define a chroot filesystem built on top of the existing | ||
25 | host filesystem. Each line describes a file element that is removed from | ||
26 | the filesystem (\fBblacklist\fR), a read-only file or directory (\fBread-only\fR), | ||
27 | a tmpfs mounted on top of an existing directory (\fBtmpfs\fR), | ||
28 | or mount-bind a directory or file on top of another directory or file (\fBbind\fR). | ||
29 | Use \fBprivate\fR to set private mode. | ||
30 | File globbing is supported, and PATH and HOME directories are searched. | ||
31 | Examples: | ||
32 | .TP | ||
33 | \f\blacklist /usr/bin | ||
34 | Remove /usr/bin directory. | ||
35 | .TP | ||
36 | \f\blacklist /etc/password | ||
37 | Remove /etc/password file. | ||
38 | .TP | ||
39 | \f\read-only /etc/password | ||
40 | Read-only /etc/password file. | ||
41 | .TP | ||
42 | tmpfs /etc | ||
43 | Mount an empty tmpfs filesystem on top of /etc directory. | ||
44 | .TP | ||
45 | bind /root/config/ssh,/etc/ssh | ||
46 | Mount-bind /root/config/ssh on /etc/ssh. | ||
47 | .TP | ||
48 | \f\blacklist /usr/bin/gcc* | ||
49 | Remove all gcc files in /usr/bin (file globbing). | ||
50 | .TP | ||
51 | \f\blacklist ${PATH}/ifconfig | ||
52 | Remove ifconfig command from the regular path directories. | ||
53 | .TP | ||
54 | \f\blacklist ${HOME}/.ssh | ||
55 | Remove .ssh directory from user home directory. | ||
56 | .TP | ||
57 | \f\private | ||
58 | Mount new /root and /home/user directories in temporary | ||
59 | filesystems. All modifications are discarded when the sandbox is | ||
60 | closed. | ||
61 | .TP | ||
62 | \f\private directory | ||
63 | Use directory as user home. | ||
64 | .TP | ||
65 | \f\private.keep file,directory | ||
66 | Build a new user home in a temporary | ||
67 | filesystem, and copy the files and directories in the list in the | ||
68 | new home. All modifications are discarded when the sandbox is | ||
69 | closed. | ||
70 | .TP | ||
71 | \f\private-dev | ||
72 | Create a new /dev directory. Only null, full, zero, tty, pts, ptmx, random, urandom and shm devices are available. | ||
73 | |||
74 | .SH Filters | ||
75 | \fBcaps\fR and \fBseccomp\fR enable Linux capabilities and seccomp filters. Examples: | ||
76 | |||
77 | .TP | ||
78 | caps | ||
79 | Enable default Linux capabilities filter. | ||
80 | .TP | ||
81 | caps.drop all | ||
82 | Blacklist all Linux capabilities. | ||
83 | .TP | ||
84 | caps.drop capability,capability,capability | ||
85 | Blacklist Linux capabilities filter. | ||
86 | .TP | ||
87 | caps.drop capability,capability,capability | ||
88 | Whitelist Linux capabilities filter. | ||
89 | .TP | ||
90 | \f\seccomp | ||
91 | Enable default seccomp filter. | ||
92 | .TP | ||
93 | \f\seccomp syscall,syscall,syscall | ||
94 | Enable seccomp filter and blacklist the system calls in the list on top of default seccomp filter. | ||
95 | .TP | ||
96 | \f\seccomp.drop syscall,syscall,syscall | ||
97 | Enable seccomp filter and blacklist the system calls in the list. | ||
98 | .TP | ||
99 | \f\seccomp.keep syscall,syscall,syscall | ||
100 | Enable seccomp filter and whitelist the system calls in the list. | ||
101 | |||
102 | |||
103 | .SH User Namespace | ||
104 | Use \fBnoroot\fR to enable an user namespace. The namespace has only one user, the current user. | ||
105 | There is no root account defined in the namespace. | ||
106 | |||
107 | .TP | ||
108 | noroot | ||
109 | Enable an user namespace without root user defined. | ||
110 | |||
111 | |||
112 | .SH Resource limits | ||
113 | These profile entries define the limits on system resources (rlimits) for the processes inside the sandbox. | ||
114 | The limits can be modified inside the sandbox using the regular \fBulimt\fR command. Examples: | ||
115 | |||
116 | .TP | ||
117 | \f\rlimit-fsize 1024 | ||
118 | Set the maximum file size that can be created by a process to 1024 bytes. | ||
119 | .TP | ||
120 | \f\rlimit-nproc 1000 | ||
121 | Set the maximum number of processes that can be created for the real user ID of the calling process to 1000. | ||
122 | .TP | ||
123 | \f\rlimit-nofile 500 | ||
124 | Set the maximum number of files that can be opened by a process to 500. | ||
125 | .TP | ||
126 | \f\rlimit-sigpending 200 | ||
127 | Set the maximum number of processes that can be created for the real user ID of the calling process to 200. | ||
128 | |||
129 | .SH CPU Affinity | ||
130 | Set the CPU cores available for this sandbox. Examples: | ||
131 | |||
132 | .TP | ||
133 | cpu 1,2,3 | ||
134 | Use only CPU cores 0, 1 and 2. | ||
135 | |||
136 | .SH Control Groups | ||
137 | Place the sandbox in an existing control group specified by the full path of the task file. Example: | ||
138 | |||
139 | .TP | ||
140 | cgroup /sys/fs/cgroup/g1/tasks | ||
141 | The sandbox is placed in g1 control group. | ||
142 | |||
143 | .SH User Environment | ||
144 | |||
145 | .TP | ||
146 | nogroups | ||
147 | Disable supplementary user groups | ||
148 | .TP | ||
149 | shell none | ||
150 | Run the program directly, without a shell. | ||
151 | |||
152 | .SH Networking | ||
153 | Networking features available in profile files. | ||
154 | |||
155 | .TP | ||
156 | netfilter | ||
157 | If a new network namespace is created, enabled default network filter. | ||
158 | |||
159 | .TP | ||
160 | netfilter filename | ||
161 | If a new network namespace is created, enabled the network filter in filename. | ||
162 | |||
163 | .TP | ||
164 | dns address | ||
165 | Set a DNS server for the sandbox. Up to three DNS servers can be defined. | ||
166 | |||
167 | |||
168 | .SH FILES | ||
169 | /etc/firejail/filename.profile, $HOME/.config/firejail/filename.profile | ||
170 | |||
171 | .SH LICENSE | ||
172 | Firejail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. | ||
173 | .PP | ||
174 | Homepage: http://firejail.sourceforge.net | ||
175 | .SH SEE ALSO | ||
176 | \&\flfirejail\fR\|(1), | ||
177 | \&\flfiremon\fR\|(1), | ||
178 | \&\flfirejail-login\fR\|(5) | ||
179 | |||
180 | |||
181 | |||
diff --git a/src/man/firejail.txt b/src/man/firejail.txt new file mode 100644 index 000000000..51f21975e --- /dev/null +++ b/src/man/firejail.txt | |||
@@ -0,0 +1,1196 @@ | |||
1 | .TH man 1 "MONTH YEAR" "VERSION" "firejail man page" | ||
2 | .SH NAME | ||
3 | Firejail \- Linux namespaces sandbox program | ||
4 | .SH SYNOPSIS | ||
5 | Start a sandbox: | ||
6 | .PP | ||
7 | .RS | ||
8 | firejail [OPTIONS] [program and arguments] | ||
9 | .RE | ||
10 | .PP | ||
11 | Network traffic shaping for an existing sandbox: | ||
12 | .PP | ||
13 | .RS | ||
14 | firejail \-\-bandwidth={<name>|<PID>} bandwidth-command | ||
15 | .RE | ||
16 | .PP | ||
17 | Monitoring: | ||
18 | .PP | ||
19 | .RS | ||
20 | firejail {\-\-list | \-\-netstats | \-\-top | \-\-tree} | ||
21 | .RE | ||
22 | .PP | ||
23 | Miscellaneous: | ||
24 | .PP | ||
25 | .RS | ||
26 | firejail {\-? | \-\-debug-caps | \-\-debug-syscalls | \-\-help | | ||
27 | .br | ||
28 | \-\-version} | ||
29 | .RE | ||
30 | .SH DESCRIPTION | ||
31 | Firejail is a SUID sandbox program that reduces the risk of security breaches by | ||
32 | restricting the running environment of untrusted applications using Linux | ||
33 | namespaces, seccomp-bpf and Linux capabilities. | ||
34 | It allows a process and all its descendants to have their own private view of the | ||
35 | globally shared kernel resources, such as the network stack, process table, mount table. | ||
36 | Firejail can work in a SELinux or AppArmor environment, | ||
37 | and it is integrated with Linux Control Groups. | ||
38 | .PP | ||
39 | Written in C with virtually no dependencies, the software runs on any Linux computer with a 3.x kernel version | ||
40 | or newer. | ||
41 | It can sandbox any type of processes: servers, graphical applications, and even user login sessions. | ||
42 | The software includes sandbox profiles for a number of more common | ||
43 | Linux programs, such as Mozilla Firefox, Chromium, VLC, Transmission etc. | ||
44 | .SH USAGE | ||
45 | Without any options, the sandbox consists of a chroot filesystem build in a new mount namespace, | ||
46 | and new PID and UTS namespaces. IPC, network and user namespaces can be added using the command line options. | ||
47 | The default Firejail filesystem is based on the host filesystem with the main directories mounted read-only. | ||
48 | Only /home, /tmp and /var directories are writable. | ||
49 | .PP | ||
50 | If no program is specified as an argument, /bin/bash is started by default. | ||
51 | Examples: | ||
52 | .PP | ||
53 | $ firejail [OPTIONS] # starting a /bin/bash shell | ||
54 | .PP | ||
55 | $ firejail [OPTIONS] firefox # starting Mozilla Firefox | ||
56 | .PP | ||
57 | Multiple commands can be run in sandbox using regular bash logic operators: | ||
58 | .PP | ||
59 | $ sudo firejail [OPTIONS] "/etc/init.d/nginx start && sleep inf" | ||
60 | .PP | ||
61 | In the previous example, "sleep inf" command is required in order to keep the session open for the daemon program. | ||
62 | |||
63 | .SH OPTIONS | ||
64 | .TP | ||
65 | \fB\-\- | ||
66 | Signal the end of options and disables further option processing. | ||
67 | .TP | ||
68 | \fB\-\-bandwidth=name | ||
69 | Set bandwidth limits for the sandbox identified by name, see TRAFFIC SHAPING section for more details. | ||
70 | .TP | ||
71 | \fB\-\-bandwidth=pid | ||
72 | Set bandwidth limits for the sandbox identified by PID, see TRAFFIC SHAPING section for more details. | ||
73 | .TP | ||
74 | \fB\-\-bind=dirname1,dirname2 | ||
75 | Mount-bind dirname1 on top of dirname2. This option is only available when running the sandbox as root. | ||
76 | .br | ||
77 | |||
78 | .br | ||
79 | Example: | ||
80 | .br | ||
81 | # firejail \-\-bind=/config/www,/var/www | ||
82 | .TP | ||
83 | \fB\-\-bind=filename1,filename2 | ||
84 | Mount-bind filename1 on top of filename2. This option is only available when running as root. | ||
85 | .br | ||
86 | |||
87 | .br | ||
88 | Example: | ||
89 | .br | ||
90 | # firejail \-\-bind=/config/etc/passwd,/etc/passwd | ||
91 | .TP | ||
92 | \fB\-\-blacklist=dirname_or_filename | ||
93 | Blacklist directory or file. | ||
94 | .br | ||
95 | |||
96 | .br | ||
97 | Example: | ||
98 | .br | ||
99 | $ firejail \-\-blacklist=/sbin \-\-blacklist=/usr/sbin | ||
100 | .TP | ||
101 | \fB\-c | ||
102 | Execute command and exit. | ||
103 | .TP | ||
104 | \fB\-\-caps | ||
105 | Linux capabilities is a kernel feature designed to split up the root privilege into a set of distinct privileges. | ||
106 | These privileges can be enabled or disabled independently, thus restricting what a process running | ||
107 | as root can do in the system. | ||
108 | |||
109 | By default root programs run with all capabilities enabled. \-\-caps option disables the following capabilities: | ||
110 | CAP_SYS_MODULE, CAP_SYS_RAWIO, | ||
111 | CAP_SYS_BOOT, CAP_SYS_NICE, CAP_SYS_TTY_CONFIG, CAP_SYSLOG, CAP_MKNOD, CAP_SYS_ADMIN. | ||
112 | The filter is applied to all processes started in the sandbox. | ||
113 | .br | ||
114 | |||
115 | .br | ||
116 | Example: | ||
117 | .br | ||
118 | $ sudo firejail \-\-caps "/etc/init.d/nginx start && sleep inf" | ||
119 | |||
120 | .TP | ||
121 | \fB\-\-caps.drop=all | ||
122 | Drop all capabilities for the processes running in the sandbox. This option is recommended for running GUI programs | ||
123 | or any other program that doesn't require root privileges. It is a must-have option for sandboxing untrusted programs | ||
124 | installed from unofficial sources - such as games, Java programs, etc. | ||
125 | .br | ||
126 | |||
127 | .br | ||
128 | Example: | ||
129 | .br | ||
130 | $ firejail \-\-caps.drop=all warzone2100 | ||
131 | |||
132 | .TP | ||
133 | \fB\-\-caps.drop=capability,capability,capability | ||
134 | Define a custom blacklist Linux capabilities filter. | ||
135 | .br | ||
136 | |||
137 | .br | ||
138 | Example: | ||
139 | .br | ||
140 | $ firejail \-\-caps.keep=net_broadcast,net_admin,net_raw | ||
141 | |||
142 | .TP | ||
143 | \fB\-\-caps.keep=capability,capability,capability | ||
144 | Define a custom whitelist Linux capabilities filter. | ||
145 | .br | ||
146 | |||
147 | .br | ||
148 | Example: | ||
149 | .br | ||
150 | $ sudo firejail \-\-caps.keep=chown,net_bind_service,setgid,\\ | ||
151 | setuid "/etc/init.d/nginx start && sleep inf" | ||
152 | |||
153 | .TP | ||
154 | \fB\-\-caps.print=name | ||
155 | Print the caps filter for the sandbox identified by name. | ||
156 | .br | ||
157 | |||
158 | .br | ||
159 | Example: | ||
160 | .br | ||
161 | $ firejail \-\-name=mygame \-\-caps.drop=all warzone2100 & | ||
162 | .br | ||
163 | [...] | ||
164 | .br | ||
165 | $ firejail \-\-caps.print=mygame | ||
166 | |||
167 | .TP | ||
168 | \fB\-\-caps.print=pid | ||
169 | Print the caps filter for a sandbox identified by PID. | ||
170 | .br | ||
171 | |||
172 | .br | ||
173 | Example: | ||
174 | .br | ||
175 | $ firejail \-\-list | ||
176 | .br | ||
177 | 3272:netblue:firejail \-\-private firefox | ||
178 | .br | ||
179 | $ firejail \-\-caps.print=3272 | ||
180 | |||
181 | .TP | ||
182 | \fB\-\-cgroup=tasks-file | ||
183 | Place the sandbox in the specified control group. tasks-file is the full path of cgroup tasks file. | ||
184 | .br | ||
185 | |||
186 | .br | ||
187 | Example: | ||
188 | .br | ||
189 | # firejail \-\-cgroup=/sys/fs/cgroup/g1/tasks | ||
190 | |||
191 | .TP | ||
192 | \fB\-\-chroot=dirname | ||
193 | Chroot the sandbox into a root filesystem. If the sandbox is started as a | ||
194 | regular user, default seccomp and capabilities filters are eanbled. | ||
195 | .br | ||
196 | |||
197 | .br | ||
198 | Example: | ||
199 | .br | ||
200 | $ firejail \-\-chroot=/media/ubuntu warzone2100 | ||
201 | |||
202 | .TP | ||
203 | \fB\-\-cpu=cpu-number,cpu-number,cpu-number | ||
204 | Set CPU affinity. | ||
205 | .br | ||
206 | |||
207 | .br | ||
208 | Example: | ||
209 | .br | ||
210 | $ firejail \-\-cpu=0,1 handbrake | ||
211 | |||
212 | .TP | ||
213 | \fB\-\-csh | ||
214 | Use /bin/csh as default user shell. | ||
215 | .br | ||
216 | |||
217 | .br | ||
218 | Example: | ||
219 | .br | ||
220 | $ firejail \-\-csh | ||
221 | .TP | ||
222 | \fB\-\-debug\fR | ||
223 | Print debug messages. | ||
224 | .br | ||
225 | |||
226 | .br | ||
227 | Example: | ||
228 | .br | ||
229 | $ firejail \-\-debug firefox | ||
230 | .TP | ||
231 | \fB\-\-debug-syscalls | ||
232 | Print all recognized system calls in the current Firejail software build and exit. | ||
233 | .br | ||
234 | |||
235 | .br | ||
236 | Example: | ||
237 | .br | ||
238 | $ firejail \-\-debug-syscalls | ||
239 | .TP | ||
240 | \fB\-\-debug-caps | ||
241 | Print all recognized capabilities in the current Firejail software build and exit. | ||
242 | .br | ||
243 | |||
244 | .br | ||
245 | Example: | ||
246 | .br | ||
247 | $ firejail \-\-debug-caps | ||
248 | .TP | ||
249 | \fB\-\-defaultgw=address | ||
250 | Use this address as default gateway in the new network namespace. | ||
251 | .br | ||
252 | |||
253 | .br | ||
254 | Example: | ||
255 | .br | ||
256 | $ firejail \-\-net=eth0 \-\-defaultgw=10.10.20.1 firefox | ||
257 | |||
258 | .TP | ||
259 | \fB\-\-dns=address | ||
260 | Set a DNS server for the sandbox. Up to three DNS servers can be defined. | ||
261 | Use this option if you don't trust the DNS setup on your network. | ||
262 | .br | ||
263 | |||
264 | .br | ||
265 | Example: | ||
266 | .br | ||
267 | $ firejail \-\-dns=8.8.8.8 \-\-dns=8.8.4.4 firefox | ||
268 | |||
269 | .TP | ||
270 | \fB\-\-dns.print=name | ||
271 | Print DNS configuration for a sandbox identified by name. | ||
272 | .br | ||
273 | |||
274 | .br | ||
275 | Example: | ||
276 | .br | ||
277 | $ firejail \-\-name=mygame \-\-caps.drop=all warzone2100 & | ||
278 | .br | ||
279 | [...] | ||
280 | .br | ||
281 | $ firejail \-\-dns.print=mygame | ||
282 | |||
283 | .TP | ||
284 | \fB\-\-dns.print=pid | ||
285 | Print DNS configuration for a sandbox identified by PID. | ||
286 | .br | ||
287 | |||
288 | .br | ||
289 | Example: | ||
290 | .br | ||
291 | $ firejail \-\-list | ||
292 | .br | ||
293 | 3272:netblue:firejail \-\-private firefox | ||
294 | .br | ||
295 | $ firejail \-\-dns.print=3272 | ||
296 | |||
297 | .TP | ||
298 | \fB\-?\fR, \fB\-\-help\fR | ||
299 | Print options end exit. | ||
300 | .TP | ||
301 | \fB\-\-ip=address | ||
302 | Assign IP addresses to the last network interface defined by a \-\-net option. A | ||
303 | default gateway is assigned by default. | ||
304 | .br | ||
305 | |||
306 | .br | ||
307 | Example: | ||
308 | .br | ||
309 | $ firejail \-\-net=eth0 \-\-ip=10.10.20.56 firefox | ||
310 | |||
311 | .TP | ||
312 | \fB\-\-ip=none | ||
313 | No IP address and no default gateway are configured for the last interface | ||
314 | defined by a \-\-net option. Use this option | ||
315 | in case you intend to start an external DHCP client in the sandbox. | ||
316 | .br | ||
317 | |||
318 | .br | ||
319 | Example: | ||
320 | .br | ||
321 | $ firejail \-\-net=eth0 \-\-\ip=none | ||
322 | |||
323 | .TP | ||
324 | \fB\-\-iprange=address,address | ||
325 | Assign an IP address in the provided range to the last network interface defined by a \-\-net option. A | ||
326 | default gateway is assigned by default. | ||
327 | .br | ||
328 | |||
329 | .br | ||
330 | Example: | ||
331 | .br | ||
332 | $ firejail \-\-net=eth0 \-\-\iprange=192.168.1.100,192.168.1.150 | ||
333 | |||
334 | .TP | ||
335 | \fB\-\-ipc-namespace | ||
336 | Enable a new IPC namespace if the sandbox was started as a regular user. IPC namespace is enabled by default | ||
337 | for sandboxes started as root. | ||
338 | .br | ||
339 | |||
340 | .br | ||
341 | Example: | ||
342 | .br | ||
343 | $ firejail \-\-ipc-namespace firefox | ||
344 | .TP | ||
345 | \fB\-\-join=name | ||
346 | Join the sandbox identified by name. By default a /bin/bash shell is started after joining the sandbox. | ||
347 | If a program is specified, the program is run in the sandbox. | ||
348 | .br | ||
349 | |||
350 | .br | ||
351 | Example: | ||
352 | .br | ||
353 | $ firejail \-\-name=mygame \-\-caps.drop=all warzone2100 & | ||
354 | .br | ||
355 | [...] | ||
356 | .br | ||
357 | $ firejail \-\-join=mygame | ||
358 | |||
359 | |||
360 | .TP | ||
361 | \fB\-\-join=pid | ||
362 | Join the sandbox identified by PID. By default a /bin/bash shell is started after joining the sandbox. | ||
363 | If a program is specified, the program is run in the sandbox. | ||
364 | .br | ||
365 | |||
366 | .br | ||
367 | Example: | ||
368 | .br | ||
369 | $ firejail \-\-list | ||
370 | .br | ||
371 | 3272:netblue:firejail \-\-private firefox | ||
372 | .br | ||
373 | $ firejail \-\-join=3272 | ||
374 | |||
375 | .TP | ||
376 | \fB\-\-list | ||
377 | List all sandboxes, see MONITORING section for more details. | ||
378 | .br | ||
379 | |||
380 | .br | ||
381 | Example: | ||
382 | .br | ||
383 | $ firejail \-\-list | ||
384 | .br | ||
385 | 7015:netblue:firejail firefox | ||
386 | .br | ||
387 | 7056:netblue:firejail \-\-net=eth0 transmission-gtk | ||
388 | .br | ||
389 | 7064:netblue:firejail \-\-noroot xterm | ||
390 | .br | ||
391 | $ | ||
392 | .TP | ||
393 | \fB\-\-mac=address | ||
394 | Assign MAC addresses to the last network interface defined by a \-\-net option. | ||
395 | .br | ||
396 | |||
397 | .br | ||
398 | Example: | ||
399 | .br | ||
400 | $ firejail \-\-net=eth0 \-\-mac=00:11:22:33:44:55 firefox | ||
401 | |||
402 | .TP | ||
403 | \fB\-\-name=name | ||
404 | Set sandbox hostname. Several options, such as \-\-join and \-\-shutdown, can use | ||
405 | this name to identify a sandbox. | ||
406 | .br | ||
407 | |||
408 | .br | ||
409 | Example: | ||
410 | .br | ||
411 | $ firejail \-\-name=mybrowser firefox | ||
412 | |||
413 | .TP | ||
414 | \fB\-\-net=bridge_interface | ||
415 | Enable a new network namespace and connect it to this bridge interface. | ||
416 | Unless specified with option \-\-ip and \-\-defaultgw, an IP address and a default gateway will be assigned | ||
417 | automatically to the sandbox. The IP address is verified using ARP before assignment. The address | ||
418 | configured as default gateway is the bridge device IP address. Up to four \-\-net | ||
419 | bridge devices can be defined. Mixing bridge and macvlan devices is allowed. | ||
420 | .br | ||
421 | |||
422 | .br | ||
423 | Example: | ||
424 | .br | ||
425 | $ sudo brctl addbr br0 | ||
426 | .br | ||
427 | $ sudo ifconfig br0 10.10.20.1/24 | ||
428 | .br | ||
429 | $ sudo brctl addbr br1 | ||
430 | .br | ||
431 | $ sudo ifconfig br1 10.10.30.1/24 | ||
432 | .br | ||
433 | $ firejail \-\-net=br0 \-\-net=br1 | ||
434 | |||
435 | .TP | ||
436 | \fB\-\-net=ethernet_interface | ||
437 | Enable a new network namespace and connect it | ||
438 | to this ethernet interface using the standard Linux macvlan | ||
439 | driver. Unless specified with option \-\-ip and \-\-defaultgw, an | ||
440 | IP address and a default gateway will be assigned automatically | ||
441 | to the sandbox. The IP address is verified using ARP before | ||
442 | assignment. The address configured as default gateway is the | ||
443 | default gateway of the host. Up to four \-\-net devices can | ||
444 | be defined. Mixing bridge and macvlan devices is allowed. | ||
445 | .br | ||
446 | |||
447 | .br | ||
448 | Example: | ||
449 | .br | ||
450 | $ firejail \-\-net=eth0 \-\-ip=192.168.1.80 \-\-dns=8.8.8.8 firefox | ||
451 | |||
452 | .TP | ||
453 | \fB\-\-net=none | ||
454 | Enable a new, unconnected network namespace. The only interface | ||
455 | available in the new namespace is a new loopback interface (lo). | ||
456 | Use this option to deny | ||
457 | network access to programs that don't really need network access. | ||
458 | .br | ||
459 | |||
460 | .br | ||
461 | Example: | ||
462 | .br | ||
463 | $ firejail \-\-net=none vlc | ||
464 | |||
465 | .TP | ||
466 | \fB\-\-netfilter | ||
467 | Enable a default client network filter in the new network namespace. | ||
468 | New network namespaces are created using \-\-net option. If a new network namespaces is not created, | ||
469 | \-\-netfilter option does nothing. | ||
470 | The default filter is as follows: | ||
471 | .br | ||
472 | |||
473 | .br | ||
474 | *filter | ||
475 | .br | ||
476 | :INPUT DROP [0:0] | ||
477 | .br | ||
478 | :FORWARD DROP [0:0] | ||
479 | .br | ||
480 | :OUTPUT ACCEPT [0:0] | ||
481 | .br | ||
482 | \-A INPUT \-i lo \-j ACCEPT | ||
483 | .br | ||
484 | \-A INPUT \-m state \-\-state RELATED,ESTABLISHED \-j ACCEPT | ||
485 | .br | ||
486 | \-A INPUT \-p icmp \-\-icmp-type destination-unreachable \-j ACCEPT | ||
487 | .br | ||
488 | \-A INPUT \-p icmp \-\-icmp-type time-exceeded \-j ACCEPT | ||
489 | .br | ||
490 | \-A INPUT \-p icmp \-\-icmp-type echo-request \-j ACCEPT | ||
491 | .br | ||
492 | COMMIT | ||
493 | .br | ||
494 | |||
495 | .br | ||
496 | Example: | ||
497 | .br | ||
498 | $ firejail \-\-net=eth0 \-\-netfilter firefox | ||
499 | .TP | ||
500 | \fB\-\-netfilter=filename | ||
501 | Enable the network filter specified by filename in the new network namespace. The filter file format | ||
502 | is the format of iptables-save and iptable-restore commands. | ||
503 | New network namespaces are created using \-\-net option. If a new network namespaces is not created, | ||
504 | \-\-netfilter option does nothing. | ||
505 | .br | ||
506 | |||
507 | .br | ||
508 | Example: | ||
509 | .br | ||
510 | $ firejail \-\-net=eth0 \-\-netfilter=myfile firefox | ||
511 | .TP | ||
512 | \fB\-\-netstats | ||
513 | Monitor network namespace statistics, see MONITORING section for more details. | ||
514 | .br | ||
515 | |||
516 | .br | ||
517 | Example: | ||
518 | .br | ||
519 | $ firejail \-\-netstats | ||
520 | .br | ||
521 | PID User RX(KB/s) TX(KB/s) Command | ||
522 | .br | ||
523 | 1294 netblue 53.355 1.473 firejail \-\-net=eth0 firefox | ||
524 | .br | ||
525 | 7383 netblue 9.045 0.112 firejail \-\-net=eth0 transmission | ||
526 | |||
527 | |||
528 | .TP | ||
529 | \fB\-\-nogroups | ||
530 | Disable supplementary groups. Without this option, supplementary groups are enabled for the user starting the | ||
531 | sandbox. For root user supplementary groups are always disabled. | ||
532 | .br | ||
533 | |||
534 | .br | ||
535 | Example: | ||
536 | .br | ||
537 | $ id | ||
538 | .br | ||
539 | uid=1000(netblue) gid=1000(netblue) groups=1000(netblue),24(cdrom),25(floppy),27(sudo),29(audio) | ||
540 | .br | ||
541 | $ firejail \-\-nogroups | ||
542 | .br | ||
543 | Parent pid 8704, child pid 8705 | ||
544 | .br | ||
545 | Child process initialized | ||
546 | .br | ||
547 | $ id | ||
548 | .br | ||
549 | uid=1000(netblue) gid=1000(netblue) groups=1000(netblue) | ||
550 | .br | ||
551 | $ | ||
552 | |||
553 | .TP | ||
554 | \fB\-\-noroot | ||
555 | Install a user namespace with a single user - the current user. | ||
556 | root user does not exist in the new namespace. This option | ||
557 | requires a Linux kernel version 3.8 or newer. The option | ||
558 | is not supported for \-\-chroot and \-\-overlay configurations, | ||
559 | or for sandboxes started as root. | ||
560 | .br | ||
561 | |||
562 | .br | ||
563 | Example: | ||
564 | .br | ||
565 | $ firejail \-\-noroot | ||
566 | .br | ||
567 | Parent pid 8553, child pid 8554 | ||
568 | .br | ||
569 | Child process initialized | ||
570 | .br | ||
571 | $ ping google.com | ||
572 | .br | ||
573 | ping: icmp open socket: Operation not permitted | ||
574 | .br | ||
575 | $ | ||
576 | .TP | ||
577 | \fB\-\-output=logfile | ||
578 | stdout logging and log rotation. Copy stdout to logfile, and keep the size of the file under 500KB using log | ||
579 | rotation. Five files with prefixes .1 to .5 are used in rotation. | ||
580 | .br | ||
581 | |||
582 | .br | ||
583 | Example: | ||
584 | .br | ||
585 | $ firejail \-\-output=sandboxlog /bin/bash | ||
586 | .br | ||
587 | [...] | ||
588 | .br | ||
589 | $ ls -l sandboxlog* | ||
590 | .br | ||
591 | -rw-r--r-- 1 netblue netblue 333890 Jun 2 07:48 sadnboxlog | ||
592 | .br | ||
593 | -rw-r--r-- 1 netblue netblue 511488 Jun 2 07:48 sandboxlog.1 | ||
594 | .br | ||
595 | -rw-r--r-- 1 netblue netblue 511488 Jun 2 07:48 sandboxlog.2 | ||
596 | .br | ||
597 | -rw-r--r-- 1 netblue netblue 511488 Jun 2 07:48 sandboxlog.3 | ||
598 | .br | ||
599 | -rw-r--r-- 1 netblue netblue 511488 Jun 2 07:48 sandboxlog.4 | ||
600 | .br | ||
601 | -rw-r--r-- 1 netblue netblue 511488 Jun 2 07:48 sandboxlog.5 | ||
602 | |||
603 | .TP | ||
604 | \fB\-\-overlay | ||
605 | Mount a filesystem overlay on top of the current filesystem. All filesystem modifications go into the overlay, | ||
606 | and are discarded when the sandbox is closed. | ||
607 | .br | ||
608 | |||
609 | .br | ||
610 | OverlayFS support is required in Linux kernel for this option to work. | ||
611 | OverlayFS was officially introduced in Linux kernel version 3.18. It was also | ||
612 | available in earlier kernel versions in some distributions such as Ubuntu and OpenSUSE. | ||
613 | .br | ||
614 | |||
615 | .br | ||
616 | Example: | ||
617 | .br | ||
618 | $ firejail \-\-overlay firefox | ||
619 | |||
620 | .TP | ||
621 | \fB\-\-private | ||
622 | Mount new /root and /home/user directories in temporary | ||
623 | filesystems. All modifications are discarded when the sandbox is | ||
624 | closed. | ||
625 | .br | ||
626 | |||
627 | .br | ||
628 | Example: | ||
629 | .br | ||
630 | $ firejail \-\-private firefox | ||
631 | .TP | ||
632 | \fB\-\-private=directory | ||
633 | Use directory as user home. | ||
634 | .br | ||
635 | |||
636 | .br | ||
637 | Example: | ||
638 | .br | ||
639 | $ firejail \-\-private=/home/netblue/firefox-home firefox | ||
640 | |||
641 | .TP | ||
642 | \fB\-\-private.keep=file,directory | ||
643 | Build a new user home in a temporary | ||
644 | filesystem, and copy the files and directories in the list in the | ||
645 | new home. All modifications are discarded when the sandbox is | ||
646 | closed. | ||
647 | .br | ||
648 | |||
649 | .br | ||
650 | Example: | ||
651 | .br | ||
652 | $ firejail \-\-private.keep=.mozilla firefox | ||
653 | .TP | ||
654 | \fB\-\-private-dev | ||
655 | Create a new /dev directory. Only null, full, zero, tty, pts, ptmx, random, urandom and shm devices are available. | ||
656 | .br | ||
657 | |||
658 | .br | ||
659 | Example: | ||
660 | .br | ||
661 | $ firejail \-\-private-dev | ||
662 | .br | ||
663 | Parent pid 9887, child pid 9888 | ||
664 | .br | ||
665 | Child process initialized | ||
666 | .br | ||
667 | $ ls /dev | ||
668 | .br | ||
669 | full null ptmx pts random shm tty urandom zero | ||
670 | .br | ||
671 | $ | ||
672 | .TP | ||
673 | \fB\-\-profile=filename | ||
674 | Load a custom profile from filename. For filename use an absolute path or a path relative to the current path. | ||
675 | For more information, see PROFILES section below. | ||
676 | .br | ||
677 | |||
678 | .br | ||
679 | Example: | ||
680 | .br | ||
681 | $ firejail \-\-profile=myprofile | ||
682 | .TP | ||
683 | \fB\-\-read-only=dirname_or_filename | ||
684 | Set directory or file read-only. | ||
685 | .br | ||
686 | |||
687 | .br | ||
688 | Example: | ||
689 | .br | ||
690 | $ firejail \-\-read-only=~/.mozilla firefox | ||
691 | .TP | ||
692 | \fB\-\-rlimit-fsize=number | ||
693 | Set the maximum file size that can be created by a process. | ||
694 | .TP | ||
695 | \fB\-\-rlimit-nofile=number | ||
696 | Set the maximum number of files that can be opened by a process. | ||
697 | .TP | ||
698 | \fB\-\-rlimit-nproc=number | ||
699 | Set the maximum number of processes that can be created for the real user ID of the calling process. | ||
700 | .TP | ||
701 | \fB\-\-rlimit-sigpending=number | ||
702 | Set the maximum number of pending signals for a process. | ||
703 | .TP | ||
704 | \fB\-\-scan | ||
705 | ARP-scan all the networks from inside a network namespace. | ||
706 | This makes it possible to detect macvlan kernel device drivers running on the current host. | ||
707 | .br | ||
708 | |||
709 | .br | ||
710 | Example: | ||
711 | .br | ||
712 | $ firejail \-\-net=eth0 \-\-scan | ||
713 | .TP | ||
714 | \fB\-\-seccomp | ||
715 | Enable seccomp filter and blacklist the syscalls in the default list. The default list is as follows: | ||
716 | mount, umount2, ptrace, kexec_load, open_by_handle_at, init_module, finit_module, delete_module, | ||
717 | iopl, ioperm, swapon, swapoff, mknode, syslog, process_vm_readv and process_vm_writev, | ||
718 | sysfs,_sysctl, adjtimex, clock_adjtime, lookup_dcookie, perf_event_open, fanotify_init and kcmp. | ||
719 | .br | ||
720 | |||
721 | .br | ||
722 | Example: | ||
723 | .br | ||
724 | $ firejail \-\-sccomp | ||
725 | .TP | ||
726 | \fB\-\-seccomp=syscall,syscall,syscall | ||
727 | Enable seccomp filter, blacklist the default list and the syscalls specified by the command. | ||
728 | .br | ||
729 | |||
730 | .br | ||
731 | Example: | ||
732 | .br | ||
733 | $ firejail \-\-seccomp=utime,utimensat,utimes firefox | ||
734 | .TP | ||
735 | \fB\-\-seccomp.drop=syscall,syscall,syscall | ||
736 | Enable seccomp filter, and blacklist the syscalls specified by the command. | ||
737 | .br | ||
738 | |||
739 | .br | ||
740 | Example: | ||
741 | .br | ||
742 | $ firejail \-\-seccomp.drop=utime,utimensat,utimes | ||
743 | .TP | ||
744 | \fB\-\-seccomp.keep=syscall,syscall,syscall | ||
745 | Enable seccomp filter, and whitelist the syscalls specified by the command. | ||
746 | .br | ||
747 | |||
748 | .br | ||
749 | Example: | ||
750 | .br | ||
751 | $ firejail \-\-shell=none \-\-seccomp.keep=poll,select,[...] transmission-gtk | ||
752 | .TP | ||
753 | \fB\-\-seccomp.print=name | ||
754 | Print the seccomp filter for the sandbox started using \-\-name option. | ||
755 | .br | ||
756 | |||
757 | .br | ||
758 | Example: | ||
759 | .br | ||
760 | $ firejail \-\-name=browser firefox & | ||
761 | .br | ||
762 | $ firejail \-\-seccomp.print=browser | ||
763 | .br | ||
764 | SECCOMP Filter: | ||
765 | .br | ||
766 | VALIDATE_ARCHITECTURE | ||
767 | .br | ||
768 | EXAMINE_SYSCAL | ||
769 | .br | ||
770 | BLACKLIST 165 mount | ||
771 | .br | ||
772 | BLACKLIST 166 umount2 | ||
773 | .br | ||
774 | BLACKLIST 101 ptrace | ||
775 | .br | ||
776 | BLACKLIST 246 kexec_load | ||
777 | .br | ||
778 | BLACKLIST 304 open_by_handle_at | ||
779 | .br | ||
780 | BLACKLIST 175 init_module | ||
781 | .br | ||
782 | BLACKLIST 176 delete_module | ||
783 | .br | ||
784 | BLACKLIST 172 iopl | ||
785 | .br | ||
786 | BLACKLIST 173 ioperm | ||
787 | .br | ||
788 | BLACKLIST 167 swapon | ||
789 | .br | ||
790 | BLACKLIST 168 swapoff | ||
791 | .br | ||
792 | BLACKLIST 103 syslog | ||
793 | .br | ||
794 | BLACKLIST 310 process_vm_readv | ||
795 | .br | ||
796 | BLACKLIST 311 process_vm_writev | ||
797 | .br | ||
798 | BLACKLIST 133 mknod | ||
799 | .br | ||
800 | BLACKLIST 139 sysfs | ||
801 | .br | ||
802 | BLACKLIST 156 _sysctl | ||
803 | .br | ||
804 | BLACKLIST 159 adjtimex | ||
805 | .br | ||
806 | BLACKLIST 305 clock_adjtime | ||
807 | .br | ||
808 | BLACKLIST 212 lookup_dcookie | ||
809 | .br | ||
810 | BLACKLIST 298 perf_event_open | ||
811 | .br | ||
812 | BLACKLIST 300 fanotify_init | ||
813 | .br | ||
814 | RETURN_ALLOW | ||
815 | .br | ||
816 | $ | ||
817 | .TP | ||
818 | \fB\-\-seccomp.print=pid | ||
819 | Print the seccomp filter for the sandbox specified by process ID. Use \-\-list option to get a list of all active sandboxes. | ||
820 | .br | ||
821 | |||
822 | .br | ||
823 | Example: | ||
824 | .br | ||
825 | $ firejail \-\-list | ||
826 | .br | ||
827 | 10786:netblue:firejail \-\-name=browser firefox | ||
828 | $ firejail \-\-seccomp.print=10786 | ||
829 | .br | ||
830 | SECCOMP Filter: | ||
831 | .br | ||
832 | VALIDATE_ARCHITECTURE | ||
833 | .br | ||
834 | EXAMINE_SYSCAL | ||
835 | .br | ||
836 | BLACKLIST 165 mount | ||
837 | .br | ||
838 | BLACKLIST 166 umount2 | ||
839 | .br | ||
840 | BLACKLIST 101 ptrace | ||
841 | .br | ||
842 | BLACKLIST 246 kexec_load | ||
843 | .br | ||
844 | BLACKLIST 304 open_by_handle_at | ||
845 | .br | ||
846 | BLACKLIST 175 init_module | ||
847 | .br | ||
848 | BLACKLIST 176 delete_module | ||
849 | .br | ||
850 | BLACKLIST 172 iopl | ||
851 | .br | ||
852 | BLACKLIST 173 ioperm | ||
853 | .br | ||
854 | BLACKLIST 167 swapon | ||
855 | .br | ||
856 | BLACKLIST 168 swapoff | ||
857 | .br | ||
858 | BLACKLIST 103 syslog | ||
859 | .br | ||
860 | BLACKLIST 310 process_vm_readv | ||
861 | .br | ||
862 | BLACKLIST 311 process_vm_writev | ||
863 | .br | ||
864 | BLACKLIST 133 mknod | ||
865 | .br | ||
866 | BLACKLIST 139 sysfs | ||
867 | .br | ||
868 | BLACKLIST 156 _sysctl | ||
869 | .br | ||
870 | BLACKLIST 159 adjtimex | ||
871 | .br | ||
872 | BLACKLIST 305 clock_adjtime | ||
873 | .br | ||
874 | BLACKLIST 212 lookup_dcookie | ||
875 | .br | ||
876 | BLACKLIST 298 perf_event_open | ||
877 | .br | ||
878 | BLACKLIST 300 fanotify_init | ||
879 | .br | ||
880 | RETURN_ALLOW | ||
881 | .br | ||
882 | $ | ||
883 | .TP | ||
884 | \fB\-\-shell=none | ||
885 | Run the program directly, without a user shell. | ||
886 | .br | ||
887 | |||
888 | .br | ||
889 | Example: | ||
890 | .br | ||
891 | $ firejail \-\-shell=none script.sh | ||
892 | .TP | ||
893 | \fB\-\-shell=program | ||
894 | Set default user shell. Use this shell to run the application using \-c shell option. | ||
895 | For example "firejail \-\-shell=/bin/dash firefox" will start Mozilla Firefox as "/bin/dash \-c firefox". | ||
896 | By default Bash shell (/bin/bash) is used. Options such as \-\-zsh and \-\-csh can also set the default | ||
897 | shell. | ||
898 | .br | ||
899 | |||
900 | .br | ||
901 | Example: | ||
902 | $firejail \-\-shell=/bin/dash script.sh | ||
903 | .TP | ||
904 | \fB\-\-shutdown=name | ||
905 | Shutdown the sandbox started using \-\-name option. | ||
906 | .br | ||
907 | |||
908 | .br | ||
909 | Example: | ||
910 | .br | ||
911 | $ firejail \-\-name=mygame \-\-caps.drop=all warzone2100 & | ||
912 | .br | ||
913 | [...] | ||
914 | .br | ||
915 | $ firejail \-\-shutdown=mygame | ||
916 | .TP | ||
917 | \fB\-\-shutdown=pid | ||
918 | Shutdown the sandbox specified by process ID. Use \-\-list option to get a list of all active sandboxes. | ||
919 | .br | ||
920 | |||
921 | .br | ||
922 | Example: | ||
923 | .br | ||
924 | $ firejail \-\-list | ||
925 | .br | ||
926 | 3272:netblue:firejail \-\-private firefox | ||
927 | .br | ||
928 | $ firejail \-\-shutdown=3272 | ||
929 | .TP | ||
930 | \fB\-\-tmpfs=dirname | ||
931 | Mount a tmpfs filesystem on directory dirname. | ||
932 | .br | ||
933 | |||
934 | .br | ||
935 | Example: | ||
936 | .br | ||
937 | $ firejail \-\-tmpfs=/var | ||
938 | .TP | ||
939 | \fB\-\-top | ||
940 | Monitor the most CPU-intensive sandboxes, see MONITORING section for more details. | ||
941 | .br | ||
942 | |||
943 | .br | ||
944 | Example: | ||
945 | .br | ||
946 | $ firejail \-\-top | ||
947 | .TP | ||
948 | \fB\-\-trace | ||
949 | Trace open, access and connect system calls. | ||
950 | .br | ||
951 | |||
952 | .br | ||
953 | Example: | ||
954 | .br | ||
955 | $ firejail \-\-trace wget -q www.debian.org | ||
956 | .br | ||
957 | Parent pid 11793, child pid 11794 | ||
958 | .br | ||
959 | Child process initialized | ||
960 | .br | ||
961 | 1:bash:open /dev/tty | ||
962 | .br | ||
963 | 1:wget:fopen64 /etc/wgetrc | ||
964 | .br | ||
965 | 1:wget:fopen /etc/hosts | ||
966 | .br | ||
967 | 1:wget:socket AF_INET SOCK_DGRAM IPPROTO_IP | ||
968 | .br | ||
969 | 1:wget:connect 8.8.8.8:53 | ||
970 | .br | ||
971 | 1:wget:socket AF_INET SOCK_STREAM IPPROTO_IP | ||
972 | .br | ||
973 | 1:wget:connect 140.211.15.34:80 | ||
974 | .br | ||
975 | 1:wget:fopen64 index.html.1 | ||
976 | .br | ||
977 | |||
978 | .br | ||
979 | parent is shutting down, bye... | ||
980 | .TP | ||
981 | \fB\-\-tree | ||
982 | Print a tree of all sandboxed processes, see MONITORING section for more details. | ||
983 | .br | ||
984 | |||
985 | .br | ||
986 | Example: | ||
987 | .br | ||
988 | $ firejail \-\-tree | ||
989 | .br | ||
990 | 11903:netblue:firejail iceweasel | ||
991 | .br | ||
992 | 11904:netblue:iceweasel | ||
993 | .br | ||
994 | 11957:netblue:/usr/lib/iceweasel/plugin-container | ||
995 | .br | ||
996 | 11969:netblue:firejail \-\-net=eth0 transmission-gtk | ||
997 | .br | ||
998 | 11970:netblue:transmission-gtk | ||
999 | .TP | ||
1000 | \fB\-\-version | ||
1001 | Print program version and exit. | ||
1002 | .br | ||
1003 | |||
1004 | .br | ||
1005 | Example: | ||
1006 | .br | ||
1007 | $ firejail \-\-version | ||
1008 | .br | ||
1009 | firejail version 0.9.27 | ||
1010 | .TP | ||
1011 | \fB\-\-zsh | ||
1012 | Use /usr/bin/zsh as default user shell. | ||
1013 | .br | ||
1014 | |||
1015 | .br | ||
1016 | Example: | ||
1017 | .br | ||
1018 | $ firejakil \-\-zsh | ||
1019 | .SH TRAFFIC SHAPING | ||
1020 | Network bandwidth is an expensive resource shared among all sandboxes running on a system. | ||
1021 | Traffic shaping allows the user to increase network performance by controlling | ||
1022 | the amount of data that flows into and out of the sandboxes. | ||
1023 | |||
1024 | Firejail implements a simple rate-limiting shaper based on Linux command tc. | ||
1025 | The shaper works at sandbox level, and can be used only for sandboxes configured with new network namespaces. | ||
1026 | |||
1027 | Set rate-limits: | ||
1028 | |||
1029 | firejail --bandwidth={name|pid} set network download upload | ||
1030 | |||
1031 | Clear rate-limits: | ||
1032 | |||
1033 | firejail --bandwidth={name|pid} clear network | ||
1034 | |||
1035 | Status: | ||
1036 | |||
1037 | firejail --bandwidth={name|pid} status | ||
1038 | |||
1039 | where: | ||
1040 | .br | ||
1041 | name - sandbox name | ||
1042 | .br | ||
1043 | pid - sandbox pid | ||
1044 | .br | ||
1045 | network - network interface as used by \-\-net option | ||
1046 | .br | ||
1047 | download - download speed in KB/s (kilobyte per second) | ||
1048 | .br | ||
1049 | upload - upload speed in KB/s (kilobyte per second) | ||
1050 | |||
1051 | Example: | ||
1052 | .br | ||
1053 | $ firejail \-\-name=mybrowser \-\-net=eth0 firefox & | ||
1054 | .br | ||
1055 | $ firejail \-\-bandwidth=mybrowser set eth0 80 20 | ||
1056 | .br | ||
1057 | $ firejail \-\-bandwidth=mybrowser status | ||
1058 | .br | ||
1059 | $ firejail \-\-bandwidth=mybrowser clear eth0 | ||
1060 | |||
1061 | .SH MONITORING | ||
1062 | Option \-\-list prints a list of all sandboxes. The format | ||
1063 | for each process entry is as follows: | ||
1064 | |||
1065 | PID:USER:Command | ||
1066 | |||
1067 | Option \-\-tree prints the tree of processes running in the sandbox. The format | ||
1068 | for each process entry is as follows: | ||
1069 | |||
1070 | PID:USER:Command | ||
1071 | |||
1072 | Option \-\-top is similar to the UNIX top command, however it applies only to | ||
1073 | sandboxes. | ||
1074 | |||
1075 | Option \-\-netstats prints network statistics for active sandboxes installing new network namespaces. | ||
1076 | |||
1077 | |||
1078 | Listed below are the available fields (columns) in alphabetical | ||
1079 | order for \-\-top and \-\-netstat options: | ||
1080 | |||
1081 | .TP | ||
1082 | Command | ||
1083 | Command used to start the sandbox. | ||
1084 | .TP | ||
1085 | CPU% | ||
1086 | CPU usage, the sandbox share of the elapsed CPU time since the | ||
1087 | last screen update | ||
1088 | .TP | ||
1089 | PID | ||
1090 | Unique process ID for the task controlling the sandbox. | ||
1091 | .TP | ||
1092 | Prcs | ||
1093 | Number of processes running in sandbox, including the controlling process. | ||
1094 | .TP | ||
1095 | RES | ||
1096 | Resident Memory Size (KiB), sandbox non-swapped physical memory. | ||
1097 | It is a sum of the RES values for all processes running in the sandbox. | ||
1098 | .TP | ||
1099 | RX(KB/s) | ||
1100 | Network receive speed. | ||
1101 | .TP | ||
1102 | SHR | ||
1103 | Shared Memory Size (KiB), it reflects memory shared with other | ||
1104 | processes. It is a sum of the SHR values for all processes running | ||
1105 | in the sandbox, including the controlling process. | ||
1106 | .TP | ||
1107 | TX(KB/s) | ||
1108 | Network transmit speed. | ||
1109 | .TP | ||
1110 | Uptime | ||
1111 | Sandbox running time in hours:minutes:seconds format. | ||
1112 | .TP | ||
1113 | User | ||
1114 | The owner of the sandbox. | ||
1115 | |||
1116 | .SH PROFILES | ||
1117 | Several command line configuration options can be passed to the program using | ||
1118 | profile files. Firejail supports user specified profile files and automatic profile files, | ||
1119 | as follows: | ||
1120 | |||
1121 | 1. Load a specific profile file from a full path, or a path relative to the current directory. | ||
1122 | Example: | ||
1123 | .PP | ||
1124 | .RS | ||
1125 | $ firejail --profile=/home/netblue/icecat.profile icecat | ||
1126 | .RE | ||
1127 | |||
1128 | 2. Load a default profile file automatically from ~/.config/firejail or from /etc/firejail, based | ||
1129 | on the name of the executable started in the sandbox. Example: | ||
1130 | .PP | ||
1131 | .RS | ||
1132 | $ firejail icecat | ||
1133 | .br | ||
1134 | Command name #icecat# | ||
1135 | .br | ||
1136 | .br | ||
1137 | Found icecat profile in /home/netblue/.config/firejail directory | ||
1138 | .br | ||
1139 | Reading profile /home/netblue/.config/firejail/icecat.profile | ||
1140 | .br | ||
1141 | [...] | ||
1142 | .RE | ||
1143 | |||
1144 | See man 5 firejail-profile for profile file syntax information. | ||
1145 | |||
1146 | .SH RESTRICTED SHELL | ||
1147 | To configure a restricted shell, replace /bin/bash with /usr/bin/firejail in | ||
1148 | /etc/password file for each user that needs to be restricted. Alternatively, | ||
1149 | you can specify /usr/bin/firejail in adduser command: | ||
1150 | |||
1151 | adduser \-\-shell /usr/bin/firejail username | ||
1152 | |||
1153 | Additional arguments passed to firejail executable upon login are declared in /etc/firejail/login.users file. | ||
1154 | |||
1155 | .SH EXAMPLES | ||
1156 | .TP | ||
1157 | \f\firejail | ||
1158 | Start a regular /bin/bash session in sandbox. | ||
1159 | .TP | ||
1160 | \f\firejail firefox | ||
1161 | Start Mozilla Firefox. | ||
1162 | .TP | ||
1163 | \f\firejail \-\-seccomp firefox | ||
1164 | Start Mozilla Firefox in a seccomp sandbox. | ||
1165 | .TP | ||
1166 | \f\firejail \-\-caps firefox | ||
1167 | Start Mozilla Firefox in a Linux capabilities sandbox. | ||
1168 | .TP | ||
1169 | \f\firejail \-\-debug firefox | ||
1170 | Debug Firefox sandbox. | ||
1171 | .TP | ||
1172 | \f\firejail \-\-private | ||
1173 | Start a /bin/bash session with a new tmpfs home directory. | ||
1174 | .TP | ||
1175 | \f\firejail \-\-net=br0 ip=10.10.20.10 | ||
1176 | Start a /bin/bash session in a new network namespace. The session is | ||
1177 | connected to the main network using br0 bridge device. An IP address | ||
1178 | of 10.10.20.10 is assigned to the sandbox. | ||
1179 | .TP | ||
1180 | \f\firejail \-\-net=br0 \-\-net=br1 \-\-net=br2 | ||
1181 | Start a /bin/bash session in a new network namespace and connect it | ||
1182 | to br0, br1, and br2 host bridge devices. | ||
1183 | .TP | ||
1184 | \f\firejail \-\-list | ||
1185 | List all sandboxed processes. | ||
1186 | .SH LICENSE | ||
1187 | This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. | ||
1188 | .PP | ||
1189 | Homepage: http://firejail.sourceforge.net | ||
1190 | .SH SEE ALSO | ||
1191 | \&\flfiremon\fR\|(1), | ||
1192 | \&\flfirejail-profile\fR\|(5), | ||
1193 | \&\flfirejail-login\fR\|(5) | ||
1194 | |||
1195 | |||
1196 | |||
diff --git a/src/man/firemon.txt b/src/man/firemon.txt new file mode 100644 index 000000000..b6010f46e --- /dev/null +++ b/src/man/firemon.txt | |||
@@ -0,0 +1,107 @@ | |||
1 | .TH man 1 "MONTH YEAR" "VERSION" "firemon man page" | ||
2 | .SH NAME | ||
3 | Firemon \- Monitoring program for processes started in a Firejail sandbox. | ||
4 | .SH SYNOPSIS | ||
5 | firemon [OPTIONS] [PID] | ||
6 | .SH DESCRIPTION | ||
7 | Firemon monitors programs started in a Firejail sandbox. | ||
8 | Without a PID specified, all processes started by Firejail are monitored. Descendants of | ||
9 | these processes are also being monitored. | ||
10 | .SH OPTIONS | ||
11 | .TP | ||
12 | \fB\-\-arp | ||
13 | Print ARP table for each sandbox. | ||
14 | .TP | ||
15 | \fB\-\-caps | ||
16 | Print capabilities configuration for each sandbox. | ||
17 | .TP | ||
18 | \fB\-\-cgroup | ||
19 | Print control group information for each sandbox. | ||
20 | .TP | ||
21 | \fB\-\-cpu | ||
22 | Print CPU affinity for each sandbox. | ||
23 | .TP | ||
24 | \fB\-?\fR, \fB\-\-help\fR | ||
25 | Print options end exit. | ||
26 | .TP | ||
27 | \fB\-\-interface | ||
28 | Print network interface information for each sandbox. | ||
29 | .TP | ||
30 | \fB\-\-list | ||
31 | List all sandboxes. | ||
32 | .TP | ||
33 | \fB\-\-name=name | ||
34 | Print information only about named sandbox. | ||
35 | .TP | ||
36 | \fB\-\-netstats | ||
37 | Monitor network statistics for sandboxes creating a new network namespace. | ||
38 | .TP | ||
39 | \fB\-\-route | ||
40 | Print route table for each sandbox. | ||
41 | .TP | ||
42 | \fB\-\-seccomp | ||
43 | Print seccomp configuration for each sandbox. | ||
44 | .TP | ||
45 | \fB\-\-top | ||
46 | Monitor the most CPU-intensive sandboxes. | ||
47 | .TP | ||
48 | \fB\-\-tree | ||
49 | Print a tree of all sandboxed processes. | ||
50 | .TP | ||
51 | \fB\-\-version | ||
52 | Print program version and exit. | ||
53 | |||
54 | .PP | ||
55 | Option \-\-list prints a list of all sandboxes. The format | ||
56 | for each entry is as follows: | ||
57 | |||
58 | PID:USER:Command | ||
59 | |||
60 | Option \-\-tree prints the tree of processes running in the sandbox. The format | ||
61 | for each process entry is as follows: | ||
62 | |||
63 | PID:USER:Command | ||
64 | |||
65 | Option \-\-top is similar to the UNIX top command, however it applies only to | ||
66 | sandboxes. Listed below are the available fields (columns) in alphabetical | ||
67 | order: | ||
68 | |||
69 | .TP | ||
70 | Command | ||
71 | Command used to start the sandbox. | ||
72 | .TP | ||
73 | CPU% | ||
74 | CPU usage, the sandbox share of the elapsed CPU time since the | ||
75 | last screen update | ||
76 | .TP | ||
77 | PID | ||
78 | Unique process ID for the task controlling the sandbox. | ||
79 | .TP | ||
80 | Prcs | ||
81 | Number of processes running in sandbox, including the controlling process. | ||
82 | .TP | ||
83 | RES | ||
84 | Resident Memory Size (KiB), sandbox non-swapped physical memory. | ||
85 | It is a sum of the RES values for all processes running in the sandbox. | ||
86 | .TP | ||
87 | SHR | ||
88 | Shared Memory Size (KiB), it reflects memory shared with other | ||
89 | processes. It is a sum of the SHR values for all processes running | ||
90 | in the sandbox, including the controlling process. | ||
91 | .TP | ||
92 | Uptime | ||
93 | Sandbox running time in hours:minutes:seconds format. | ||
94 | .TP | ||
95 | User | ||
96 | The owner of the sandbox. | ||
97 | |||
98 | .SH LICENSE | ||
99 | This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. | ||
100 | .PP | ||
101 | Homepage: http://firejail.sourceforge.net | ||
102 | .SH SEE ALSO | ||
103 | \&\flfirejail\fR\|(1), | ||
104 | \&\flfirejail-profile\fR\|(5), | ||
105 | \&\flfirejail-login\fR\|(5) | ||
106 | |||
107 | |||
diff --git a/src/tools/check-caps.sh b/src/tools/check-caps.sh new file mode 100755 index 000000000..13525677b --- /dev/null +++ b/src/tools/check-caps.sh | |||
@@ -0,0 +1,46 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | if [ $# -eq 0 ] | ||
4 | then | ||
5 | echo "Usage: check-caps.sh program-and-arguments" | ||
6 | echo | ||
7 | fi | ||
8 | |||
9 | set -x | ||
10 | |||
11 | firejail --caps.drop=chown "$1" | ||
12 | firejail --caps.drop=dac_override "$1" | ||
13 | firejail --caps.drop=dac_read_search "$1" | ||
14 | firejail --caps.drop=fowner "$1" | ||
15 | firejail --caps.drop=fsetid "$1" | ||
16 | firejail --caps.drop=kill "$1" | ||
17 | firejail --caps.drop=setgid "$1" | ||
18 | firejail --caps.drop=setuid "$1" | ||
19 | firejail --caps.drop=setpcap "$1" | ||
20 | firejail --caps.drop=linux_immutable "$1" | ||
21 | firejail --caps.drop=net_bind_service "$1" | ||
22 | firejail --caps.drop=net_broadcast "$1" | ||
23 | firejail --caps.drop=net_admin "$1" | ||
24 | firejail --caps.drop=net_raw "$1" | ||
25 | firejail --caps.drop=ipc_lock "$1" | ||
26 | firejail --caps.drop=ipc_owner "$1" | ||
27 | firejail --caps.drop=sys_module "$1" | ||
28 | firejail --caps.drop=sys_rawio "$1" | ||
29 | firejail --caps.drop=sys_chroot "$1" | ||
30 | firejail --caps.drop=sys_ptrace "$1" | ||
31 | firejail --caps.drop=sys_pacct "$1" | ||
32 | firejail --caps.drop=sys_admin "$1" | ||
33 | firejail --caps.drop=sys_boot "$1" | ||
34 | firejail --caps.drop=sys_nice "$1" | ||
35 | firejail --caps.drop=sys_resource "$1" | ||
36 | firejail --caps.drop=sys_time "$1" | ||
37 | firejail --caps.drop=sys_tty_config "$1" | ||
38 | firejail --caps.drop=mknod "$1" | ||
39 | firejail --caps.drop=lease "$1" | ||
40 | firejail --caps.drop=audit_write "$1" | ||
41 | firejail --caps.drop=audit_control "$1" | ||
42 | firejail --caps.drop=setfcap "$1" | ||
43 | firejail --caps.drop=mac_override "$1" | ||
44 | firejail --caps.drop=mac_admin "$1" | ||
45 | firejail --caps.drop=syslog "$1" | ||
46 | firejail --caps.drop=wake_alarm "$1" | ||
diff --git a/src/tools/extract_caps.c b/src/tools/extract_caps.c new file mode 100644 index 000000000..94a062ccb --- /dev/null +++ b/src/tools/extract_caps.c | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | #include <assert.h> | ||
24 | |||
25 | #define BUFMAX 4096 | ||
26 | |||
27 | int main(int argc, char **argv) { | ||
28 | if (argc != 2) { | ||
29 | printf("usage: %s /usr/include/linux/capability.h\n", argv[0]); | ||
30 | return 1; | ||
31 | } | ||
32 | |||
33 | //open file | ||
34 | FILE *fp = fopen(argv[1], "r"); | ||
35 | if (!fp) { | ||
36 | fprintf(stderr, "Error: cannot open file\n"); | ||
37 | return 1; | ||
38 | } | ||
39 | |||
40 | // read file | ||
41 | char buf[BUFMAX]; | ||
42 | while (fgets(buf, BUFMAX, fp)) { | ||
43 | // cleanup | ||
44 | char *start = buf; | ||
45 | while (*start == ' ' || *start == '\t') | ||
46 | start++; | ||
47 | char *end = strchr(start, '\n'); | ||
48 | if (end) | ||
49 | *end = '\0'; | ||
50 | |||
51 | // parsing | ||
52 | if (strncmp(start, "#define CAP_", 12) == 0) { | ||
53 | if (strstr(start, "CAP_LAST_CAP")) | ||
54 | break; | ||
55 | |||
56 | char *ptr1 = start + 8; | ||
57 | char *ptr2 = ptr1; | ||
58 | while (*ptr2 == ' ' || *ptr2 == '\t') | ||
59 | ptr2++; | ||
60 | while (*ptr2 != ' ' && *ptr2 != '\t') | ||
61 | ptr2++; | ||
62 | *ptr2 = '\0'; | ||
63 | |||
64 | ptr2 = strdup(ptr1); | ||
65 | assert(ptr2); | ||
66 | ptr2 += 4; | ||
67 | char *ptr3 = ptr2; | ||
68 | while (*ptr3 != '\0') { | ||
69 | *ptr3 = tolower(*ptr3); | ||
70 | ptr3++; | ||
71 | } | ||
72 | |||
73 | |||
74 | printf("#ifdef %s\n", ptr1); | ||
75 | printf("\t{\"%s\", %s },\n", ptr2, ptr1); | ||
76 | printf("#endif\n"); | ||
77 | |||
78 | } | ||
79 | |||
80 | } | ||
81 | fclose(fp); | ||
82 | return 0; | ||
83 | } | ||
diff --git a/src/tools/extract_syscalls.c b/src/tools/extract_syscalls.c new file mode 100644 index 000000000..0e064a49e --- /dev/null +++ b/src/tools/extract_syscalls.c | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 <stdio.h> | ||
21 | #include <stdlib.h>6 | ||
22 | #include <string.h> | ||
23 | |||
24 | #define BUFMAX 4096 | ||
25 | |||
26 | int main(int argc, char **argv) { | ||
27 | if (argc != 2) { | ||
28 | printf("usage: %s /media/ubuntu/usr/include/x86_64-linux-gnu/bits/syscall.h\n", argv[0]); | ||
29 | return 1; | ||
30 | } | ||
31 | |||
32 | //open file | ||
33 | FILE *fp = fopen(argv[1], "r"); | ||
34 | if (!fp) { | ||
35 | fprintf(stderr, "Error: cannot open file\n"); | ||
36 | return 1; | ||
37 | } | ||
38 | |||
39 | // read file | ||
40 | char buf[BUFMAX]; | ||
41 | while (fgets(buf, BUFMAX, fp)) { | ||
42 | // cleanup | ||
43 | char *start = buf; | ||
44 | while (*start == ' ' || *start == '\t') | ||
45 | start++; | ||
46 | char *end = strchr(start, '\n'); | ||
47 | if (end) | ||
48 | *end = '\0'; | ||
49 | |||
50 | // parsing | ||
51 | if (strncmp(start, "#endif", 6) == 0) | ||
52 | printf("%s\n", start); | ||
53 | if (strncmp(start, "#endif", 6) == 0) | ||
54 | printf("%s\n", start); | ||
55 | else if (strncmp(start, "#if", 3) == 0) | ||
56 | printf("%s\n", start); | ||
57 | else if (strncmp(start, "#define", 7) == 0) { | ||
58 | // extract data | ||
59 | char *ptr1 = strstr(start, "SYS_"); | ||
60 | char *ptr2 = strstr(start, "__NR_"); | ||
61 | if (!ptr1 || !ptr2) { | ||
62 | fprintf(stderr, "Error: cannot parse \"%s\"\n", start); | ||
63 | fclose(fp); | ||
64 | return 1; | ||
65 | } | ||
66 | *(ptr2 - 1) = '\0'; | ||
67 | |||
68 | char *ptr3 = ptr1; | ||
69 | while (*ptr3 != ' ' && *ptr3 != '\t' && *ptr3 != '\0') | ||
70 | ptr3++; | ||
71 | *ptr3 = '\0'; | ||
72 | ptr3 = ptr2; | ||
73 | while (*ptr3 != ' ' && *ptr3 != '\t' && *ptr3 != '\0') | ||
74 | ptr3++; | ||
75 | *ptr3 = '\0'; | ||
76 | |||
77 | ptr3 = ptr1; | ||
78 | while (*ptr3 != '_') | ||
79 | ptr3++; | ||
80 | ptr3++; | ||
81 | |||
82 | printf("#ifdef %s\n", ptr1); | ||
83 | printf("#ifdef %s\n", ptr2); | ||
84 | printf("\t{\"%s\", %s},\n", ptr3, ptr2); | ||
85 | printf("#endif\n"); | ||
86 | printf("#endif\n"); | ||
87 | } | ||
88 | } | ||
89 | fclose(fp); | ||
90 | return 0; | ||
91 | } | ||
diff --git a/src/tools/mkcoverit.sh b/src/tools/mkcoverit.sh new file mode 100755 index 000000000..4af84a7a1 --- /dev/null +++ b/src/tools/mkcoverit.sh | |||
@@ -0,0 +1,45 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | # unpack firejail archive | ||
4 | ARCFIREJAIL=`ls *.tar.bz2| grep firejail` | ||
5 | if [ "$?" -eq 0 ]; | ||
6 | then | ||
7 | echo "preparing $ARCFIREJAIL" | ||
8 | DIRFIREJAIL=`basename $ARCFIREJAIL .tar.bz2` | ||
9 | rm -fr $DIRFIREJAIL | ||
10 | tar -xjvf $ARCFIREJAIL | ||
11 | cd $DIRFIREJAIL | ||
12 | ./configure --prefix=/usr | ||
13 | cd .. | ||
14 | else | ||
15 | echo "Error: firejail source archive missing" | ||
16 | exit 1 | ||
17 | fi | ||
18 | |||
19 | |||
20 | # unpack firetools archive | ||
21 | ARCFIRETOOLS=`ls *.tar.bz2 | grep firetools` | ||
22 | if [ "$?" -eq 0 ]; | ||
23 | then | ||
24 | echo "preparing $ARCFIRETOOLS" | ||
25 | DIRFIRETOOLS=`basename $ARCFIRETOOLS .tar.bz2` | ||
26 | rm -fr $DIRFIRETOOLS | ||
27 | tar -xjvf $ARCFIRETOOLS | ||
28 | cd $DIRFIRETOOLS | ||
29 | pwd | ||
30 | ./configure --prefix=/usr | ||
31 | cd .. | ||
32 | |||
33 | else | ||
34 | echo "Error: firetools source archive missing" | ||
35 | exit 1 | ||
36 | fi | ||
37 | |||
38 | # move firetools in firejail source tree | ||
39 | mkdir -p $DIRFIREJAIL/extras | ||
40 | mv $DIRFIRETOOLS $DIRFIREJAIL/extras/firetools | ||
41 | |||
42 | # build | ||
43 | cd $DIRFIREJAIL | ||
44 | cov-build --dir cov-int make -j 4 extras | ||
45 | tar czvf myproject.tgz cov-int | ||
diff --git a/src/tools/rvtest.c b/src/tools/rvtest.c new file mode 100644 index 000000000..95050e671 --- /dev/null +++ b/src/tools/rvtest.c | |||
@@ -0,0 +1,144 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) | ||
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 | |||
21 | // run it as "rvtest 2>/dev/null | grep TESTING" | ||
22 | |||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <unistd.h> | ||
26 | #include <string.h> | ||
27 | #include <sys/types.h> | ||
28 | #include <signal.h> | ||
29 | |||
30 | #define MAXBUF 1024 // line buffer | ||
31 | #define TIMEOUT 30 // timeout time in seconds | ||
32 | |||
33 | static pid_t pid; | ||
34 | static void catch_alarm(int sig) { | ||
35 | kill(pid, SIGTERM); | ||
36 | sleep(1); | ||
37 | kill(pid, SIGKILL); | ||
38 | printf("TESTING ERROR: SIGALARM triggered\n"); | ||
39 | exit(1); | ||
40 | } | ||
41 | |||
42 | static void usage(void) { | ||
43 | printf("Usage: rvtest testfile\n"); | ||
44 | printf("\n"); | ||
45 | printf("Testfile format:\n"); | ||
46 | printf("\tretval command\n"); | ||
47 | printf("\n"); | ||
48 | printf("Testfile example:\n"); | ||
49 | printf("\n"); | ||
50 | printf("0 firejail --net=none exit\n"); | ||
51 | printf("1 firejail --private=/etc sleep 1\n"); | ||
52 | printf("1 firejail --blablabla\n"); | ||
53 | } | ||
54 | |||
55 | int main(int argc, char **argv) { | ||
56 | if (argc != 2) { | ||
57 | fprintf(stderr, "Error: test file missing\n"); | ||
58 | usage(); | ||
59 | return 1; | ||
60 | } | ||
61 | |||
62 | signal (SIGALRM, catch_alarm); | ||
63 | |||
64 | // open test file | ||
65 | char *fname = argv[1]; | ||
66 | FILE *fp = fopen(fname, "r"); | ||
67 | |||
68 | // read test file | ||
69 | char buf[MAXBUF]; | ||
70 | int line = 0; | ||
71 | while (fgets(buf, MAXBUF, fp)) { | ||
72 | line++; | ||
73 | // skip blanks | ||
74 | char *start = buf; | ||
75 | while (*start == ' ' || *start == '\t') | ||
76 | start++; | ||
77 | // remove '\n' | ||
78 | char *ptr = strchr(start, '\n'); | ||
79 | if (ptr) | ||
80 | *ptr ='\0'; | ||
81 | if (*start == '\0') | ||
82 | continue; | ||
83 | |||
84 | // skip comments | ||
85 | if (*start == '#') | ||
86 | continue; | ||
87 | ptr = strchr(start, '#'); | ||
88 | if (ptr) | ||
89 | *ptr = '\0'; | ||
90 | |||
91 | // extract exit status | ||
92 | int status; | ||
93 | int rv = sscanf(start, "%d\n", &status); | ||
94 | if (rv != 1) { | ||
95 | fprintf(stderr, "Error: invalid line %d in %s\n", line, fname); | ||
96 | exit(1); | ||
97 | } | ||
98 | |||
99 | // extract command | ||
100 | char *cmd = strchr(start, ' '); | ||
101 | if (!cmd) { | ||
102 | fprintf(stderr, "Error: invalid line %d in %s\n", line, fname); | ||
103 | exit(1); | ||
104 | } | ||
105 | |||
106 | // execute command | ||
107 | printf("TESTING %s\n", cmd); | ||
108 | fflush(0); | ||
109 | pid = fork(); | ||
110 | if (pid == -1) { | ||
111 | perror("fork"); | ||
112 | exit(1); | ||
113 | } | ||
114 | |||
115 | // child | ||
116 | if (pid == 0) { | ||
117 | char *earg[50]; | ||
118 | earg[0] = "/bin/bash"; | ||
119 | earg[1] = "-c"; | ||
120 | earg[2] = cmd; | ||
121 | earg[3] = NULL; | ||
122 | execvp(earg[0], earg); | ||
123 | } | ||
124 | // parent | ||
125 | else { | ||
126 | int exit_status; | ||
127 | |||
128 | alarm(TIMEOUT); | ||
129 | pid = waitpid(pid, &exit_status, 0); | ||
130 | if (pid == -1) { | ||
131 | perror("waitpid"); | ||
132 | exit(1); | ||
133 | } | ||
134 | |||
135 | if (WEXITSTATUS(exit_status) != status) | ||
136 | printf("ERROR TESTING: %s\n", cmd); | ||
137 | } | ||
138 | |||
139 | fflush(0); | ||
140 | } | ||
141 | fclose(fp); | ||
142 | |||
143 | return 0; | ||
144 | } \ No newline at end of file | ||
diff --git a/src/tools/ttytest.c b/src/tools/ttytest.c new file mode 100644 index 000000000..a449bf9ba --- /dev/null +++ b/src/tools/ttytest.c | |||
@@ -0,0 +1,36 @@ | |||
1 | #define _XOPEN_SOURCE 600 | ||
2 | #include <stdlib.h> | ||
3 | #include <stdio.h> | ||
4 | #include <fcntl.h> | ||
5 | #include <errno.h> | ||
6 | |||
7 | int main(void) { | ||
8 | int fdm; | ||
9 | int rc; | ||
10 | |||
11 | // initial | ||
12 | system("ls -l /dev/pts"); | ||
13 | |||
14 | fdm = posix_openpt(O_RDWR); | ||
15 | if (fdm < 0) { | ||
16 | perror("posix_openpt"); | ||
17 | return 1; | ||
18 | } | ||
19 | |||
20 | rc = grantpt(fdm); | ||
21 | if (rc != 0) { | ||
22 | perror("grantpt"); | ||
23 | return 1; | ||
24 | } | ||
25 | |||
26 | rc = unlockpt(fdm); | ||
27 | if (rc != 0) { | ||
28 | perror("unlockpt"); | ||
29 | return 1; | ||
30 | } | ||
31 | |||
32 | // final | ||
33 | system("ls -l /dev/pts"); | ||
34 | |||
35 | return 0; | ||
36 | } | ||