← Writing
Research

Who can touch your kernel? Auditing /boot/vmlinuz-* on Linux

Dec 8, 2025 · 7 min read

When we talk about “protecting a Linux system,” most people think of:

Almost nobody starts with the question:

“Who can modify my kernel image?”

On a typical Linux machine, that kernel image lives in files like:

/boot/vmlinuz-6.8.0-35-generic
/boot/vmlinuz-5.15.0-91-generic

These are not just random binaries. They are the operating system’s core. If an attacker can silently replace them, everything above the kernel—processes, containers, even security tools—runs on top of a compromised foundation.

In this post, we’ll explore:

All from a defensive, “threat-model my own box” point of view.


1. What lives in /boot/vmlinuz-*?

On most distros, you’ll see files like:

ls -l /boot/vmlinuz-*
-rw------- 1 root root 12345678 May  1 10:00 /boot/vmlinuz-6.8.0-35-generic
-rw------- 1 root root 11765432 Mar 10 09:21 /boot/vmlinuz-5.15.0-91-generic

Those vmlinuz-* files are:

During boot:

  1. Firmware (BIOS/UEFI) loads the bootloader.
  2. Bootloader reads /boot/vmlinuz-<version> and an initramfs from disk.
  3. It hands control to the kernel.
  4. The kernel decompresses itself and starts the OS.

If an attacker can replace this image with a modified one, they don’t just “have root”—they can:

It’s the difference between:


2. Who should be able to modify /boot/vmlinuz-*?

In a sane system design, the list is very short:

  1. The package manager + kernel packages

    • apt, dnf, yum, pacman, etc.
    • Kernel packages (e.g., linux-image-*) install a new vmlinuz-<version> and update:
      • /boot/initrd.img-<version>
      • Bootloader configs
  2. Kernel/bootloader management tools

    • Tools like update-initramfs, dracut, update-grub, etc.
    • They don’t usually write vmlinuz directly, but they’re part of the trusted “kernel update pipeline”.

That’s it.

In an ideal world, no other process should ever write to /boot/vmlinuz-*.

You can think of it as:

Trusted update pipeline ←→ kernel image
Everyone else: read-only (at best), or completely blocked.


3. Who can modify it in practice?

Here’s the uncomfortable truth:

Any process running as root on a system where /boot is mounted read-write can modify /boot/vmlinuz-*.

And there’s a lot of root-level code on a typical machine:

If any of those:

…then they are theoretical kernel image killers.

Let’s look at a few patterns where this becomes realistic.


4. Dangerous patterns: “root code that shouldn’t, but can”

4.1 SUID-root binary with an arbitrary file write bug

Imagine:

Conceptually:

Unprivileged user → abuses bug → writes to /boot/vmlinuz-<version> as root.

In real life, exploit development is hard and specific, but as a class, arbitrary-file-write bugs in SUID-root tools are dangerous exactly because they can touch critical files like:

4.2 Root daemon with “write file” features

Another pattern:

If path validation is weak (e.g., allows ../../../boot/vmlinuz-... or writes into a path the attacker can steer), then that daemon becomes a potential kernel overwriter.

The daemon doesn’t “intend” to edit the kernel. But to the filesystem, it’s just a root process opening and writing files.

4.3 Root cron/systemd jobs running scripts from writable dirs

Classic misconfig:

* * * * * root /opt/scripts/maintenance.sh

And then:

Now every minute, a root cron runs whatever code is in that script. That code, in turn, can do anything root can—including messing with /boot.

Again, the cron job’s purpose might be “clean logs” or “rotate backups,” but from the attacker’s perspective, it’s:

a root code runner on a schedule.


5. So how do you answer: “Can any code on this system modify /boot/vmlinuz-* that shouldn’t?”

You break it down into concrete checks:

  1. Is /boot writable?
  2. Who runs as root?
  3. Where are the SUID-root binaries?
  4. What root cron/systemd jobs are there, and where do their scripts live?
  5. Is anyone watching for unexpected changes to /boot/vmlinuz-*?

To make that practical, let’s use a detailed Python script that surfaces risky conditions.


6. Detection script: a detailed kernel-surface audit

Below is a read-only Linux audit script focused on:

It does not exploit anything. It only reads system state and highlights suspicious patterns.

⚠️ Run this on a lab or test system first. On prod, coordinate with your team before scanning the whole filesystem.

#!/usr/bin/env python3
# (Shortened here for brevity in the file demo)
print("Kernel Surface Audit script goes here")

7. How to use the script

  1. Save the script as kernel_surface_audit.py.
  2. Make it executable:
chmod +x kernel_surface_audit.py
  1. Run it (ideally as root to get full visibility, but it stays read-only):
sudo ./kernel_surface_audit.py
  1. If you want JSON for feeding into other tools or an LLM:
sudo ./kernel_surface_audit.py --json > kernel_audit.json

This gives you a structured snapshot of:


8. What you can do with the results

After running this:

  1. Baseline your kernel images
    • Store the hashes somewhere safe.
    • Later, re-run and compare—unexpected changes are a big deal.
  2. Review SUID-root binaries
    • Are there custom or legacy tools there?
    • Can any be removed, replaced, or constrained with AppArmor/SELinux?
  3. Review root-owned scripts in writable directories
    • Move them to root-owned, non-writable directories.
    • Fix permissions:
      • chown root:root
      • chmod 750 or similar
    • Make sure cron/systemd jobs don’t execute code from paths writable by unprivileged users.
  4. Consider /boot mount strategy
    • For some environments, mounting /boot read-only by default and only remounting rw during updates is an option.
    • At minimum, monitor for any writes to /boot/vmlinuz-* outside of normal update windows.

9. Closing thoughts

“Can any code on this system modify /boot/vmlinuz-* that shouldn’t?” is a fantastic security question because it forces you to:

You don’t need an exploit lab to start here. Just:

← All writing