Как обеспечить изоляцию файлов, используя пространство имен linux - PullRequest
1 голос
/ 18 апреля 2020

Я пытаюсь запустить одну и ту же программу в двух linux пространствах имен.

Программа должна прочитать и записать файл /tmp/server.log.

Поэтому я хочу убедиться, что программа A читает / записывает server.log, но на самом деле она читает и пишет /tmp/server-A.log. А для программы B read / write server.log это фактически чтение и запись /tmp/server-B.log.

Я пытаюсь использовать mount, но безуспешно ... Кто-нибудь может мне помочь? Или для меня есть другой способ обеспечить изоляцию файлов, чтобы две программы фактически не читали и не записывали один и тот же файл?

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

Обновление: я решаю проблему, основываясь на решениях, на которые даны ответы ниже! Их решения действительно помогают мне!

Ответы [ 2 ]

1 голос
/ 18 апреля 2020
  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;
}
1 голос
/ 18 апреля 2020

Вы хотите что-то вроде этого:

#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 тупо делает монтирование общих по умолчанию , что в основном заставляет пространства имен монтирования ничего не делать (т. Е. Изменения будут распространяться обратно к другим пространствам имен, таким образом, побеждая цель частного пространства имен). mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL) отменяет это, чтобы заставить их действительно работать.
  • Я не уверен, что вы пытались связать с mount, но это было не то. Правильнее всего подключить отдельный журнал к общему имени.
...