From dm@home3.dinoex.sub.de  Sun Jul 19 10:52:39 2009
Return-Path: <dm@home3.dinoex.sub.de>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 8A843106566B
	for <FreeBSD-gnats-submit@freebsd.org>; Sun, 19 Jul 2009 10:52:39 +0000 (UTC)
	(envelope-from dm@home3.dinoex.sub.de)
Received: from uucp.dinoex.sub.de (uucp.dinoex.sub.de [194.45.71.2])
	by mx1.freebsd.org (Postfix) with ESMTP id 1D20F8FC17
	for <FreeBSD-gnats-submit@freebsd.org>; Sun, 19 Jul 2009 10:52:38 +0000 (UTC)
	(envelope-from dm@home3.dinoex.sub.de)
Received: from home3.dinoex.sub.de (home3.dinoex.sub.de [194.45.71.20])
	by uucp.dinoex.sub.de (8.14.3/8.14.2) with ESMTP id n6JAprsI005662
	for <FreeBSD-gnats-submit@freebsd.org>; Sun, 19 Jul 2009 12:52:09 +0200 (CEST)
	(envelope-from dm@home3.dinoex.sub.de)
Received: (from dm@localhost)
	by home3.dinoex.sub.de (8.14.3/8.14.3/Submit) id n6JAqcwg068851;
	Sun, 19 Jul 2009 12:52:38 +0200 (CEST)
	(envelope-from dm)
Message-Id: <200907191052.n6JAqcwg068851@home3.dinoex.sub.de>
Date: Sun, 19 Jul 2009 12:52:38 +0200 (CEST)
From: Dirk Meyer <dirk.meyer+gnats@dinoex.sub.org>
Reply-To: Dirk Meyer <dirk.meyer+gnats@dinoex.sub.org>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: upd/jail LOR after reboot
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         136899
>Category:       kern
>Synopsis:       [jail] [lor] upd/jail LOR after reboot
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-jail
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Jul 19 11:00:17 UTC 2009
>Closed-Date:    Thu Jul 30 15:54:37 UTC 2009
>Last-Modified:  Thu Jul 30 15:54:37 UTC 2009
>Originator:     Dirk Meyer
>Release:        FreeBSD 8.0-BETA2 i386
>Organization:
>Environment:

FreeBSD root8.dinoex.sub.de 8.0-BETA2 FreeBSD 8.0-BETA2 #15: Sat Jul 18 18:02:18 CEST 2009     root@root8.dinoex.sub.de:/usr/obj/usr/src/sys/GENERIC  i386

>Description:

Trying to mount root from ufs:/dev/ad0s1a
lock order reversal:
 1st 0xc6046270 ufs (ufs) @ /usr/src/sys/kern/vfs_mount.c:1054
 2nd 0xc6046058 devfs (devfs) @ /usr/src/sys/kern/vfs_subr.c:2083
KDB: stack backtrace:
db_trace_self_wrapper(c0c871b4,e80b1818,c08ce405,c08bedcb,c0c8a049,...) at db_trace_self_wrapper+0x26
kdb_backtrace(c08bedcb,c0c8a049,c592ee18,c592ed48,e80b1874,...) at kdb_backtrace+0x29
_witness_debugger(c0c8a049,c6046058,c0c790f8,c592ed48,c0c912d8,...) at _witness_debugger+0x25
witness_checkorder(c6046058,9,c0c912d8,823,0,...) at witness_checkorder+0x82b
__lockmgr_args(c6046058,80100,c6046074,0,0,...) at __lockmgr_args+0x7f7
vop_stdlock(e80b1978,c08ce1ab,c0c79329,80100,c6046000,...) at vop_stdlock+0x62
VOP_LOCK1_APV(c0d65680,e80b1978,c5eb7764,c0da2920,c6046000,...) at VOP_LOCK1_APV+0xb5
_vn_lock(c6046000,80100,c0c912d8,823,8,...) at _vn_lock+0x5e
vget(c6046000,80100,c5eb76c0,15e,c0c7924b,...) at vget+0xbb
devfs_allocv(c5dacb00,c5d90000,e80b1a10,9d,c0f43d58,...) at devfs_allocv+0x100
devfs_root(c5d90000,80000,e80b1c30,42c,0,...) at devfs_root+0x4a
vfs_donmount(c5eb76c0,0,c5dac500,c5dac500,bfbfde54,...) at vfs_donmount+0x14dc
nmount(c5eb76c0,e80b1cf8,c,c5eb76c0,c0d6b3d8,...) at nmount+0x84
syscall(e80b1d38) at syscall+0x2d3
Xint0x80_syscall() at Xint0x80_syscall+0x20
--- syscall (378, FreeBSD ELF32, nmount), eip = 0x280e8c07, esp = 0xbfbfde2c, ebp = 0xbfbfe388 ---
lock order reversal: (sleepable after non-sleepable)
 1st 0xc5f80238 udpinp (udpinp) @ /usr/src/sys/netinet6/udp6_usrreq.c:840
 2nd 0xc0dd5a6c allprison (allprison) @ /usr/src/sys/kern/kern_jail.c:2972
