也是菜鸟 发表于 2022-05-26 14:46

使用clone函数+CLONE_NEWNS函数创建挂载命名空间,为啥别的进程还是能看见挂载信息

我的目标是用一个进程创建新的命名空间,在这个进程里做mount操作,达到只有同命名空间里的进程能看到挂载情况的目的。可是,这个效果就是没有,执行进程后,shell 里执行ls ,还是能看到挂载的文件。这是怎么回事呢?请高手指点!

代码如下:
#define _GNU_SOURCE
#include <stdio.h>                /* for convenience */
#include <stdlib.h>                /* for convenience */
#include <string.h>                /* for convenience */
#include <unistd.h>                /* for convenience */
#include <errno.h>
#include <pwd.h>
#include <sched.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/mount.h>


#define MAXLINE 10


/*若某字符串中有多个空格,tab标志,换行符或者回车符 */
/*且这些字符可能接连出现,则将此字符串中的多个连续的*/
/*不可显示字符压缩为一个空格*/
/*参数len看似多余,其实有大用。如果源址与目的地址*/
/*重叠的情况下,可消除可能出现的死循环*/
void shrink(char *src,char *dest,size_t len)
{
        int i= 0,j=0;
        int n= 0;
        int spacelen = 0;
        while( (src!='\0') && n<=len )
        {
                if( (src==32)||(src==9)||(src==10) )
                {
                        if(spacelen==0)
                        {
                                dest=' ';
                                spacelen++;
                                i++;
                                j++;
                        }
                        else
                                i++;
                        n++;
                        continue;
                }
                dest=src;
                i++;
                j++;
                n++;
                spacelen = 0;
        }
        dest='\0';
}





char * my_itoa(int value,char *string,int radix)
{
        char zm="0123456789abcdefghijklmnopqrstuvwxyz";
        char aa={0};

        int sum=value;
        char *cp=string;
        int i=0;
       
        if(radix<2||radix>36)//增加了对错误的检测
        {
                //cout<<"error data!"<<endl;
                return string;
        }

        if(value<0)
        {
                //cout<<"error data!"<<endl;
                return string;
        }
       

        while(sum>0)
        {
                aa=zm;
                sum/=radix;
        }

        for(int j=i-1;j>=0;j--)
        {
                *cp++=aa;
        }
        *cp='\0';
        return string;
}





//按空格切分字符串。假设sub数组的长度够用
int splitestr(const char *src,char sub[],int * argc)
{
        /*split a string by space key*/
        int i=0;
        int j=0;
        int len=0;
        int flag=0;
        char *tmp=NULL;
        while( src!='\0' )
        {
                if (src!=' ')
                {
                        i++;
                        len++;
                }
                if(src==' ' )
                {
                        i++;
                        tmp = (char *)&src;
                        strncpy(sub,tmp,len);
                        j++;
                        flag = i;
                        len =0;
                }
        }
        tmp = (char *)&src;
        strncpy(sub,tmp,len);
        *argc = j+1;
        return 0;
}


int get_ns_id(pid_t pid,const char *ns_type)
{
    char tmp = {0};
    my_itoa(pid,tmp,10);

    char cmd = {0};
    strcat(cmd,"ls -l /proc/");
    strcat(cmd,tmp);
    strcat(cmd,"/ns/");

    FILE   *stream;
    char buf = {0};
    stream = popen(cmd, "r" ); //将命令的输出 通过管道读取(“r”参数)到FILE* stream
    fread( buf, sizeof(char), sizeof(buf), stream); //将刚刚FILE* stream的数据流读取到buf中
    pclose( stream );


/*

        mode_t f_attrib = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;   
        char * tmpfile = tmpnam(0);
      printf("tmpfile:%s\n",tmpfile);

        int fd = open(tmpfile, O_RDWR|O_CREAT,f_attrib);

    if(fd == -1)
      perror("open tmpfile error");

    int old_fd=dup(STDOUT_FILENO);//保存屏幕输出的文件描述符,用于恢复
        dup2(fd,STDOUT_FILENO);         //输出重定向

    char buf = {0};
        system(cmd);
    read(fd,buf,1000);
    close(fd);
    dup2(old_fd,STDOUT_FILENO);// 还原屏幕输出默认文件描述符指向

*/
    //printf("buf:%s\n",buf);

    char search = {0};
    strcat(search,ns_type);
    strcat(search,"[");

    char *first_pos = strstr(buf,search);
    char *last_pos = strstr(first_pos,"]");
    char ns_name = {0};
    strncpy(ns_name, first_pos+strlen(search), last_pos-(first_pos+strlen(search)) );
    //printf("ns_name:%s\n",ns_name);

    return atoi(ns_name);
}


void my_system(const char * cmd)
{
        char cmd2 = {0};
        strcpy(cmd2,cmd);
        shrink(cmd2,cmd2,strlen(cmd2));
       
        pid_t        pid;
        if ((pid = fork()) < 0)
        {
                perror("fork error\n");
        }
        else if (pid == 0)
        {       
                setuid(0);

      char path = {0};
      strcat(path,"/proc/");

      char tmp = {0};
      pid_t parent_pid = getppid();
      my_itoa(parent_pid,tmp,10);

      strcat(path,tmp);
      strcat(path,"/ns/mnt");

      //get mount id of parent
      int mnt_fd = open(path,O_RDONLY);
         if (mnt_fd == -1)
               perror("open mnt");

      if (setns(mnt_fd, CLONE_NEWNS) == -1)
            perror("setns error");


      int argc = 0;
      char args = {0};
      splitestr(cmd2,args,&argc);


      char * argv = {0};
      for(int i=0;i< argc;i++)
      {
            argv = args;
                        printf("%s\n",argv);
      }

                if (execvp(argv, argv) < 0)
                        perror("execl error\n");

      close(mnt_fd);
        }

        if (waitpid(pid, 0, 0) < 0)
                perror("wait error\n");
}


static char child_stack;

static int child_fn()
{
    setuid(0);


        //if (unshare(CLONE_NEWNS) < 0)
        //{
        //        perrpr("unshare");
        //}


        char pass[] = {'1','2','3','4','5','6'};
        mode_t f_attrib = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;   
        char * tmpfile = tmpnam(0);
        int fd = open(tmpfile, O_RDWR|O_CREAT,f_attrib);
        write(fd,pass,sizeof(pass));

    int old_fd=dup(STDIN_FILENO);//保存描述符,用于恢复
        dup2(fd,STDIN_FILENO);
        lseek(0,0,SEEK_SET);

        //char cmd2 = {0};
        my_system("cryptsetup luksOpen /home/wxf/dss/sdb1 dss_encrypted_partition");
        close(fd);
        unlink(tmpfile);

    dup2(old_fd,STDIN_FILENO);// 还原文件描述符

        //my_system("mkfs.ext4 /dev/mapper/dss_encrypted_partition");
        my_system("mount --make-private/dev/mapper/dss_encrypted_partition /mnt/dssdir");
        //my_system("mount    /dev/mapper/dss_encrypted_partition    /mnt/dssdir");

        while(1)
        {
                sleep(10);
        }

    return 0;
}



int main(int argc, char *argv[])
{
        pid_t child_pid = clone(child_fn, child_stack+1048576,CLONE_NEWNS, 0);// 0x00020000   CLONE_NEWNS

    if(child_pid == -1)
      perror("clone error");

        return 0;
}



页: [1]
查看完整版本: 使用clone函数+CLONE_NEWNS函数创建挂载命名空间,为啥别的进程还是能看见挂载信息