summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_descrip.c21
-rw-r--r--sys/kern/kern_event.c21
2 files changed, 35 insertions, 7 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index d967d543b38..a9adcb7a83e 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_descrip.c,v 1.192 2019/08/05 08:35:59 anton Exp $ */
+/* $OpenBSD: kern_descrip.c,v 1.193 2020/01/03 05:37:00 visa Exp $ */
/* $NetBSD: kern_descrip.c,v 1.42 1996/03/30 22:24:38 christos Exp $ */
/*
@@ -262,6 +262,18 @@ fd_getfile_mode(struct filedesc *fdp, int fd, int mode)
return (fp);
}
+int
+fd_checkclosed(struct filedesc *fdp, int fd, struct file *fp)
+{
+ int closed;
+
+ mtx_enter(&fdp->fd_fplock);
+ KASSERT(fd < fdp->fd_nfiles);
+ closed = (fdp->fd_ofiles[fd] != fp);
+ mtx_leave(&fdp->fd_fplock);
+ return (closed);
+}
+
/*
* System calls on descriptors.
*/
@@ -396,7 +408,7 @@ sys_fcntl(struct proc *p, void *v, register_t *retval)
} */ *uap = v;
int fd = SCARG(uap, fd);
struct filedesc *fdp = p->p_fd;
- struct file *fp, *fp2;
+ struct file *fp;
struct vnode *vp;
int i, tmp, newmin, flg = F_POSIX;
struct flock fl;
@@ -570,8 +582,7 @@ restart:
goto out;
}
- fp2 = fd_getfile(fdp, fd);
- if (fp != fp2) {
+ if (fd_checkclosed(fdp, fd, fp)) {
/*
* We have lost the race with close() or dup2();
* unlock, pretend that we've won the race and that
@@ -583,8 +594,6 @@ restart:
VOP_ADVLOCK(vp, fdp, F_UNLCK, &fl, F_POSIX);
fl.l_type = F_UNLCK;
}
- if (fp2 != NULL)
- FRELE(fp2, p);
goto out;
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index c634353caa5..3141af589ce 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_event.c,v 1.113 2019/12/31 14:09:56 visa Exp $ */
+/* $OpenBSD: kern_event.c,v 1.114 2020/01/03 05:37:00 visa Exp $ */
/*-
* Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org>
@@ -724,6 +724,25 @@ again:
knote_drop(kn, p);
goto done;
}
+
+ /*
+ * If this is a file descriptor filter, check if
+ * fd was closed while the knote was being added.
+ * knote_fdclose() has missed kn if the function
+ * ran before kn appeared in kq_knlist.
+ */
+ if (fops->f_isfd &&
+ fd_checkclosed(fdp, kev->ident, kn->kn_fp)) {
+ /*
+ * Drop the knote silently without error
+ * because another thread might already have
+ * seen it. This corresponds to the insert
+ * happening in full before the close.
+ */
+ kn->kn_fop->f_detach(kn);
+ knote_drop(kn, p);
+ goto done;
+ }
} else {
/*
* The user may change some filter values after the