Page MenuHomeFreeBSD

Compute priority with an intermediate widening to prevent overflow
AbandonedPublic

Authored by jhibbits on Nov 7 2017, 10:34 PM.
Tags
None
Referenced Files
Unknown Object (File)
Jan 22 2024, 6:27 AM
Unknown Object (File)
Jan 18 2024, 8:43 PM
Unknown Object (File)
Dec 28 2023, 1:24 AM
Unknown Object (File)
Dec 23 2023, 2:42 AM
Unknown Object (File)
Dec 7 2023, 3:41 AM
Unknown Object (File)
Nov 4 2023, 7:39 PM
Unknown Object (File)
Oct 28 2023, 9:27 AM
Unknown Object (File)
Oct 12 2023, 12:45 AM
Subscribers

Details

Reviewers
markj
jeff
kib
jhb
Summary

It's possible to overflow an integer when rounding up a near-UINT_MAX value. To
prevent overflow in this intermediary rounded value, widen the type to hold 33
bits.

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 12748
Build 13016: arc lint + arc unit

Event Timeline

sys/kern/sched_ule.c
169

Sorry if I'm misunderstanding, but I don't see what this fixes. The cast back to int might truncate the value of roundup(SCHED_TICK_TOTAL(ts), SCHED_PRI_RANGE). If the truncated value is smaller than SCHED_PRI_RANGE, we'll get a divide-by-zero.

The cast to int should be of the full result, not just the roundup().

jhibbits added inline comments.
sys/kern/sched_ule.c
169

D'oh, this was a manual copy from my internal repo, so missed the parentheses to cast the full result, instead of just the roundup().

Perhaps s/33/32/ in the message ? Or am I missing something ?

That said, SCHED_TICK_TOTAL() is already defined as max(ts_ltick-ts_ftick, hz), and max() casts its arguments to u_int. Isn't it too late to cast SCHED_TICK_TOTAL() to uintmax_t ?

In D12984#270029, @kib wrote:

Perhaps s/33/32/ in the message ? Or am I missing something ?

Nope, the intermediate type has to hold 33 bits, for the rounding (round up to 2**32), but it gets dropped back down to 32 bits after the divide.

That said, SCHED_TICK_TOTAL() is already defined as max(ts_ltick-ts_ftick, hz), and max() casts its arguments to u_int. Isn't it too late to cast SCHED_TICK_TOTAL() to uintmax_t ?

I debated which would be best, and figured if it overflows as the max() arguments (which would need additional casting), it would return hz, which though possibly not desirable won't panic with a divide by zero.

This looks ok to me. I'm not really sure that it's the best way to address the overflow - I think this solution is making assumptions about how roundup() is implemented. I don't have a better suggestion though.

This revision is now accepted and ready to land.Nov 13 2017, 11:47 PM

Cast the tick difference to uintmax_t earlier on, instead of in the roundup() argument list.

This revision now requires review to proceed.Nov 14 2017, 7:16 PM

Cast the tick difference to uintmax_t earlier on, instead of in the roundup() argument list.

Taking a step back, the problem occurs when roundup(SCHED_TICK_TOTAL(ts), SCHED_PRI_RANGE) ends up in the interval (-SCHED_PRI_RANGE, SCHED_PRI_RANGE), right? SCHED_TICK_TOTAL(ts) is max(ts->ts_ltick - ts->ts_ftick, hz); note that max()'s return value is an unsigned int. So, to hit the bug, that difference needs to be quite large, i.e., close to INT_MAX.

ftick and ltick are the boundaries of the %CPU sliding window for the thread, and are updated in sched_pctcpu_update(). In particular, that difference ltick - ftick is supposed to be no larger than SCHED_TICK_MAX = 11 * hz. In r314625 I fixed a bug which caused us to stop updating ts_ftick for a thread if it had not run in a long time. So how else are we getting that large difference? Is it possible that your bug is already fixed by the above-mentioned revision?

Cast the tick difference to uintmax_t earlier on, instead of in the roundup() argument list.

Taking a step back, the problem occurs when roundup(SCHED_TICK_TOTAL(ts), SCHED_PRI_RANGE) ends up in the interval (-SCHED_PRI_RANGE, SCHED_PRI_RANGE), right? SCHED_TICK_TOTAL(ts) is max(ts->ts_ltick - ts->ts_ftick, hz); note that max()'s return value is an unsigned int. So, to hit the bug, that difference needs to be quite large, i.e., close to INT_MAX.

ftick and ltick are the boundaries of the %CPU sliding window for the thread, and are updated in sched_pctcpu_update(). In particular, that difference ltick - ftick is supposed to be no larger than SCHED_TICK_MAX = 11 * hz. In r314625 I fixed a bug which caused us to stop updating ts_ftick for a thread if it had not run in a long time. So how else are we getting that large difference? Is it possible that your bug is already fixed by the above-mentioned revision?

Reviewing the change in r314625, and the code surrounding it, I think r314625 fixes the bug completely, by keeping the ticks within the window. Dropping this as unnecessary now.