20.2 List and Identify SELinux File and Process Contexts
Key Takeaways
- SELinux labels are user:role:type:level tuples; on targeted policy, the type field (for example httpd_sys_content_t) is what you read most often for access decisions.
- List file contexts with ls -Z (and ls -Zd for directories); list process contexts with ps -Z or ps auxZ; show your own context with id -Z.
- Match process type to file type: a confined domain such as httpd_t needs correctly typed content, logs, and ports—wrong type is a classic AVC denial cause.
- Compare contexts on working vs broken paths (for example /var/www/html vs a custom DocumentRoot) to spot mislabels before changing modes or booleans.
- Identification is a read-only skill: this section focuses on listing and recognizing labels; restoring and persistently fixing labels is Section 20.3.
20.2 List and Identify SELinux File and Process Contexts
Quick Answer: File labels:
ls -Z/ls -Zd. Process labels:ps -Zorps auxZ. Your login context:id -Z. Read the type field inuser:role:type:levelfirst—on RHEL’s targeted policy, type is usually the decision that matters for services.
Why context identification is an EX200 skill
Under Manage security, Red Hat expects you to list and identify SELinux file and process contexts. Tasks look like:
- “Identify the SELinux context of
/var/www/html.” - “Show the context of the
httpdprocess.” - “Determine whether files under
/srv/webhave the correct type for a web server.” - “Report the SELinux user/role/type of the current shell.”
Before you run restorecon or change booleans, you must see what is labeled and what is running. Graders and real systems both reward correct reading of -Z output.
Anatomy of a context
A full SELinux security context looks like:
user:role:type:level
unconfined_u:object_r:httpd_sys_content_t:s0
system_u:system_r:httpd_t:s0
| Field | Typical meaning on RHEL targeted |
|---|---|
| user | SELinux user identity (unconfined_u, system_u, root_u, …)—not always the same as the Linux login name |
| role | Role in role-based access (object_r for files, system_r for many daemons, unconfined_r, …) |
| type (domain for processes) | The critical field for most RHCSA work—e.g. httpd_sys_content_t, httpd_t, sshd_t, user_home_t |
| level | Sensitivity/category (s0, sometimes s0:c0.c1023 with MCS)—often s0 on simple tasks |
Mental model: Linux discretionary permissions (ugo/rwx) answer “who may open this as UID/GID?” SELinux answers “may this domain (process type) access this type (file type) for this class of operation?” Both must allow access.
On targeted policy (RHEL default), many admin shells run as unconfined domains with broad freedom, while network-facing daemons (httpd_t, sshd_t, named_t, …) are tightly confined. That is why a file you can cat as root may still be denied to Apache if the type is wrong.
List file and directory contexts: ls -Z
ls -Z /var/www/html
ls -Z /var/www/html/index.html
ls -Zd /var/www/html
ls -laZ /var/www/html
| Command | Use |
|---|---|
ls -Z path | Show SELinux context with names |
ls -Zd dir | Context of the directory itself (not only its children) |
ls -laZ | Combine long listing (DAC mode, owner) with SELinux context |
ls -ZR dir | Recursive listing (noisy; use carefully) |
Example patterns you should recognize:
system_u:object_r:httpd_sys_content_t:s0 /var/www/html
unconfined_u:object_r:user_home_t:s0 /home/alice/public_html
system_u:object_r:var_t:s0 /var/myservice # often wrong for httpd content
system_u:object_r:etc_t:s0 /etc/httpd
Common web content types:
| Type | Typical use |
|---|---|
httpd_sys_content_t | Static content readable by httpd |
httpd_sys_rw_content_t | Content httpd may write |
httpd_sys_script_exec_t | Executable scripts (CGI-style paths) |
httpd_config_t | Apache configuration |
httpd_log_t | Apache logs |
httpd_var_run_t | Runtime files under /run |
Home and user types:
| Type | Typical use |
|---|---|
user_home_t | Normal home content |
user_home_dir_t | The home directory inode itself |
ssh_home_t | ~/.ssh materials |
admin_home_t | Root’s home content in many policies |
Shared / custom data:
| Type | Note |
|---|---|
var_t | Generic /var default—often insufficient for httpd DocumentRoot |
default_t | Generic default—frequently appears on new filesystems or poorly labeled mounts |
nfs_t / related | Network filesystem labels when applicable |
When a task moves web content to /srv/www or /web, ls -Zd /srv/www often reveals default_t or var_t instead of httpd_sys_content_t—that identification drives the restore/label fix in Section 20.3.
matchpathcon and stat (optional identification helpers)
matchpathcon /var/www/html
matchpathcon /srv/web
stat -c '%n %C' /var/www/html/index.html
matchpathcon shows what the policy’s file context database thinks a path should be labeled. Compare that to ls -Z actual label to see drift. stat -c '%C' prints the context in a compact form.
List process contexts: ps -Z
ps -Z
ps -eZ | head
ps -eZ | grep httpd
ps auxZ | grep -E 'httpd|sshd|nginx'
ps -ZC httpd
| Command | Use |
|---|---|
ps -Z | Contexts for processes in the current view |
ps -eZ | All processes with SELinux context |
ps -ZC name | Processes by name with context |
ps auxZ | User-oriented listing plus context |
Example process lines (simplified):
system_u:system_r:httpd_t:s0 ... httpd
system_u:system_r:sshd_t:s0 ... sshd
unconfined_u:unconfined_r:unconfined_t:s0 ... bash
Identify:
- Is the daemon confined? (
httpd_tyes; unexpectedunconfined_tfor a service may mean it was started oddly.) - Does the domain match the service you think is running?
- Are helper processes in related domains?
systemctl status httpd
ps -eZ | grep httpd
If httpd is not running, start it only if the task allows—identification of installed unit vs running domain are different checks.
Current user context: id -Z
id -Z
id -Z alice
Example:
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
id -Z shows the SELinux identity of your session (or another user when permitted). On RHEL, interactive admins are often unconfined, which explains why root can edit files that httpd cannot serve—DAC allows root, and SELinux does not confine that shell the same way as httpd_t.
Related tools:
secon # if available, decode context components
prompt often shows context in specialized shells—not required
Putting it together: process type vs file type
Access problems almost always reduce to:
Process domain T_process wants operation O on object type T_file (and class file/dir/…).
Identification workflow:
# 1) What domain is the service?
ps -eZ | grep httpd
# 2) What type is the content path?
ls -Zd /srv/web
ls -Z /srv/web | head
# 3) What should the path be?
matchpathcon /srv/web
# 4) Mode still enforcing?
getenforce
If httpd_t is serving files labeled user_home_t or default_t, you have identified a context mismatch. Do not conclude “SELinux is broken”—conclude “labels do not match the service domain.”
Directory vs contents
ls -Zd /srv/web
ls -Z /srv/web
Sometimes the directory is correct but new files created by copy (cp without preserving context) inherit an unexpected type, or only the top directory was relabeled. Identify both directory and file labels.
Copy and create behavior (awareness)
cp /var/www/html/index.html /tmp/index.html
ls -Z /var/www/html/index.html /tmp/index.html
Copied files often receive a type based on the destination directory policy, not always a perfect clone of the source type—unless you use options that preserve contexts. Identification after copy is a common exam discovery step before restorecon.
Other useful listing commands
# Find files with a given type (can be slow on large trees)
sudo find /srv -context '*:httpd_sys_content_t:*' 2>/dev/null | head
# Show context with find -Z (GNU find on RHEL)
find /var/www -maxdepth 2 -Z 2>/dev/null | head
# Pathname regex rules (policy database)—advanced identification
sudo semanage fcontext -l | grep '/srv/web'
semanage fcontext -l lists persistent path → context rules. You do not need to memorize the full policy map, but grepping for a custom path shows whether a permanent mapping already exists. Changing those rules belongs with restore workflows (20.3); listing them is identification.
DAC vs MAC: do not misread ls -l
ls -laZ /srv/web/index.html
You might see:
-rw-r--r--. 1 root root ... unconfined_u:object_r:default_t:s0 index.html
- Mode
644and ownerrootmay look “fine” for a web server reading world-readable files. - Type
default_tmay still cause AVC denial forhttpd_t.
Always include -Z when SELinux is in play. Conversely, a perfect SELinux type with mode 000 still fails DAC.
Exam identification workflows
Workflow A — Web content path
getenforce
ls -Zd /var/www/html
ls -Z /var/www/html | head
matchpathcon /var/www/html
ps -eZ | grep httpd
Workflow B — Custom DocumentRoot
ls -Zd /srv/myapp
ls -Z /srv/myapp | head
matchpathcon /srv/myapp
sudo semanage fcontext -l | grep '/srv/myapp' || true
Workflow C — User home and SSH
ls -Zd /home/alice
ls -Za /home/alice/.ssh 2>/dev/null
id -Z alice
ps -eZ | grep sshd
Workflow D — Compare good vs bad
ls -Zd /var/www/html /srv/web
matchpathcon /var/www/html /srv/web
Side-by-side context comparison is the fastest way to see that /srv/web is mislabeled relative to a known-good path.
Workflow E — Process domain inventory
ps -eZ | awk '{print $1}' | sort | uniq -c | sort -nr | head
Shows which SELinux domains are active—useful when a task asks which domain a service uses.
Common traps
- Reading
ls -lonly and missing a wrong type. - Checking files but not the directory (
ls -Zd). - Confusing SELinux user (
unconfined_u) with Linux user (alice). - Assuming root shell context means Apache can read the same path.
- Ignoring
matchpathconwhen actualls -Zdiffers from expected policy. - Looking at Permissive denials without identifying the process domain and file type pair.
- Treating
default_tas “fine because world-readable.” - Expecting
id -Zalone to show file contexts—it shows identity, not path labels. - Stopping at process list without
ps -Z, so you never seehttpd_t. - Jumping to
setenforce 0before identifying the mismatch (mode change hides the teaching of labels).
Relationship to other sections
| Skill | Section |
|---|---|
| Enforcing/Permissive modes | 20.1 |
| List/identify contexts | 20.2 (this) |
| restorecon / persistent fcontext | 20.3 |
| Port types for non-default ports | 21.1 |
| Booleans that loosen policy | 21.2 |
Identification tells you what is wrong; 20.3 and Chapter 21 tell you how to fix it without disabling SELinux.
Section checkpoint
You should list file contexts with ls -Z / ls -Zd, list process contexts with ps -Z / ps -eZ, show session context with id -Z, interpret user:role:type:level with emphasis on type/domain, compare actual labels to matchpathcon, relate httpd_t (and other domains) to content types such as httpd_sys_content_t, and separate DAC mode bits from SELinux labels. That is the EX200 skill to list and identify SELinux file and process contexts on RHEL 10.
Which command best lists the SELinux security context of files in a directory?
You need to see the SELinux domain of running httpd processes. Which approach is appropriate?
In the context unconfined_u:object_r:httpd_sys_content_t:s0, which field is usually most important for targeted-policy access decisions on RHEL?
What does id -Z display?