Happy Wednesday. Time for another From Problem & To Polish scenario.
We usually trust ls -l to tell us who can access a file. But sometimes it tells you everything is fine, while the system quietly blocks access anyway.
Today’s challenge digs into a classic pitfall where permissions look correct, but SELinux has the final say.
You’re setting up a simple web page. You create the file in your home directory:
[user@server ~]$ vim index.html
Then you move it into the web server directory:
[root@server ~]# mv /home/user/index.html /var/www/html/
You check permissions with ls -l. Everything looks right. The file is readable.
But when you access the page, Apache or Nginx returns a 403 Forbidden. The audit log shows an AVC denial.
You’ve run into the classic mv versus cp trap. Let’s break it down.
ls -l isn’t showing the full picture. What flag do you add to reveal the SELinux context?user_home_t. Why did it keep that label after being moved into /var/www/html?/var/www/html?cp instead of mv, this problem wouldn’t have shown up. Why not?Who can spot the real permission issue here? Share your answers below.
Hi
My answers are:
1) The -Z option for the ls command will show the SE Linux contexts. For example; ls -lZ.
2) Moving a file retains the SE Linux file context of the directory it was created in. This means the SE Linux context will be incorrect for the directory that the file is being moved to.
3) Running the following command will change the SE Linux context on the moved file and restore the defaults to any other files in the directory:
sudo restorecon -Rv /var/www/html/
Bonus) When you copy a file, the file system creates a new file in place. The new file is created with the default SE Linux context/labelling rules for the directory it is created in. Copying a file from one directory to another keeps the original file context and labelling from the original directory.
restorecon -R
/var/www/html/index.html
cp instead of mv, this problem wouldn’t have shown up. Why not? Because it retains the selinux permissions
Hi
My answers are:
1) The -Z option for the ls command will show the SE Linux contexts. For example; ls -lZ.
2) Moving a file retains the SE Linux file context of the directory it was created in. This means the SE Linux context will be incorrect for the directory that the file is being moved to.
3) Running the following command will change the SE Linux context on the moved file and restore the defaults to any other files in the directory:
sudo restorecon -Rv /var/www/html/
Bonus) When you copy a file, the file system creates a new file in place. The new file is created with the default SE Linux context/labelling rules for the directory it is created in. Copying a file from one directory to another keeps the original file context and labelling from the original directory.
Hi
Find the details
The Diagnosis: ls -l isn’t showing the full picture. What flag do you add to reveal the SELinux context?
# ls -lZ
- This reveals the SELinux security context (like httpd_sys_content_t, user_home_t, etc.).
The Cause: You see the file labeled as user_home_t. Why did it keep that label after being moved into /var/www/html?
- When you move () a file, SELinux does not relabel it. It simply keeps the existing label because the inode is preserved — only the directory entry changes.
- So if the file was originally in with the label , moving it into won’t trigger a relabel. It still carries , which Apache () cannot read.
The Fix: What single command immediately restores the correct SELinux labels on everything under /var/www/html?
# restorecon -Rv /var/www/html
Bonus: If you had used cp instead of mv, this problem wouldn’t have shown up. Why not?
- When you copy () a file, a new inode is created in the destination.
- SELinux applies the default context for the destination directory to the new file.
- That’s why into would have automatically given it the correct label.
1. To reveal the SELinux context, when using the ls command,
I'm going to include the -Z option/switch: ls -Z.
Of course, if I want to see the file permissions, in additon to the
SELinux context (i.e. labels), I'll use both the -l and -Z options/swtiches: $ ls -lZ
2. Moving a file to a directory preserves the attributes (i.e. SELinux
labels).
Moving a file to the /var/www/html diretory preserves the original SELinux
which could be the incorrect SELinux context. In the case of moving a file
from the HOME directory of a user - which will have an SELinux context of
user_home_t - to the /var/www/html directory, will NOT change the
SELinux label for that file to the necessary SELinux context that a file is
required to have when being accessed by the web service (httpd).
3. The single command that immediately restores the correct SELinux
labels on everything under /var/www/html is:
$ sudo restorecon -Rv /var/www/html
-R change files and directories file labels recursively (descend directories).
-v show changes in file labels. Multiple -v options increase the verbosity.
Bonus: This issue would NOT have shown up, had the cp command been
used, instead of the mv command, because copying a file to a directory
causes that file to inherit the security context of the destination's directory.
Copying a file to /var/www/html ensures that the file inherits the correct
SELinux label for web content - which is typically httpd_sys_context_t.
The httpd_sys_context_t label is necessary for a web server to serve the
files correctly.
By default, the Apache HTTP Server cannot read files that are labeled with
the user_home_t type. If all files comprising a web page are labeled with
the user_home_t type, or another type that the Apache HTTP Server
cannot read, permission is denied when attempting to access them.
Brief SELinux Addendum:
SELinux labels (or contexts) are unique security identifies, that are
attached to every file, to enforce access control. These SELinux labels
define what can interact with what (e.g. what processes can interfact
with what files). A label typically has the following look:
user:role:type:level
with type being the most critical part for basic policies - in the case of web content, this type is httpd_sys_content_t.
A file with the SELinux type httpd_sys_content_t tells SELinux which
processes can access this file.
SELinux labels are stored as extended attributes for files, and ensure
strict confinement, allowing only explicitly (mandatory) permitted actions,
with access denial being the default action.
In the RHEL world, Apache is the default web server used. By default,
it has the following SELinux context: system_u:system_r:httpd:t:s0.
In this SELinux context, the httpd_t component is the key SELinux type
context for the Apache process.
The Apache web server process runs in the httpd_t domain. The SElinux
policy allows the Apache web server process to access web content that is
labeled with the httpd_sys_content_t type context.
Apache is allowed to access web content because of a specific SELinux
policy rule that permits a process running in the httpd_t domain to read
files and directories labeled with the httpd_sys_content_t type.
SELinux uses a type enforcement mechanismn, where processes are assigned domains, and files are assigned type contexts. Access by
processes is only permitted when a policy rule is explicitly defined.
httpd_t: This is the security context (or domain) assigned to the Apache
web server process itself when it runs.
httpd_sys_content_t: This is the file type context assigned to standard
static web content directories and files, such as those found in
/var/www/html/ by default.
If you've gone through the exercise of actually copying and moving a
file to the /var/www/html directory, a nice command to run, that will
provide some supporting evidence is the following:
$ matchpathcon -V /var/www/html/*
Red Hat
Learning Community
A collaborative learning environment, enabling open source skill development.