forked from lix-project/lix
In chroot builds, use a private network namespace
On Linux it's possible to run a process in its own network namespace, meaning that it gets its own set of network interfaces, disjunct from the rest of the system. We use this to completely remove network access to chroot builds, except that they get a private loopback interface. This means that: - Builders cannot connect to the outside network or to other processes on the same machine, except processes within the same build. - Vice versa, other processes cannot connect to processes in a chroot build, and open ports/connections do not show up in "netstat". - If two concurrent builders try to listen on the same port (e.g. as part of a test), they no longer conflict with each other. This was inspired by the "PrivateNetwork" flag in systemd.
This commit is contained in:
parent
2f3f413e91
commit
df716c98d2
|
@ -47,6 +47,13 @@
|
||||||
|
|
||||||
#define CHROOT_ENABLED HAVE_CHROOT && HAVE_UNSHARE && HAVE_SYS_MOUNT_H && defined(MS_BIND) && defined(CLONE_NEWNS)
|
#define CHROOT_ENABLED HAVE_CHROOT && HAVE_UNSHARE && HAVE_SYS_MOUNT_H && defined(MS_BIND) && defined(CLONE_NEWNS)
|
||||||
|
|
||||||
|
#if CHROOT_ENABLED
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if HAVE_SYS_PERSONALITY_H
|
#if HAVE_SYS_PERSONALITY_H
|
||||||
#include <sys/personality.h>
|
#include <sys/personality.h>
|
||||||
|
@ -1769,12 +1776,30 @@ void DerivationGoal::startBuilder()
|
||||||
|
|
||||||
#if CHROOT_ENABLED
|
#if CHROOT_ENABLED
|
||||||
if (useChroot) {
|
if (useChroot) {
|
||||||
/* Create our own mount namespace. This means that
|
/* Create our own mount and network namespace. This
|
||||||
all the bind mounts we do will only show up in this
|
means that all the bind mounts we do will only show
|
||||||
process and its children, and will disappear
|
up in this process and its children, and will
|
||||||
automatically when we're done. */
|
disappear automatically when we're done.
|
||||||
if (unshare(CLONE_NEWNS) == -1)
|
Similarly, this process will not have any network
|
||||||
throw SysError(format("cannot set up a private mount namespace"));
|
interface except "lo" created below. */
|
||||||
|
if (unshare(CLONE_NEWNS | CLONE_NEWNET) == -1)
|
||||||
|
throw SysError("cannot set up a private mount namespace");
|
||||||
|
|
||||||
|
/* Initialise the loopback interface. Note that this
|
||||||
|
loopback device is unique to this process and its
|
||||||
|
children. Thus they won't be able to open
|
||||||
|
connections to the rest of the system, or vice
|
||||||
|
versa. */
|
||||||
|
AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP));
|
||||||
|
if (fd == -1) throw SysError("cannot open IP socket");
|
||||||
|
|
||||||
|
struct ifreq ifr;
|
||||||
|
strcpy(ifr.ifr_name, "lo");
|
||||||
|
ifr.ifr_flags = IFF_UP | IFF_LOOPBACK | IFF_RUNNING;
|
||||||
|
if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1)
|
||||||
|
throw SysError("cannot set loopback interface flags");
|
||||||
|
|
||||||
|
fd.close();
|
||||||
|
|
||||||
/* Bind-mount all the directories from the "host"
|
/* Bind-mount all the directories from the "host"
|
||||||
filesystem that we want in the chroot
|
filesystem that we want in the chroot
|
||||||
|
|
Loading…
Reference in a new issue