Published: Tue, Feb 03, 26

This patch instruments the Linux do_sys_openat2() syscall to log successful file open operations initiated by user-space processes. By observing file access at a central VFS entry point, it provides low-level visibility into process behavior without altering syscall semantics.


Security Rationale & Detection Value

From a security standpoint, file-open behavior is one of the most revealing low-level signals of process intent. Malware, compromised applications, and post-exploitation tooling often betray themselves not through network traffic alone, but through unexpected or anomalous filesystem access patterns.

By observing file opens at the syscall boundary, this instrumentation enables:

  • Early malware detection
    Malicious binaries frequently probe sensitive paths such as credential stores, configuration files, or persistence locations. Even simple logging can surface suspicious access sequences that would otherwise go unnoticed.

  • Compromised process identification
    Legitimate processes accessing files outside their normal operational profile (e.g., a user application opening /proc/kcore or /etc/shadow) can indicate runtime compromise or abuse.

  • Behavioral forensics and research
    Because this hook sits below libc and language runtimes, it captures real behavior rather than high-level intent, making it useful for studying loaders, droppers, and living-off-the-land techniques.

  • Low-impact observability
    Rate-limited logging prevents kernel log flooding, making this suitable for debugging, research kernels, and controlled monitoring scenarios without destabilizing the system.

This approach does not enforce policy or block access; instead, it provides transparent observability — a foundational capability for intrusion detection, threat modeling, and kernel-level telemetry experiments.


static long do_sys_openat2(int dfd, const char __user *filename,
			   struct open_how *how)
{
	struct open_flags op;
	int fd = build_open_flags(how, &op);
	struct filename *tmp;

	if (fd)
		return fd;

	tmp = getname(filename);
	if (IS_ERR(tmp))
		return PTR_ERR(tmp);

	fd = get_unused_fd_flags(how->flags);
	if (fd >= 0) {
		struct file *f = do_filp_open(dfd, tmp, &op);

		if (!IS_ERR(f) && current->mm) {
		    // ======= SECURITY PATCH: log every user-space open =======
	        pr_info_ratelimited(
		        "SECURITY_LOG: open pid=%d comm=%s path=%s\n",
		        current->pid, current->comm, tmp->name
	        );
	        // =========================================================
        }

		if (IS_ERR(f)) {
			put_unused_fd(fd);
			fd = PTR_ERR(f);
		} else {
			fsnotify_open(f);
			fd_install(fd, f);
		}
	}
	putname(tmp);
	return fd;
}


Notes & Scope

  • Logged paths are user-supplied strings, not fully resolved filesystem paths
  • Events may be dropped due to rate limiting
  • Intended for research, instrumentation, and documentation — not production enforcement
  • Superseded in modern systems by LSM or eBPF-based solutions, but valuable as a minimal, direct kernel hook example