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
This commit is contained in:
Robert Watson 2011-08-11 12:30:23 +00:00
parent 2ffd5fdcc4
commit a9d2f8d84f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=224778
56 changed files with 563 additions and 237 deletions

View File

@ -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_uintptr_t addr, l_size_t len, l_int prot,
* 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);

View File

@ -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);
}

View File

@ -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, struct freebsd32_ioctl_args *uap)
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);

View File

@ -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 dirfd, char *path, int l_flags, int mod
* 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, struct linux_getdents64_args *args,
} 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 linux_fcntl64_args *args)
* 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) {

View File

@ -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, struct linux_ioctl_args *args)
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, struct linux_ioctl_args *args)
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, struct linux_ioctl_args *args)
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, struct linux_ioctl_args *args)
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, struct linux_ioctl_args *args)
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, struct linux_ioctl_args *args)
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, struct linux_ioctl_args *args)
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 linux_ioctl_args *args)
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, struct linux_ioctl_args *args)
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, struct linux_ioctl_args *args)
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, struct linux_ioctl_args *args)
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, struct linux_ioctl_args *args)
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, struct linux_ioctl_args *args)
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, struct linux_ioctl_args *args)
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, struct linux_ioctl_args *args)
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, struct linux_ioctl_args *args)
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, struct linux_ioctl_args *args)
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, struct linux_ioctl_args *args)
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, struct linux_ioctl_args *args)
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 linux_ioctl_args *args)
(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);

View File

@ -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 linux_connect_args *args)
* 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) {

View File

@ -141,8 +141,11 @@ translate_fd_major_minor(struct thread *td, int fd, struct stat *buf)
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 &&

View File

@ -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

View File

@ -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;
}

View File

@ -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) {

View File

@ -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);

View File

@ -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

View File

@ -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, struct linux_ioctl_args *args)
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;

View File

@ -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 linux_ioctl_args *args)
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);

View File

@ -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, struct pmc_owner *po, int logfd)
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;

View File

@ -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, struct linux_ioctl_args *args)
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;

View File

@ -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, struct thread *td)
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);
}

View File

@ -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 linux_ioctl_args *args)
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);

View File

@ -252,6 +252,9 @@ snp_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags,
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();

View File

@ -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, struct linux_ioctl_args* args)
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));

View File

