From 2d896b816b7a55f8093cd3959c231c2bd549cc94 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Thu, 19 Mar 2020 15:39:45 +0000 Subject: Enter a write sequence when updating rights. The Capsicum system calls modify file descriptor table entries. To ensure that readers observe a consistent snapshot of descriptor writes, the system calls need to signal to unlocked readers that an update is pending. Note that ioctl rights are always checked with the descriptor table lock held, so it is not strictly necessary to signal unlocked readers. However, we probably want to enable lockless ioctl checks eventually, so use seqc_write_begin() in kern_cap_ioctls_limit() too. Reviewed by: kib MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D24119 --- sys/kern/sys_capability.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'sys/kern/sys_capability.c') diff --git a/sys/kern/sys_capability.c b/sys/kern/sys_capability.c index e1eb0faf29a3..6f97b74a0a53 100644 --- a/sys/kern/sys_capability.c +++ b/sys/kern/sys_capability.c @@ -234,6 +234,7 @@ kern_cap_rights_limit(struct thread *td, int fd, cap_rights_t *rights) { struct filedesc *fdp; struct filedescent *fdep; + u_long *ioctls; int error; fdp = td->td_proc->p_fd; @@ -243,18 +244,22 @@ kern_cap_rights_limit(struct thread *td, int fd, cap_rights_t *rights) FILEDESC_XUNLOCK(fdp); return (EBADF); } + ioctls = NULL; error = _cap_check(cap_rights(fdp, fd), rights, CAPFAIL_INCREASE); if (error == 0) { + seqc_write_begin(&fdep->fde_seqc); fdep->fde_rights = *rights; if (!cap_rights_is_set(rights, CAP_IOCTL)) { - free(fdep->fde_ioctls, M_FILECAPS); + ioctls = fdep->fde_ioctls; fdep->fde_ioctls = NULL; fdep->fde_nioctls = 0; } if (!cap_rights_is_set(rights, CAP_FCNTL)) fdep->fde_fcntls = 0; + seqc_write_end(&fdep->fde_seqc); } FILEDESC_XUNLOCK(fdp); + free(ioctls, M_FILECAPS); return (error); } @@ -439,8 +444,10 @@ kern_cap_ioctls_limit(struct thread *td, int fd, u_long *cmds, size_t ncmds) goto out; ocmds = fdep->fde_ioctls; + seqc_write_begin(&fdep->fde_seqc); fdep->fde_ioctls = cmds; fdep->fde_nioctls = ncmds; + seqc_write_end(&fdep->fde_seqc); cmds = ocmds; error = 0; @@ -597,7 +604,9 @@ sys_cap_fcntls_limit(struct thread *td, struct cap_fcntls_limit_args *uap) return (ENOTCAPABLE); } + seqc_write_begin(&fdep->fde_seqc); fdep->fde_fcntls = fcntlrights; + seqc_write_end(&fdep->fde_seqc); FILEDESC_XUNLOCK(fdp); return (0); -- cgit v1.2.3