Skip to content

mktime() may panic on large tm_year because of overflow #357

@nuczyc

Description

@nuczyc

Describe the bug

Calling mktime() with an excessively large tm_year can trigger a kernel panic caused by integer overflow in axlibc's mktime implementation. The overflow occurs at ulib/axlibc/src/mktime.rs:20 in the expression (*t).tm_year + 1900. When tm_year is set close to INT_MAX, adding 1900 overflows and causes a panic in debug mode. This makes mktime() unsafe against malformed or adversarial input and allows a user program to crash the system through a libc API call. The provided PoC reproduces the issue by setting tm_year to a very large value before invoking mktime().

let mut year = (*t).tm_year + 1900;

To Reproduce

  1. Compile the program and run.
#define _GNU_SOURCE
#include <time.h>
#include <stdio.h>
#include <limits.h>
#include <string.h>

/*
 * PoC for ex58: Potential arithmetic overflow in mktime()
 * Location: /home/yuchen/ArceOS/arceos/ulib/axlibc/src/mktime.rs:20:20
 * Panic type: potential_arithmetic_overflow
 *
 * The vulnerable code: `let mut year = (*t).tm_year + 1900;`
 *
 * This can overflow when tm_year is set to a very large value such that
 * tm_year + 1900 overflows the integer type.
 *
 * Trigger strategy: Use mktime() with tm_year set near INT_MAX to cause
 * overflow when adding 1900.
 */

int main() {
    struct tm tm;

    memset(&tm, 0, sizeof(tm));

    /* Set tm_year to a value that will overflow when 1900 is added
     * INT_MAX - 1900 is close to INT_MAX, so adding 1900 will overflow
     */
    tm.tm_year = INT_MAX - 1000;  /* Close to INT_MAX */
    tm.tm_mon = 0;   /* January */
    tm.tm_mday = 1;  /* 1st day */
    tm.tm_hour = 0;
    tm.tm_min = 0;
    tm.tm_sec = 0;
    tm.tm_isdst = -1;

    printf("Calling mktime with tm_year = %d\n", tm.tm_year);

    /* This will trigger the overflow: tm_year + 1900 */
    time_t result = mktime(&tm);

    printf("mktime result: %ld\n", (long)result);

    /* The overflow happens at: let mut year = (*t).tm_year + 1900; */

    return 0;
}

Environment

Logs

SeaBIOS (version 1.16.3-debian-1.16.3-2)


iPXE (https://ipxe.org) 00:03.0 CA00 PCI2.10 PnP PMM+06FCAA40+06F0AA40 CA00
                                                                               


Booting from ROM..TSC frequency: 4000 MHz

       d8888                            .d88888b.   .d8888b.
      d88888                           d88P" "Y88b d88P  Y88b
     d88P888                           888     888 Y88b.
    d88P 888 888d888  .d8888b  .d88b.  888     888  "Y888b.
   d88P  888 888P"   d88P"    d8P  Y8b 888     888     "Y88b.
  d88P   888 888     888      88888888 888     888       "888
 d8888888888 888     Y88b.    Y8b.     Y88b. .d88P Y88b  d88P
d88P     888 888      "Y8888P  "Y8888   "Y88888P"   "Y8888P"

arch = x86_64
platform = x86-pc
target = x86_64-unknown-none
build_mode = debug
log_level = warn

smp = 1
[  0.201092 0 fatfs::dir:145] Is a directory
[  0.204007 0 fatfs::dir:145] Is a directory
[  0.208302 0 fatfs::dir:145] Is a directory
[  0.213843 0 fatfs::dir:145] Is a directory
[  0.256037 0 axcpu::x86_64::trap:46] No registered handler for trap IRQ
Calling mktime with tm_year = 2147482647
[  0.256794 0:2 axruntime::lang_items:5] panicked at ulib/axlibc/src/mktime.rs:20:20:
attempt to add with overflow

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions