From 20f5734c098679a0461aa244a19651d1da6e2a3a Mon Sep 17 00:00:00 2001 From: Sapan Bhatia Date: Fri, 20 Mar 2009 14:18:31 +0000 Subject: [PATCH] This repository is to contain libraries that will let privilege-demanding applications run transparently from inside of a slice. --- fuse/Makefile | 4 + fuse/reroutemount.c | 130 ++++++++++++++++++++++++++++ fuse/stolen_from_fuse.c | 162 +++++++++++++++++++++++++++++++++++ fuse/stolen_from_fuse.c.orig | 157 +++++++++++++++++++++++++++++++++ 4 files changed, 453 insertions(+) create mode 100644 fuse/Makefile create mode 100644 fuse/reroutemount.c create mode 100644 fuse/stolen_from_fuse.c create mode 100644 fuse/stolen_from_fuse.c.orig diff --git a/fuse/Makefile b/fuse/Makefile new file mode 100644 index 0000000..3d0c5eb --- /dev/null +++ b/fuse/Makefile @@ -0,0 +1,4 @@ +all: reroutemount.c reroutemount_server.c stolen_from_fuse.c + gcc -g -c stolen_from_fuse.c -o stolen_from_fuse.o + gcc -g stolen_from_fuse.o reroutemount_server.c -o reroutemount_server + gcc -g -shared stolen_from_fuse.o reroutemount.c -o reroutemount.so diff --git a/fuse/reroutemount.c b/fuse/reroutemount.c new file mode 100644 index 0000000..4ded3bb --- /dev/null +++ b/fuse/reroutemount.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include +#include +#include +#include "stolen_from_fuse.h" + +char *socket_name = "/vsys/local_fusemount.control"; + +int rrm_connect_socket() { + int fd = socket( AF_UNIX, SOCK_STREAM, 0 ); + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; + strcpy( addr.sun_path, socket_name ); + int len = strlen(socket_name) + sizeof(addr.sun_family); + assert( connect( fd, (struct sockaddr *) &addr, len ) == 0 ); + return fd; +} + +void rrm_do_umount( char *const argv[], int n, int fd ) { + + // write the length + char buf[1024]; + sprintf( buf, "%08x\n", n ); + write( fd, buf, strlen(buf) ); + + // now write each arg + int i; + for( i = 0; i < n; i++ ) { + assert( strlen(argv[i]) < 1024 ); + sprintf( buf, "%s\n", argv[i] ); + write( fd, buf, strlen(buf) ); + } + + char inbuf[10]; + int n2 = read( fd, inbuf, 10 ); + inbuf[n2] = '\0'; + + int r = atoi(inbuf); + +} + +int umount2( const char *mnt, int flags ) { + + int fd = rrm_connect_socket(); + + const char *argv[3]; + argv[0] = "fusermount"; + argv[1] = "-u"; + argv[2] = mnt; + + rrm_do_umount( (char **const) argv, 3, fd ); + + close(fd); + +} + +int mount(const char *source, const char *target, const char *filesystemtype, + unsigned long mountflags, const void *data) { + + int fd = rrm_connect_socket(); + + char buf[1024]; + sprintf( buf, "%08x\n", 0 ); + write( fd, buf, strlen(buf) ); + + sprintf( buf, "%s\n%s\n%s\n%ld\n%s\n", source, target, filesystemtype, + mountflags, data ); + write( fd, buf, strlen(buf) ); + + char inbuf[10]; + int n = read( fd, inbuf, 9 ); + inbuf[n] = '\0'; + + int r; + assert( sscanf( inbuf, "%08x\n", &r ) == 1); + + int fuse_fd = 0; + if( r < 0 ) { + errno = r; + return -1; + } else if( r > 0 ) { + // get the fd + fuse_fd = rrm_receive_fd(fd); + + // what was the old fd? + int old_fd; + char extra[1024]; + int s = sscanf( data, "fd=%d,%s", &old_fd, extra ); + assert( dup2( fuse_fd, old_fd ) == old_fd ); + + } + + close(fd); + return 0; + +} + +int execv( const char *path, char *const argv[] ) { + + if( strstr( path, "fusermount" ) == NULL ) { + return execv( path, argv ); + } + + // also make sure this is an unmount . . . + int n = 0; + char *arg = argv[n]; + int found_u = 0; + while( arg != NULL ) { + if( strcmp( arg, "-u" ) == 0 ) { + found_u = 1; + break; + } + arg = argv[++n]; + } + + if( !found_u ) { + return execv( path, argv ); + } + + // Have root do any fusermounts we need done + int fd = rrm_connect_socket(); + + rrm_do_umount( argv, n, fd ); + + exit(0); + +} + diff --git a/fuse/stolen_from_fuse.c b/fuse/stolen_from_fuse.c new file mode 100644 index 0000000..87fef01 --- /dev/null +++ b/fuse/stolen_from_fuse.c @@ -0,0 +1,162 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "stolen_from_fuse.h" + +// Most of this code is stolen from FUSE 2.7.4 + +/** Function to pass a file descriptor over a UNIX socket. + * + * Sends the file descriptor fd over the channel sock_fd. + * + ***/ +int rrm_send_fd(int sock_fd, int fd) +{ + int retval; + struct msghdr msg; + struct cmsghdr *p_cmsg; + struct iovec vec; + size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)]; + 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; +} + + +/* return value: + * >= 0 => fd + * -1 => error + */ +int rrm_receive_fd(int fd) +{ + struct msghdr msg; + struct iovec iov; + char buf[1]; + int rv; + size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)]; + 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 rrm_fuse_mnt_umount(const char *progname, const char *mnt, int lazy) +{ + int res; + int status; + + res = umount2(mnt, lazy ? 2 : 0); + if (res == -1) + fprintf(stderr, "%s: failed to unmount %s: %s\n", + progname, mnt, strerror(errno)); + return res; + +} + +static int rrm_try_open(const char *dev, char **devp, int silent) +{ + int fd = open(dev, O_RDWR); + if (fd != -1) { + *devp = strdup(dev); + if (*devp == NULL) { + fprintf(stderr, "failed to allocate memory\n" ); + + close(fd); + fd = -1; + } + } else if (errno == ENODEV || + errno == ENOENT)/* check for ENOENT too, for the udev case */ + return -2; + else if (!silent) { + fprintf(stderr, "failed to open %s: %s\n", dev, + strerror(errno)); + } + return fd; +} + +static int rrm_try_open_fuse_device(char **devp) +{ + int fd; + int err; + + //drop_privs(); + fd = rrm_try_open(FUSE_DEV_NEW, devp, 0); + //restore_privs(); + if (fd >= 0) + return fd; + + err = fd; + fd = rrm_try_open(FUSE_DEV_OLD, devp, 1); + if (fd >= 0) + return fd; + + return err; +} + +int rrm_open_fuse_device(char **devp) +{ + int fd = rrm_try_open_fuse_device(devp); + if (fd >= -1) + return fd; + + fprintf(stderr, + "fuse device not found, try 'modprobe fuse' first\n"); + + return -1; +} diff --git a/fuse/stolen_from_fuse.c.orig b/fuse/stolen_from_fuse.c.orig new file mode 100644 index 0000000..a96cbd7 --- /dev/null +++ b/fuse/stolen_from_fuse.c.orig @@ -0,0 +1,157 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "stolen_from_fuse.h" + +// Most of this code is stolen from FUSE 2.7.4 + +int rrm_send_fd(int sock_fd, int fd) +{ + int retval; + struct msghdr msg; + struct cmsghdr *p_cmsg; + struct iovec vec; + size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)]; + 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; +} + + +/* return value: + * >= 0 => fd + * -1 => error + */ +int rrm_receive_fd(int fd) +{ + struct msghdr msg; + struct iovec iov; + char buf[1]; + int rv; + size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)]; + 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 rrm_fuse_mnt_umount(const char *progname, const char *mnt, int lazy) +{ + int res; + int status; + + res = umount2(mnt, lazy ? 2 : 0); + if (res == -1) + fprintf(stderr, "%s: failed to unmount %s: %s\n", + progname, mnt, strerror(errno)); + return res; + +} + +static int rrm_try_open(const char *dev, char **devp, int silent) +{ + int fd = open(dev, O_RDWR); + if (fd != -1) { + *devp = strdup(dev); + if (*devp == NULL) { + fprintf(stderr, "failed to allocate memory\n" ); + + close(fd); + fd = -1; + } + } else if (errno == ENODEV || + errno == ENOENT)/* check for ENOENT too, for the udev case */ + return -2; + else if (!silent) { + fprintf(stderr, "failed to open %s: %s\n", dev, + strerror(errno)); + } + return fd; +} + +static int rrm_try_open_fuse_device(char **devp) +{ + int fd; + int err; + + //drop_privs(); + fd = rrm_try_open(FUSE_DEV_NEW, devp, 0); + //restore_privs(); + if (fd >= 0) + return fd; + + err = fd; + fd = rrm_try_open(FUSE_DEV_OLD, devp, 1); + if (fd >= 0) + return fd; + + return err; +} + +int rrm_open_fuse_device(char **devp) +{ + int fd = rrm_try_open_fuse_device(devp); + if (fd >= -1) + return fd; + + fprintf(stderr, + "fuse device not found, try 'modprobe fuse' first\n"); + + return -1; +} -- 2.43.0