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);
}