KDB: stack backtrace:
db_trace_self_wrapper(c0c871b4,e811fabc,c08ce405,c08bedcb,c0c8a049,...) at db_trace_self_wrapper+0x26
kdb_backtrace(c08bedcb,c0c8a049,c59287b8,c5928138,e811fb18,...) at kdb_backtrace+0x29
_witness_debugger(c0c8a049,c0dd5a6c,c0c806f6,c5928138,c0c7fa14,...) at _witness_debugger+0x25
witness_checkorder(c0dd5a6c,1,c0c7fa14,b9c,0,...) at witness_checkorder+0x82b
_sx_slock(c0dd5a6c,0,c0c7fa14,b9c,c5f80ab8,...) at _sx_slock+0x85
prison_equal_ip6(c5db3800,c0d6d340,10,28b,c087ea9c,...) at prison_equal_ip6+0x3f
in6_pcblookup_local(c0f46540,c5d2d8e8,202,0,c5d7b380,...) at in6_pcblookup_local+0xc3
in6_pcbbind(c5f80188,c5d2d8e0,c5d7b380,c5ffe000,c087829f,...) at in6_pcbbind+0x3f2
udp6_bind(c601c4d4,c5d2d8e0,c5ffe000,e811fc60,c08facb2,...) at udp6_bind+0x109
sobind(c601c4d4,c5d2d8e0,c5ffe000,c5d2d8e0,c5de5700,...) at sobind+0x23
kern_bind(c5ffe000,6,c5d2d8e0,c5d2d8e0,28223340,...) at kern_bind+0xc2
bind(c5ffe000,e811fcf8,c,c0c8aaf4,c0d695e0,...) at bind+0x46
syscall(e811fd38) at syscall+0x2d3
Xint0x80_syscall() at Xint0x80_syscall+0x20
--- syscall (104, FreeBSD ELF32, bind), eip = 0x2812c9a7, esp = 0xbfbfde4c, ebp = 0xbfbfdeb8 ---
lock order reversal:
 1st 0xc55e82d0 bufwait (bufwait) @ /usr/src/sys/kern/vfs_bio.c:2558
 2nd 0xc5dd9400 dirhash (dirhash) @ /usr/src/sys/ufs/ufs/ufs_dirhash.c:285
KDB: stack backtrace:
db_trace_self_wrapper(c0c871b4,e807886c,c08ce405,c08bedcb,c0c8a049,...) at db_trace_self_wrapper+0x26
kdb_backtrace(c08bedcb,c0c8a049,c592be90,c592ee80,e80788c8,...) at kdb_backtrace+0x29
_witness_debugger(c0c8a049,c5dd9400,c0caae27,c592ee80,c0caaac0,...) at _witness_debugger+0x25
witness_checkorder(c5dd9400,9,c0caaac0,11d,0,...) at witness_checkorder+0x82b
_sx_xlock(c5dd9400,0,c0caaac0,11d,c609b910,...) at _sx_xlock+0x85
ufsdirhash_acquire(c55e8270,e8078a1c,e8078c00,180,e8078998,...) at ufsdirhash_acquire+0x35
ufsdirhash_add(c609b910,e8078a1c,894,e8078984,e8078988,...) at ufsdirhash_add+0x13
ufs_direnter(c6095a78,c6094d9c,e8078a1c,e8078c00,c55e8510,...) at ufs_direnter+0x746
ufs_mkdir(e8078c28,ec2,0,0,e8078b6c,...) at ufs_mkdir+0x967
VOP_MKDIR_APV(c0d89ea0,e8078c28,e8078c00,e8078b6c,0,...) at VOP_MKDIR_APV+0xa5
kern_mkdirat(c5d8e900,ffffff9c,bfbfef5a,0,1ff,...) at kern_mkdirat+0x2a1
kern_mkdir(c5d8e900,bfbfef5a,0,1ff,e8078d2c,...) at kern_mkdir+0x2e
mkdir(c5d8e900,e8078cf8,8,c0c8a963,c0d69960,...) at mkdir+0x29
syscall(e8078d38) at syscall+0x2d3
Xint0x80_syscall() at Xint0x80_syscall+0x20
--- syscall (136, FreeBSD ELF32, mkdir), eip = 0x28162447, esp = 0xbfbfed8c, ebp = 0xbfbfee38 ---

>How-To-Repeat:

	on reboot start a jail by script in /usr/lcoal/etc/rc.d

>Fix:
	unknown

	http://sources.zabbadoz.net/freebsd/lor.html
	First LOR may be #280
	Second LOR is unknown/new
	Third LOR may be #261

