https://discussion.fedoraproject.org/t/f46-change-proposal-relocate-the-selinux-policy-store-to-etc-selinux-system-wide/204918

# Summary

Move the SELinux policy store (installed modules, local customizations and the 
compiled policy) from `/var/lib/selinux` to `/etc/selinux/<policy>/active` by 
setting `store-root = /etc/selinux` in the default `semanage.conf`. This brings 
every Fedora edition, spin and atomic variant to a single layout, matches the 
location already used on ostree-based systems such as Fedora Silverblue, and 
follows the migration that openSUSE completed in 2026. Existing systems are 
migrated automatically on upgrade.

## Detailed Description

### Current location

Since the SELinux userspace release adopted in Fedora 23, the policy store 
lives under `/var/lib/selinux/<policy>/`, while the configuration 
(`/etc/selinux/config`, `semanage.conf`) and the policy-related content shipped 
by packages live under `/etc/selinux` and `/usr/share/selinux`. The policy 
store is the area that `semodule`, `semanage` and `setsebool -P` read and 
write: it holds the module set, local changes (booleans, users, ports, file 
contexts) and the linked and compiled policy.

### New location

`/etc/selinux/<policy>/active` (for example `/etc/selinux/targeted/active`), 
reached by changing `store-root` in `/etc/selinux/semanage.conf` from its 
default `/var/lib/selinux` to `/etc/selinux`. This is the layout that Fedora 
Silverblue 44 already uses: `booleans.local`, `file_contexts`, 
`file_contexts.homedirs`, `homedir_template`, `modules/`, `policy.kern`, 
`policy.linked`, `seusers` and `users_extra` all sit under 
`/etc/selinux/targeted/active`. 

### Why this is needed

`/usr` and `/etc` are the trees that atomic and snapshot-based update schemes 
capture and roll back together; `/var` holds mutable state and is deliberately 
left alone. A policy store in `/var` therefore breaks that model. After a 
rollback, the files from packages under `/usr/share/selinux` and `/etc/selinux` 
return to their earlier state while the store in `/var/lib/selinux` keeps the 
newer one. If the update added or removed types, attributes or modules, 
rebuilding the policy or installing an external module afterwards can fail, and 
the system ends up in a state that is hard to recover automatically. openSUSE 
documented exactly this failure mode, rated it very rare in practice, and still 
decided to remove it by moving the store to `/etc`.

The same reasoning drove two earlier decisions that this Change builds on:

* **Fedora 36, RPM database to /usr** (`Changes/RelocateRPMToUsr`): the RPM 
database describes mostly `/usr`, so it was moved next to it so that `/usr` can 
be rolled back as a unit without touching `/var`. The rpm-ostree variants and 
openSUSE were already doing so, and the move was applied on upgrade by a 
systemd service that relocated the data. The discussion also raised FHS 
objections, which are addressed below for this proposal.
* **openSUSE, SELinux store to /etc** (2026): the migration landed in 
Tumbleweed snapshot 20260505 after months of testing, runs automatically on 
package update, preserves local changes and custom modules, and removes the old 
`/var/lib/selinux` tree only once no snapshot still needs it.

On the atomic side, the problem was already visible in 2016: with an empty 
`/var` after a factory reset, the store in `/var/lib/selinux` was missing and 
`semanage` and `semodule` stopped working, which led to a dedicated policy 
variant that kept the store in `/etc`. Standardizing on `/etc/selinux` removes 
that special case and the divergence between variants.

### What will change

1. The default `semanage.conf` shipped by Fedora sets `store-root = 
/etc/selinux` like Atomic spins but for all the Fedora ecosystem.
2. On upgrade, a migration step moves the store from 
`/var/lib/selinux/<policy>` to `/etc/selinux/<policy>`, keeping local booleans, 
users, ports, file-context changes, custom modules at any priority and disabled 
modules, then records completion with a marker file so it runs once. It follows 
the approach used for the RPM database in Fedora 36: a one-time step during the 
offline upgrade, with scriptlets as a safety net for online upgrades.
3. The old tree is kept unused as a fallback for one release and then removed.
4. Packages that install SELinux modules or set booleans from scriptlets are 
audited, for the new location.
5. The policy is checked for the file contexts and rules that apply to the new 
paths, so `semanage` tools run in their usual domain without new denials.
6. Ostree-based variants drop whatever special-casing they carry today and use 
the same default as everyone else.

## Benefit to Fedora

* Policy and module changes roll back together with the rest of the system on 
any setup that snapshots `/usr` and `/etc`: openSUSE-style btrfs layouts with 
`/var` as a separate subvolume, LVM and device-mapper snapshots, and similar 
schemes.

* One layout across Workstation, Server, spins and the atomic variants instead 
of two. Documentation, tooling and troubleshooting become the same everywhere.

* Fixes the empty-`/var` failure on atomic systems at the source, with no 
variant-specific workaround.


Please share your thoughts on this proposal so that it can serve as an 
incentive for developers and help make this change a reality.
-- 
_______________________________________________
devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]
Fedora Code of Conduct: 
https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedoraproject.org/archives/list/[email protected]
Do not reply to spam, report it: 
https://forge.fedoraproject.org/infra/tickets/issues/new

Reply via email to