Place pam_selinux Safely in a PAM Session Stack
You will finish with a PAM session configuration that lets pam_selinux set the SELinux context for the next process and restore the earlier context when the session closes. The examples match the installed Linux-PAM package, version 1.5.3-5ubuntu5.7, whose module is at /lib/x86_64-linux-gnu/security/pam_selinux.so.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow 15 to 20 minutes. You need root access, a second login path that you have already tested, and an SELinux policy that is appropriate for the service. This module is a session module only. It does not enable SELinux, install policy, or choose a policy for you.
Safety boundary
A malformed PAM file can prevent logins, including administrative logins. Keep an existing root shell or console open while testing. Do not close your last known-good session until the new session has been verified.
1. Check the module and the service file
PAM reads service-specific files from /etc/pam.d/. The filename is the service name, such as login or sshd. Start by checking the module and identifying the service you intend to change:
$ dpkg-query -W -f='${Package} ${Version}\n' libpam-modules:amd64
libpam-modules:amd64 1.5.3-5ubuntu5.7
$ test -r /lib/x86_64-linux-gnu/security/pam_selinux.so && echo 'pam_selinux is installed'
pam_selinux is installed
$ sudo sed -n '1,220p' /etc/pam.d/LOGIN_SERVICE
Replace LOGIN_SERVICE with a real service name, for example login or sshd. The first command is ordinary user work. Reading a root-owned service file may require sudo.
Checkpoint: stop if the module is absent, if you do not have a recovery login, or if you cannot identify which service starts the session you want to label. Installing packages or enabling SELinux is a separate change with its own rollback plan.
2. Understand what open and close do
On session open, the module prepares the execution context used by the next execve call. It also sets the context used for the controlling terminal and for a new kernel keyring. On session close, it restores the contexts that were in effect before the module changed them.
Use both phases for a complete session lifecycle:
session ... pam_selinux.so close
session ... pam_selinux.so open
The order is not cosmetic. The module documentation recommends placing open after PAM modules that execute applications, and close before those modules. This avoids another module running with an unintended context. On an Ubuntu system with the stock configuration, the SELinux close rule is deliberately near the start of the session stack and the open rule appears later, before the user-session work that follows it.
The module only provides the session type. Do not add it as an auth, account or password rule.
3. Back up the PAM file before editing
This is the one state-changing step in the guide. In the root shell that you will keep open, make a timestamped copy of the exact service file:
$ service=LOGIN_SERVICE
$ sudo cp --preserve=mode,ownership "/etc/pam.d/$service" "/etc/pam.d/$service.before-pam-selinux"
$ sudo ls -l "/etc/pam.d/$service" "/etc/pam.d/$service.before-pam-selinux"
Replace LOGIN_SERVICE before running this. The backup is a recovery file, not a second PAM service file that PAM will load. Keep it until the session test passes.
To undo this guide after a failed edit, restore the backup from the still-open root shell:
$ sudo cp --preserve=mode,ownership "/etc/pam.d/$service.before-pam-selinux" "/etc/pam.d/$service"
Do not delete the backup while you are still testing. Restoring a PAM file is safer than trying to repair several experimental lines from memory.
4. Add the two session rules
Edit only the target service file and preserve its existing control policy. A minimal module entry can use optional, as shown in the installed manual's example:
session optional pam_selinux.so close
session optional pam_selinux.so open
That example shows module syntax, not a universal placement recommendation. In a real distribution file, copy the surrounding style and place the rules according to the session ordering described above. Existing files may use a bracketed control value so that a machine without a loaded SELinux module can ignore the rule while still treating other failures as errors. Do not replace such a control value with optional without understanding the effect on that service.
If your service already contains pam_selinux.so close and pam_selinux.so open, do not add duplicates. Check the complete file first:
$ sudo grep -n 'pam_selinux\.so' "/etc/pam.d/$service"
12:session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so close
31:session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so open
The line numbers above are illustrative output. Your service may have different numbers and control values. The useful verification is that the intended file contains one deliberate close rule and one deliberate open rule.
5. Choose context input only when you need it
With no extra option, the module uses the default context selected by the SELinux policy. That is the least surprising starting point. The module also supports these mutually exclusive ways to request a role and, when MLS is enabled, a sensitivity level:
select_contextasks the user interactively for a custom role and MLS level.env_paramsreadsSELINUX_ROLE_REQUESTEDandSELINUX_LEVEL_REQUESTEDfrom the PAM environment. IfSELINUX_USE_CURRENT_RANGEis set to1, it also requests the current range.use_current_rangeuses the current process sensitivity level and suppresses a separate sensitivity request.
Do not put select_context and env_params on the same line. The installed module reports that combination as invalid. Treat environment-controlled role selection as security-sensitive: only use it when the calling service controls that environment and your SELinux policy explicitly supports the requested transition.
6. Verify without locking yourself out
First inspect the final file and the module's presence. Then start a new session through the service you changed while keeping the old session open:
$ sudo grep -n 'pam_selinux\.so' "/etc/pam.d/$service"
$ ls -l /lib/x86_64-linux-gnu/security/pam_selinux.so
$ ssh USERNAME@HOSTNAME
Replace USERNAME and HOSTNAME with a test account and host. The SSH command is only an example. Use the actual service, and use a second terminal or console rather than replacing the shell that can restore the file.
Inside the new session, check the process context if the SELinux tools are installed:
$ id -Z
USER:ROLE:TYPE:LEVEL
The exact context is policy- and machine-specific, so do not expect the placeholder output literally. A successful login alone does not prove the intended domain transition. Compare the result with your policy's expected user context and review the service log if the session fails.
The documented module failures include an invalid or unavailable context, an unknown user, and a session error. A failed open can stop a session depending on the control value. If the test cannot log in, use the still-open recovery shell to restore the backup, then test that the service accepts sessions again before investigating policy.
7. Use debug and verbose only while investigating
Add debug only for a controlled troubleshooting run. It sends module diagnostics through syslog. Add verbose when you need the module to attempt to tell the user that a context was set:
session ... pam_selinux.so open debug verbose
These options do not repair an SELinux policy or make an invalid context valid. Remove them after the test, because routine authentication and session logs should not be made noisier than necessary.
Done means
- The installed module and package version were checked.
- The target PAM service has one intentional
closerule and one intentionalopenrule. - The rules are ordered around other session modules that may execute applications.
- Any existing bracketed control values were preserved unless their behaviour was deliberately reviewed.
- A backup remains available, and a new session was tested before the recovery shell was closed.
select_contextandenv_paramswere not combined, and custom context selection was used only with a matching SELinux policy.