From aa04a06df55556014e5e6d6e10ce935cda7da6cf Mon Sep 17 00:00:00 2001 From: Ed Schouten Date: Tue, 11 Aug 2015 08:43:50 +0000 Subject: [PATCH] Introduce kern_cap_rights_limit(). The existing sys_cap_rights_limit() expects that a cap_rights_t object lives in userspace. It is therefore hard to call into it from kernelspace. Move the interesting bits of sys_cap_rights_limit() into kern_cap_rights_limit(), so that we can call into it from the CloudABI compatibility layer. Obtained from: https://github.com/NuxiNL/freebsd Differential Revision: https://reviews.freebsd.org/D3314 --- sys/kern/sys_capability.c | 55 +++++++++++++++++++++------------------ sys/sys/syscallsubr.h | 1 + 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/sys/kern/sys_capability.c b/sys/kern/sys_capability.c index b0b77fe0a9b3..e87f0b1445ac 100644 --- a/sys/kern/sys_capability.c +++ b/sys/kern/sys_capability.c @@ -213,15 +213,41 @@ cap_rights(struct filedesc *fdp, int fd) return (cap_rights_fde(&fdp->fd_ofiles[fd])); } +int +kern_cap_rights_limit(struct thread *td, int fd, cap_rights_t *rights) +{ + struct filedesc *fdp; + int error; + + fdp = td->td_proc->p_fd; + FILEDESC_XLOCK(fdp); + if (fget_locked(fdp, fd) == NULL) { + FILEDESC_XUNLOCK(fdp); + return (EBADF); + } + error = _cap_check(cap_rights(fdp, fd), rights, CAPFAIL_INCREASE); + if (error == 0) { + fdp->fd_ofiles[fd].fde_rights = *rights; + if (!cap_rights_is_set(rights, CAP_IOCTL)) { + free(fdp->fd_ofiles[fd].fde_ioctls, M_FILECAPS); + fdp->fd_ofiles[fd].fde_ioctls = NULL; + fdp->fd_ofiles[fd].fde_nioctls = 0; + } + if (!cap_rights_is_set(rights, CAP_FCNTL)) + fdp->fd_ofiles[fd].fde_fcntls = 0; + } + FILEDESC_XUNLOCK(fdp); + return (error); +} + /* * System call to limit rights of the given capability. */ int sys_cap_rights_limit(struct thread *td, struct cap_rights_limit_args *uap) { - struct filedesc *fdp; cap_rights_t rights; - int error, fd, version; + int error, version; cap_rights_init(&rights); @@ -252,30 +278,9 @@ sys_cap_rights_limit(struct thread *td, struct cap_rights_limit_args *uap) ktrcaprights(&rights); #endif - fd = uap->fd; - - AUDIT_ARG_FD(fd); + AUDIT_ARG_FD(uap->fd); AUDIT_ARG_RIGHTS(&rights); - - fdp = td->td_proc->p_fd; - FILEDESC_XLOCK(fdp); - if (fget_locked(fdp, fd) == NULL) { - FILEDESC_XUNLOCK(fdp); - return (EBADF); - } - error = _cap_check(cap_rights(fdp, fd), &rights, CAPFAIL_INCREASE); - if (error == 0) { - fdp->fd_ofiles[fd].fde_rights = rights; - if (!cap_rights_is_set(&rights, CAP_IOCTL)) { - free(fdp->fd_ofiles[fd].fde_ioctls, M_FILECAPS); - fdp->fd_ofiles[fd].fde_ioctls = NULL; - fdp->fd_ofiles[fd].fde_nioctls = 0; - } - if (!cap_rights_is_set(&rights, CAP_FCNTL)) - fdp->fd_ofiles[fd].fde_fcntls = 0; - } - FILEDESC_XUNLOCK(fdp); - return (error); + return (kern_cap_rights_limit(td, uap->fd, &rights)); } /* diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h index ce68ba80a085..094a32267102 100644 --- a/sys/sys/syscallsubr.h +++ b/sys/sys/syscallsubr.h @@ -74,6 +74,7 @@ int kern_alternate_path(struct thread *td, const char *prefix, const char *path, int kern_bindat(struct thread *td, int dirfd, int fd, struct sockaddr *sa); int kern_cap_ioctls_limit(struct thread *td, int fd, u_long *cmds, size_t ncmds); +int kern_cap_rights_limit(struct thread *td, int fd, cap_rights_t *rights); int kern_chdir(struct thread *td, char *path, enum uio_seg pathseg); int kern_clock_getcpuclockid2(struct thread *td, id_t id, int which, clockid_t *clk_id);