majorwiki/05-troubleshooting/selinux-dovecot-vmail-context.md
Marcus Summers 110a6d49e5 wiki: add inbound spam filtering guide (spamass-milter + SpamAssassin Bayes)
New 02-selfhosting/services article: the full Postfix/Dovecot inbound spam stack
on Fedora — spamass-milter tag-only wiring (the -r footgun), socket permissions
(sa-milt group + UMask), site-wide Bayes DB, Sieve-to-Junk, and sa-learn training
(folders, spam/ham balance, manual-not-cron). From the majormail setup.

Also extends selinux-dovecot-vmail-context with a Permissive-mode variant + a
postfix_cleanup->mysqld_etc companion-denial note. SUMMARY.md nav updated.
2026-06-04 16:31:14 -04:00

135 lines
5.5 KiB
Markdown

---
title: "SELinux: Fixing Dovecot Mail Spool Context (/var/vmail)"
domain: troubleshooting
category: general
tags: [selinux, dovecot, mail, fedora, vmail]
status: published
created: 2026-04-02
updated: 2026-04-02
---
# SELinux: Fixing Dovecot Mail Spool Context (/var/vmail)
If Dovecot is generating SELinux AVC denials and mail delivery or retrieval is broken on a Fedora/RHEL system with SELinux enforcing, the `/var/vmail` directory tree likely has incorrect file contexts.
## Symptoms
- Thousands of AVC denials in `/var/log/audit/audit.log` for Dovecot processes
- Denials reference `var_t` context on files under `/var/vmail/`
- Mail delivery may fail silently; IMAP folders may appear empty or inaccessible
- `ausearch -m avc -ts recent` shows denials like:
```
type=AVC msg=audit(...): avc: denied { write } for pid=... comm="dovecot" name="..." scontext=system_u:system_r:dovecot_t:s0 tcontext=system_u:object_r:var_t:s0
```
## Why It Happens
SELinux requires files to have the correct security context for the process that accesses them. When Postfix/Dovecot are installed on a fresh system and `/var/vmail` is created manually (or by the mail stack installer), the directory may inherit the default `var_t` context from `/var/` rather than the mail-specific `mail_spool_t` context Dovecot expects.
The correct context for the entire `/var/vmail` tree is `mail_spool_t` — including the `tmp/` subdirectories inside each Maildir folder.
> [!warning] Do NOT apply `dovecot_tmp_t` to Maildir `tmp/` directories
> `dovecot_tmp_t` is for Dovecot's own process-level temp files, not for Maildir `tmp/` folders. Postfix's virtual delivery agent writes to `tmp/` when delivering new mail. Applying `dovecot_tmp_t` will block Postfix from delivering any mail, silently deferring all messages with `Permission denied`.
## Fix
### 1. Check Current Context
```bash
ls -Zd /var/vmail/
ls -Z /var/vmail/example.com/user/
ls -Zd /var/vmail/example.com/user/tmp/
```
If you see `var_t` instead of `mail_spool_t`, the contexts need to be set. If you see `dovecot_tmp_t` on `tmp/`, that needs to be corrected too.
### 2. Define the Correct File Context Rule
One rule covers everything — including `tmp/`:
```bash
sudo semanage fcontext -a -t mail_spool_t "/var/vmail(/.*)?"
```
If you previously added a `dovecot_tmp_t` rule for `tmp/` directories, remove it:
```bash
# Check for an erroneous dovecot_tmp_t rule
sudo semanage fcontext -l | grep vmail
# If you see one like "/var/vmail(/.*)*/tmp(/.*)?" with dovecot_tmp_t, delete it:
sudo semanage fcontext -d "/var/vmail(/.*)*/tmp(/.*)?"
```
### 3. Apply the Labels
```bash
sudo restorecon -Rv /var/vmail
```
This relabels all existing files. On a mail server with many users and messages, this may take a moment and will print every relabeled path.
### 4. Verify
```bash
ls -Zd /var/vmail/
ls -Zd /var/vmail/example.com/user/tmp/
```
Both should show `mail_spool_t`:
```
system_u:object_r:mail_spool_t:s0 /var/vmail/
system_u:object_r:mail_spool_t:s0 /var/vmail/example.com/user/tmp/
```
### 5. Flush Deferred Mail
If mail was queued while the context was wrong, flush it:
```bash
postqueue -f
postqueue -p # should be empty shortly
```
### 6. Check That Denials Stopped
```bash
ausearch -m avc -ts recent | grep dovecot
```
No output = no new denials.
## Variant: a Freshly-Rebuilt Box Left in Permissive Mode
If a server was rebuilt or migrated and came up **Permissive** (check `getenforce`), the symptom flips: mail works fine, but `/var/log/audit/audit.log` quietly fills with thousands of `dovecot_t → var_t` denials that *would* break IMAP/LMTP the instant you switch to Enforcing. The mailstore was created or `rsync`'d onto `/var/vmail` with no fcontext rule, so it defaulted to `var_t`.
Apply the relabel above first, then flip to Enforcing **only after** verifying zero new denials:
```bash
MARK=$(date +%H:%M:%S)
# ...deliver a test message + do an IMAP login...
ausearch -m avc -ts "$MARK" | grep -c denied # expect 0
setenforce 1
sed -i 's/^SELINUX=permissive/SELINUX=enforcing/' /etc/selinux/config
```
**Companion denial:** a Postfix virtual-mailbox server that looks up recipients in MySQL also trips `postfix_cleanup_t` reading `/etc/my.cnf*` (`mysqld_etc_t`). Allow it with a small local module:
```bash
ausearch -m avc -c cleanup | audit2allow -M local_postfix_mysql
semodule -i local_postfix_mysql.pp
```
See also [[postfix-spamassassin-bayes-spam-filtering|Inbound Spam Filtering]] — the SpamAssassin Bayes DB belongs under `/var/lib/spamassassin` (`spamd_var_lib_t`) for the same labeling reason.
## Key Notes
- **One rule is enough** — `"/var/vmail(/.*)?"` with `mail_spool_t` covers every file and directory under `/var/vmail`, including all `tmp/` subdirectories.
- **`semanage fcontext` is persistent** — the rules survive reboots and `restorecon` calls. You only need to run `semanage` once.
- **`restorecon` applies current rules to existing files** — run it after any `semanage` change and any time you manually create directories.
- **New mail directories are labeled automatically** — SELinux applies the registered `semanage` rules to any new files created under `/var/vmail`.
- **`var_t` context is the default for `/var/`** — any directory created under `/var/` without a specific `semanage` rule will inherit `var_t`. This is almost never correct for service data directories.
## Related
- [Linux Server Hardening Checklist](../02-selfhosting/security/linux-server-hardening-checklist.md)
- [Docker & Caddy Recovery After Reboot (Fedora + SELinux)](docker-caddy-selinux-post-reboot-recovery.md)