I created small SUID application which should isolate Chromium from main system (Arch Linux):
unshare(CLONE_NEWNS|CLONE_NEWCGROUP|CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWPID);
mount("none", "/", NULL, MS_PRIVATE|MS_REC, NULL);
chroot("/path/to/new/root");
chdir("/");
mount("proc", "/proc", "proc", MS_NOSUID|MS_NODEV|MS_NOEXEC, NULL);
setresuid(1000, 1000, 1000);
I can connect to Xorg through:
xauth add "$DISPLAY" MIT-MAGIC-COOKIE-1 <hex key>
and start GUI application, but when i try to isolate network:
int namespace_fd = open("/var/run/netns/chromium_netns", O_RDONLY|O_CLOEXEC);
setns(namespace_fd, CLONE_NEWNET);
Chromium throws errors:
[2:2:0915/194118.898349:ERROR:ozone_platform_x11.cc(240)] Missing X server or $DISPLAY
[2:2:0915/194118.898364:ERROR:env.cc(255)] The platform failed to initialize. Exiting.
strace:
connect(29, {sa_family=AF_UNIX, sun_path=@"/tmp/.X11-unix/X0"}, 20) = -1 ECONNREFUSED (Connection refused)
connect(29, {sa_family=AF_INET6, sin6_port=htons(6000), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_scope_id=0}, 28) = -1 ECONNREFUSED (Connection refused)
connect(29, {sa_family=AF_INET, sin_port=htons(6000), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 ECONNREFUSED (Connection refused)
I create network namespace and set up iptables like this:
ip netns add chromium_netns
ip link add veth0 type veth peer name veth1
ip link set veth1 netns chromium_netns
ip addr add 192.168.0.2/24 dev veth0
ip link set dev veth0 up
ip netns exec chromium_netns ip addr add 192.168.0.1/24 dev veth1
ip netns exec chromium_netns ip link set dev veth1 up
ip netns exec chromium_netns ip link set dev lo up
ip netns exec chromium_netns ip route add default via 192.168.0.2
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o ens33 -j MASQUERADE
iptables -A FORWARD -i ens33 -o veth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i veth0 -o ens33 -j ACCEPT
Curl connects to network inside namespace, but GUI applications cannot connect to Xorg. Entire source code of my program (I removed error checking):
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mount.h>
#include <sys/wait.h>
using namespace std;
int main()
{
unshare(CLONE_NEWNS|CLONE_NEWCGROUP|CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWPID);
int namespace_fd = open("/var/run/netns/chromium_netns", O_RDONLY|O_CLOEXEC);
setns(namespace_fd, CLONE_NEWNET);
close(namespace_fd);
int pid = fork();
if (pid != 0) {
setresuid(1000, 1000, 1000);
int status;
waitpid(-1, &status, 0);
return status;
}
mount("none", "/", NULL, MS_PRIVATE|MS_REC, NULL);
chroot("/path/to/new/root/");
chdir("/");
mount("proc", "/proc", "proc", MS_NOSUID|MS_NODEV|MS_NOEXEC, NULL);
setresuid(1000, 1000, 1000);
execlp("/bin/bash", "/bin/bash", NULL);
return 0;
}