Linux Internals: How /proc/self/mem writes to unwritable memory (2021)

Linux’s “read‑only” memory isn’t so read‑only — devs split, memes fly

TLDR: Linux lets programs change “read‑only” memory through /proc/self/mem by having the kernel sidestep hardware checks, a behavior used by tools like Julia’s JIT and rr. Commenters split between “feature, not bug” swagger and security caveats, with a Linus Torvalds cameo stoking the debate.

Linux nerds are clutching pearls after a demo shows a program writing to “read‑only” memory using a sneaky system file: /proc/self/mem. It even hot‑patches a standard library function so the next call trips a debugger trap — and yes, real projects like the Julia JIT (just‑in‑time compiler) and the rr debugger rely on this. The twist: it’s not a bug. It’s an intentional “punch‑through” feature.

Cue the fireworks. One camp is shouting “the kernel is god”, waving bluepeter’s line that the kernel owns the map and can always find another way in. Others worry this blurs the promise of “read‑only,” but haberman’s TL;DR calms the thread: the kernel can bypass the hardware’s memory cop (the MMU, a chip that enforces permissions) by emulating access in software, so protections don’t apply the usual way.

Then the nitpickers arrive: hansendc reminds everyone there are more guardrails than the two listed — keys, virtualization layers, and secure enclaves like SGX/SEV — meaning context matters. And the drama cherry on top? KenoFischer name‑drops: Linus tried to change this and he was the first to notice. The memes write themselves: “Hold my /proc/self/mem,” “Schrödinger’s read‑only,” and “it’s not a bug, it’s a power move.” The takeaway: this quirk highlights where hardware rules end and kernel magic begins — and the community is loving the chaos.

Key Points

  • Linux’s /proc/*/mem supports “punch-through” writes that succeed even on pages marked read-only.
  • A demo program writes to a read-only mapping and to libc’s text segment via /proc/self/mem and verifies success.
  • Writing 0xCC (INT3) into libc’s getchar triggers SIGTRAP on execution, confirming code modification.
  • On x86-64, CR0.WP controls whether the kernel can write to read-only pages; when set, it inhibits such writes.
  • CR4.SMAP restricts kernel access to user memory, framing how hardware can constrain and the kernel can bypass protections.

Hottest takes

The kernel owns the page tables. It can always find another way in. — bluepeter
TL;DR: ... the kernel bypasses the MMU ... which allows it to disregard any memory protection ... — haberman
I’m still surprised I was the first one to notice when Linus tried to change this — KenoFischer
Made with <3 by @siedrix and @shesho from CDMX. Powered by Forge&Hive.