2015-08-26 16 views
1

我在學習Linux命名空間,這是Linux內核提供的一種隔離機制。我寫了一個簡單的C程序來測試它。CLONE_NEWNS在Android上無效

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

#define STACK_SIZE (1024 * 1024) 
static char container_stack[STACK_SIZE]; 

char* const container_args[] = { 
    "/bin/bash", 
    NULL 
}; 

void mounts(void) 
{ 
    syscall(__NR_mount, "proc", "/home/aaa/nstest/", "proc", 0, NULL); 
} 

int container_main(void* arg) 
{ 
    printf("Container - inside the container!\n"); 
    errno = 0; 
    mounts(); 
    perror("mount"); 
    execv(container_args[0], container_args); 
    printf("Something's wrong!\n"); 
    return 1; 
} 

int main() 
{ 
    printf("Parent - start a container!\n"); 
    int pid = syscall(__NR_clone, CLONE_NEWNS | SIGCHLD, NULL, NULL, NULL,  NULL); 
    if (pid < 0) { 
     perror("clone failed"); 
     exit(-1); 
    } else if (pid == 0) { 
     container_main(NULL); 
     exit(0); 
    } 
    waitpid(pid, NULL, 0); 
    printf("Parent - container stopped!\n"); 
    return 0; 
} 

而這段代碼在我的Ubuntu上運行良好。目錄「/ home/aaa/nstest /」在掛載到新的掛載名稱空間後在根掛載名稱空間中爲空。

但是,它不適用於Android仿真器。掛載傳播到根掛載名稱空間。首先我認爲可能是由於內核不支持命名空間造成的。所以我用所有相關的CONFIG開關編譯金魚,例如CONFIG_NAMESPACE。而且它也不起作用。

回答

1

即使使用所有CONFIG_NAMESPACE重新編譯內核,我也有同樣的問題。我試過unshare -m /bin/bash命令,它在我的archlinux x86_64盒子上工作,

因此我深入瞭解命令的strace unshare -m /bin/bash

... 
unshare(CLONE_NEWNS)     = 0 
mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL) = 0 
execve("/bin/bash", ["/bin/bash"], [/* 19 vars */]) = 0 
... 

接縫有一個額外的電話mount(...)。將呼叫添加到我的代碼,它的工作原理!

int main(int argc, const char* argv[]) { 
    const char * source=argv[1]; 
    const char * target=argv[2]; 

    if (unshare(CLONE_NEWNS) == -1) { 
     printf("Failed to unshare(): %s\n", strerror(errno)); 
     return -1; 
    } 
    mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL); 

    if (mount(source, target, NULL, MS_BIND, NULL) == -1) { 
     printf("Failed to mount %s to %s: %s\n", source, target, strerror(errno)); 
     return -1; 
    } 
    sleep(50); 
    return 0; 
}