summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2013-09-05 00:09:56 +0000
committerpjd <pjd@FreeBSD.org>2013-09-05 00:09:56 +0000
commit029a6f5d92dc57925b5f155d94d6e01fdab7a45d (patch)
treeecf189da5929e9d96594e07f21c25b003ec96d1d /sys
parentceb5fa1b16f231bab58c8a447b3c122dd1c5bf6c (diff)
downloadFreeBSD-src-029a6f5d92dc57925b5f155d94d6e01fdab7a45d.zip
FreeBSD-src-029a6f5d92dc57925b5f155d94d6e01fdab7a45d.tar.gz
Change the cap_rights_t type from uint64_t to a structure that we can extend
in the future in a backward compatible (API and ABI) way. The cap_rights_t represents capability rights. We used to use one bit to represent one right, but we are running out of spare bits. Currently the new structure provides place for 114 rights (so 50 more than the previous cap_rights_t), but it is possible to grow the structure to hold at least 285 rights, although we can make it even larger if 285 rights won't be enough. The structure definition looks like this: struct cap_rights { uint64_t cr_rights[CAP_RIGHTS_VERSION + 2]; }; The initial CAP_RIGHTS_VERSION is 0. The top two bits in the first element of the cr_rights[] array contain total number of elements in the array - 2. This means if those two bits are equal to 0, we have 2 array elements. The top two bits in all remaining array elements should be 0. The next five bits in all array elements contain array index. Only one bit is used and bit position in this five-bits range defines array index. This means there can be at most five array elements in the future. To define new right the CAPRIGHT() macro must be used. The macro takes two arguments - an array index and a bit to set, eg. #define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL) We still support aliases that combine few rights, but the rights have to belong to the same array element, eg: #define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL) #define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL) #define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP) There is new API to manage the new cap_rights_t structure: cap_rights_t *cap_rights_init(cap_rights_t *rights, ...); void cap_rights_set(cap_rights_t *rights, ...); void cap_rights_clear(cap_rights_t *rights, ...); bool cap_rights_is_set(const cap_rights_t *rights, ...); bool cap_rights_is_valid(const cap_rights_t *rights); void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src); void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src); bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little); Capability rights to the cap_rights_init(), cap_rights_set(), cap_rights_clear() and cap_rights_is_set() functions are provided by separating them with commas, eg: cap_rights_t rights; cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_FSTAT); There is no need to terminate the list of rights, as those functions are actually macros that take care of the termination, eg: #define cap_rights_set(rights, ...) \ __cap_rights_set((rights), __VA_ARGS__, 0ULL) void __cap_rights_set(cap_rights_t *rights, ...); Thanks to using one bit as an array index we can assert in those functions that there are no two rights belonging to different array elements provided together. For example this is illegal and will be detected, because CAP_LOOKUP belongs to element 0 and CAP_PDKILL to element 1: cap_rights_init(&rights, CAP_LOOKUP | CAP_PDKILL); Providing several rights that belongs to the same array's element this way is correct, but is not advised. It should only be used for aliases definition. This commit also breaks compatibility with some existing Capsicum system calls, but I see no other way to do that. This should be fine as Capsicum is still experimental and this change is not going to 9.x. Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'sys')
-rw-r--r--sys/amd64/linux32/linux32_machdep.c5
-rw-r--r--sys/bsm/audit_kevents.h1
-rw-r--r--sys/bsm/audit_record.h4
-rw-r--r--sys/cddl/compat/opensolaris/sys/file.h4
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c15
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_onexit.c3
-rw-r--r--sys/compat/freebsd32/freebsd32_capability.c20
-rw-r--r--sys/compat/freebsd32/freebsd32_ioctl.c4
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.c5
-rw-r--r--sys/compat/freebsd32/syscalls.master16
-rw-r--r--sys/compat/linux/linux_file.c17
-rw-r--r--sys/compat/linux/linux_ioctl.c82
-rw-r--r--sys/compat/linux/linux_socket.c4
-rw-r--r--sys/compat/svr4/svr4_fcntl.c16
-rw-r--r--sys/compat/svr4/svr4_filio.c3
-rw-r--r--sys/compat/svr4/svr4_ioctl.c4
-rw-r--r--sys/compat/svr4/svr4_misc.c10
-rw-r--r--sys/compat/svr4/svr4_stream.c12
-rw-r--r--sys/conf/files1
-rw-r--r--sys/dev/aac/aac_linux.c4
-rw-r--r--sys/dev/amr/amr_linux.c4
-rw-r--r--sys/dev/filemon/filemon.c16
-rw-r--r--sys/dev/hwpmc/hwpmc_logging.c4
-rw-r--r--sys/dev/ipmi/ipmi_linux.c4
-rw-r--r--sys/dev/iscsi_initiator/iscsi.c7
-rw-r--r--sys/dev/mfi/mfi_linux.c4
-rw-r--r--sys/dev/tdfx/tdfx_linux.c4
-rw-r--r--sys/fs/fdescfs/fdesc_vnops.c4
-rw-r--r--sys/fs/fuse/fuse_vfsops.c3
-rw-r--r--sys/fs/nfsclient/nfs_clport.c9
-rw-r--r--sys/fs/nfsserver/nfs_nfsdport.c5
-rw-r--r--sys/i386/ibcs2/ibcs2_fcntl.c4
-rw-r--r--sys/i386/ibcs2/ibcs2_ioctl.c4
-rw-r--r--sys/i386/ibcs2/ibcs2_misc.c11
-rw-r--r--sys/i386/linux/linux_machdep.c5
-rw-r--r--sys/kern/capabilities.conf3
-rw-r--r--sys/kern/kern_descrip.c137
-rw-r--r--sys/kern/kern_event.c12
-rw-r--r--sys/kern/kern_exec.c4
-rw-r--r--sys/kern/kern_ktrace.c8
-rw-r--r--sys/kern/kern_sig.c4
-rw-r--r--sys/kern/subr_capability.c285
-rw-r--r--sys/kern/sys_capability.c170
-rw-r--r--sys/kern/sys_generic.c32
-rw-r--r--sys/kern/sys_procdesc.c12
-rw-r--r--sys/kern/syscalls.master8
-rw-r--r--sys/kern/tty.c4
-rw-r--r--sys/kern/uipc_mqueue.c25
-rw-r--r--sys/kern/uipc_sem.c18
-rw-r--r--sys/kern/uipc_syscalls.c82
-rw-r--r--sys/kern/uipc_usrreq.c8
-rw-r--r--sys/kern/vfs_acl.c18
-rw-r--r--sys/kern/vfs_aio.c11
-rw-r--r--sys/kern/vfs_extattr.c17
-rw-r--r--sys/kern/vfs_lookup.c33
-rw-r--r--sys/kern/vfs_syscalls.c140
-rw-r--r--sys/netsmb/smb_dev.c3
-rw-r--r--sys/nfsserver/nfs_srvkrpc.c4
-rw-r--r--sys/security/audit/audit.h2
-rw-r--r--sys/security/audit/audit_arg.c4
-rw-r--r--sys/security/audit/audit_bsm.c3
-rw-r--r--sys/security/audit/audit_private.h1
-rw-r--r--sys/security/audit/bsm_token.c16
-rw-r--r--sys/security/mac/mac_syscalls.c6
-rw-r--r--sys/sys/_types.h1
-rw-r--r--sys/sys/capability.h247
-rw-r--r--sys/sys/caprights.h61
-rw-r--r--sys/sys/file.h21
-rw-r--r--sys/sys/filedesc.h9
-rw-r--r--sys/sys/ktrace.h7
-rw-r--r--sys/sys/namei.h29
-rw-r--r--sys/sys/procdesc.h4
-rw-r--r--sys/sys/types.h9
-rw-r--r--sys/sys/user.h4
-rw-r--r--sys/ufs/ffs/ffs_alloc.c7
-rw-r--r--sys/vm/vm_mmap.c12
76 files changed, 1228 insertions, 571 deletions
diff --git a/sys/amd64/linux32/linux32_machdep.c b/sys/amd64/linux32/linux32_machdep.c
index 65f034a..3dd8f7a 100644
--- a/sys/amd64/linux32/linux32_machdep.c
+++ b/sys/amd64/linux32/linux32_machdep.c
@@ -519,6 +519,7 @@ linux_mmap_common(struct thread *td, l_uintptr_t addr, l_size_t len, l_int prot,
} */ bsd_args;
int error;
struct file *fp;
+ cap_rights_t rights;
error = 0;
bsd_args.flags = 0;
@@ -567,7 +568,9 @@ 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, CAP_MMAP, &fp)) != 0)
+ error = fget(td, bsd_args.fd,
+ cap_rights_init(&rights, CAP_MMAP), &fp);
+ if (error != 0)
return (error);
if (fp->f_type != DTYPE_VNODE) {
fdrop(fp, td);
diff --git a/sys/bsm/audit_kevents.h b/sys/bsm/audit_kevents.h
index da2bc7c..303d37f 100644
--- a/sys/bsm/audit_kevents.h
+++ b/sys/bsm/audit_kevents.h
@@ -589,6 +589,7 @@
#define AUE_POSIX_OPENPT 43185 /* FreeBSD. */
#define AUE_CAP_NEW 43186 /* TrustedBSD. */
#define AUE_CAP_RIGHTS_GET 43187 /* TrustedBSD. */
+#define AUE_CAP_GETRIGHTS AUE_CAP_RIGHTS_GET
#define AUE_CAP_ENTER 43188 /* TrustedBSD. */
#define AUE_CAP_GETMODE 43189 /* TrustedBSD. */
#define AUE_POSIX_SPAWN 43190 /* Darwin. */
diff --git a/sys/bsm/audit_record.h b/sys/bsm/audit_record.h
index 706c6f3..7e6074f 100644
--- a/sys/bsm/audit_record.h
+++ b/sys/bsm/audit_record.h
@@ -34,6 +34,7 @@
#define _BSM_AUDIT_RECORD_H_
#include <sys/time.h> /* struct timeval */
+#include <sys/caprights.h> /* cap_rights_t */
/*
* Token type identifiers.
@@ -126,6 +127,8 @@
#define AUT_SOCKINET128 0x81 /* XXX */
#define AUT_SOCKUNIX 0x82 /* XXX */
+#define AUT_RIGHTS 0x83
+
/* print values for the arbitrary token */
#define AUP_BINARY 0
#define AUP_OCTAL 1
@@ -248,6 +251,7 @@ token_t *au_to_process32_ex(au_id_t auid, uid_t euid, gid_t egid,
au_tid_addr_t *tid);
token_t *au_to_process64_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid,
gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid);
+token_t *au_to_rights(cap_rights_t *rightsp);
token_t *au_to_return(char status, uint32_t ret);
token_t *au_to_return32(char status, uint32_t ret);
token_t *au_to_return64(char status, uint64_t ret);
diff --git a/sys/cddl/compat/opensolaris/sys/file.h b/sys/cddl/compat/opensolaris/sys/file.h
index 0b8f875..a1c1d45 100644
--- a/sys/cddl/compat/opensolaris/sys/file.h
+++ b/sys/cddl/compat/opensolaris/sys/file.h
@@ -39,11 +39,11 @@ typedef struct file file_t;
#include <sys/capability.h>
static __inline file_t *
-getf(int fd, cap_rights_t rights)
+getf(int fd, cap_rights_t *rightsp)
{
struct file *fp;
- if (fget(curthread, fd, rights, &fp) == 0)
+ if (fget(curthread, fd, rightsp, &fp) == 0)
return (fp);
return (NULL);
}
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
index 10456f8..e9fba26 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
@@ -4005,6 +4005,7 @@ zfs_ioc_recv(zfs_cmd_t *zc)
char *origin = NULL;
char *tosnap;
char tofs[ZFS_MAXNAMELEN];
+ cap_rights_t rights;
boolean_t first_recvd_props = B_FALSE;
if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
@@ -4022,7 +4023,7 @@ zfs_ioc_recv(zfs_cmd_t *zc)
return (error);
fd = zc->zc_cookie;
- fp = getf(fd, CAP_PREAD);
+ fp = getf(fd, cap_rights_init(&rights, CAP_PREAD));
if (fp == NULL) {
nvlist_free(props);
return (SET_ERROR(EBADF));
@@ -4260,7 +4261,11 @@ zfs_ioc_send(zfs_cmd_t *zc)
dsl_dataset_rele(tosnap, FTAG);
dsl_pool_rele(dp, FTAG);
} else {
- file_t *fp = getf(zc->zc_cookie, CAP_WRITE);
+ file_t *fp;
+ cap_rights_t rights;
+
+ fp = getf(zc->zc_cookie,
+ cap_rights_init(&rights, CAP_WRITE));
if (fp == NULL)
return (SET_ERROR(EBADF));
@@ -4851,10 +4856,11 @@ static int
zfs_ioc_diff(zfs_cmd_t *zc)
{
file_t *fp;
+ cap_rights_t rights;
offset_t off;
int error;
- fp = getf(zc->zc_cookie, CAP_WRITE);
+ fp = getf(zc->zc_cookie, cap_rights_init(&rights, CAP_WRITE));
if (fp == NULL)
return (SET_ERROR(EBADF));
@@ -5214,6 +5220,7 @@ zfs_ioc_unjail(zfs_cmd_t *zc)
static int
zfs_ioc_send_new(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
{
+ cap_rights_t rights;
int error;
offset_t off;
char *fromname = NULL;
@@ -5225,7 +5232,7 @@ zfs_ioc_send_new(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
(void) nvlist_lookup_string(innvl, "fromsnap", &fromname);
- file_t *fp = getf(fd, CAP_READ);
+ file_t *fp = getf(fd, cap_rights_init(&rights, CAP_READ));
if (fp == NULL)
return (SET_ERROR(EBADF));
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_onexit.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_onexit.c
index 05252cb..6a90b9c 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_onexit.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_onexit.c
@@ -122,10 +122,11 @@ zfs_onexit_fd_hold(int fd, minor_t *minorp)
{
file_t *fp, *tmpfp;
zfs_onexit_t *zo;
+ cap_rights_t rights;
void *data;
int error;
- fp = getf(fd, CAP_NONE);
+ fp = getf(fd, cap_rights_init(&rights));
if (fp == NULL)
return (SET_ERROR(EBADF));
diff --git a/sys/compat/freebsd32/freebsd32_capability.c b/sys/compat/freebsd32/freebsd32_capability.c
index e17c394..b23cf95 100644
--- a/sys/compat/freebsd32/freebsd32_capability.c
+++ b/sys/compat/freebsd32/freebsd32_capability.c
@@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$");
#include <security/audit/audit.h>
-#include <compat/freebsd32/freebsd32_misc.h>
#include <compat/freebsd32/freebsd32_proto.h>
#ifdef CAPABILITIES
@@ -50,17 +49,6 @@ __FBSDID("$FreeBSD$");
MALLOC_DECLARE(M_FILECAPS);
int
-freebsd32_cap_rights_limit(struct thread *td,
- struct freebsd32_cap_rights_limit_args *uap)
-{
- struct cap_rights_limit_args ap;
-
- ap.fd = uap->fd;
- ap.rights = PAIR32TO64(uint64_t, uap->rights);
- return (sys_cap_rights_limit(td, &ap));
-}
-
-int
freebsd32_cap_ioctls_limit(struct thread *td,
struct freebsd32_cap_ioctls_limit_args *uap)
{
@@ -148,14 +136,6 @@ out:
#else /* !CAPABILITIES */
int
-freebsd32_cap_rights_limit(struct thread *td,
- struct freebsd32_cap_rights_limit_args *uap)
-{
-
- return (ENOSYS);
-}
-
-int
freebsd32_cap_ioctls_limit(struct thread *td,
struct freebsd32_cap_ioctls_limit_args *uap)
{
diff --git a/sys/compat/freebsd32/freebsd32_ioctl.c b/sys/compat/freebsd32/freebsd32_ioctl.c
index 81f5c8e..1f90e58 100644
--- a/sys/compat/freebsd32/freebsd32_ioctl.c
+++ b/sys/compat/freebsd32/freebsd32_ioctl.c
@@ -353,9 +353,11 @@ freebsd32_ioctl(struct thread *td, struct freebsd32_ioctl_args *uap)
caddr_t data;
}*/ ;
struct file *fp;
+ cap_rights_t rights;
int error;
- if ((error = fget(td, uap->fd, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, uap->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
fdrop(fp, td);
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index 16d1205..a3cf5cf 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -1650,6 +1650,7 @@ freebsd32_do_sendfile(struct thread *td,
struct uio *hdr_uio, *trl_uio;
struct iovec32 *iov32;
struct file *fp;
+ cap_rights_t rights;
off_t offset;
int error;
@@ -1686,8 +1687,10 @@ freebsd32_do_sendfile(struct thread *td,
AUDIT_ARG_FD(uap->fd);
- if ((error = fget_read(td, uap->fd, CAP_PREAD, &fp)) != 0)
+ if ((error = fget_read(td, uap->fd,
+ cap_rights_init(&rights, CAP_PREAD), &fp)) != 0) {
goto out;
+ }
error = fo_sendfile(fp, uap->s, hdr_uio, trl_uio, offset,
uap->nbytes, uap->sbytes, uap->flags, compat ? SFK_COMPAT : 0, td);
diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master
index a2e3e78..f537a54 100644
--- a/sys/compat/freebsd32/syscalls.master
+++ b/sys/compat/freebsd32/syscalls.master
@@ -970,9 +970,9 @@
512 AUE_SHMCTL NOSTD { int freebsd32_shmctl(int shmid, int cmd, \
struct shmid_ds32 *buf); }
513 AUE_LPATHCONF NOPROTO { int lpathconf(char *path, int name); }
-514 AUE_CAP_NEW NOPROTO { int cap_new(int fd, uint64_t rights); }
-515 AUE_CAP_RIGHTS_GET NOPROTO { int cap_rights_get(int fd, \
- uint64_t *rightsp); }
+514 AUE_NULL OBSOL cap_new
+515 AUE_CAP_RIGHTS_GET NOPROTO { int __cap_rights_get(int version, \
+ int fd, cap_rights_t *rightsp); }
516 AUE_CAP_ENTER NOPROTO { int cap_enter(void); }
517 AUE_CAP_GETMODE NOPROTO { int cap_getmode(u_int *modep); }
518 AUE_PDFORK NOPROTO { int pdfork(int *fdp, int flags); }
@@ -1016,10 +1016,6 @@
int *status, int options, \
struct wrusage32 *wrusage, \
siginfo_t *info); }
-533 AUE_CAP_RIGHTS_LIMIT STD { \
- int freebsd32_cap_rights_limit(int fd, \
- int pad, \
- uint32_t rights1, uint32_t rights2); }
#else
530 AUE_NULL STD { int freebsd32_posix_fallocate(int fd,\
uint32_t offset1, uint32_t offset2,\
@@ -1033,10 +1029,10 @@
int *status, int options, \
struct wrusage32 *wrusage, \
siginfo_t *info); }
-533 AUE_CAP_RIGHTS_LIMIT STD { \
- int freebsd32_cap_rights_limit(int fd, \
- uint32_t rights1, uint32_t rights2); }
#endif
+533 AUE_CAP_RIGHTS_LIMIT NOPROTO { \
+ int cap_rights_limit(int fd, \
+ cap_rights_t *rightsp); }
534 AUE_CAP_IOCTLS_LIMIT STD { \
int freebsd32_cap_ioctls_limit(int fd, \
const uint32_t *cmds, size_t ncmds); }
diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c
index 49c3fdf..a6b1d35 100644
--- a/sys/compat/linux/linux_file.c
+++ b/sys/compat/linux/linux_file.c
@@ -92,6 +92,7 @@ linux_creat(struct thread *td, struct linux_creat_args *args)
static int
linux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode)
{
+ cap_rights_t rights;
struct proc *p = td->td_proc;
struct file *fp;
int fd;
@@ -143,7 +144,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, CAP_IOCTL, &fp);
+ error = fget(td, fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
if (!error) {
sx_slock(&proctree_lock);
PROC_LOCK(p);
@@ -328,6 +329,7 @@ getdents_common(struct thread *td, struct linux_getdents64_args *args,
caddr_t outp; /* Linux-format */
int resid, linuxreclen=0; /* Linux-format */
caddr_t lbuf; /* Linux-format */
+ cap_rights_t rights;
struct file *fp;
struct uio auio;
struct iovec aiov;
@@ -348,7 +350,9 @@ getdents_common(struct thread *td, struct linux_getdents64_args *args,
} else
justone = 0;
- if ((error = getvnode(td->td_proc->p_fd, args->fd, CAP_READ, &fp)) != 0)
+ error = getvnode(td->td_proc->p_fd, args->fd,
+ cap_rights_init(&rights, CAP_READ), &fp);
+ if (error != 0)
return (error);
if ((fp->f_flag & FREAD) == 0) {
@@ -1024,6 +1028,7 @@ linux_pread(td, uap)
struct linux_pread_args *uap;
{
struct pread_args bsd;
+ cap_rights_t rights;
struct vnode *vp;
int error;
@@ -1036,7 +1041,9 @@ linux_pread(td, uap)
if (error == 0) {
/* This seems to violate POSIX but linux does it */
- if ((error = fgetvp(td, uap->fd, CAP_PREAD, &vp)) != 0)
+ error = fgetvp(td, uap->fd,
+ cap_rights_init(&rights, CAP_PREAD), &vp);
+ if (error != 0)
return (error);
if (vp->v_type == VDIR) {
vrele(vp);
@@ -1283,6 +1290,7 @@ fcntl_common(struct thread *td, struct linux_fcntl64_args *args)
{
struct l_flock linux_flock;
struct flock bsd_flock;
+ cap_rights_t rights;
struct file *fp;
long arg;
int error, result;
@@ -1385,7 +1393,8 @@ 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, CAP_FCNTL, &fp);
+ error = fget(td, args->fd,
+ cap_rights_init(&rights, CAP_FCNTL), &fp);
if (error)
return (error);
if (fp->f_type == DTYPE_PIPE) {
diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c
index 4df28aa..2a4016a 100644
--- a/sys/compat/linux/linux_ioctl.c
+++ b/sys/compat/linux/linux_ioctl.c
@@ -189,12 +189,14 @@ struct linux_hd_big_geometry {
static int
linux_ioctl_hdio(struct thread *td, struct linux_ioctl_args *args)
{
+ cap_rights_t rights;
struct file *fp;
int error;
u_int sectorsize, fwcylinders, fwheads, fwsectors;
off_t mediasize, bytespercyl;
- if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
switch (args->cmd & 0xffff) {
case LINUX_HDIO_GET_GEO:
@@ -270,12 +272,14 @@ linux_ioctl_hdio(struct thread *td, struct linux_ioctl_args *args)
static int
linux_ioctl_disk(struct thread *td, struct linux_ioctl_args *args)
{
+ cap_rights_t rights;
struct file *fp;
int error;
u_int sectorsize;
off_t mediasize;
- if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
switch (args->cmd & 0xffff) {
case LINUX_BLKGETSIZE:
@@ -698,10 +702,12 @@ linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args)
struct termios bios;
struct linux_termios lios;
struct linux_termio lio;
+ cap_rights_t rights;
struct file *fp;
int error;
- if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
switch (args->cmd & 0xffff) {
@@ -1438,10 +1444,12 @@ bsd_to_linux_dvd_authinfo(struct dvd_authinfo *bp, l_dvd_authinfo *lp)
static int
linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
{
+ cap_rights_t rights;
struct file *fp;
int error;
- if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
switch (args->cmd & 0xffff) {
@@ -1963,10 +1971,12 @@ linux_ioctl_sound(struct thread *td, struct linux_ioctl_args *args)
static int
linux_ioctl_console(struct thread *td, struct linux_ioctl_args *args)
{
+ cap_rights_t rights;
struct file *fp;
int error;
- if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
switch (args->cmd & 0xffff) {
@@ -2351,6 +2361,7 @@ static int
linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
{
char lifname[LINUX_IFNAMSIZ], ifname[IFNAMSIZ];
+ cap_rights_t rights;
struct ifnet *ifp;
struct file *fp;
int error, type;
@@ -2358,7 +2369,8 @@ linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
ifp = NULL;
error = 0;
- if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
type = fp->f_type;
fdrop(fp, td);
@@ -2581,10 +2593,12 @@ linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
static int
linux_ioctl_private(struct thread *td, struct linux_ioctl_args *args)
{
+ cap_rights_t rights;
struct file *fp;
int error, type;
- if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
type = fp->f_type;
fdrop(fp, td);
@@ -2606,11 +2620,13 @@ linux_ioctl_drm(struct thread *td, struct linux_ioctl_args *args)
static int
linux_ioctl_sg(struct thread *td, struct linux_ioctl_args *args)
{
+ cap_rights_t rights;
struct file *fp;
u_long cmd;
int error;
- if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0) {
+ error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0) {
printf("sg_linux_ioctl: fget returned %d\n", error);
return (error);
}
@@ -2828,6 +2844,7 @@ linux_v4l_cliplist_copy(struct l_video_window *lvw, struct video_window *vw)
static int
linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args)
{
+ cap_rights_t rights;
struct file *fp;
int error;
struct video_tuner vtun;
@@ -2845,7 +2862,9 @@ 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, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd,
+ cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun));
if (error) {
@@ -2863,7 +2882,9 @@ linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args)
return (error);
case LINUX_VIDIOCSTUNER:
- if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd,
+ cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun));
if (error) {
@@ -2880,7 +2901,9 @@ 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, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd,
+ cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
error = fo_ioctl(fp, VIDIOCGWIN, &vwin, td->td_ucred, td);
if (!error) {
@@ -2892,7 +2915,9 @@ linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args)
return (error);
case LINUX_VIDIOCSWIN:
- if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd,
+ cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
error = copyin((void *) args->arg, &l_vwin, sizeof(l_vwin));
if (error) {
@@ -2915,7 +2940,9 @@ linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args)
return (error);
case LINUX_VIDIOCGFBUF:
- if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd,
+ cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
error = fo_ioctl(fp, VIDIOCGFBUF, &vbuf, td->td_ucred, td);
if (!error) {
@@ -2927,7 +2954,9 @@ linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args)
return (error);
case LINUX_VIDIOCSFBUF:
- if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd,
+ cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
error = copyin((void *) args->arg, &l_vbuf, sizeof(l_vbuf));
if (error) {
@@ -2955,7 +2984,9 @@ 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, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd,
+ cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
error = copyin((void *) args->arg, &l_vcode, sizeof(l_vcode));
if (error) {
@@ -3108,6 +3139,7 @@ bsd_to_linux_v4l2_format(struct v4l2_format *vf, struct l_v4l2_format *lvf)
static int
linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args)
{
+ cap_rights_t rights;
struct file *fp;
int error;
struct v4l2_format vformat;
@@ -3199,7 +3231,9 @@ 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, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd,
+ cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error)
return (error);
if (linux_to_bsd_v4l2_format(&l_vformat, &vformat) != 0)
error = EINVAL;
@@ -3222,7 +3256,9 @@ 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, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd,
+ cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error)
return (error);
error = fo_ioctl(fp, VIDIOC_ENUMSTD, (caddr_t)&vstd,
td->td_ucred, td);
@@ -3244,7 +3280,9 @@ 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, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd,
+ cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
error = fo_ioctl(fp, VIDIOC_ENUMINPUT, (caddr_t)&vinp,
td->td_ucred, td);
@@ -3263,7 +3301,9 @@ 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, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd,
+ cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error)
return (error);
linux_to_bsd_v4l2_buffer(&l_vbuf, &vbuf);
if ((args->cmd & 0xffff) == LINUX_VIDIOC_QUERYBUF)
@@ -3432,6 +3472,7 @@ linux_ioctl_fbsd_usb(struct thread *td, struct linux_ioctl_args *args)
int
linux_ioctl(struct thread *td, struct linux_ioctl_args *args)
{
+ cap_rights_t rights;
struct file *fp;
struct handler_element *he;
int error, cmd;
@@ -3442,7 +3483,8 @@ linux_ioctl(struct thread *td, struct linux_ioctl_args *args)
(unsigned long)args->cmd);
#endif
- if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
fdrop(fp, td);
diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c
index 36b23ac..22f811c 100644
--- a/sys/compat/linux/linux_socket.c
+++ b/sys/compat/linux/linux_socket.c
@@ -748,6 +748,7 @@ int linux_connect(struct thread *, struct linux_connect_args *);
int
linux_connect(struct thread *td, struct linux_connect_args *args)
{
+ cap_rights_t rights;
struct socket *so;
struct sockaddr *sa;
u_int fflag;
@@ -772,7 +773,8 @@ 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, CAP_CONNECT, &so, &fflag);
+ error = fgetsock(td, args->s, cap_rights_init(&rights, CAP_CONNECT),
+ &so, &fflag);
if (error == 0) {
error = EISCONN;
if (fflag & FNONBLOCK) {
diff --git a/sys/compat/svr4/svr4_fcntl.c b/sys/compat/svr4/svr4_fcntl.c
index 86fab78..8d0b715 100644
--- a/sys/compat/svr4/svr4_fcntl.c
+++ b/sys/compat/svr4/svr4_fcntl.c
@@ -259,6 +259,7 @@ fd_revoke(td, fd)
struct vnode *vp;
struct mount *mp;
struct vattr vattr;
+ cap_rights_t rights;
int error, *retval;
retval = td->td_retval;
@@ -267,12 +268,13 @@ fd_revoke(td, fd)
* or FreeBSD grows a native frevoke() (more likely), we will need a
* CAP_FREVOKE here.
*
- * In the meantime, use CAP_ALL: if a SVR4 process wants to
+ * In the meantime, use CAP_ALL(): 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_ALL, &vp)) != 0)
+ CAP_ALL(&rights);
+ if ((error = fgetvp(td, fd, &rights, &vp)) != 0)
return (error);
if (vp->v_type != VCHR && vp->v_type != VBLK) {
@@ -318,13 +320,15 @@ fd_truncate(td, fd, flp)
struct vattr vattr;
int error, *retval;
struct ftruncate_args ft;
+ cap_rights_t rights;
retval = td->td_retval;
/*
* We only support truncating the file.
*/
- if ((error = fget(td, fd, CAP_FTRUNCATE, &fp)) != 0)
+ error = fget(td, fd, cap_rights_init(&rights, CAP_FTRUNCATE), &fp);
+ if (error != 0)
return (error);
vp = fp->f_vnode;
@@ -401,9 +405,11 @@ svr4_sys_open(td, uap)
if (!(bsd_flags & O_NOCTTY) && SESS_LEADER(p) &&
!(p->p_flag & P_CONTROLT)) {
#if defined(NOTYET)
- struct file *fp;
+ cap_rights_t rights;
+ struct file *fp;
- error = fget(td, retval, CAP_IOCTL, &fp);
+ error = fget(td, retval,
+ cap_rights_init(&rights, CAP_IOCTL), &fp);
PROC_UNLOCK(p);
/*
* we may have lost a race the above open() and
diff --git a/sys/compat/svr4/svr4_filio.c b/sys/compat/svr4/svr4_filio.c
index 0fbba07..b953e72 100644
--- a/sys/compat/svr4/svr4_filio.c
+++ b/sys/compat/svr4/svr4_filio.c
@@ -104,6 +104,7 @@ svr4_sys_read(td, uap)
struct svr4_sys_read_args *uap;
{
struct read_args ra;
+ cap_rights_t rights;
struct file *fp;
struct socket *so = NULL;
int so_state;
@@ -114,7 +115,7 @@ svr4_sys_read(td, uap)
ra.buf = uap->buf;
ra.nbyte = uap->nbyte;
- if (fget(td, uap->fd, CAP_READ, &fp) != 0) {
+ if (fget(td, uap->fd, cap_rights_init(&rights, CAP_READ), &fp) != 0) {
DPRINTF(("Something fishy with the user-supplied file descriptor...\n"));
return EBADF;
}
diff --git a/sys/compat/svr4/svr4_ioctl.c b/sys/compat/svr4/svr4_ioctl.c
index 36b0580..a8c8c8c 100644
--- a/sys/compat/svr4/svr4_ioctl.c
+++ b/sys/compat/svr4/svr4_ioctl.c
@@ -84,6 +84,7 @@ svr4_sys_ioctl(td, uap)
struct svr4_sys_ioctl_args *uap;
{
int *retval;
+ cap_rights_t rights;
struct file *fp;
u_long cmd;
int (*fun)(struct file *, struct thread *, register_t *,
@@ -103,7 +104,8 @@ svr4_sys_ioctl(td, uap)
retval = td->td_retval;
cmd = uap->com;
- if ((error = fget(td, uap->fd, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, uap->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
diff --git a/sys/compat/svr4/svr4_misc.c b/sys/compat/svr4/svr4_misc.c
index 0cfaeae..4888698 100644
--- a/sys/compat/svr4/svr4_misc.c
+++ b/sys/compat/svr4/svr4_misc.c
@@ -236,6 +236,7 @@ svr4_sys_getdents64(td, uap)
int len, reclen; /* BSD-format */
caddr_t outp; /* SVR4-format */
int resid, svr4reclen=0; /* SVR4-format */
+ cap_rights_t rights;
struct file *fp;
struct uio auio;
struct iovec aiov;
@@ -247,7 +248,9 @@ 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, CAP_READ, &fp)) != 0)
+ error = getvnode(td->td_proc->p_fd, uap->fd,
+ cap_rights_init(&rights, CAP_READ), &fp);
+ if (error != 0)
return (error);
if ((fp->f_flag & FREAD) == 0) {
@@ -412,6 +415,7 @@ svr4_sys_getdents(td, uap)
int len, reclen; /* BSD-format */
caddr_t outp; /* SVR4-format */
int resid, svr4_reclen; /* SVR4-format */
+ cap_rights_t rights;
struct file *fp;
struct uio auio;
struct iovec aiov;
@@ -424,7 +428,9 @@ svr4_sys_getdents(td, uap)
if (uap->nbytes < 0)
return (EINVAL);
- if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_READ, &fp)) != 0)
+ error = getvnode(td->td_proc->p_fd, uap->fd,
+ cap_rights_init(&rights, CAP_READ), &fp);
+ if (error != 0)
return (error);
if ((fp->f_flag & FREAD) == 0) {
diff --git a/sys/compat/svr4/svr4_stream.c b/sys/compat/svr4/svr4_stream.c
index 1c7e83e..6348b9b 100644
--- a/sys/compat/svr4/svr4_stream.c
+++ b/sys/compat/svr4/svr4_stream.c
@@ -1446,10 +1446,12 @@ svr4_sys_putmsg(td, uap)
struct thread *td;
struct svr4_sys_putmsg_args *uap;
{
- struct file *fp;
+ cap_rights_t rights;
+ struct file *fp;
int error;
- if ((error = fget(td, uap->fd, CAP_SEND, &fp)) != 0) {
+ error = fget(td, uap->fd, cap_rights_init(&rights, CAP_SEND), &fp);
+ if (error != 0) {
#ifdef DEBUG_SVR4
uprintf("putmsg: bad fp\n");
#endif
@@ -1618,10 +1620,12 @@ svr4_sys_getmsg(td, uap)
struct thread *td;
struct svr4_sys_getmsg_args *uap;
{
- struct file *fp;
+ cap_rights_t rights;
+ struct file *fp;
int error;
- if ((error = fget(td, uap->fd, CAP_RECV, &fp)) != 0) {
+ error = fget(td, uap->fd, cap_rights_init(&rights, CAP_RECV), &fp);
+ if (error != 0) {
#ifdef DEBUG_SVR4
uprintf("getmsg: bad fp\n");
#endif
diff --git a/sys/conf/files b/sys/conf/files
index f02944f..8bb4eff 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -2847,6 +2847,7 @@ kern/subr_blist.c standard
kern/subr_bus.c standard
kern/subr_bus_dma.c standard
kern/subr_bufring.c standard
+kern/subr_capability.c standard
kern/subr_clock.c standard
kern/subr_counter.c standard
kern/subr_devstat.c standard
diff --git a/sys/dev/aac/aac_linux.c b/sys/dev/aac/aac_linux.c
index 049e2be..591dfbb 100644
--- a/sys/dev/aac/aac_linux.c
+++ b/sys/dev/aac/aac_linux.c
@@ -75,11 +75,13 @@ MODULE_DEPEND(aac_linux, linux, 1, 1, 1);
static int
aac_linux_ioctl(struct thread *td, struct linux_ioctl_args *args)
{
+ cap_rights_t rights;
struct file *fp;
u_long cmd;
int error;
- if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
cmd = args->cmd;
diff --git a/sys/dev/amr/amr_linux.c b/sys/dev/amr/amr_linux.c
index 44e858b..5b1a17f 100644
--- a/sys/dev/amr/amr_linux.c
+++ b/sys/dev/amr/amr_linux.c
@@ -72,10 +72,12 @@ MODULE_DEPEND(amr, linux, 1, 1, 1);
static int
amr_linux_ioctl(struct thread *p, struct linux_ioctl_args *args)
{
+ cap_rights_t rights;
struct file *fp;
int error;
- if ((error = fget(p, args->fd, CAP_IOCTL, &fp)) != 0)
+ error = fget(p, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
error = fo_ioctl(fp, args->cmd, (caddr_t)args->arg, p->td_ucred, p);
fdrop(fp, p);
diff --git a/sys/dev/filemon/filemon.c b/sys/dev/filemon/filemon.c
index ce84e3d..e3fda18 100644
--- a/sys/dev/filemon/filemon.c
+++ b/sys/dev/filemon/filemon.c
@@ -138,12 +138,6 @@ filemon_dtr(void *data)
}
}
-#if __FreeBSD_version < 900041
-#define FGET_WRITE(a1, a2, a3) fget_write((a1), (a2), (a3))
-#else
-#define FGET_WRITE(a1, a2, a3) fget_write((a1), (a2), CAP_WRITE | CAP_SEEK, (a3))
-#endif
-
static int
filemon_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag __unused,
struct thread *td)
@@ -151,13 +145,21 @@ filemon_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag __unused,
int error = 0;
struct filemon *filemon;
struct proc *p;
+#if __FreeBSD_version >= 900041
+ cap_rights_t rights;
+#endif
devfs_get_cdevpriv((void **) &filemon);
switch (cmd) {
/* Set the output file descriptor. */
case FILEMON_SET_FD:
- if ((error = FGET_WRITE(td, *(int *)data, &filemon->fp)) == 0)
+ error = fget_write(td, *(int *)data,
+#if __FreeBSD_version >= 900041
+ cap_rights_init(&rights, CAP_PWRITE),
+#endif
+ &filemon->fp);
+ if (error == 0)
/* Write the file header. */
filemon_comment(filemon);
break;
diff --git a/sys/dev/hwpmc/hwpmc_logging.c b/sys/dev/hwpmc/hwpmc_logging.c
index 880bcaa..a60e096 100644
--- a/sys/dev/hwpmc/hwpmc_logging.c
+++ b/sys/dev/hwpmc/hwpmc_logging.c
@@ -570,6 +570,7 @@ pmclog_configure_log(struct pmc_mdep *md, struct pmc_owner *po, int logfd)
{
int error;
struct proc *p;
+ cap_rights_t rights;
/*
* As long as it is possible to get a LOR between pmc_sx lock and
@@ -593,7 +594,8 @@ 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, CAP_WRITE, &po->po_file);
+ error = fget_write(curthread, logfd,
+ cap_rights_init(&rights, CAP_WRITE), &po->po_file);
if (error)
goto error;
diff --git a/sys/dev/ipmi/ipmi_linux.c b/sys/dev/ipmi/ipmi_linux.c
index 430bd08..b6b38f2 100644
--- a/sys/dev/ipmi/ipmi_linux.c
+++ b/sys/dev/ipmi/ipmi_linux.c
@@ -89,11 +89,13 @@ MODULE_DEPEND(ipmi_linux, linux, 1, 1, 1);
static int
ipmi_linux_ioctl(struct thread *td, struct linux_ioctl_args *args)
{
+ cap_rights_t rights;
struct file *fp;
u_long cmd;
int error;
- if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
cmd = args->cmd;
diff --git a/sys/dev/iscsi_initiator/iscsi.c b/sys/dev/iscsi_initiator/iscsi.c
index 4dbf163..4a1cb96 100644
--- a/sys/dev/iscsi_initiator/iscsi.c
+++ b/sys/dev/iscsi_initiator/iscsi.c
@@ -382,16 +382,19 @@ i_ping(struct cdev *dev)
static int
i_setsoc(isc_session_t *sp, int fd, struct thread *td)
{
+ cap_rights_t rights;
int error = 0;
if(sp->soc != NULL)
isc_stop_receiver(sp);
- error = fget(td, fd, CAP_SOCK_CLIENT, &sp->fp);
+ error = fget(td, fd, cap_rights_init(&rights, CAP_SOCK_CLIENT), &sp->fp);
if(error)
return error;
- if((error = fgetsock(td, fd, CAP_SOCK_CLIENT, &sp->soc, 0)) == 0) {
+ error = fgetsock(td, fd, cap_rights_init(&rights, CAP_SOCK_CLIENT),
+ &sp->soc, 0);
+ if(error == 0) {
sp->td = td;
isc_start_receiver(sp);
}
diff --git a/sys/dev/mfi/mfi_linux.c b/sys/dev/mfi/mfi_linux.c
index 3328a66..429d496 100644
--- a/sys/dev/mfi/mfi_linux.c
+++ b/sys/dev/mfi/mfi_linux.c
@@ -84,6 +84,7 @@ MODULE_DEPEND(mfi, linux, 1, 1, 1);
static int
mfi_linux_ioctl(struct thread *p, struct linux_ioctl_args *args)
{
+ cap_rights_t rights;
struct file *fp;
int error;
u_long cmd = args->cmd;
@@ -97,7 +98,8 @@ mfi_linux_ioctl(struct thread *p, struct linux_ioctl_args *args)
break;
}
- if ((error = fget(p, args->fd, CAP_IOCTL, &fp)) != 0)
+ error = fget(p, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
error = fo_ioctl(fp, cmd, (caddr_t)args->arg, p->td_ucred, p);
fdrop(fp, p);
diff --git a/sys/dev/tdfx/tdfx_linux.c b/sys/dev/tdfx/tdfx_linux.c
index 0b769f0..fa39ab1 100644
--- a/sys/dev/tdfx/tdfx_linux.c
+++ b/sys/dev/tdfx/tdfx_linux.c
@@ -45,6 +45,7 @@ LINUX_IOCTL_SET(tdfx, LINUX_IOCTL_TDFX_MIN, LINUX_IOCTL_TDFX_MAX);
static int
linux_ioctl_tdfx(struct thread *td, struct linux_ioctl_args* args)
{
+ cap_rights_t rights;
int error = 0;
u_long cmd = args->cmd & 0xffff;
@@ -54,7 +55,8 @@ linux_ioctl_tdfx(struct thread *td, struct linux_ioctl_args* args)
struct file *fp;
- if ((error = fget(td, args->fd, CAP_IOCTL, &fp)) != 0)
+ error = fget(td, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0)
return (error);
/* We simply copy the data and send it right to ioctl */
copyin((caddr_t)args->arg, &d_pio, sizeof(d_pio));
diff --git a/sys/fs/fdescfs/fdesc_vnops.c b/sys/fs/fdescfs/fdesc_vnops.c
index f18c0fc..fe939b1 100644
--- a/sys/fs/fdescfs/fdesc_vnops.c
+++ b/sys/fs/fdescfs/fdesc_vnops.c
@@ -445,6 +445,7 @@ fdesc_setattr(ap)
struct mount *mp;
struct file *fp;
struct thread *td = curthread;
+ cap_rights_t rights;
unsigned fd;
int error;
@@ -459,7 +460,8 @@ fdesc_setattr(ap)
/*
* Allow setattr where there is an underlying vnode.
*/
- error = getvnode(td->td_proc->p_fd, fd, CAP_EXTATTR_SET, &fp);
+ error = getvnode(td->td_proc->p_fd, fd,
+ cap_rights_init(&rights, CAP_EXTATTR_SET), &fp);
if (error) {
/*
* getvnode() returns EINVAL if the file descriptor is not
diff --git a/sys/fs/fuse/fuse_vfsops.c b/sys/fs/fuse/fuse_vfsops.c
index 639550a..0b4f19b 100644
--- a/sys/fs/fuse/fuse_vfsops.c
+++ b/sys/fs/fuse/fuse_vfsops.c
@@ -220,6 +220,7 @@ fuse_vfsop_mount(struct mount *mp)
struct file *fp, *fptmp;
char *fspec, *subtype;
struct vfsoptlist *opts;
+ cap_rights_t rights;
subtype = NULL;
max_read_set = 0;
@@ -289,7 +290,7 @@ fuse_vfsop_mount(struct mount *mp)
FS_DEBUG2G("mntopts 0x%jx\n", (uintmax_t)mntopts);
- err = fget(td, fd, CAP_READ, &fp);
+ err = fget(td, fd, cap_rights_init(&rights, CAP_READ), &fp);
if (err != 0) {
FS_DEBUG("invalid or not opened device: data=%p\n", data);
goto out;
diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c
index d7b082b..b198d59 100644
--- a/sys/fs/nfsclient/nfs_clport.c
+++ b/sys/fs/nfsclient/nfs_clport.c
@@ -1219,10 +1219,11 @@ nfssvc_nfscl(struct thread *td, struct nfssvc_args *uap)
struct file *fp;
struct nfscbd_args nfscbdarg;
struct nfsd_nfscbd_args nfscbdarg2;
- int error;
struct nameidata nd;
struct nfscl_dumpmntopts dumpmntopts;
+ cap_rights_t rights;
char *buf;
+ int error;
if (uap->flag & NFSSVC_CBADDSOCK) {
error = copyin(uap->argp, (caddr_t)&nfscbdarg, sizeof(nfscbdarg));
@@ -1233,10 +1234,10 @@ nfssvc_nfscl(struct thread *td, struct nfssvc_args *uap)
* pretend that we need them all. It is better to be too
* careful than too reckless.
*/
- if ((error = fget(td, nfscbdarg.sock, CAP_SOCK_CLIENT, &fp))
- != 0) {
+ error = fget(td, nfscbdarg.sock,
+ cap_rights_init(&rights, CAP_SOCK_CLIENT), &fp);
+ if (error)
return (error);
- }
if (fp->f_type != DTYPE_SOCKET) {
fdrop(fp, td);
return (EPERM);
diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
index a6a0169..2f9d40a 100644
--- a/sys/fs/nfsserver/nfs_nfsdport.c
+++ b/sys/fs/nfsserver/nfs_nfsdport.c
@@ -3035,6 +3035,7 @@ nfssvc_nfsd(struct thread *td, struct nfssvc_args *uap)
struct file *fp;
struct nfsd_addsock_args sockarg;
struct nfsd_nfsd_args nfsdarg;
+ cap_rights_t rights;
int error;
if (uap->flag & NFSSVC_NFSDADDSOCK) {
@@ -3046,7 +3047,9 @@ nfssvc_nfsd(struct thread *td, struct nfssvc_args *uap)
* pretend that we need them all. It is better to be too
* careful than too reckless.
*/
- if ((error = fget(td, sockarg.sock, CAP_SOCK_SERVER, &fp)) != 0)
+ error = fget(td, sockarg.sock,
+ cap_rights_init(&rights, CAP_SOCK_SERVER), &fp);
+ if (error != 0)
goto out;
if (fp->f_type != DTYPE_SOCKET) {
fdrop(fp, td);
diff --git a/sys/i386/ibcs2/ibcs2_fcntl.c b/sys/i386/ibcs2/ibcs2_fcntl.c
index 2902da7..d061b79 100644
--- a/sys/i386/ibcs2/ibcs2_fcntl.c
+++ b/sys/i386/ibcs2/ibcs2_fcntl.c
@@ -201,10 +201,12 @@ ibcs2_open(td, uap)
free(path, M_TEMP);
PROC_LOCK(p);
if (!ret && !noctty && SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
+ cap_rights_t rights;
struct file *fp;
int error;
- error = fget(td, td->td_retval[0], CAP_IOCTL, &fp);
+ error = fget(td, td->td_retval[0],
+ cap_rights_init(&rights, CAP_IOCTL), &fp);
PROC_UNLOCK(p);
if (error)
return (EBADF);
diff --git a/sys/i386/ibcs2/ibcs2_ioctl.c b/sys/i386/ibcs2/ibcs2_ioctl.c
index 83e68cd..03fa5f6 100644
--- a/sys/i386/ibcs2/ibcs2_ioctl.c
+++ b/sys/i386/ibcs2/ibcs2_ioctl.c
@@ -331,10 +331,12 @@ ibcs2_ioctl(td, uap)
struct ibcs2_ioctl_args *uap;
{
struct proc *p = td->td_proc;
+ cap_rights_t rights;
struct file *fp;
int error;
- if ((error = fget(td, uap->fd, CAP_IOCTL, &fp)) != 0) {
+ error = fget(td, uap->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0) {
DPRINTF(("ibcs2_ioctl(%d): bad fd %d ", p->p_pid,
uap->fd));
return EBADF;
diff --git a/sys/i386/ibcs2/ibcs2_misc.c b/sys/i386/ibcs2/ibcs2_misc.c
index 9f382aa..28cd83c 100644
--- a/sys/i386/ibcs2/ibcs2_misc.c
+++ b/sys/i386/ibcs2/ibcs2_misc.c
@@ -326,6 +326,7 @@ ibcs2_getdents(td, uap)
register int len, reclen; /* BSD-format */
register caddr_t outp; /* iBCS2-format */
register int resid; /* iBCS2-format */
+ cap_rights_t rights;
struct file *fp;
struct uio auio;
struct iovec aiov;
@@ -337,7 +338,9 @@ 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, CAP_READ, &fp)) != 0)
+ error = getvnode(td->td_proc->p_fd, uap->fd,
+ cap_rights_init(&rights, CAP_READ), &fp);
+ if (error != 0)
return (error);
if ((fp->f_flag & FREAD) == 0) {
fdrop(fp, td);
@@ -478,6 +481,7 @@ ibcs2_read(td, uap)
register int len, reclen; /* BSD-format */
register caddr_t outp; /* iBCS2-format */
register int resid; /* iBCS2-format */
+ cap_rights_t rights;
struct file *fp;
struct uio auio;
struct iovec aiov;
@@ -490,8 +494,9 @@ ibcs2_read(td, uap)
u_long *cookies = NULL, *cookiep;
int ncookies;
- if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_READ,
- &fp)) != 0) {
+ error = getvnode(td->td_proc->p_fd, uap->fd,
+ cap_rights_init(&rights, CAP_READ), &fp);
+ if (error != 0) {
if (error == EINVAL)
return sys_read(td, (struct read_args *)uap);
else
diff --git a/sys/i386/linux/linux_machdep.c b/sys/i386/linux/linux_machdep.c
index 14d1892..2d79204 100644
--- a/sys/i386/linux/linux_machdep.c
+++ b/sys/i386/linux/linux_machdep.c
@@ -422,6 +422,7 @@ linux_mmap_common(struct thread *td, l_uintptr_t addr, l_size_t len, l_int prot,
} */ bsd_args;
int error;
struct file *fp;
+ cap_rights_t rights;
error = 0;
bsd_args.flags = 0;
@@ -473,7 +474,9 @@ linux_mmap_common(struct thread *td, l_uintptr_t addr, l_size_t len, l_int prot,
* is done in the FreeBSD mmap().
*/
- if ((error = fget(td, bsd_args.fd, CAP_MMAP, &fp)) != 0)
+ error = fget(td, bsd_args.fd,
+ cap_rights_init(&rights, CAP_MMAP), &fp);
+ if (error != 0)
return (error);
if (fp->f_type != DTYPE_VNODE) {
fdrop(fp, td);
diff --git a/sys/kern/capabilities.conf b/sys/kern/capabilities.conf
index d2fa51c..eaa5b14 100644
--- a/sys/kern/capabilities.conf
+++ b/sys/kern/capabilities.conf
@@ -114,8 +114,7 @@ cap_fcntls_limit
cap_getmode
cap_ioctls_get
cap_ioctls_limit
-cap_new
-cap_rights_get
+__cap_rights_get
cap_rights_limit
##
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index d0de6b9..a0545e1 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -455,6 +455,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
struct filedescent *fde;
struct proc *p;
struct vnode *vp;
+ cap_rights_t rights;
int error, flg, tmp;
u_int old, new;
uint64_t bsize;
@@ -515,7 +516,8 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
break;
case F_GETFL:
- error = fget_unlocked(fdp, fd, CAP_FCNTL, F_GETFL, &fp, NULL);
+ error = fget_unlocked(fdp, fd,
+ cap_rights_init(&rights, CAP_FCNTL), F_GETFL, &fp, NULL);
if (error != 0)
break;
td->td_retval[0] = OFLAGS(fp->f_flag);
@@ -523,7 +525,8 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
break;
case F_SETFL:
- error = fget_unlocked(fdp, fd, CAP_FCNTL, F_SETFL, &fp, NULL);
+ error = fget_unlocked(fdp, fd,
+ cap_rights_init(&rights, CAP_FCNTL), F_SETFL, &fp, NULL);
if (error != 0)
break;
do {
@@ -550,7 +553,8 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
break;
case F_GETOWN:
- error = fget_unlocked(fdp, fd, CAP_FCNTL, F_GETOWN, &fp, NULL);
+ error = fget_unlocked(fdp, fd,
+ cap_rights_init(&rights, CAP_FCNTL), F_GETOWN, &fp, NULL);
if (error != 0)
break;
error = fo_ioctl(fp, FIOGETOWN, &tmp, td->td_ucred, td);
@@ -560,7 +564,8 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
break;
case F_SETOWN:
- error = fget_unlocked(fdp, fd, CAP_FCNTL, F_SETOWN, &fp, NULL);
+ error = fget_unlocked(fdp, fd,
+ cap_rights_init(&rights, CAP_FCNTL), F_SETOWN, &fp, NULL);
if (error != 0)
break;
tmp = arg;
@@ -581,7 +586,8 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
case F_SETLK:
do_setlk:
- error = fget_unlocked(fdp, fd, CAP_FLOCK, 0, &fp, NULL);
+ error = fget_unlocked(fdp, fd,
+ cap_rights_init(&rights, CAP_FLOCK), 0, &fp, NULL);
if (error != 0)
break;
if (fp->f_type != DTYPE_VNODE) {
@@ -688,7 +694,8 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
break;
case F_GETLK:
- error = fget_unlocked(fdp, fd, CAP_FLOCK, 0, &fp, NULL);
+ error = fget_unlocked(fdp, fd,
+ cap_rights_init(&rights, CAP_FLOCK), 0, &fp, NULL);
if (error != 0)
break;
if (fp->f_type != DTYPE_VNODE) {
@@ -1281,11 +1288,13 @@ int
kern_fstat(struct thread *td, int fd, struct stat *sbp)
{
struct file *fp;
+ cap_rights_t rights;
int error;
AUDIT_ARG_FD(fd);
- if ((error = fget(td, fd, CAP_FSTAT, &fp)) != 0)
+ error = fget(td, fd, cap_rights_init(&rights, CAP_FSTAT), &fp);
+ if (error != 0)
return (error);
AUDIT_ARG_FILE(td->td_proc, fp);
@@ -1339,9 +1348,11 @@ sys_fpathconf(struct thread *td, struct fpathconf_args *uap)
{
struct file *fp;
struct vnode *vp;
+ cap_rights_t rights;
int error;
- if ((error = fget(td, uap->fd, CAP_FPATHCONF, &fp)) != 0)
+ error = fget(td, uap->fd, cap_rights_init(&rights, CAP_FPATHCONF), &fp);
+ if (error != 0)
return (error);
/* If asynchronous I/O is available, it works for all descriptors. */
@@ -1417,7 +1428,7 @@ static void
filecaps_fill(struct filecaps *fcaps)
{
- fcaps->fc_rights = CAP_ALL;
+ CAP_ALL(&fcaps->fc_rights);
fcaps->fc_ioctls = NULL;
fcaps->fc_nioctls = -1;
fcaps->fc_fcntls = CAP_FCNTL_ALL;
@@ -1441,16 +1452,18 @@ static void
filecaps_validate(const struct filecaps *fcaps, const char *func)
{
- KASSERT((fcaps->fc_rights & ~CAP_MASK_VALID) == 0,
+ KASSERT(cap_rights_is_valid(&fcaps->fc_rights),
("%s: invalid rights", func));
KASSERT((fcaps->fc_fcntls & ~CAP_FCNTL_ALL) == 0,
("%s: invalid fcntls", func));
- KASSERT(fcaps->fc_fcntls == 0 || (fcaps->fc_rights & CAP_FCNTL) != 0,
+ KASSERT(fcaps->fc_fcntls == 0 ||
+ cap_rights_is_set(&fcaps->fc_rights, CAP_FCNTL),
("%s: fcntls without CAP_FCNTL", func));
KASSERT(fcaps->fc_ioctls != NULL ? fcaps->fc_nioctls > 0 :
(fcaps->fc_nioctls == -1 || fcaps->fc_nioctls == 0),
("%s: invalid ioctls", func));
- KASSERT(fcaps->fc_nioctls == 0 || (fcaps->fc_rights & CAP_IOCTL) != 0,
+ KASSERT(fcaps->fc_nioctls == 0 ||
+ cap_rights_is_set(&fcaps->fc_rights, CAP_IOCTL),
("%s: ioctls without CAP_IOCTL", func));
}
@@ -2285,7 +2298,7 @@ finit(struct file *fp, u_int flag, short type, void *data, struct fileops *ops)
}
int
-fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t needrights,
+fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t *needrightsp,
int needfcntl, struct file **fpp, cap_rights_t *haverightsp)
{
struct file *fp;
@@ -2310,11 +2323,11 @@ fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t needrights,
if (fp == NULL)
return (EBADF);
#ifdef CAPABILITIES
- haverights = cap_rights(fdp, fd);
- error = cap_check(haverights, needrights);
+ haverights = *cap_rights(fdp, fd);
+ error = cap_check(&haverights, needrightsp);
if (error != 0)
return (error);
- if ((needrights & CAP_FCNTL) != 0) {
+ if (cap_rights_is_set(needrightsp, CAP_FCNTL)) {
error = cap_fcntl_check(fdp, fd, needfcntl);
if (error != 0)
return (error);
@@ -2338,7 +2351,7 @@ fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t needrights,
#ifdef CAPABILITIES
*haverightsp = haverights;
#else
- *haverightsp = CAP_ALL;
+ CAP_ALL(haverightsp);
#endif
}
return (0);
@@ -2359,19 +2372,20 @@ fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t needrights,
*/
static __inline int
_fget(struct thread *td, int fd, struct file **fpp, int flags,
- cap_rights_t needrights, u_char *maxprotp)
+ cap_rights_t *needrightsp, u_char *maxprotp)
{
struct filedesc *fdp;
struct file *fp;
- cap_rights_t haverights;
+ cap_rights_t haverights, needrights;
int error;
*fpp = NULL;
if (td == NULL || (fdp = td->td_proc->p_fd) == NULL)
return (EBADF);
+ needrights = *needrightsp;
if (maxprotp != NULL)
- needrights |= CAP_MMAP;
- error = fget_unlocked(fdp, fd, needrights, 0, &fp, &haverights);
+ cap_rights_set(&needrights, CAP_MMAP);
+ error = fget_unlocked(fdp, fd, &needrights, 0, &fp, &haverights);
if (error != 0)
return (error);
if (fp->f_ops == &badfileops) {
@@ -2384,7 +2398,7 @@ _fget(struct thread *td, int fd, struct file **fpp, int flags,
* If requested, convert capability rights to access flags.
*/
if (maxprotp != NULL)
- *maxprotp = cap_rights_to_vmprot(haverights);
+ *maxprotp = cap_rights_to_vmprot(&haverights);
#else /* !CAPABILITIES */
if (maxprotp != NULL)
*maxprotp = VM_PROT_ALL;
@@ -2421,32 +2435,32 @@ _fget(struct thread *td, int fd, struct file **fpp, int flags,
}
int
-fget(struct thread *td, int fd, cap_rights_t rights, struct file **fpp)
+fget(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp)
{
- return(_fget(td, fd, fpp, 0, rights, NULL));
+ return(_fget(td, fd, fpp, 0, rightsp, NULL));
}
int
-fget_mmap(struct thread *td, int fd, cap_rights_t rights, u_char *maxprotp,
+fget_mmap(struct thread *td, int fd, cap_rights_t *rightsp, u_char *maxprotp,
struct file **fpp)
{
- return (_fget(td, fd, fpp, 0, rights, maxprotp));
+ return (_fget(td, fd, fpp, 0, rightsp, maxprotp));
}
int
-fget_read(struct thread *td, int fd, cap_rights_t rights, struct file **fpp)
+fget_read(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp)
{
- return(_fget(td, fd, fpp, FREAD, rights, NULL));
+ return(_fget(td, fd, fpp, FREAD, rightsp, NULL));
}
int
-fget_write(struct thread *td, int fd, cap_rights_t rights, struct file **fpp)
+fget_write(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp)
{
- return (_fget(td, fd, fpp, FWRITE, rights, NULL));
+ return (_fget(td, fd, fpp, FWRITE, rightsp, NULL));
}
/*
@@ -2457,15 +2471,15 @@ fget_write(struct thread *td, int fd, cap_rights_t rights, struct file **fpp)
* XXX: what about the unused flags ?
*/
static __inline int
-_fgetvp(struct thread *td, int fd, int flags, cap_rights_t needrights,
+_fgetvp(struct thread *td, int fd, int flags, cap_rights_t *needrightsp,
struct vnode **vpp)
{
struct file *fp;
int error;
*vpp = NULL;
- error = _fget(td, fd, &fp, flags, needrights, NULL);
- if (error)
+ error = _fget(td, fd, &fp, flags, needrightsp, NULL);
+ if (error != 0)
return (error);
if (fp->f_vnode == NULL) {
error = EINVAL;
@@ -2479,14 +2493,14 @@ _fgetvp(struct thread *td, int fd, int flags, cap_rights_t needrights,
}
int
-fgetvp(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp)
+fgetvp(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp)
{
- return (_fgetvp(td, fd, 0, rights, vpp));
+ return (_fgetvp(td, fd, 0, rightsp, vpp));
}
int
-fgetvp_rights(struct thread *td, int fd, cap_rights_t need,
+fgetvp_rights(struct thread *td, int fd, cap_rights_t *needrightsp,
struct filecaps *havecaps, struct vnode **vpp)
{
struct filedesc *fdp;
@@ -2503,7 +2517,7 @@ fgetvp_rights(struct thread *td, int fd, cap_rights_t need,
return (EBADF);
#ifdef CAPABILITIES
- error = cap_check(cap_rights(fdp, fd), need);
+ error = cap_check(cap_rights(fdp, fd), needrightsp);
if (error != 0)
return (error);
#endif
@@ -2519,26 +2533,26 @@ fgetvp_rights(struct thread *td, int fd, cap_rights_t need,
}
int
-fgetvp_read(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp)
+fgetvp_read(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp)
{
- return (_fgetvp(td, fd, FREAD, rights, vpp));
+ return (_fgetvp(td, fd, FREAD, rightsp, vpp));
}
int
-fgetvp_exec(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp)
+fgetvp_exec(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp)
{
- return (_fgetvp(td, fd, FEXEC, rights, vpp));
+ return (_fgetvp(td, fd, FEXEC, rightsp, vpp));
}
#ifdef notyet
int
-fgetvp_write(struct thread *td, int fd, cap_rights_t rights,
+fgetvp_write(struct thread *td, int fd, cap_rights_t *rightsp,
struct vnode **vpp)
{
- return (_fgetvp(td, fd, FWRITE, rights, vpp));
+ return (_fgetvp(td, fd, FWRITE, rightsp, vpp));
}
#endif
@@ -2554,7 +2568,7 @@ fgetvp_write(struct thread *td, int fd, cap_rights_t rights,
* during use.
*/
int
-fgetsock(struct thread *td, int fd, cap_rights_t rights, struct socket **spp,
+fgetsock(struct thread *td, int fd, cap_rights_t *rightsp, struct socket **spp,
u_int *fflagp)
{
struct file *fp;
@@ -2563,7 +2577,7 @@ fgetsock(struct thread *td, int fd, cap_rights_t rights, struct socket **spp,
*spp = NULL;
if (fflagp != NULL)
*fflagp = 0;
- if ((error = _fget(td, fd, &fp, 0, rights, NULL)) != 0)
+ if ((error = _fget(td, fd, &fp, 0, rightsp, NULL)) != 0)
return (error);
if (fp->f_type != DTYPE_SOCKET) {
error = ENOTSOCK;
@@ -2637,9 +2651,11 @@ sys_flock(struct thread *td, struct flock_args *uap)
struct file *fp;
struct vnode *vp;
struct flock lf;
+ cap_rights_t rights;
int error;
- if ((error = fget(td, uap->fd, CAP_FLOCK, &fp)) != 0)
+ error = fget(td, uap->fd, cap_rights_init(&rights, CAP_FLOCK), &fp);
+ if (error != 0)
return (error);
if (fp->f_type != DTYPE_VNODE) {
fdrop(fp, td);
@@ -3185,7 +3201,7 @@ struct export_fd_buf {
static int
export_fd_to_sb(void *data, int type, int fd, int fflags, int refcnt,
- int64_t offset, cap_rights_t fd_cap_rights, struct export_fd_buf *efbuf)
+ int64_t offset, cap_rights_t *rightsp, struct export_fd_buf *efbuf)
{
struct {
int fflag;
@@ -3259,7 +3275,10 @@ export_fd_to_sb(void *data, int type, int fd, int fflags, int refcnt,
for (i = 0; i < NFFLAGS; i++)
if (fflags & fflags_table[i].fflag)
kif->kf_flags |= fflags_table[i].kf_fflag;
- kif->kf_cap_rights = fd_cap_rights;
+ if (rightsp != NULL)
+ kif->kf_cap_rights = *rightsp;
+ else
+ cap_rights_init(&kif->kf_cap_rights);
kif->kf_fd = fd;
kif->kf_type = type;
kif->kf_ref_count = refcnt;
@@ -3302,7 +3321,7 @@ kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen)
void *data;
int error, i;
int type, refcnt, fflags;
- cap_rights_t fd_cap_rights;
+ cap_rights_t rights;
PROC_LOCK_ASSERT(p, MA_OWNED);
@@ -3329,13 +3348,13 @@ kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen)
efbuf->remainder = maxlen;
if (tracevp != NULL)
export_fd_to_sb(tracevp, KF_TYPE_VNODE, KF_FD_TYPE_TRACE,
- FREAD | FWRITE, -1, -1, 0, efbuf);
+ FREAD | FWRITE, -1, -1, NULL, efbuf);
if (textvp != NULL)
export_fd_to_sb(textvp, KF_TYPE_VNODE, KF_FD_TYPE_TEXT,
- FREAD, -1, -1, 0, efbuf);
+ FREAD, -1, -1, NULL, efbuf);
if (cttyvp != NULL)
export_fd_to_sb(cttyvp, KF_TYPE_VNODE, KF_FD_TYPE_CTTY,
- FREAD | FWRITE, -1, -1, 0, efbuf);
+ FREAD | FWRITE, -1, -1, NULL, efbuf);
error = 0;
if (fdp == NULL)
goto fail;
@@ -3346,30 +3365,30 @@ kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen)
vref(fdp->fd_cdir);
data = fdp->fd_cdir;
export_fd_to_sb(data, KF_TYPE_VNODE, KF_FD_TYPE_CWD,
- FREAD, -1, -1, 0, efbuf);
+ FREAD, -1, -1, NULL, efbuf);
}
/* root directory */
if (fdp->fd_rdir != NULL) {
vref(fdp->fd_rdir);
data = fdp->fd_rdir;
export_fd_to_sb(data, KF_TYPE_VNODE, KF_FD_TYPE_ROOT,
- FREAD, -1, -1, 0, efbuf);
+ FREAD, -1, -1, NULL, efbuf);
}
/* jail directory */
if (fdp->fd_jdir != NULL) {
vref(fdp->fd_jdir);
data = fdp->fd_jdir;
export_fd_to_sb(data, KF_TYPE_VNODE, KF_FD_TYPE_JAIL,
- FREAD, -1, -1, 0, efbuf);
+ FREAD, -1, -1, NULL, efbuf);
}
for (i = 0; i < fdp->fd_nfiles; i++) {
if ((fp = fdp->fd_ofiles[i].fde_file) == NULL)
continue;
data = NULL;
#ifdef CAPABILITIES
- fd_cap_rights = cap_rights(fdp, i);
+ rights = *cap_rights(fdp, i);
#else /* !CAPABILITIES */
- fd_cap_rights = 0;
+ cap_rights_init(&rights);
#endif
switch (fp->f_type) {
case DTYPE_VNODE:
@@ -3443,8 +3462,8 @@ kern_proc_filedesc_out(struct proc *p, struct sbuf *sb, ssize_t maxlen)
* the loop continues.
*/
error = export_fd_to_sb(data, type, i, fflags, refcnt,
- offset, fd_cap_rights, efbuf);
- if (error)
+ offset, &rights, efbuf);
+ if (error != 0)
break;
}
FILEDESC_SUNLOCK(fdp);
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index dfd1c46..8bde25a 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -824,9 +824,11 @@ kern_kevent(struct thread *td, int fd, int nchanges, int nevents,
struct kevent *kevp, *changes;
struct kqueue *kq;
struct file *fp;
+ cap_rights_t rights;
int i, n, nerrors, error;
- if ((error = fget(td, fd, CAP_POST_EVENT, &fp)) != 0)
+ error = fget(td, fd, cap_rights_init(&rights, CAP_POST_EVENT), &fp);
+ if (error != 0)
return (error);
if ((error = kqueue_acquire(fp, &kq)) != 0)
goto done_norel;
@@ -964,6 +966,7 @@ kqueue_register(struct kqueue *kq, struct kevent *kev, struct thread *td, int wa
struct filterops *fops;
struct file *fp;
struct knote *kn, *tkn;
+ cap_rights_t rights;
int error, filt, event;
int haskqglobal;
@@ -982,7 +985,8 @@ 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, CAP_POLL_EVENT, &fp);
+ error = fget(td, kev->ident,
+ cap_rights_init(&rights, CAP_POLL_EVENT), &fp);
if (error)
goto done;
@@ -2237,9 +2241,11 @@ kqfd_register(int fd, struct kevent *kev, struct thread *td, int waitok)
{
struct kqueue *kq;
struct file *fp;
+ cap_rights_t rights;
int error;
- if ((error = fget(td, fd, CAP_POST_EVENT, &fp)) != 0)
+ error = fget(td, fd, cap_rights_init(&rights, CAP_POST_EVENT), &fp);
+ if (error != 0)
return (error);
if ((error = kqueue_acquire(fp, &kq)) != 0)
goto noacquire;
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 833fd18..45f732b 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -338,6 +338,7 @@ do_execve(td, args, mac_p)
struct ucred *tracecred = NULL;
#endif
struct vnode *textvp = NULL, *binvp = NULL;
+ cap_rights_t rights;
int credential_changing;
int textset;
#ifdef MAC
@@ -438,7 +439,8 @@ interpret:
/*
* Descriptors opened only with O_EXEC or O_RDONLY are allowed.
*/
- error = fgetvp_exec(td, args->fd, CAP_FEXECVE, &binvp);
+ error = fgetvp_exec(td, args->fd,
+ cap_rights_init(&rights, CAP_FEXECVE), &binvp);
if (error)
goto exec_fail;
vn_lock(binvp, LK_EXCLUSIVE | LK_RETRY);
diff --git a/sys/kern/kern_ktrace.c b/sys/kern/kern_ktrace.c
index e512a33..3b34fb0 100644
--- a/sys/kern/kern_ktrace.c
+++ b/sys/kern/kern_ktrace.c
@@ -779,8 +779,8 @@ ktrstruct(name, data, datalen)
void
ktrcapfail(type, needed, held)
enum ktr_cap_fail_type type;
- cap_rights_t needed;
- cap_rights_t held;
+ const cap_rights_t *needed;
+ const cap_rights_t *held;
{
struct thread *td = curthread;
struct ktr_request *req;
@@ -791,8 +791,8 @@ ktrcapfail(type, needed, held)
return;
kcf = &req->ktr_data.ktr_cap_fail;
kcf->cap_type = type;
- kcf->cap_needed = needed;
- kcf->cap_held = held;
+ kcf->cap_needed = *needed;
+ kcf->cap_held = *held;
ktr_enqueuerequest(td, req);
ktrace_exit(td);
}
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 22fc1b7..1797ebc 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -1726,6 +1726,7 @@ sys_pdkill(td, uap)
{
#ifdef PROCDESC
struct proc *p;
+ cap_rights_t rights;
int error;
AUDIT_ARG_SIGNUM(uap->signum);
@@ -1733,7 +1734,8 @@ sys_pdkill(td, uap)
if ((u_int)uap->signum > _SIG_MAXSIG)
return (EINVAL);
- error = procdesc_find(td, uap->fd, CAP_PDKILL, &p);
+ error = procdesc_find(td, uap->fd,
+ cap_rights_init(&rights, CAP_PDKILL), &p);
if (error)
return (error);
AUDIT_ARG_PROCESS(p);
diff --git a/sys/kern/subr_capability.c b/sys/kern/subr_capability.c
new file mode 100644
index 0000000..7043fe7
--- /dev/null
+++ b/sys/kern/subr_capability.c
@@ -0,0 +1,285 @@
+/*-
+ * Copyright (c) 2013 FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef _KERNEL
+#include <sys/types.h>
+#include <sys/capability.h>
+#include <sys/systm.h>
+
+#include <machine/stdarg.h>
+#else /* !_KERNEL */
+#include <sys/types.h>
+#include <sys/capability.h>
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#endif
+
+#ifdef _KERNEL
+#define assert(exp) KASSERT((exp), ("%s:%u", __func__, __LINE__))
+#endif
+
+static __inline unsigned int
+right_to_index(uint64_t right)
+{
+ static const int bit2idx[] = {
+ -1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1,
+ 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+ };
+ int idx;
+
+ idx = CAPIDXBIT(right);
+ assert(idx == 1 || idx == 2 || idx == 4 || idx == 8 || idx == 16);
+
+ idx = bit2idx[idx];
+ assert(idx >= 0 && idx <= 4);
+
+ return ((unsigned int)idx);
+}
+
+static void
+cap_rights_vset(cap_rights_t *rights, va_list ap)
+{
+ unsigned int i, n;
+ uint64_t right;
+
+ assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
+
+ n = CAPARSIZE(rights);
+
+ for (;;) {
+ right = (uint64_t)va_arg(ap, unsigned long long);
+ if (right == 0)
+ break;
+ assert(CAPRVER(right) == 0);
+ i = right_to_index(right);
+ assert(i < n);
+ assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
+ rights->cr_rights[i] |= right;
+ assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
+ }
+}
+
+static void
+cap_rights_vclear(cap_rights_t *rights, va_list ap)
+{
+ unsigned int i, n;
+ uint64_t right;
+
+ assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
+
+ n = CAPARSIZE(rights);
+
+ for (;;) {
+ right = (uint64_t)va_arg(ap, unsigned long long);
+ if (right == 0)
+ break;
+ assert(CAPRVER(right) == 0);
+ i = right_to_index(right);
+ assert(i < n);
+ assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
+ rights->cr_rights[i] &= ~(right & 0x01FFFFFFFFFFFFFFULL);
+ assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
+ }
+}
+
+static bool
+cap_rights_is_vset(const cap_rights_t *rights, va_list ap)
+{
+ unsigned int i, n;
+ uint64_t right;
+
+ assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
+
+ n = CAPARSIZE(rights);
+
+ for (;;) {
+ right = (uint64_t)va_arg(ap, unsigned long long);
+ if (right == 0)
+ break;
+ assert(CAPRVER(right) == 0);
+ i = right_to_index(right);
+ assert(i < n);
+ assert(CAPIDXBIT(rights->cr_rights[i]) == CAPIDXBIT(right));
+ if ((rights->cr_rights[i] & right) != right)
+ return (false);
+ }
+
+ return (true);
+}
+
+cap_rights_t *
+__cap_rights_init(int version, cap_rights_t *rights, ...)
+{
+ unsigned int n;
+ va_list ap;
+
+ assert(version == CAP_RIGHTS_VERSION_00);
+
+ n = version + 2;
+ memset(rights->cr_rights, 0, sizeof(rights->cr_rights[0]) * n);
+ CAP_NONE(rights);
+ va_start(ap, rights);
+ cap_rights_vset(rights, ap);
+ va_end(ap);
+
+ return (rights);
+}
+
+void
+__cap_rights_set(cap_rights_t *rights, ...)
+{
+ va_list ap;
+
+ assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
+
+ va_start(ap, rights);
+ cap_rights_vset(rights, ap);
+ va_end(ap);
+}
+
+void
+__cap_rights_clear(cap_rights_t *rights, ...)
+{
+ va_list ap;
+
+ assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
+
+ va_start(ap, rights);
+ cap_rights_vclear(rights, ap);
+ va_end(ap);
+}
+
+bool
+__cap_rights_is_set(const cap_rights_t *rights, ...)
+{
+ va_list ap;
+ bool ret;
+
+ assert(CAPVER(rights) == CAP_RIGHTS_VERSION_00);
+
+ va_start(ap, rights);
+ ret = cap_rights_is_vset(rights, ap);
+ va_end(ap);
+
+ return (ret);
+}
+
+bool
+cap_rights_is_valid(const cap_rights_t *rights)
+{
+ cap_rights_t allrights;
+ unsigned int i, j;
+
+ if (CAPVER(rights) != CAP_RIGHTS_VERSION_00)
+ return (false);
+ CAP_ALL(&allrights);
+ if (!cap_rights_contains(&allrights, rights))
+ return (false);
+ for (i = 0; i < CAPARSIZE(rights); i++) {
+ j = right_to_index(rights->cr_rights[i]);
+ if (i != j)
+ return (false);
+ if (i > 0) {
+ if (CAPRVER(rights->cr_rights[i]) != 0)
+ return (false);
+ }
+ }
+
+ return (true);
+}
+
+void
+cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src)
+{
+ unsigned int i, n;
+
+ assert(CAPVER(dst) == CAP_RIGHTS_VERSION_00);
+ assert(CAPVER(src) == CAP_RIGHTS_VERSION_00);
+ assert(CAPVER(dst) == CAPVER(src));
+ assert(cap_rights_is_valid(src));
+ assert(cap_rights_is_valid(dst));
+
+ n = CAPARSIZE(dst);
+
+ for (i = 0; i < n; i++)
+ dst->cr_rights[i] |= src->cr_rights[i];
+
+ assert(cap_rights_is_valid(src));
+ assert(cap_rights_is_valid(dst));
+}
+
+void
+cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src)
+{
+ unsigned int i, n;
+
+ assert(CAPVER(dst) == CAP_RIGHTS_VERSION_00);
+ assert(CAPVER(src) == CAP_RIGHTS_VERSION_00);
+ assert(CAPVER(dst) == CAPVER(src));
+ assert(cap_rights_is_valid(src));
+ assert(cap_rights_is_valid(dst));
+
+ n = CAPARSIZE(dst);
+
+ for (i = 0; i < n; i++) {
+ dst->cr_rights[i] &=
+ ~(src->cr_rights[i] & 0x01FFFFFFFFFFFFFFULL);
+ }
+
+ assert(cap_rights_is_valid(src));
+ assert(cap_rights_is_valid(dst));
+}
+
+bool
+cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little)
+{
+ unsigned int i, n;
+
+ assert(CAPVER(big) == CAP_RIGHTS_VERSION_00);
+ assert(CAPVER(little) == CAP_RIGHTS_VERSION_00);
+ assert(CAPVER(big) == CAPVER(little));
+
+ n = CAPARSIZE(big);
+
+ for (i = 0; i < n; i++) {
+ if ((big->cr_rights[i] & little->cr_rights[i]) !=
+ little->cr_rights[i]) {
+ return (false);
+ }
+ }
+
+ return (true);
+}
diff --git a/sys/kern/sys_capability.c b/sys/kern/sys_capability.c
index 224042e..456f7ac 100644
--- a/sys/kern/sys_capability.c
+++ b/sys/kern/sys_capability.c
@@ -148,16 +148,19 @@ FEATURE(security_capabilities, "Capsicum Capabilities");
MALLOC_DECLARE(M_FILECAPS);
static inline int
-_cap_check(cap_rights_t have, cap_rights_t need, enum ktr_cap_fail_type type)
+_cap_check(const cap_rights_t *havep, const cap_rights_t *needp,
+ enum ktr_cap_fail_type type)
{
+ int i;
-
- if ((need & ~have) != 0) {
+ for (i = 0; i < nitems(havep->cr_rights); i++) {
+ if (!cap_rights_contains(havep, needp)) {
#ifdef KTRACE
- if (KTRPOINT(curthread, KTR_CAPFAIL))
- ktrcapfail(type, need, have);
+ if (KTRPOINT(curthread, KTR_CAPFAIL))
+ ktrcapfail(type, needp, havep);
#endif
- return (ENOTCAPABLE);
+ return (ENOTCAPABLE);
+ }
}
return (0);
}
@@ -166,26 +169,26 @@ _cap_check(cap_rights_t have, cap_rights_t need, enum ktr_cap_fail_type type)
* Test whether a capability grants the requested rights.
*/
int
-cap_check(cap_rights_t have, cap_rights_t need)
+cap_check(const cap_rights_t *havep, const cap_rights_t *needp)
{
- return (_cap_check(have, need, CAPFAIL_NOTCAPABLE));
+ return (_cap_check(havep, needp, CAPFAIL_NOTCAPABLE));
}
/*
* Convert capability rights into VM access flags.
*/
u_char
-cap_rights_to_vmprot(cap_rights_t have)
+cap_rights_to_vmprot(cap_rights_t *havep)
{
u_char maxprot;
maxprot = VM_PROT_NONE;
- if (have & CAP_MMAP_R)
+ if (cap_rights_is_set(havep, CAP_MMAP_R))
maxprot |= VM_PROT_READ;
- if (have & CAP_MMAP_W)
+ if (cap_rights_is_set(havep, CAP_MMAP_W))
maxprot |= VM_PROT_WRITE;
- if (have & CAP_MMAP_X)
+ if (cap_rights_is_set(havep, CAP_MMAP_X))
maxprot |= VM_PROT_EXECUTE;
return (maxprot);
@@ -196,11 +199,11 @@ cap_rights_to_vmprot(cap_rights_t have)
* any other way, as we want to keep all capability permission evaluation in
* this one file.
*/
-cap_rights_t
+cap_rights_t *
cap_rights(struct filedesc *fdp, int fd)
{
- return (fdp->fd_ofiles[fd].fde_rights);
+ return (&fdp->fd_ofiles[fd].fde_rights);
}
/*
@@ -211,32 +214,57 @@ sys_cap_rights_limit(struct thread *td, struct cap_rights_limit_args *uap)
{
struct filedesc *fdp;
cap_rights_t rights;
- int error, fd;
+ int error, fd, version;
- fd = uap->fd;
- rights = uap->rights;
+ cap_rights_init(&rights);
- AUDIT_ARG_FD(fd);
- AUDIT_ARG_RIGHTS(rights);
+ error = copyin(uap->rightsp, &rights, sizeof(rights.cr_rights[0]));
+ if (error != 0)
+ return (error);
+ version = CAPVER(&rights);
+ if (version != CAP_RIGHTS_VERSION_00)
+ return (EINVAL);
- if ((rights & ~CAP_ALL) != 0)
+ error = copyin(uap->rightsp, &rights,
+ sizeof(rights.cr_rights[0]) * CAPARSIZE(&rights));
+ if (error != 0)
+ return (error);
+ /* Check for race. */
+ if (CAPVER(&rights) != version)
return (EINVAL);
+ if (!cap_rights_is_valid(&rights))
+ return (EINVAL);
+
+ if (version != CAP_RIGHTS_VERSION) {
+ rights.cr_rights[0] &= ~(0x3ULL << 62);
+ rights.cr_rights[0] |= ((uint64_t)CAP_RIGHTS_VERSION << 62);
+ }
+#ifdef KTRACE
+ if (KTRPOINT(td, KTR_STRUCT))
+ ktrcaprights(&rights);
+#endif
+
+ fd = uap->fd;
+
+ AUDIT_ARG_FD(fd);
+ AUDIT_ARG_RIGHTS(&rights);
+
fdp = td->td_proc->p_fd;
FILEDESC_XLOCK(fdp);
if (fget_locked(fdp, fd) == NULL) {
FILEDESC_XUNLOCK(fdp);
return (EBADF);
}
- error = _cap_check(cap_rights(fdp, fd), rights, CAPFAIL_INCREASE);
+ error = _cap_check(cap_rights(fdp, fd), &rights, CAPFAIL_INCREASE);
if (error == 0) {
fdp->fd_ofiles[fd].fde_rights = rights;
- if ((rights & CAP_IOCTL) == 0) {
+ if (!cap_rights_is_set(&rights, CAP_IOCTL)) {
free(fdp->fd_ofiles[fd].fde_ioctls, M_FILECAPS);
fdp->fd_ofiles[fd].fde_ioctls = NULL;
fdp->fd_ofiles[fd].fde_nioctls = 0;
}
- if ((rights & CAP_FCNTL) == 0)
+ if (!cap_rights_is_set(&rights, CAP_FCNTL))
fdp->fd_ofiles[fd].fde_fcntls = 0;
}
FILEDESC_XUNLOCK(fdp);
@@ -247,11 +275,14 @@ sys_cap_rights_limit(struct thread *td, struct cap_rights_limit_args *uap)
* System call to query the rights mask associated with a capability.
*/
int
-sys_cap_rights_get(struct thread *td, struct cap_rights_get_args *uap)
+sys___cap_rights_get(struct thread *td, struct __cap_rights_get_args *uap)
{
struct filedesc *fdp;
cap_rights_t rights;
- int fd;
+ int error, fd, i, n;
+
+ if (uap->version != CAP_RIGHTS_VERSION_00)
+ return (EINVAL);
fd = uap->fd;
@@ -263,9 +294,26 @@ sys_cap_rights_get(struct thread *td, struct cap_rights_get_args *uap)
FILEDESC_SUNLOCK(fdp);
return (EBADF);
}
- rights = cap_rights(fdp, fd);
+ rights = *cap_rights(fdp, fd);
FILEDESC_SUNLOCK(fdp);
- return (copyout(&rights, uap->rightsp, sizeof(*uap->rightsp)));
+ n = uap->version + 2;
+ if (uap->version != CAPVER(&rights)) {
+ /*
+ * For older versions we need to check if the descriptor
+ * doesn't contain rights not understood by the caller.
+ * If it does, we have to return an error.
+ */
+ for (i = n; i < CAPARSIZE(&rights); i++) {
+ if ((rights.cr_rights[i] & ~(0x7FULL << 57)) != 0)
+ return (EINVAL);
+ }
+ }
+ error = copyout(&rights, uap->rightsp, sizeof(rights.cr_rights[0]) * n);
+#ifdef KTRACE
+ if (error == 0 && KTRPOINT(td, KTR_STRUCT))
+ ktrcaprights(&rights);
+#endif
+ return (error);
}
/*
@@ -513,65 +561,6 @@ sys_cap_fcntls_get(struct thread *td, struct cap_fcntls_get_args *uap)
return (copyout(&rights, uap->fcntlrightsp, sizeof(rights)));
}
-/*
- * For backward compatibility.
- */
-int
-sys_cap_new(struct thread *td, struct cap_new_args *uap)
-{
- struct filedesc *fdp;
- cap_rights_t rights;
- register_t newfd;
- int error, fd;
-
- fd = uap->fd;
- rights = uap->rights;
-
- AUDIT_ARG_FD(fd);
- AUDIT_ARG_RIGHTS(rights);
-
- if ((rights & ~CAP_ALL) != 0)
- return (EINVAL);
-
- fdp = td->td_proc->p_fd;
- FILEDESC_SLOCK(fdp);
- if (fget_locked(fdp, fd) == NULL) {
- FILEDESC_SUNLOCK(fdp);
- return (EBADF);
- }
- error = _cap_check(cap_rights(fdp, fd), rights, CAPFAIL_INCREASE);
- FILEDESC_SUNLOCK(fdp);
- if (error != 0)
- return (error);
-
- error = do_dup(td, 0, fd, 0, &newfd);
- if (error != 0)
- return (error);
-
- FILEDESC_XLOCK(fdp);
- /*
- * We don't really care about the race between checking capability
- * rights for the source descriptor and now. If capability rights
- * were ok at that earlier point, the process had this descriptor
- * with those rights, so we don't increase them in security sense,
- * the process might have done the cap_new(2) a bit earlier to get
- * the same effect.
- */
- fdp->fd_ofiles[newfd].fde_rights = rights;
- if ((rights & CAP_IOCTL) == 0) {
- free(fdp->fd_ofiles[newfd].fde_ioctls, M_FILECAPS);
- fdp->fd_ofiles[newfd].fde_ioctls = NULL;
- fdp->fd_ofiles[newfd].fde_nioctls = 0;
- }
- if ((rights & CAP_FCNTL) == 0)
- fdp->fd_ofiles[newfd].fde_fcntls = 0;
- FILEDESC_XUNLOCK(fdp);
-
- td->td_retval[0] = newfd;
-
- return (0);
-}
-
#else /* !CAPABILITIES */
/*
@@ -587,7 +576,7 @@ sys_cap_rights_limit(struct thread *td, struct cap_rights_limit_args *uap)
}
int
-sys_cap_rights_get(struct thread *td, struct cap_rights_get_args *uap)
+sys___cap_rights_get(struct thread *td, struct cap___rights_get_args *uap)
{
return (ENOSYS);
@@ -621,11 +610,4 @@ sys_cap_fcntls_get(struct thread *td, struct cap_fcntls_get_args *uap)
return (ENOSYS);
}
-int
-sys_cap_new(struct thread *td, struct cap_new_args *uap)
-{
-
- return (ENOSYS);
-}
-
#endif /* CAPABILITIES */
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
index 44d1a89..5eaa695 100644
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -243,9 +243,10 @@ int
kern_readv(struct thread *td, int fd, struct uio *auio)
{
struct file *fp;
+ cap_rights_t rights;
int error;
- error = fget_read(td, fd, CAP_READ, &fp);
+ error = fget_read(td, fd, cap_rights_init(&rights, CAP_READ), &fp);
if (error)
return (error);
error = dofileread(td, fd, fp, auio, (off_t)-1, 0);
@@ -286,9 +287,10 @@ kern_preadv(td, fd, auio, offset)
off_t offset;
{
struct file *fp;
+ cap_rights_t rights;
int error;
- error = fget_read(td, fd, CAP_PREAD, &fp);
+ error = fget_read(td, fd, cap_rights_init(&rights, CAP_PREAD), &fp);
if (error)
return (error);
if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE))
@@ -452,9 +454,10 @@ int
kern_writev(struct thread *td, int fd, struct uio *auio)
{
struct file *fp;
+ cap_rights_t rights;
int error;
- error = fget_write(td, fd, CAP_WRITE, &fp);
+ error = fget_write(td, fd, cap_rights_init(&rights, CAP_WRITE), &fp);
if (error)
return (error);
error = dofilewrite(td, fd, fp, auio, (off_t)-1, 0);
@@ -495,9 +498,10 @@ kern_pwritev(td, fd, auio, offset)
off_t offset;
{
struct file *fp;
+ cap_rights_t rights;
int error;
- error = fget_write(td, fd, CAP_PWRITE, &fp);
+ error = fget_write(td, fd, cap_rights_init(&rights, CAP_PWRITE), &fp);
if (error)
return (error);
if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE))
@@ -575,12 +579,13 @@ kern_ftruncate(td, fd, length)
off_t length;
{
struct file *fp;
+ cap_rights_t rights;
int error;
AUDIT_ARG_FD(fd);
if (length < 0)
return (EINVAL);
- error = fget(td, fd, CAP_FTRUNCATE, &fp);
+ error = fget(td, fd, cap_rights_init(&rights, CAP_FTRUNCATE), &fp);
if (error)
return (error);
AUDIT_ARG_FILE(td->td_proc, fp);
@@ -705,6 +710,9 @@ kern_ioctl(struct thread *td, int fd, u_long com, caddr_t data)
{
struct file *fp;
struct filedesc *fdp;
+#ifndef CAPABILITIES
+ cap_rights_t rights;
+#endif
int error, tmp, locked;
AUDIT_ARG_FD(fd);
@@ -743,7 +751,8 @@ kern_ioctl(struct thread *td, int fd, u_long com, caddr_t data)
locked = LA_UNLOCKED;
}
#else
- if ((error = fget(td, fd, CAP_IOCTL, &fp)) != 0) {
+ error = fget(td, fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0) {
fp = NULL;
goto out;
}
@@ -1180,8 +1189,10 @@ selsetbits(fd_mask **ibits, fd_mask **obits, int idx, fd_mask bit, int events)
static __inline int
getselfd_cap(struct filedesc *fdp, int fd, struct file **fpp)
{
+ cap_rights_t rights;
- return (fget_unlocked(fdp, fd, CAP_POLL_EVENT, 0, fpp, NULL));
+ return (fget_unlocked(fdp, fd, cap_rights_init(&rights, CAP_POLL_EVENT),
+ 0, fpp, NULL));
}
/*
@@ -1357,6 +1368,7 @@ pollrescan(struct thread *td)
struct filedesc *fdp;
struct file *fp;
struct pollfd *fd;
+ cap_rights_t rights;
int n;
n = 0;
@@ -1373,7 +1385,8 @@ pollrescan(struct thread *td)
fp = fdp->fd_ofiles[fd->fd].fde_file;
#ifdef CAPABILITIES
if (fp == NULL ||
- cap_check(cap_rights(fdp, fd->fd), CAP_POLL_EVENT) != 0)
+ cap_check(cap_rights(fdp, fd->fd),
+ cap_rights_init(&rights, CAP_POLL_EVENT)) != 0)
#else
if (fp == NULL)
#endif
@@ -1431,6 +1444,7 @@ pollscan(td, fds, nfd)
{
struct filedesc *fdp = td->td_proc->p_fd;
struct file *fp;
+ cap_rights_t rights;
int i, n = 0;
FILEDESC_SLOCK(fdp);
@@ -1445,7 +1459,7 @@ pollscan(td, fds, nfd)
#ifdef CAPABILITIES
if (fp == NULL ||
cap_check(cap_rights(fdp, fds->fd),
- CAP_POLL_EVENT) != 0)
+ cap_rights_init(&rights, CAP_POLL_EVENT)) != 0)
#else
if (fp == NULL)
#endif
diff --git a/sys/kern/sys_procdesc.c b/sys/kern/sys_procdesc.c
index bacaf18..4bafeab 100644
--- a/sys/kern/sys_procdesc.c
+++ b/sys/kern/sys_procdesc.c
@@ -138,14 +138,14 @@ SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_ANY, procdesc_init, NULL);
* died.
*/
int
-procdesc_find(struct thread *td, int fd, cap_rights_t rights,
+procdesc_find(struct thread *td, int fd, cap_rights_t *rightsp,
struct proc **p)
{
struct procdesc *pd;
struct file *fp;
int error;
- error = fget(td, fd, rights, &fp);
+ error = fget(td, fd, rightsp, &fp);
if (error)
return (error);
if (fp->f_type != DTYPE_PROCDESC) {
@@ -185,12 +185,12 @@ procdesc_pid(struct file *fp_procdesc)
* Retrieve the PID associated with a process descriptor.
*/
int
-kern_pdgetpid(struct thread *td, int fd, cap_rights_t rights, pid_t *pidp)
+kern_pdgetpid(struct thread *td, int fd, cap_rights_t *rightsp, pid_t *pidp)
{
struct file *fp;
int error;
- error = fget(td, fd, rights, &fp);
+ error = fget(td, fd, rightsp, &fp);
if (error)
return (error);
if (fp->f_type != DTYPE_PROCDESC) {
@@ -209,11 +209,13 @@ out:
int
sys_pdgetpid(struct thread *td, struct pdgetpid_args *uap)
{
+ cap_rights_t rights;
pid_t pid;
int error;
AUDIT_ARG_FD(uap->fd);
- error = kern_pdgetpid(td, uap->fd, CAP_PDGETPID, &pid);
+ error = kern_pdgetpid(td, uap->fd,
+ cap_rights_init(&rights, CAP_PDGETPID), &pid);
if (error == 0)
error = copyout(&pid, uap->pidp, sizeof(pid));
return (error);
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index 789f95a5..e19e310 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -917,9 +917,9 @@
512 AUE_SHMCTL NOSTD { int shmctl(int shmid, int cmd, \
struct shmid_ds *buf); }
513 AUE_LPATHCONF STD { int lpathconf(char *path, int name); }
-514 AUE_CAP_NEW STD { int cap_new(int fd, uint64_t rights); }
-515 AUE_CAP_RIGHTS_GET STD { int cap_rights_get(int fd, \
- uint64_t *rightsp); }
+514 AUE_NULL OBSOL cap_new
+515 AUE_CAP_RIGHTS_GET STD { int __cap_rights_get(int version, \
+ int fd, cap_rights_t *rightsp); }
516 AUE_CAP_ENTER STD { int cap_enter(void); }
517 AUE_CAP_GETMODE STD { int cap_getmode(u_int *modep); }
518 AUE_PDFORK STD { int pdfork(int *fdp, int flags); }
@@ -957,7 +957,7 @@
struct __wrusage *wrusage, \
siginfo_t *info); }
533 AUE_CAP_RIGHTS_LIMIT STD { int cap_rights_limit(int fd, \
- uint64_t rights); }
+ cap_rights_t *rightsp); }
534 AUE_CAP_IOCTLS_LIMIT STD { int cap_ioctls_limit(int fd, \
const u_long *cmds, size_t ncmds); }
535 AUE_CAP_IOCTLS_GET STD { ssize_t cap_ioctls_get(int fd, \
diff --git a/sys/kern/tty.c b/sys/kern/tty.c
index 02eccd7..4fce607 100644
--- a/sys/kern/tty.c
+++ b/sys/kern/tty.c
@@ -1837,11 +1837,13 @@ ttyhook_register(struct tty **rtp, struct proc *p, int fd,
struct cdev *dev;
struct cdevsw *cdp;
struct filedesc *fdp;
+ cap_rights_t rights;
int error, ref;
/* Validate the file descriptor. */
fdp = p->p_fd;
- error = fget_unlocked(fdp, fd, CAP_TTYHOOK, 0, &fp, NULL);
+ error = fget_unlocked(fdp, fd, cap_rights_init(&rights, CAP_TTYHOOK),
+ 0, &fp, NULL);
if (error != 0)
return (error);
if (fp->f_ops == &badfileops) {
diff --git a/sys/kern/uipc_mqueue.c b/sys/kern/uipc_mqueue.c
index 62c54d3..6a1bf76 100644
--- a/sys/kern/uipc_mqueue.c
+++ b/sys/kern/uipc_mqueue.c
@@ -2086,19 +2086,19 @@ sys_kmq_unlink(struct thread *td, struct kmq_unlink_args *uap)
return (error);
}
-typedef int (*_fgetf)(struct thread *, int, cap_rights_t, 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, cap_rights_t rights, _fgetf func,
+_getmq(struct thread *td, int fd, cap_rights_t *rightsp, _fgetf func,
struct file **fpp, struct mqfs_node **ppn, struct mqueue **pmq)
{
struct mqfs_node *pn;
int error;
- error = func(td, fd, rights, fpp);
+ error = func(td, fd, rightsp, fpp);
if (error)
return (error);
if (&mqueueops != (*fpp)->f_ops) {
@@ -2117,21 +2117,30 @@ static __inline int
getmq(struct thread *td, int fd, struct file **fpp, struct mqfs_node **ppn,
struct mqueue **pmq)
{
- return _getmq(td, fd, CAP_POLL_EVENT, fget, fpp, ppn, pmq);
+ cap_rights_t rights;
+
+ return _getmq(td, fd, cap_rights_init(&rights, CAP_POLL_EVENT), 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, CAP_READ, fget_read, fpp, ppn, pmq);
+ cap_rights_t rights;
+
+ return _getmq(td, fd, cap_rights_init(&rights, 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, CAP_WRITE, fget_write, fpp, ppn, pmq);
+ cap_rights_t rights;
+
+ return _getmq(td, fd, cap_rights_init(&rights, CAP_WRITE), fget_write,
+ fpp, ppn, pmq);
}
static int
@@ -2238,6 +2247,7 @@ sys_kmq_timedsend(struct thread *td, struct kmq_timedsend_args *uap)
static int
kern_kmq_notify(struct thread *td, int mqd, struct sigevent *sigev)
{
+ cap_rights_t rights;
struct filedesc *fdp;
struct proc *p;
struct mqueue *mq;
@@ -2269,7 +2279,8 @@ again:
goto out;
}
#ifdef CAPABILITIES
- error = cap_check(cap_rights(fdp, mqd), CAP_POLL_EVENT);
+ error = cap_check(cap_rights(fdp, mqd),
+ cap_rights_init(&rights, CAP_POLL_EVENT));
if (error) {
FILEDESC_SUNLOCK(fdp);
goto out;
diff --git a/sys/kern/uipc_sem.c b/sys/kern/uipc_sem.c
index 8c86cc4..f641654 100644
--- a/sys/kern/uipc_sem.c
+++ b/sys/kern/uipc_sem.c
@@ -116,7 +116,7 @@ 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, cap_rights_t rights,
+static int ksem_get(struct thread *td, semid_t id, cap_rights_t *rightsp,
struct file **fpp);
static struct ksem *ksem_hold(struct ksem *ks);
static void ksem_insert(char *path, Fnv32_t fnv, struct ksem *ks);
@@ -600,13 +600,14 @@ ksem_create(struct thread *td, const char *name, semid_t *semidp, mode_t mode,
}
static int
-ksem_get(struct thread *td, semid_t id, cap_rights_t rights, struct file **fpp)
+ksem_get(struct thread *td, semid_t id, cap_rights_t *rightsp,
+ struct file **fpp)
{
struct ksem *ks;
struct file *fp;
int error;
- error = fget(td, id, rights, &fp);
+ error = fget(td, id, rightsp, &fp);
if (error)
return (EINVAL);
if (fp->f_type != DTYPE_SEM) {
@@ -720,11 +721,13 @@ struct ksem_post_args {
int
sys_ksem_post(struct thread *td, struct ksem_post_args *uap)
{
+ cap_rights_t rights;
struct file *fp;
struct ksem *ks;
int error;
- error = ksem_get(td, uap->id, CAP_SEM_POST, &fp);
+ error = ksem_get(td, uap->id,
+ cap_rights_init(&rights, CAP_SEM_POST), &fp);
if (error)
return (error);
ks = fp->f_data;
@@ -809,12 +812,13 @@ kern_sem_wait(struct thread *td, semid_t id, int tryflag,
{
struct timespec ts1, ts2;
struct timeval tv;
+ cap_rights_t rights;
struct file *fp;
struct ksem *ks;
int error;
DP((">>> kern_sem_wait entered! pid=%d\n", (int)td->td_proc->p_pid));
- error = ksem_get(td, id, CAP_SEM_WAIT, &fp);
+ error = ksem_get(td, id, cap_rights_init(&rights, CAP_SEM_WAIT), &fp);
if (error)
return (error);
ks = fp->f_data;
@@ -876,11 +880,13 @@ struct ksem_getvalue_args {
int
sys_ksem_getvalue(struct thread *td, struct ksem_getvalue_args *uap)
{
+ cap_rights_t rights;
struct file *fp;
struct ksem *ks;
int error, val;
- error = ksem_get(td, uap->id, CAP_SEM_GETVALUE, &fp);
+ error = ksem_get(td, uap->id,
+ cap_rights_init(&rights, CAP_SEM_GETVALUE), &fp);
if (error)
return (error);
ks = fp->f_data;
diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c
index 72663a2..7e25da8 100644
--- a/sys/kern/uipc_syscalls.c
+++ b/sys/kern/uipc_syscalls.c
@@ -164,13 +164,13 @@ SYSCTL_PROC(_kern_ipc, OID_AUTO, sfstat, CTLTYPE_OPAQUE | CTLFLAG_RW,
* A reference on the file entry is held upon returning.
*/
static int
-getsock_cap(struct filedesc *fdp, int fd, cap_rights_t rights,
+getsock_cap(struct filedesc *fdp, int fd, cap_rights_t *rightsp,
struct file **fpp, u_int *fflagp)
{
struct file *fp;
int error;
- error = fget_unlocked(fdp, fd, rights, 0, &fp, NULL);
+ error = fget_unlocked(fdp, fd, rightsp, 0, &fp, NULL);
if (error != 0)
return (error);
if (fp->f_type != DTYPE_SOCKET) {
@@ -267,11 +267,13 @@ kern_bindat(struct thread *td, int dirfd, int fd, struct sockaddr *sa)
{
struct socket *so;
struct file *fp;
+ cap_rights_t rights;
int error;
AUDIT_ARG_FD(fd);
AUDIT_ARG_SOCKADDR(td, dirfd, sa);
- error = getsock_cap(td->td_proc->p_fd, fd, CAP_BIND, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, fd,
+ cap_rights_init(&rights, CAP_BIND), &fp, NULL);
if (error)
return (error);
so = fp->f_data;
@@ -334,10 +336,12 @@ sys_listen(td, uap)
{
struct socket *so;
struct file *fp;
+ cap_rights_t rights;
int error;
AUDIT_ARG_FD(uap->s);
- error = getsock_cap(td->td_proc->p_fd, uap->s, CAP_LISTEN, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, uap->s,
+ cap_rights_init(&rights, CAP_LISTEN), &fp, NULL);
if (error == 0) {
so = fp->f_data;
#ifdef MAC
@@ -419,6 +423,7 @@ kern_accept4(struct thread *td, int s, struct sockaddr **name,
int error;
struct socket *head, *so;
int fd;
+ cap_rights_t rights;
u_int fflag;
pid_t pgid;
int tmp;
@@ -428,7 +433,8 @@ kern_accept4(struct thread *td, int s, struct sockaddr **name,
AUDIT_ARG_FD(s);
fdp = td->td_proc->p_fd;
- error = getsock_cap(fdp, s, CAP_ACCEPT, &headfp, &fflag);
+ error = getsock_cap(fdp, s, cap_rights_init(&rights, CAP_ACCEPT),
+ &headfp, &fflag);
if (error)
return (error);
head = headfp->f_data;
@@ -629,12 +635,14 @@ kern_connectat(struct thread *td, int dirfd, int fd, struct sockaddr *sa)
{
struct socket *so;
struct file *fp;
+ cap_rights_t rights;
int error;
int interrupted = 0;
AUDIT_ARG_FD(fd);
AUDIT_ARG_SOCKADDR(td, dirfd, sa);
- error = getsock_cap(td->td_proc->p_fd, fd, CAP_CONNECT, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, fd,
+ cap_rights_init(&rights, CAP_CONNECT), &fp, NULL);
if (error)
return (error);
so = fp->f_data;
@@ -898,12 +906,12 @@ kern_sendit(td, s, mp, flags, control, segflg)
#endif
AUDIT_ARG_FD(s);
- rights = CAP_SEND;
+ cap_rights_init(&rights, CAP_SEND);
if (mp->msg_name != NULL) {
AUDIT_ARG_SOCKADDR(td, AT_FDCWD, mp->msg_name);
- rights |= CAP_CONNECT;
+ cap_rights_set(&rights, CAP_CONNECT);
}
- error = getsock_cap(td->td_proc->p_fd, s, rights, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, s, &rights, &fp, NULL);
if (error)
return (error);
so = (struct socket *)fp->f_data;
@@ -1099,6 +1107,7 @@ kern_recvit(td, s, mp, fromseg, controlp)
struct file *fp;
struct socket *so;
struct sockaddr *fromsa = NULL;
+ cap_rights_t rights;
#ifdef KTRACE
struct uio *ktruio = NULL;
#endif
@@ -1107,7 +1116,8 @@ kern_recvit(td, s, mp, fromseg, controlp)
*controlp = NULL;
AUDIT_ARG_FD(s);
- error = getsock_cap(td->td_proc->p_fd, s, CAP_RECV, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, s,
+ cap_rights_init(&rights, CAP_RECV), &fp, NULL);
if (error)
return (error);
so = fp->f_data;
@@ -1420,11 +1430,12 @@ sys_shutdown(td, uap)
{
struct socket *so;
struct file *fp;
+ cap_rights_t rights;
int error;
AUDIT_ARG_FD(uap->s);
- error = getsock_cap(td->td_proc->p_fd, uap->s, CAP_SHUTDOWN, &fp,
- NULL);
+ error = getsock_cap(td->td_proc->p_fd, uap->s,
+ cap_rights_init(&rights, CAP_SHUTDOWN), &fp, NULL);
if (error == 0) {
so = fp->f_data;
error = soshutdown(so, uap->how);
@@ -1464,6 +1475,7 @@ kern_setsockopt(td, s, level, name, val, valseg, valsize)
struct socket *so;
struct file *fp;
struct sockopt sopt;
+ cap_rights_t rights;
if (val == NULL && valsize != 0)
return (EFAULT);
@@ -1487,7 +1499,8 @@ kern_setsockopt(td, s, level, name, val, valseg, valsize)
}
AUDIT_ARG_FD(s);
- error = getsock_cap(td->td_proc->p_fd, s, CAP_SETSOCKOPT, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, s,
+ cap_rights_init(&rights, CAP_SETSOCKOPT), &fp, NULL);
if (error == 0) {
so = fp->f_data;
error = sosetopt(so, &sopt);
@@ -1543,6 +1556,7 @@ kern_getsockopt(td, s, level, name, val, valseg, valsize)
struct socket *so;
struct file *fp;
struct sockopt sopt;
+ cap_rights_t rights;
if (val == NULL)
*valsize = 0;
@@ -1566,7 +1580,8 @@ kern_getsockopt(td, s, level, name, val, valseg, valsize)
}
AUDIT_ARG_FD(s);
- error = getsock_cap(td->td_proc->p_fd, s, CAP_GETSOCKOPT, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, s,
+ cap_rights_init(&rights, CAP_GETSOCKOPT), &fp, NULL);
if (error == 0) {
so = fp->f_data;
error = sogetopt(so, &sopt);
@@ -1621,11 +1636,13 @@ kern_getsockname(struct thread *td, int fd, struct sockaddr **sa,
{
struct socket *so;
struct file *fp;
+ cap_rights_t rights;
socklen_t len;
int error;
AUDIT_ARG_FD(fd);
- error = getsock_cap(td->td_proc->p_fd, fd, CAP_GETSOCKNAME, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, fd,
+ cap_rights_init(&rights, CAP_GETSOCKNAME), &fp, NULL);
if (error)
return (error);
so = fp->f_data;
@@ -1718,11 +1735,13 @@ kern_getpeername(struct thread *td, int fd, struct sockaddr **sa,
{
struct socket *so;
struct file *fp;
+ cap_rights_t rights;
socklen_t len;
int error;
AUDIT_ARG_FD(fd);
- error = getsock_cap(td->td_proc->p_fd, fd, CAP_GETPEERNAME, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, fd,
+ cap_rights_init(&rights, CAP_GETPEERNAME), &fp, NULL);
if (error)
return (error);
so = fp->f_data;
@@ -1907,6 +1926,7 @@ do_sendfile(struct thread *td, struct sendfile_args *uap, int compat)
struct sf_hdtr hdtr;
struct uio *hdr_uio, *trl_uio;
struct file *fp;
+ cap_rights_t rights;
int error;
if (uap->offset < 0)
@@ -1937,8 +1957,10 @@ do_sendfile(struct thread *td, struct sendfile_args *uap, int compat)
* sendfile(2) can start at any offset within a file so we require
* CAP_READ+CAP_SEEK = CAP_PREAD.
*/
- if ((error = fget_read(td, uap->fd, CAP_PREAD, &fp)) != 0)
+ if ((error = fget_read(td, uap->fd,
+ cap_rights_init(&rights, CAP_PREAD), &fp)) != 0) {
goto out;
+ }
error = fo_sendfile(fp, uap->s, hdr_uio, trl_uio, uap->offset,
uap->nbytes, uap->sbytes, uap->flags, compat ? SFK_COMPAT : 0, td);
@@ -1983,6 +2005,7 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
struct sf_buf *sf;
struct vm_page *pg;
struct vattr va;
+ cap_rights_t rights;
off_t off, xfsize, fsbytes = 0, sbytes = 0, rem = 0;
int error, hdrlen = 0, mnw = 0;
int bsize;
@@ -2030,8 +2053,9 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
* The socket must be a stream socket and connected.
* Remember if it a blocking or non-blocking socket.
*/
- if ((error = getsock_cap(td->td_proc->p_fd, sockfd, CAP_SEND,
- &sock_fp, NULL)) != 0)
+ error = getsock_cap(td->td_proc->p_fd, sockfd,
+ cap_rights_init(&rights, CAP_SEND), &sock_fp, NULL);
+ if (error != 0)
goto out;
so = sock_fp->f_data;
if (so->so_type != SOCK_STREAM) {
@@ -2463,10 +2487,12 @@ sys_sctp_peeloff(td, uap)
int error;
struct socket *head, *so;
int fd;
+ cap_rights_t rights;
u_int fflag;
AUDIT_ARG_FD(uap->sd);
- error = fgetsock(td, uap->sd, CAP_PEELOFF, &head, &fflag);
+ error = fgetsock(td, uap->sd, cap_rights_init(&rights, CAP_PEELOFF),
+ &head, &fflag);
if (error)
goto done2;
if (head->so_proto->pr_protocol != IPPROTO_SCTP) {
@@ -2574,18 +2600,18 @@ sys_sctp_generic_sendmsg (td, uap)
u_sinfo = &sinfo;
}
- rights = CAP_SEND;
+ cap_rights_init(&rights, CAP_SEND);
if (uap->tolen) {
error = getsockaddr(&to, uap->to, uap->tolen);
if (error) {
to = NULL;
goto sctp_bad2;
}
- rights |= CAP_CONNECT;
+ cap_rights_set(&rights, CAP_CONNECT);
}
AUDIT_ARG_FD(uap->sd);
- error = getsock_cap(td->td_proc->p_fd, uap->sd, rights, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, uap->sd, &rights, &fp, NULL);
if (error)
goto sctp_bad;
#ifdef KTRACE
@@ -2685,18 +2711,18 @@ sys_sctp_generic_sendmsg_iov(td, uap)
return (error);
u_sinfo = &sinfo;
}
- rights = CAP_SEND;
+ cap_rights_init(&rights, CAP_SEND);
if (uap->tolen) {
error = getsockaddr(&to, uap->to, uap->tolen);
if (error) {
to = NULL;
goto sctp_bad2;
}
- rights |= CAP_CONNECT;
+ cap_rights_set(&rights, CAP_CONNECT);
}
AUDIT_ARG_FD(uap->sd);
- error = getsock_cap(td->td_proc->p_fd, uap->sd, rights, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, uap->sd, &rights, &fp, NULL);
if (error)
goto sctp_bad1;
@@ -2804,12 +2830,14 @@ sys_sctp_generic_recvmsg(td, uap)
ssize_t len;
int i, msg_flags;
int error = 0;
+ cap_rights_t rights;
#ifdef KTRACE
struct uio *ktruio = NULL;
#endif
AUDIT_ARG_FD(uap->sd);
- error = getsock_cap(td->td_proc->p_fd, uap->sd, CAP_RECV, &fp, NULL);
+ error = getsock_cap(td->td_proc->p_fd, uap->sd,
+ cap_rights_init(&rights, CAP_RECV), &fp, NULL);
if (error) {
return (error);
}
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index 7a4db04..c0a5d2e 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -464,6 +464,7 @@ uipc_bindat(int fd, struct socket *so, struct sockaddr *nam, struct thread *td)
struct unpcb *unp;
struct vnode *vp;
struct mount *mp;
+ cap_rights_t rights;
char *buf;
unp = sotounpcb(so);
@@ -502,7 +503,7 @@ uipc_bindat(int fd, struct socket *so, struct sockaddr *nam, struct thread *td)
restart:
NDINIT_ATRIGHTS(&nd, CREATE, NOFOLLOW | LOCKPARENT | SAVENAME,
- UIO_SYSSPACE, buf, fd, CAP_BINDAT, td);
+ UIO_SYSSPACE, buf, fd, cap_rights_init(&rights, CAP_BINDAT), td);
/* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
error = namei(&nd);
if (error)
@@ -1276,10 +1277,11 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam,
struct vnode *vp;
struct socket *so2, *so3;
struct unpcb *unp, *unp2, *unp3;
- int error, len;
struct nameidata nd;
char buf[SOCK_MAXADDRLEN];
struct sockaddr *sa;
+ cap_rights_t rights;
+ int error, len;
UNP_LINK_WLOCK_ASSERT();
@@ -1305,7 +1307,7 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam,
sa = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK);
NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF,
- UIO_SYSSPACE, buf, fd, CAP_CONNECTAT, td);
+ UIO_SYSSPACE, buf, fd, cap_rights_init(&rights, CAP_CONNECTAT), td);
error = namei(&nd);
if (error)
vp = NULL;
diff --git a/sys/kern/vfs_acl.c b/sys/kern/vfs_acl.c
index 1c9923d..362792b 100644
--- a/sys/kern/vfs_acl.c
+++ b/sys/kern/vfs_acl.c
@@ -399,9 +399,11 @@ int
sys___acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap)
{
struct file *fp;
+ cap_rights_t rights;
int error;
- error = getvnode(td->td_proc->p_fd, uap->filedes, CAP_ACL_GET, &fp);
+ error = getvnode(td->td_proc->p_fd, uap->filedes,
+ cap_rights_init(&rights, CAP_ACL_GET), &fp);
if (error == 0) {
error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp);
fdrop(fp, td);
@@ -416,9 +418,11 @@ int
sys___acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap)
{
struct file *fp;
+ cap_rights_t rights;
int error;
- error = getvnode(td->td_proc->p_fd, uap->filedes, CAP_ACL_SET, &fp);
+ error = getvnode(td->td_proc->p_fd, uap->filedes,
+ cap_rights_init(&rights, CAP_ACL_SET), &fp);
if (error == 0) {
error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp);
fdrop(fp, td);
@@ -469,10 +473,11 @@ int
sys___acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap)
{
struct file *fp;
+ cap_rights_t rights;
int error;
- error = getvnode(td->td_proc->p_fd, uap->filedes, CAP_ACL_DELETE,
- &fp);
+ error = getvnode(td->td_proc->p_fd, uap->filedes,
+ cap_rights_init(&rights, CAP_ACL_DELETE), &fp);
if (error == 0) {
error = vacl_delete(td, fp->f_vnode, uap->type);
fdrop(fp, td);
@@ -523,10 +528,11 @@ int
sys___acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap)
{
struct file *fp;
+ cap_rights_t rights;
int error;
- error = getvnode(td->td_proc->p_fd, uap->filedes, CAP_ACL_CHECK,
- &fp);
+ error = getvnode(td->td_proc->p_fd, uap->filedes,
+ cap_rights_init(&rights, CAP_ACL_CHECK), &fp);
if (error == 0) {
error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp);
fdrop(fp, td);
diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c
index a66f7c2..9f3adaf 100644
--- a/sys/kern/vfs_aio.c
+++ b/sys/kern/vfs_aio.c
@@ -1567,6 +1567,7 @@ aio_aqueue(struct thread *td, struct aiocb *job, struct aioliojob *lj,
int type, struct aiocb_ops *ops)
{
struct proc *p = td->td_proc;
+ cap_rights_t rights;
struct file *fp;
struct socket *so;
struct aiocblist *aiocbe, *cb;
@@ -1647,19 +1648,21 @@ aio_aqueue(struct thread *td, struct aiocb *job, struct aioliojob *lj,
fd = aiocbe->uaiocb.aio_fildes;
switch (opcode) {
case LIO_WRITE:
- error = fget_write(td, fd, CAP_PWRITE, &fp);
+ error = fget_write(td, fd,
+ cap_rights_init(&rights, CAP_PWRITE), &fp);
break;
case LIO_READ:
- error = fget_read(td, fd, CAP_PREAD, &fp);
+ error = fget_read(td, fd,
+ cap_rights_init(&rights, CAP_PREAD), &fp);
break;
case LIO_SYNC:
- error = fget(td, fd, CAP_FSYNC, &fp);
+ error = fget(td, fd, cap_rights_init(&rights, CAP_FSYNC), &fp);
break;
case LIO_MLOCK:
fp = NULL;
break;
case LIO_NOP:
- error = fget(td, fd, CAP_NONE, &fp);
+ error = fget(td, fd, cap_rights_init(&rights), &fp);
break;
default:
error = EINVAL;
diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c
index 700a70c..bc7b942 100644
--- a/sys/kern/vfs_extattr.c
+++ b/sys/kern/vfs_extattr.c
@@ -216,6 +216,7 @@ sys_extattr_set_fd(td, uap)
{
struct file *fp;
char attrname[EXTATTR_MAXNAMELEN];
+ cap_rights_t rights;
int error;
AUDIT_ARG_FD(uap->fd);
@@ -225,7 +226,8 @@ sys_extattr_set_fd(td, uap)
return (error);
AUDIT_ARG_TEXT(attrname);
- error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_SET, &fp);
+ error = getvnode(td->td_proc->p_fd, uap->fd,
+ cap_rights_init(&rights, CAP_EXTATTR_SET), &fp);
if (error)
return (error);
@@ -389,6 +391,7 @@ sys_extattr_get_fd(td, uap)
{
struct file *fp;
char attrname[EXTATTR_MAXNAMELEN];
+ cap_rights_t rights;
int error;
AUDIT_ARG_FD(uap->fd);
@@ -398,7 +401,8 @@ sys_extattr_get_fd(td, uap)
return (error);
AUDIT_ARG_TEXT(attrname);
- error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_GET, &fp);
+ error = getvnode(td->td_proc->p_fd, uap->fd,
+ cap_rights_init(&rights, CAP_EXTATTR_GET), &fp);
if (error)
return (error);
@@ -531,6 +535,7 @@ sys_extattr_delete_fd(td, uap)
{
struct file *fp;
char attrname[EXTATTR_MAXNAMELEN];
+ cap_rights_t rights;
int error;
AUDIT_ARG_FD(uap->fd);
@@ -540,8 +545,8 @@ sys_extattr_delete_fd(td, uap)
return (error);
AUDIT_ARG_TEXT(attrname);
- error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_DELETE,
- &fp);
+ error = getvnode(td->td_proc->p_fd, uap->fd,
+ cap_rights_init(&rights, CAP_EXTATTR_DELETE), &fp);
if (error)
return (error);
@@ -687,11 +692,13 @@ sys_extattr_list_fd(td, uap)
} */ *uap;
{
struct file *fp;
+ cap_rights_t rights;
int error;
AUDIT_ARG_FD(uap->fd);
AUDIT_ARG_VALUE(uap->attrnamespace);
- error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_LIST, &fp);
+ error = getvnode(td->td_proc->p_fd, uap->fd,
+ cap_rights_init(&rights, CAP_EXTATTR_LIST), &fp);
if (error)
return (error);
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index 7fe1908..d4d0166 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -222,20 +222,26 @@ namei(struct nameidata *ndp)
dp = ndp->ni_startdir;
error = 0;
} else if (ndp->ni_dirfd != AT_FDCWD) {
+ cap_rights_t rights;
+
+ rights = ndp->ni_rightsneeded;
+ cap_rights_set(&rights, CAP_LOOKUP);
+
if (cnp->cn_flags & AUDITVNODE1)
AUDIT_ARG_ATFD1(ndp->ni_dirfd);
if (cnp->cn_flags & AUDITVNODE2)
AUDIT_ARG_ATFD2(ndp->ni_dirfd);
error = fgetvp_rights(td, ndp->ni_dirfd,
- ndp->ni_rightsneeded | CAP_LOOKUP,
- &ndp->ni_filecaps, &dp);
+ &rights, &ndp->ni_filecaps, &dp);
#ifdef CAPABILITIES
/*
* If file descriptor doesn't have all rights,
* all lookups relative to it must also be
* strictly relative.
*/
- if (ndp->ni_filecaps.fc_rights != CAP_ALL ||
+ CAP_ALL(&rights);
+ if (!cap_rights_contains(&ndp->ni_filecaps.fc_rights,
+ &rights) ||
ndp->ni_filecaps.fc_fcntls != CAP_FCNTL_ALL ||
ndp->ni_filecaps.fc_nioctls != -1) {
ndp->ni_strictrelative = 1;
@@ -1059,6 +1065,27 @@ bad:
return (error);
}
+void
+NDINIT_ALL(struct nameidata *ndp, u_long op, u_long flags, enum uio_seg segflg,
+ const char *namep, int dirfd, struct vnode *startdir, cap_rights_t *rightsp,
+ struct thread *td)
+{
+
+ ndp->ni_cnd.cn_nameiop = op;
+ ndp->ni_cnd.cn_flags = flags;
+ ndp->ni_segflg = segflg;
+ ndp->ni_dirp = namep;
+ ndp->ni_dirfd = dirfd;
+ ndp->ni_startdir = startdir;
+ ndp->ni_strictrelative = 0;
+ if (rightsp != NULL)
+ ndp->ni_rightsneeded = *rightsp;
+ else
+ cap_rights_init(&ndp->ni_rightsneeded);
+ filecaps_init(&ndp->ni_filecaps);
+ ndp->ni_cnd.cn_thread = td;
+}
+
/*
* Free data allocated by namei(); see namei(9) for details.
*/
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 2877ad2..7df315d 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -367,10 +367,12 @@ kern_fstatfs(struct thread *td, int fd, struct statfs *buf)
struct mount *mp;
struct statfs *sp, sb;
struct vnode *vp;
+ cap_rights_t rights;
int error;
AUDIT_ARG_FD(fd);
- error = getvnode(td->td_proc->p_fd, fd, CAP_FSTATFS, &fp);
+ error = getvnode(td->td_proc->p_fd, fd,
+ cap_rights_init(&rights, CAP_FSTATFS), &fp);
if (error)
return (error);
vp = fp->f_vnode;
@@ -730,10 +732,13 @@ sys_fchdir(td, uap)
struct vnode *vp, *tdp, *vpold;
struct mount *mp;
struct file *fp;
+ cap_rights_t rights;
int error;
AUDIT_ARG_FD(uap->fd);
- if ((error = getvnode(fdp, uap->fd, CAP_FCHDIR, &fp)) != 0)
+ error = getvnode(fdp, uap->fd, cap_rights_init(&rights, CAP_FCHDIR),
+ &fp);
+ if (error != 0)
return (error);
vp = fp->f_vnode;
VREF(vp);
@@ -954,42 +959,39 @@ change_root(vp, td)
return (0);
}
-static __inline cap_rights_t
-flags_to_rights(int flags)
+static __inline void
+flags_to_rights(int flags, cap_rights_t *rightsp)
{
- cap_rights_t rights = 0;
if (flags & O_EXEC) {
- rights |= CAP_FEXECVE;
+ cap_rights_set(rightsp, CAP_FEXECVE);
} else {
switch ((flags & O_ACCMODE)) {
case O_RDONLY:
- rights |= CAP_READ;
+ cap_rights_set(rightsp, CAP_READ);
break;
case O_RDWR:
- rights |= CAP_READ;
+ cap_rights_set(rightsp, CAP_READ);
/* FALLTHROUGH */
case O_WRONLY:
- rights |= CAP_WRITE;
+ cap_rights_set(rightsp, CAP_WRITE);
if (!(flags & (O_APPEND | O_TRUNC)))
- rights |= CAP_SEEK;
+ cap_rights_set(rightsp, CAP_SEEK);
break;
}
}
if (flags & O_CREAT)
- rights |= CAP_CREATE;
+ cap_rights_set(rightsp, CAP_CREATE);
if (flags & O_TRUNC)
- rights |= CAP_FTRUNCATE;
+ cap_rights_set(rightsp, CAP_FTRUNCATE);
if (flags & (O_SYNC | O_FSYNC))
- rights |= CAP_FSYNC;
+ cap_rights_set(rightsp, CAP_FSYNC);
if (flags & (O_EXLOCK | O_SHLOCK))
- rights |= CAP_FLOCK;
-
- return (rights);
+ cap_rights_set(rightsp, CAP_FLOCK);
}
/*
@@ -1051,12 +1053,13 @@ kern_openat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
int cmode;
int indx = -1, error;
struct nameidata nd;
- cap_rights_t rights_needed = CAP_LOOKUP;
+ cap_rights_t rights;
AUDIT_ARG_FFLAGS(flags);
AUDIT_ARG_MODE(mode);
/* XXX: audit dirfd */
- rights_needed |= flags_to_rights(flags);
+ cap_rights_init(&rights, CAP_LOOKUP);
+ flags_to_rights(flags, &rights);
/*
* Only one of the O_EXEC, O_RDONLY, O_WRONLY and O_RDWR flags
* may be specified.
@@ -1084,7 +1087,7 @@ kern_openat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
fp->f_flag = flags & FMASK;
cmode = ((mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | AUDITVNODE1, pathseg, path, fd,
- rights_needed, td);
+ &rights, td);
td->td_dupfd = -1; /* XXX check for fdopen */
error = vn_open(&nd, &flags, cmode, fp);
if (error) {
@@ -1258,6 +1261,7 @@ kern_mknodat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
int error;
int whiteout = 0;
struct nameidata nd;
+ cap_rights_t rights;
AUDIT_ARG_MODE(mode);
AUDIT_ARG_DEV(dev);
@@ -1285,7 +1289,7 @@ kern_mknodat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
restart:
bwillwrite();
NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE1,
- pathseg, path, fd, CAP_MKNODAT, td);
+ pathseg, path, fd, cap_rights_init(&rights, CAP_MKNODAT), td);
if ((error = namei(&nd)) != 0)
return (error);
vp = nd.ni_vp;
@@ -1398,6 +1402,7 @@ kern_mkfifoat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
{
struct mount *mp;
struct vattr vattr;
+ cap_rights_t rights;
int error;
struct nameidata nd;
@@ -1405,7 +1410,7 @@ kern_mkfifoat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
restart:
bwillwrite();
NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE1,
- pathseg, path, fd, CAP_MKFIFOAT, td);
+ pathseg, path, fd, cap_rights_init(&rights, CAP_MKFIFOAT), td);
if ((error = namei(&nd)) != 0)
return (error);
if (nd.ni_vp != NULL) {
@@ -1541,6 +1546,7 @@ kern_linkat(struct thread *td, int fd1, int fd2, char *path1, char *path2,
struct vnode *vp;
struct mount *mp;
struct nameidata nd;
+ cap_rights_t rights;
int error;
bwillwrite();
@@ -1559,7 +1565,7 @@ kern_linkat(struct thread *td, int fd1, int fd2, char *path1, char *path2,
return (error);
}
NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE2,
- segflg, path2, fd2, CAP_LINKAT, td);
+ segflg, path2, fd2, cap_rights_init(&rights, CAP_LINKAT), td);
if ((error = namei(&nd)) == 0) {
if (nd.ni_vp != NULL) {
if (nd.ni_dvp == nd.ni_vp)
@@ -1640,6 +1646,7 @@ kern_symlinkat(struct thread *td, char *path1, int fd, char *path2,
char *syspath;
int error;
struct nameidata nd;
+ cap_rights_t rights;
if (segflg == UIO_SYSSPACE) {
syspath = path1;
@@ -1652,7 +1659,7 @@ kern_symlinkat(struct thread *td, char *path1, int fd, char *path2,
restart:
bwillwrite();
NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE1,
- segflg, path2, fd, CAP_SYMLINKAT, td);
+ segflg, path2, fd, cap_rights_init(&rights, CAP_SYMLINKAT), td);
if ((error = namei(&nd)) != 0)
goto out;
if (nd.ni_vp) {
@@ -1800,11 +1807,12 @@ kern_unlinkat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
int error;
struct nameidata nd;
struct stat sb;
+ cap_rights_t rights;
restart:
bwillwrite();
NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1,
- pathseg, path, fd, CAP_UNLINKAT, td);
+ pathseg, path, fd, cap_rights_init(&rights, CAP_UNLINKAT), td);
if ((error = namei(&nd)) != 0)
return (error == EINVAL ? EPERM : error);
vp = nd.ni_vp;
@@ -1880,10 +1888,12 @@ sys_lseek(td, uap)
} */ *uap;
{
struct file *fp;
+ cap_rights_t rights;
int error;
AUDIT_ARG_FD(uap->fd);
- if ((error = fget(td, uap->fd, CAP_SEEK, &fp)) != 0)
+ error = fget(td, uap->fd, cap_rights_init(&rights, CAP_SEEK), &fp);
+ if (error != 0)
return (error);
error = (fp->f_ops->fo_flags & DFLAG_SEEKABLE) != 0 ?
fo_seek(fp, uap->offset, uap->whence, td) : ESPIPE;
@@ -2026,6 +2036,7 @@ kern_accessat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
struct ucred *cred, *tmpcred;
struct vnode *vp;
struct nameidata nd;
+ cap_rights_t rights;
int error;
/*
@@ -2042,7 +2053,8 @@ kern_accessat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
cred = tmpcred = td->td_ucred;
AUDIT_ARG_VALUE(amode);
NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF |
- AUDITVNODE1, pathseg, path, fd, CAP_FSTAT, td);
+ AUDITVNODE1, pathseg, path, fd, cap_rights_init(&rights, CAP_FSTAT),
+ td);
if ((error = namei(&nd)) != 0)
goto out1;
vp = nd.ni_vp;
@@ -2244,6 +2256,7 @@ kern_statat_vnhook(struct thread *td, int flag, int fd, char *path,
{
struct nameidata nd;
struct stat sb;
+ cap_rights_t rights;
int error;
if (flag & ~AT_SYMLINK_NOFOLLOW)
@@ -2251,7 +2264,7 @@ kern_statat_vnhook(struct thread *td, int flag, int fd, char *path,
NDINIT_ATRIGHTS(&nd, LOOKUP, ((flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW :
FOLLOW) | LOCKSHARED | LOCKLEAF | AUDITVNODE1, pathseg, path, fd,
- CAP_FSTAT, td);
+ cap_rights_init(&rights, CAP_FSTAT), td);
if ((error = namei(&nd)) != 0)
return (error);
@@ -2663,12 +2676,13 @@ kern_chflagsat(struct thread *td, int fd, const char *path,
enum uio_seg pathseg, u_long flags, int atflag)
{
struct nameidata nd;
+ cap_rights_t rights;
int error, follow;
AUDIT_ARG_FFLAGS(flags);
follow = (atflag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd,
- CAP_FCHFLAGS, td);
+ cap_rights_init(&rights, CAP_FCHFLAGS), td);
if ((error = namei(&nd)) != 0)
return (error);
NDFREE(&nd, NDF_ONLY_PNBUF);
@@ -2695,12 +2709,14 @@ sys_fchflags(td, uap)
} */ *uap;
{
struct file *fp;
+ cap_rights_t rights;
int error;
AUDIT_ARG_FD(uap->fd);
AUDIT_ARG_FFLAGS(uap->flags);
- if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_FCHFLAGS,
- &fp)) != 0)
+ error = getvnode(td->td_proc->p_fd, uap->fd,
+ cap_rights_init(&rights, CAP_FCHFLAGS), &fp);
+ if (error != 0)
return (error);
#ifdef AUDIT
vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY);
@@ -2820,11 +2836,12 @@ kern_fchmodat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
int error;
struct nameidata nd;
int follow;
+ cap_rights_t rights;
AUDIT_ARG_MODE(mode);
follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd,
- CAP_FCHMOD, td);
+ cap_rights_init(&rights, CAP_FCHMOD), td);
if ((error = namei(&nd)) != 0)
return (error);
NDFREE(&nd, NDF_ONLY_PNBUF);
@@ -2846,12 +2863,13 @@ int
sys_fchmod(struct thread *td, struct fchmod_args *uap)
{
struct file *fp;
+ cap_rights_t rights;
int error;
AUDIT_ARG_FD(uap->fd);
AUDIT_ARG_MODE(uap->mode);
- error = fget(td, uap->fd, CAP_FCHMOD, &fp);
+ error = fget(td, uap->fd, cap_rights_init(&rights, CAP_FCHMOD), &fp);
if (error != 0)
return (error);
error = fo_chmod(fp, uap->mode, td->td_ucred, td);
@@ -2949,12 +2967,13 @@ kern_fchownat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
int uid, int gid, int flag)
{
struct nameidata nd;
+ cap_rights_t rights;
int error, follow;
AUDIT_ARG_OWNER(uid, gid);
follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd,
- CAP_FCHOWN, td);
+ cap_rights_init(&rights, CAP_FCHOWN), td);
if ((error = namei(&nd)) != 0)
return (error);
@@ -3016,11 +3035,12 @@ sys_fchown(td, uap)
} */ *uap;
{
struct file *fp;
+ cap_rights_t rights;
int error;
AUDIT_ARG_FD(uap->fd);
AUDIT_ARG_OWNER(uap->uid, uap->gid);
- error = fget(td, uap->fd, CAP_FCHOWN, &fp);
+ error = fget(td, uap->fd, cap_rights_init(&rights, CAP_FCHOWN), &fp);
if (error != 0)
return (error);
error = fo_chown(fp, uap->uid, uap->gid, td->td_ucred, td);
@@ -3155,12 +3175,13 @@ kern_utimesat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
{
struct nameidata nd;
struct timespec ts[2];
+ cap_rights_t rights;
int error;
if ((error = getutimes(tptr, tptrseg, ts)) != 0)
return (error);
NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | AUDITVNODE1, pathseg, path, fd,
- CAP_FUTIMES, td);
+ cap_rights_init(&rights, CAP_FUTIMES), td);
if ((error = namei(&nd)) != 0)
return (error);
@@ -3238,12 +3259,15 @@ kern_futimes(struct thread *td, int fd, struct timeval *tptr,
{
struct timespec ts[2];
struct file *fp;
+ cap_rights_t rights;
int error;
AUDIT_ARG_FD(fd);
if ((error = getutimes(tptr, tptrseg, ts)) != 0)
return (error);
- if ((error = getvnode(td->td_proc->p_fd, fd, CAP_FUTIMES, &fp)) != 0)
+ error = getvnode(td->td_proc->p_fd, fd,
+ cap_rights_init(&rights, CAP_FUTIMES), &fp);
+ if (error != 0)
return (error);
#ifdef AUDIT
vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY);
@@ -3390,10 +3414,13 @@ sys_fsync(td, uap)
struct vnode *vp;
struct mount *mp;
struct file *fp;
+ cap_rights_t rights;
int error, lock_flags;
AUDIT_ARG_FD(uap->fd);
- if ((error = getvnode(td->td_proc->p_fd, uap->fd, CAP_FSYNC, &fp)) != 0)
+ error = getvnode(td->td_proc->p_fd, uap->fd,
+ cap_rights_init(&rights, CAP_FSYNC), &fp);
+ if (error != 0)
return (error);
vp = fp->f_vnode;
if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
@@ -3472,15 +3499,17 @@ kern_renameat(struct thread *td, int oldfd, char *old, int newfd, char *new,
struct mount *mp = NULL;
struct vnode *tvp, *fvp, *tdvp;
struct nameidata fromnd, tond;
+ cap_rights_t rights;
int error;
bwillwrite();
#ifdef MAC
NDINIT_ATRIGHTS(&fromnd, DELETE, LOCKPARENT | LOCKLEAF | SAVESTART |
- AUDITVNODE1, pathseg, old, oldfd, CAP_RENAMEAT, td);
+ AUDITVNODE1, pathseg, old, oldfd,
+ cap_rights_init(&rights, CAP_RENAMEAT), td);
#else
NDINIT_ATRIGHTS(&fromnd, DELETE, WANTPARENT | SAVESTART | AUDITVNODE1,
- pathseg, old, oldfd, CAP_RENAMEAT, td);
+ pathseg, old, oldfd, cap_rights_init(&rights, CAP_RENAMEAT), td);
#endif
if ((error = namei(&fromnd)) != 0)
@@ -3502,7 +3531,8 @@ kern_renameat(struct thread *td, int oldfd, char *old, int newfd, char *new,
goto out1;
}
NDINIT_ATRIGHTS(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE |
- SAVESTART | AUDITVNODE2, pathseg, new, newfd, CAP_LINKAT, td);
+ SAVESTART | AUDITVNODE2, pathseg, new, newfd,
+ cap_rights_init(&rights, CAP_LINKAT), td);
if (fromnd.ni_vp->v_type == VDIR)
tond.ni_cnd.cn_flags |= WILLBEDIR;
if ((error = namei(&tond)) != 0) {
@@ -3531,8 +3561,8 @@ kern_renameat(struct thread *td, int oldfd, char *old, int newfd, char *new,
* If the target already exists we require CAP_UNLINKAT
* from 'newfd'.
*/
- error = cap_check(tond.ni_filecaps.fc_rights,
- CAP_UNLINKAT);
+ error = cap_check(&tond.ni_filecaps.fc_rights,
+ cap_rights_init(&rights, CAP_UNLINKAT));
if (error != 0)
goto out;
}
@@ -3630,6 +3660,7 @@ kern_mkdirat(struct thread *td, int fd, char *path, enum uio_seg segflg,
struct mount *mp;
struct vnode *vp;
struct vattr vattr;
+ cap_rights_t rights;
int error;
struct nameidata nd;
@@ -3637,7 +3668,7 @@ kern_mkdirat(struct thread *td, int fd, char *path, enum uio_seg segflg,
restart:
bwillwrite();
NDINIT_ATRIGHTS(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE1,
- segflg, path, fd, CAP_MKDIRAT, td);
+ segflg, path, fd, cap_rights_init(&rights, CAP_MKDIRAT), td);
nd.ni_cnd.cn_flags |= WILLBEDIR;
if ((error = namei(&nd)) != 0)
return (error);
@@ -3715,13 +3746,14 @@ kern_rmdirat(struct thread *td, int fd, char *path, enum uio_seg pathseg)
{
struct mount *mp;
struct vnode *vp;
+ cap_rights_t rights;
int error;
struct nameidata nd;
restart:
bwillwrite();
NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1,
- pathseg, path, fd, CAP_UNLINKAT, td);
+ pathseg, path, fd, cap_rights_init(&rights, CAP_UNLINKAT), td);
if ((error = namei(&nd)) != 0)
return (error);
vp = nd.ni_vp;
@@ -3806,6 +3838,7 @@ kern_ogetdirentries(struct thread *td, struct ogetdirentries_args *uap,
struct uio auio, kuio;
struct iovec aiov, kiov;
struct dirent *dp, *edp;
+ cap_rights_t rights;
caddr_t dirbuf;
int error, eofflag, readcnt;
long loff;
@@ -3814,7 +3847,9 @@ 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, CAP_READ, &fp)) != 0)
+ error = getvnode(td->td_proc->p_fd, uap->fd,
+ cap_rights_init(&rights, CAP_READ), &fp);
+ if (error != 0)
return (error);
if ((fp->f_flag & FREAD) == 0) {
fdrop(fp, td);
@@ -3967,6 +4002,7 @@ kern_getdirentries(struct thread *td, int fd, char *buf, u_int count,
struct file *fp;
struct uio auio;
struct iovec aiov;
+ cap_rights_t rights;
long loff;
int error, eofflag;
off_t foffset;
@@ -3975,7 +4011,9 @@ kern_getdirentries(struct thread *td, int fd, char *buf, u_int count,
if (count > IOSIZE_MAX)
return (EINVAL);
auio.uio_resid = count;
- if ((error = getvnode(td->td_proc->p_fd, fd, CAP_READ, &fp)) != 0)
+ error = getvnode(td->td_proc->p_fd, fd,
+ cap_rights_init(&rights, CAP_READ), &fp);
+ if (error != 0)
return (error);
if ((fp->f_flag & FREAD) == 0) {
fdrop(fp, td);
@@ -4138,12 +4176,12 @@ out:
* entry is held upon returning.
*/
int
-getvnode(struct filedesc *fdp, int fd, cap_rights_t rights, struct file **fpp)
+getvnode(struct filedesc *fdp, int fd, cap_rights_t *rightsp, struct file **fpp)
{
struct file *fp;
int error;
- error = fget_unlocked(fdp, fd, rights, 0, &fp, NULL);
+ error = fget_unlocked(fdp, fd, rightsp, 0, &fp, NULL);
if (error != 0)
return (error);
@@ -4466,11 +4504,12 @@ kern_posix_fallocate(struct thread *td, int fd, off_t offset, off_t len)
struct file *fp;
struct mount *mp;
struct vnode *vp;
+ cap_rights_t rights;
off_t olen, ooffset;
int error;
fp = NULL;
- error = fget(td, fd, CAP_WRITE, &fp);
+ error = fget(td, fd, cap_rights_init(&rights, CAP_WRITE), &fp);
if (error != 0)
goto out;
@@ -4562,6 +4601,7 @@ kern_posix_fadvise(struct thread *td, int fd, off_t offset, off_t len,
struct fadvise_info *fa, *new;
struct file *fp;
struct vnode *vp;
+ cap_rights_t rights;
off_t end;
int error;
@@ -4582,7 +4622,7 @@ kern_posix_fadvise(struct thread *td, int fd, off_t offset, off_t len,
return (EINVAL);
}
/* XXX: CAP_POSIX_FADVISE? */
- error = fget(td, fd, CAP_NONE, &fp);
+ error = fget(td, fd, cap_rights_init(&rights), &fp);
if (error != 0)
goto out;
diff --git a/sys/netsmb/smb_dev.c b/sys/netsmb/smb_dev.c
index 0efb282..279ae67 100644
--- a/sys/netsmb/smb_dev.c
+++ b/sys/netsmb/smb_dev.c
@@ -378,6 +378,7 @@ int
smb_dev2share(int fd, int mode, struct smb_cred *scred,
struct smb_share **sspp, struct smb_dev **ssdp)
{
+ cap_rights_t rights;
struct file *fp, *fptmp;
struct smb_dev *sdp;
struct smb_share *ssp;
@@ -385,7 +386,7 @@ smb_dev2share(int fd, int mode, struct smb_cred *scred,
int error;
td = curthread;
- error = fget(td, fd, CAP_READ, &fp);
+ error = fget(td, fd, cap_rights_init(&rights, CAP_READ), &fp);
if (error)
return (error);
fptmp = td->td_fpop;
diff --git a/sys/nfsserver/nfs_srvkrpc.c b/sys/nfsserver/nfs_srvkrpc.c
index db69df9..85003b7 100644
--- a/sys/nfsserver/nfs_srvkrpc.c
+++ b/sys/nfsserver/nfs_srvkrpc.c
@@ -168,6 +168,7 @@ nfssvc_nfsserver(struct thread *td, struct nfssvc_args *uap)
struct file *fp;
struct nfsd_addsock_args addsockarg;
struct nfsd_nfsd_args nfsdarg;
+ cap_rights_t rights;
int error;
if (uap->flag & NFSSVC_ADDSOCK) {
@@ -175,7 +176,8 @@ nfssvc_nfsserver(struct thread *td, struct nfssvc_args *uap)
sizeof(addsockarg));
if (error)
return (error);
- error = fget(td, addsockarg.sock, CAP_SOCK_SERVER, &fp);
+ error = fget(td, addsockarg.sock,
+ cap_rights_init(&rights, CAP_SOCK_SERVER), &fp);
if (error)
return (error);
if (fp->f_type != DTYPE_SOCKET) {
diff --git a/sys/security/audit/audit.h b/sys/security/audit/audit.h
index dd55875..559d571 100644
--- a/sys/security/audit/audit.h
+++ b/sys/security/audit/audit.h
@@ -114,7 +114,7 @@ void audit_arg_auditon(union auditon_udata *udata);
void audit_arg_file(struct proc *p, struct file *fp);
void audit_arg_argv(char *argv, int argc, int length);
void audit_arg_envv(char *envv, int envc, int length);
-void audit_arg_rights(cap_rights_t rights);
+void audit_arg_rights(cap_rights_t *rightsp);
void audit_arg_fcntl_rights(uint32_t fcntlrights);
void audit_sysclose(struct thread *td, int fd);
void audit_cred_copy(struct ucred *src, struct ucred *dest);
diff --git a/sys/security/audit/audit_arg.c b/sys/security/audit/audit_arg.c
index 4927be0..2e86842 100644
--- a/sys/security/audit/audit_arg.c
+++ b/sys/security/audit/audit_arg.c
@@ -861,7 +861,7 @@ audit_arg_envv(char *envv, int envc, int length)
}
void
-audit_arg_rights(cap_rights_t rights)
+audit_arg_rights(cap_rights_t *rightsp)
{
struct kaudit_record *ar;
@@ -869,7 +869,7 @@ audit_arg_rights(cap_rights_t rights)
if (ar == NULL)
return;
- ar->k_ar.ar_arg_rights = rights;
+ ar->k_ar.ar_arg_rights = *rightsp;
ARG_SET_VALID(ar, ARG_RIGHTS);
}
diff --git a/sys/security/audit/audit_bsm.c b/sys/security/audit/audit_bsm.c
index 03b3c23..9f29ece 100644
--- a/sys/security/audit/audit_bsm.c
+++ b/sys/security/audit/audit_bsm.c
@@ -1611,14 +1611,13 @@ kaudit_to_bsm(struct kaudit_record *kar, struct au_record **pau)
}
break;
- case AUE_CAP_NEW:
case AUE_CAP_RIGHTS_LIMIT:
/*
* XXXRW/XXXJA: Would be nice to audit socket/etc information.
*/
FD_VNODE1_TOKENS;
if (ARG_IS_VALID(kar, ARG_RIGHTS)) {
- tok = au_to_arg64(2, "rights", ar->ar_arg_rights);
+ tok = au_to_rights(&ar->ar_arg_rights);
kau_write(rec, tok);
}
break;
diff --git a/sys/security/audit/audit_private.h b/sys/security/audit/audit_private.h
index e23ba08..b5c373a 100644
--- a/sys/security/audit/audit_private.h
+++ b/sys/security/audit/audit_private.h
@@ -41,6 +41,7 @@
#error "no user-serviceable parts inside"
#endif
+#include <sys/caprights.h>
#include <sys/ipc.h>
#include <sys/socket.h>
#include <sys/ucred.h>
diff --git a/sys/security/audit/bsm_token.c b/sys/security/audit/bsm_token.c
index 6d0d67f..763d597 100644
--- a/sys/security/audit/bsm_token.c
+++ b/sys/security/audit/bsm_token.c
@@ -835,6 +835,22 @@ au_to_process_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid,
tid));
}
+token_t *
+au_to_rights(cap_rights_t *rightsp)
+{
+ token_t *t;
+ u_char *dptr;
+ int i;
+
+ GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(*rightsp));
+
+ ADD_U_CHAR(dptr, AUT_RIGHTS);
+ for (i = 0; i < nitems(rightsp->cr_rights); i++)
+ ADD_U_INT64(dptr, rightsp->cr_rights[i]);
+
+ return (t);
+}
+
/*
* token ID 1 byte
* error status 1 byte
diff --git a/sys/security/mac/mac_syscalls.c b/sys/security/mac/mac_syscalls.c
index ff55ec9..6405586 100644
--- a/sys/security/mac/mac_syscalls.c
+++ b/sys/security/mac/mac_syscalls.c
@@ -229,6 +229,7 @@ sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
struct vnode *vp;
struct pipe *pipe;
struct socket *so;
+ cap_rights_t rights;
short label_type;
int error;
@@ -248,7 +249,7 @@ sys___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, CAP_MAC_GET, &fp);
+ error = fget(td, uap->fd, cap_rights_init(&rights, CAP_MAC_GET), &fp);
if (error)
goto out;
@@ -425,6 +426,7 @@ sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
struct mount *mp;
struct vnode *vp;
struct mac mac;
+ cap_rights_t rights;
char *buffer;
int error;
@@ -443,7 +445,7 @@ sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
return (error);
}
- error = fget(td, uap->fd, CAP_MAC_SET, &fp);
+ error = fget(td, uap->fd, cap_rights_init(&rights, CAP_MAC_SET), &fp);
if (error)
goto out;
diff --git a/sys/sys/_types.h b/sys/sys/_types.h
index 34d1edb..ffef9d8 100644
--- a/sys/sys/_types.h
+++ b/sys/sys/_types.h
@@ -38,7 +38,6 @@
typedef __uint32_t __blksize_t; /* file block size */
typedef __int64_t __blkcnt_t; /* file block count */
typedef __int32_t __clockid_t; /* clock_gettime()... */
-typedef __uint64_t __cap_rights_t; /* capability rights */
typedef __uint32_t __fflags_t; /* file flags */
typedef __uint64_t __fsblkcnt_t;
typedef __uint64_t __fsfilcnt_t;
diff --git a/sys/sys/capability.h b/sys/sys/capability.h
index ec63de7..e5b9ec7 100644
--- a/sys/sys/capability.h
+++ b/sys/sys/capability.h
@@ -42,9 +42,16 @@
#include <sys/cdefs.h>
#include <sys/param.h>
+#include <sys/caprights.h>
#include <sys/file.h>
#include <sys/fcntl.h>
+#ifndef _KERNEL
+#include <stdbool.h>
+#endif
+
+#define CAPRIGHT(idx, bit) ((1ULL << (57 + (idx))) | (bit))
+
/*
* Possible rights on capabilities.
*
@@ -59,29 +66,31 @@
* involve reads or writes depending a great deal on context.
*/
-#define CAP_NONE 0x0000000000000000ULL
+/* INDEX 0 */
/*
* General file I/O.
*/
/* Allows for openat(O_RDONLY), read(2), readv(2). */
-#define CAP_READ 0x0000000000000001ULL
+#define CAP_READ CAPRIGHT(0, 0x0000000000000001ULL)
/* Allows for openat(O_WRONLY | O_APPEND), write(2), writev(2). */
-#define CAP_WRITE 0x0000000000000002ULL
+#define CAP_WRITE CAPRIGHT(0, 0x0000000000000002ULL)
+/* Allows for lseek(fd, 0, SEEK_CUR). */
+#define CAP_SEEK_TELL CAPRIGHT(0, 0x0000000000000004ULL)
/* Allows for lseek(2). */
-#define CAP_SEEK 0x0000000000000080ULL
+#define CAP_SEEK (CAP_SEEK_TELL | 0x0000000000000008ULL)
/* Allows for pread(2), preadv(2). */
#define CAP_PREAD (CAP_SEEK | CAP_READ)
/* Allows for openat(O_WRONLY) (without O_APPEND), pwrite(2), pwritev(2). */
#define CAP_PWRITE (CAP_SEEK | CAP_WRITE)
/* Allows for mmap(PROT_NONE). */
-#define CAP_MMAP 0x0000000000000004ULL
+#define CAP_MMAP CAPRIGHT(0, 0x0000000000000010ULL)
/* Allows for mmap(PROT_READ). */
#define CAP_MMAP_R (CAP_MMAP | CAP_SEEK | CAP_READ)
/* Allows for mmap(PROT_WRITE). */
#define CAP_MMAP_W (CAP_MMAP | CAP_SEEK | CAP_WRITE)
/* Allows for mmap(PROT_EXEC). */
-#define CAP_MMAP_X (CAP_MMAP | CAP_SEEK | 0x0000000000000008ULL)
+#define CAP_MMAP_X (CAP_MMAP | CAP_SEEK | 0x0000000000000020ULL)
/* Allows for mmap(PROT_READ | PROT_WRITE). */
#define CAP_MMAP_RW (CAP_MMAP_R | CAP_MMAP_W)
/* Allows for mmap(PROT_READ | PROT_EXEC). */
@@ -91,67 +100,67 @@
/* Allows for mmap(PROT_READ | PROT_WRITE | PROT_EXEC). */
#define CAP_MMAP_RWX (CAP_MMAP_R | CAP_MMAP_W | CAP_MMAP_X)
/* Allows for openat(O_CREAT). */
-#define CAP_CREATE 0x0000000000080000ULL
+#define CAP_CREATE CAPRIGHT(0, 0x0000000000000040ULL)
/* Allows for openat(O_EXEC) and fexecve(2) in turn. */
-#define CAP_FEXECVE 0x0000000000000010ULL
+#define CAP_FEXECVE CAPRIGHT(0, 0x0000000000000080ULL)
/* Allows for openat(O_SYNC), openat(O_FSYNC), fsync(2). */
-#define CAP_FSYNC 0x0000000000000020ULL
+#define CAP_FSYNC CAPRIGHT(0, 0x0000000000000100ULL)
/* Allows for openat(O_TRUNC), ftruncate(2). */
-#define CAP_FTRUNCATE 0x0000000000000040ULL
-
-/* VFS methods. */
-#define CAP_FCHDIR 0x0000000000000200ULL
-#define CAP_FCHFLAGS 0x0000000000000100ULL
-#define CAP_CHFLAGSAT CAP_FCHFLAGS
-#define CAP_FCHMOD 0x0000000000000400ULL
-#define CAP_FCHMODAT CAP_FCHMOD
-#define CAP_FCHOWN 0x0000000000000800ULL
-#define CAP_FCHOWNAT CAP_FCHOWN
-#define CAP_FCNTL 0x0000000000001000ULL
-#define CAP_FLOCK 0x0000000000004000ULL
-#define CAP_FPATHCONF 0x0000000000002000ULL
-#define CAP_FSCK 0x0000000000008000ULL
-#define CAP_FSTAT 0x0000000000010000ULL
-#define CAP_FSTATAT CAP_FSTAT
-#define CAP_FSTATFS 0x0000000000020000ULL
-#define CAP_FUTIMES 0x0000000000040000ULL
-#define CAP_FUTIMESAT CAP_FUTIMES
-#define CAP_LINKAT 0x0000000000400000ULL
-#define CAP_MKDIRAT 0x0000000000200000ULL
-#define CAP_MKFIFOAT 0x0000000000800000ULL
-#define CAP_MKNODAT 0x0080000000000000ULL
-#define CAP_RENAMEAT 0x0200000000000000ULL
-#define CAP_SYMLINKAT 0x0100000000000000ULL
-#define CAP_UNLINKAT 0x0000000000100000ULL
+#define CAP_FTRUNCATE CAPRIGHT(0, 0x0000000000000200ULL)
/* Lookups - used to constrain *at() calls. */
-#define CAP_LOOKUP 0x0000000001000000ULL
+#define CAP_LOOKUP CAPRIGHT(0, 0x0000000000000400ULL)
+
+/* VFS methods. */
+#define CAP_FCHDIR CAPRIGHT(0, 0x0000000000000800ULL)
+#define CAP_FCHFLAGS CAPRIGHT(0, 0x0000000000001000ULL)
+#define CAP_CHFLAGSAT (CAP_FCHFLAGS | CAP_LOOKUP)
+#define CAP_FCHMOD CAPRIGHT(0, 0x0000000000002000ULL)
+#define CAP_FCHMODAT (CAP_FCHMOD | CAP_LOOKUP)
+#define CAP_FCHOWN CAPRIGHT(0, 0x0000000000004000ULL)
+#define CAP_FCHOWNAT (CAP_FCHOWN | CAP_LOOKUP)
+#define CAP_FCNTL CAPRIGHT(0, 0x0000000000008000ULL)
+#define CAP_FLOCK CAPRIGHT(0, 0x0000000000010000ULL)
+#define CAP_FPATHCONF CAPRIGHT(0, 0x0000000000020000ULL)
+#define CAP_FSCK CAPRIGHT(0, 0x0000000000040000ULL)
+#define CAP_FSTAT CAPRIGHT(0, 0x0000000000080000ULL)
+#define CAP_FSTATAT (CAP_FSTAT | CAP_LOOKUP)
+#define CAP_FSTATFS CAPRIGHT(0, 0x0000000000100000ULL)
+#define CAP_FUTIMES CAPRIGHT(0, 0x0000000000200000ULL)
+#define CAP_FUTIMESAT (CAP_FUTIMES | CAP_LOOKUP)
+#define CAP_LINKAT CAPRIGHT(0, 0x0000000000400000ULL)
+#define CAP_MKDIRAT CAPRIGHT(0, 0x0000000000800000ULL)
+#define CAP_MKFIFOAT CAPRIGHT(0, 0x0000000001000000ULL)
+#define CAP_MKNODAT CAPRIGHT(0, 0x0000000002000000ULL)
+#define CAP_RENAMEAT CAPRIGHT(0, 0x0000000004000000ULL)
+#define CAP_SYMLINKAT CAPRIGHT(0, 0x0000000008000000ULL)
+#define CAP_UNLINKAT CAPRIGHT(0, 0x0000000010000000ULL)
/* Extended attributes. */
-#define CAP_EXTATTR_DELETE 0x0000000002000000ULL
-#define CAP_EXTATTR_GET 0x0000000004000000ULL
-#define CAP_EXTATTR_LIST 0x0000000008000000ULL
-#define CAP_EXTATTR_SET 0x0000000010000000ULL
+#define CAP_EXTATTR_DELETE CAPRIGHT(0, 0x0000000020000000ULL)
+#define CAP_EXTATTR_GET CAPRIGHT(0, 0x0000000040000000ULL)
+#define CAP_EXTATTR_LIST CAPRIGHT(0, 0x0000000080000000ULL)
+#define CAP_EXTATTR_SET CAPRIGHT(0, 0x0000000100000000ULL)
/* Access Control Lists. */
-#define CAP_ACL_CHECK 0x0000000020000000ULL
-#define CAP_ACL_DELETE 0x0000000040000000ULL
-#define CAP_ACL_GET 0x0000000080000000ULL
-#define CAP_ACL_SET 0x0000000100000000ULL
+#define CAP_ACL_CHECK CAPRIGHT(0, 0x0000000200000000ULL)
+#define CAP_ACL_DELETE CAPRIGHT(0, 0x0000000400000000ULL)
+#define CAP_ACL_GET CAPRIGHT(0, 0x0000000800000000ULL)
+#define CAP_ACL_SET CAPRIGHT(0, 0x0000001000000000ULL)
/* Socket operations. */
-#define CAP_ACCEPT 0x0000000200000000ULL
-#define CAP_BIND 0x0000000400000000ULL
-#define CAP_CONNECT 0x0000000800000000ULL
-#define CAP_GETPEERNAME 0x0000001000000000ULL
-#define CAP_GETSOCKNAME 0x0000002000000000ULL
-#define CAP_GETSOCKOPT 0x0000004000000000ULL
-#define CAP_LISTEN 0x0000008000000000ULL
-#define CAP_PEELOFF 0x0000010000000000ULL
+#define CAP_ACCEPT CAPRIGHT(0, 0x0000002000000000ULL)
+#define CAP_BIND CAPRIGHT(0, 0x0000004000000000ULL)
+#define CAP_CONNECT CAPRIGHT(0, 0x0000008000000000ULL)
+#define CAP_GETPEERNAME CAPRIGHT(0, 0x0000010000000000ULL)
+#define CAP_GETSOCKNAME CAPRIGHT(0, 0x0000020000000000ULL)
+#define CAP_GETSOCKOPT CAPRIGHT(0, 0x0000040000000000ULL)
+#define CAP_LISTEN CAPRIGHT(0, 0x0000080000000000ULL)
+#define CAP_PEELOFF CAPRIGHT(0, 0x0000100000000000ULL)
#define CAP_RECV CAP_READ
#define CAP_SEND CAP_WRITE
-#define CAP_SETSOCKOPT 0x0000020000000000ULL
-#define CAP_SHUTDOWN 0x0000040000000000ULL
+#define CAP_SETSOCKOPT CAPRIGHT(0, 0x0000200000000000ULL)
+#define CAP_SHUTDOWN CAPRIGHT(0, 0x0000400000000000ULL)
#define CAP_SOCK_CLIENT \
(CAP_CONNECT | CAP_GETPEERNAME | CAP_GETSOCKNAME | CAP_GETSOCKOPT | \
@@ -161,56 +170,69 @@
CAP_GETSOCKOPT | CAP_LISTEN | CAP_PEELOFF | CAP_RECV | CAP_SEND | \
CAP_SETSOCKOPT | CAP_SHUTDOWN)
+/* All used bits for index 0. */
+#define CAP_ALL0 CAPRIGHT(0, 0x00007FFFFFFFFFFFULL)
+
+/* Available bits for index 0. */
+#define CAP_UNUSED0_48 CAPRIGHT(0, 0x0000800000000000ULL)
+/* ... */
+#define CAP_UNUSED0_57 CAPRIGHT(0, 0x0100000000000000ULL)
+
+/* INDEX 1 */
+
/* Mandatory Access Control. */
-#define CAP_MAC_GET 0x0000080000000000ULL
-#define CAP_MAC_SET 0x0000100000000000ULL
+#define CAP_MAC_GET CAPRIGHT(1, 0x0000000000000001ULL)
+#define CAP_MAC_SET CAPRIGHT(1, 0x0000000000000002ULL)
/* Methods on semaphores. */
-#define CAP_SEM_GETVALUE 0x0000200000000000ULL
-#define CAP_SEM_POST 0x0000400000000000ULL
-#define CAP_SEM_WAIT 0x0000800000000000ULL
+#define CAP_SEM_GETVALUE CAPRIGHT(1, 0x0000000000000004ULL)
+#define CAP_SEM_POST CAPRIGHT(1, 0x0000000000000008ULL)
+#define CAP_SEM_WAIT CAPRIGHT(1, 0x0000000000000010ULL)
/* kqueue events. */
-#define CAP_POLL_EVENT 0x0001000000000000ULL
-#define CAP_POST_EVENT 0x0002000000000000ULL
+#define CAP_POLL_EVENT CAPRIGHT(1, 0x0000000000000020ULL)
+#define CAP_POST_EVENT CAPRIGHT(1, 0x0000000000000040ULL)
/* Strange and powerful rights that should not be given lightly. */
-#define CAP_IOCTL 0x0004000000000000ULL
-#define CAP_TTYHOOK 0x0008000000000000ULL
+#define CAP_IOCTL CAPRIGHT(1, 0x0000000000000080ULL)
+#define CAP_TTYHOOK CAPRIGHT(1, 0x0000000000000100ULL)
/* Process management via process descriptors. */
-#define CAP_PDGETPID 0x0010000000000000ULL
-#define CAP_PDWAIT 0x0020000000000000ULL
-#define CAP_PDKILL 0x0040000000000000ULL
+#define CAP_PDGETPID CAPRIGHT(1, 0x0000000000000200ULL)
+#define CAP_PDWAIT CAPRIGHT(1, 0x0000000000000400ULL)
+#define CAP_PDKILL CAPRIGHT(1, 0x0000000000000800ULL)
/*
* Rights that allow to use bindat(2) and connectat(2) syscalls on a
* directory descriptor.
*/
-#define CAP_BINDAT 0x0400000000000000ULL
-#define CAP_CONNECTAT 0x0800000000000000ULL
-
-/* The mask of all valid method rights. */
-#define CAP_MASK_VALID 0x0fffffffffffffffULL
-#define CAP_ALL CAP_MASK_VALID
-
-/* Available bits. */
-#define CAP_UNUSED3 0x1000000000000000ULL
-#define CAP_UNUSED2 0x2000000000000000ULL
-#define CAP_UNUSED1 0x4000000000000000ULL
-#define CAP_UNUSED0 0x8000000000000000ULL
-
-/*
- * The following defines are provided for backward API compatibility and
- * should not be used in new code.
- */
-#define CAP_MAPEXEC CAP_MMAP_X
-#define CAP_DELETE CAP_UNLINKAT
-#define CAP_MKDIR CAP_MKDIRAT
-#define CAP_RMDIR CAP_UNLINKAT
-#define CAP_MKFIFO CAP_MKFIFOAT
-#define CAP_MKNOD CAP_MKNODAT
-#define CAP_SOCK_ALL (CAP_SOCK_CLIENT | CAP_SOCK_SERVER)
+#define CAP_BINDAT CAPRIGHT(1, 0x0000000000001000ULL)
+#define CAP_CONNECTAT CAPRIGHT(1, 0x0000000000002000ULL)
+
+/* All used bits for index 1. */
+#define CAP_ALL1 CAPRIGHT(1, 0x0000000000003FFFULL)
+
+/* Available bits for index 1. */
+#define CAP_UNUSED1_15 CAPRIGHT(1, 0x0000000000004000ULL)
+/* ... */
+#define CAP_UNUSED1_57 CAPRIGHT(1, 0x0100000000000000ULL)
+
+#define CAP_ALL(rights) do { \
+ (rights)->cr_rights[0] = \
+ ((uint64_t)CAP_RIGHTS_VERSION << 62) | CAP_ALL0; \
+ (rights)->cr_rights[1] = CAP_ALL1; \
+} while (0)
+
+#define CAP_NONE(rights) do { \
+ (rights)->cr_rights[0] = \
+ ((uint64_t)CAP_RIGHTS_VERSION << 62) | CAPRIGHT(0, 0ULL); \
+ (rights)->cr_rights[1] = CAPRIGHT(1, 0ULL); \
+} while (0)
+
+#define CAPRVER(right) ((int)((right) >> 62))
+#define CAPVER(rights) CAPRVER((rights)->cr_rights[0])
+#define CAPARSIZE(rights) (CAPVER(rights) + 2)
+#define CAPIDXBIT(right) ((int)(((right) >> 57) & 0x1F))
/*
* Allowed fcntl(2) commands.
@@ -230,6 +252,27 @@
#define CAP_IOCTLS_ALL SSIZE_MAX
+#define cap_rights_init(...) \
+ __cap_rights_init(CAP_RIGHTS_VERSION, __VA_ARGS__, 0ULL)
+cap_rights_t *__cap_rights_init(int version, cap_rights_t *rights, ...);
+
+#define cap_rights_set(rights, ...) \
+ __cap_rights_set((rights), __VA_ARGS__, 0ULL)
+void __cap_rights_set(cap_rights_t *rights, ...);
+
+#define cap_rights_clear(rights, ...) \
+ __cap_rights_clear((rights), __VA_ARGS__, 0ULL)
+void __cap_rights_clear(cap_rights_t *rights, ...);
+
+#define cap_rights_is_set(rights, ...) \
+ __cap_rights_is_set((rights), __VA_ARGS__, 0ULL)
+bool __cap_rights_is_set(const cap_rights_t *rights, ...);
+
+bool cap_rights_is_valid(const cap_rights_t *rights);
+void cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src);
+void cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src);
+bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little);
+
#ifdef _KERNEL
#include <sys/systm.h>
@@ -241,17 +284,17 @@ struct filedesc;
/*
* Test whether a capability grants the requested rights.
*/
-int cap_check(cap_rights_t have, cap_rights_t need);
+int cap_check(const cap_rights_t *havep, const cap_rights_t *needp);
/*
* Convert capability rights into VM access flags.
*/
-u_char cap_rights_to_vmprot(cap_rights_t have);
+u_char cap_rights_to_vmprot(cap_rights_t *havep);
/*
* For the purposes of procstat(1) and similar tools, allow kern_descrip.c to
* extract the rights from a capability.
*/
-cap_rights_t cap_rights(struct filedesc *fdp, int fd);
+cap_rights_t *cap_rights(struct filedesc *fdp, int fd);
int cap_ioctl_check(struct filedesc *fdp, int fd, u_long cmd);
int cap_fcntl_check(struct filedesc *fdp, int fd, int cmd);
@@ -259,18 +302,11 @@ int cap_fcntl_check(struct filedesc *fdp, int fd, int cmd);
#else /* !_KERNEL */
__BEGIN_DECLS
-#include <stdbool.h>
-
/*
* cap_enter(): Cause the process to enter capability mode, which will
* prevent it from directly accessing global namespaces. System calls will
* be limited to process-local, process-inherited, or file descriptor
* operations. If already in capability mode, a no-op.
- *
- * Currently, process-inherited operations are not properly handled -- in
- * particular, we're interested in things like waitpid(2), kill(2), etc,
- * being properly constrained. One possible solution is to introduce process
- * descriptors.
*/
int cap_enter(void);
@@ -288,11 +324,12 @@ int cap_getmode(u_int *modep);
/*
* Limits capability rights for the given descriptor (CAP_*).
*/
-int cap_rights_limit(int fd, cap_rights_t rights);
+int cap_rights_limit(int fd, const cap_rights_t *rights);
/*
- * Returns bitmask of capability rights for the given descriptor.
+ * Returns capability rights for the given descriptor.
*/
-int cap_rights_get(int fd, cap_rights_t *rightsp);
+#define cap_rights_get(fd, rights) __cap_rights_get(CAP_RIGHTS_VERSION, (fd), (rights))
+int __cap_rights_get(int version, int fd, cap_rights_t *rightsp);
/*
* Limits allowed ioctls for the given descriptor.
*/
@@ -312,10 +349,6 @@ int cap_fcntls_limit(int fd, uint32_t fcntlrights);
*/
int cap_fcntls_get(int fd, uint32_t *fcntlrightsp);
-/* For backward compatibility. */
-int cap_new(int fd, cap_rights_t rights);
-#define cap_getrights(fd, rightsp) cap_rights_get((fd), (rightsp))
-
__END_DECLS
#endif /* !_KERNEL */
diff --git a/sys/sys/caprights.h b/sys/sys/caprights.h
new file mode 100644
index 0000000..eb8e454
--- /dev/null
+++ b/sys/sys/caprights.h
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2013 FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SYS_CAPRIGHTS_H_
+#define _SYS_CAPRIGHTS_H_
+
+/*
+ * The top two bits in the first element of the cr_rights[] array contain
+ * total number of elements in the array - 2. This means if those two bits are
+ * equal to 0, we have 2 array elements.
+ * The top two bits in all remaining array elements should be 0.
+ * The next five bits contain array index. Only one bit is used and bit position
+ * in this five-bits range defines array index. This means there can be at most
+ * five array elements.
+ */
+#define CAP_RIGHTS_VERSION_00 0
+/*
+#define CAP_RIGHTS_VERSION_01 1
+#define CAP_RIGHTS_VERSION_02 2
+#define CAP_RIGHTS_VERSION_03 3
+*/
+#define CAP_RIGHTS_VERSION CAP_RIGHTS_VERSION_00
+
+struct cap_rights {
+ uint64_t cr_rights[CAP_RIGHTS_VERSION + 2];
+};
+
+#ifndef _CAP_RIGHTS_T_DECLARED
+#define _CAP_RIGHTS_T_DECLARED
+typedef struct cap_rights cap_rights_t;
+#endif
+
+#endif /* !_SYS_CAPRIGHTS_H_ */
diff --git a/sys/sys/file.h b/sys/sys/file.h
index 72c512f..7b373f0 100644
--- a/sys/sys/file.h
+++ b/sys/sys/file.h
@@ -217,12 +217,12 @@ 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, cap_rights_t rights, struct file **fpp);
-int fget_mmap(struct thread *td, int fd, cap_rights_t rights,
+int fget(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp);
+int fget_mmap(struct thread *td, int fd, cap_rights_t *rightsp,
u_char *maxprotp, struct file **fpp);
-int fget_read(struct thread *td, int fd, cap_rights_t rights,
+int fget_read(struct thread *td, int fd, cap_rights_t *rightsp,
struct file **fpp);
-int fget_write(struct thread *td, int fd, cap_rights_t rights,
+int fget_write(struct thread *td, int fd, cap_rights_t *rightsp,
struct file **fpp);
int _fdrop(struct file *fp, struct thread *td);
@@ -248,17 +248,18 @@ fo_sendfile_t vn_sendfile;
fo_seek_t vn_seek;
void finit(struct file *, u_int, short, void *, struct fileops *);
-int fgetvp(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp);
-int fgetvp_exec(struct thread *td, int fd, cap_rights_t rights,
+int fgetvp(struct thread *td, int fd, cap_rights_t *rightsp,
struct vnode **vpp);
-int fgetvp_rights(struct thread *td, int fd, cap_rights_t need,
+int fgetvp_exec(struct thread *td, int fd, cap_rights_t *rightsp,
+ struct vnode **vpp);
+int fgetvp_rights(struct thread *td, int fd, cap_rights_t *needrightsp,
struct filecaps *havecaps, struct vnode **vpp);
-int fgetvp_read(struct thread *td, int fd, cap_rights_t rights,
+int fgetvp_read(struct thread *td, int fd, cap_rights_t *rightsp,
struct vnode **vpp);
-int fgetvp_write(struct thread *td, int fd, cap_rights_t rights,
+int fgetvp_write(struct thread *td, int fd, cap_rights_t *rightsp,
struct vnode **vpp);
-int fgetsock(struct thread *td, int fd, cap_rights_t rights,
+int fgetsock(struct thread *td, int fd, cap_rights_t *rightsp,
struct socket **spp, u_int *fflagp);
void fputsock(struct socket *sp);
diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h
index 9f73915..968ceff 100644
--- a/sys/sys/filedesc.h
+++ b/sys/sys/filedesc.h
@@ -33,6 +33,7 @@
#ifndef _SYS_FILEDESC_H_
#define _SYS_FILEDESC_H_
+#include <sys/caprights.h>
#include <sys/queue.h>
#include <sys/event.h>
#include <sys/lock.h>
@@ -108,10 +109,6 @@ struct filedesc_to_leader {
#ifdef _KERNEL
-#include <sys/systm.h> /* CTASSERT() */
-
-CTASSERT(sizeof(cap_rights_t) == sizeof(uint64_t));
-
/* Flags for do_dup() */
#define DUP_FIXED 0x1 /* Force fixed allocation. */
#define DUP_FCNTL 0x2 /* fcntl()-style errors. */
@@ -163,13 +160,13 @@ 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, cap_rights_t rights,
+int getvnode(struct filedesc *fdp, int fd, cap_rights_t *rightsp,
struct file **fpp);
void mountcheckdirs(struct vnode *olddp, struct vnode *newdp);
void setugidsafety(struct thread *td);
/* Return a referenced file from an unlocked descriptor. */
-int fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t needrights,
+int fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t *needrightsp,
int needfcntl, struct file **fpp, cap_rights_t *haverightsp);
/* Requires a FILEDESC_{S,X}LOCK held and returns without a ref. */
diff --git a/sys/sys/ktrace.h b/sys/sys/ktrace.h
index b3e6be8..e9cfa6e 100644
--- a/sys/sys/ktrace.h
+++ b/sys/sys/ktrace.h
@@ -33,6 +33,8 @@
#ifndef _SYS_KTRACE_H_
#define _SYS_KTRACE_H_
+#include <sys/caprights.h>
+
/*
* operations to ktrace system call (KTROP(op))
*/
@@ -264,7 +266,10 @@ void ktrprocexit(struct thread *);
void ktrprocfork(struct proc *, struct proc *);
void ktruserret(struct thread *);
void ktrstruct(const char *, void *, size_t);
-void ktrcapfail(enum ktr_cap_fail_type, cap_rights_t, cap_rights_t);
+void ktrcapfail(enum ktr_cap_fail_type, const cap_rights_t *,
+ const cap_rights_t *);
+#define ktrcaprights(s) \
+ ktrstruct("caprights", (s), sizeof(cap_rights_t))
#define ktrsockaddr(s) \
ktrstruct("sockaddr", (s), ((struct sockaddr *)(s))->sa_len)
#define ktrstat(s) \
diff --git a/sys/sys/namei.h b/sys/sys/namei.h
index a9992f4..f1b1223 100644
--- a/sys/sys/namei.h
+++ b/sys/sys/namei.h
@@ -33,6 +33,7 @@
#ifndef _SYS_NAMEI_H_
#define _SYS_NAMEI_H_
+#include <sys/caprights.h>
#include <sys/filedesc.h>
#include <sys/queue.h>
#include <sys/uio.h>
@@ -158,32 +159,14 @@ struct nameidata {
NDINIT_ALL(ndp, op, flags, segflg, namep, AT_FDCWD, NULL, 0, td)
#define NDINIT_AT(ndp, op, flags, segflg, namep, dirfd, td) \
NDINIT_ALL(ndp, op, flags, segflg, namep, dirfd, NULL, 0, td)
-#define NDINIT_ATRIGHTS(ndp, op, flags, segflg, namep, dirfd, rights, td) \
- NDINIT_ALL(ndp, op, flags, segflg, namep, dirfd, NULL, rights, td)
+#define NDINIT_ATRIGHTS(ndp, op, flags, segflg, namep, dirfd, rightsp, td) \
+ NDINIT_ALL(ndp, op, flags, segflg, namep, dirfd, NULL, rightsp, td)
#define NDINIT_ATVP(ndp, op, flags, segflg, namep, vp, td) \
NDINIT_ALL(ndp, op, flags, segflg, namep, AT_FDCWD, vp, 0, td)
-static __inline void
-NDINIT_ALL(struct nameidata *ndp,
- u_long op, u_long flags,
- enum uio_seg segflg,
- const char *namep,
- int dirfd,
- struct vnode *startdir,
- cap_rights_t rights,
- struct thread *td)
-{
- ndp->ni_cnd.cn_nameiop = op;
- ndp->ni_cnd.cn_flags = flags;
- ndp->ni_segflg = segflg;
- ndp->ni_dirp = namep;
- ndp->ni_dirfd = dirfd;
- ndp->ni_startdir = startdir;
- ndp->ni_strictrelative = 0;
- ndp->ni_rightsneeded = rights;
- filecaps_init(&ndp->ni_filecaps);
- ndp->ni_cnd.cn_thread = td;
-}
+void NDINIT_ALL(struct nameidata *ndp, u_long op, u_long flags,
+ enum uio_seg segflg, const char *namep, int dirfd, struct vnode *startdir,
+ cap_rights_t *rightsp, struct thread *td);
#define NDF_NO_DVP_RELE 0x00000001
#define NDF_NO_DVP_UNLOCK 0x00000002
diff --git a/sys/sys/procdesc.h b/sys/sys/procdesc.h
index cc8b716..4d77a05 100644
--- a/sys/sys/procdesc.h
+++ b/sys/sys/procdesc.h
@@ -92,8 +92,8 @@ struct procdesc {
* In-kernel interfaces to process descriptors.
*/
int procdesc_exit(struct proc *);
-int procdesc_find(struct thread *, int fd, cap_rights_t, struct proc **);
-int kern_pdgetpid(struct thread *, int fd, cap_rights_t, pid_t *pidp);
+int procdesc_find(struct thread *, int fd, cap_rights_t *, struct proc **);
+int kern_pdgetpid(struct thread *, int fd, cap_rights_t *, pid_t *pidp);
void procdesc_new(struct proc *, int);
void procdesc_finit(struct procdesc *, struct file *);
pid_t procdesc_pid(struct file *);
diff --git a/sys/sys/types.h b/sys/sys/types.h
index cc0bca8..03eaa60 100644
--- a/sys/sys/types.h
+++ b/sys/sys/types.h
@@ -88,8 +88,6 @@ typedef __blkcnt_t blkcnt_t;
#define _BLKCNT_T_DECLARED
#endif
-typedef __cap_rights_t cap_rights_t;
-
#ifndef _CLOCK_T_DECLARED
typedef __clock_t clock_t;
#define _CLOCK_T_DECLARED
@@ -234,6 +232,13 @@ typedef __useconds_t useconds_t; /* microseconds (unsigned) */
#define _USECONDS_T_DECLARED
#endif
+#ifndef _CAP_RIGHTS_T_DECLARED
+#define _CAP_RIGHTS_T_DECLARED
+struct cap_rights;
+
+typedef struct cap_rights cap_rights_t;
+#endif
+
typedef __vm_offset_t vm_offset_t;
typedef __vm_ooffset_t vm_ooffset_t;
typedef __vm_paddr_t vm_paddr_t;
diff --git a/sys/sys/user.h b/sys/sys/user.h
index 9389e55..349003d 100644
--- a/sys/sys/user.h
+++ b/sys/sys/user.h
@@ -61,6 +61,7 @@
#ifndef _SYS_SOCKET_VAR_H_
#include <sys/socket.h>
#endif
+#include <sys/caprights.h>
/*
* KERN_PROC subtype ops return arrays of selected proc structure entries:
@@ -318,7 +319,7 @@ struct kinfo_ofile {
};
#if defined(__amd64__) || defined(__i386__)
-#define KINFO_FILE_SIZE 1392
+#define KINFO_FILE_SIZE 1424
#endif
struct kinfo_file {
@@ -389,6 +390,7 @@ struct kinfo_file {
uint16_t kf_pad1; /* Round to 32 bit alignment. */
int _kf_ispare0; /* Space for more stuff. */
cap_rights_t kf_cap_rights; /* Capability rights. */
+ uint64_t _kf_cap_spare[3]; /* Space for future cap_rights_t. */
int _kf_ispare[4]; /* Space for more stuff. */
/* Truncated before copyout in sysctl */
char kf_path[PATH_MAX]; /* Path to file, if any. */
diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c
index 3063ade..19e880c 100644
--- a/sys/ufs/ffs/ffs_alloc.c
+++ b/sys/ufs/ffs/ffs_alloc.c
@@ -2709,6 +2709,7 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS)
long blkcnt, blksize;
struct filedesc *fdp;
struct file *fp, *vfp;
+ cap_rights_t rights;
int filetype, error;
static struct fileops *origops, bufferedops;
@@ -2718,8 +2719,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, CAP_FSCK,
- &fp)) != 0)
+ if ((error = getvnode(td->td_proc->p_fd, cmd.handle,
+ cap_rights_init(&rights, CAP_FSCK), &fp)) != 0)
return (error);
vp = fp->f_data;
if (vp->v_type != VREG && vp->v_type != VDIR) {
@@ -3033,7 +3034,7 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS)
}
#endif /* DEBUG */
if ((error = getvnode(td->td_proc->p_fd, cmd.value,
- CAP_FSCK, &vfp)) != 0)
+ cap_rights_init(&rights, CAP_FSCK), &vfp)) != 0)
break;
if (vfp->f_vnode->v_type != VCHR) {
fdrop(vfp, td);
diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c
index 53a7be5..77f64f4 100644
--- a/sys/vm/vm_mmap.c
+++ b/sys/vm/vm_mmap.c
@@ -311,17 +311,17 @@ sys_mmap(td, uap)
* rights, but also return the maximum rights to be combined
* with maxprot later.
*/
- rights = CAP_MMAP;
+ cap_rights_init(&rights, CAP_MMAP);
if (prot & PROT_READ)
- rights |= CAP_MMAP_R;
+ cap_rights_set(&rights, CAP_MMAP_R);
if ((flags & MAP_SHARED) != 0) {
if (prot & PROT_WRITE)
- rights |= CAP_MMAP_W;
+ cap_rights_set(&rights, CAP_MMAP_W);
}
if (prot & PROT_EXEC)
- rights |= CAP_MMAP_X;
- if ((error = fget_mmap(td, uap->fd, rights, &cap_maxprot,
- &fp)) != 0)
+ cap_rights_set(&rights, CAP_MMAP_X);
+ error = fget_mmap(td, uap->fd, &rights, &cap_maxprot, &fp);
+ if (error != 0)
goto done;
if (fp->f_type == DTYPE_SHM) {
handle = fp->f_data;
OpenPOWER on IntegriCloud