aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2019-06-29 16:11:09 +0000
committerMark Johnston <markj@FreeBSD.org>2019-06-29 16:11:09 +0000
commit7c3703a69466c7088a0900e2ee643e59b59ae846 (patch)
treef3acdcc061d25e25c22f52bbd9e1e41d69cf709d
parent02476c44c5eb0a9cd9f41e4921b113b56f49f3e8 (diff)
downloadsrc-7c3703a69466c7088a0900e2ee643e59b59ae846.tar.gz
src-7c3703a69466c7088a0900e2ee643e59b59ae846.zip
Use a consistent snapshot of the fd's rights in fget_mmap().
fget_mmap() translates rights on the descriptor to a VM protection mask. It was doing so without holding any locks on the descriptor table, so a writer could simultaneously be modifying those rights. Such a situation would be detected using a sequence counter, but not before an inconsistency could trigger assertion failures in the capability code. Fix the problem by copying the fd's rights to a structure on the stack, and perform the translation only once we know that that snapshot is consistent. Reported by: syzbot+ae359438769fda1840f8@syzkaller.appspotmail.com Reviewed by: brooks, mjg MFC after: 1 week Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D20800
Notes
Notes: svn path=/head/; revision=349547
-rw-r--r--sys/kern/kern_descrip.c12
1 files changed, 8 insertions, 4 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 4bc1a1546820..a6c766f71985 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -2761,6 +2761,7 @@ fget_mmap(struct thread *td, int fd, cap_rights_t *rightsp, u_char *maxprotp,
if (maxprotp != NULL)
*maxprotp = VM_PROT_ALL;
#else
+ cap_rights_t fdrights;
struct filedesc *fdp = td->td_proc->p_fd;
seqc_t seq;
@@ -2769,15 +2770,18 @@ fget_mmap(struct thread *td, int fd, cap_rights_t *rightsp, u_char *maxprotp,
error = _fget(td, fd, fpp, 0, rightsp, &seq);
if (error != 0)
return (error);
- /*
- * If requested, convert capability rights to access flags.
- */
if (maxprotp != NULL)
- *maxprotp = cap_rights_to_vmprot(cap_rights(fdp, fd));
+ fdrights = *cap_rights(fdp, fd);
if (!fd_modified(fdp, fd, seq))
break;
fdrop(*fpp, td);
}
+
+ /*
+ * If requested, convert capability rights to access flags.
+ */
+ if (maxprotp != NULL)
+ *maxprotp = cap_rights_to_vmprot(&fdrights);
#endif
return (error);
}