Re: [RCF] [PATCH] unprivileged mount/umount

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 2005-05-12 at 11:51, Miklos Szeredi wrote:
> > > I'm not sure passing directory file descriptors is the right semantic
> > > we want - but at least it provides a point of explicit control (in
> > > much the same way as a bind).  Are you sure the clone + open("/") +
> > > pass-to-parent scenario you allows the parent to traverse the child's
> > > private name space through that fd?
> > 
> > Pretty sure.
> 
> Yup.  Attached a little program that can be used to try this out.  It
> creates a new namespace in the child, does a bind mount (so the
> namespaces can be differentiated), then sends the file descriptor of
> "/" to the parent.  The parent does fchdir(fd), then starts a shell.


> So the result is that CWD is under the child namespace, while root is
> under the initial namespace.
> 

r u sure, this program works? Sorry if I am saying something dumb here.
Correct me.  When a file descriptor is sent from one process to other,
arn't they referring to different files in each of the processes.
fd=5 may be pointing to file 'xyz' in parent process, 
where as fd=5 will be pointing to 'abc' in the child process.  

This program did not work for me, and I was wondering if adding
CLONE_FILES in clone() would help. Because that would make sure
 that both
the processes share the same file descriptor. It did not work too.

What am I understanding wrong?

In any case my opinion is if this program works than the hole should
be closed instead of exploting it to access different namespace. I 
know Jamie is going to pounce at me. ;)

RP



> I also tried bind mounting from the child's namespace to the parent's,
> and that works too.  But the new mount's mnt_namespace is copied from
> the old, which makes the mount un-removable.  This is most likely not
> intentional, IOW a bug.
> 
> Miklos
> 
> === newns.c =========================================================
> #define _GNU_SOURCE
> 
> #include <stdio.h>
> #include <unistd.h>
> #include <stdlib.h>
> #include <signal.h>
> #include <sched.h>
> #include <errno.h>
> #include <fcntl.h>
> #include <unistd.h>
> #include <sys/un.h>
> #include <sys/socket.h>
> 
> static int socks[2];
> 
> static int send_fd(int sock_fd, int fd)
> {
>     int retval;
>     struct msghdr msg;
>     struct cmsghdr *p_cmsg;
>     struct iovec vec;
>     char cmsgbuf[CMSG_SPACE(sizeof(fd))];
>     int *p_fds;
>     char sendchar = 0;
> 
>     msg.msg_control = cmsgbuf;
>     msg.msg_controllen = sizeof(cmsgbuf);
>     p_cmsg = CMSG_FIRSTHDR(&msg);
>     p_cmsg->cmsg_level = SOL_SOCKET;
>     p_cmsg->cmsg_type = SCM_RIGHTS;
>     p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
>     p_fds = (int *) CMSG_DATA(p_cmsg);
>     *p_fds = fd;
>     msg.msg_controllen = p_cmsg->cmsg_len;
>     msg.msg_name = NULL;
>     msg.msg_namelen = 0;
>     msg.msg_iov = &vec;
>     msg.msg_iovlen = 1;
>     msg.msg_flags = 0;
>     /* "To pass file descriptors or credentials you need to send/read at
>      * least one byte" (man 7 unix) */
>     vec.iov_base = &sendchar;
>     vec.iov_len = sizeof(sendchar);
>     while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
>     if (retval != 1) {
>         perror("sending file descriptor");
>         return -1;
>     }
>     return 0;
> }
> 
> static int receive_fd(int fd)
> {
>     struct msghdr msg;
>     struct iovec iov;
>     char buf[1];
>     int rv;
>     int connfd = -1;
>     char ccmsg[CMSG_SPACE(sizeof(connfd))];
>     struct cmsghdr *cmsg;
> 
>     iov.iov_base = buf;
>     iov.iov_len = 1;
> 
>     msg.msg_name = 0;
>     msg.msg_namelen = 0;
>     msg.msg_iov = &iov;
>     msg.msg_iovlen = 1;
>     /* old BSD implementations should use msg_accrights instead of
>      * msg_control; the interface is different. */
>     msg.msg_control = ccmsg;
>     msg.msg_controllen = sizeof(ccmsg);
> 
>     while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
>     if (rv == -1) {
>         perror("recvmsg");
>         return -1;
>     }
>     if(!rv) {
>         /* EOF */
>         return -1;
>     }
> 
>     cmsg = CMSG_FIRSTHDR(&msg);
>     if (!cmsg->cmsg_type == SCM_RIGHTS) {
>         fprintf(stderr, "got control message of unknown type %d\n",
>                 cmsg->cmsg_type);
>         return -1;
>     }
>     return *(int*)CMSG_DATA(cmsg);
> }
> 
> int childfn(void *p)
> {
>     int fd;
> 
>     (void) p;
>     mkdir("/tmp/clonetest", 755);
>     mkdir("/tmp/clonetest/dir1", 755);
>     mkdir("/tmp/clonetest/dir1/subdir1", 755);
>     mkdir("/tmp/clonetest/mnt", 755);
>     system("mount --bind /tmp/clonetest/dir1 /tmp/clonetest/mnt");
>     fd = open("/", O_RDONLY | O_DIRECTORY);
>     send_fd(socks[0], fd);
>     sleep(1000);
>     return 1;
> }
> 
> int main()
> {
>     char buf[10000];
>     pid_t pid;
>     int res;
>     int childfd;
> 
>     res = socketpair(AF_UNIX, SOCK_STREAM, 0, socks);
>     if (res == -1) {
>         perror("socketpair");
>         return 1;
>     }
> 
>     pid = clone(childfn, buf+5000, CLONE_NEWNS | SIGCHLD, NULL);
>     if ((int) pid == -1) {
>         perror("clone");
>         exit(1);
>     }
> 
>     childfd = receive_fd(socks[1]);
>     res = fchdir(childfd);
>     if (res == -1) {
>         perror("fchdir");
>         return 1;
>     }
>     execl("/bin/bash", "/bin/bash", NULL);
>     
>     return 0;
> }

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux