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
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to