@ -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 *uiop, int flag)
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) {
/*

View File

@ -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

View File

@ -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 nfssvc_args *uap)
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) {

View File

@ -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 nfssvc_args *uap)
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;

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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_uintptr_t addr, l_size_t len, l_int prot,
* 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);

View File

@ -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, int cmd, intptr_t arg)
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, int cmd, intptr_t arg)
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, int cmd, intptr_t arg)
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, int cmd, intptr_t arg)
case F_SETOWN:
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);
@ -573,9 +593,9 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
case F_SETLK:
do_setlk:
FILEDESC_SLOCK(fdp);
if ((fp = fdtofp(fd, fdp)) == NULL) {
error = fdunwrap(fd, CAP_FLOCK, fdp, &fp);
if (error != 0) {
FILEDESC_SUNLOCK(fdp);
error = EBADF;
break;
}
if (fp->f_type != DTYPE_VNODE) {
@ -668,9 +688,9 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
case F_GETLK:
FILEDESC_SLOCK(fdp);
if ((fp = fdtofp(fd, fdp)) == NULL) {
error = fdunwrap(fd, CAP_FLOCK, fdp, &fp);
if (error != 0) {
FILEDESC_SUNLOCK(fdp);
error = EBADF;
break;
}
if (fp->f_type != DTYPE_VNODE) {
@ -1312,7 +1332,7 @@ kern_fstat(struct thread *td, int fd, struct stat *sbp)
AUDIT_ARG_FD(fd);
if ((error = fget(td, fd, &fp)) != 0)
if ((error = fget(td, fd, CAP_FSTAT, &fp)) != 0)
return (error);
AUDIT_ARG_FILE(td->td_proc, fp);
@ -1368,7 +1388,7 @@ fpathconf(struct thread *td, struct fpathconf_args *uap)
struct vnode *vp;
int error;
if ((error = fget(td, uap->fd, &fp)) != 0)
if ((error = fget(td, uap->fd, CAP_FPATHCONF, &fp)) != 0)
return (error);
/* If asynchronous I/O is available, it works for all descriptors. */
@ -2294,7 +2314,7 @@ fget_unlocked(struct filedesc *fdp, int fd)
#define FGET_GETCAP 0x00000001
static __inline int
_fget(struct thread *td, int fd, struct file **fpp, int flags,
cap_rights_t needrights, cap_rights_t *haverights, u_char *maxprotp,
cap_rights_t needrights, cap_rights_t *haverightsp, u_char *maxprotp,
int fget_flags)
{
struct filedesc *fdp;
@ -2369,28 +2389,36 @@ _fget(struct thread *td, int fd, struct file **fpp, int flags,
}
int
fget(struct thread *td, int fd, struct file **fpp)
fget(struct thread *td, int fd, cap_rights_t rights, struct file **fpp)
{
return(_fget(td, fd, fpp, 0, 0, NULL, NULL, 0));
return(_fget(td, fd, fpp, 0, rights, NULL, NULL, 0));
}
int
fget_read(struct thread *td, int fd, struct file **fpp)
fget_mmap(struct thread *td, int fd, cap_rights_t rights, u_char *maxprotp,
struct file **fpp)
{
return(_fget(td, fd, fpp, FREAD, 0, NULL, NULL, 0));
return (_fget(td, fd, fpp, 0, rights, NULL, maxprotp, 0));
}
int
fget_write(struct thread *td, int fd, struct file **fpp)
fget_read(struct thread *td, int fd, cap_rights_t rights, struct file **fpp)
{
return(_fget(td, fd, fpp, FWRITE, 0, NULL, NULL, 0));
return(_fget(td, fd, fpp, FREAD, rights, NULL, NULL, 0));
}
int
fget_write(struct thread *td, int fd, cap_rights_t rights, struct file **fpp)
{
return (_fget(td, fd, fpp, FWRITE, rights, NULL, NULL, 0));
}
/*
* Unlike the other fget() calls, which will accept and check capability rights
* Unlike the other fget() calls, which accept and check capability rights
* but never return capabilities, fgetcap() returns the capability but doesn't
* check capability rights.
*/
@ -2410,13 +2438,15 @@ fgetcap(struct thread *td, int fd, struct file **fpp)
* XXX: what about the unused flags ?
*/
static __inline int
_fgetvp(struct thread *td, int fd, struct vnode **vpp, int flags)
_fgetvp(struct thread *td, int fd, int flags, cap_rights_t needrights,
cap_rights_t *haverightsp, struct vnode **vpp)
{
struct file *fp;
int error;
*vpp = NULL;
if ((error = _fget(td, fd, &fp, flags, 0, NULL, NULL, 0)) != 0)
if ((error = _fget(td, fd, &fp, flags, needrights, haverightsp,
NULL, 0)) != 0)
return (error);
if (fp->f_vnode == NULL) {
error = EINVAL;
@ -2430,25 +2460,33 @@ _fgetvp(struct thread *td, int fd, struct vnode **vpp, int flags)
}
int
fgetvp(struct thread *td, int fd, struct vnode **vpp)
fgetvp(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp)
{
return (_fgetvp(td, fd, vpp, 0));
return (_fgetvp(td, fd, 0, rights, NULL, vpp));
}
int
fgetvp_read(struct thread *td, int fd, struct vnode **vpp)
fgetvp_rights(struct thread *td, int fd, cap_rights_t need, cap_rights_t *have,
struct vnode **vpp)
{
return (_fgetvp(td, fd, 0, need, have, vpp));
}
int
fgetvp_read(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp)
{
return (_fgetvp(td, fd, vpp, FREAD));
return (_fgetvp(td, fd, FREAD, rights, NULL, vpp));
}
#ifdef notyet
int
fgetvp_write(struct thread *td, int fd, struct vnode **vpp)
fgetvp_write(struct thread *td, int fd, cap_rights_t rights,
struct vnode **vpp)
{
return (_fgetvp(td, fd, vpp, FWRITE));
return (_fgetvp(td, fd, FWRITE, rights, NULL, vpp));
}
#endif
@ -2464,7 +2502,8 @@ fgetvp_write(struct thread *td, int fd, struct vnode **vpp)
* during use.
*/
int
fgetsock(struct thread *td, int fd, struct socket **spp, u_int *fflagp)
fgetsock(struct thread *td, int fd, cap_rights_t rights, struct socket **spp,
u_int *fflagp)
{
struct file *fp;
int error;
@ -2472,7 +2511,7 @@ fgetsock(struct thread *td, int fd, struct socket **spp, u_int *fflagp)
*spp = NULL;
if (fflagp != NULL)
*fflagp = 0;
if ((error = _fget(td, fd, &fp, 0, 0, NULL, NULL, 0)) != 0)
if ((error = _fget(td, fd, &fp, 0, rights, NULL, NULL, 0)) != 0)
return (error);
if (fp->f_type != DTYPE_SOCKET) {
error = ENOTSOCK;
@ -2557,7 +2596,7 @@ flock(struct thread *td, struct flock_args *uap)
int vfslocked;
int error;
if ((error = fget(td, uap->fd, &fp)) != 0)
if ((error = fget(td, uap->fd, CAP_FLOCK, &fp)) != 0)
return (error);
if (fp->f_type != DTYPE_VNODE) {
fdrop(fp, td);

View File

@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/capability.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mutex.h>
@ -816,7 +817,7 @@ kern_kevent(struct thread *td, int fd, int nchanges, int nevents,
struct file *fp;
int i, n, nerrors, error;
if ((error = fget(td, fd, &fp)) != 0)
if ((error = fget(td, fd, CAP_POST_KEVENT, &fp)) != 0)
return (error);
if ((error = kqueue_acquire(fp, &kq)) != 0)
goto done_norel;
@ -972,7 +973,7 @@ kqueue_register(struct kqueue *kq, struct kevent *kev, struct thread *td, int wa
findkn:
if (fops->f_isfd) {
KASSERT(td != NULL, ("td is NULL"));
error = fget(td, kev->ident, &fp);
error = fget(td, kev->ident, CAP_POLL_KEVENT, &fp);
if (error)
goto done;
@ -2181,7 +2182,7 @@ kqfd_register(int fd, struct kevent *kev, struct thread *td, int waitok)
struct file *fp;
int error;
if ((error = fget(td, fd, &fp)) != 0)
if ((error = fget(td, fd, CAP_POST_KEVENT, &fp)) != 0)
return (error);
if ((error = kqueue_acquire(fp, &kq)) != 0)
goto noacquire;

View File

@ -439,7 +439,11 @@ do_execve(td, args, mac_p)
imgp->vp = binvp;
} else {
AUDIT_ARG_FD(args->fd);
error = fgetvp(td, args->fd, &binvp);
/*
* Some might argue that CAP_READ and/or CAP_MMAP should also
* be required here; such arguments will be entertained.
*/
error = fgetvp_read(td, args->fd, CAP_FEXECVE, &binvp);
if (error)
goto exec_fail;
vfslocked = VFS_LOCK_GIANT(binvp->v_mount);

View File

@ -225,7 +225,7 @@ cap_new(struct thread *td, struct cap_new_args *uap)
AUDIT_ARG_FD(fd);
AUDIT_ARG_RIGHTS(rights);
error = fget(td, fd, &fp);
error = fget(td, fd, rights, &fp);
if (error)
return (error);
AUDIT_ARG_FILE(td->td_proc, fp);

View File

@ -37,12 +37,14 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_capsicum.h"
#include "opt_compat.h"
#include "opt_ktrace.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysproto.h>
#include <sys/capability.h>
#include <sys/filedesc.h>
#include <sys/filio.h>
#include <sys/fcntl.h>
@ -232,7 +234,7 @@ kern_readv(struct thread *td, int fd, struct uio *auio)
struct file *fp;
int error;
error = fget_read(td, fd, &fp);
error = fget_read(td, fd, CAP_READ | CAP_SEEK, &fp);
if (error)
return (error);
error = dofileread(td, fd, fp, auio, (off_t)-1, 0);
@ -275,7 +277,7 @@ kern_preadv(td, fd, auio, offset)
struct file *fp;
int error;
error = fget_read(td, fd, &fp);
error = fget_read(td, fd, CAP_READ, &fp);
if (error)
return (error);
if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE))
@ -441,7 +443,7 @@ kern_writev(struct thread *td, int fd, struct uio *auio)
struct file *fp;
int error;
error = fget_write(td, fd, &fp);
error = fget_write(td, fd, CAP_WRITE | CAP_SEEK, &fp);
if (error)
return (error);
error = dofilewrite(td, fd, fp, auio, (off_t)-1, 0);
@ -484,7 +486,7 @@ kern_pwritev(td, fd, auio, offset)
struct file *fp;
int error;
error = fget_write(td, fd, &fp);
error = fget_write(td, fd, CAP_WRITE, &fp);
if (error)
return (error);
if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE))
@ -566,7 +568,7 @@ kern_ftruncate(td, fd, length)
AUDIT_ARG_FD(fd);
if (length < 0)
return (EINVAL);
error = fget(td, fd, &fp);
error = fget(td, fd, CAP_FTRUNCATE, &fp);
if (error)
return (error);
AUDIT_ARG_FILE(td->td_proc, fp);
@ -696,7 +698,7 @@ kern_ioctl(struct thread *td, int fd, u_long com, caddr_t data)
AUDIT_ARG_FD(fd);
AUDIT_ARG_CMD(com);
if ((error = fget(td, fd, &fp)) != 0)
if ((error = fget(td, fd, CAP_IOCTL, &fp)) != 0)
return (error);
if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
fdrop(fp, td);
@ -1054,6 +1056,37 @@ selsetbits(fd_mask **ibits, fd_mask **obits, int idx, fd_mask bit, int events)
return (n);
}
static __inline int
getselfd_cap(struct filedesc *fdp, int fd, struct file **fpp)
{
struct file *fp;
#ifdef CAPABILITIES
struct file *fp_fromcap;
int error;
#endif
if ((fp = fget_unlocked(fdp, fd)) == NULL)
return (EBADF);
#ifdef CAPABILITIES
/*
* If the file descriptor is for a capability, test rights and use
* the file descriptor references by the capability.
*/
error = cap_funwrap(fp, CAP_POLL_KEVENT, &fp_fromcap);
if (error) {
fdrop(fp, curthread);
return (error);
}
if (fp != fp_fromcap) {
fhold(fp_fromcap);
fdrop(fp, curthread);
fp = fp_fromcap;
}
#endif /* CAPABILITIES */
*fpp = fp;
return (0);
}
/*
* Traverse the list of fds attached to this thread's seltd and check for
* completion.
@ -1069,6 +1102,7 @@ selrescan(struct thread *td, fd_mask **ibits, fd_mask **obits)
struct file *fp;
fd_mask bit;
int fd, ev, n, idx;
int error;
fdp = td->td_proc->p_fd;
stp = td->td_sel;
@ -1080,8 +1114,9 @@ selrescan(struct thread *td, fd_mask **ibits, fd_mask **obits)
/* If the selinfo wasn't cleared the event didn't fire. */
if (si != NULL)
continue;
if ((fp = fget_unlocked(fdp, fd)) == NULL)
return (EBADF);
error = getselfd_cap(fdp, fd, &fp);
if (error)
return (error);
idx = fd / NFDBITS;
bit = (fd_mask)1 << (fd % NFDBITS);
ev = fo_poll(fp, selflags(ibits, idx, bit), td->td_ucred, td);
@ -1109,6 +1144,7 @@ selscan(td, ibits, obits, nfd)
fd_mask bit;
int ev, flags, end, fd;
int n, idx;
int error;
fdp = td->td_proc->p_fd;
n = 0;
@ -1119,8 +1155,9 @@ selscan(td, ibits, obits, nfd)
flags = selflags(ibits, idx, bit);
if (flags == 0)
continue;
if ((fp = fget_unlocked(fdp, fd)) == NULL)
return (EBADF);
error = getselfd_cap(fdp, fd, &fp);
if (error)
return (error);
selfdalloc(td, (void *)(uintptr_t)fd);
ev = fo_poll(fp, flags, td->td_ucred, td);
fdrop(fp, td);

View File

@ -30,9 +30,11 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_capsicum.h"
#include "opt_compat.h"
#include <sys/param.h>
#include <sys/capability.h>
#include <sys/conf.h>
#include <sys/cons.h>
#include <sys/fcntl.h>
@ -1810,6 +1812,9 @@ ttyhook_register(struct tty **rtp, struct proc *p, int fd,
{
struct tty *tp;
struct file *fp;
#ifdef CAPABILITIES
struct file *fp_cap;
#endif
struct cdev *dev;
struct cdevsw *cdp;
struct filedesc *fdp;
@ -1827,6 +1832,13 @@ ttyhook_register(struct tty **rtp, struct proc *p, int fd,
goto done1;
}
#ifdef CAPABILITIES
fp_cap = fp;
error = cap_funwrap(fp_cap, CAP_TTYHOOK, &fp);
if (error)
return (error);
#endif
/*
* Make sure the vnode is bound to a character device.
* Unlocked check for the vnode type is ok there, because we

View File

@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/limits.h>
#include <sys/buf.h>
#include <sys/capability.h>
#include <sys/dirent.h>
#include <sys/event.h>
#include <sys/eventhandler.h>
@ -2087,19 +2088,19 @@ kmq_unlink(struct thread *td, struct kmq_unlink_args *uap)
return (error);
}
typedef int (*_fgetf)(struct thread *, int, struct file **);
typedef int (*_fgetf)(struct thread *, int, cap_rights_t, struct file **);
/*
* Get message queue by giving file slot
*/
static int
_getmq(struct thread *td, int fd, _fgetf func,
_getmq(struct thread *td, int fd, cap_rights_t rights, _fgetf func,
struct file **fpp, struct mqfs_node **ppn, struct mqueue **pmq)
{
struct mqfs_node *pn;
int error;
error = func(td, fd, fpp);
error = func(td, fd, rights, fpp);
if (error)
return (error);
if (&mqueueops != (*fpp)->f_ops) {
@ -2118,21 +2119,21 @@ static __inline int
getmq(struct thread *td, int fd, struct file **fpp, struct mqfs_node **ppn,
struct mqueue **pmq)
{
return _getmq(td, fd, fget, fpp, ppn, pmq);
return _getmq(td, fd, CAP_POLL_KEVENT, fget, fpp, ppn, pmq);
}
static __inline int
getmq_read(struct thread *td, int fd, struct file **fpp,
struct mqfs_node **ppn, struct mqueue **pmq)
{
return _getmq(td, fd, fget_read, fpp, ppn, pmq);
return _getmq(td, fd, CAP_READ, fget_read, fpp, ppn, pmq);
}
static __inline int
getmq_write(struct thread *td, int fd, struct file **fpp,
struct mqfs_node **ppn, struct mqueue **pmq)
{
return _getmq(td, fd, fget_write, fpp, ppn, pmq);
return _getmq(td, fd, CAP_WRITE, fget_write, fpp, ppn, pmq);
}
static int
@ -2243,7 +2244,7 @@ kmq_notify(struct thread *td, struct kmq_notify_args *uap)
struct filedesc *fdp;
struct proc *p;
struct mqueue *mq;
struct file *fp;
struct file *fp, *fp2;
struct mqueue_notifier *nt, *newnt = NULL;
int error;
@ -2267,7 +2268,18 @@ kmq_notify(struct thread *td, struct kmq_notify_args *uap)
return (error);
again:
FILEDESC_SLOCK(fdp);
if (fget_locked(fdp, uap->mqd) != fp) {
fp2 = fget_locked(fdp, uap->mqd);
if (fp2 == NULL) {
FILEDESC_SUNLOCK(fdp);
error = EBADF;
goto out;
}
error = cap_funwrap(fp2, CAP_POLL_KEVENT, &fp2);
if (error) {
FILEDESC_SUNLOCK(fdp);
goto out;
}
if (fp2 != fp) {
FILEDESC_SUNLOCK(fdp);
error = EBADF;
goto out;

View File

@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
#include "opt_posix.h"
#include <sys/param.h>
#include <sys/capability.h>
#include <sys/condvar.h>
#include <sys/fcntl.h>
#include <sys/file.h>
@ -116,7 +117,8 @@ static int ksem_create(struct thread *td, const char *path,
semid_t *semidp, mode_t mode, unsigned int value,
int flags, int compat32);
static void ksem_drop(struct ksem *ks);
static int ksem_get(struct thread *td, semid_t id, struct file **fpp);
static int ksem_get(struct thread *td, semid_t id, cap_rights_t rights,
struct file **fpp);
static struct ksem *ksem_hold(struct ksem *ks);
static void ksem_insert(char *path, Fnv32_t fnv, struct ksem *ks);
static struct ksem *ksem_lookup(char *path, Fnv32_t fnv);
@ -525,13 +527,13 @@ ksem_create(struct thread *td, const char *name, semid_t *semidp, mode_t mode,
}
static int
ksem_get(struct thread *td, semid_t id, struct file **fpp)
ksem_get(struct thread *td, semid_t id, cap_rights_t rights, struct file **fpp)
{
struct ksem *ks;
struct file *fp;
int error;
error = fget(td, id, &fp);
error = fget(td, id, rights, &fp);
if (error)
return (EINVAL);
if (fp->f_type != DTYPE_SEM) {
@ -623,7 +625,8 @@ ksem_close(struct thread *td, struct ksem_close_args *uap)
struct file *fp;
int error;
error = ksem_get(td, uap->id, &fp);
/* No capability rights required to close a semaphore. */
error = ksem_get(td, uap->id, 0, &fp);
if (error)
return (error);
ks = fp->f_data;
@ -648,7 +651,7 @@ ksem_post(struct thread *td, struct ksem_post_args *uap)
struct ksem *ks;
int error;
error = ksem_get(td, uap->id, &fp);
error = ksem_get(td, uap->id, CAP_SEM_POST, &fp);
if (error)
return (error);
ks = fp->f_data;
@ -738,7 +741,7 @@ kern_sem_wait(struct thread *td, semid_t id, int tryflag,
int error;
DP((">>> kern_sem_wait entered! pid=%d\n", (int)td->td_proc->p_pid));
error = ksem_get(td, id, &fp);
error = ksem_get(td, id, CAP_SEM_WAIT, &fp);
if (error)
return (error);
ks = fp->f_data;
@ -804,7 +807,7 @@ ksem_getvalue(struct thread *td, struct ksem_getvalue_args *uap)
struct ksem *ks;
int error, val;
error = ksem_get(td, uap->id, &fp);
error = ksem_get(td, uap->id, CAP_SEM_GETVALUE, &fp);
if (error)
return (error);
ks = fp->f_data;
@ -838,7 +841,8 @@ ksem_destroy(struct thread *td, struct ksem_destroy_args *uap)
struct ksem *ks;
int error;
error = ksem_get(td, uap->id, &fp);
/* No capability rights required to close a semaphore. */
error = ksem_get(td, uap->id, 0, &fp);
if (error)
return (error);
ks = fp->f_data;

View File

@ -120,33 +120,47 @@ SYSCTL_INT(_kern_ipc, OID_AUTO, nsfbufsused, CTLFLAG_RD, &nsfbufsused, 0,
"Number of sendfile(2) sf_bufs in use");
/*
* Convert a user file descriptor to a kernel file entry. A reference on the
* file entry is held upon returning. This is lighter weight than
* fgetsock(), which bumps the socket reference drops the file reference
* count instead, as this approach avoids several additional mutex operations
* associated with the additional reference count. If requested, return the
* open file flags.
* Convert a user file descriptor to a kernel file entry and check that, if
* it is a capability, the right rights are present. A reference on the file
* entry is held upon returning.
*/
static int
getsock(struct filedesc *fdp, int fd, struct file **fpp, u_int *fflagp)
getsock_cap(struct filedesc *fdp, int fd, cap_rights_t rights,
struct file **fpp, u_int *fflagp)
{
struct file *fp;
#ifdef CAPABILITIES
struct file *fp_fromcap;
int error;
#endif
fp = NULL;
if (fdp == NULL || (fp = fget_unlocked(fdp, fd)) == NULL) {
error = EBADF;
} else if (fp->f_type != DTYPE_SOCKET) {
if ((fdp == NULL) || ((fp = fget_unlocked(fdp, fd)) == NULL))
return (EBADF);
#ifdef CAPABILITIES
/*
* If the file descriptor is for a capability, test rights and use
* the file descriptor referenced by the capability.
*/
error = cap_funwrap(fp, rights, &fp_fromcap);
if (error) {
fdrop(fp, curthread);
fp = NULL;
error = ENOTSOCK;
} else {
if (fflagp != NULL)
*fflagp = fp->f_flag;
error = 0;
return (error);
}
if (fp != fp_fromcap) {
fhold(fp_fromcap);
fdrop(fp, curthread);
fp = fp_fromcap;
}
#endif /* CAPABILITIES */
if (fp->f_type != DTYPE_SOCKET) {
fdrop(fp, curthread);
return (ENOTSOCK);
}
if (fflagp != NULL)
*fflagp = fp->f_flag;
*fpp = fp;
return (error);
return (0);
}
/*
@ -226,7 +240,7 @@ kern_bind(td, fd, sa)
int error;
AUDIT_ARG_FD(fd);
error = getsock(td->td_proc->p_fd, fd, &fp, NULL);
error = getsock_cap(td->td_proc->p_fd, fd, CAP_BIND, &fp, NULL);
if (error)
return (error);
so = fp->f_data;
@ -257,7 +271,7 @@ listen(td, uap)
int error;
AUDIT_ARG_FD(uap->s);
error = getsock(td->td_proc->p_fd, uap->s, &fp, NULL);
error = getsock_cap(td->td_proc->p_fd, uap->s, CAP_LISTEN, &fp, NULL);
if (error == 0) {
so = fp->f_data;
#ifdef MAC
@ -347,7 +361,7 @@ kern_accept(struct thread *td, int s, struct sockaddr **name,
AUDIT_ARG_FD(s);
fdp = td->td_proc->p_fd;
error = getsock(fdp, s, &headfp, &fflag);
error = getsock_cap(fdp, s, CAP_ACCEPT, &headfp, &fflag);
if (error)
return (error);
head = headfp->f_data;
@ -535,7 +549,7 @@ kern_connect(td, fd, sa)
int interrupted = 0;
AUDIT_ARG_FD(fd);
error = getsock(td->td_proc->p_fd, fd, &fp, NULL);
error = getsock_cap(td->td_proc->p_fd, fd, CAP_CONNECT, &fp, NULL);
if (error)
return (error);
so = fp->f_data;
@ -744,12 +758,16 @@ kern_sendit(td, s, mp, flags, control, segflg)
struct socket *so;
int i;
int len, error;
cap_rights_t rights;
#ifdef KTRACE
struct uio *ktruio = NULL;
#endif
AUDIT_ARG_FD(s);
error = getsock(td->td_proc->p_fd, s, &fp, NULL);
rights = CAP_WRITE;
if (mp->msg_name != NULL)
rights |= CAP_CONNECT;
error = getsock_cap(td->td_proc->p_fd, s, rights, &fp, NULL);
if (error)
return (error);
so = (struct socket *)fp->f_data;
@ -953,7 +971,7 @@ kern_recvit(td, s, mp, fromseg, controlp)
*controlp = NULL;
AUDIT_ARG_FD(s);
error = getsock(td->td_proc->p_fd, s, &fp, NULL);
error = getsock_cap(td->td_proc->p_fd, s, CAP_READ, &fp, NULL);
if (error)
return (error);
so = fp->f_data;
@ -1267,7 +1285,8 @@ shutdown(td, uap)
int error;
AUDIT_ARG_FD(uap->s);
error = getsock(td->td_proc->p_fd, uap->s, &fp, NULL);
error = getsock_cap(td->td_proc->p_fd, uap->s, CAP_SHUTDOWN, &fp,
NULL);
if (error == 0) {
so = fp->f_data;
error = soshutdown(so, uap->how);
@ -1330,7 +1349,7 @@ kern_setsockopt(td, s, level, name, val, valseg, valsize)
}
AUDIT_ARG_FD(s);
error = getsock(td->td_proc->p_fd, s, &fp, NULL);
error = getsock_cap(td->td_proc->p_fd, s, CAP_SETSOCKOPT, &fp, NULL);
if (error == 0) {
so = fp->f_data;
error = sosetopt(so, &sopt);
@ -1409,7 +1428,7 @@ kern_getsockopt(td, s, level, name, val, valseg, valsize)
}
AUDIT_ARG_FD(s);
error = getsock(td->td_proc->p_fd, s, &fp, NULL);
error = getsock_cap(td->td_proc->p_fd, s, CAP_GETSOCKOPT, &fp, NULL);
if (error == 0) {
so = fp->f_data;
error = sogetopt(so, &sopt);
@ -1471,7 +1490,7 @@ kern_getsockname(struct thread *td, int fd, struct sockaddr **sa,
return (EINVAL);
AUDIT_ARG_FD(fd);
error = getsock(td->td_proc->p_fd, fd, &fp, NULL);
error = getsock_cap(td->td_proc->p_fd, fd, CAP_GETSOCKNAME, &fp, NULL);
if (error)
return (error);
so = fp->f_data;
@ -1571,7 +1590,7 @@ kern_getpeername(struct thread *td, int fd, struct sockaddr **sa,
return (EINVAL);
AUDIT_ARG_FD(fd);
error = getsock(td->td_proc->p_fd, fd, &fp, NULL);
error = getsock_cap(td->td_proc->p_fd, fd, CAP_GETPEERNAME, &fp, NULL);
if (error)
return (error);
so = fp->f_data;
@ -1827,7 +1846,7 @@ kern_sendfile(struct thread *td, struct sendfile_args *uap,
* we send only the header/trailer and no payload data.
*/
AUDIT_ARG_FD(uap->fd);
if ((error = fgetvp_read(td, uap->fd, &vp)) != 0)
if ((error = fgetvp_read(td, uap->fd, CAP_READ, &vp)) != 0)
goto out;
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
vn_lock(vp, LK_SHARED | LK_RETRY);
@ -1865,8 +1884,8 @@ kern_sendfile(struct thread *td, struct sendfile_args *uap,
* The socket must be a stream socket and connected.
* Remember if it a blocking or non-blocking socket.
*/
if ((error = getsock(td->td_proc->p_fd, uap->s, &sock_fp,
NULL)) != 0)
if ((error = getsock_cap(td->td_proc->p_fd, uap->s, CAP_WRITE,
&sock_fp, NULL)) != 0)
goto out;
so = sock_fp->f_data;
if (so->so_type != SOCK_STREAM) {
@ -2298,7 +2317,7 @@ sctp_peeloff(td, uap)
fdp = td->td_proc->p_fd;
AUDIT_ARG_FD(uap->sd);
error = fgetsock(td, uap->sd, &head, &fflag);
error = fgetsock(td, uap->sd, CAP_PEELOFF, &head, &fflag);
if (error)
goto done2;
error = sctp_can_peel_off(head, (sctp_assoc_t)uap->name);
@ -2391,6 +2410,7 @@ sctp_generic_sendmsg (td, uap)
#endif
struct uio auio;
struct iovec iov[1];
cap_rights_t rights;
if (uap->sinfo) {
error = copyin(uap->sinfo, &sinfo, sizeof (sinfo));
@ -2398,16 +2418,19 @@ sctp_generic_sendmsg (td, uap)
return (error);
u_sinfo = &sinfo;
}
rights = CAP_WRITE;
if (uap->tolen) {
error = getsockaddr(&to, uap->to, uap->tolen);
if (error) {
to = NULL;
goto sctp_bad2;
}
rights |= CAP_CONNECT;
}
AUDIT_ARG_FD(uap->sd);
error = getsock(td->td_proc->p_fd, uap->sd, &fp, NULL);
error = getsock_cap(td->td_proc->p_fd, uap->sd, rights, &fp, NULL);
if (error)
goto sctp_bad;
#ifdef KTRACE
@ -2494,6 +2517,7 @@ sctp_generic_sendmsg_iov(td, uap)
#endif
struct uio auio;
struct iovec *iov, *tiov;
cap_rights_t rights;
if (uap->sinfo) {
error = copyin(uap->sinfo, &sinfo, sizeof (sinfo));
@ -2501,16 +2525,18 @@ sctp_generic_sendmsg_iov(td, uap)
return (error);
u_sinfo = &sinfo;
}
rights = CAP_WRITE;
if (uap->tolen) {
error = getsockaddr(&to, uap->to, uap->tolen);
if (error) {
to = NULL;
goto sctp_bad2;
}
rights |= CAP_CONNECT;
}
AUDIT_ARG_FD(uap->sd);
error = getsock(td->td_proc->p_fd, uap->sd, &fp, NULL);
error = getsock_cap(td->td_proc->p_fd, uap->sd, rights, &fp, NULL);
if (error)
goto sctp_bad1;
@ -2618,7 +2644,7 @@ sctp_generic_recvmsg(td, uap)
#endif
AUDIT_ARG_FD(uap->sd);
error = getsock(td->td_proc->p_fd, uap->sd, &fp, NULL);
error = getsock_cap(td->td_proc->p_fd, uap->sd, CAP_READ, &fp, NULL);
if (error) {
return (error);
}

View File

@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysproto.h>
#include <sys/capability.h>
#include <sys/fcntl.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
@ -408,7 +409,7 @@ __acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap)
struct file *fp;
int vfslocked, error;
error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
error = getvnode(td->td_proc->p_fd, uap->filedes, CAP_ACL_GET, &fp);
if (error == 0) {
vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp);
@ -427,7 +428,7 @@ __acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap)
struct file *fp;
int vfslocked, error;
error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
error = getvnode(td->td_proc->p_fd, uap->filedes, CAP_ACL_SET, &fp);
if (error == 0) {
vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp);
@ -486,7 +487,8 @@ __acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap)
struct file *fp;
int vfslocked, error;
error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
error = getvnode(td->td_proc->p_fd, uap->filedes, CAP_ACL_DELETE,
&fp);
if (error == 0) {
vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
error = vacl_delete(td, fp->f_vnode, uap->type);
@ -545,7 +547,8 @@ __acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap)
struct file *fp;
int vfslocked, error;
error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
error = getvnode(td->td_proc->p_fd, uap->filedes, CAP_ACL_CHECK,
&fp);
if (error == 0) {
vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp);

View File

@ -28,6 +28,7 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/capability.h>
#include <sys/eventhandler.h>
#include <sys/sysproto.h>
#include <sys/filedesc.h>
@ -1577,17 +1578,30 @@ aio_aqueue(struct thread *td, struct aiocb *job, struct aioliojob *lj,
aiocbe->uaiocb.aio_lio_opcode = type;
opcode = aiocbe->uaiocb.aio_lio_opcode;
/* Fetch the file object for the specified file descriptor. */
/*
* Validate the opcode and fetch the file object for the specified
* file descriptor.
*
* XXXRW: Moved the opcode validation up here so that we don't
* retrieve a file descriptor without knowing what the capabiltity
* should be.
*/
fd = aiocbe->uaiocb.aio_fildes;
switch (opcode) {
case LIO_WRITE:
error = fget_write(td, fd, &fp);
error = fget_write(td, fd, CAP_WRITE | CAP_SEEK, &fp);
break;
case LIO_READ:
error = fget_read(td, fd, &fp);
error = fget_read(td, fd, CAP_READ | CAP_SEEK, &fp);
break;
case LIO_SYNC:
error = fget(td, fd, CAP_FSYNC, &fp);
break;
case LIO_NOP:
error = fget(td, fd, 0, &fp);
break;
default:
error = fget(td, fd, &fp);
error = EINVAL;
}
if (error) {
uma_zfree(aiocb_zone, aiocbe);
@ -1623,11 +1637,6 @@ aio_aqueue(struct thread *td, struct aiocb *job, struct aioliojob *lj,
uma_zfree(aiocb_zone, aiocbe);
return (0);
}
if ((opcode != LIO_READ) && (opcode != LIO_WRITE) &&
(opcode != LIO_SYNC)) {
error = EINVAL;
goto aqueue_fail;
}
if (aiocbe->uaiocb.aio_sigevent.sigev_notify != SIGEV_KEVENT)
goto no_kqueue;
@ -1971,7 +1980,7 @@ aio_cancel(struct thread *td, struct aio_cancel_args *uap)
struct vnode *vp;
/* Lookup file object. */
error = fget(td, uap->fd, &fp);
error = fget(td, uap->fd, 0, &fp);
if (error)
return (error);

View File

@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/capability.h>
#include <sys/lock.h>
#include <sys/mount.h>
#include <sys/mutex.h>
@ -230,7 +231,7 @@ extattr_set_fd(td, uap)
return (error);
AUDIT_ARG_TEXT(attrname);
error = getvnode(td->td_proc->p_fd, uap->fd, &fp);
error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_SET, &fp);
if (error)
return (error);
@ -410,7 +411,7 @@ extattr_get_fd(td, uap)
return (error);
AUDIT_ARG_TEXT(attrname);
error = getvnode(td->td_proc->p_fd, uap->fd, &fp);
error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_GET, &fp);
if (error)
return (error);
@ -560,7 +561,8 @@ extattr_delete_fd(td, uap)
return (error);
AUDIT_ARG_TEXT(attrname);
error = getvnode(td->td_proc->p_fd, uap->fd, &fp);
error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_DELETE,
&fp);
if (error)
return (error);
@ -719,7 +721,7 @@ extattr_list_fd(td, uap)
AUDIT_ARG_FD(uap->fd);
AUDIT_ARG_VALUE(uap->attrnamespace);
error = getvnode(td->td_proc->p_fd, uap->fd, &fp);
error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_LIST, &fp);
if (error)
return (error);

View File

@ -37,12 +37,14 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_capsicum.h"
#include "opt_kdtrace.h"
#include "opt_ktrace.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/capability.h>
#include <sys/fcntl.h>
#include <sys/jail.h>
#include <sys/lock.h>
@ -212,7 +214,12 @@ namei(struct nameidata *ndp)
AUDIT_ARG_ATFD1(ndp->ni_dirfd);
if (cnp->cn_flags & AUDITVNODE2)
AUDIT_ARG_ATFD2(ndp->ni_dirfd);
error = fgetvp(td, ndp->ni_dirfd, &dp);
#ifdef CAPABILITY_MODE
KASSERT(!IN_CAPABILITY_MODE(td),
("%s: reached %s:%d in capability mode",
__func__, __FILE__, __LINE__));
#endif
error = fgetvp(td, ndp->ni_dirfd, 0, &dp);
}
if (error != 0 || dp != NULL) {
FILEDESC_SUNLOCK(fdp);

View File

@ -37,6 +37,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_capsicum.h"
#include "opt_compat.h"
#include "opt_kdtrace.h"
#include "opt_ktrace.h"
@ -45,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/capability.h>
#include <sys/disk.h>
#include <sys/sysent.h>
#include <sys/malloc.h>
@ -373,7 +375,7 @@ kern_fstatfs(struct thread *td, int fd, struct statfs *buf)
int error;
AUDIT_ARG_FD(fd);
error = getvnode(td->td_proc->p_fd, fd, &fp);
error = getvnode(td->td_proc->p_fd, fd, CAP_FSTATFS, &fp);
if (error)
return (error);
vp = fp->f_vnode;
@ -746,7 +748,7 @@ fchdir(td, uap)
int error;
AUDIT_ARG_FD(uap->fd);
if ((error = getvnode(fdp, uap->fd, &fp)) != 0)
if ((error = getvnode(fdp, uap->fd, CAP_FCHDIR, &fp)) != 0)
return (error);
vp = fp->f_vnode;
VREF(vp);
@ -1049,7 +1051,7 @@ kern_openat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
struct vnode *vp;
int cmode;
struct file *nfp;
int type, indx, error;
int type, indx = -1, error;
struct flock lf;
struct nameidata nd;
int vfslocked;
@ -1069,10 +1071,13 @@ kern_openat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
else
flags = FFLAGS(flags);
error = falloc(td, &nfp, &indx, flags);
/*
* allocate the file descriptor, but don't install a descriptor yet
*/
error = falloc_noinstall(td, &nfp);
if (error)
return (error);
/* An extra reference on `nfp' has been held for us by falloc(). */
/* An extra reference on `nfp' has been held for us by falloc_noinstall(). */
fp = nfp;
/* Set the flags early so the finit in devfs can pick them up. */
fp->f_flag = flags & FMASK;
@ -1099,12 +1104,13 @@ kern_openat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
* if it succeeds.
*/
if ((error == ENODEV || error == ENXIO) &&
td->td_dupfd >= 0 && /* XXX from fdopen */
(error =
dupfdopen(td, fdp, indx, td->td_dupfd, flags, error)) == 0) {
td->td_retval[0] = indx;
fdrop(fp, td);
return (0);
(td->td_dupfd >= 0)) {
/* XXX from fdopen */
if ((error = finstall(td, fp, &indx, flags)) != 0)
goto bad_unlocked;
if ((error = dupfdopen(td, fdp, indx, td->td_dupfd,
flags, error)) == 0)
goto success;
}
/*
* Clean up the descriptor, but only if another thread hadn't
@ -1161,6 +1167,14 @@ kern_openat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
goto bad;
}
VFS_UNLOCK_GIANT(vfslocked);
success:
/*
* If we haven't already installed the FD (for dupfdopen), do so now.
*/
if (indx == -1)
if ((error = finstall(td, fp, &indx, flags)) != 0)
goto bad_unlocked;
/*
* Release our private reference, leaving the one associated with
* the descriptor table intact.
@ -1170,8 +1184,10 @@ kern_openat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
return (0);
bad:
VFS_UNLOCK_GIANT(vfslocked);
bad_unlocked:
fdclose(fdp, fp, indx, td);
fdrop(fp, td);
td->td_retval[0] = -1;
return (error);
}
@ -1918,7 +1934,7 @@ lseek(td, uap)
int vfslocked;
AUDIT_ARG_FD(uap->fd);
if ((error = fget(td, uap->fd, &fp)) != 0)
if ((error = fget(td, uap->fd, CAP_SEEK, &fp)) != 0)
return (error);
if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE)) {
fdrop(fp, td);
@ -2775,7 +2791,8 @@ fchflags(td, uap)
AUDIT_ARG_FD(uap->fd);
AUDIT_ARG_FFLAGS(uap->flags);
if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_FCHFLAGS,
&fp)) != 0)
return (error);
vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
#ifdef AUDIT
@ -2936,7 +2953,8 @@ fchmod(td, uap)
AUDIT_ARG_FD(uap->fd);
AUDIT_ARG_MODE(uap->mode);
if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_FCHMOD,
&fp)) != 0)
return (error);
vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
#ifdef AUDIT
@ -3113,7 +3131,8 @@ fchown(td, uap)
AUDIT_ARG_FD(uap->fd);
AUDIT_ARG_OWNER(uap->uid, uap->gid);
if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_FCHOWN, &fp))
!= 0)
return (error);
vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
#ifdef AUDIT
@ -3348,7 +3367,8 @@ kern_futimes(struct thread *td, int fd, struct timeval *tptr,
AUDIT_ARG_FD(fd);
if ((error = getutimes(tptr, tptrseg, ts)) != 0)
return (error);
if ((error = getvnode(td->td_proc->p_fd, fd, &fp)) != 0)
if ((error = getvnode(td->td_proc->p_fd, fd, CAP_FUTIMES, &fp))
!= 0)
return (error);
vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
#ifdef AUDIT
@ -3500,7 +3520,8 @@ fsync(td, uap)
int error, lock_flags;
AUDIT_ARG_FD(uap->fd);
if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_FSYNC,
&fp)) != 0)
return (error);
vp = fp->f_vnode;
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
@ -3925,7 +3946,8 @@ kern_ogetdirentries(struct thread *td, struct ogetdirentries_args *uap,
/* XXX arbitrary sanity limit on `count'. */
if (uap->count > 64 * 1024)
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,
&fp)) != 0)
return (error);
if ((fp->f_flag & FREAD) == 0) {
fdrop(fp, td);
@ -4085,7 +4107,8 @@ kern_getdirentries(struct thread *td, int fd, char *buf, u_int count,
AUDIT_ARG_FD(fd);
if (count > INT_MAX)
return (EINVAL);
if ((error = getvnode(td->td_proc->p_fd, fd, &fp)) != 0)
if ((error = getvnode(td->td_proc->p_fd, fd, CAP_READ | CAP_SEEK,
&fp)) != 0)
return (error);
if ((fp->f_flag & FREAD) == 0) {
fdrop(fp, td);
@ -4248,30 +4271,49 @@ revoke(td, uap)
}
/*
* Convert a user file descriptor to a kernel file entry.
* A reference on the file entry is held upon returning.
* Convert a user file descriptor to a kernel file entry and check that, if it
* is a capability, the correct rights are present. A reference on the file
* entry is held upon returning.
*/
int
getvnode(fdp, fd, fpp)
struct filedesc *fdp;
int fd;
struct file **fpp;
getvnode(struct filedesc *fdp, int fd, cap_rights_t rights,
struct file **fpp)
{
int error;
struct file *fp;
#ifdef CAPABILITIES
struct file *fp_fromcap;
#endif
int error;
error = 0;
fp = NULL;
if (fdp == NULL || (fp = fget_unlocked(fdp, fd)) == NULL)
error = EBADF;
else if (fp->f_vnode == NULL) {
error = EINVAL;
if ((fdp == NULL) || (fp = fget_unlocked(fdp, fd)) == NULL)
return (EBADF);
#ifdef CAPABILITIES
/*
* If the file descriptor is for a capability, test rights and use the
* file descriptor referenced by the capability.
*/
error = cap_funwrap(fp, rights, &fp_fromcap);
if (error) {
fdrop(fp, curthread);
return (error);
}
if (fp != fp_fromcap) {
fhold(fp_fromcap);
fdrop(fp, curthread);
fp = fp_fromcap;
}
#endif /* CAPABILITIES */
if (fp->f_vnode == NULL) {
fdrop(fp, curthread);
return (EINVAL);
}
*fpp = fp;
return (error);
return (0);
}
/*
* Get an (NFS) file handle.
*/
@ -4683,7 +4725,7 @@ kern_posix_fallocate(struct thread *td, int fd, off_t offset, off_t len)
fp = NULL;
vfslocked = 0;
error = fget(td, fd, &fp);
error = fget(td, fd, CAP_WRITE, &fp);
if (error != 0)
goto out;

View File

@ -694,7 +694,7 @@ ng_internalize(struct mbuf *control, struct thread *td)
/* Check that the FD given is legit. and change it to a pointer to a
* struct file. */
fd = CMSG_DATA(cm);
if ((error = fget(td, fd, &fp)) != 0)
if ((error = fget(td, fd, 0, &fp)) != 0)
return (error);
/* Depending on what kind of resource it is, act differently. For

View File

@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include "opt_kgssapi.h"
#include <sys/param.h>
#include <sys/capability.h>
#include <sys/systm.h>
#include <sys/sysproto.h>
#include <sys/kernel.h>
@ -173,7 +174,7 @@ nfssvc_nfsserver(struct thread *td, struct nfssvc_args *uap)
sizeof(addsockarg));
if (error)
return (error);
if ((error = fget(td, addsockarg.sock, &fp)) != 0)
if ((error = fget(td, addsockarg.sock, CAP_SOCK_ALL, &fp)) != 0)
return (error);
if (fp->f_type != DTYPE_SOCKET) {
fdrop(fp, td);

View File

@ -899,7 +899,7 @@ audit_sysclose(struct thread *td, int fd)
audit_arg_fd(fd);
if (getvnode(td->td_proc->p_fd, fd, &fp) != 0)
if (getvnode(td->td_proc->p_fd, fd, 0, &fp) != 0)
return;
vp = fp->f_vnode;

View File

@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include "opt_mac.h"
#include <sys/param.h>
#include <sys/capability.h>
#include <sys/fcntl.h>
#include <sys/kernel.h>
#include <sys/lock.h>
@ -247,7 +248,7 @@ __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
}
buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
error = fget(td, uap->fd, &fp);
error = fget(td, uap->fd, CAP_MAC_GET, &fp);
if (error)
goto out;
@ -442,7 +443,7 @@ __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
return (error);
}
error = fget(td, uap->fd, &fp);
error = fget(td, uap->fd, CAP_MAC_SET, &fp);
if (error)
goto out;

View File

@ -115,9 +115,9 @@
#define CAP_SEM_POST 0x0000010000000000ULL
#define CAP_SEM_WAIT 0x0000020000000000ULL
/* Events - maybe we need a post/get distinction? */
#define CAP_EVENT 0x0000040000000000ULL
#define CAP_KEVENT 0x0000080000000000ULL
/* kqueue events. */
#define CAP_POLL_KEVENT 0x0000040000000000ULL
#define CAP_POST_KEVENT 0x0000080000000000ULL
/* Strange and powerful rights that should not be given lightly. */
#define CAP_IOCTL 0x0000100000000000ULL

View File

@ -176,9 +176,13 @@ extern int maxfiles; /* kernel limit on number of open files */
extern int maxfilesperproc; /* per process limit on number of open files */
extern volatile int openfiles; /* actual number of open files */
int fget(struct thread *td, int fd, struct file **fpp);
int fget_read(struct thread *td, int fd, struct file **fpp);
int fget_write(struct thread *td, int fd, struct file **fpp);
int fget(struct thread *td, int fd, cap_rights_t rights, struct file **fpp);
int fget_mmap(struct thread *td, int fd, cap_rights_t rights,
u_char *maxprotp, struct file **fpp);
int fget_read(struct thread *td, int fd, cap_rights_t rights,
struct file **fpp);
int fget_write(struct thread *td, int fd, cap_rights_t rights,
struct file **fpp);
int fgetcap(struct thread *td, int fd, struct file **fpp);
int _fdrop(struct file *fp, struct thread *td);
@ -197,11 +201,16 @@ fo_stat_t soo_stat;
fo_close_t soo_close;
void finit(struct file *, u_int, short, void *, struct fileops *);
int fgetvp(struct thread *td, int fd, struct vnode **vpp);
int fgetvp_read(struct thread *td, int fd, struct vnode **vpp);
int fgetvp_write(struct thread *td, int fd, struct vnode **vpp);
int fgetvp(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp);
int fgetvp_rights(struct thread *td, int fd, cap_rights_t need,
cap_rights_t *have, struct vnode **vpp);
int fgetvp_read(struct thread *td, int fd, cap_rights_t rights,
struct vnode **vpp);
int fgetvp_write(struct thread *td, int fd, cap_rights_t rights,
struct vnode **vpp);
int fgetsock(struct thread *td, int fd, struct socket **spp, u_int *fflagp);
int fgetsock(struct thread *td, int fd, cap_rights_t rights,
struct socket **spp, u_int *fflagp);
void fputsock(struct socket *sp);
static __inline int

View File

@ -128,7 +128,8 @@ struct filedesc *fdshare(struct filedesc *fdp);
struct filedesc_to_leader *
filedesc_to_leader_alloc(struct filedesc_to_leader *old,
struct filedesc *fdp, struct proc *leader);
int getvnode(struct filedesc *fdp, int fd, struct file **fpp);
int getvnode(struct filedesc *fdp, int fd, cap_rights_t rights,
struct file **fpp);
void mountcheckdirs(struct vnode *olddp, struct vnode *newdp);
void setugidsafety(struct thread *td);

View File

@ -62,9 +62,11 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_capsicum.h"
#include "opt_quota.h"
#include <sys/param.h>
#include <sys/capability.h>
#include <sys/systm.h>
#include <sys/bio.h>
#include <sys/buf.h>
@ -2477,7 +2479,8 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS)
return (error);
if (cmd.version != FFS_CMD_VERSION)
return (ERPCMISMATCH);
if ((error = getvnode(td->td_proc->p_fd, cmd.handle, &fp)) != 0)
if ((error = getvnode(td->td_proc->p_fd, cmd.handle, CAP_FSCK,
&fp)) != 0)
return (error);
vp = fp->f_data;
if (vp->v_type != VREG && vp->v_type != VDIR) {
@ -2798,7 +2801,8 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS)
(intmax_t)cmd.value);
}
#endif /* DEBUG */
if ((error = getvnode(td->td_proc->p_fd, cmd.value, &vfp)) != 0)
if ((error = getvnode(td->td_proc->p_fd, cmd.value,
CAP_FSCK, &vfp)) != 0)
break;
if (vfp->f_vnode->v_type != VCHR) {
fdrop(vfp, td);

View File

@ -48,6 +48,8 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/capability.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/sysproto.h>
@ -189,12 +191,13 @@ mmap(td, uap)
struct vnode *vp;
vm_offset_t addr;
vm_size_t size, pageoff;
vm_prot_t prot, maxprot;
vm_prot_t cap_maxprot, prot, maxprot;
void *handle;
objtype_t handle_type;
int flags, error;
off_t pos;
struct vmspace *vms = td->td_proc->p_vmspace;
cap_rights_t rights;
addr = (vm_offset_t) uap->addr;
size = uap->len;
@ -274,12 +277,25 @@ mmap(td, uap)
handle = NULL;
handle_type = OBJT_DEFAULT;
maxprot = VM_PROT_ALL;
cap_maxprot = VM_PROT_ALL;
} else {
/*
* Mapping file, get fp for validation and
* don't let the descriptor disappear on us if we block.
* Mapping file, get fp for validation and don't let the
* descriptor disappear on us if we block. Check capability
* rights, but also return the maximum rights to be combined
* with maxprot later.
*/
if ((error = fget(td, uap->fd, &fp)) != 0)
rights = CAP_MMAP;
if (prot & PROT_READ)
rights |= CAP_READ;
if ((flags & MAP_SHARED) != 0) {
if (prot & PROT_WRITE)
rights |= CAP_WRITE;
}
if (prot & PROT_EXEC)
rights |= CAP_MAPEXEC;
if ((error = fget_mmap(td, uap->fd, rights, &cap_maxprot,
&fp)) != 0)
goto done;
if (fp->f_type == DTYPE_SHM) {
handle = fp->f_data;
@ -346,12 +362,14 @@ mmap(td, uap)
}
} else if (vp->v_type != VCHR || (fp->f_flag & FWRITE) != 0) {
maxprot |= VM_PROT_WRITE;
cap_maxprot |= VM_PROT_WRITE;
}
handle = (void *)vp;
handle_type = OBJT_VNODE;
}
map:
td->td_fpop = fp;
maxprot &= cap_maxprot;
error = vm_mmap(&vms->vm_map, &addr, size, prot, maxprot,
flags, handle_type, handle, pos);
td->td_fpop = NULL;

View File

@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$");
#include <sys/wait.h>
#include <err.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -60,7 +61,7 @@ main(int argc, char *argv[])
* If no tests have been specified at the command line, run them all.
*/
if (argc == 1) {
printf("1..%ld\n", test_count);
printf("1..%ju\n", (uintmax_t)test_count);
for (size_t i = 0; i < test_count; i++)
execute(i + 1, all_tests + i);

View File

@ -237,8 +237,8 @@ test_capabilities(void)
TRY(fd, CAP_MMAP | CAP_MAPEXEC | CAP_WRITE);
TRY(fd, CAP_MMAP | CAP_READ | CAP_WRITE | CAP_MAPEXEC);
TRY(fd, CAP_FCNTL);
TRY(fd, CAP_EVENT);
TRY(fd, CAP_KEVENT);
TRY(fd, CAP_POST_KEVENT);
TRY(fd, CAP_POLL_KEVENT);
TRY(fd, CAP_FSYNC);
TRY(fd, CAP_FCHOWN);
TRY(fd, CAP_FCHMOD);