>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->freebsd-jail 
Responsible-Changed-By: linimon 
Responsible-Changed-When: Sun Jul 19 20:40:50 UTC 2009 
Responsible-Changed-Why:  
Over to maintainer(s). 

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

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/136899: commit references a PR
Date: Thu, 30 Jul 2009 14:29:07 +0000 (UTC)

 Author: jamie
 Date: Thu Jul 30 14:28:56 2009
 New Revision: 195974
 URL: http://svn.freebsd.org/changeset/base/195974
 
 Log:
   Remove a LOR, where the the sleepable allprison_lock was being obtained
   in prison_equal_ip4/6 while an inp mutex was held.  Locking allprison_lock
   can be avoided by making a restriction on the IP addresses associated with
   jails:
   
   Don't allow the "ip4" and "ip6" parameters to be changed after a jail is
   created.  Setting the "ip4.addr" and "ip6.addr" parameters is allowed,
   but only if the jail was already created with either ip4/6=new or
   ip4/6=disable.  With this restriction, the prison flags in question
   (PR_IP4_USER and PR_IP6_USER) become read-only and can be checked
   without locking.
   
   This also allows the simplification of a messy code path that was needed
   to handle an existing prison gaining an IP address list.
   
   PR:		kern/136899
   Reported by:	Dirk Meyer
   Approved by:	re (kib), bz (mentor)
 
 Modified:
   head/sys/kern/kern_jail.c
 
 Modified: head/sys/kern/kern_jail.c
 ==============================================================================
 --- head/sys/kern/kern_jail.c	Thu Jul 30 13:19:12 2009	(r195973)
 +++ head/sys/kern/kern_jail.c	Thu Jul 30 14:28:56 2009	(r195974)
 @@ -484,10 +484,10 @@ kern_jail_set(struct thread *td, struct 
  	int ii, ij;
  #endif
  #ifdef INET
 -	int ip4s, ip4a, redo_ip4;
 +	int ip4s, redo_ip4;
  #endif
  #ifdef INET6
 -	int ip6s, ip6a, redo_ip6;
 +	int ip6s, redo_ip6;
  #endif
  	unsigned pr_flags, ch_flags;
  	unsigned pr_allow, ch_allow, tallow;
 @@ -518,17 +518,12 @@ kern_jail_set(struct thread *td, struct 
  	if (error)
  		return (error);
  #ifdef INET
 -	ip4a = 0;
  	ip4 = NULL;
  #endif
  #ifdef INET6
 -	ip6a = 0;
  	ip6 = NULL;
  #endif
  
 -#if defined(INET) || defined(INET6)
 - again:
 -#endif
  	error = vfs_copyopt(opts, "jid", &jid, sizeof(jid));
  	if (error == ENOENT)
  		jid = 0;
 @@ -610,6 +605,20 @@ kern_jail_set(struct thread *td, struct 
  		goto done_errmsg;
  	}
  #endif
 +#ifdef INET
 +	if ((flags & JAIL_UPDATE) && (ch_flags & PR_IP4_USER)) {
 +		error = EINVAL;
 +		vfs_opterror(opts, "ip4 cannot be changed after creation");
 +		goto done_errmsg;
 +	}
 +#endif
 +#ifdef INET6
 +	if ((flags & JAIL_UPDATE) && (ch_flags & PR_IP6_USER)) {
 +		error = EINVAL;
 +		vfs_opterror(opts, "ip6 cannot be changed after creation");
 +		goto done_errmsg;
 +	}
 +#endif
  
  	pr_allow = ch_allow = 0;
  	for (fi = 0; fi < sizeof(pr_allow_names) / sizeof(pr_allow_names[0]);
 @@ -708,7 +717,6 @@ kern_jail_set(struct thread *td, struct 
  		pr_flags |= PR_HOST;
  	}
  
 -	/* This might be the second time around for this option. */
  #ifdef INET
  	error = vfs_getopt(opts, "ip4.addr", &op, &ip4s);
  	if (error == ENOENT)
 @@ -730,14 +738,7 @@ kern_jail_set(struct thread *td, struct 
  				vfs_opterror(opts, "too many IPv4 addresses");
  				goto done_errmsg;
  			}
 -			if (ip4a < ip4s) {
 -				ip4a = ip4s;
 -				free(ip4, M_PRISON);
 -				ip4 = NULL;
 -			}
 -			if (ip4 == NULL)
 -				ip4 = malloc(ip4a * sizeof(*ip4), M_PRISON,
 -				    M_WAITOK);
 +			ip4 = malloc(ip4s * sizeof(*ip4), M_PRISON, M_WAITOK);
  			bcopy(op, ip4, ip4s * sizeof(*ip4));
  			/*
  			 * IP addresses are all sorted but ip[0] to preserve
 @@ -793,14 +794,7 @@ kern_jail_set(struct thread *td, struct 
  				vfs_opterror(opts, "too many IPv6 addresses");
  				goto done_errmsg;
  			}
 -			if (ip6a < ip6s) {
 -				ip6a = ip6s;
 -				free(ip6, M_PRISON);
 -				ip6 = NULL;
 -			}
 -			if (ip6 == NULL)
 -				ip6 = malloc(ip6a * sizeof(*ip6), M_PRISON,
 -				    M_WAITOK);
 +			ip6 = malloc(ip6s * sizeof(*ip6), M_PRISON, M_WAITOK);
  			bcopy(op, ip6, ip6s * sizeof(*ip6));
  			if (ip6s > 1)
  				qsort(ip6 + 1, ip6s - 1, sizeof(*ip6), qcmp_v6);
 @@ -1152,10 +1146,36 @@ kern_jail_set(struct thread *td, struct 
  #endif
  		{
  #ifdef INET
 -			pr->pr_flags |= PR_IP4 | PR_IP4_USER | PR_IP4_DISABLE;
 +			if (!(ch_flags & PR_IP4_USER))
 +				pr->pr_flags |=
 +				    PR_IP4 | PR_IP4_USER | PR_IP4_DISABLE;
 +			else if (!(pr_flags & PR_IP4_USER)) {
 +				pr->pr_flags |= ppr->pr_flags & PR_IP4;
 +				if (ppr->pr_ip4 != NULL) {
 +					pr->pr_ip4s = ppr->pr_ip4s;
 +					pr->pr_ip4 = malloc(pr->pr_ip4s *
 +					    sizeof(struct in_addr), M_PRISON,
 +					    M_WAITOK);
 +					bcopy(ppr->pr_ip4, pr->pr_ip4,
 +					    pr->pr_ip4s * sizeof(*pr->pr_ip4));
 +				}
 +			}
  #endif
  #ifdef INET6
 -			pr->pr_flags |= PR_IP6 | PR_IP6_USER | PR_IP6_DISABLE;
 +			if (!(ch_flags & PR_IP6_USER))
 +				pr->pr_flags |=
 +				    PR_IP6 | PR_IP6_USER | PR_IP6_DISABLE;
 +			else if (!(pr_flags & PR_IP6_USER)) {
 +				pr->pr_flags |= ppr->pr_flags & PR_IP6;
 +				if (ppr->pr_ip6 != NULL) {
 +					pr->pr_ip6s = ppr->pr_ip6s;
 +					pr->pr_ip6 = malloc(pr->pr_ip6s *
 +					    sizeof(struct in6_addr), M_PRISON,
 +					    M_WAITOK);
 +					bcopy(ppr->pr_ip6, pr->pr_ip6,
 +					    pr->pr_ip6s * sizeof(*pr->pr_ip6));
 +				}
 +			}
  #endif
  		}
  #endif
 @@ -1189,6 +1209,11 @@ kern_jail_set(struct thread *td, struct 
  		 */
  	} else {
  		created = 0;
 +		/*
 +		 * Grab a reference for existing prisons, to ensure they
 +		 * continue to exist for the duration of the call.
 +		 */
 +		pr->pr_ref++;
  #if defined(VIMAGE) && (defined(INET) || defined(INET6))
  		if ((pr->pr_flags & PR_VNET) &&
  		    (ch_flags & (PR_IP4_USER | PR_IP6_USER))) {
 @@ -1198,11 +1223,22 @@ kern_jail_set(struct thread *td, struct 
  			goto done_deref_locked;
  		}
  #endif
 -		/*
 -		 * Grab a reference for existing prisons, to ensure they
 -		 * continue to exist for the duration of the call.
 -		 */
 -		pr->pr_ref++;
 +#ifdef INET
 +		if (PR_IP4_USER & ch_flags & (pr_flags ^ pr->pr_flags)) {
 +			error = EINVAL;
 +			vfs_opterror(opts,
 +			    "ip4 cannot be changed after creation");
 +			goto done_deref_locked;
 +		}
 +#endif
 +#ifdef INET6
 +		if (PR_IP6_USER & ch_flags & (pr_flags ^ pr->pr_flags)) {
 +			error = EINVAL;
 +			vfs_opterror(opts,
 +			    "ip6 cannot be changed after creation");
 +			goto done_deref_locked;
 +		}
 +#endif
  	}
  
  	/* Do final error checking before setting anything. */
 @@ -1225,254 +1261,138 @@ kern_jail_set(struct thread *td, struct 
  		}
  	}
  #ifdef INET
 -	if (ch_flags & PR_IP4_USER) {
 +	if (ip4s > 0) {
  		if (ppr->pr_flags & PR_IP4) {
 -			if (!(pr_flags & PR_IP4_USER)) {
 -				/*
 -				 * Silently ignore attempts to make the IP
 -				 * addresses unrestricted when the parent is
 -				 * restricted; in other words, interpret
 -				 * "unrestricted" as "as unrestricted as
 -				 * possible".
 -				 */
 -				ip4s = ppr->pr_ip4s;
 -				if (ip4s == 0) {
 -					free(ip4, M_PRISON);
 -					ip4 = NULL;
 -				} else if (ip4s <= ip4a) {
 -					/* Inherit the parent's address(es). */
 -					bcopy(ppr->pr_ip4, ip4,
 -					    ip4s * sizeof(*ip4));
 -				} else {
 -					/*
 -					 * There's no room for the parent's
 -					 * address list.  Allocate some more.
 -					 */
 -					ip4a = ip4s;
 -					free(ip4, M_PRISON);
 -					ip4 = malloc(ip4a * sizeof(*ip4),
 -					    M_PRISON, M_NOWAIT);
 -					if (ip4 != NULL)
 -						bcopy(ppr->pr_ip4, ip4,
 -						    ip4s * sizeof(*ip4));
 -					else {
 -						/* Allocation failed without
 -						 * sleeping.  Unlocking the
 -						 * prison now will invalidate
 -						 * some checks and prematurely
 -						 * show an unfinished new jail.
 -						 * So let go of everything and
 -						 * start over.
 -						 */
 -						prison_deref(pr, created
 -						    ? PD_LOCKED |
 -						      PD_LIST_XLOCKED
 -						    : PD_DEREF | PD_LOCKED |
 -						      PD_LIST_XLOCKED);
 -						if (root != NULL) {
 -							vfslocked =
 -							    VFS_LOCK_GIANT(
 -							    root->v_mount);
 -							vrele(root);
 -							VFS_UNLOCK_GIANT(
 -							    vfslocked);
 -						}
 -						ip4 = malloc(ip4a *
 -						    sizeof(*ip4), M_PRISON,
 -						    M_WAITOK);
 -						goto again;
 -					}
 -				}
 -			} else if (ip4s > 0) {
 -				/*
 -				 * Make sure the new set of IP addresses is a
 -				 * subset of the parent's list.  Don't worry
 -				 * about the parent being unlocked, as any
 -				 * setting is done with allprison_lock held.
 -				 */
 -				for (ij = 0; ij < ppr->pr_ip4s; ij++)
 -					if (ip4[0].s_addr ==
 -					    ppr->pr_ip4[ij].s_addr)
 +			/*
 +			 * Make sure the new set of IP addresses is a
 +			 * subset of the parent's list.  Don't worry
 +			 * about the parent being unlocked, as any
 +			 * setting is done with allprison_lock held.
 +			 */
 +			for (ij = 0; ij < ppr->pr_ip4s; ij++)
 +				if (ip4[0].s_addr == ppr->pr_ip4[ij].s_addr)
 +					break;
 +			if (ij == ppr->pr_ip4s) {
 +				error = EPERM;
 +				goto done_deref_locked;
 +			}
 +			if (ip4s > 1) {
 +				for (ii = ij = 1; ii < ip4s; ii++) {
 +					if (ip4[ii].s_addr ==
 +					    ppr->pr_ip4[0].s_addr)
 +						continue;
 +					for (; ij < ppr->pr_ip4s; ij++)
 +						if (ip4[ii].s_addr ==
 +						    ppr->pr_ip4[ij].s_addr)
 +							break;
 +					if (ij == ppr->pr_ip4s)
  						break;
 +				}
  				if (ij == ppr->pr_ip4s) {
  					error = EPERM;
  					goto done_deref_locked;
  				}
 -				if (ip4s > 1) {
 -					for (ii = ij = 1; ii < ip4s; ii++) {
 -						if (ip4[ii].s_addr ==
 -						    ppr->pr_ip4[0].s_addr)
 -							continue;
 -						for (; ij < ppr->pr_ip4s; ij++)
 -						    if (ip4[ii].s_addr ==
 -							ppr->pr_ip4[ij].s_addr)
 -							    break;
 -						if (ij == ppr->pr_ip4s)
 -							break;
 -					}
 -					if (ij == ppr->pr_ip4s) {
 -						error = EPERM;
 -						goto done_deref_locked;
 -					}
 -				}
  			}
  		}
 -		if (ip4s > 0) {
 -			/*
 -			 * Check for conflicting IP addresses.  We permit them
 -			 * if there is no more than one IP on each jail.  If
 -			 * there is a duplicate on a jail with more than one
 -			 * IP stop checking and return error.
 -			 */
 -			tppr = ppr;
 +		/*
 +		 * Check for conflicting IP addresses.  We permit them
 +		 * if there is no more than one IP on each jail.  If
 +		 * there is a duplicate on a jail with more than one
 +		 * IP stop checking and return error.
 +		 */
 +		tppr = ppr;
  #ifdef VIMAGE
 -			for (; tppr != &prison0; tppr = tppr->pr_parent)
 -				if (tppr->pr_flags & PR_VNET)
 -					break;
 +		for (; tppr != &prison0; tppr = tppr->pr_parent)
 +			if (tppr->pr_flags & PR_VNET)
 +				break;
  #endif
 -			FOREACH_PRISON_DESCENDANT(tppr, tpr, descend) {
 -				if (tpr == pr ||
 +		FOREACH_PRISON_DESCENDANT(tppr, tpr, descend) {
 +			if (tpr == pr ||
  #ifdef VIMAGE
 -				    (tpr != tppr &&
 -				     (tpr->pr_flags & PR_VNET)) ||
 +			    (tpr != tppr && (tpr->pr_flags & PR_VNET)) ||
  #endif
 -				    tpr->pr_uref == 0) {
 -					descend = 0;
 -					continue;
 -				}
 -				if (!(tpr->pr_flags & PR_IP4_USER))
 -					continue;
 +			    tpr->pr_uref == 0) {
  				descend = 0;
 -				if (tpr->pr_ip4 == NULL ||
 -				    (ip4s == 1 && tpr->pr_ip4s == 1))
 -					continue;
 -				for (ii = 0; ii < ip4s; ii++) {
 -					if (_prison_check_ip4(tpr,
 -					    &ip4[ii]) == 0) {
 -						error = EADDRINUSE;
 -						vfs_opterror(opts,
 -						    "IPv4 addresses clash");
 -						goto done_deref_locked;
 -					}
 +				continue;
 +			}
 +			if (!(tpr->pr_flags & PR_IP4_USER))
 +				continue;
 +			descend = 0;
 +			if (tpr->pr_ip4 == NULL ||
 +			    (ip4s == 1 && tpr->pr_ip4s == 1))
 +				continue;
 +			for (ii = 0; ii < ip4s; ii++) {
 +				if (_prison_check_ip4(tpr, &ip4[ii]) == 0) {
 +					error = EADDRINUSE;
 +					vfs_opterror(opts,
 +					    "IPv4 addresses clash");
 +					goto done_deref_locked;
  				}
  			}
  		}
  	}
  #endif
  #ifdef INET6
 -	if (ch_flags & PR_IP6_USER) {
 +	if (ip6s > 0) {
  		if (ppr->pr_flags & PR_IP6) {
 -			if (!(pr_flags & PR_IP6_USER)) {
 -				/*
 -				 * Silently ignore attempts to make the IP
 -				 * addresses unrestricted when the parent is
 -				 * restricted.
 -				 */
 -				ip6s = ppr->pr_ip6s;
 -				if (ip6s == 0) {
 -					free(ip6, M_PRISON);
 -					ip6 = NULL;
 -				} else if (ip6s <= ip6a) {
 -					/* Inherit the parent's address(es). */
 -					bcopy(ppr->pr_ip6, ip6,
 -					    ip6s * sizeof(*ip6));
 -				} else {
 -					/*
 -					 * There's no room for the parent's
 -					 * address list.
 -					 */
 -					ip6a = ip6s;
 -					free(ip6, M_PRISON);
 -					ip6 = malloc(ip6a * sizeof(*ip6),
 -					    M_PRISON, M_NOWAIT);
 -					if (ip6 != NULL)
 -						bcopy(ppr->pr_ip6, ip6,
 -						    ip6s * sizeof(*ip6));
 -					else {
 -						prison_deref(pr, created
 -						    ? PD_LOCKED |
 -						      PD_LIST_XLOCKED
 -						    : PD_DEREF | PD_LOCKED |
 -						      PD_LIST_XLOCKED);
 -						if (root != NULL) {
 -							vfslocked =
 -							    VFS_LOCK_GIANT(
 -							    root->v_mount);
 -							vrele(root);
 -							VFS_UNLOCK_GIANT(
 -							    vfslocked);
 -						}
 -						ip6 = malloc(ip6a *
 -						    sizeof(*ip6), M_PRISON,
 -						    M_WAITOK);
 -						goto again;
 -					}
 -				}
 -			} else if (ip6s > 0) {
 -				/*
 -				 * Make sure the new set of IP addresses is a
 -				 * subset of the parent's list.
 -				 */
 -				for (ij = 0; ij < ppr->pr_ip6s; ij++)
 -					if (IN6_ARE_ADDR_EQUAL(&ip6[0],
 -					    &ppr->pr_ip6[ij]))
 +			/*
 +			 * Make sure the new set of IP addresses is a
 +			 * subset of the parent's list.
 +			 */
 +			for (ij = 0; ij < ppr->pr_ip6s; ij++)
 +				if (IN6_ARE_ADDR_EQUAL(&ip6[0],
 +				    &ppr->pr_ip6[ij]))
 +					break;
 +			if (ij == ppr->pr_ip6s) {
 +				error = EPERM;
 +				goto done_deref_locked;
 +			}
 +			if (ip6s > 1) {
 +				for (ii = ij = 1; ii < ip6s; ii++) {
 +					if (IN6_ARE_ADDR_EQUAL(&ip6[ii],
 +					     &ppr->pr_ip6[0]))
 +						continue;
 +					for (; ij < ppr->pr_ip6s; ij++)
 +						if (IN6_ARE_ADDR_EQUAL(
 +						    &ip6[ii], &ppr->pr_ip6[ij]))
 +							break;
 +					if (ij == ppr->pr_ip6s)
  						break;
 +				}
  				if (ij == ppr->pr_ip6s) {
  					error = EPERM;
  					goto done_deref_locked;
  				}
 -				if (ip6s > 1) {
 -					for (ii = ij = 1; ii < ip6s; ii++) {
 -						if (IN6_ARE_ADDR_EQUAL(&ip6[ii],
 -						    &ppr->pr_ip6[0]))
 -							continue;
 -						for (; ij < ppr->pr_ip6s; ij++)
 -							if (IN6_ARE_ADDR_EQUAL(
 -							    &ip6[ii],
 -							    &ppr->pr_ip6[ij]))
 -								break;
 -						if (ij == ppr->pr_ip6s)
 -							break;
 -					}
 -					if (ij == ppr->pr_ip6s) {
 -						error = EPERM;
 -						goto done_deref_locked;
 -					}
 -				}
  			}
  		}
 -		if (ip6s > 0) {
 -			/* Check for conflicting IP addresses. */
 -			tppr = ppr;
 +		/* Check for conflicting IP addresses. */
 +		tppr = ppr;
  #ifdef VIMAGE
 -			for (; tppr != &prison0; tppr = tppr->pr_parent)
 -				if (tppr->pr_flags & PR_VNET)
 -					break;
 +		for (; tppr != &prison0; tppr = tppr->pr_parent)
 +			if (tppr->pr_flags & PR_VNET)
 +				break;
  #endif
 -			FOREACH_PRISON_DESCENDANT(tppr, tpr, descend) {
 -				if (tpr == pr ||
 +		FOREACH_PRISON_DESCENDANT(tppr, tpr, descend) {
 +			if (tpr == pr ||
  #ifdef VIMAGE
 -				    (tpr != tppr &&
 -				     (tpr->pr_flags & PR_VNET)) ||
 +			    (tpr != tppr && (tpr->pr_flags & PR_VNET)) ||
  #endif
 -				    tpr->pr_uref == 0) {
 -					descend = 0;
 -					continue;
 -				}
 -				if (!(tpr->pr_flags & PR_IP6_USER))
 -					continue;
 +			    tpr->pr_uref == 0) {
  				descend = 0;
 -				if (tpr->pr_ip6 == NULL ||
 -				    (ip6s == 1 && tpr->pr_ip6s == 1))
 -					continue;
 -				for (ii = 0; ii < ip6s; ii++) {
 -					if (_prison_check_ip6(tpr,
 -					    &ip6[ii]) == 0) {
 -						error = EADDRINUSE;
 -						vfs_opterror(opts,
 -						    "IPv6 addresses clash");
 -						goto done_deref_locked;
 -					}
 +				continue;
 +			}
 +			if (!(tpr->pr_flags & PR_IP6_USER))
 +				continue;
 +			descend = 0;
 +			if (tpr->pr_ip6 == NULL ||
 +			    (ip6s == 1 && tpr->pr_ip6s == 1))
 +				continue;
 +			for (ii = 0; ii < ip6s; ii++) {
 +				if (_prison_check_ip6(tpr, &ip6[ii]) == 0) {
 +					error = EADDRINUSE;
 +					vfs_opterror(opts,
 +					    "IPv6 addresses clash");
 +					goto done_deref_locked;
  				}
  			}
  		}
 @@ -1514,28 +1434,12 @@ kern_jail_set(struct thread *td, struct 
  	/* Set the parameters of the prison. */
  #ifdef INET
  	redo_ip4 = 0;
 -	if (ch_flags & PR_IP4_USER) {
 -		if (pr_flags & PR_IP4_USER) {
 -			/* Some restriction set. */
 -			pr->pr_flags |= PR_IP4;
 -			if (ip4s >= 0) {
 -				free(pr->pr_ip4, M_PRISON);
 -				pr->pr_ip4s = ip4s;
 -				pr->pr_ip4 = ip4;
 -				ip4 = NULL;
 -			}
 -		} else if (ppr->pr_flags & PR_IP4) {
 -			/* This restriction cleared, but keep inherited. */
 -			free(pr->pr_ip4, M_PRISON);
 -			pr->pr_ip4s = ip4s;
 -			pr->pr_ip4 = ip4;
 -			ip4 = NULL;
 -		} else {
 -			/* Restriction cleared, now unrestricted. */
 -			pr->pr_flags &= ~PR_IP4;
 -			free(pr->pr_ip4, M_PRISON);
 -			pr->pr_ip4s = 0;
 -		}
 +	if (pr_flags & PR_IP4_USER) {
 +		pr->pr_flags |= PR_IP4;
 +		free(pr->pr_ip4, M_PRISON);
 +		pr->pr_ip4s = ip4s;
 +		pr->pr_ip4 = ip4;
 +		ip4 = NULL;
  		FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) {
  #ifdef VIMAGE
  			if (tpr->pr_flags & PR_VNET) {
 @@ -1552,28 +1456,12 @@ kern_jail_set(struct thread *td, struct 
  #endif
  #ifdef INET6
  	redo_ip6 = 0;
 -	if (ch_flags & PR_IP6_USER) {
 -		if (pr_flags & PR_IP6_USER) {
 -			/* Some restriction set. */
 -			pr->pr_flags |= PR_IP6;
 -			if (ip6s >= 0) {
 -				free(pr->pr_ip6, M_PRISON);
 -				pr->pr_ip6s = ip6s;
 -				pr->pr_ip6 = ip6;
 -				ip6 = NULL;
 -			}
 -		} else if (ppr->pr_flags & PR_IP6) {
 -			/* This restriction cleared, but keep inherited. */
 -			free(pr->pr_ip6, M_PRISON);
 -			pr->pr_ip6s = ip6s;
 -			pr->pr_ip6 = ip6;
 -			ip6 = NULL;
 -		} else {
 -			/* Restriction cleared, now unrestricted. */
 -			pr->pr_flags &= ~PR_IP6;
 -			free(pr->pr_ip6, M_PRISON);
 -			pr->pr_ip6s = 0;
 -		}
 +	if (pr_flags & PR_IP6_USER) {
 +		pr->pr_flags |= PR_IP6;
 +		free(pr->pr_ip6, M_PRISON);
 +		pr->pr_ip6s = ip6s;
 +		pr->pr_ip6 = ip6;
 +		ip6 = NULL;
  		FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) {
  #ifdef VIMAGE
  			if (tpr->pr_flags & PR_VNET) {
 @@ -2661,7 +2549,6 @@ prison_restrict_ip4(struct prison *pr, s
  				free(pr->pr_ip4, M_PRISON);
  				pr->pr_ip4 = newip4;
  				pr->pr_ip4s = ppr->pr_ip4s;
 -				pr->pr_flags |= PR_IP4;
  			}
  			return (used);
  		}
 @@ -2673,9 +2560,7 @@ prison_restrict_ip4(struct prison *pr, s
  			free(pr->pr_ip4, M_PRISON);
  			pr->pr_ip4 = NULL;
  		}
 -		pr->pr_flags =
 -			(pr->pr_flags & ~PR_IP4) | (ppr->pr_flags & PR_IP4);
 -	} else if (pr->pr_ip4s > 0 && (ppr->pr_flags & PR_IP4)) {
 +	} else if (pr->pr_ip4s > 0) {
  		/* Remove addresses that aren't in the parent. */
  		for (ij = 0; ij < ppr->pr_ip4s; ij++)
  			if (pr->pr_ip4[0].s_addr == ppr->pr_ip4[ij].s_addr)
 @@ -2762,12 +2647,9 @@ prison_equal_ip4(struct prison *pr1, str
  		return (1);
  
  	/*
 -	 * jail_set maintains an exclusive hold on allprison_lock while it
 -	 * changes the IP addresses, so only a shared hold is needed.  This is
 -	 * easier than locking the two prisons which would require finding the
 -	 * proper locking order and end up needing allprison_lock anyway.
 +	 * No need to lock since the PR_IP4_USER flag can't be altered for
 +	 * existing prisons.
  	 */
 -	sx_slock(&allprison_lock);
  	while (pr1 != &prison0 &&
  #ifdef VIMAGE
  	       !(pr1->pr_flags & PR_VNET) &&
 @@ -2780,7 +2662,6 @@ prison_equal_ip4(struct prison *pr1, str
  #endif
  	       !(pr2->pr_flags & PR_IP4_USER))
  		pr2 = pr2->pr_parent;
 -	sx_sunlock(&allprison_lock);
  	return (pr1 == pr2);
  }
  
 @@ -2972,7 +2853,6 @@ prison_restrict_ip6(struct prison *pr, s
  				free(pr->pr_ip6, M_PRISON);
  				pr->pr_ip6 = newip6;
  				pr->pr_ip6s = ppr->pr_ip6s;
 -				pr->pr_flags |= PR_IP6;
  			}
  			return (used);
  		}
 @@ -2984,9 +2864,7 @@ prison_restrict_ip6(struct prison *pr, s
  			free(pr->pr_ip6, M_PRISON);
  			pr->pr_ip6 = NULL;
  		}
 -		pr->pr_flags =
 -			(pr->pr_flags & ~PR_IP6) | (ppr->pr_flags & PR_IP6);
 -	} else if (pr->pr_ip6s > 0 && (ppr->pr_flags & PR_IP6)) {
 +	} else if (pr->pr_ip6s > 0) {
  		/* Remove addresses that aren't in the parent. */
  		for (ij = 0; ij < ppr->pr_ip6s; ij++)
  			if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0],
 @@ -3073,7 +2951,6 @@ prison_equal_ip6(struct prison *pr1, str
  	if (pr1 == pr2)
  		return (1);
  
 -	sx_slock(&allprison_lock);
  	while (pr1 != &prison0 &&
  #ifdef VIMAGE
  	       !(pr1->pr_flags & PR_VNET) &&
 @@ -3086,7 +2963,6 @@ prison_equal_ip6(struct prison *pr1, str
  #endif
  	       !(pr2->pr_flags & PR_IP6_USER))
  		pr2 = pr2->pr_parent;
 -	sx_sunlock(&allprison_lock);
  	return (pr1 == pr2);
  }
  
 @@ -4172,12 +4048,14 @@ SYSCTL_JAIL_PARAM_NODE(cpuset, "Jail cpu
  SYSCTL_JAIL_PARAM(_cpuset, id, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail cpuset ID");
  
  #ifdef INET
 -SYSCTL_JAIL_PARAM_SYS_NODE(ip4, CTLFLAG_RW, "Jail IPv4 address virtualization");
 +SYSCTL_JAIL_PARAM_SYS_NODE(ip4, CTLFLAG_RDTUN,
 +    "Jail IPv4 address virtualization");
  SYSCTL_JAIL_PARAM_STRUCT(_ip4, addr, CTLFLAG_RW, sizeof(struct in_addr),
      "S,in_addr,a", "Jail IPv4 addresses");
  #endif
  #ifdef INET6
 -SYSCTL_JAIL_PARAM_SYS_NODE(ip6, CTLFLAG_RW, "Jail IPv6 address virtualization");
 +SYSCTL_JAIL_PARAM_SYS_NODE(ip6, CTLFLAG_RDTUN,
 +    "Jail IPv6 address virtualization");
  SYSCTL_JAIL_PARAM_STRUCT(_ip6, addr, CTLFLAG_RW, sizeof(struct in6_addr),
      "S,in6_addr,a", "Jail IPv6 addresses");
  #endif
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: open->closed 
State-Changed-By: jamie 
State-Changed-When: Thu Jul 30 15:42:26 UTC 2009 
State-Changed-Why:  
Fixed by r195974, which restricts the prison "ip4" and "ip6" parameters 
in order to avoid locking allprison_lock in prison_equal_ip4/6. 

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