Home / Alt manpages / pam_selinux(8)

  • pam_selinux(8)
  • Admin command
  • linux

Slot pam_selinux Into a PAM Session Stack Safely

pam_selinux sets the SELinux context on session open and restores it on close, and getting its stack position wrong is a classic way to break logins. The examples match the installed Linux-PAM package, version 1.5.3-5ubuntu5.7, whose module lives at /lib/x86_64-linux-gnu/security/pam_selinux.so.

  • Allow: 15 to 20 minutes.
  • You need: root access, a second login path you've already tested, and an SELinux policy appropriate for the service.
  • It will not: enable SELinux, install policy, or choose a policy for you. This is a session module only.

Safety boundary

A malformed PAM file can prevent logins, including administrative ones. Keep an existing root shell or console open while testing, and 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/, one per service name (login, sshd, and so on). 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 such as login or sshd. The first command is ordinary user work; reading a root-owned service file may need sudo.

Checkpoint

Stop if the module is absent, if you have no recovery login, or if you can't identify which service starts the session you want to label. Installing packages or enabling SELinux is a separate change with its own rollback plan, not part of this one.

2. Understand what open and close do

On session open, the module prepares the execution context used by the next execve call, and also sets the context used for the controlling terminal and a new kernel keyring. On session close, it restores whatever contexts were in effect before it 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 any PAM modules that execute applications, and close before them, which avoids another module running with an unintended context. On a stock Ubuntu configuration, the SELinux close rule sits deliberately near the start of the session stack and open 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, it simply won't do anything useful there.

3. Back up the PAM file before editing

This is the one state-changing step in the guide. In the root shell you're keeping 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 ever load, so keep it until the session test passes.

Recovery

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're still testing. Restoring a PAM file is safer than trying to reconstruct 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 entry can use optional, as shown in the installed manual's own example:

session  optional  pam_selinux.so close
session  optional  pam_selinux.so open

That's syntax, not a universal placement recommendation. In a real distribution file, copy the surrounding style and place the rules according to the session ordering above. Existing files may use a bracketed control value so a machine without a loaded SELinux module can ignore the rule while still treating other failures as errors, don't replace such a value with optional without understanding what you'd change.

If your service already has both lines, don't add duplicates. Check the whole 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; yours will differ. What matters is that the file ends up with one deliberate close rule and one deliberate open rule, not two of either.

5. Choose context input only when you need it

With no extra option, the module uses the default context selected by the SELinux policy, which is the least surprising starting point. Three mutually exclusive options ask for something different:

  • select_context asks the user interactively for a custom role and, when MLS is enabled, an MLS level.
  • env_params reads SELINUX_ROLE_REQUESTED and SELINUX_LEVEL_REQUESTED from the PAM environment. Set SELINUX_USE_CURRENT_RANGE to 1 and it also requests the current range.
  • use_current_range uses the current process sensitivity level and suppresses a separate sensitivity request.

Warning

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 changed service 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 a second terminal or console rather than the shell that can still 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, don't expect that placeholder output literally. A successful login alone doesn't prove the intended domain transition happened, so compare the result with your policy's expected user context and check the service log if the session fails.

Recovery

Documented module failures include an invalid or unavailable context, an unknown user, and a session error, and a failed open can stop a session depending on the control value. If the test can't log in, use the still-open recovery shell to restore the backup, then confirm the service accepts sessions again before investigating policy further.

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 try telling the user that a context was set:

session  ...  pam_selinux.so open debug verbose

Neither option repairs an SELinux policy or makes an invalid context valid. Remove them after the test: routine authentication and session logs shouldn't be any noisier than they need to be.

Done means

  • Module confirmed. The installed module and package version were checked.
  • Rules paired. The target PAM service has exactly one intentional close rule and one intentional open rule.
  • Ordering respected. The rules are placed around other session modules that may execute applications.
  • Control values preserved. Any existing bracketed control values stayed as they were unless their behaviour was deliberately reviewed.
  • Backup verified before use. A backup remains available, and a new session was tested before the recovery shell was closed.
  • Context options used correctly. select_context and env_params were never combined, and custom context selection was used only with a matching SELinux policy.