2017-02-21 17 views
0

Корень создает сетевое пространство имен testns и клонирует флаг CLONE_NEWUSER, чтобы получить дочерний элемент в пространстве имен пользователей. Затем ребенок пытается присоединиться к testns, позвонив по номеру setns, в котором указано разрешение. Есть ли альтернатива, позволяющая ребенку внутри пространства имен пользователей присоединиться к пространству имен в сети?Включение сетевого пространства имен из внутреннего пространства имен пользователя

Просто написал этот следующий тест: (Перед запуском, я создал testns по телефону sudo ip netns add testns)

#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); 
    } 
} 

ответ

0

Ядро будет делать проверку безопасности, что userns «владелец»/создатель сети пространств имен спичек прежде чем разрешить соединение с существующим пространством имен в сети.

Вы можете определенно присоединиться к пространству имен в сети как раз внутри пространства имен пользователей, но это начальное пространство имен в сети должно быть создано с тем же пространством имен пользователей. В процессе работы с контейнером, таком как инструмент runc, вы можете проверить его, запустив простой контейнер в пространстве имен пользователей с созданным пространством имен, а затем запустите второй контейнер со ссылками на пользователя пользователя и сети пути пространства имен. Я продемонстрировал это с помощью runc на предыдущем DockerCon; вы можете видеть, как я разделяю пространство имен пользователей и сетевое пространство имен in this segment starting at 41:24

Смежные вопросы