Linux 从用户名称空间内部连接网络名称空间
Root创建一个网络名称空间Linux 从用户名称空间内部连接网络名称空间,linux,linux-namespaces,Linux,Linux Namespaces,Root创建一个网络名称空间testns,并使用标志进行克隆,以获取用户名称空间中的子级。然后,子级通过调用尝试加入testns,这表明权限被拒绝是否有其他方法可以让用户名称空间中的子级加入网络名称空间? 刚刚编写了以下测试:(在运行之前,我通过调用sudoipnetnsaddtestns创建了testns) 定义GNU源 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #定义堆栈大小(1024*1024) 静态字符子_堆栈[堆栈_大小]; 静态无效更新映射(char*映射,ch
testns
,并使用标志进行克隆,以获取用户名称空间中的子级。然后,子级通过调用尝试加入testns
,这表明权限被拒绝是否有其他方法可以让用户名称空间中的子级加入网络名称空间?
刚刚编写了以下测试:(在运行之前,我通过调用sudoipnetnsaddtestns
创建了testns
)
定义GNU源
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义堆栈大小(1024*1024)
静态字符子_堆栈[堆栈_大小];
静态无效更新映射(char*映射,char*映射文件){
int-fd,j;
尺寸图;
map_len=strlen(映射);
对于(j=0;j
在允许加入现有网络名称空间之前,内核将执行安全检查,以确保网络名称空间的userns“owner”/creator匹配
您肯定可以在用户名称空间内加入网络名称空间,但必须使用相同的用户名称空间创建初始网络名称空间。在容器运行时(如runc
工具)中,您可以通过在用户名称空间中启动一个简单容器并创建网络名称空间来验证这一点,然后启动第二个容器并引用第一个容器的用户和网络名称空间路径。我在以前的DockerCon中使用runc
演示了这一点;您可以看到我共享用户名称空间和网络名称空间
#define _GNU_SOURCE
#include <sched.h>
#include <stdlib.h>
#include <signal.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#define STACK_SIZE (1024 * 1024)
static char child_stack[STACK_SIZE];
static void update_map(char *mapping, char *map_file) {
int fd, j;
size_t map_len;
map_len = strlen(mapping);
for (j = 0; j < map_len; j++)
if (mapping[j] == ',')
mapping[j] = '\n';
fd = open(map_file, O_RDWR);
if (fd == -1) {
fprintf(stderr, "open %s: %s\n", map_file, strerror(errno));
exit(EXIT_FAILURE);
}
if (write(fd, mapping, map_len) != map_len) {
fprintf(stderr, "write %s: %s\n", map_file, strerror(errno));
exit(EXIT_FAILURE);
}
close(fd);
}
static void proc_setgroups_write(pid_t child_pid, char *str) {
char setgroups_path[PATH_MAX];
int fd;
snprintf(setgroups_path, PATH_MAX, "/proc/%ld/setgroups",
(long) child_pid);
fd = open(setgroups_path, O_RDWR);
if (fd == -1) {
if (errno != ENOENT)
fprintf(stderr, "ERROR: open %s: %s\n", setgroups_path,
strerror(errno));
return;
}
if (write(fd, str, strlen(str)) == -1)
fprintf(stderr, "ERROR: write %s: %s\n", setgroups_path,
strerror(errno));
close(fd);
}
static void update_userns(pid_t pid, char *uidMap, char *gidMap) {
char map_path[PATH_MAX];
snprintf(map_path, PATH_MAX, "/proc/%ld/uid_map", (long) pid);
update_map(uidMap, map_path);
proc_setgroups_write(pid, "deny");
snprintf(map_path, PATH_MAX, "/proc/%ld/gid_map", (long) pid);
update_map(gidMap, map_path);
}
static int join_netns(char *netns_name) {
char netns_path[256];
snprintf(netns_path, sizeof(netns_path), "/var/run/netns/%s", netns_name);
int fd = open(netns_path, O_RDONLY);
if (fd == -1) {
fprintf(stderr, "open netns path failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if (setns(fd, CLONE_NEWNET) == -1) {
fprintf(stderr, "set netns failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
return 0;
}
static int child(void* arg) {
// Sleep so that userns has the correct mapping.
sleep(1);
return join_netns("testns");
}
int main(int argc, char *argv[]) {
uid_t uid = getuid();
char mapping[10];
snprintf(mapping, 10, "0 %d 1", uid);
int pid1 = clone(child, child_stack + STACK_SIZE, CLONE_NEWUSER | SIGCHLD, NULL);
if (pid1 == -1) {
perror("Clone");
exit(EXIT_FAILURE);
}
update_userns(pid1, mapping, mapping);
if (waitpid(pid1, NULL, 0) == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
}