我想运行一个行为与父级完全相同但没有网络的外壳。为什么我必须su <login>
之后unshare
?
答案1
我很惊讶你仍然可以su user
,据我所知,在 Linux 内核 3.19 之后,su
命令可能会变得混乱。
unshare 命令不够灵活,无法做到这一点:它只允许映射到根目录。之后你必须映射到自己unshare
,但在任何 fork/exec 之前通过写入"<user> <user> 1"
(/proc/self/uid_map
与 相同/proc/self/gid_map
)。所有最近的内核还要求首先写入deny
:/proc/$$/setgroups
所有补充组(例如:视频)都必须丢失,这是不可避免的,就像unshare -U/-r
.
这是一个很简单C 程序仅作为概念证明,它不会执行任何检查来执行您要求的操作,但前提是由 uid/gid 1000/1000 的用户运行:丢失网络。请随意改进它。
#define _GNU_SOURCE
#include <sched.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int fd;
unshare(CLONE_NEWUSER|CLONE_NEWNET);
fd=open("/proc/self/setgroups",O_WRONLY);
write(fd,"deny",4);
close(fd);
fd=open("/proc/self/uid_map",O_WRONLY);
write(fd,"1000 1000 1",11);
close(fd);
fd=open("/proc/self/gid_map",O_WRONLY);
write(fd,"1000 1000 1",11);
close(fd);
execvp(argv[1],argv+1);
}
如果调用该文件removenet.c
,则使用 编译它gcc -o removenet removenet.c
。
$ id
uid=1000(user) gid=1000(user) groups=1000(user),44(video)
$ ip -br a
lo UNKNOWN 127.0.0.1/8 ::1/128
eth0@if11 UP 10.0.3.66/24 fe80::216:3eff:fe6a:c1e9/64
$ ./removenet bash
$ id
uid=1000(user) gid=1000(user) groups=1000(user),65534(nogroup)
$ ip -br a
lo DOWN
另请注意,新的网络命名空间的lo
接口已关闭,并且由于您不是 root,因此您甚至无法对其进行设置。
您可以运行该程序的变体以恢复为以前的用户后unshare -r -n -m
通过更改成为 root 例如再次进入新的用户命名空间。这允许首先设置一些环境,例如安装/sys
以看不到以前的接口,将接口lo
调出等。请参阅我对类似问题的回答(使用相同的代码,您只需再次添加|CLONE_NEWNET
):
unshare --map-root-user 设置后切换到原始 uid/用户名
需要明确的是:我不知道有任何标准实用程序能够通过简单的 shell 命令完成您所要求的操作。所以你必须求助于使用 shell 之外的其他语言:C、python……甚至还有ctypes.sh bash 的外部函数接口。
我的另一个答案还提供了一些附加信息和另一种“语言”,即 gdb 调试器: