SELinux Denied Operation: Fix the AVC Denial Fast
SELinux blocking an operation? We'll find the denial in audit.log, fix the context or policy, and prevent it from coming back.
Quick answer
Run sudo ausearch -m avc -ts recent | audit2why to see the denial reason, then either restorecon -v /path to fix a label, or setsebool -P boolean_name on to enable a policy boolean.
What’s happening?
SELinux enforces a mandatory access control policy on every process and file. When something gets denied, it’s usually because the file has the wrong security context (label) or the policy doesn’t allow that operation by default. I’ve seen this mostly when you copy files from a non-SELinux system (like a Docker container or a backup) — the files inherit the wrong context, or when a new service tries to bind to a high port that’s restricted. The error message you see in dmesg or /var/log/messages will say something like “SELinux is preventing httpd from open access on the file /var/www/html/index.html.” It’s frustrating, but the fix is straightforward once you know where to look.
I’ll walk you through the standard fix that works on RHEL 8/9, CentOS Stream 9, Fedora 38+, and Rocky Linux 9. If you’re on an older version like RHEL 7, the commands are the same — just make sure policycoreutils and setroubleshoot are installed.
Step-by-step fix
- Install setroubleshoot if missing. This gives you
sealert, which translates AVC denials into plain English. On RHEL/Fedora:sudo dnf install setroubleshoot setroubleshoot-server. On Debian/Ubuntu it’s rarely used — SELinux is enforcing by default only on CentOS/RHEL-family. - Check the denial in real time. Run
sudo tail -f /var/log/audit/audit.log | grep AVC. Then trigger the operation that failed (e.g., restart the service or access the file). You’ll see lines liketype=AVC msg=audit(1234567890.123:456): avc: denied { write } for pid=1234 comm="httpd" name="index.html" dev="dm-0" ino=789 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file. - Interpret the denial. The key parts:
scontext(source context — the process, herehttpd_t),tcontext(target context — the file or resource, hereuser_home_t), andtclass(file, dir, port, etc.). The denial is “httpd_t trying to write to a file labeled user_home_t.” That’s a label mismatch. - Fix the label. If the file should be served by Apache, relabel it:
sudo restorecon -v /var/www/html/index.html. If it’s a whole directory:sudo restorecon -R /var/www/html. If the file doesn’t have a default context, set one:sudo semanage fcontext -a -t httpd_sys_content_t '/var/www/html(/.*)?'thenrestorecon -R /var/www/html. Note:restoreconreads the file contexts defined bysemanage— if you haven’t set one, it won’t change anything. - If it’s a boolean. Some denials are expected and controlled by SELinux booleans. Example: Apache writing to user home directories. Instead of relabeling, toggle the boolean:
sudo setsebool -P httpd_enable_homedirs on. To find the right boolean, runsudo sealert -a /var/log/audit/audit.log— it will suggest the boolean name. - If it’s a port. Binding to a non-standard port?
sudo semanage port -a -t http_port_t -p tcp 8080to add it. - Test the fix. Retry the operation. If it works, you’re done. If not, check
audit.logagain — sometimes one denial hides another.
Alternative fixes if the main one fails
Method 1: Disable SELinux temporarily — only as a test. sudo setenforce 0. If the operation works now, it’s definitely SELinux. Run setenforce 1 to re-enable. Never leave it disabled in production.
Method 2: Use audit2allow to create a custom policy module. This is for rare cases where no boolean or label fix exists. Example: sudo grep AVC /var/log/audit/audit.log | audit2allow -M mycustommodule then sudo semodule -i mycustommodule.pp. But be careful — this can create a permissive rule. I’ve seen people use this as a crutch instead of fixing the actual label.
Method 3: Check if the file is on a filesystem mounted with context= or no context. If you mount an NFS or tmpfs without context=, files get a generic label. Add context=system_u:object_r:httpd_sys_content_t:s0 to the mount options in /etc/fstab and remount.
Prevention tip
Use semanage fcontext to set permanent file contexts before deploying files. For example, if you have a custom web app directory at /opt/myapp, run semanage fcontext -a -t httpd_sys_content_t '/opt/myapp(/.*)?' and then restorecon -R /opt/myapp. This way, even if you copy files again, the restorecon command will reapply the correct label. Also, enable setroubleshoot and route its alerts to your logging system — it’ll email you on denials. I set that up on every server I manage; it catches issues before users do.
Was this solution helpful?