From abe5cb027416771da3d01c9b55d12a8f70618ed8 Mon Sep 17 00:00:00 2001 From: netblue30 Date: Thu, 27 Oct 2016 08:58:48 -0400 Subject: network code split --- Makefile.in | 4 +- configure | 3 +- configure.ac | 2 +- src/firejail/Makefile.in | 4 +- src/firejail/appimage_size.c | 20 +++- src/firejail/firejail.h | 6 -- src/firejail/network.c | 46 --------- src/firejail/network_main.c | 87 +++++++++++++--- src/firejail/veth.c | 236 ------------------------------------------- src/fnet/Makefile.in | 43 ++++++++ src/fnet/fnet.h | 40 ++++++++ src/fnet/interface.c | 183 +++++++++++++++++++++++++++++++++ src/fnet/main.c | 63 ++++++++++++ src/fnet/veth.c | 230 +++++++++++++++++++++++++++++++++++++++++ 14 files changed, 658 insertions(+), 309 deletions(-) delete mode 100644 src/firejail/veth.c create mode 100644 src/fnet/Makefile.in create mode 100644 src/fnet/fnet.h create mode 100644 src/fnet/interface.c create mode 100644 src/fnet/main.c create mode 100644 src/fnet/veth.c diff --git a/Makefile.in b/Makefile.in index dbf53e2cb..0ae8fc903 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,6 +1,6 @@ all: apps man MYLIBS = src/lib -APPS = src/firejail src/firemon src/firecfg src/libtrace src/libtracelog src/ftee src/faudit src/libconnect +APPS = src/firejail src/firemon src/firecfg src/libtrace src/libtracelog src/ftee src/faudit src/libconnect src/fnet MANPAGES = firejail.1 firemon.1 firecfg.1 firejail-profile.5 firejail-login.5 prefix=@prefix@ @@ -76,6 +76,7 @@ realinstall: install -c -m 0755 src/fshaper/fshaper.sh $(DESTDIR)/$(libdir)/firejail/. install -c -m 0644 src/firecfg/firecfg.config $(DESTDIR)/$(libdir)/firejail/. install -c -m 0755 src/faudit/faudit $(DESTDIR)/$(libdir)/firejail/. + install -c -m 0755 src/fnet/fnet $(DESTDIR)/$(libdir)/firejail/. # documents install -m 0755 -d $(DESTDIR)/$(DOCDIR) install -c -m 0644 COPYING $(DESTDIR)/$(DOCDIR)/. @@ -124,6 +125,7 @@ install-strip: all strip src/libconnect/libconnect.so strip src/ftee/ftee strip src/faudit/faudit + strip src/fnet/fnet $(MAKE) realinstall uninstall: diff --git a/configure b/configure index a470dffba..58d236815 100755 --- a/configure +++ b/configure @@ -3759,7 +3759,7 @@ if test "$prefix" = /usr; then sysconfdir="/etc" fi -ac_config_files="$ac_config_files Makefile src/lib/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/libconnect/Makefile" +ac_config_files="$ac_config_files Makefile src/lib/Makefile src/fnet/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/libconnect/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -4470,6 +4470,7 @@ do case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "src/lib/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib/Makefile" ;; + "src/fnet/Makefile") CONFIG_FILES="$CONFIG_FILES src/fnet/Makefile" ;; "src/firejail/Makefile") CONFIG_FILES="$CONFIG_FILES src/firejail/Makefile" ;; "src/firemon/Makefile") CONFIG_FILES="$CONFIG_FILES src/firemon/Makefile" ;; "src/libtrace/Makefile") CONFIG_FILES="$CONFIG_FILES src/libtrace/Makefile" ;; diff --git a/configure.ac b/configure.ac index 95947a8e3..c7125e9c5 100644 --- a/configure.ac +++ b/configure.ac @@ -148,7 +148,7 @@ if test "$prefix" = /usr; then sysconfdir="/etc" fi -AC_OUTPUT(Makefile src/lib/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/libconnect/Makefile) +AC_OUTPUT(Makefile src/lib/Makefile src/fnet/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/libconnect/Makefile) echo echo "Configuration options:" diff --git a/src/firejail/Makefile.in b/src/firejail/Makefile.in index fce460906..7d4bcb19b 100644 --- a/src/firejail/Makefile.in +++ b/src/firejail/Makefile.in @@ -30,11 +30,11 @@ BINOBJS = $(foreach file, $(OBJS), $file) CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_SECCOMP) $(HAVE_GLOBALCFG) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_BIND) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread -%.o : %.c $(H_FILE_LIST) ../include/common.h ../include/euid_common.h ../include/libnetlink.h ../include/pid.h +%.o : %.c $(H_FILE_LIST) ../include/common.h ../include/euid_common.h ../include/pid.h $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ firejail: $(OBJS) ../lib/libnetlink.o ../lib/common.o - $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/libnetlink.o ../lib/common.o $(LIBS) $(EXTRA_LDFLAGS) + $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/common.o $(LIBS) $(EXTRA_LDFLAGS) clean:; rm -f *.o firejail firejail.1 firejail.1.gz diff --git a/src/firejail/appimage_size.c b/src/firejail/appimage_size.c index c8b3d28c5..64fff6901 100644 --- a/src/firejail/appimage_size.c +++ b/src/firejail/appimage_size.c @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2014-2016 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. + */ /* Compile with: gcc elfsize.c -o elfsize @@ -9,7 +28,6 @@ Size of section headers e_shentsize 64 Number of section headers e_shnum 29 e_shoff + ( e_shentsize * e_shnum ) = 126584 */ - #include #include #include diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 9a9bb1ae7..6c0441472 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -362,7 +362,6 @@ void net_if_ip6(const char *ifname, const char *addr6); int net_get_if_addr(const char *bridge, uint32_t *ip, uint32_t *mask, uint8_t mac[6], int *mtu); int net_add_route(uint32_t dest, uint32_t mask, uint32_t gw); void net_ifprint(void); -void net_bridge_add_interface(const char *bridge, const char *dev); uint32_t network_get_defaultgw(void); int net_config_mac(const char *ifname, const unsigned char mac[6]); int net_get_mac(const char *ifname, unsigned char mac[6]); @@ -432,11 +431,6 @@ uint32_t arp_assign(const char *dev, Bridge *br); // scan interface (--scan option) void arp_scan(const char *dev, uint32_t srcaddr, uint32_t srcmask); -// veth.c -int net_create_veth(const char *dev, const char *nsdev, unsigned pid); -int net_create_macvlan(const char *dev, const char *parent, unsigned pid); -int net_move_interface(const char *dev, unsigned pid); - // util.c void drop_privs(int nogroups); int mkpath_as_root(const char* path); diff --git a/src/firejail/network.c b/src/firejail/network.c index 4473ef099..ac0d86559 100644 --- a/src/firejail/network.c +++ b/src/firejail/network.c @@ -431,52 +431,6 @@ int net_add_route(uint32_t ip, uint32_t mask, uint32_t gw) { } -// add a veth device to a bridge -void net_bridge_add_interface(const char *bridge, const char *dev) { - if (strlen(bridge) > IFNAMSIZ) { - fprintf(stderr, "Error: invalid network device name %s\n", bridge); - exit(1); - } - - // somehow adding the interface to the bridge resets MTU on bridge device!!! - // workaround: restore MTU on the bridge device - // todo: put a real fix in - int mtu1 = net_get_mtu(bridge); - - struct ifreq ifr; - int err; - int ifindex = if_nametoindex(dev); - - if (ifindex <= 0) - errExit("if_nametoindex"); - - int sock; - if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) - errExit("socket"); - - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, bridge, IFNAMSIZ); -#ifdef SIOCBRADDIF - ifr.ifr_ifindex = ifindex; - err = ioctl(sock, SIOCBRADDIF, &ifr); - if (err < 0) -#endif - { - unsigned long args[4] = { BRCTL_ADD_IF, ifindex, 0, 0 }; - - ifr.ifr_data = (char *) args; - err = ioctl(sock, SIOCDEVPRIVATE, &ifr); - } - (void) err; - close(sock); - - int mtu2 = net_get_mtu(bridge); - if (mtu1 != mtu2) { - if (arg_debug) - printf("Restoring MTU for %s\n", bridge); - net_set_mtu(bridge, mtu1); - } -} #define BUFSIZE 1024 uint32_t network_get_defaultgw(void) { diff --git a/src/firejail/network_main.c b/src/firejail/network_main.c index 907b84642..d2aa84bb6 100644 --- a/src/firejail/network_main.c +++ b/src/firejail/network_main.c @@ -23,6 +23,50 @@ #include #include #include +#include + +static void fnet_run(int num, ...) { + int i; + va_list valist; + va_start(valist, num); + + char *fnet; + if (asprintf(&fnet, "%s/firejail/fnet", LIBDIR) == -1) + errExit("asprintf"); + + char *arg[num + 2]; + arg[0] = fnet; + for (i = 0; i < num; i++) + arg[i + 1] = va_arg(valist, char*); + arg[i + 1] = NULL; + + pid_t child = fork(); + if (child < 0) + errExit("fork"); + if (child == 0) { + // elevate privileges in order to get grsecurity working + if (setreuid(0, 0)) + errExit("setreuid"); + if (setregid(0, 0)) + errExit("setregid"); + + execvp(arg[0], arg); + perror("execl"); + _exit(1); + } + + int status; + if (waitpid(child, &status, 0) == -1 ) { + errExit("waitpid"); + } + if (WIFEXITED(status) && status != 0) { + fprintf(stderr, "Error: cannot run fnet\n"); + exit(1); + } + + va_end(valist); + free(fnet); +} // configure bridge structure // - extract ip address and mask from the bridge interface @@ -127,13 +171,12 @@ void net_configure_veth_pair(Bridge *br, const char *ifname, pid_t child) { else dev = br->veth_name; - net_create_veth(dev, ifname, child); - - // add interface to the bridge - net_bridge_add_interface(br->dev, dev); - - // bring up the interface - net_if_up(dev); +// net_create_veth(dev, ifname, child); + char *cstr; + if (asprintf(&cstr, "%d", child) == -1) + errExit("asprintf"); + fnet_run(6, "create", "veth", dev, ifname, br->dev, cstr); + free(cstr); char *msg; if (asprintf(&msg, "%d.%d.%d.%d address assigned to sandbox", PRINT_IP(br->ipsandbox)) == -1) @@ -290,47 +333,61 @@ void net_dns_print(pid_t pid) { } void network_main(pid_t child) { + char *cstr; + if (asprintf(&cstr, "%d", child) == -1) + errExit("asprintf"); + // create veth pair or macvlan device if (cfg.bridge0.configured) { if (cfg.bridge0.macvlan == 0) { net_configure_veth_pair(&cfg.bridge0, "eth0", child); } else - net_create_macvlan(cfg.bridge0.devsandbox, cfg.bridge0.dev, child); +// net_create_macvlan(cfg.bridge0.devsandbox, cfg.bridge0.dev, child); + fnet_run(5, "create", "macvlan", cfg.bridge0.devsandbox, cfg.bridge0.dev, cstr); } if (cfg.bridge1.configured) { if (cfg.bridge1.macvlan == 0) net_configure_veth_pair(&cfg.bridge1, "eth1", child); else - net_create_macvlan(cfg.bridge1.devsandbox, cfg.bridge1.dev, child); +// net_create_macvlan(cfg.bridge1.devsandbox, cfg.bridge1.dev, child); + fnet_run(5, "create", "macvlan", cfg.bridge1.devsandbox, cfg.bridge1.dev, cstr); } if (cfg.bridge2.configured) { if (cfg.bridge2.macvlan == 0) net_configure_veth_pair(&cfg.bridge2, "eth2", child); else - net_create_macvlan(cfg.bridge2.devsandbox, cfg.bridge2.dev, child); +// net_create_macvlan(cfg.bridge2.devsandbox, cfg.bridge2.dev, child); + fnet_run(5, "create", "macvlan", cfg.bridge2.devsandbox, cfg.bridge2.dev, cstr); } if (cfg.bridge3.configured) { if (cfg.bridge3.macvlan == 0) net_configure_veth_pair(&cfg.bridge3, "eth3", child); else - net_create_macvlan(cfg.bridge3.devsandbox, cfg.bridge3.dev, child); +// net_create_macvlan(cfg.bridge3.devsandbox, cfg.bridge3.dev, child); + fnet_run(5, "create", "macvlan", cfg.bridge3.devsandbox, cfg.bridge3.dev, cstr); } // move interfaces in sandbox if (cfg.interface0.configured) { - net_move_interface(cfg.interface0.dev, child); +// net_move_interface(cfg.interface0.dev, child); + fnet_run(3, "moveif", cfg.interface0.dev, cstr); } if (cfg.interface1.configured) { - net_move_interface(cfg.interface1.dev, child); +// net_move_interface(cfg.interface1.dev, child); + fnet_run(3, "moveif", cfg.interface1.dev, cstr); } if (cfg.interface2.configured) { - net_move_interface(cfg.interface2.dev, child); +// net_move_interface(cfg.interface2.dev, child); + fnet_run(3, "moveif", cfg.interface3.dev, cstr); } if (cfg.interface3.configured) { - net_move_interface(cfg.interface3.dev, child); +// net_move_interface(cfg.interface3.dev, child); + fnet_run(3, "moveif", cfg.interface3.dev, cstr); } + + free(cstr); } diff --git a/src/firejail/veth.c b/src/firejail/veth.c deleted file mode 100644 index df3c1d1f9..000000000 --- a/src/firejail/veth.c +++ /dev/null @@ -1,236 +0,0 @@ -/* code based on iproute2 ip/iplink.c, modified to be included in firejail project - * - * Original source code: - * - * Information: - * http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2 - * - * Download: - * http://www.kernel.org/pub/linux/utils/net/iproute2/ - * - * Repository: - * git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git - * - * License: GPL v2 - * - * Original copyright header - * - * iplink.c "ip link". - * - * 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. - * - * Authors: Alexey Kuznetsov, - * - */ - /* - * Copyright (C) 2014-2016 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/libnetlink.h" -#include -#include - -struct iplink_req -{ - struct nlmsghdr n; - struct ifinfomsg i; - char buf[1024]; -}; - -static struct rtnl_handle rth = { .fd = -1 }; - -int net_create_veth(const char *dev, const char *nsdev, unsigned pid) { - int len; - struct iplink_req req; - - if (arg_debug) - printf("create veth %s/%s/%u\n", dev, nsdev, pid); - assert(dev); - assert(nsdev); - assert(pid); - - if (rtnl_open(&rth, 0) < 0) { - fprintf(stderr, "cannot open netlink\n"); - exit(1); - } - - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; - req.n.nlmsg_type = RTM_NEWLINK; - req.i.ifi_family = 0; - - if (dev) { - len = strlen(dev) + 1; - addattr_l(&req.n, sizeof(req), IFLA_IFNAME, dev, len); - } - - struct rtattr *linkinfo = NLMSG_TAIL(&req.n); - addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); - addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, "veth", strlen("veth")); - - struct rtattr * data = NLMSG_TAIL(&req.n); - addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); - - struct rtattr * peerdata = NLMSG_TAIL(&req.n); - addattr_l (&req.n, sizeof(req), VETH_INFO_PEER, NULL, 0); - req.n.nlmsg_len += sizeof(struct ifinfomsg); - - // place the link in the child namespace - addattr_l (&req.n, sizeof(req), IFLA_NET_NS_PID, &pid, 4); - - if (nsdev) { - int len = strlen(nsdev) + 1; - addattr_l(&req.n, sizeof(req), IFLA_IFNAME, nsdev, len); - } - peerdata->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)peerdata; - - data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; - linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; - - // send message - if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) - exit(2); - - return 0; -} - - -int net_create_macvlan(const char *dev, const char *parent, unsigned pid) { - int len; - struct iplink_req req; - if (arg_debug) - printf("create macvlan %s, parent %s\n", dev, parent); - assert(dev); - assert(parent); - - if (rtnl_open(&rth, 0) < 0) { - fprintf(stderr, "cannot open netlink\n"); - exit(1); - } - - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; - req.n.nlmsg_type = RTM_NEWLINK; - req.i.ifi_family = 0; - - // find parent ifindex - int parent_ifindex = if_nametoindex(parent); - if (parent_ifindex <= 0) { - fprintf(stderr, "Error: cannot find network device %s\n", parent); - exit(1); - } - - // add parent - addattr_l(&req.n, sizeof(req), IFLA_LINK, &parent_ifindex, 4); - - // add new interface name - len = strlen(dev) + 1; - addattr_l(&req.n, sizeof(req), IFLA_IFNAME, dev, len); - - // place the interface in child namespace - addattr_l (&req.n, sizeof(req), IFLA_NET_NS_PID, &pid, 4); - - - // add link info for the new interface - struct rtattr *linkinfo = NLMSG_TAIL(&req.n); - addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); - addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, "macvlan", strlen("macvlan")); - - // set macvlan bridge mode - struct rtattr * data = NLMSG_TAIL(&req.n); - addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); - int macvlan_type = MACVLAN_MODE_BRIDGE; - addattr_l (&req.n, sizeof(req), IFLA_INFO_KIND, &macvlan_type, 4); - - data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; -// req.n.nlmsg_len += sizeof(struct ifinfomsg); - - - data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; - linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; - - // send message - if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) - exit(2); - - return 0; -} - -// move the interface dev in namespace of program pid -// when the interface is moved, netlink does not preserve interface configuration -int net_move_interface(const char *dev, unsigned pid) { - struct iplink_req req; - if (arg_debug) - printf("move device %s inside the namespace\n", dev); - assert(dev); - - if (rtnl_open(&rth, 0) < 0) { - fprintf(stderr, "cannot open netlink\n"); - exit(1); - } - - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = RTM_NEWLINK; - req.i.ifi_family = 0; - - // find ifindex - int ifindex = if_nametoindex(dev); - if (ifindex <= 0) { - fprintf(stderr, "Error: cannot find interface %s\n", dev); - exit(1); - } - req.i.ifi_index = ifindex; - - // place the interface in child namespace - addattr_l (&req.n, sizeof(req), IFLA_NET_NS_PID, &pid, 4); - - // send message - if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) - exit(2); - - return 0; -} - -/* -int main(int argc, char **argv) { - printf("Hello\n"); - - - char *dev = argv[3]; - char *nsdev = argv[8]; - unsigned pid; - sscanf(argv[10], "%u", &pid); - - - net_create_veth(dev, nsdev, pid); - - return 0; -} -*/ \ No newline at end of file diff --git a/src/fnet/Makefile.in b/src/fnet/Makefile.in new file mode 100644 index 000000000..1bfb4c68d --- /dev/null +++ b/src/fnet/Makefile.in @@ -0,0 +1,43 @@ +all: fnet + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +sysconfdir=@sysconfdir@ + +VERSION=@PACKAGE_VERSION@ +NAME=@PACKAGE_NAME@ +HAVE_SECCOMP_H=@HAVE_SECCOMP_H@ +HAVE_SECCOMP=@HAVE_SECCOMP@ +HAVE_CHROOT=@HAVE_CHROOT@ +HAVE_BIND=@HAVE_BIND@ +HAVE_FATAL_WARNINGS=@HAVE_FATAL_WARNINGS@ +HAVE_NETWORK=@HAVE_NETWORK@ +HAVE_USERNS=@HAVE_USERNS@ +HAVE_X11=@HAVE_X11@ +HAVE_FILE_TRANSFER=@HAVE_FILE_TRANSFER@ +HAVE_WHITELIST=@HAVE_WHITELIST@ +HAVE_GLOBALCFG=@HAVE_GLOBALCFG@ +HAVE_APPARMOR=@HAVE_APPARMOR@ +HAVE_OVERLAYFS=@HAVE_OVERLAYFS@ +HAVE_PRIVATE_HOME=@HAVE_PRIVATE_HOME@ +EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@ + +H_FILE_LIST = $(sort $(wildcard *.[h])) +C_FILE_LIST = $(sort $(wildcard *.c)) +OBJS = $(C_FILE_LIST:.c=.o) +BINOBJS = $(foreach file, $(OBJS), $file) +CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_SECCOMP) $(HAVE_GLOBALCFG) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_BIND) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security +LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread + +%.o : %.c $(H_FILE_LIST) ../include/common.h ../include/euid_common.h ../include/libnetlink.h ../include/pid.h + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +fnet: $(OBJS) ../lib/libnetlink.o ../lib/common.o + $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/libnetlink.o ../lib/common.o $(LIBS) $(EXTRA_LDFLAGS) + +clean:; rm -f *.o fnet + +distclean: clean + rm -fr Makefile + diff --git a/src/fnet/fnet.h b/src/fnet/fnet.h new file mode 100644 index 000000000..58efbbed5 --- /dev/null +++ b/src/fnet/fnet.h @@ -0,0 +1,40 @@ + /* + * Copyright (C) 2014-2016 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. +*/ +#ifndef FNET_H +#define FNET_H + +#include +#include +#include +#include +#include "../include/common.h" + +// veth.c +int net_create_veth(const char *dev, const char *nsdev, unsigned pid); +int net_create_macvlan(const char *dev, const char *parent, unsigned pid); +int net_move_interface(const char *dev, unsigned pid); + +// interface.c +void net_bridge_add_interface(const char *bridge, const char *dev); +void net_if_up(const char *ifname); +int net_get_mtu(const char *ifname); +void net_set_mtu(const char *ifname, int mtu); + +#endif diff --git a/src/fnet/interface.c b/src/fnet/interface.c new file mode 100644 index 000000000..b1903dd46 --- /dev/null +++ b/src/fnet/interface.c @@ -0,0 +1,183 @@ + /* + * Copyright (C) 2014-2016 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 "fnet.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// add a veth device to a bridge +void net_bridge_add_interface(const char *bridge, const char *dev) { + if (strlen(bridge) > IFNAMSIZ) { + fprintf(stderr, "Error fnet: invalid network device name %s\n", bridge); + exit(1); + } + + // somehow adding the interface to the bridge resets MTU on bridge device!!! + // workaround: restore MTU on the bridge device + // todo: put a real fix in + int mtu1 = net_get_mtu(bridge); + + struct ifreq ifr; + int err; + int ifindex = if_nametoindex(dev); + + if (ifindex <= 0) + errExit("if_nametoindex"); + + int sock; + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + errExit("socket"); + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, bridge, IFNAMSIZ); +#ifdef SIOCBRADDIF + ifr.ifr_ifindex = ifindex; + err = ioctl(sock, SIOCBRADDIF, &ifr); + if (err < 0) +#endif + { + unsigned long args[4] = { BRCTL_ADD_IF, ifindex, 0, 0 }; + + ifr.ifr_data = (char *) args; + err = ioctl(sock, SIOCDEVPRIVATE, &ifr); + } + (void) err; + close(sock); + + int mtu2 = net_get_mtu(bridge); + if (mtu1 != mtu2) { + net_set_mtu(bridge, mtu1); + } +} + + +// bring interface up +void net_if_up(const char *ifname) { + if (strlen(ifname) > IFNAMSIZ) { + fprintf(stderr, "Error fnet: invalid network device name %s\n", ifname); + exit(1); + } + + int sock = socket(AF_INET,SOCK_DGRAM,0); + if (sock < 0) + errExit("socket"); + + // get the existing interface flags + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_addr.sa_family = AF_INET; + + // read the existing flags + if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) { + close(sock); + printf("Error fnet: cannot bring up interface %s\n", ifname); + errExit("ioctl"); + } + + ifr.ifr_flags |= IFF_UP; + + // set the new flags + if (ioctl( sock, SIOCSIFFLAGS, &ifr ) < 0) { + close(sock); + printf("Error fnet: cannot bring up interface %s\n", ifname); + errExit("ioctl"); + } + + // checking + // read the existing flags + if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) { + close(sock); + printf("Error fnet: cannot bring up interface %s\n", ifname); + errExit("ioctl"); + } + + // wait not more than 500ms for the interface to come up + int cnt = 0; + while (cnt < 50) { + usleep(10000); // sleep 10ms + + // read the existing flags + if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) { + close(sock); + printf("Error fnet: cannot bring up interface %s\n", ifname); + errExit("ioctl"); + } + if (ifr.ifr_flags & IFF_RUNNING) + break; + cnt++; + } + + close(sock); +} + +int net_get_mtu(const char *ifname) { + int mtu = 0; + if (strlen(ifname) > IFNAMSIZ) { + fprintf(stderr, "Error fnet: invalid network device name %s\n", ifname); + exit(1); + } + + int s; + struct ifreq ifr; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + errExit("socket"); + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_addr.sa_family = AF_INET; + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == 0) + mtu = ifr.ifr_mtu; + close(s); + + + return mtu; +} + +void net_set_mtu(const char *ifname, int mtu) { + if (strlen(ifname) > IFNAMSIZ) { + fprintf(stderr, "Error fnet: invalid network device name %s\n", ifname); + exit(1); + } + + int s; + struct ifreq ifr; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + errExit("socket"); + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_addr.sa_family = AF_INET; + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_mtu = mtu; + if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) != 0) + fprintf(stderr, "Warning fnet: cannot set mtu for interface %s\n", ifname); + close(s); +} + + diff --git a/src/fnet/main.c b/src/fnet/main.c new file mode 100644 index 000000000..ae780c2ea --- /dev/null +++ b/src/fnet/main.c @@ -0,0 +1,63 @@ + /* + * Copyright (C) 2014-2016 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 +#include +#include +#include +#include + +static void usage(void) { + printf("Usage:\n"); + printf("\tfnet create veth dev1 dev2 bridge child\n"); + printf("\tfnet create macvlan dev parent child\n"); + printf("\tfnet moveif dev proc\n"); +} + +int main(int argc, char **argv) { + if (argc < 2) + return 1; + + if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { + usage(); + return 0; + } + else if (argc == 7 && strcmp(argv[1], "create") == 0 && strcmp(argv[2], "veth") == 0) { + // create veth pair and move one end in the the namespace + net_create_veth(argv[3], argv[4], atoi(argv[6])); + + // connect the ohter veth end to the bridge ... + net_bridge_add_interface(argv[5], argv[3]); + + // ... and bring it up + net_if_up(argv[3]); + } + else if (argc == 6 && strcmp(argv[1], "create") == 0 && strcmp(argv[2], "macvlan") == 0) { + net_create_macvlan(argv[3], argv[4], atoi(argv[5])); + } + else if (argc == 4 && strcmp(argv[1], "moveif") == 0) { + net_move_interface(argv[2], atoi(argv[3])); + } + else { + fprintf(stderr, "Error fnet: invalid arguments\n"); + return 1; + } + + return 0; +} diff --git a/src/fnet/veth.c b/src/fnet/veth.c new file mode 100644 index 000000000..d06bc9256 --- /dev/null +++ b/src/fnet/veth.c @@ -0,0 +1,230 @@ +/* code based on iproute2 ip/iplink.c, modified to be included in firejail project + * + * Original source code: + * + * Information: + * http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2 + * + * Download: + * http://www.kernel.org/pub/linux/utils/net/iproute2/ + * + * Repository: + * git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git + * + * License: GPL v2 + * + * Original copyright header + * + * iplink.c "ip link". + * + * 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. + * + * Authors: Alexey Kuznetsov, + * + */ + /* + * Copyright (C) 2014-2016 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 "fnet.h" +#include "../include/libnetlink.h" +#include +#include + +struct iplink_req +{ + struct nlmsghdr n; + struct ifinfomsg i; + char buf[1024]; +}; + +static struct rtnl_handle rth = { .fd = -1 }; + +int net_create_veth(const char *dev, const char *nsdev, unsigned pid) { + int len; + struct iplink_req req; + + assert(dev); + assert(nsdev); + assert(pid); + + if (rtnl_open(&rth, 0) < 0) { + fprintf(stderr, "cannot open netlink\n"); + exit(1); + } + + memset(&req, 0, sizeof(req)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; + req.n.nlmsg_type = RTM_NEWLINK; + req.i.ifi_family = 0; + + if (dev) { + len = strlen(dev) + 1; + addattr_l(&req.n, sizeof(req), IFLA_IFNAME, dev, len); + } + + struct rtattr *linkinfo = NLMSG_TAIL(&req.n); + addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); + addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, "veth", strlen("veth")); + + struct rtattr * data = NLMSG_TAIL(&req.n); + addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); + + struct rtattr * peerdata = NLMSG_TAIL(&req.n); + addattr_l (&req.n, sizeof(req), VETH_INFO_PEER, NULL, 0); + req.n.nlmsg_len += sizeof(struct ifinfomsg); + + // place the link in the child namespace + addattr_l (&req.n, sizeof(req), IFLA_NET_NS_PID, &pid, 4); + + if (nsdev) { + int len = strlen(nsdev) + 1; + addattr_l(&req.n, sizeof(req), IFLA_IFNAME, nsdev, len); + } + peerdata->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)peerdata; + + data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; + linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; + + // send message + if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) + exit(2); + + return 0; +} + + +int net_create_macvlan(const char *dev, const char *parent, unsigned pid) { + int len; + struct iplink_req req; + assert(dev); + assert(parent); + + if (rtnl_open(&rth, 0) < 0) { + fprintf(stderr, "cannot open netlink\n"); + exit(1); + } + + memset(&req, 0, sizeof(req)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; + req.n.nlmsg_type = RTM_NEWLINK; + req.i.ifi_family = 0; + + // find parent ifindex + int parent_ifindex = if_nametoindex(parent); + if (parent_ifindex <= 0) { + fprintf(stderr, "Error: cannot find network device %s\n", parent); + exit(1); + } + + // add parent + addattr_l(&req.n, sizeof(req), IFLA_LINK, &parent_ifindex, 4); + + // add new interface name + len = strlen(dev) + 1; + addattr_l(&req.n, sizeof(req), IFLA_IFNAME, dev, len); + + // place the interface in child namespace + addattr_l (&req.n, sizeof(req), IFLA_NET_NS_PID, &pid, 4); + + + // add link info for the new interface + struct rtattr *linkinfo = NLMSG_TAIL(&req.n); + addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); + addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, "macvlan", strlen("macvlan")); + + // set macvlan bridge mode + struct rtattr * data = NLMSG_TAIL(&req.n); + addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); + int macvlan_type = MACVLAN_MODE_BRIDGE; + addattr_l (&req.n, sizeof(req), IFLA_INFO_KIND, &macvlan_type, 4); + + data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; +// req.n.nlmsg_len += sizeof(struct ifinfomsg); + + + data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; + linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; + + // send message + if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) + exit(2); + + return 0; +} + +// move the interface dev in namespace of program pid +// when the interface is moved, netlink does not preserve interface configuration +int net_move_interface(const char *dev, unsigned pid) { + struct iplink_req req; + assert(dev); + + if (rtnl_open(&rth, 0) < 0) { + fprintf(stderr, "cannot open netlink\n"); + exit(1); + } + + memset(&req, 0, sizeof(req)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_NEWLINK; + req.i.ifi_family = 0; + + // find ifindex + int ifindex = if_nametoindex(dev); + if (ifindex <= 0) { + fprintf(stderr, "Error: cannot find interface %s\n", dev); + exit(1); + } + req.i.ifi_index = ifindex; + + // place the interface in child namespace + addattr_l (&req.n, sizeof(req), IFLA_NET_NS_PID, &pid, 4); + + // send message + if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) + exit(2); + + return 0; +} + +/* +int main(int argc, char **argv) { + printf("Hello\n"); + + + char *dev = argv[3]; + char *nsdev = argv[8]; + unsigned pid; + sscanf(argv[10], "%u", &pid); + + + net_create_veth(dev, nsdev, pid); + + return 0; +} +*/ \ No newline at end of file -- cgit v1.2.3-70-g09d2