minijail: bring up loopback interface in new net namespaces

For basic network logic, we need loopback.  Bring it up all the time
in new net namespaces since it shouldn't cause a problem otherwise --
it's not like it gets us external network connectivity.

BUG=chromium:665649
TEST=`sudo ./minijail0 -r -v -p -e /sbin/ip a s` shows loopback as up

Change-Id: I7e98f0ca42a2993e8c8e2b1de96df7b68c21e3f0
diff --git a/libminijail.c b/libminijail.c
index 70577c6..ad9afa8 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -16,6 +16,7 @@
 #include <inttypes.h>
 #include <limits.h>
 #include <linux/capability.h>
+#include <net/if.h>
 #include <pwd.h>
 #include <sched.h>
 #include <signal.h>
@@ -29,6 +30,7 @@
 #include <sys/mount.h>
 #include <sys/param.h>
 #include <sys/prctl.h>
+#include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/user.h>
@@ -1519,6 +1521,35 @@
 	}
 }
 
+static void net_bring_up_loopback(void)
+{
+	static const char ifname[] = "lo";
+	int sock;
+	struct ifreq ifr;
+
+	/* Make sure people don't try to add really long names. */
+	_Static_assert(sizeof(ifname) <= IFNAMSIZ, "interface name too long");
+
+	sock = socket(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0);
+	if (sock < 0)
+		pdie("socket(AF_LOCAL) failed");
+
+	/*
+	 * Do the equiv of `ip link set up lo`.  The kernel will assign
+	 * IPv4 (127.0.0.1) & IPv6 (::1) addresses automatically!
+	 */
+	strcpy(ifr.ifr_name, ifname);
+	if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0)
+		pdie("ioctl(SIOCGIFFLAGS) failed");
+
+	/* The kernel preserves ifr.ifr_name for use. */
+	ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
+	if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0)
+		pdie("ioctl(SIOCSIFFLAGS) failed");
+
+	close(sock);
+}
+
 void API minijail_enter(const struct minijail *j)
 {
 	/*
@@ -1566,8 +1597,10 @@
 	if (j->flags.enter_net) {
 		if (setns(j->netns_fd, CLONE_NEWNET))
 			pdie("setns(CLONE_NEWNET)");
-	} else if (j->flags.net && unshare(CLONE_NEWNET)) {
-		pdie("unshare(net)");
+	} else if (j->flags.net) {
+		if (unshare(CLONE_NEWNET))
+			pdie("unshare(net)");
+		net_bring_up_loopback();
 	}
 
 	if (j->flags.ns_cgroups && unshare(CLONE_NEWCGROUP))