Dissecting selinuxfs at /sys/fs/selinux as the userspace-kernel bridge, the enforce file and runtime booleans, label verification with matchpathcon, and live inspection with seinfo, sesearch, and semanage.

In episode 15 you read denials from ausearch, changed booleans with setsebool, and ran semanage. All of that works — but have you ever asked where the meeting point between userspace and kernel actually is? The answer is selinuxfs: a virtual filesystem the kernel opens specifically for SELinux, and the place where libselinux, all the tooling, and you yourself talk to the kernel.
This episode opens the hood. We dissect the contents of /sys/fs/selinux, understand userspace-kernel interaction (including the AVC cache in userspace), and complete it with a runtime inspection toolkit: matchpathcon for label verification, seinfo for exploring the policy, and semanage for seeing the configuration that's actually in effect on a live machine. By the end of this episode, when a machine is "weird", you'll know exactly where to start investigating.
selinuxfs is a virtual filesystem (nothing stored on disk) created by the kernel for SELinux, usually mounted at /sys/fs/selinux. Confirm it:
mount | grep selinuxfsselinuxfs on /sys/fs/selinux type selinuxfs (rw,nosuid,nodev,noexec,relatime)Note: this filesystem doesn't exist when SELinux is set to disabled — it only exists in enforcing or permissive mode. That's a very useful diagnostic point: if /sys/fs/selinux isn't mounted, SELinux isn't active at the kernel level, no matter what the config file claims.
The contents of this directory are the communication gate to the kernel. Some of the most important files:
ls /sys/fs/selinux
cat /sys/fs/selinux/enforce
cat /sys/fs/selinux/policyversenforce avc booleans context create deny_unknown policy policy_capabilities policyvers status validatetrans
1
33The meaning of each:
enforce — contains 1 (enforcing) or 0 (permissive). Writing 1 or 0 to this file is equivalent to setenforce 1/setenforce 0. This is the lowest-level "switch".policyvers — the maximum binary policy version the kernel supports (here 33 for modern kernels). This version rises every time the kernel adds policy features.policy — the loaded binary policy image; tooling saves it to disk as a forensic artifact.booleans/ — one file per boolean; reading them shows the boolean value currently active in the kernel, regardless of what userspace claims:cat /sys/fs/selinux/booleans/httpd_can_network_connectavc/ — kernel AVC cache statistics (hash_stats, cache_stats). High numbers of cache lookups being hit means the policy is rarely queried — that's normal; what deserves attention are denials appearing alongside.Now the part that ties it all together: how do SELinux tools talk to the kernel? The answer: libselinux — the userspace library used by almost all tools — reads and writes files in selinuxfs. The flow for one access decision:
open()).status file, which provide notifications when the policy or booleans change.Meaning, when you run setsebool -P, what happens is: the change is written to the policy store (/var/lib/selinux/<policy>/), the kernel is notified through the boolean files in selinuxfs, and waiting userspace gets a notification to refresh its cache. All layers are in sync — and selinuxfs is the connecting axis.
Tip
If you change a boolean via semanage boolean or setsebool and the application behavior doesn't change, compare the value at cat /sys/fs/selinux/booleans/<name> with the value in the store. What's active in the kernel is the truth; the value in the config file is just an intention.
In episode 5 we introduced restorecon. Now we use its counterpart for verification without changing anything: matchpathcon matches a path against the default context it should have according to semanage fcontext:
matchpathcon /var/www/html/index.html
matchpathcon -V /var/www/html/var/www/html/index.html verified.-V verifies the entire directory contents against the default contexts — and only reports the mismatches, changing nothing. This is the safest label audit tool that exists: it doesn't write, only compares. Compare it with restorecon -n, which shows what would be changed without applying it:
restorecon -n -R -v /var/www/htmlseinfo (part of setools) reads the active policy and answers catalog questions: "how many types? what booleans? what attributes does this type have?" Two most useful forms:
seinfo -t
seinfo -bBooleans: 294With the -x (expand) flag, seinfo shows details per type — including the attributes it belongs to. This is very useful when you find a denial and want to know "what attribute is this type part of?":
seinfo -xtype httpd_tIf seinfo is the policy dictionary, sesearch is the investigator — we've used it in episodes 13 and 14 to find rules. The combination is the static analysis toolkit: seinfo for structure, sesearch for behavior.
Runtime inspection isn't complete without seeing what changed from the defaults. This is where the -C (custom) flag on semanage is gold — it shows only the entries you (or someone) added to the store, not the whole database:
semanage fcontext -l -C
semanage boolean -l -C
semanage port -l -C
semanage permissive -l
semanage login -lsemanage fcontext -l -C
/data/vms(/.*)? all files system_u:object_r:virt_image_t:s0Those four commands are the "configuration health snapshot": custom file contexts, changed booleans, relabeled ports, and permissive domains. If there's something you "don't remember installing", this is the first line of investigation evidence — just like the forensics we did in episode 15.
One more thing often forgotten during live inspection: sestatus -v shows the contexts of important processes and files (sshd, cron, /etc/shadow) while verifying them at the same time. For a host managed by many people, running the five -C commands above every time there's a major change is a cheap and very valuable habit.
In this episode 16, you've opened the SELinux hood: understanding selinuxfs as the virtual filesystem bridge between userspace and kernel (and as diagnostic proof that SELinux is active), reading and writing the enforce file, checking policyvers and booleans directly from the kernel, understanding AVC cache synchronization through netlink notifications, verifying labeling with matchpathcon and restorecon -n, exploring the policy catalog with seinfo -t/seinfo -b/seinfo -xtype, and doing live inspection with semanage ... -l -C to find every custom change.
The essentials to take with you:
/sys/fs/selinux being mounted.selinuxfs (enforce, booleans) are the runtime truth; config files are just intentions.matchpathcon -V verifies labels without changing anything — the safest audit tool.seinfo for policy structure, sesearch for its behavior.semanage ... -l -C is the surveillance camera for every custom change in the store.Now you can dissect a live machine down to its kernel bridge. But all this tooling uses a ready-made policy. What if you want to build a large-scale policy with full control — not one small module like episode 12, but a layered policy architecture? In the next episode 17, we enter Advanced Policy Development (CIL & Module Layers): the modern CIL language, compilation with secilc, modular policy hierarchy, the difference between .pp modules and CIL, dependency management, and maintainability best practices for production policies. See you in episode 17!