【问题标题】:unshare user namespace, fork, map uid then execvp failing取消共享用户命名空间、fork、映射 uid 然后 execvp 失败
【发布时间】:2021-09-12 17:27:17
【问题描述】:

我正在尝试执行以下一系列操作:

  • unshareuser 命名空间;
  • 将子进程中的user映射到root
  • execvp

但是,当运行id 时,我的代码将用户输出为nobody 或失败而没有错误。

#include <sched.h>
#include <cstdio>
#include <cstring>
#include <cerrno>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <system_error>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

void unshare_user_namespace() {
  if (0 != unshare(CLONE_NEWUSER)) {
    fprintf(stderr, "%s\n", "USER unshare has failed");
    exit(1);
  }
}

void map_id() {
  int pid = getpid();
  char file[100];
  if (0 > sprintf(file, "/proc/%d/uid_map", pid)) {
    printf("Couldn't sprintf uid_map path.");
    exit(1);
  }

  int fd;
  fd = open(file, 1);
  if (fd < 0) {
    printf("Coudln't open file for writing.\n");
    exit(1);
  }

  int uid = getuid();
  char * buf;
  if (0 > sprintf(buf, "0 %d 1", uid)) {
    printf("Couldn't sprintf uid_map content.");
    exit(1);
  }

  if (write(fd, buf, strlen(buf))) {
    printf("Coudln't write mapping into file.\n");
    exit(1);
  }

  free(buf);
  close(fd);
}

void start(char * command, char ** args) {
  unshare_user_namespace();
  int fork_pid = fork();

  if (-1 == fork_pid) {
    fprintf(stderr, "%s\n", "couldn't fork");
    exit(1);
  }

  if (0 == fork_pid) {
    map_id();

    if (-1 == execvp(command, args)) {
      fprintf(stderr, "%s\n", "couldn't execvp");
      exit(1);
    }
  }
}

int main(int argc, char ** argv) {
  start(argv[1], & argv[1]);
  int status;
  wait( & status);
  return 0;
}

我尝试阅读 namespacesunshare 等的手册页,但无法弄清楚我的代码有什么问题。

运行代码:

$ g++ <file_containing_code> && ./a.out id

【问题讨论】:

    标签: c++ linux-kernel fork linux-namespaces


    【解决方案1】:

    很确定您已经找到了答案,但这是我能想到的最小示例:

    // gcc -Wall -std=c11
    #define _GNU_SOURCE
    #include <stdio.h>
    #include <unistd.h>
    #include <sched.h>
    #include <sys/wait.h>
    #include <stdlib.h>
    #include <stdarg.h>
    
    void write_to_file(const char *which, const char *format, ...) {
      FILE * fu = fopen(which, "w");
      va_list args;
      va_start(args, format);
      if (vfprintf(fu, format, args) < 0) {
        perror("cannot write");
        exit(1);
      }
      fclose(fu);
    }
    
    int main(int argc, char ** argv) {
      // array of strings, terminated with NULL entry
      char **cmd_and_args = (char**) calloc(argc, sizeof(char*));
      for (int i = 1 ; i < argc; i++) {
        cmd_and_args[i-1] = argv[i];
      }
      uid_t uid = getuid();
      gid_t gid = getgid();
      // first unshare
      if (0 != unshare(CLONE_NEWUSER)) {
        fprintf(stderr, "%s\n", "USER unshare has failed");
        exit(1);
      }
      // remap uid
      write_to_file("/proc/self/uid_map", "0 %d 1", uid);
      // deny setgroups (see user_namespaces(7))
      write_to_file("/proc/self/setgroups", "deny");
      // remap gid
      write_to_file("/proc/self/gid_map", "0 %d 1", gid);
      // exec the command
      if (execvp(cmd_and_args[0], cmd_and_args) < 0) {
        perror("cannot execvp");
        exit(1);
      }
      // unreachable
      free(cmd_and_args);
      return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2018-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-24
      • 2017-05-24
      • 2017-11-29
      • 2018-02-28
      相关资源
      最近更新 更多