diff options
author | Mark Johnston <markj@FreeBSD.org> | 2019-06-29 16:11:09 +0000 |
---|---|---|
committer | Mark Johnston <markj@FreeBSD.org> | 2019-06-29 16:11:09 +0000 |
commit | 7c3703a69466c7088a0900e2ee643e59b59ae846 (patch) | |
tree | f3acdcc061d25e25c22f52bbd9e1e41d69cf709d | |
parent | 02476c44c5eb0a9cd9f41e4921b113b56f49f3e8 (diff) | |
download | src-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.c | 12 |
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); } |