Skip to content

Arithmetic overflow panic in pread with invalid offset (off_t)-1 #227

@nuczyc

Description

@nuczyc

Describe the bug

The kernel panics with an attempt to add with overflow error when the pread system call is invoked with a negative offset (specifically (off_t)-1). This occurs in the axfs_ramfs module.

let end = content.len().min(offset as usize + buf.len());

To Reproduce

  1. Compile the program and run.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <stdint.h>

/*
 * PoC for potential remainder by zero in RuxOS ext4 filesystem
 * 
 * The crash occurs in ruxfs/src/fs/ext4_rs.rs:43 in the read_offset function:
 *   let mut offset_in_block = offset % DISK_BLOCK_SIZE;
 * 
 * While DISK_BLOCK_SIZE is a constant (512), the static analyzer flags this as 
 * a potential division by zero. This PoC attempts to trigger the condition
 * by performing file operations with various offsets.
 * 
 * Reachability analysis:
 * - The read_offset function is part of BlockDevice trait implementation
 * - It's called during file read operations through the filesystem layer
 * - User applications can trigger this via open(), read(), lseek() syscalls
 * - The offset parameter is controllable from user space
 * 
 * Note: In practice, DISK_BLOCK_SIZE is a constant (512), so actual division 
 * by zero shouldn't occur. This is likely a false positive from static analysis.
 */

int main() {
    const char* filename = "/tmp/test_file";
    int fd;
    char buffer[4096];
    ssize_t bytes_read;
    
    // Create a test file
    fd = open(filename, O_CREAT | O_RDWR | O_TRUNC, 0644);
    if (fd < 0) {
        perror("open");
        return 1;
    }
    
    // Write some data to the file
    const char* data = "This is test data for triggering the potential remainder by zero issue";
    write(fd, data, strlen(data));
    
    // Attempt to read at various offsets to trigger the condition
    // The offset parameter in read_offset comes from file position
    off_t test_offsets[] = {
        0,      // Normal case
        511,    // Just before block boundary
        512,    // Exactly at block boundary
        1023,   // Near next block boundary
        1024,   // At next block boundary
        4095,   // Large offset
        4096,   // Block size boundary
        8192,   // Multiple blocks
        (off_t)-1, // Negative offset (should fail but worth trying)
        SIZE_MAX - 511 // Very large offset
    };
    
    int num_tests = sizeof(test_offsets) / sizeof(test_offsets[0]);
    
    for (int i = 0; i < num_tests; i++) {
        printf("Testing offset: %ld\n", test_offsets[i]);
        
        // Seek to the test offset
        if (lseek(fd, test_offsets[i], SEEK_SET) == (off_t)-1) {
            printf("  lseek failed for offset %ld\n", test_offsets[i]);
            continue;
        }
        
        // Attempt to read - this should trigger read_offset in the kernel
        bytes_read = read(fd, buffer, sizeof(buffer));
        if (bytes_read < 0) {
            printf("  read failed for offset %ld\n", test_offsets[i]);
        } else {
            printf("  Successfully read %zd bytes at offset %ld\n", bytes_read, test_offsets[i]);
        }
    }
    
    // Additional test: Use pread to read at specific offsets without changing file position
    printf("\nTesting with pread:\n");
    for (int i = 0; i < num_tests; i++) {
        printf("Testing pread at offset: %ld\n", test_offsets[i]);
        bytes_read = pread(fd, buffer, sizeof(buffer), test_offsets[i]);
        if (bytes_read < 0) {
            printf("  pread failed for offset %ld\n", test_offsets[i]);
        } else {
            printf("  Successfully pread %zd bytes at offset %ld\n", bytes_read, test_offsets[i]);
        }
    }
    
    close(fd);
    unlink(filename);
    
    printf("\nPoC completed. If the kernel has the remainder by zero vulnerability, "
           "it should have panicked during one of the read operations.\n");
    
    return 0;
}

2.features.txt

alloc
paging
net
multitask
irq
fs

Environment

Logs

SeaBIOS (version 1.16.3-debian-1.16.3-2)


iPXE (https://ipxe.org) 00:03.0 CA00 PCI2.10 PnP PMM+7EFCAA40+7EF0AA40 CA00
                                                                               


Booting from ROM..
Initialize IDT & GDT...

8888888b.                     .d88888b.   .d8888b.
888   Y88b                   d88P" "Y88b d88P  Y88b
888    888                   888     888 Y88b.
888   d88P 888  888 888  888 888     888  "Y888b.
8888888P"  888  888 `Y8bd8P' 888     888     "Y88b.
888 T88b   888  888   X88K   888     888       "888
888  T88b  Y88b 888 .d8""8b. Y88b. .d88P Y88b  d88P
888   T88b  "Y88888 888  888  "Y88888P"   "Y8888P"

arch = x86_64
platform = x86_64-qemu-q35
target = x86_64-unknown-none
smp = 1
build_mode = debug
log_level = warn

[  0.191208 0 axfs_ramfs::dir:68] AlreadyExists sys
Testing offset: 0
  Successfully read 70 bytes at offset 0
Testing offset: 511
  Successfully read 0 bytes at offset 511
Testing offset: 512
  Successfully read 0 bytes at offset 512
Testing offset: 1023
  Successfully read 0 bytes at offset 1023
Testing offset: 1024
  Successfully read 0 bytes at offset 1024
Testing offset: 4095
  Successfully read 0 bytes at offset 4095
Testing offset: 4096
  Successfully read 0 bytes at offset 4096
Testing offset: 8192
  Successfully read 0 bytes at offset 8192
Testing offset: -1
  lseek failed for offset -1
Testing offset: -512
  lseek failed for offset -512

Testing with pread:
Testing pread at offset: 0
  Successfully pread 70 bytes at offset 0
Testing pread at offset: 511
  Successfully pread 0 bytes at offset 511
Testing pread at offset: 512
  Successfully pread 0 bytes at offset 512
Testing pread at offset: 1023
  Successfully pread 0 bytes at offset 1023
Testing pread at offset: 1024
  Successfully pread 0 bytes at offset 1024
Testing pread at offset: 4095
  Successfully pread 0 bytes at offset 4095
Testing pread at offset: 4096
  Successfully pread 0 bytes at offset 4096
Testing pread at offset: 8192
  Successfully pread 0 bytes at offset 8192
Testing pread at offset: -1
[  0.198242 0:1 ruxruntime::lang_items:14] panicked at crates/axfs_ramfs/src/file.rs:64:37:
attempt to add with overflow

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions