If a process exit(3)s while one of its threads is blocking in accept(2)
and the half-opened descriptor has already been dup'ed, we get the
following panic:

panic: closef: count (1) < 2
Stopped at      db_enter+0x5:   popq    %rbp
TID    PID    UID     PRFLAGS     PFLAGS  CPU  COMMAND
*204115  80020      0      0x1003    0x80000    0K dup2_accept
db_enter() at db_enter+0x5
panic() at panic+0x120
closef(ffffff000583d948,ffff8000ffffa020) at closef+0x145
doaccept(1e0,ffff8000ffffa020,1e,ffff8000039a03c0,7f7ffffc9d58,bc7efe80dd509fa1)
 at doaccept+0x2a3
syscall(1) at syscall+0x31d
Xsyscall_untramp(6,0,0,0,0,1e) at Xsyscall_untramp+0xc0
end of kernel

A test for this problem can be found there:
  https://marc.info/?l=openbsd-tech&m=152637351632752&w=2

Diff below prevents the problem by returning EBUSY in dup2(2) & friends
like Linux does when trying to dup an half-opened file.  I'd like to
reuse this logic to keep the future locking simple, ok?

Index: sys/kern/kern_descrip.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_descrip.c,v
retrieving revision 1.158
diff -u -p -r1.158 kern_descrip.c
--- sys/kern/kern_descrip.c     8 May 2018 09:03:58 -0000       1.158
+++ sys/kern/kern_descrip.c     21 May 2018 12:12:50 -0000
@@ -634,13 +634,14 @@ finishdup(struct proc *p, struct file *f
                return (EDEADLK);
        }
 
-       /*
-        * Don't fd_getfile here. We want to closef LARVAL files and
-        * closef can deal with that.
-        */
        oldfp = fdp->fd_ofiles[new];
-       if (oldfp != NULL)
+       if (oldfp != NULL) {
+               if (!FILE_IS_USABLE(oldfp)) {
+                       FRELE(fp, p);
+                       return (EBUSY);
+               }
                FREF(oldfp);
+       }
 
        fdp->fd_ofiles[new] = fp;
        fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] & ~UF_EXCLOSE;
Index: lib/libc/sys//dup.2
===================================================================
RCS file: /cvs/src/lib/libc/sys/dup.2,v
retrieving revision 1.18
diff -u -p -r1.18 dup.2
--- lib/libc/sys//dup.2 10 Dec 2014 19:46:48 -0000      1.18
+++ lib/libc/sys//dup.2 21 May 2018 12:12:38 -0000
@@ -157,6 +157,10 @@ is not a valid active descriptor or
 is negative or greater than or equal to the process's
 .Dv RLIMIT_NOFILE
 limit.
+.It Bq Er EBUSY
+A race condition with
+.Xr accept 2
+has been detected.
 .It Bq Er EINTR
 An interrupt was received.
 .It Bq Er EIO

Reply via email to