41.5 audit2allow: Generating Policy Modules from AVC Denials
Alright, let’s talk about audit2allow. You’ve just been smacked down by an SELinux AVC denial. Your first instinct might be to just flip the setenforce 0 switch and call it a day. I get it. I’ve been there. But we’re better than that. We’re going to fix this properly, and audit2allow is the power tool we use to build a custom policy module that says, “Hey, SELinux, this thing I want to happen? Let it.”
Think of audit2allow not as a magic wand, but as a very clever, slightly lazy intern. It reads the complaints SELinux logs (/var/log/audit/audit.log) and, based on the access vector denials it finds, drafts a policy module that would allow those specific actions. It does the tedious work of writing the .te file boilerplate. Your job is to be the senior engineer who reviews its work to make sure it’s not doing something catastrophically stupid.
How It Works: The Basic Two-Step
The classic, most common workflow is dead simple. First, you need to generate the denial logs. Trigger the denial again, then pipe the relevant logs into audit2allow.
# Grab the most recent denials for a specific context (e.g., httpd)
# and have audit2allow generate a Type Enforcement (.te) file for you.
sudo ausearch -m avc -c httpd | sudo audit2allow -M my_httpd_module
This does two things:
- It creates
my_httpd_module.te: a human-readable Type Enforcement policy source file. This is the most important part. You must read this file. - It compiles that
.tefile into a policy module package (.pp) and loads it withsemodule -i.
Now your application should work. Magic! Except it’s not magic, it’s a policy that now explicitly allows the thing that was just denied. The problem is, audit2allow is a blunt instrument. It sees a denial and allows it. It doesn’t know if that allowance is a minimal, safe fix or a gaping security hole. That’s on you.
The Critical Step: Reviewing the .te File
Never, ever, just blindly run audit2allow -M and load the module. That’s how you end up with policies that allow your web server to read /etc/shadow because one poorly written script tried to once. Let’s look at a hypothetical output:
# This is the content of my_httpd_module.te
module my_httpd_module 1.0;
require {
type httpd_t;
type user_home_t;
class file { read write };
}
#============= httpd_t ==============
allow httpd_t user_home_t:file { read write };
See that? It wants to let the web server process (httpd_t) read and write to files in user home directories (user_home_t). That is bonkers. It’s a massive red flag. In 99% of cases, your web app shouldn’t be anywhere near user_home_t. The real fix might be to move your web content to /var/www (labeled httpd_sys_content_t) or to create a new security context for your specific app data. audit2allow doesn’t know that; it just knows httpd_t tried to access user_home_t and got denied, so it lets it. You have to be the brains of the operation.
A Safer, More Surgical Approach
Instead of just allowing everything, a better practice is to use audit2allow to identify the problem and then craft a more precise solution. Use the -w flag to get a more verbose explanation of why the denial is happening.
sudo ausearch -m avc -c nginx | sudo audit2allow -w
This will output something like:
Was caused by:
The boolean nis_enabled was set incorrectly.
Module nginx requires this boolean to be set.
Or, you might need to create a new policy module.
Ah-ha! The fix isn’t a new module at all; it’s just turning on a boolean (setsebool -P nis_enabled on). This is why you always check.
Generating a Reference Policy (The Right Way)
If you’ve reviewed the denials and determined you truly need a custom module, generate the .te file but don’t compile it automatically. Use -o to write the .te file and then stop.
sudo ausearch -m avc -ts today | sudo audit2allow -o my_custom_module.te
Now, open my_custom_module.te in your favorite editor. Your job is to make the policy as tight and specific as possible. Maybe it doesn’t need read write, maybe it just needs getattr. Maybe the target type is wrong and you should be allowing access to a different, more specific type. This is where you earn your paycheck.
Once you’re happy with the .te file, you can compile and load it manually:
# Compile the module
sudo checkmodule -M -m -o my_custom_module.mod my_custom_module.te
# Create the package
sudo semodule_package -o my_custom_module.pp -m my_custom_module.mod
# Load it into the kernel policy
sudo semodule -i my_custom_module.pp
It’s more steps, but it’s the difference between carefully installing a deadbolt and just nailing your front door shut. Both “fix” the problem, but only one lets you sleep soundly at night. audit2allow is an incredible tool for taming SELinux, but never forget: it’s a tool, not an oracle. You are the one who has to understand what it’s doing and why.