Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 30 Jul 2016 10:38:34 +1000 (EST)
From:      Bruce Evans <brde@optusnet.com.au>
To:        John Baldwin <jhb@freebsd.org>
Cc:        src-committers@freebsd.org, svn-src-all@freebsd.org,  svn-src-head@freebsd.org
Subject:   Re: svn commit: r303503 - head/sys/kern
Message-ID:  <20160730101227.J1336@besplex.bde.org>
In-Reply-To: <201607292019.u6TKJE98050271@repo.freebsd.org>
References:  <201607292019.u6TKJE98050271@repo.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Fri, 29 Jul 2016, John Baldwin wrote:

> Log:
>  Don't treat NOCPU as a valid CPU to CPU_ISSET.
>
>  If a thread is created bound to a cpuset it might already be bound before
>  it's very first timeslice, and td_lastcpu will be NOCPU in that case.
>
>  MFC after:	1 week

Thanks.  Did you get this from your mail queue on 2016/05/08?
>
> Modified: head/sys/kern/sched_4bsd.c
> ==============================================================================
> --- head/sys/kern/sched_4bsd.c	Fri Jul 29 19:36:10 2016	(r303502)
> +++ head/sys/kern/sched_4bsd.c	Fri Jul 29 20:19:14 2016	(r303503)
> @@ -1241,7 +1241,7 @@ sched_pickcpu(struct thread *td)
>
> 	mtx_assert(&sched_lock, MA_OWNED);
>
> -	if (THREAD_CAN_SCHED(td, td->td_lastcpu))
> +	if (td->td_lastcpu != NOCPU && THREAD_CAN_SCHED(td, td->td_lastcpu))
> 		best = td->td_lastcpu;
> 	else
> 		best = NOCPU;

This bug was more fatal on amd64 than on i386.  td_last_cpu has a correct
(signed) type int and NOCPU is -1.  THREAD_CAN_SCHED uses unsigned type.
-1 becomes 0xFFFFFFFFFFFFFFFF in it on amd64 and 0xFFFFFFFF on i386.
The old mail says that these get shifted to 1/4 as big, but I think
the relevant value is more like 8 -- 8 bits per byte requires a byte
at offset 1/8 of of these values in a byte array for a bitmap, but the
array is of u_int or u_long so the array index is 1/32nd or 1/64 of
these values and the memory offset is 1/8.  Anyway, the final offset
is small enough to not always trap on i386 only.

When NOCPU was 255, t_lastcpu was u_char and the memory offset was 31
bytes.  This didn't even give a buffer overrun with MAXCPU = 254.

When td_lastcpu is NOCPU and the check doesn't trap, 'best' is set to
NOCPU in both cases and the code works.

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20160730101227.J1336>