From owner-freebsd-bugs@FreeBSD.ORG Tue Aug 17 19:40:23 2004 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 2577316A4CE for ; Tue, 17 Aug 2004 19:40:23 +0000 (GMT) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id 034AF43D62 for ; Tue, 17 Aug 2004 19:40:22 +0000 (GMT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.12.11/8.12.11) with ESMTP id i7HJeLUd071500 for ; Tue, 17 Aug 2004 19:40:21 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.12.11/8.12.11/Submit) id i7HJeLw0071491; Tue, 17 Aug 2004 19:40:21 GMT (envelope-from gnats) Resent-Date: Tue, 17 Aug 2004 19:40:21 GMT Resent-Message-Id: <200408171940.i7HJeLw0071491@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Uwe Doering Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id BF72D16A4CE for ; Tue, 17 Aug 2004 19:40:05 +0000 (GMT) Received: from gen129.n001.c02.escapebox.net (gen129.n001.c02.escapebox.net [213.73.91.129]) by mx1.FreeBSD.org (Postfix) with ESMTP id CC07E43D53 for ; Tue, 17 Aug 2004 19:40:04 +0000 (GMT) (envelope-from gemini@geminix.org) Received: from gemini by geminix.org with local (Exim 3.36 #1) id 1Bx9oP-0006aG-00; Tue, 17 Aug 2004 21:40:01 +0200 Message-Id: Date: Tue, 17 Aug 2004 21:40:01 +0200 From: Uwe Doering To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Subject: kern/70587: NULL pointer dereference in vm_pageout_scan() X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list Reply-To: Uwe Doering List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 17 Aug 2004 19:40:23 -0000 >Number: 70587 >Category: kern >Synopsis: NULL pointer dereference in vm_pageout_scan() >Confidential: no >Severity: critical >Priority: high >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Tue Aug 17 19:40:21 GMT 2004 >Closed-Date: >Last-Modified: >Originator: Uwe Doering >Release: FreeBSD 4.5-RELEASE i386 >Organization: EscapeBox - Managed On-Demand UNIX Servers http://www.escapebox.net >Environment: System: FreeBSD geminix.org 4.5-RELEASE FreeBSD 4.5-RELEASE #1: Sun Aug 15 10:59:08 GMT 2004 root@localhost:/STABLE_Enhanced_Edition i386 >Description: A couple of days ago one of our normally extremely stable server machines panicked due to a NULL pointer dereference. While we didn't get a kernel dump we at least had the instruction pointer and the offending data address. After disassembling the respective part of the kernel it became clear that the pointer in the 'object' field of the relevant 'vm_page_t' structure was NULL at the time and was beeing used without checking it for NULL first. Here's the section of code where it happened (in vm_pageout.c:vm_pageout_scan()): /* * If the object is not being used, we ignore previous * references. */ if (m->object->ref_count == 0) { vm_page_flag_clear(m, PG_REFERENCED); pmap_clear_reference(m); Now, the original assumption when this code had been written may well have been that it can never happen that a page on the inactive queue is _not_ associated with an object. The crash we experienced unfortunately proves the opposite. And we also found that other parts of the kernel certainly don't trust the 'object' field blindly. >How-To-Repeat: I have no idea how to repeat that condition. We are running several servers for over two years in production now, and this was the first time it happend to us. I speculate that the 'object' field being NULL is just a transitory state that became apparent due to a race condition. Otherwise it should have hit us more frequently in the past. >Fix: Please consider adopting the patch below. We take the pragmatic approach and skip the page if it isn't associated with an object, on the assumption that this state will be short-lived, and also because in this context we wouldn't know what to do with a page like this, anyway. The patch deals with the scanning loops for both the inactive and active queue. --- vm_pageout.c.diff begins here --- --- src/sys/vm/vm_pageout.c.orig Mon Mar 11 16:48:15 2002 +++ src/sys/vm/vm_pageout.c Mon Aug 2 13:30:57 2004 @@ -704,7 +704,7 @@ /* * A held page may be undergoing I/O, so skip it. */ - if (m->hold_count) { + if (m->hold_count || m->object == NULL) { s = splvm(); TAILQ_REMOVE(&vm_page_queues[PQ_INACTIVE].pl, m, pageq); TAILQ_INSERT_TAIL(&vm_page_queues[PQ_INACTIVE].pl, m, pageq); @@ -988,7 +988,8 @@ */ if ((m->busy != 0) || (m->flags & PG_BUSY) || - (m->hold_count != 0)) { + (m->hold_count != 0) || + (m->object == NULL)) { s = splvm(); TAILQ_REMOVE(&vm_page_queues[PQ_ACTIVE].pl, m, pageq); TAILQ_INSERT_TAIL(&vm_page_queues[PQ_ACTIVE].pl, m, pageq); --- vm_pageout.c.diff ends here --- >Release-Note: >Audit-Trail: >Unformatted: