Skip to content

Commit

Permalink
During F_SETFL, don't change file flags on error
Browse files Browse the repository at this point in the history
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 <[email protected]>
MFC after:	2 weeks
Reviewed by:	kib
Differential Revision: https://reviews.freebsd.org/D40955
  • Loading branch information
asomers committed Jul 10, 2023
1 parent 8ab2da6 commit 6c04999
Showing 1 changed file with 12 additions and 5 deletions.
17 changes: 12 additions & 5 deletions sys/kern/kern_descrip.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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) {
Expand All @@ -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;

Expand Down

0 comments on commit 6c04999

Please sign in to comment.