During F_SETFL, don't change file flags on error
Previously, even if the FIONBIO or FIOASYNC ioctl failed, the file's f_flags variable would still be changed. Now, kern_fcntl will restore the original flags if the ioctl fails. PR: 265736 Reported by: Yuval Pavel Zholkover <paulzhol@gmail.com> MFC after: 2 weeks Reviewed by: kib Differential Revision: https://reviews.freebsd.org/D40955
This commit is contained in:
parent
8ab2da6828
commit
6c049996ec
@ -495,7 +495,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
|
||||
struct vnode *vp;
|
||||
struct mount *mp;
|
||||
struct kinfo_file *kif;
|
||||
int error, flg, kif_sz, seals, tmp;
|
||||
int error, flg, kif_sz, seals, tmp, got_set, got_cleared;
|
||||
uint64_t bsize;
|
||||
off_t foffset;
|
||||
|
||||
@ -573,12 +573,12 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
|
||||
tmp &= ~FCNTLFLAGS;
|
||||
tmp |= FFLAGS(arg & ~O_ACCMODE) & FCNTLFLAGS;
|
||||
} while (atomic_cmpset_int(&fp->f_flag, flg, tmp) == 0);
|
||||
got_set = tmp & ~flg;
|
||||
got_cleared = flg & ~tmp;
|
||||
tmp = fp->f_flag & FNONBLOCK;
|
||||
error = fo_ioctl(fp, FIONBIO, &tmp, td->td_ucred, td);
|
||||
if (error != 0) {
|
||||
fdrop(fp, td);
|
||||
break;
|
||||
}
|
||||
if (error != 0)
|
||||
goto revert_f_setfl;
|
||||
tmp = fp->f_flag & FASYNC;
|
||||
error = fo_ioctl(fp, FIOASYNC, &tmp, td->td_ucred, td);
|
||||
if (error == 0) {
|
||||
@ -588,6 +588,13 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
|
||||
atomic_clear_int(&fp->f_flag, FNONBLOCK);
|
||||
tmp = 0;
|
||||
(void)fo_ioctl(fp, FIONBIO, &tmp, td->td_ucred, td);
|
||||
revert_f_setfl:
|
||||
do {
|
||||
tmp = flg = fp->f_flag;
|
||||
tmp &= ~FCNTLFLAGS;
|
||||
tmp |= got_cleared;
|
||||
tmp &= ~got_set;
|
||||
} while (atomic_cmpset_int(&fp->f_flag, flg, tmp) == 0);
|
||||
fdrop(fp, td);
|
||||
break;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user