From dba2d1f8b4ed330e9bbdbf39f1dc550ccb3ecc8b Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Wed, 18 Sep 2013 13:55:15 +0200 Subject: [PATCH] VFS: add dupfrom(2) call This call copies a file descriptor from a remote process into the calling process. The call is for the VND driver only, and in the future, ACLs will prevent any other process from using this call. Change-Id: Ib16fdd1f1a12cb38a70d7e441dad91bc86898f6d --- include/lib.h | 1 + include/minix/callnr.h | 1 + include/minix/com.h | 4 +++ lib/libminlib/Makefile | 7 ++--- lib/libminlib/dupfrom.c | 14 ++++++++++ servers/pm/table.c | 2 +- servers/vfs/filedes.c | 58 ++++++++++++++++++++++++++++++++++++++++- servers/vfs/proto.h | 1 + servers/vfs/table.c | 2 +- servers/vfs/vnode.h | 1 + 10 files changed, 85 insertions(+), 6 deletions(-) create mode 100644 lib/libminlib/dupfrom.c diff --git a/include/lib.h b/include/lib.h index 512714f66..92cf2a5fb 100644 --- a/include/lib.h +++ b/include/lib.h @@ -44,6 +44,7 @@ int mapdriver(char *label, int major, int style, int flags); pid_t getnpid(endpoint_t proc_ep); uid_t getnuid(endpoint_t proc_ep); gid_t getngid(endpoint_t proc_ep); +int dupfrom(endpoint_t endpt, int fd); ssize_t pread64(int fd, void *buf, size_t count, u64_t where); ssize_t pwrite64(int fd, const void *buf, size_t count, u64_t where); diff --git a/include/minix/callnr.h b/include/minix/callnr.h index 340e6d619..ed220aba5 100644 --- a/include/minix/callnr.h +++ b/include/minix/callnr.h @@ -47,6 +47,7 @@ #define FSTAT 52 #define LSTAT 53 #define IOCTL 54 +#define DUPFROM 56 #define FS_READY 57 #define PIPE2 58 #define EXEC 59 diff --git a/include/minix/com.h b/include/minix/com.h index 3847825f7..e0985618f 100644 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -887,6 +887,10 @@ #define VFS_PFS_FD m2_i3 #define VFS_PFS_FILP m2_p1 +/* Field names for the dupfrom(2) call. */ +#define VFS_DUPFROM_ENDPT m1_i1 +#define VFS_DUPFROM_FD m1_i2 + /* Field names for GETRUSAGE related calls */ #define RU_ENDPT m1_i1 /* indicates a process for sys_getrusage */ #define RU_WHO m1_i1 /* who argument in getrusage call */ diff --git a/lib/libminlib/Makefile b/lib/libminlib/Makefile index af025661c..5d5092d52 100644 --- a/lib/libminlib/Makefile +++ b/lib/libminlib/Makefile @@ -30,9 +30,10 @@ SRCS+= servxcheck.c # queryparam SRCS+= paramvalue.c -# Minix servers/drivers syscall. -SRCS+= getngid.c getnpid.c getnprocnr.c getnucred.c getnuid.c getprocnr.c \ - mapdriver.c vm_memctl.c vm_set_priv.c vm_query_exit.c vm_update.c +# Minix servers/drivers syscall. FIXME: these should be moved into libsys. +SRCS+= dupfrom.c getngid.c getnpid.c getnprocnr.c getnucred.c getnuid.c \ + getprocnr.c mapdriver.c vm_memctl.c vm_set_priv.c vm_query_exit.c \ + vm_update.c SRCS+= oneC_sum.c diff --git a/lib/libminlib/dupfrom.c b/lib/libminlib/dupfrom.c new file mode 100644 index 000000000..b244fbbef --- /dev/null +++ b/lib/libminlib/dupfrom.c @@ -0,0 +1,14 @@ +#include +#include + +int +dupfrom(endpoint_t endpt, int fd) +{ + message m; + + memset(&m, 0, sizeof(m)); + m.VFS_DUPFROM_ENDPT = endpt; + m.VFS_DUPFROM_FD = fd; + + return _syscall(VFS_PROC_NR, DUPFROM, &m); +} diff --git a/servers/pm/table.c b/servers/pm/table.c index 6290a4cce..2150f0bf6 100644 --- a/servers/pm/table.c +++ b/servers/pm/table.c @@ -67,7 +67,7 @@ int (*call_vec[])(void) = { no_sys, /* 53 = (lstat) */ no_sys, /* 54 = ioctl */ no_sys, /* 55 = fcntl */ - no_sys, /* 56 = unused */ + no_sys, /* 56 = dupfrom */ no_sys, /* 57 = unused */ no_sys, /* 58 = unused */ do_exec, /* 59 = execve */ diff --git a/servers/vfs/filedes.c b/servers/vfs/filedes.c index 3167fc01a..a285625d1 100644 --- a/servers/vfs/filedes.c +++ b/servers/vfs/filedes.c @@ -13,6 +13,7 @@ * do_put_filp: marks a filp as not in-flight anymore. * do_cancel_fd: cancel the transaction when something goes wrong for * the receiver. + * do_dupfrom: copies a filp from another endpoint. */ #include @@ -172,7 +173,7 @@ tll_access_t locktype; err_code = EIO; /* disallow all use except close(2) */ else if ((filp = rfp->fp_filp[fild]) == NULL) err_code = EBADF; - else + else if (locktype != VNODE_NONE) /* Only lock the filp if requested */ lock_filp(filp, locktype); /* All is fine */ return(filp); /* may also be NULL */ @@ -614,3 +615,58 @@ struct filp *f; mutex_unlock(&f->filp_lock); } + +/*===========================================================================* + * do_dupfrom * + *===========================================================================*/ +int do_dupfrom(message *UNUSED(m_out)) +{ +/* Duplicate a file descriptor from another process into the calling process. + * The other process is identified by a magic grant created for it to make the + * initial (IOCTL) request to the calling process. This call has been added + * specifically for the VND driver. + */ + struct fproc *rfp; + struct filp *rfilp; + struct vnode *vp; + endpoint_t endpt; + int r, fd, slot; + + /* This should be replaced with an ACL check. */ + if (!super_user) return(EPERM); + + endpt = (endpoint_t) job_m_in.VFS_DUPFROM_ENDPT; + fd = job_m_in.VFS_DUPFROM_FD; + + if (isokendpt(endpt, &slot) != OK) return(EINVAL); + rfp = &fproc[slot]; + + /* Obtain the filp, but do not lock it yet: we first need to make sure that + * locking it will not result in a deadlock. + */ + if ((rfilp = get_filp2(rfp, fd, VNODE_NONE)) == NULL) + return(err_code); + + /* For now, we do not allow remote duplication of device nodes. In practice, + * only a block-special file can cause a deadlock for the caller (currently + * only the VND driver). This would happen if a user process passes in the + * file descriptor to the device node on which it is performing the IOCTL. + * This would cause two VFS threads to deadlock on the same filp. Since the + * VND driver does not allow device nodes to be used anyway, this somewhat + * rudimentary check eliminates such deadlocks. A better solution would be + * to check if the given endpoint holds a lock to the target filp, but we + * currently do not have this information within VFS. + */ + vp = rfilp->filp_vno; + if (S_ISCHR(vp->v_mode) || S_ISBLK(vp->v_mode)) + return(EINVAL); + + /* Now we can safely lock the filp, copy it, and unlock it again. */ + lock_filp(rfilp, VNODE_READ); + + r = copy_filp(who_e, (filp_id_t) rfilp); + + unlock_filp(rfilp); + + return(r); +} diff --git a/servers/vfs/proto.h b/servers/vfs/proto.h index 25df2dce4..8da3eef1e 100644 --- a/servers/vfs/proto.h +++ b/servers/vfs/proto.h @@ -100,6 +100,7 @@ int do_put_filp(message *m_out); int cancel_fd(endpoint_t ep, int fd); int do_cancel_fd(message *m_out); void close_filp(struct filp *fp); +int do_dupfrom(message *m_out); /* fscall.c */ void nested_fs_call(message *m); diff --git a/servers/vfs/table.c b/servers/vfs/table.c index 2329aac07..982d96c59 100644 --- a/servers/vfs/table.c +++ b/servers/vfs/table.c @@ -70,7 +70,7 @@ int (*call_vec[])(message *m_out) = { do_lstat, /* 53 = lstat */ do_ioctl, /* 54 = ioctl */ do_fcntl, /* 55 = fcntl */ - no_sys, /* 56 = (mpx) */ + do_dupfrom, /* 56 = dupfrom */ do_fsready, /* 57 = FS proc ready */ do_pipe2, /* 58 = pipe2 */ no_sys, /* 59 = (execve)*/ diff --git a/servers/vfs/vnode.h b/servers/vfs/vnode.h index e9f7cdc5e..068053f89 100644 --- a/servers/vfs/vnode.h +++ b/servers/vfs/vnode.h @@ -23,6 +23,7 @@ EXTERN struct vnode { } vnode[NR_VNODES]; /* vnode lock types mapping */ +#define VNODE_NONE TLL_NONE /* used only for get_filp2 to avoid locking */ #define VNODE_READ TLL_READ #define VNODE_OPCL TLL_READSER #define VNODE_WRITE TLL_WRITE -- 2.44.0