Author: rwatson Date: Thu Aug 11 12:30:23 2011 New Revision: 224778 URL: http://svn.freebsd.org/changeset/base/224778
Log: Second-to-last commit implementing Capsicum capabilities in the FreeBSD kernel for FreeBSD 9.0: Add a new capability mask argument to fget(9) and friends, allowing system call code to declare what capabilities are required when an integer file descriptor is converted into an in-kernel struct file *. With options CAPABILITIES compiled into the kernel, this enforces capability protection; without, this change is effectively a no-op. Some cases require special handling, such as mmap(2), which must preserve information about the maximum rights at the time of mapping in the memory map so that they can later be enforced in mprotect(2) -- this is done by narrowing the rights in the existing max_protection field used for similar purposes with file permissions. In namei(9), we assert that the code is not reached from within capability mode, as we're not yet ready to enforce namespace capabilities there. This will follow in a later commit. Update two capability names: CAP_EVENT and CAP_KEVENT become CAP_POST_KEVENT and CAP_POLL_KEVENT to more accurately indicate what they represent. Approved by: re (bz) Submitted by: jonathan Sponsored by: Google Inc Modified: head/sys/amd64/linux32/linux32_machdep.c head/sys/cddl/compat/opensolaris/sys/file.h head/sys/compat/freebsd32/freebsd32_ioctl.c head/sys/compat/linux/linux_file.c head/sys/compat/linux/linux_ioctl.c head/sys/compat/linux/linux_socket.c head/sys/compat/linux/linux_stats.c head/sys/compat/svr4/svr4_fcntl.c head/sys/compat/svr4/svr4_filio.c head/sys/compat/svr4/svr4_ioctl.c head/sys/compat/svr4/svr4_misc.c head/sys/compat/svr4/svr4_stream.c head/sys/dev/aac/aac_linux.c head/sys/dev/amr/amr_linux.c head/sys/dev/hwpmc/hwpmc_logging.c head/sys/dev/ipmi/ipmi_linux.c head/sys/dev/iscsi/initiator/iscsi.c head/sys/dev/mfi/mfi_linux.c head/sys/dev/snp/snp.c head/sys/dev/tdfx/tdfx_linux.c head/sys/fs/coda/coda_psdev.c head/sys/fs/fdescfs/fdesc_vnops.c head/sys/fs/nfsclient/nfs_clport.c head/sys/fs/nfsserver/nfs_nfsdport.c head/sys/fs/portalfs/portal_vfsops.c head/sys/fs/portalfs/portal_vnops.c head/sys/gnu/fs/xfs/xfs_dfrag.c head/sys/i386/ibcs2/ibcs2_fcntl.c head/sys/i386/ibcs2/ibcs2_ioctl.c head/sys/i386/ibcs2/ibcs2_misc.c head/sys/i386/linux/linux_machdep.c head/sys/kern/kern_descrip.c head/sys/kern/kern_event.c head/sys/kern/kern_exec.c head/sys/kern/sys_capability.c head/sys/kern/sys_generic.c head/sys/kern/tty.c head/sys/kern/uipc_mqueue.c head/sys/kern/uipc_sem.c head/sys/kern/uipc_syscalls.c head/sys/kern/vfs_acl.c head/sys/kern/vfs_aio.c head/sys/kern/vfs_extattr.c head/sys/kern/vfs_lookup.c head/sys/kern/vfs_syscalls.c head/sys/netgraph/ng_socket.c head/sys/nfsserver/nfs_srvkrpc.c head/sys/security/audit/audit_arg.c head/sys/security/mac/mac_syscalls.c head/sys/sys/capability.h head/sys/sys/file.h head/sys/sys/filedesc.h head/sys/ufs/ffs/ffs_alloc.c head/sys/vm/vm_mmap.c head/tools/regression/security/cap_test/cap_test.c head/tools/regression/security/cap_test/cap_test_capabilities.c Modified: head/sys/amd64/linux32/linux32_machdep.c ============================================================================== --- head/sys/amd64/linux32/linux32_machdep.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/amd64/linux32/linux32_machdep.c Thu Aug 11 12:30:23 2011 (r224778) @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/file.h> #include <sys/fcntl.h> #include <sys/clock.h> @@ -566,7 +567,7 @@ linux_mmap_common(struct thread *td, l_u * protection options specified. */ - if ((error = fget(td, bsd_args.fd, &fp)) != 0) + if ((error = fget(td, bsd_args.fd, CAP_MMAP, &fp)) != 0) return (error); if (fp->f_type != DTYPE_VNODE) { fdrop(fp, td); Modified: head/sys/cddl/compat/opensolaris/sys/file.h ============================================================================== --- head/sys/cddl/compat/opensolaris/sys/file.h Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/cddl/compat/opensolaris/sys/file.h Thu Aug 11 12:30:23 2011 (r224778) @@ -36,12 +36,18 @@ #ifdef _KERNEL typedef struct file file_t; +#include <sys/capability.h> + static __inline file_t * getf(int fd) { struct file *fp; - if (fget(curthread, fd, &fp) == 0) + /* + * We wouldn't need all of these rights on every invocation + * if we had more information about intent. + */ + if (fget(curthread, fd, CAP_READ | CAP_WRITE | CAP_SEEK, &fp) == 0) return (fp); return (NULL); } @@ -51,7 +57,8 @@ releasef(int fd) { struct file *fp; - if (fget(curthread, fd, &fp) == 0) { + /* No CAP_ rights required, as we're only releasing. */ + if (fget(curthread, fd, 0, &fp) == 0) { fdrop(fp, curthread); fdrop(fp, curthread); } Modified: head/sys/compat/freebsd32/freebsd32_ioctl.c ============================================================================== --- head/sys/compat/freebsd32/freebsd32_ioctl.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/compat/freebsd32/freebsd32_ioctl.c Thu Aug 11 12:30:23 2011 (r224778) @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include "opt_compat.h" #include <sys/param.h> +#include <sys/capability.h> #include <sys/cdio.h> #include <sys/fcntl.h> #include <sys/filio.h> @@ -354,7 +355,7 @@ freebsd32_ioctl(struct thread *td, struc struct file *fp; int error; - if ((error = fget(td, uap->fd, &fp)) != 0) + if ((error = fget(td, uap->fd, CAP_IOCTL, &fp)) != 0) return (error); if ((fp->f_flag & (FREAD | FWRITE)) == 0) { fdrop(fp, td); Modified: head/sys/compat/linux/linux_file.c ============================================================================== --- head/sys/compat/linux/linux_file.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/compat/linux/linux_file.c Thu Aug 11 12:30:23 2011 (r224778) @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/conf.h> #include <sys/dirent.h> #include <sys/fcntl.h> @@ -141,7 +142,7 @@ linux_common_open(struct thread *td, int * having the same filedesc could use that fd without * checking below. */ - error = fget(td, fd, &fp); + error = fget(td, fd, CAP_IOCTL, &fp); if (!error) { sx_slock(&proctree_lock); PROC_LOCK(p); @@ -345,7 +346,7 @@ getdents_common(struct thread *td, struc } else justone = 0; - if ((error = getvnode(td->td_proc->p_fd, args->fd, &fp)) != 0) + if ((error = getvnode(td->td_proc->p_fd, args->fd, CAP_READ, &fp)) != 0) return (error); if ((fp->f_flag & FREAD) == 0) { @@ -1041,7 +1042,7 @@ linux_pread(td, uap) if (error == 0) { /* This seems to violate POSIX but linux does it */ - if ((error = fgetvp(td, uap->fd, &vp)) != 0) + if ((error = fgetvp(td, uap->fd, CAP_READ, &vp)) != 0) return (error); if (vp->v_type == VDIR) { vrele(vp); @@ -1390,7 +1391,7 @@ fcntl_common(struct thread *td, struct l * significant effect for pipes (SIGIO is not delivered for * pipes under Linux-2.2.35 at least). */ - error = fget(td, args->fd, &fp); + error = fget(td, args->fd, CAP_FCNTL, &fp); if (error) return (error); if (fp->f_type == DTYPE_PIPE) { Modified: head/sys/compat/linux/linux_ioctl.c ============================================================================== --- head/sys/compat/linux/linux_ioctl.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/compat/linux/linux_ioctl.c Thu Aug 11 12:30:23 2011 (r224778) @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> #include <sys/sysproto.h> +#include <sys/capability.h> #include <sys/cdio.h> #include <sys/dvdio.h> #include <sys/conf.h> @@ -193,7 +194,7 @@ linux_ioctl_hdio(struct thread *td, stru u_int sectorsize, fwcylinders, fwheads, fwsectors; off_t mediasize, bytespercyl; - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); switch (args->cmd & 0xffff) { case LINUX_HDIO_GET_GEO: @@ -274,7 +275,7 @@ linux_ioctl_disk(struct thread *td, stru u_int sectorsize; off_t mediasize; - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); switch (args->cmd & 0xffff) { case LINUX_BLKGETSIZE: @@ -700,7 +701,7 @@ linux_ioctl_termio(struct thread *td, st struct file *fp; int error; - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); switch (args->cmd & 0xffff) { @@ -1440,7 +1441,7 @@ linux_ioctl_cdrom(struct thread *td, str struct file *fp; int error; - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); switch (args->cmd & 0xffff) { @@ -1965,7 +1966,7 @@ linux_ioctl_console(struct thread *td, s struct file *fp; int error; - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); switch (args->cmd & 0xffff) { @@ -2356,7 +2357,7 @@ linux_ioctl_socket(struct thread *td, st ifp = NULL; error = 0; - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); type = fp->f_type; fdrop(fp, td); @@ -2582,7 +2583,7 @@ linux_ioctl_private(struct thread *td, s struct file *fp; int error, type; - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); type = fp->f_type; fdrop(fp, td); @@ -2608,7 +2609,7 @@ linux_ioctl_sg(struct thread *td, struct u_long cmd; int error; - if ((error = fget(td, args->fd, &fp)) != 0) { + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) { printf("sg_linux_ioctl: fget returned %d\n", error); return (error); } @@ -2843,7 +2844,7 @@ linux_ioctl_v4l(struct thread *td, struc case LINUX_VIDIOCSCHAN: args->cmd = VIDIOCSCHAN; break; case LINUX_VIDIOCGTUNER: - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun)); if (error) { @@ -2861,7 +2862,7 @@ linux_ioctl_v4l(struct thread *td, struc return (error); case LINUX_VIDIOCSTUNER: - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun)); if (error) { @@ -2878,7 +2879,7 @@ linux_ioctl_v4l(struct thread *td, struc case LINUX_VIDIOCCAPTURE: args->cmd = VIDIOCCAPTURE; break; case LINUX_VIDIOCGWIN: - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = fo_ioctl(fp, VIDIOCGWIN, &vwin, td->td_ucred, td); if (!error) { @@ -2890,7 +2891,7 @@ linux_ioctl_v4l(struct thread *td, struc return (error); case LINUX_VIDIOCSWIN: - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = copyin((void *) args->arg, &l_vwin, sizeof(l_vwin)); if (error) { @@ -2913,7 +2914,7 @@ linux_ioctl_v4l(struct thread *td, struc return (error); case LINUX_VIDIOCGFBUF: - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = fo_ioctl(fp, VIDIOCGFBUF, &vbuf, td->td_ucred, td); if (!error) { @@ -2925,7 +2926,7 @@ linux_ioctl_v4l(struct thread *td, struc return (error); case LINUX_VIDIOCSFBUF: - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = copyin((void *) args->arg, &l_vbuf, sizeof(l_vbuf)); if (error) { @@ -2953,7 +2954,7 @@ linux_ioctl_v4l(struct thread *td, struc case LINUX_VIDIOCGPLAYINFO: args->cmd = VIDIOCGPLAYINFO; break; case LINUX_VIDIOCSMICROCODE: - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = copyin((void *) args->arg, &l_vcode, sizeof(l_vcode)); if (error) { @@ -3197,7 +3198,7 @@ linux_ioctl_v4l2(struct thread *td, stru error = copyin((void *)args->arg, &l_vformat, sizeof(l_vformat)); if (error) return (error); - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); if (linux_to_bsd_v4l2_format(&l_vformat, &vformat) != 0) error = EINVAL; @@ -3220,7 +3221,7 @@ linux_ioctl_v4l2(struct thread *td, stru if (error) return (error); linux_to_bsd_v4l2_standard(&l_vstd, &vstd); - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = fo_ioctl(fp, VIDIOC_ENUMSTD, (caddr_t)&vstd, td->td_ucred, td); @@ -3242,7 +3243,7 @@ linux_ioctl_v4l2(struct thread *td, stru sizeof(struct l_v4l2_input)); if (error != 0) return (error); - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = fo_ioctl(fp, VIDIOC_ENUMINPUT, (caddr_t)&vinp, td->td_ucred, td); @@ -3261,7 +3262,7 @@ linux_ioctl_v4l2(struct thread *td, stru error = copyin((void *)args->arg, &l_vbuf, sizeof(l_vbuf)); if (error) return (error); - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); linux_to_bsd_v4l2_buffer(&l_vbuf, &vbuf); if ((args->cmd & 0xffff) == LINUX_VIDIOC_QUERYBUF) @@ -3431,7 +3432,7 @@ linux_ioctl(struct thread *td, struct li (unsigned long)args->cmd); #endif - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); if ((fp->f_flag & (FREAD|FWRITE)) == 0) { fdrop(fp, td); Modified: head/sys/compat/linux/linux_socket.c ============================================================================== --- head/sys/compat/linux/linux_socket.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/compat/linux/linux_socket.c Thu Aug 11 12:30:23 2011 (r224778) @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include <sys/proc.h> #include <sys/systm.h> #include <sys/sysproto.h> +#include <sys/capability.h> #include <sys/fcntl.h> #include <sys/file.h> #include <sys/limits.h> @@ -743,7 +744,7 @@ linux_connect(struct thread *td, struct * socket and use the file descriptor reference instead of * creating a new one. */ - error = fgetsock(td, args->s, &so, &fflag); + error = fgetsock(td, args->s, CAP_CONNECT, &so, &fflag); if (error == 0) { error = EISCONN; if (fflag & FNONBLOCK) { Modified: head/sys/compat/linux/linux_stats.c ============================================================================== --- head/sys/compat/linux/linux_stats.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/compat/linux/linux_stats.c Thu Aug 11 12:30:23 2011 (r224778) @@ -141,8 +141,11 @@ translate_fd_major_minor(struct thread * struct vnode *vp; int major, minor; + /* + * No capability rights required here. + */ if ((!S_ISCHR(buf->st_mode) && !S_ISBLK(buf->st_mode)) || - fget(td, fd, &fp) != 0) + fget(td, fd, 0, &fp) != 0) return; vp = fp->f_vnode; if (vp != NULL && vp->v_rdev != NULL && Modified: head/sys/compat/svr4/svr4_fcntl.c ============================================================================== --- head/sys/compat/svr4/svr4_fcntl.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/compat/svr4/svr4_fcntl.c Thu Aug 11 12:30:23 2011 (r224778) @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/capability.h> #include <sys/systm.h> #include <sys/file.h> #include <sys/filedesc.h> @@ -261,7 +262,17 @@ fd_revoke(td, fd) int error, *retval; retval = td->td_retval; - if ((error = fgetvp(td, fd, &vp)) != 0) + /* + * If we ever want to support Capsicum on SVR4 processes (unlikely) + * or FreeBSD grows a native frevoke() (more likely), we will need a + * CAP_REVOKE here. + * + * In the meantime, use CAP_MASK_VALID: if a SVR4 process wants to + * do an frevoke(), it needs to do it on either a regular file + * descriptor or a fully-privileged capability (which is effectively + * the same as a non-capability-restricted file descriptor). + */ + if ((error = fgetvp(td, fd, CAP_MASK_VALID, &vp)) != 0) return (error); if (vp->v_type != VCHR && vp->v_type != VBLK) { @@ -313,7 +324,7 @@ fd_truncate(td, fd, flp) /* * We only support truncating the file. */ - if ((error = fget(td, fd, &fp)) != 0) + if ((error = fget(td, fd, CAP_FTRUNCATE, &fp)) != 0) return (error); vp = fp->f_vnode; @@ -392,7 +403,7 @@ svr4_sys_open(td, uap) #if defined(NOTYET) struct file *fp; - error = fget(td, retval, &fp); + error = fget(td, retval, CAP_IOCTL, &fp); PROC_UNLOCK(p); /* * we may have lost a race the above open() and Modified: head/sys/compat/svr4/svr4_filio.c ============================================================================== --- head/sys/compat/svr4/svr4_filio.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/compat/svr4/svr4_filio.c Thu Aug 11 12:30:23 2011 (r224778) @@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/proc.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/file.h> #include <sys/filio.h> #include <sys/lock.h> @@ -113,7 +114,7 @@ svr4_sys_read(td, uap) ra.buf = uap->buf; ra.nbyte = uap->nbyte; - if (fget(td, uap->fd, &fp) != 0) { + if (fget(td, uap->fd, CAP_READ, &fp) != 0) { DPRINTF(("Something fishy with the user-supplied file descriptor...\n")); return EBADF; } Modified: head/sys/compat/svr4/svr4_ioctl.c ============================================================================== --- head/sys/compat/svr4/svr4_ioctl.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/compat/svr4/svr4_ioctl.c Thu Aug 11 12:30:23 2011 (r224778) @@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/proc.h> +#include <sys/capability.h> #include <sys/file.h> #include <sys/filedesc.h> #include <sys/fcntl.h> @@ -102,7 +103,7 @@ svr4_sys_ioctl(td, uap) retval = td->td_retval; cmd = uap->com; - if ((error = fget(td, uap->fd, &fp)) != 0) + if ((error = fget(td, uap->fd, CAP_IOCTL, &fp)) != 0) return (error); if ((fp->f_flag & (FREAD | FWRITE)) == 0) { Modified: head/sys/compat/svr4/svr4_misc.c ============================================================================== --- head/sys/compat/svr4/svr4_misc.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/compat/svr4/svr4_misc.c Thu Aug 11 12:30:23 2011 (r224778) @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/dirent.h> #include <sys/fcntl.h> #include <sys/filedesc.h> @@ -246,7 +247,8 @@ svr4_sys_getdents64(td, uap) DPRINTF(("svr4_sys_getdents64(%d, *, %d)\n", uap->fd, uap->nbytes)); - if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) { + if ((error = getvnode(td->td_proc->p_fd, uap->fd, + CAP_READ | CAP_SEEK, &fp)) != 0) { return (error); } @@ -427,7 +429,8 @@ svr4_sys_getdents(td, uap) if (uap->nbytes < 0) return (EINVAL); - if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) + if ((error = getvnode(td->td_proc->p_fd, uap->fd, + CAP_READ | CAP_SEEK, &fp)) != 0) return (error); if ((fp->f_flag & FREAD) == 0) { @@ -615,7 +618,8 @@ svr4_sys_fchroot(td, uap) if ((error = priv_check(td, PRIV_VFS_FCHROOT)) != 0) return error; - if ((error = getvnode(fdp, uap->fd, &fp)) != 0) + /* XXX: we have the chroot priv... what cap might we need? all? */ + if ((error = getvnode(fdp, uap->fd, 0, &fp)) != 0) return error; vp = fp->f_vnode; VREF(vp); Modified: head/sys/compat/svr4/svr4_stream.c ============================================================================== --- head/sys/compat/svr4/svr4_stream.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/compat/svr4/svr4_stream.c Thu Aug 11 12:30:23 2011 (r224778) @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/fcntl.h> #include <sys/filedesc.h> #include <sys/filio.h> @@ -1448,7 +1449,7 @@ svr4_sys_putmsg(td, uap) struct file *fp; int error; - if ((error = fget(td, uap->fd, &fp)) != 0) { + if ((error = fget(td, uap->fd, CAP_WRITE, &fp)) != 0) { #ifdef DEBUG_SVR4 uprintf("putmsg: bad fp\n"); #endif @@ -1620,7 +1621,7 @@ svr4_sys_getmsg(td, uap) struct file *fp; int error; - if ((error = fget(td, uap->fd, &fp)) != 0) { + if ((error = fget(td, uap->fd, CAP_READ, &fp)) != 0) { #ifdef DEBUG_SVR4 uprintf("getmsg: bad fp\n"); #endif Modified: head/sys/dev/aac/aac_linux.c ============================================================================== --- head/sys/dev/aac/aac_linux.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/dev/aac/aac_linux.c Thu Aug 11 12:30:23 2011 (r224778) @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/conf.h> #include <sys/kernel.h> #include <sys/module.h> @@ -78,7 +79,7 @@ aac_linux_ioctl(struct thread *td, struc u_long cmd; int error; - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); cmd = args->cmd; Modified: head/sys/dev/amr/amr_linux.c ============================================================================== --- head/sys/dev/amr/amr_linux.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/dev/amr/amr_linux.c Thu Aug 11 12:30:23 2011 (r224778) @@ -30,6 +30,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/conf.h> #include <sys/kernel.h> #include <sys/module.h> @@ -74,7 +75,7 @@ amr_linux_ioctl(struct thread *p, struct struct file *fp; int error; - if ((error = fget(p, args->fd, &fp)) != 0) + if ((error = fget(p, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = fo_ioctl(fp, args->cmd, (caddr_t)args->arg, p->td_ucred, p); fdrop(fp, p); Modified: head/sys/dev/hwpmc/hwpmc_logging.c ============================================================================== --- head/sys/dev/hwpmc/hwpmc_logging.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/dev/hwpmc/hwpmc_logging.c Thu Aug 11 12:30:23 2011 (r224778) @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/capability.h> #include <sys/file.h> #include <sys/kernel.h> #include <sys/kthread.h> @@ -589,7 +590,7 @@ pmclog_configure_log(struct pmc_mdep *md po->po_file)); /* get a reference to the file state */ - error = fget_write(curthread, logfd, &po->po_file); + error = fget_write(curthread, logfd, CAP_WRITE, &po->po_file); if (error) goto error; Modified: head/sys/dev/ipmi/ipmi_linux.c ============================================================================== --- head/sys/dev/ipmi/ipmi_linux.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/dev/ipmi/ipmi_linux.c Thu Aug 11 12:30:23 2011 (r224778) @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/conf.h> #include <sys/kernel.h> #include <sys/module.h> @@ -92,7 +93,7 @@ ipmi_linux_ioctl(struct thread *td, stru u_long cmd; int error; - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); cmd = args->cmd; Modified: head/sys/dev/iscsi/initiator/iscsi.c ============================================================================== --- head/sys/dev/iscsi/initiator/iscsi.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/dev/iscsi/initiator/iscsi.c Thu Aug 11 12:30:23 2011 (r224778) @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); #include "opt_iscsi_initiator.h" #include <sys/param.h> +#include <sys/capability.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/conf.h> @@ -387,11 +388,11 @@ i_setsoc(isc_session_t *sp, int fd, stru if(sp->soc != NULL) isc_stop_receiver(sp); - error = fget(td, fd, &sp->fp); + error = fget(td, fd, CAP_SOCK_ALL, &sp->fp); if(error) return error; - if((error = fgetsock(td, fd, &sp->soc, 0)) == 0) { + if((error = fgetsock(td, fd, CAP_SOCK_ALL, &sp->soc, 0)) == 0) { sp->td = td; isc_start_receiver(sp); } Modified: head/sys/dev/mfi/mfi_linux.c ============================================================================== --- head/sys/dev/mfi/mfi_linux.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/dev/mfi/mfi_linux.c Thu Aug 11 12:30:23 2011 (r224778) @@ -29,6 +29,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/conf.h> #include <sys/kernel.h> #include <sys/module.h> @@ -95,7 +96,7 @@ mfi_linux_ioctl(struct thread *p, struct break; } - if ((error = fget(p, args->fd, &fp)) != 0) + if ((error = fget(p, args->fd, CAP_IOCTL, &fp)) != 0) return (error); error = fo_ioctl(fp, cmd, (caddr_t)args->arg, p->td_ucred, p); fdrop(fp, p); Modified: head/sys/dev/snp/snp.c ============================================================================== --- head/sys/dev/snp/snp.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/dev/snp/snp.c Thu Aug 11 12:30:23 2011 (r224778) @@ -252,6 +252,9 @@ snp_ioctl(struct cdev *dev, u_long cmd, SNP_UNLOCK(); return (EBUSY); } + /* + * XXXRW / XXXJA: no capability check here. + */ error = ttyhook_register(&ss->snp_tty, td->td_proc, *(int *)data, &snp_hook, ss); SNP_UNLOCK(); Modified: head/sys/dev/tdfx/tdfx_linux.c ============================================================================== --- head/sys/dev/tdfx/tdfx_linux.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/dev/tdfx/tdfx_linux.c Thu Aug 11 12:30:23 2011 (r224778) @@ -28,6 +28,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/capability.h> #include <sys/file.h> #include <sys/kernel.h> #include <sys/module.h> @@ -53,7 +54,7 @@ linux_ioctl_tdfx(struct thread *td, stru struct file *fp; - if ((error = fget(td, args->fd, &fp)) != 0) + if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) return (error); /* We simply copy the data and send it right to ioctl */ copyin((caddr_t)args->arg, &d_pio, sizeof(d_pio)); Modified: head/sys/fs/coda/coda_psdev.c ============================================================================== --- head/sys/fs/coda/coda_psdev.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/fs/coda/coda_psdev.c Thu Aug 11 12:30:23 2011 (r224778) @@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/conf.h> #include <sys/ioccom.h> #include <sys/kernel.h> @@ -371,7 +372,7 @@ vc_write(struct cdev *dev, struct uio *u struct vnode *vp = NULL; if (tmp->oh.result == 0) { - error = getvnode(uiop->uio_td->td_proc->p_fd, + error = getvnode(uiop->uio_td->td_proc->p_fd, CAP_WRITE, tmp->fd, &fp); if (!error) { /* Modified: head/sys/fs/fdescfs/fdesc_vnops.c ============================================================================== --- head/sys/fs/fdescfs/fdesc_vnops.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/fs/fdescfs/fdesc_vnops.c Thu Aug 11 12:30:23 2011 (r224778) @@ -40,6 +40,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/conf.h> #include <sys/dirent.h> #include <sys/filedesc.h> @@ -305,7 +306,10 @@ fdesc_lookup(ap) fd = fd1; } - if ((error = fget(td, fd, &fp)) != 0) + /* + * No rights to check since 'fp' isn't actually used. + */ + if ((error = fget(td, fd, 0, &fp)) != 0) goto bad; /* Check if we're looking up ourselves. */ @@ -455,7 +459,7 @@ fdesc_setattr(ap) /* * Allow setattr where there is an underlying vnode. */ - error = getvnode(td->td_proc->p_fd, fd, &fp); + error = getvnode(td->td_proc->p_fd, fd, CAP_EXTATTR_SET, &fp); if (error) { /* * getvnode() returns EINVAL if the file descriptor is not Modified: head/sys/fs/nfsclient/nfs_clport.c ============================================================================== --- head/sys/fs/nfsclient/nfs_clport.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/fs/nfsclient/nfs_clport.c Thu Aug 11 12:30:23 2011 (r224778) @@ -36,6 +36,8 @@ __FBSDID("$FreeBSD$"); #include "opt_kdtrace.h" +#include <sys/capability.h> + /* * generally, I don't like #includes inside .h files, but it seems to * be the easiest way to handle the port. @@ -1231,7 +1233,13 @@ nfssvc_nfscl(struct thread *td, struct n error = copyin(uap->argp, (caddr_t)&nfscbdarg, sizeof(nfscbdarg)); if (error) return (error); - if ((error = fget(td, nfscbdarg.sock, &fp)) != 0) { + /* + * Since we don't know what rights might be required, + * pretend that we need them all. It is better to be too + * careful than too reckless. + */ + if ((error = fget(td, nfscbdarg.sock, CAP_SOCK_ALL, &fp)) + != 0) { return (error); } if (fp->f_type != DTYPE_SOCKET) { Modified: head/sys/fs/nfsserver/nfs_nfsdport.c ============================================================================== --- head/sys/fs/nfsserver/nfs_nfsdport.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/fs/nfsserver/nfs_nfsdport.c Thu Aug 11 12:30:23 2011 (r224778) @@ -34,6 +34,8 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include <sys/capability.h> + /* * Functions that perform the vfs operations required by the routines in * nfsd_serv.c. It is hoped that this change will make the server more @@ -3027,8 +3029,14 @@ nfssvc_nfsd(struct thread *td, struct nf error = copyin(uap->argp, (caddr_t)&sockarg, sizeof (sockarg)); if (error) goto out; - if ((error = fget(td, sockarg.sock, &fp)) != 0) + /* + * Since we don't know what rights might be required, + * pretend that we need them all. It is better to be too + * careful than too reckless. + */ + if ((error = fget(td, sockarg.sock, CAP_SOCK_ALL, &fp)) != 0) goto out; + return (error); if (fp->f_type != DTYPE_SOCKET) { fdrop(fp, td); error = EPERM; Modified: head/sys/fs/portalfs/portal_vfsops.c ============================================================================== --- head/sys/fs/portalfs/portal_vfsops.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/fs/portalfs/portal_vfsops.c Thu Aug 11 12:30:23 2011 (r224778) @@ -40,6 +40,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/domain.h> #include <sys/filedesc.h> #include <sys/kernel.h> @@ -112,7 +113,12 @@ portal_mount(struct mount *mp) if (error) return (error); - if ((error = fget(td, v, &fp)) != 0) + /* + * Capsicum is not incompatible with portalfs, but we don't really + * know what rights are required. In the spirit of "better safe than + * sorry", pretend that all rights are required for now. + */ + if ((error = fget(td, v, CAP_MASK_VALID, &fp)) != 0) return (error); if (fp->f_type != DTYPE_SOCKET) { fdrop(fp, td); Modified: head/sys/fs/portalfs/portal_vnops.c ============================================================================== --- head/sys/fs/portalfs/portal_vnops.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/fs/portalfs/portal_vnops.c Thu Aug 11 12:30:23 2011 (r224778) @@ -38,7 +38,10 @@ * Portal Filesystem */ +#include "opt_capsicum.h" + #include <sys/param.h> +#include <sys/capability.h> #include <sys/fcntl.h> #include <sys/file.h> #include <sys/kernel.h> @@ -232,6 +235,15 @@ portal_open(ap) struct file *fp; struct portal_cred pcred; +#ifdef CAPABILITY_MODE + /* + * This may require access to a global namespace (e.g. an IP address); + * disallow it entirely, as we do open(2). + */ + if (IN_CAPABILITY_MODE(td)) + return (ECAPMODE); +#endif + /* * Nothing to do when opening the root node. */ @@ -414,7 +426,7 @@ portal_open(ap) * Check that the mode the file is being opened for is a subset * of the mode of the existing descriptor. */ - if ((error = fget(td, fd, &fp)) != 0) + if ((error = fget(td, fd, 0, &fp)) != 0) goto bad; if (((ap->a_mode & (FREAD|FWRITE)) | fp->f_flag) != fp->f_flag) { fdrop(fp, td); Modified: head/sys/gnu/fs/xfs/xfs_dfrag.c ============================================================================== --- head/sys/gnu/fs/xfs/xfs_dfrag.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/gnu/fs/xfs/xfs_dfrag.c Thu Aug 11 12:30:23 2011 (r224778) @@ -46,6 +46,7 @@ #include "xfs_mac.h" #include "xfs_rw.h" +#include <sys/capability.h> #include <sys/file.h> /* @@ -79,7 +80,8 @@ xfs_swapext( } /* Pull information for the target fd */ - if (fgetvp(td, (int)sxp->sx_fdtarget, &bvp) != 0) { + if (fgetvp(td, (int)sxp->sx_fdtarget, CAP_READ | CAP_WRITE, &bvp) + != 0) { error = XFS_ERROR(EINVAL); goto error0; } @@ -91,7 +93,7 @@ xfs_swapext( goto error0; } - if (fgetvp(td, (int)sxp->sx_fdtmp, &btvp) != 0) { + if (fgetvp(td, (int)sxp->sx_fdtmp, CAP_READ | CAP_WRITE, &btvp) != 0) { error = XFS_ERROR(EINVAL); goto error0; } Modified: head/sys/i386/ibcs2/ibcs2_fcntl.c ============================================================================== --- head/sys/i386/ibcs2/ibcs2_fcntl.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/i386/ibcs2/ibcs2_fcntl.c Thu Aug 11 12:30:23 2011 (r224778) @@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/fcntl.h> #include <sys/file.h> #include <sys/filedesc.h> @@ -203,7 +204,7 @@ ibcs2_open(td, uap) struct file *fp; int error; - error = fget(td, td->td_retval[0], &fp); + error = fget(td, td->td_retval[0], CAP_IOCTL, &fp); PROC_UNLOCK(p); if (error) return (EBADF); Modified: head/sys/i386/ibcs2/ibcs2_ioctl.c ============================================================================== --- head/sys/i386/ibcs2/ibcs2_ioctl.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/i386/ibcs2/ibcs2_ioctl.c Thu Aug 11 12:30:23 2011 (r224778) @@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/consio.h> #include <sys/fcntl.h> #include <sys/file.h> @@ -333,7 +334,7 @@ ibcs2_ioctl(td, uap) struct file *fp; int error; - if ((error = fget(td, uap->fd, &fp)) != 0) { + if ((error = fget(td, uap->fd, CAP_IOCTL, &fp)) != 0) { DPRINTF(("ibcs2_ioctl(%d): bad fd %d ", p->p_pid, uap->fd)); return EBADF; Modified: head/sys/i386/ibcs2/ibcs2_misc.c ============================================================================== --- head/sys/i386/ibcs2/ibcs2_misc.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/i386/ibcs2/ibcs2_misc.c Thu Aug 11 12:30:23 2011 (r224778) @@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$"); */ #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/dirent.h> #include <sys/fcntl.h> #include <sys/filedesc.h> @@ -336,7 +337,8 @@ ibcs2_getdents(td, uap) #define BSD_DIRENT(cp) ((struct dirent *)(cp)) #define IBCS2_RECLEN(reclen) (reclen + sizeof(u_short)) - if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) + if ((error = getvnode(td->td_proc->p_fd, uap->fd, + CAP_READ | CAP_SEEK, &fp)) != 0) return (error); if ((fp->f_flag & FREAD) == 0) { fdrop(fp, td); @@ -492,7 +494,8 @@ ibcs2_read(td, uap) u_long *cookies = NULL, *cookiep; int ncookies; - if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) { + if ((error = getvnode(td->td_proc->p_fd, uap->fd, + CAP_READ | CAP_SEEK, &fp)) != 0) { if (error == EINVAL) return read(td, (struct read_args *)uap); else Modified: head/sys/i386/linux/linux_machdep.c ============================================================================== --- head/sys/i386/linux/linux_machdep.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/i386/linux/linux_machdep.c Thu Aug 11 12:30:23 2011 (r224778) @@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/file.h> #include <sys/fcntl.h> #include <sys/imgact.h> @@ -467,9 +468,12 @@ linux_mmap_common(struct thread *td, l_u * The file descriptor fildes is opened with * read permission, regardless of the * protection options specified. + * + * Checking just CAP_MMAP is fine here, since the real work + * is done in the FreeBSD mmap(). */ - if ((error = fget(td, bsd_args.fd, &fp)) != 0) + if ((error = fget(td, bsd_args.fd, CAP_MMAP, &fp)) != 0) return (error); if (fp->f_type != DTYPE_VNODE) { fdrop(fp, td); Modified: head/sys/kern/kern_descrip.c ============================================================================== --- head/sys/kern/kern_descrip.c Thu Aug 11 11:30:21 2011 (r224777) +++ head/sys/kern/kern_descrip.c Thu Aug 11 12:30:23 2011 (r224778) @@ -431,6 +431,26 @@ fdtofp(int fd, struct filedesc *fdp) return (fp); } +static inline int +fdunwrap(int fd, cap_rights_t rights, struct filedesc *fdp, struct file **fpp) +{ + + *fpp = fdtofp(fd, fdp); + if (*fpp == NULL) + return (EBADF); + +#ifdef CAPABILITIES + if ((*fpp)->f_type == DTYPE_CAPABILITY) { + int err = cap_funwrap(*fpp, rights, fpp); + if (err != 0) { + *fpp = NULL; + return (err); + } + } +#endif /* CAPABILITIES */ + return (0); +} + int kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) { @@ -489,9 +509,9 @@ kern_fcntl(struct thread *td, int fd, in case F_GETFL: FILEDESC_SLOCK(fdp); - if ((fp = fdtofp(fd, fdp)) == NULL) { + error = fdunwrap(fd, CAP_FCNTL, fdp, &fp); + if (error != 0) { FILEDESC_SUNLOCK(fdp); - error = EBADF; break; } td->td_retval[0] = OFLAGS(fp->f_flag); @@ -500,9 +520,9 @@ kern_fcntl(struct thread *td, int fd, in case F_SETFL: FILEDESC_SLOCK(fdp); - if ((fp = fdtofp(fd, fdp)) == NULL) { + error = fdunwrap(fd, CAP_FCNTL, fdp, &fp); + if (error != 0) { FILEDESC_SUNLOCK(fdp); - error = EBADF; break; } fhold(fp); @@ -532,9 +552,9 @@ kern_fcntl(struct thread *td, int fd, in case F_GETOWN: FILEDESC_SLOCK(fdp); - if ((fp = fdtofp(fd, fdp)) == NULL) { + error = fdunwrap(fd, CAP_FCNTL, fdp, &fp); + if (error != 0) { FILEDESC_SUNLOCK(fdp); - error = EBADF; break; } fhold(fp); @@ -547,9 +567,9 @@ kern_fcntl(struct thread *td, int fd, in case F_SETOWN: FILEDESC_SLOCK(fdp); - if ((fp = fdtofp(fd, fdp)) == NULL) { + error = fdunwrap(fd, CAP_FCNTL, fdp, &fp); *** DIFF OUTPUT TRUNCATED AT 1000 LINES *** _______________________________________________ svn-src-head@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"