163 lines
4.6 KiB
Markdown
163 lines
4.6 KiB
Markdown
# Selinux
|
||
|
||
<https://thecybersecguru.com/tutorials/selinux-ultimate-guide/>
|
||
|
||
## Terminology
|
||
|
||
Subjects vs Objects:
|
||
|
||
- A Subject is a process (e.g., the Apache httpd process).
|
||
- An Object is the thing a subject wants to access (e.g., a file, a directory,
|
||
a network port, a system socket).
|
||
|
||
Labels (Contexts):
|
||
|
||
- Every single Subject and every single Object on an SELinux system has a
|
||
label. This label is called an SELinux Context.
|
||
- A process’s label is called a domain.
|
||
- A file’s label is called a type.
|
||
|
||
The Policy:
|
||
|
||
- The SELinux policy is just a massive database of rules that says which
|
||
domains can access which types.
|
||
- A rule might say: “Allow the domain httpd_t (the Apache process) to read
|
||
files with the type httpd_sys_content_t (web content).”
|
||
|
||
Type Enforcement (TE):
|
||
|
||
- This is the name of the engine that enforces these rules. When a Subject
|
||
(process) tries to access an Object (file), the Linux kernel’s hook for
|
||
SELinux checks their labels.
|
||
- It looks up the rule in the policy.
|
||
- If a rule allow httpd_t httpd_sys_content_t:file { read }; exists, the access
|
||
is granted.
|
||
- If no “allow” rule exists, the access is implicitly denied, and an event is
|
||
logged to /var/log/audit/audit.log.
|
||
|
||
An SELinux context is a string with four parts, separated by colons: `user:role:type:level`
|
||
|
||
- User: An SELinux user (e.g., system_u, unconfined_u). This is not the same as
|
||
your Linux user (root, john). It’s an identity within the policy.
|
||
- Role: Used in Role-Based Access Control (RBAC). (e.g., system_r, object_r).
|
||
- Level: Used in Multi-Level Security (MLS) and Multi-Category Security (MCS).
|
||
(e.g., s0, or s0:c0,c1). This is what keeps containers (Docker, Podman)
|
||
separate from each other.
|
||
- For 99% of all system administration, you can COMPLETELY IGNORE the user, role, and level.
|
||
|
||
The only part that matters for day-to-day troubleshooting is the third part:
|
||
the type. This is the real label.
|
||
|
||
- For a process (Subject), the type is its domain.
|
||
- For a file (Object), the type is its type.
|
||
|
||
## Using Selinux
|
||
|
||
```bash
|
||
# List labels
|
||
# The type is the third item in the four colon-separated values
|
||
ls -lZ /var
|
||
ls -lZ /var/log
|
||
ls -lZ .
|
||
|
||
# List processes
|
||
ps -eZ | grep -i auditd
|
||
ps -eZ | grep -i clam
|
||
ps -eZ | grep -i grep
|
||
```
|
||
|
||
### Using Selinux Booleans
|
||
|
||
When you see an "selinux denied" error you have two choices:
|
||
|
||
1. (Wrong) Write a custom policy module to allow this.
|
||
2. (Right) Check if there’s an “off” switch for this rule.
|
||
|
||
This “off” switch is called an SELinux Boolean.
|
||
|
||
Booleans are on/off toggles for common policy rules. They are the first thing
|
||
you should check when you have a denial.
|
||
|
||
Your workflow should look like:
|
||
|
||
1. Get a denial.
|
||
2. Run getsebool -a | grep service_name.
|
||
3. Read the list of booleans and find one that sounds like the action being denied.
|
||
4. Temporarily flip it with setsebool.
|
||
5. Test. If it works, make it permanent with setsebool -P.
|
||
|
||
```bash
|
||
# Get all booleans
|
||
getsebool -a
|
||
|
||
# Find one that's relevant
|
||
getsebool -a | grep -i clam
|
||
|
||
# Flip an sebool on temporarily
|
||
setsebool httpd_can_network_connect_db on
|
||
|
||
# Flip sebool on permanently
|
||
setsebool -P httpd_can_network_connect_db on
|
||
```
|
||
|
||
### Using Selinux with Audit Log
|
||
|
||
If the selinux boolean approach doesn't work.
|
||
|
||
```bash
|
||
# Make sure you have the troubleshooting package installed
|
||
sudo dnf install -y setroubleshoot-server
|
||
|
||
# List all alerts
|
||
sudo sealert -a /var/log/audit/audit.log
|
||
|
||
# If sealert doesn't have a recommendation, like restorecon, then use audit2why
|
||
# This will tell you what you should do to fix the issue
|
||
sudo grep "denied" /var/log/audit/audit.log | tail -n 1 | audit2why
|
||
|
||
# Check what rule would be created
|
||
sudo grep "antivirus_t" /var/log/audit/audit.log | audit2allow -m clamav-notifysend
|
||
|
||
# Create the .te (human readable) policy, compile it (.pp), and load it into the kernel
|
||
sudo grep "antivirus_t" /var/log/audit/audit.log | audit2allow -M clamav-notifysend
|
||
|
||
# Apply the policy
|
||
sudo semodule -X 300 -i clamav-notifysend.pp
|
||
|
||
# List active policies
|
||
sudo semodule -l
|
||
|
||
# Remove an active policy
|
||
sudo semodule -r clamav-notifysend
|
||
```
|
||
|
||
### Showing Dontaudit Rules
|
||
|
||
Selinux will hide denies that are explicitly prohibited through a rule.
|
||
|
||
```bash
|
||
# Show dontaudit rules
|
||
semodule -DB
|
||
|
||
# Hide dontaudit rules
|
||
semodule -B
|
||
```
|
||
|
||
## Compiling Modules
|
||
|
||
If you have a `te` file you can compile to a `pp` file with the following:
|
||
|
||
```bash
|
||
# Compile to module source, then to policy package
|
||
checkmodule -M -m -o sample.mod sample.te
|
||
semodule_package -o sample.pp -m sample.mod
|
||
```
|
||
|
||
## Cloning a Virtual Machine
|
||
|
||
```bash
|
||
cd active/os_fedora/selinux_policies
|
||
sudo ausearch -c 'rpc-virtstorage' --raw | audit2allow -M my-rpcvirtstorage
|
||
sudo semodule -X 300 -i my-rpcvirtstorage.pp
|
||
```
|