如何在不更改为 root 的情况下“unshare -n”?

如何在不更改为 root 的情况下“unshare -n”?

我想运行一个行为与父级完全相同但没有网络的外壳。为什么我必须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 调试器:

如何取消当前进程的网络共享

相关内容