手搓了个linux沙箱软件,firejail替代品

这个东西目前仍然非常早期,但已经能用了。
如果你经常使用firejail,那么你可能有兴趣

做了一个完全可控的沙箱
花了十天搓了千行代码,稍学习了下内核的namespace机制。,

涉及内核的编程,这方面我其实还算个菜鸟,自学一点出来献丑,希望有大佬斧正。

有太多内容,看github readme吧,这里不写了

比firejail好在:

  • (已实现)可无限嵌套。firejail拒绝嵌套的,其他unshare等工具在这方面也有间接限制

  • (计划中)支持overlay. firejail以前支持,但已经移除了这个功能

  • (计划中)控制容器流量 。firejail的内部iptables是需要预先给了firejail二进制特权的。想搞个完全不需要特权的

  • (计划中) 外面可随时获取沙箱内的shell. Firejail的沙箱想要从外面进入的是需要sudo nsenter的。所以我想弄个免root办法,把沙箱内shell“共享”到沙箱外

还有好多,不在这写了,看readme吧

1 个赞

关于上面提到的计划的后面两点

  • (计划中)控制容器流量

  • (计划中) 把沙箱内shell“共享”到沙箱外,从主机随时进入

这两点用什么方法来达到完全免特权的实现,心里还没有确定可靠的方案

关于控制流量,看到 passt / pasta,他们用的tun/tap. 但网上关于这个工具的资料很少

关于共享shell, 不知大家有什么经验,比如什么工具可以通过unix socket文件做到server/client的shell共享

你是不是在找:systemd-nspawn。

控制流量需要root。要获取沙箱内的shell,你只要在沙箱内跑个提供该服务的进程就好了。

systemd-nspawn+ssh就可以。

tun也是需要特权的。

关于“共享shell":

sshd似乎不能监听unix socket文件,只能监听tcp。 我弄这个沙箱想要让“共享shell"这个功能与网络解耦,所以想要避免任何tcp.

毕竟socket文件可以随着文件系统bind mount, 更优。

tmux 似乎可以监听socket 文件,我刚试了下。但tmux有点… 不是为此目的而生的,还不确定是否选它

关于tun:

我已简单地试了一下pasta (opensuse仓库里有,passt),它的确可以免root使用tun.

原理我刚查了些资料,说在刚创建user namespace时,暂时拥有内部的CAP_NET_ADMIN能力。很可能pasta就是通过这种方法使用tun的(不过我也暂时没深入研究)

systemd支持。看看你有没有:

systemctl cat sshd-unix-local.socket
cat /etc/ssh/ssh_config.d/20-systemd-ssh-proxy.conf

userns里的root也算是特权,特别是你强调了「完全免特权」。不然你开个虚拟机,里边不也有个root么?

另外要让netns能够访问外部网络,要么需要root权限来配置veth和网桥之类的设施,要么只模拟TCP和UDP(基本上就是传输层转发啦,跟各种翻墙工具的tun代理一个样子),会造成netns的网络栈不完整,我很不喜欢。

我没有sshd的socket耶。。

$ systemctl cat sshd-unix-local.socket
No files found for sshd-unix-local.socket.
$ cat /etc/ssh/ssh_config.d/20-systemd-ssh-proxy.conf
cat: /etc/ssh/ssh_config.d/20-systemd-ssh-proxy.conf: 没有那个文件或目录

我在leap 15.6上

那你可以自己配一个。基本思路就是让systemd去监听socket文件然后用inet的方式启动sshd。连接的话,用ProxyCommand调用nc就行吧。

使用 persistent 的 tun 不需要特权。
先用 ip tuntap add dev tun0 user USER 创建好 tun interface,再用非特权的 USER 打开 tun0。
创建 tun interface 也只需要 cap_net_admin.

原来还能这样,学习了~

肝了那么久,感觉可以发布首个试用版了。

项目起名 Tree Sandbox , 新地址在:

虽然没有专业安全团队,对这个沙箱项目现在不能给什么安全评估保证,不过,我自认为自己对各种细节还是比较严谨周到的,所以,欢迎尝鲜,欢迎试用~

1 个赞

讲些之前开发过程中遇到的。

@lilydjwg 我弄了你说的sshd方案,万事具备了结果最后一步过不去

sshd -i 、传递client socket fd, 密钥等等 都弄好了之后,结果在连接到来、通过验证、sshd将要启动shell session时,setgroup失败。
因为 user namespace 容器在启动后都要对proc里的setgroups 写一次 deny, 而sshd启动时它又一定要做 setgroups

结论: sshd是为root系统设计的,是对 user namespace容器不友好的

最后我转向了一个叫dtach的工具。它是专门为通过unix socket文件共享shell设计的、非常简单的,一次成功

还发现了一个 Konsole的bug 。害我排查了好久,bug竟然出在终端模拟器

我脚本在启动时会创建一个专门的 cgroups v2 目录,把自己添加进这个cgroup,然后自然地,所有子进程,也就是整个沙箱都会在这个cgroup里

但konsole偶尔会把其子进程树里的进程擅自移回konsole的cgroup,导致沙箱出些问题。如果用其他终端就没事

我已经向konsole上游反馈了这个问题

这个就是用来保证安全用的吗?