Diving into the SELinux labeling system: reading file contexts with ls -Z and stat -Z, changing labels temporarily with chcon, mapping permanent labels with semanage fcontext, restoring default labels with restorecon, and relabeling the filesystem with fixfiles and setfiles.

In episode 3 we learned to read AVC denials and diagnose them — and the answer is often a wrong label. Labels are the language the policy matches on: a file labeled user_home_t won't be read by the httpd_t process no matter how simply the file is chmod'd. This episode will teach you how to view, change, restore, and relabel the filesystem — the skill that saves you most often in production.
This is also the episode where you'll start using semanage often — the tool that's been mentioned since episode 0. Let's break it down one by one.
All the commands you normally use have a -Z variant to display the security context — try ls -Z and stat -Z:
ls -Z /var/www
ls -lZ /etc/nginx/nginx.conf/var/www:
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 htmlThe extra column that appears is the security context in the user:role:type:sensitivity format we dissected in episode 2. For more precise detail — including unrecognized labels shown as ? — use stat:
stat -Z /etc/nginx/nginx.conf File: /etc/nginx/nginx.conf
Size: 641 Blocks: 8 IO Block: 4096 regular file
Device: fd00h/64768d Inode: 21347 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Context: system_u:object_r:etc_t:s0ls -Z for viewing many files at once, stat -Z for digging deep into a single file — including checking whether its label is ? (unknown), which is often the first clue that something is wrong.
There are two ways to change labels, and the difference between them is the biggest source of confusion in the SELinux world.
chcon directly writes a new label to the object — like chmod for contexts. This command is fast and practical for experimentation:
sudo chcon -t httpd_sys_content_t /srv/www/index.htmlThe problem is that this change is not permanent: when the system relabels the filesystem (for example via fixfiles, or at boot with a relabel flag), the labels will return to the policy's default values. For production, this isn't the right way.
chcon only changes the label; it doesn't change the rule. Rules live in the semanage fcontext database, and that's where permanent mappings are made:
sudo semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?"
sudo restorecon -Rv /srv/wwwThe first line adds a rule: all files under /srv/www (the regex pattern (/.*)?) must be labeled httpd_sys_content_t. The second line, restorecon, applies that label to the objects that currently exist.
Important
The golden rule of labeling: chcon for experimentation, semanage fcontext for permanence. If you only use chcon in production, the labels will disappear on the next relabel and the problem will come back — and you'll struggle to explain why. Always get in the habit of adding an fcontext rule for permanent changes.
restorecon restores an object's label according to the registered fcontext rules. This is the command you'll use most often when copied or moved files carry an old label:
sudo restorecon -Rv /etc/nginx-R for recursive, -v to show changes. A typical example: you move a config file from /home/user to /etc — the file still carries the user_home_t label even though its location is now in the etc_t area. One restorecon and the label is correct again.
Sometimes the whole filesystem needs to be relabeled — for example when moving from disabled to enforcing, or after many labels got scrambled. Two tools that work as a pair:
fixfiles — the high-level (wrapper) tool for relabeling the entire filesystem:sudo fixfiles -F onboot
sudo rebootfixfiles -F onboot marks the system to relabel at the next boot — the safest way because the filesystem isn't mounted read-write while the process runs.
setfiles — the low-level tool that does the actual relabeling. fixfiles is just a wrapper that calls setfiles with the right arguments. For manual use on a specific directory, give it the file context file and the target root path:sudo setfiles -v -A /etc/selinux/targeted/contexts/files/file_contexts /srvThe -v option shows every label change, and -A disables tracking of files with multiple hard links — saving memory for large relabeling jobs.
It's important to understand the priority order: restorecon uses the fcontext rules you added via semanage; fixfiles and setfiles use the default context files stored in /etc/selinux/<policy>/contexts/files/file_contexts plus the fcontext additions. That's why semanage fcontext rules survive even when a relabel is done.
An fcontext rule can be written as a literal path or a regex pattern — and this determines the rule's scope:
| Type | Example | Scope |
|---|---|---|
| Literal | /srv/www | Only that exact directory |
| Regex | /srv/www(/.*)? | That directory and all its contents |
The /srv/www(/.*)? pattern is the most common idiom — look at the list of built-in rules to learn the patterns:
sudo semanage fcontext -l | grep -E "^/var/www"/var/www(/.*)? all files system_u:object_r:httpd_sys_content_t:s0
/var/www/html(/.*)? all files system_u:object_r:httpd_sys_content_t:s0Notice two things: the middle column (all files) determines which object classes the rule affects, and the same regex pattern is reused over and over. Getting used to reading this table will help you guess the correct label before running restorecon.
Tip
When unsure what label a file should have, check an example from the system: find a similar file that's already correct, for example ls -Z /var/www/html, then use the type from that result. You can also look for references in semanage fcontext -l. Guessing types without looking at examples is the most common source of scrambled labels.
In this episode 4, we've mastered the complete labeling workflow: reading labels with ls -Z and stat -Z, changing them temporarily with chcon, mapping them permanently with semanage fcontext, restoring them with restorecon, and full relabeling with fixfiles and setfiles. We also understood the difference between literal vs regex patterns in fcontext rules.
The essentials to take with you:
ls -Z for many files; stat -Z for single-file detail.chcon = temporary, semanage fcontext = permanent — the golden rule of labeling.restorecon restores labels according to the registered fcontext rules.fixfiles -F onboot to relabel the entire filesystem at boot; setfiles as its low-level tool.(/.*)? regex pattern makes an fcontext rule cover the entire directory contents.In the next episode 5, we'll discuss domains, types & policy modules — reading TE rules with sesearch and seinfo, understanding the structure of allow and neverallow rules, and managing policy modules with semodule in the .pp and .cil formats. Stay motivated, because this is where you start "reading" and "understanding" the policy you've only seen from the outside until now!