From delphij@delphij.net  Thu Jan 18 03:02:51 2007
Return-Path: <delphij@delphij.net>
Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52])
	by hub.freebsd.org (Postfix) with ESMTP id 6132816A494
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 18 Jan 2007 03:02:51 +0000 (UTC)
	(envelope-from delphij@delphij.net)
Received: from tarsier.geekcn.org (tarsier.geekcn.org [210.51.165.229])
	by mx1.freebsd.org (Postfix) with ESMTP id 0CC0913C442
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 18 Jan 2007 03:02:51 +0000 (UTC)
	(envelope-from delphij@delphij.net)
Received: from localhost (tarsier.geekcn.org [210.51.165.229])
	by tarsier.geekcn.org (Postfix) with ESMTP id BB213EB09FC
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 18 Jan 2007 11:02:47 +0800 (CST)
Received: from tarsier.geekcn.org ([210.51.165.229])
	by localhost (mail.geekcn.org [210.51.165.229]) (amavisd-new, port 10024)
	with ESMTP id U3EYL3O9pRC2 for <FreeBSD-gnats-submit@freebsd.org>;
	Thu, 18 Jan 2007 11:02:34 +0800 (CST)
Received: from tarsier.delphij.net (tarsier.geekcn.org [210.51.165.229])
	(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by tarsier.geekcn.org (Postfix) with ESMTP id 53A10EB08F3
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 18 Jan 2007 11:02:33 +0800 (CST)
Received: from tarsier.delphij.net (localhost [127.0.0.1])
	by tarsier.delphij.net (8.13.8/8.13.8) with ESMTP id l0I32WQu059497
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 18 Jan 2007 11:02:32 +0800 (CST)
	(envelope-from delphij@delphij.net)
Received: (from delphij@localhost)
	by tarsier.delphij.net (8.13.8/8.13.8/Submit) id l0I32S4H059407;
	Thu, 18 Jan 2007 11:02:28 +0800 (CST)
	(envelope-from delphij)
Message-Id: <200701180302.l0I32S4H059407@tarsier.delphij.net>
Date: Thu, 18 Jan 2007 11:02:28 +0800 (CST)
From: Xin LI <delphij@delphij.net>
Reply-To: Xin LI <delphij@delphij.net>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: [PATCH] Panic in [sg]etpriority() due to NULL pointer deference
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         108071
>Category:       kern
>Synopsis:       [kernel] [patch] Panic in [sg]etpriority() due to NULL pointer deference
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    delphij
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Jan 18 03:10:20 GMT 2007
>Closed-Date:    Thu Jul 19 23:26:24 GMT 2007
>Last-Modified:  Thu Jul 19 23:26:24 GMT 2007
>Originator:     Xin LI
>Release:        FreeBSD 6.2-RELEASE i386
>Organization:
The FreeBSD Project
>Environment:
System: FreeBSD tarsier.delphij.net 6.2-RELEASE FreeBSD 6.2-RELEASE #0: Fri Jan 12 12:23:27 CST 2007 delphij@tarsier.delphij.net:/usr/obj/usr/src/sys/TARSIER i386


>Description:
	There is a race between fork(2) and [sg]etpriority where when a
newly born process in allproc list, [sg]etpriority could end up with a
NULL deference which would lead to a panic.
>How-To-Repeat:
	The following shell script would demostrate the race and can easily
trigger panic with non-privileged user, on a multi-core system, in my case
Dell 2950:

--- demo.sh begins here ---
#!/bin/sh

P=0

while [ ${P} -lt 200 ];
do
        sleep 3 &
        renice +4 -u delphij &
        sleep 3 &
        renice +4 -u delphij &
        sleep 3 &
        renice +4 -u delphij &
        sleep 3 &
        renice +4 -u delphij &
        P=`expr ${P} + 1`
done
--- demo.sh ends here ---

>Fix:
	An easy fix for this would be to guard with PRS_NEW state
by just skipping it.  However, we are still looking for better
solution for the issue.

--- patch-kern_resource.c begins here ---
Index: kern_resource.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_resource.c,v
retrieving revision 1.164
diff -u -p -r1.164 kern_resource.c
--- kern_resource.c	6 Dec 2006 06:34:55 -0000	1.164
+++ kern_resource.c	18 Jan 2007 02:27:53 -0000
@@ -143,6 +143,8 @@ getpriority(td, uap)
 			uap->who = td->td_ucred->cr_uid;
 		sx_slock(&allproc_lock);
 		LIST_FOREACH(p, &allproc, p_list) {
+			if (p->p_state == PRS_NEW)
+				continue;
 			PROC_LOCK(p);
 			if (!p_cansee(td, p) &&
 			    p->p_ucred->cr_uid == uap->who) {
@@ -230,6 +232,8 @@ setpriority(td, uap)
 			uap->who = td->td_ucred->cr_uid;
 		sx_slock(&allproc_lock);
 		FOREACH_PROC_IN_SYSTEM(p) {
+			if (p->p_state == PRS_NEW)
+				continue;
 			PROC_LOCK(p);
 			if (p->p_ucred->cr_uid == uap->who &&
 			    !p_cansee(td, p)) {
--- patch-kern_resource.c ends here ---


>Release-Note:
>Audit-Trail:
State-Changed-From-To: open->analyzed 
State-Changed-By: delphij 
State-Changed-When: Thu Jan 18 06:11:54 UTC 2007 
State-Changed-Why:  
This is undergoing discussion. 


Responsible-Changed-From-To: freebsd-bugs->delphij 
Responsible-Changed-By: delphij 
Responsible-Changed-When: Thu Jan 18 06:11:54 UTC 2007 
Responsible-Changed-Why:  
My PR. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=108071 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/108071: commit references a PR
Date: Mon, 26 Feb 2007 03:38:16 +0000 (UTC)

 delphij     2007-02-26 03:38:10 UTC
 
   FreeBSD src repository
 
   Modified files:
     sys/kern             kern_fork.c kern_resource.c 
   Log:
   Close race conditions between fork() and [sg]etpriority()'s
   PRIO_USER case, possibly also other places that deferences
   p_ucred.
   
   In the past, we insert a new process into the allproc list right
   after PID allocation, and release the allproc_lock sx.  Because
   most content in new proc's structure is not yet initialized,
   this could lead to undefined result if we do not handle PRS_NEW
   with care.
   
   The problem with PRS_NEW state is that it does not provide fine
   grained information about how much initialization is done for a
   new process.  By defination, after PRIO_USER setpriority(), all
   processes that belongs to given user should have their nice value
   set to the specified value.  Therefore, if p_{start,end}copy
   section was done for a PRS_NEW process, we can not safely ignore
   it because p_nice is in this area.  On the other hand, we should
   be careful on PRS_NEW processes because we do not allow non-root
   users to lower their nice values, and without a successful copy
   of the copy section, we can get stale values that is inherted
   from the uninitialized area of the process structure.
   
   This commit tries to close the race condition by grabbing proc
   mutex *before* we release allproc_lock xlock, and do copy as
   well as zero immediately after the allproc_lock xunlock.  This
   guarantees that the new process would have its p_copy and p_zero
   sections, as well as user credential informaion initialized.  In
   getpriority() case, instead of grabbing PROC_LOCK for a PRS_NEW
   process, we just skip the process in question, because it does
   not affect the final result of the call, as the p_nice value
   would be copied from its parent, and we will see it during
   allproc traverse.
   
   Other potential solutions are still under evaluation.
   
   Discussed with: davidxu, jhb, rwatson
   PR:             kern/108071
   MFC after:      2 weeks
   
   Revision  Changes    Path
   1.267     +14 -5     src/sys/kern/kern_fork.c
   1.167     +3 -0      src/sys/kern/kern_resource.c
 _______________________________________________
 cvs-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/cvs-all
 To unsubscribe, send any mail to "cvs-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: analyzed->closed 
State-Changed-By: delphij 
State-Changed-When: Thu Jul 19 23:25:57 UTC 2007 
State-Changed-Why:  
A patch applied against -CURRENT and was recently MFC'ed by 
jhb@. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=108071 
>Unformatted:
