Description
Display managers authenticate users through PAM services in /etc/pam.d/. A line
auth required pam_succeed_if.so user != root quiet_success at the top of the auth stack
refuses root before the password is checked. Ubuntu's GDM package ships that line in every
service; other display managers may not. The control checks the password, fingerprint and
smart card services of GDM (gdm-smartcard and its gdm-smartcard-* variants, selected
with update-alternatives since 22.04), and the login services of LightDM and SDDM, that are
present.
Automatic login services (gdm-autologin, lightdm-autologin, sddm-autologin) are not
checked: CB-UBU-DESK-006 forbids automatic login. The fix only adds the line to services
that lack it and was tested by removing the line from gdm-password; it was not tested with
LightDM or SDDM. It changes PAM, so it is disabled by default.
Rationale
A graphical session runs hundreds of processes and parses untrusted content (web pages, mail, documents). Running all of it as root turns any bug into a full compromise. Administrators should log in with their own account and elevate with sudo, which keeps their actions attributable.
Impact
root cannot log in graphically. Administrators use their own account and sudo.
Setting
| Location | /etc/pam.d/gdm-password, gdm-fingerprint, gdm-smartcard*, lightdm, sddm |
| Default | Present for GDM |
| Recommended | auth required pam_succeed_if.so user != root quiet_success |
Audit
For each of /etc/pam.d/gdm-password, gdm-fingerprint, gdm-smartcard*, lightdm and
sddm that exists, check that the auth stack contains a pam_succeed_if.so line with
user != root and a required or requisite control (or default=bad).
Automated: every check must pass. Scanners report each check by its id.
pam-root
Display manager PAM services refuse root.
script: |
re='^[[:space:]]*auth[[:space:]]+(required|requisite|\[[^]]*default=(bad|die)[^]]*\])[[:space:]]+pam_succeed_if\.so[[:space:]].*user[[:space:]]*!=[[:space:]]*root'
found=0 rc=0
for f in /etc/pam.d/gdm-password /etc/pam.d/gdm-fingerprint /etc/pam.d/gdm-smartcard* \
/etc/pam.d/lightdm /etc/pam.d/sddm; do
[ -f "$f" ] || continue
found=1
if grep -Eq "$re" "$f"; then echo "$f refuses root"; else echo "$f allows root"; rc=1; fi
done
[ "$found" = 1 ] || { echo "no display manager PAM service"; exit 2; }
exit "$rc"
Remediation
In each display manager PAM service listed by the audit that lacks it, add before the first
auth line:
auth required pam_succeed_if.so user != root quiet_success
| Restart | none |
| Disruption | low |
| Lockout risk | yes: can cut off administrative access. Off by default in generated scripts and playbooks, opt in through a tailoring file. |
Rollback
Restore the changed files of /etc/pam.d/ from the backup directory.
pam-root
# Add "auth required pam_succeed_if.so user != root quiet_success" before the first auth line of
# each display manager PAM service that lacks a root refusal.
re='^[[:space:]]*auth[[:space:]]+(required|requisite|\[[^]]*default=(bad|die)[^]]*\])[[:space:]]+pam_succeed_if\.so[[:space:]].*user[[:space:]]*!=[[:space:]]*root'
line='auth required pam_succeed_if.so user != root quiet_success'
for f in /etc/pam.d/gdm-password /etc/pam.d/gdm-fingerprint /etc/pam.d/gdm-smartcard* \
/etc/pam.d/lightdm /etc/pam.d/sddm; do
[ -f "$f" ] || continue
grep -Eq "$re" "$f" && continue
grep -Eq '^[[:space:]]*(auth[[:space:]]|@include[[:space:]]+common-auth)' "$f" || {
echo "$f has no auth line, left unchanged" >&2
continue
}
cb_backup "$f"
L=$line awk '!done && /^[ \t]*(auth[ \t]|@include[ \t]+common-auth)/ { print ENVIRON["L"]; done = 1 } { print }' \
"$f" >"$f.cirsec-tmp" && cat "$f.cirsec-tmp" >"$f"
rc=$?
rm -f "$f.cirsec-tmp"
[ "$rc" -eq 0 ] || exit 1
echo "added root refusal to $f"
done
Handwritten code reads parameters from CB_<NAME> environment variables. Each release turns these fixes into remediate.sh and an Ansible role per profile: dry run by default, a fix runs only when its check fails.
References
- pam_succeed_if(8), Ubuntu manual pages Canonical, vendor-doc, accessed 2026-10-19
- ANSSI-BP-028 v2.0 - Recommandations de configuration d'un système GNU/Linux (R33) ANSSI, guide, accessed 2026-10-19
Mappings
| Framework | ID | Relation | Note |
|---|---|---|---|
| ANSSI-BP-028 - Recommandations de configuration d'un système GNU/Linux2.0 | R33 | related | R33 asks for attributable administration; refusing graphical root sessions is one part of it. |
| NIST SP 800-53 Rev. 55.1.1 | AC-6(2) | related |
How this control relates to the other framework's: equivalent, stricter, looser, partial or related.
Threats mitigated
| Taxonomy | ID |
|---|---|
| MITRE ATT&CK | T1078.003 |
Related controls
- related
CB-UBU-DESK-006Require a password at the graphical login, without automatic login or guest session
People and lifecycle
| Authors |
|
| Verified | 2026-10-19 by Sn0wAlice on 20.04, Proxmox VM with Ubuntu Desktop (GNOME 3.36, gdm3), Ubuntu 20.04.6, kernel 5.4.0-216-generic. Check and fix tested after removing the root line from gdm-password; pamtester confirmed root refused and a normal account still authenticated after the fix. LightDM and SDDM services not tested. |
| Verified | 2026-10-19 by Sn0wAlice on 22.04, Proxmox VM with Ubuntu Desktop (GNOME 42, gdm3), Ubuntu 22.04.5, kernel 5.15.0-198-generic. Check and fix tested after removing the root line from gdm-password; pamtester confirmed root refused and a normal account still authenticated after the fix. LightDM and SDDM services not tested. |
| Verified | 2026-10-19 by Sn0wAlice on 24.04, Proxmox VM with Ubuntu Desktop (GNOME 46, gdm3), Ubuntu 24.04.5, kernel 6.8.0-147-generic. Check and fix tested after removing the root line from gdm-password; pamtester confirmed root refused and a normal account still authenticated after the fix. LightDM and SDDM services not tested. |
| Verified | 2026-10-19 by Sn0wAlice on 26.04, Proxmox VM with Ubuntu Desktop (GNOME 50, gdm3), Ubuntu 26.04.1, kernel 7.0.0-38-generic. Check and fix tested after removing the root line from gdm-password; pamtester confirmed root refused and a normal account still authenticated after the fix. LightDM and SDDM services not tested. |
| Introduced in | v0.1.0 |
| Created, updated | 2026-10-19, 2026-10-19 |
| Translations | fr |