[Bug 214300] Integer truncation issues lead to out-of-bounds kernel reads and panics in clock_settime().

bugzilla-noreply at freebsd.org bugzilla-noreply at freebsd.org
Mon Nov 7 21:50:25 UTC 2016


https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=214300

            Bug ID: 214300
           Summary: Integer truncation issues lead to out-of-bounds kernel
                    reads and panics in clock_settime().
           Product: Base System
           Version: 10.3-RELEASE
          Hardware: amd64
                OS: Any
            Status: New
          Severity: Affects Some People
          Priority: ---
         Component: kern
          Assignee: freebsd-bugs at FreeBSD.org
          Reporter: tim.newsham at nccgroup.trust
                CC: freebsd-amd64 at FreeBSD.org
                CC: freebsd-amd64 at FreeBSD.org

Created attachment 176751
  --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=176751&action=edit
reproduction program

Integer truncation issues in clock_ts_to_ct() result in out-of-bounds
results.  These results are trusted by atrtc_settime() which calls
bin2bcd(ct.day).  bin2bcd is implemented with a table lookup, and
when ct.day is out-of-bounds, it results in an out-of-bounds read
to the bin2bcd_data[] table.  This can lead to a page fault in the
kernel and a panic. To trigger this issue you must have the
PRIV_CLOCK_SETTIME privilege.

Specifically when ts->tv_sec is large or negative on 64-bit platforms,
the clock_ts_to_ct function calculations:
    days = secs / SECDAY;
can result in an incorrect value that is negative.  This can later result
in several incorrect calculations in the result including
    ct->dow = day_of_week(days);
which performs a modulus operation on a negative value, an integer
overflow in ct->year, and an out-of-range value in ct->day,
    ct->hour = rsec / 3600;
    rsec = rsec % 3600;
    ct->min  = rsec / 60;
    rsec = rsec % 60;
    ct->sec  = rsec;
and out-of-range values for ct->min and ct->sec (due to modulus
operations on negative values).

Verified on FreeBSD 10.3-RELEASE kernel on amd64 platform with
QEMU "hardware".

Recommendation:
The "years" and "days" variables in clock_ts_to_ct() should be
"long" and not "int".  This function should not be called when
the input "ts.tv_sec" field is negative, or it should return an
error, or the function should be updated to properly handle negative
second values.  It should be carefully written to avoid signed-overflows 
and signed-modulus operations in this case.

Reproduction:
# cc -Wall crash_clock_settime.c -o crash_clock_settime
# ./crash_clock_settime
Fatal trap 12: page fault while in kernel mode
cpuid = 0; apic id = 00
fault virtual address   = 0xffffffff7eab4242
fault code      = supervisor read data, page not present
instruction pointer = 0x20:0xffffffff80e6e6c8
stack pointer           = 0x28:0xfffffe00002169d0
frame pointer           = 0x28:0xfffffe0000216a10
code segment        = base 0x0, limit 0xfffff, type 0x1b
            = DPL 0, pres 1, long 1, def32 0, gran 1
processor eflags    = interrupt enabled, IOPL = 0
current process     = 22 (a.out)
trap number     = 12
panic: page fault
cpuid = 0
KDB: stack backtrace:
#0 0xffffffff8098e390 at kdb_backtrace+0x60
#1 0xffffffff80951066 at vpanic+0x126
#2 0xffffffff80950f33 at panic+0x43
#3 0xffffffff80d55f7b at trap_fatal+0x36b
#4 0xffffffff80d5627d at trap_pfault+0x2ed
#5 0xffffffff80d558fa at trap+0x47a
#6 0xffffffff80d3b8d2 at calltrap+0x8
#7 0xffffffff809993f1 at resettodr+0xc1
#8 0xffffffff80963ea0 at settime+0x180
#9 0xffffffff80963c96 at sys_clock_settime+0x86
#10 0xffffffff80d5694f at amd64_syscall+0x40f
#11 0xffffffff80d3bbbb at Xfast_syscall+0xfb

-- 
You are receiving this mail because:
You are on the CC list for the bug.


More information about the freebsd-amd64 mailing list