I Spent a Day Digging Into Linux's Filesystem and Found Some Really Weird Stuff
Deep Dive · Linux Filesystem

I Spent a Day Digging Into Linux's Filesystem and Found Some Really Weird Stuff
Okay so here's what happened.
I was just messing around on a Linux machine — not doing anything specific, just exploring. And I started going into folders and files that I normally never touch. You know how most of us just use ls, cd, mkdir and call it a day? Yeah I was doing the same thing for months.
But then I started actually reading what's inside these files, and honestly... I felt a little dumb for not knowing this stuff earlier. Linux is sitting there being completely transparent about everything it's doing, and I was just ignoring it.
So here's what I found. No fancy jargon, no tutorial vibes. Just things that genuinely surprised me.
1. There's a folder that shows you a process looking at itself — /proc/self
This one broke my brain a little when I first saw it.
Every running process on Linux has its own folder inside /proc/. So if your terminal is PID 423, there's a /proc/423/ folder. But /proc/self/ is special — it automatically points to whatever process is reading it. So when your shell looks inside /proc/self, it sees itself. When cat opens it, cat sees cat.
Inside that folder I found stuff like:
/proc/self/maps— this shows the entire memory layout of the process. Where its code is loaded, where the heap is, which shared libraries are mapped in, all with exact memory addresses./proc/self/syscall— this shows the current system call the process is making RIGHT NOW. I ran cat /proc/self/syscall and it returned 00x3 0x7f57...which means the process was executing syscall number 0 (sys_read) — it was reading its own syscall file while doing it. That's wild./proc/self/stack— the actual kernel-side call stack. You can seeentry_SYSCALL_64 → do_syscall_64 → ksys_read → vfs_read. This is the internal route the kernel takes, visible from outside.
I didn't need any special tool or root access for most of this. Just cat. That's the thing with Linux — the transparency is insane if you know where to look.
2. Your routing table is stored as an actual tree and you can read the tree — /proc/net/fib_trie
Most people know ip route or route -n. These show routing info in a nice table. But that table is just a pretty version of what's actually inside the kernel.
The real thing lives at /proc/net/fib_trie. It's a data structure called a Patricia trie (a kind of compressed tree), and you can just... read it.
Main:
+-- 0.0.0.0/0 3 0 5
+-- 192.0.2.0/24 2 0 2
+-- 192.0.2.0/30 2 0 2
|-- 192.0.2.2 /32 host LOCAL
|-- 192.0.2.255 /32 link BROADCAST
The +-- and |-- are actual branches of the tree. When a network packet comes in and Linux needs to decide where to send it, it walks exactly this structure. Not a table, not a list — a tree, for performance.
And then there's /proc/net/route which shows the same routing data but in raw hexadecimal, little-endian format. So the gateway 010200C0 is actually 192.0.2.1 when you reverse the bytes. That's the format Linux stores it internally. Tools like ip route are just decoding this for you.
3. All your TCP connections are in a file — in hex — and you can decode them yourself
/proc/net/tcp shows every active TCP connection on your machine. But it doesn't show them nicely. It shows them like this:
020200C0:D7B4 0A684FA0:01BB 01
That first part is the local address in hex. 020200C0 reversed byte-by-byte = 192.0.2.2. Port D7B4 in decimal is 55220. The remote address 0A684FA0 = 160.79.104.10. Port 01BB = 443. State 01 = ESTABLISHED.
So this machine was actively connected to 160.79.104.10 on port 443 (HTTPS). And when I checked /etc/hosts, there it was: 160.79.104.10 api.anthropic.com — hardcoded, no DNS needed.
Tools like netstat and ss just parse this file and clean it up for you. The raw data has always been sitting right there.
4. Linux tracks how fragmented your RAM is, in real time — /proc/buddyinfo
This one I had genuinely never heard of before.
Linux uses something called a "buddy allocator" to manage physical memory. When a program needs memory, the kernel finds a free block of the right size. Over time, after lots of allocations and frees, memory gets fragmented — there are gaps, and large contiguous blocks become hard to find.
/proc/buddyinfo shows the current state of that:
Node 0, zone Normal 2 1 1 2 3 1 2 0 2 2 2 0 7
Each number is how many free blocks of that size exist (blocks are 2^n pages). That last number, 207, means 207 blocks of 4MB are free in the Normal zone.
Why does this matter? For databases, JVMs, and anything using huge pages — fragmentation directly affects performance. But free -h or top won't tell you this. They just show total free vs used. The buddy allocator state is the real picture underneath.
5. You can see where on the memory bus every device lives — /proc/iomem
00100000-bfffffff : System RAM
01000000-01e9e197 : Kernel code
02000000-023bbfff : Kernel rodata
02400000-0253933f : Kernel data
4000000000-400007ffff : virtio-pci-modern
This file shows which physical memory addresses are assigned to which things. You can see where the kernel's own code lives in physical memory, where read-only kernel data is, and where hardware devices are mapped.
That virtio-pci-modern entry told me immediately this machine is a virtual machine using VirtIO devices — the paravirtualization tech used in KVM, QEMU, and cloud VMs.
And then /proc/ioports showed me the keyboard controller at port 0x0060 and the real-time clock at 0x0070. These are legacy PC hardware ports from the 1980s — still present in this 2026 cloud VM kernel, because Linux maintains backward compatibility like it's a religion.
6. Security policy is just a number in a file — /proc/sys/kernel/randomize_va_space
ASLR — Address Space Layout Randomization — is a security feature that randomizes where memory is loaded so attackers can't predict addresses. It's considered essential for preventing certain exploits.
The setting that controls it on your entire system:
cat /proc/sys/kernel/randomize_va_space
Returns 2. That means full randomization — stack, heap, libraries, everything.
You can change it instantly:
echo 0 > /proc/sys/kernel/randomize_va_space
And ASLR is off. No reboot. No restart. Just a file write. The entire system's security posture for memory randomization, controlled by writing a number to a file.
Nearly every kernel tuning parameter works this way. /proc/sys/ is basically a live control panel for the kernel, exposed as files.
7. The kernel has already decided which process to kill first if RAM runs out — /proc/self/oom_score
When your Linux machine runs completely out of memory, the OOM (Out of Memory) killer wakes up and picks a process to kill. It doesn't pick randomly. It's been quietly scoring every process the whole time.
cat /proc/self/oom_score
Our shell: 666. PID 1 (the main system process): 0.
Score 0 means the kernel will never kill it. Score 1000 means it gets killed first. Our shell was sitting at 666 — the kernel had pre-decided it was a high-priority sacrifice.
You can change your own score:
echo -1000 > /proc/self/oom_score_adj
And your process becomes OOM-unkillable. Docker does exactly this for its daemon process. It writes -1000 to its own oom_score_adj at startup so it never gets killed, no matter what.
This scoring is happening in the background on every Linux machine, all the time. Most people have no idea.
8. The kernel's entire symbol table — every internal function with its address — is in a file — /proc/kallsyms
ffffffff81000080 T entry_SYSCALL_64
ffffffff81000230 T irq_entries_start
ffffffff81000940 T asm_exc_divide_error
entry_SYSCALL_64 at address 0xffffffff81000080 is the actual function the CPU jumps to when any program on this machine makes a system call. Every open(), read(), write(), fork() — they all enter the kernel through that address, right now, on this machine.
And you can just... read it. With cat.
On hardened systems, /proc/kallsyms returns 0000000000000000 for all symbols to prevent attackers from knowing where kernel functions live (which helps prevent certain exploit techniques). On this system, kptr_restrict was 0, so all addresses were visible.
That one file's content is literally a security decision that splits the world into "safe to read" and "dangerous".
9. The boot command line tells you everything about a machine — /proc/cmdline
This is the one that really surprised me.
console=ttyS0 reboot=k panic=1 nomodule random.trust_cpu=1
ipv6.disable=1 swiotlb=noforce rdinit=/process_api
init_on_free=1 -- --firecracker-init --addr 0.0.0.0:2024
Let me translate what I read from this:
nomodule— no kernel modules can be loaded. This is a locked-down system.rdinit=/process_api— instead of booting into systemd or /sbin/init like a normal Linux machine, this one boots directly into a custom binary called process_api. It's not a general-purpose OS at all.panic=1— if the kernel crashes, reboot in 1 second.init_on_free=1— every time memory is freed, it gets zeroed. This prevents one process from reading another's leftover data.ipv6.disable=1— IPv6 completely off at the kernel level.--firecracker-init— this machine is running inside AWS Firecracker, which is the microVM technology behind AWS Lambda.
From one file, with no special tools, I figured out this machine's entire deployment model, security configuration, virtualization layer, and purpose.
10. There's a config file that decides how Linux looks up names — and most devs have never seen it — /etc/nsswitch.conf
hosts: files dns passwd: files
hosts: files dns
passwd: files
That line hosts: files dns is why /etc/hosts beats DNS. Linux checks files first, DNS second. So when /etc/hosts says 160.79.104.10 api.anthropic.com, no DNS query is ever made — the answer is already there.
Change it to hosts: dns files and DNS wins. Change to hosts: files and DNS is never consulted at all.
This is the file that decides the order of name resolution on your entire system. It applies to hostnames, user lookups, group lookups — everything. I genuinely didn't know this file existed until I started digging, and it explains a lot of confusing behavior I've seen with /etc/hosts overrides sometimes working and sometimes not.
11. The kernel scores RAM fragmentation by zone — /proc/zoneinfo
Similar to buddyinfo but more detailed — /proc/zoneinfo breaks down memory into DMA, DMA32, and Normal zones, each with its own free pages, active/inactive anonymous pages, and file-backed page counts.
The Normal zone had pages marked as "active file" (recently used file cache) vs "inactive file" (file cache that can be reclaimed). This is the exact data the kernel uses to decide what to evict when memory pressure hits.
When your application suddenly slows down under memory pressure, this is the map the kernel is looking at to decide what to throw away.
12. /etc/shadow exists because of a mistake — and it's a lesson in security design
/etc/passwd is world-readable. It has to be, because every program that maps a user ID to a username needs to read it.
In early Unix, password hashes were stored in /etc/passwd. That was fine when cracking was slow. But as hardware got faster, storing hashes in a world-readable file became a disaster — anyone could copy the file and crack passwords offline.
The fix was /etc/shadow — a separate file with the same password info but restricted to root only.
The x in /etc/passwd just means "look in shadow instead."
When I read our /etc/shadow:
root:*:20553:0:99999:7:::
That * means no password login is possible at all for root — not even a hash to crack. The numbers after are password aging policy: last changed (days since Unix epoch), minimum days before change, maximum days before forced change, warning period.
The shadow file exists entirely because of a historical mistake. It's a reminder that in security, you often fix problems by separating concerns — put sensitive data somewhere with tighter permissions instead of protecting it with obscurity.
What I came away with
The thing that stuck with me most isn't any single file. It's the realization that Linux is completely narrating itself the entire time it runs.
Every routing decision, every memory allocation, every open socket, every process's kill priority, every security setting — it's all written into files, readable with cat, right now, on your machine.
Most of us spend years using Linux as a black box where you type commands and get outputs. But once you start reading /proc/ and /sys/, it becomes transparent. You're not reading documentation. You're reading the live state of the kernel itself.
That shift in perspective changed how I think about debugging, performance, and security. Not because I memorized file paths, but because I understood that Linux is always talking — you just have to know which files to open.
Written after a real exploration session on a Linux 6.18.5 machine running inside AWS Firecracker. All findings above came from actual files on the system — no tools, no special access, mostly just cat.



