Intermediate · SELinux and SSH · topic 30 of 57 · 35 min
Contexts and file labels: ls -Z, semanage fcontext and restorecon
Explanation
Reading a context
$ ls -Z /var/www/html/index.html
unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/index.html
$ ls -Zd /home/asha
unconfined_u:object_r:user_home_dir_t:s0 /home/asha
$ ps -eZ | grep httpd | head -1
system_u:system_r:httpd_t:s0 1301 ? 00:00:00 httpd
$ id -Z
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023A context has four parts separated by colons: SELinux user (system_u), role (object_r for files), type (httpd_sys_content_t), and level (s0, used for multi-level security). In the targeted policy, decisions are made almost entirely on the TYPE. So when people say "the label is wrong", they usually mean the type.
Where do file labels come from?
The policy contains a database of rules that map paths to types: /var/www(/.*)? should be httpd_sys_content_t, /home/[^/]+ should be user_home_dir_t, and so on. New files normally inherit the type of the directory they are created in. restorecon resets files to what the database says.
The classic problem: content in a custom folder
# mkdir /web
# echo "Namaste" > /web/index.html
# ls -Z /web/index.html
unconfined_u:object_r:default_t:s0 /web/index.html
# (DocumentRoot set to /web in httpd.conf, httpd restarted)
$ curl http://localhost/
<title>403 Forbidden</title>The right fix: semanage fcontext + restorecon
# semanage fcontext -a -t httpd_sys_content_t '/web(/.*)?'
# restorecon -Rv /web
Relabeled /web from unconfined_u:object_r:default_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0
Relabeled /web/index.html from unconfined_u:object_r:default_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0
$ curl http://localhost/
Namastesemanage comes from the policycoreutils-python-utils package. Find the type you need by looking at the default location: ls -Zd /var/www/html shows httpd_sys_content_t. semanage fcontext -l | grep /var/www lists the existing rules for that path. Use httpd_sys_rw_content_t if the web app must WRITE there (uploads).
chcon: temporary only
chcon -t httpd_sys_content_t /web/index.html also changes a label, but it does not touch the database. The next restorecon, or a full relabel, puts the old label back. Use chcon only for a quick test; always finish with semanage fcontext.
Copy versus move
| Action | Label of the result |
|---|---|
| cp file /var/www/html/ | New file: inherits the target directory's type (good) |
| mv file /var/www/html/ | Keeps its OLD label (often wrong, e.g. user_home_t) |
| cp -a or cp --preserve=context | Keeps the old label |
A very common real-world bug: a developer builds a page in their home directory and mv's it into /var/www/html. It keeps user_home_t, and httpd gets "403 Forbidden". restorecon -Rv /var/www/html fixes it.
Common mistakes
- Using chcon and thinking it is permanent.
- Writing the semanage pattern without quotes, or as /web/* instead of '/web(/.*)?'. The pattern is a regular expression.
- Running semanage fcontext and forgetting restorecon. The rule exists but existing files keep their old label.
- Changing normal permissions to 777 to fix an SELinux denial. It does not help and adds a new hole.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Contexts and file labels: ls -Z, semanage fcontext and restorecon · 1/6
Every file and process has a context: user, role, type and level. The type matters most.
Prefer a video by a teacher? Find free videos on “selinux semanage fcontext restorecon httpd tutorial” on YouTube ↗
In real life: Moving a government portal's files to a new disk
A state government portal moved its web files to a new, bigger disk mounted on /srv/portal. After the move, every page showed 403 Forbidden. The new file system had default_t labels. The admin added one semanage fcontext rule for /srv/portal, ran restorecon, and the portal was back in two minutes, with SELinux still enforcing.
# semanage fcontext -a -t httpd_sys_content_t '/srv/portal(/.*)?'
# restorecon -R /srv/portal
# ls -Zd /srv/portal
system_u:object_r:httpd_sys_content_t:s0 /srv/portalPractice (0/4 done)
In system_u:object_r:httpd_sys_content_t:s0, which part is the type?
Write parse_context(ctx) that splits an SELinux context like "system_u:object_r:httpd_sys_content_t:s0" into a dict with keys user, role, type and level. The level itself may contain colons (for example "s0-s0:c0.c1023"), so only split on the first three colons.
Which line has the bug? Goal: label /data/www permanently for httpd. 1: semanage fcontext -a -t httpd_sys_content_t '/data/www(/.*)?' 2: chcon -R -t default_t /data/www 3: restorecon -Rv /data/www
Serve a page from /web with httpd while SELinux stays enforcing: set DocumentRoot (and its <Directory>) to /web, see the 403, then fix the label permanently.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- SELinux booleans and port labelsSELinux and SSH · same module
- Troubleshooting SELinux denialsSELinux and SSH · same module
- Errors as values: wrap, Is and AsGo Programming (backend and cloud) · Pointers, interfaces and errors
- The Linux filesystem and everyday commandsDevOps: Git, Docker, Kubernetes and CI/CD · Linux for DevOps
- context: timeouts and cancellationGo Programming (backend and cloud) · Concurrency: goroutines, channels and context
- Persistent storage and containers as systemd servicesBoot, recovery and containers
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
Which command applies the labels from the policy database to existing files?
Answer: restorecon
restorecon resets labels to the database values.
Why is chcon not a permanent fix?
Answer: The next restorecon or relabel resets the label
chcon does not change the database.
A file moved with mv from /home/asha to /var/www/html gives 403. Why?
Answer: mv keeps the old user_home_t label
Moved files keep their context; run restorecon.
Which package provides semanage on RHEL 9?
Answer: policycoreutils-python-utils
dnf provides semanage tells you.
Which type should a folder where the web app saves uploads have?
Answer: httpd_sys_rw_content_t
The rw type allows httpd to write.
A port already has a different label. Which semanage option changes it?Related
What does SELinux add to normal Linux permissions?Related
Answer: Mandatory, label-based rules that even root processes must follow
It is mandatory access control based on labels.
Which command shows SELinux denials from the last few minutes?Related
Answer: ausearch -m AVC -ts recent
ausearch filters audit records by type and time.
Which command copies the folder /etc/ssh with all owners and permissions kept?Related
Answer: cp -a /etc/ssh /backup
-a (archive) copies recursively and keeps owner, permissions and times.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 3 more topics in “SELinux and SSH” before its exam: SELinux booleans and port labels, Troubleshooting SELinux denials, SSH: keys, ssh-copy-id and hardening sshd.
- Module 6 exam: SELinux and SSH · 13 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Automation basics: scheduling, archives and shell scripts. 57 topics left in the course before the final exam.