如何使用 linux 命名空间提供文件隔离

How to provide file isolation using linux namespace

我正在尝试 运行 两个 linux 命名空间中的同一个程序。

程序需要读写文件/tmp/server.log。

所以我想确定程序Aread/writeserver.log,但实际上它读写/tmp/server-A.log。而程序Bread/writeserver.log,其实就是读写/tmp/server-B.log。

我尝试使用 mount 但没有成功...有人可以帮助我吗?或者我有没有另一种方法来提供文件隔离,这样两个程序实际上不会 read/write 同一个文件?

#define _GNU_SOURCE
#include<sched.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>

static int child_func(void* arg) {
  system("mount --bind /tmp ./a");
  FILE* file;
  file = fopen("/tmp/server.log","rw");
  // write some log ...
  return 0;
}

static int child2_func(void* arg) {
  system("mount --bind /tmp ./b");
  file = fopen("/tmp/server.log","rw");
  // write some log.... 
  return 0;
}


int main(int argc, char** argv) {
  // Allocate stack for child task.
  const int STACK_SIZE = 1 * 1024 * 1024;
  char* stack = malloc(STACK_SIZE);
  char* stack2 = malloc(STACK_SIZE);
  if (!stack || !stack2) {
    perror("malloc");
    exit(1);
  }
  pid_t pid,pid2;


  if ((pid = clone(child_func, stack + STACK_SIZE, CLONE_NEWPID | CLONE_NEWUTS | CLONE_NEWNS | CLONE_NEWNET | SIGCHLD, NULL)) == -1) {
    perror("clone");
    exit(1);
  }

  if ((pid2 = clone(child2_func, stack2 + STACK_SIZE, CLONE_NEWPID | CLONE_NEWUTS | CLONE_NEWNS | CLONE_NEWNET | SIGCHLD, NULL)) == -1) {
    perror("clone");
    exit(1);
  }


  waitpid(pid,NULL,0);
  waitpid(pid2,NULL,0);


  return 0;
}

更新:我根据下面回答的解决方案解决了问题!他们的解决方案对我很有帮助!

你想要这样的东西:

#define _GNU_SOURCE

#include <sched.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <sys/wait.h>
#include <unistd.h>

int doChild(const char *source) {
    if(unshare(CLONE_NEWNS)) {
        perror("unshare");
        return 1;
    }
    if(mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL)) {
        perror("mount");
        return 1;
    }
    if(mount(source, "/tmp/server.log", NULL, MS_BIND, NULL)) {
        perror("mount");
        return 1;
    }
    execlp("myunmodifiablepythonscript", "myunmodifiablepythonscript", (char*)NULL);
    perror("execlp");
    return 1;
}

int main(void) {
    pid_t pidA, pidB;
    pidA = fork();
    if(pidA < 0) {
        perror("fork");
        return 1;
    } else if(pidA == 0) {
        return doChild("/tmp/server-A.log");
    }
    pidB = fork();
    if(pidB < 0) {
        perror("fork");
        /* n.b.: pidA will still be running as an orphan. */
        return 1;
    } else if(pidB == 0) {
        return doChild("/tmp/server-B.log");
    }
    waitpid(pidA, NULL, 0);
    /* n.b.: if pidB finishes first, it will be a zombie until pidA finishes. */
    waitpid(pidB, NULL, 0);
    return 0;
}

一些注意事项:

  • 正确使用 clone(你没有正确使用)是一件痛苦的事情。只使用 fork 然后再使用 unshare 就容易多了。
  • systemd 愚蠢 makes mounts shared by default,这基本上使挂载命名空间什么都不做(即,更改将传播回其他命名空间,从而破坏私有命名空间的目的)。 mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL) 撤消它以使它们真正起作用。
  • 我不确定你试图绑定 mount 是什么,但这是错误的。正确的做法是将个人日志挂载到共享名称。
  1. 您需要将 root 重新挂载为私有。检查此 .

  2. 当你做--bind的时候,你需要反过来做。

static int child_func(void* arg) {
  mount("/", "/", NULL, MS_PRIVATE, NULL);
  mount("./a", "/tmp", NULL, MS_BIND, NULL);

  FILE* file;
  file = fopen("/tmp/server.log","w");

  return 0;
}
static int child_func(void* arg) {
  mount("/", "/", NULL, MS_PRIVATE, NULL);
  mount("./b", "/tmp", NULL, MS_BIND, NULL);

  FILE* file;
  file = fopen("/tmp/server.log","w");

  return 0;
}