On Mon, Jan 16, 2017 at 08:36:46PM +0100, [email protected] wrote:
> kernel: protection fault trap, code=0
> Stopped at fd_getfile+0x20: testb $0x2,mptramp_gdt32_desc+0x1e(%r
> ax)
> ddb{3}> fd_getfile() at fd_getfile+0x20
> sys_fstat() at sys_fstat+0x43
> syscall() at syscall+0x27b

It crashes in fd_getfile() FILE_IS_USABLE(fp) as fdp->fd_ofiles has
been freed.

fdexpand() assumes that is has the write lock, calls free(fdp->fd_ofiles)
and then sleeps in mallocarray(M_WAITOK) before updating fdp->fd_ofiles.

As fd_getfile() does not grab a readlock, it may get scheduled while
fdexpand() sleeps.

Simply calling rw_enter_read(&fdp->fd_lock) in fd_getfile() does
not work, as sometimes it is called with the writelock already held.
Not sure wether such a write lock check is nice style, but it avoids
to fix all callers.

cheeky.m: How often does it crash?  Can you test wether this fixes
your problem?

bluhm

Index: kern/kern_descrip.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/kern/kern_descrip.c,v
retrieving revision 1.136
diff -u -p -r1.136 kern_descrip.c
--- kern/kern_descrip.c 24 Sep 2016 18:39:17 -0000      1.136
+++ kern/kern_descrip.c 16 Jan 2017 23:16:24 -0000
@@ -183,12 +183,19 @@ struct file *
 fd_getfile(struct filedesc *fdp, int fd)
 {
        struct file *fp;
+       int locked;
 
-       if ((u_int)fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL)
-               return (NULL);
+       locked = (rw_status(&fdp->fd_lock) == RW_WRITE);
+       if (!locked)
+               rw_enter_read(&fdp->fd_lock);
 
-       if (!FILE_IS_USABLE(fp))
-               return (NULL);
+       if ((u_int)fd >= fdp->fd_nfiles ||
+           (fp = fdp->fd_ofiles[fd]) == NULL ||
+           !FILE_IS_USABLE(fp))
+               fp = NULL;
+
+       if (!locked)
+               rw_exit_read(&fdp->fd_lock);
 
        return (fp);
 }

Reply via email to