可以使用 以非 root 身份在没有网络访问权限的情况下运行新命令unshare -r -n
,例如:
$ unshare -r -n ls
a.txt b.txt
一个确实需要网络访问的命令将会失败。
$ unshare -r -n curl unix.stackexchange.com
curl: (6) Could not resolve host: unix.stackexchange.com
我想知道是否可以通过写入一个神奇的文件/sys
或类似的东西来删除当前进程的网络访问。
我希望能够做类似的事情
$ /bin/sh -c 'echo 1 > /sys/unsharethis; curl unix.stackexchange.com'
strace
-ing的摘录unshare -r -n ls
显示了unshare
系统调用
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=4759040, ...}) = 0
mmap(NULL, 4759040, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7ec6968000
close(3) = 0
unshare(CLONE_NEWUSER|CLONE_NEWNET) = 0
open("/proc/self/setgroups", O_WRONLY) = 3
write(3, "deny", 4) = 4
这向我表明,从当前进程取消共享网络访问实际上是实现取消共享的唯一方法(即它不能作为参数传递给spawn
或与其等价物)。它还表明从 shell 脚本取消共享将不起作用,除非 shell 已被专门扩展以暴露unshare
.
这可以通过
gdb
调试器来完成,并且如果可以附加到正在运行的进程(改变其可转储状态的程序,或者是 setgid 等不能附加到,除非从根目录)。一些可选文件可以帮助使用 gdb,例如 libc6 的调试符号,以及一些与 Linux 相关的包含文件,以便稍后获取一些符号的实际值(例如,在 Debian: (possibly)
libc6-dbg
和libc6-dev
包linux-libc-dev
中),但实际上曾经是“配方“已经制作好了,它们可能不再需要了。首先,除了正在做什么?没有这个,新用户将保持不变,甚至不能作为其初始用户编写:
unshare()
unshare -r
nobody
这将在以后使用。
在另一个终端上:
[...]
现在让我们调用第一个函数:
好的,可能有一种方法可以让 gdb 知道它,但我不是专家:
在修改后的过程中,可以验证
eth0
界面消失了:没有回头路:新的用户命名空间不能变回它的初始命名空间。如果进程以足够的权限运行(例如没有丢失功能的 root 或 SELinux),那么它是可能的(仅使用
unshare(CLONE_NEWNET)
/setns(savedopenedfd)
)。当然,可以在文件中编写脚本,并更改任何允许的运行进程,或者让 shell 从 gdb 子进程中更改自身。的内容
removenetwork.gdb
,仅在使用pid:gid
==更改进程时有效1000:1000
:更新:为下面的系统调用添加了(近似)返回类型,这应该避免某些版本的 gdb 在非开发环境中抱怨:
例子:
更新:如果根本不需要root,就像这个问题出现的那样,那么根本不需要映射到root。只需将出现的情况替换为
write($XX, "0 1000 1", 8)
(write($XX, "1000 1000 1", 11)
对于uid:gid
==1000:1000
情况)。补充组仍然不可避免地丢失,但 uid/gid 不会改变(映射到自身)。