diff --git a/src/firejail/dhcp.c b/src/firejail/dhcp.c new file mode 100644 index 00000000000..7ce9a2b187f --- /dev/null +++ b/src/firejail/dhcp.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2014-2019 Firejail Authors + * + * This file is part of firejail project + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include "firejail.h" +#include +#include +#include +#include +#include +#include + +pid_t dhclient4_pid = 0; +pid_t dhclient6_pid = 0; + +typedef struct { + char *version_arg; + char *pid_file; + char *leases_file; + uint8_t generate_duid; + char *duid_leases_file; + pid_t *pid; + ptrdiff_t arg_offset; +} Dhclient; + +static const Dhclient dhclient4 = { .version_arg = "-4", + .pid_file = RUN_DHCLIENT_4_PID_FILE, + .leases_file = RUN_DHCLIENT_4_LEASES_FILE, + .generate_duid = 1, + .pid = &dhclient4_pid, + .arg_offset = offsetof(Bridge, arg_ip_dhcp) +}; + +static const Dhclient dhclient6 = { .version_arg = "-6", + .pid_file = RUN_DHCLIENT_6_PID_FILE, + .leases_file = RUN_DHCLIENT_6_LEASES_FILE, + .duid_leases_file = RUN_DHCLIENT_4_LEASES_FILE, + .pid = &dhclient6_pid, + .arg_offset = offsetof(Bridge, arg_ip6_dhcp) +}; + +static void dhcp_run_dhclient(const Dhclient *client) { + char *argv[256] = { "dhclient", + client->version_arg, + "-pf", client->pid_file, + "-lf", client->leases_file, + }; + int i = 6; + if (client->generate_duid) + argv[i++] = "-i"; + if (client->duid_leases_file) { + argv[i++] = "-df"; + argv[i++] = client->duid_leases_file; + } + if (arg_debug) + argv[i++] = "-v"; + if (*(uint8_t *) ((char *) &cfg.bridge0 + client->arg_offset)) + argv[i++] = cfg.bridge0.devsandbox; + if (*(uint8_t *) ((char *) &cfg.bridge1 + client->arg_offset)) + argv[i++] = cfg.bridge1.devsandbox; + if (*(uint8_t *) ((char *) &cfg.bridge2 + client->arg_offset)) + argv[i++] = cfg.bridge2.devsandbox; + if (*(uint8_t *) ((char *) &cfg.bridge3 + client->arg_offset)) + argv[i++] = cfg.bridge3.devsandbox; + + sbox_run_v(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_CAPS_NET_SERVICE | SBOX_SECCOMP, argv); +} + +static pid_t dhcp_read_pidfile(const Dhclient *client) { + // We have to run dhclient as a forking daemon (not pass the -d option), + // because we want to be notified of a successful DHCP lease by the parent process exit. + // However, try to be extra paranoid with race conditions, + // because dhclient only writes the daemon pid into the pidfile + // after its parent process has exited. + int tries = 0; + pid_t found = 0; + while (found == 0 && tries < 10) { + if (tries >= 1) + usleep(100000); + FILE *pidfile = fopen(client->pid_file, "r"); + if (pidfile) { + long pid; + if (fscanf(pidfile, "%ld", &pid) == 1) { + char *pidname = pid_proc_comm((pid_t) pid); + if (pidname && strcmp(pidname, "dhclient") == 0) + found = (pid_t) pid; + } + fclose(pidfile); + } + ++tries; + } + if (found == 0) { + fprintf(stderr, "Error: Cannot get dhclient %s PID from %s\n", + client->version_arg, client->pid_file); + exit(1); + } + return found; +} + +static void dhcp_start_dhclient(const Dhclient *client) { + dhcp_run_dhclient(client); + *(client->pid) = dhcp_read_pidfile(client); +} + +static void dhcp_waitll(const char *ifname) { + sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 3, PATH_FNET, "waitll", ifname); +} + +static void dhcp_waitll_all() { + if (cfg.bridge0.arg_ip6_dhcp) + dhcp_waitll(cfg.bridge0.devsandbox); + if (cfg.bridge1.arg_ip6_dhcp) + dhcp_waitll(cfg.bridge1.devsandbox); + if (cfg.bridge2.arg_ip6_dhcp) + dhcp_waitll(cfg.bridge2.devsandbox); + if (cfg.bridge3.arg_ip6_dhcp) + dhcp_waitll(cfg.bridge3.devsandbox); +} + +void dhcp_start(void) { + if (!any_dhcp()) + return; + + EUID_ROOT(); + if (mkdir(RUN_DHCLIENT_DIR, 0700)) + errExit("mkdir"); + + if (any_ip_dhcp()) { + dhcp_start_dhclient(&dhclient4); + if (arg_debug) + printf("Running dhclient -4 in the background as pid %ld\n", (long) dhclient4_pid); + } + if (any_ip6_dhcp()) { + dhcp_waitll_all(); + dhcp_start_dhclient(&dhclient6); + if (arg_debug) + printf("Running dhclient -6 in the background as pid %ld\n", (long) dhclient6_pid); + if (dhclient4_pid == dhclient6_pid) { + fprintf(stderr, "Error: dhclient -4 and -6 have the same PID: %ld\n", (long) dhclient4_pid); + exit(1); + } + } +} diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 03bcbda4647..4beae587ed5 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -103,6 +103,8 @@ typedef struct bridge_t { // flags uint8_t arg_ip_none; // --ip=none + uint8_t arg_ip_dhcp; + uint8_t arg_ip6_dhcp; uint8_t macvlan; // set by --net=eth0 (or eth1, ...); reset by --net=br0 (or br1, ...) uint8_t configured; uint8_t scan; // set by --scan @@ -237,6 +239,24 @@ static inline int any_interface_configured(void) { return 0; } +static inline int any_ip_dhcp(void) { + if (cfg.bridge0.arg_ip_dhcp || cfg.bridge1.arg_ip_dhcp || cfg.bridge2.arg_ip_dhcp || cfg.bridge3.arg_ip_dhcp) + return 1; + else + return 0; +} + +static inline int any_ip6_dhcp(void) { + if (cfg.bridge0.arg_ip6_dhcp || cfg.bridge1.arg_ip6_dhcp || cfg.bridge2.arg_ip6_dhcp || cfg.bridge3.arg_ip6_dhcp) + return 1; + else + return 0; +} + +static inline int any_dhcp(void) { + return any_ip_dhcp() || any_ip6_dhcp(); +} + extern int arg_private; // mount private /home extern int arg_private_cache; // private home/.cache extern int arg_debug; // print debug messages @@ -792,9 +812,11 @@ void build_appimage_cmdline(char **command_line, char **window_title, int argc, #define SBOX_ALLOW_STDIN (1 << 5) // don't close stdin #define SBOX_STDIN_FROM_FILE (1 << 6) // open file and redirect it to stdin #define SBOX_CAPS_HIDEPID (1 << 7) // hidepid caps filter for running firemon +#define SBOX_CAPS_NET_SERVICE (1 << 8) // caps filter for programs running network services // run sbox int sbox_run(unsigned filter, int num, ...); +int sbox_run_v(unsigned filter, char * const arg[]); // run_files.c void delete_run_files(pid_t pid); @@ -806,4 +828,9 @@ void set_profile_run_file(pid_t pid, const char *fname); // dbus.c void dbus_disable(void); +// dhcp.c +extern pid_t dhclient4_pid; +extern pid_t dhclient6_pid; +void dhcp_start(void); + #endif diff --git a/src/firejail/fs_hostname.c b/src/firejail/fs_hostname.c index 9da01b24c3a..60c65746bd8 100644 --- a/src/firejail/fs_hostname.c +++ b/src/firejail/fs_hostname.c @@ -89,7 +89,7 @@ void fs_hostname(const char *hostname) { } void fs_resolvconf(void) { - if (cfg.dns1 == NULL) + if (cfg.dns1 == NULL && !any_dhcp()) return; if (arg_debug) @@ -108,7 +108,8 @@ void fs_resolvconf(void) { if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; // for resolv.conf we create a brand new file - if (strcmp(entry->d_name, "resolv.conf") == 0) + if (strcmp(entry->d_name, "resolv.conf") == 0 || + strcmp(entry->d_name, "resolv.conf.dhclient-new") == 0) continue; // printf("linking %s\n", entry->d_name); @@ -169,8 +170,11 @@ void fs_resolvconf(void) { exit(1); } - if (cfg.dns1) + if (cfg.dns1) { + if (any_dhcp()) + fwarning("network setup uses DHCP, nameservers will likely be overwritten\n"); fprintf(fp, "nameserver %s\n", cfg.dns1); + } if (cfg.dns2) fprintf(fp, "nameserver %s\n", cfg.dns2); if (cfg.dns3) diff --git a/src/firejail/main.c b/src/firejail/main.c index 179f8ddf9c9..0b9ebc482f4 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c @@ -2144,7 +2144,10 @@ int main(int argc, char **argv) { // configure this IP address for the last bridge defined if (strcmp(argv[i] + 5, "none") == 0) br->arg_ip_none = 1; - else { + else if (strcmp(argv[i] + 5, "dhcp") == 0) { + br->arg_ip_none = 1; + br->arg_ip_dhcp = 1; + } else { if (atoip(argv[i] + 5, &br->ipsandbox)) { fprintf(stderr, "Error: invalid IP address\n"); exit(1); @@ -2184,20 +2187,24 @@ int main(int argc, char **argv) { fprintf(stderr, "Error: no network device configured\n"); exit(1); } - if (br->ip6sandbox) { + if (br->arg_ip6_dhcp || br->ip6sandbox) { fprintf(stderr, "Error: cannot configure the IP address twice for the same interface\n"); exit(1); } // configure this IP address for the last bridge defined - if (check_ip46_address(argv[i] + 6) == 0) { - fprintf(stderr, "Error: invalid IPv6 address\n"); - exit(1); - } - - br->ip6sandbox = strdup(argv[i] + 6); - if (br->ip6sandbox == NULL) - errExit("strdup"); + if (strcmp(argv[i] + 6, "dhcp") == 0) + br->arg_ip6_dhcp = 1; + else { + if (check_ip46_address(argv[i] + 6) == 0) { + fprintf(stderr, "Error: invalid IPv6 address\n"); + exit(1); + } + + br->ip6sandbox = strdup(argv[i] + 6); + if (br->ip6sandbox == NULL) + errExit("strdup"); + } } else exit_err_feature("networking"); diff --git a/src/firejail/network_main.c b/src/firejail/network_main.c index 6800bde8d56..ad297efc795 100644 --- a/src/firejail/network_main.c +++ b/src/firejail/network_main.c @@ -246,6 +246,10 @@ void net_check_cfg(void) { if (cfg.defaultgw) check_default_gw(cfg.defaultgw); else { + // if the first network has no assigned address, + // do not try to set up a gateway, because it will fail + if (cfg.bridge0.arg_ip_none) + return; // first network is a regular bridge if (cfg.bridge0.macvlan == 0) cfg.defaultgw = cfg.bridge0.ip; diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 9a724331bde..9596785019a 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c @@ -672,7 +672,10 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { // configure this IP address for the last bridge defined if (strcmp(ptr + 3, "none") == 0) br->arg_ip_none = 1; - else { + else if (strcmp(ptr + 3, "dhcp") == 0) { + br->arg_ip_none = 1; + br->arg_ip_dhcp = 1; + } else { if (atoip(ptr + 3, &br->ipsandbox)) { fprintf(stderr, "Error: invalid IP address\n"); exit(1); @@ -693,21 +696,24 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { fprintf(stderr, "Error: no network device configured\n"); exit(1); } - if (br->ip6sandbox) { + if (br->arg_ip6_dhcp || br->ip6sandbox) { fprintf(stderr, "Error: cannot configure the IP address twice for the same interface\n"); exit(1); } - // configure this IP address for the last bridge defined - if (check_ip46_address(ptr + 4) == 0) { - fprintf(stderr, "Error: invalid IPv6 address\n"); - exit(1); - } - - br->ip6sandbox = strdup(ptr + 4); - if (br->ip6sandbox == NULL) - errExit("strdup"); - + // configure this IP address for the last bridge defined + if (strcmp(ptr + 4, "dhcp") == 0) + br->arg_ip6_dhcp = 1; + else { + if (check_ip46_address(ptr + 4) == 0) { + fprintf(stderr, "Error: invalid IPv6 address\n"); + exit(1); + } + + br->ip6sandbox = strdup(ptr + 4); + if (br->ip6sandbox == NULL) + errExit("strdup"); + } } else warning_feature_disabled("networking"); diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 995e98f9fea..bcd812ab277 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c @@ -337,6 +337,8 @@ static int monitor_application(pid_t app_pid) { continue; if (pid == 1) continue; + if (pid == dhclient4_pid || pid == dhclient6_pid) + continue; // todo: make this generic // Dillo browser leaves a dpid process running, we need to shut it down @@ -1015,6 +1017,11 @@ int sandbox(void* sandbox_arg) { fs_logger_print(); fs_logger_change_owner(); + //**************************** + // start dhcp client + //**************************** + dhcp_start(); + //**************************** // set application environment //**************************** diff --git a/src/firejail/sbox.c b/src/firejail/sbox.c index e5739ecb595..a1e65cd3c4c 100644 --- a/src/firejail/sbox.c +++ b/src/firejail/sbox.c @@ -105,23 +105,34 @@ static struct sock_fprog prog = { }; int sbox_run(unsigned filtermask, int num, ...) { - EUID_ROOT(); - - int i; va_list valist; va_start(valist, num); // build argument list - char *arg[num + 1]; + char **arg = malloc((num + 1) * sizeof(char *)); + int i; for (i = 0; i < num; i++) arg[i] = va_arg(valist, char*); arg[i] = NULL; va_end(valist); + int status = sbox_run_v(filtermask, arg); + + free(arg); + + return status; +} + +int sbox_run_v(unsigned filtermask, char * const arg[]) { + EUID_ROOT(); + if (arg_debug) { printf("sbox run: "); - for (i = 0; i <= num; i++) + int i = 0; + while (arg[i]) { printf("%s ", arg[i]); + i++; + } printf("\n"); } @@ -171,7 +182,7 @@ int sbox_run(unsigned filtermask, int num, ...) { // close all other file descriptors int max = 20; // getdtablesize() is overkill for a firejail process - for (i = 3; i < max; i++) + for (int i = 3; i < max; i++) close(i); // close open files umask(027); @@ -179,23 +190,34 @@ int sbox_run(unsigned filtermask, int num, ...) { // apply filters if (filtermask & SBOX_CAPS_NONE) { caps_drop_all(); - } - else if (filtermask & SBOX_CAPS_NETWORK) { + } else { + uint64_t set = 0; + if (filtermask & SBOX_CAPS_NETWORK) { #ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files - uint64_t set = ((uint64_t) 1) << CAP_NET_ADMIN; - set |= ((uint64_t) 1) << CAP_NET_RAW; - caps_set(set); + set |= ((uint64_t) 1) << CAP_NET_ADMIN; + set |= ((uint64_t) 1) << CAP_NET_RAW; #endif - } - else if (filtermask & SBOX_CAPS_HIDEPID) { + } + if (filtermask & SBOX_CAPS_HIDEPID) { #ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files - uint64_t set = ((uint64_t) 1) << CAP_SYS_PTRACE; - set |= ((uint64_t) 1) << CAP_SYS_PACCT; - caps_set(set); + set |= ((uint64_t) 1) << CAP_SYS_PTRACE; + set |= ((uint64_t) 1) << CAP_SYS_PACCT; #endif - } + } + if (filtermask & SBOX_CAPS_NET_SERVICE) { +#ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files + set |= ((uint64_t) 1) << CAP_NET_BIND_SERVICE; + set |= ((uint64_t) 1) << CAP_NET_BROADCAST; +#endif + } + if (set != 0) { // some SBOX_CAPS_ flag was specified, drop all other capabilities +#ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files + caps_set(set); +#endif + } + } - if (filtermask & SBOX_SECCOMP) { + if (filtermask & SBOX_SECCOMP) { if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { perror("prctl(NO_NEW_PRIVS)"); } diff --git a/src/fnet/fnet.h b/src/fnet/fnet.h index 4900967f786..4d0d62b39d1 100644 --- a/src/fnet/fnet.h +++ b/src/fnet/fnet.h @@ -47,6 +47,7 @@ int net_get_mac(const char *ifname, unsigned char mac[6]); void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu); int net_if_mac(const char *ifname, const unsigned char mac[6]); void net_if_ip6(const char *ifname, const char *addr6); +void net_if_waitll(const char *ifname); // arp.c diff --git a/src/fnet/interface.c b/src/fnet/interface.c index 7e7cceeed8d..1c07ec8f711 100644 --- a/src/fnet/interface.c +++ b/src/fnet/interface.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include static void check_if_name(const char *ifname) { if (strlen(ifname) > IFNAMSIZ) { @@ -370,3 +372,123 @@ void net_if_ip6(const char *ifname, const char *addr6) { close(sock); } + +static int net_netlink_address_tentative(struct nlmsghdr *current_header) { + struct ifaddrmsg *msg = NLMSG_DATA(current_header); + struct rtattr *rta = IFA_RTA(msg); + size_t msg_len = IFA_PAYLOAD(current_header); + int has_flags = 0; + while (RTA_OK(rta, msg_len)) { + if (rta->rta_type == IFA_FLAGS) { + has_flags = 1; + uint32_t *flags = RTA_DATA(rta); + if (*flags & IFA_F_TENTATIVE) + return 1; + } + rta = RTA_NEXT(rta, msg_len); + } + // According to , if an IFA_FLAGS attribute is present, + // the field ifa_flags should be ignored. + return !has_flags && (msg->ifa_flags & IFA_F_TENTATIVE); +} + +static int net_netlink_if_has_ll(int sock, int index) { + struct { + struct nlmsghdr header; + struct ifaddrmsg message; + } req; + memset(&req, 0, sizeof(req)); + req.header.nlmsg_len = NLMSG_LENGTH(sizeof(req.message)); + req.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + req.header.nlmsg_type = RTM_GETADDR; + req.message.ifa_family = AF_INET6; + if (send(sock, &req, req.header.nlmsg_len, 0) != req.header.nlmsg_len) + errExit("send"); + + int found = 0; + int all_parts_processed = 0; + while (!all_parts_processed) { + char buf[16384]; + ssize_t len = recv(sock, buf, sizeof(buf), 0); + if (len < 0) + errExit("recv"); + if (len < sizeof(struct nlmsghdr)) { + fprintf(stderr, "Received incomplete netlink message\n"); + exit(1); + } + + struct nlmsghdr *current_header = (struct nlmsghdr *) buf; + while (NLMSG_OK(current_header, len)) { + switch (current_header->nlmsg_type) { + case RTM_NEWADDR: { + struct ifaddrmsg *msg = NLMSG_DATA(current_header); + if (!found && msg->ifa_index == index && msg->ifa_scope == RT_SCOPE_LINK && + !net_netlink_address_tentative(current_header)) + found = 1; + } + break; + case NLMSG_NOOP: + break; + case NLMSG_DONE: + all_parts_processed = 1; + break; + case NLMSG_ERROR: { + struct nlmsgerr *err = NLMSG_DATA(current_header); + fprintf(stderr, "Netlink error: %d\n", err->error); + exit(1); + } + break; + default: + fprintf(stderr, "Unknown netlink message type: %u\n", current_header->nlmsg_type); + exit(1); + break; + } + + current_header = NLMSG_NEXT(current_header, len); + } + } + + return found; +} + +// wait for a link-local IPv6 address for DHCPv6 +// ex: firejail --net=br0 --ip6=dhcp +void net_if_waitll(const char *ifname) { + // find interface index + int inet6_sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP); + if (inet6_sock < 0) { + fprintf(stderr, "Error fnet: IPv6 is not supported on this system\n"); + exit(1); + } + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); + ifr.ifr_addr.sa_family = AF_INET; + if (ioctl(inet6_sock, SIOGIFINDEX, &ifr) < 0) { + perror("ioctl SIOGIFINDEX"); + exit(1); + } + close(inet6_sock); + int index = ifr.ifr_ifindex; + + // poll for link-local address + int netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (netlink_sock < 0) + errExit("socket"); + int tries = 0; + int found = 0; + while (tries < 60 && !found) { + if (tries >= 1) + usleep(500000); + + found = net_netlink_if_has_ll(netlink_sock, index); + + tries++; + } + close(netlink_sock); + + if (!found) { + fprintf(stderr, "Waiting for link-local IPv6 address of %s timed out\n", ifname); + exit(1); + } +} diff --git a/src/fnet/main.c b/src/fnet/main.c index 890f842f667..3ef500b5e53 100644 --- a/src/fnet/main.c +++ b/src/fnet/main.c @@ -47,6 +47,7 @@ static void usage(void) { printf("\tfnet config mac addr\n"); printf("\tfnet config ipv6 dev ip\n"); printf("\tfnet ifup dev\n"); + printf("\tfnet waitll dev\n"); } int main(int argc, char **argv) { @@ -141,6 +142,9 @@ printf("\n"); else if (argc == 5 && strcmp(argv[1], "config") == 0 && strcmp(argv[2], "ipv6") == 0) { net_if_ip6(argv[3], argv[4]); } + else if (argc == 3 && strcmp(argv[1], "waitll") == 0) { + net_if_waitll(argv[2]); + } else { fprintf(stderr, "Error fnet: invalid arguments\n"); return 1; diff --git a/src/include/rundefs.h b/src/include/rundefs.h index df135b9ca8d..8119f31e935 100644 --- a/src/include/rundefs.h +++ b/src/include/rundefs.h @@ -49,6 +49,11 @@ #define RUN_LIB_DIR RUN_MNT_DIR "/lib" #define RUN_LIB_FILE RUN_MNT_DIR "/libfiles" #define RUN_DNS_ETC RUN_MNT_DIR "/dns-etc" +#define RUN_DHCLIENT_DIR RUN_MNT_DIR "/dhclient" +#define RUN_DHCLIENT_4_LEASES_FILE RUN_DHCLIENT_DIR "/dhclient.leases" +#define RUN_DHCLIENT_6_LEASES_FILE RUN_DHCLIENT_DIR "/dhclient6.leases" +#define RUN_DHCLIENT_4_PID_FILE RUN_DHCLIENT_DIR "/dhclient.pid" +#define RUN_DHCLIENT_6_PID_FILE RUN_DHCLIENT_DIR "/dhclient6.pid" #define RUN_SECCOMP_DIR RUN_MNT_DIR "/seccomp" #define RUN_SECCOMP_LIST RUN_SECCOMP_DIR "/seccomp.list" // list of seccomp files installed