Hi,
The opt-in sshd profile in profiles/apparmor/profiles/extras/usr.sbin.sshd
hardcodes Debian's /usr/lib/openssh/ for the OpenSSH 9.8+ helper binaries.
On distributions that place them elsewhere the exec is denied and no one
can log in over SSH.
Current master, lines 157-161:
/usr/lib/openssh/sshd-auth ix,
/usr/lib/openssh/sshd-session ix,
...
/usr/lib/openssh/sftp-server PUx,
Known-affected layouts:
Debian / Ubuntu /usr/lib/openssh/ <- the only one covered
openSUSE Leap 16 /usr/libexec/ssh/
Arch /usr/lib/ssh/ (issue #499)
Reproduced on openSUSE Leap 16.0, apparmor 4.1.7-160000.2.1,
openssh-server 10.5p1. /usr/lib/openssh does not exist there;
openssh-server installs
/usr/libexec/ssh/{sshd-session,sshd-auth,sftp-server}. The profile
contains no occurrence of "libexec", carries no "complain" flag (so it
loads in enforce), and has no catch-all exec rule -- line 155 is "/** r,"
which grants read, not execute.
Result:
apparmor="DENIED" operation="exec" class="file"
name="/usr/libexec/ssh/sshd-session"
requested_mask="x" denied_mask="x" fsuid=0 ouid=0
and client-side:
kex_exchange_identification: read: Connection reset by peer
sftp-server fails the same way.
Why this is worse than it first looks: AppArmor attaches a profile at
exec, so loading it does not confine the already-running sshd. An
administrator activates the profile, sees SSH still working, and concludes
it is fine. The lockout lands at the next sshd restart or reboot --
remotely, unattended, with no console.
Prior art: issue #499 "Apparmor sshd profile issues on Arch Linux"
(2025-03-16, closed 2025-03-17) reported the same class of problem for
Arch's /usr/lib/ssh/sftp-server and /usr/bin/sshd. It has no linked MR and
no commit, and master is still unfixed, so it appears to have been closed
without a code change. Issue #553 (RFC: @{bin}, @{sbin} and @{lib}) looks
like the structural fix.
Suggested minimal change -- cover the known layouts:
/usr/{lib/openssh,libexec/ssh,lib/ssh}/sshd-auth ix,
/usr/{lib/openssh,libexec/ssh,lib/ssh}/sshd-session ix,
/usr/{lib/openssh,libexec/ssh,lib/ssh}/sftp-server PUx,
That also closes the sftp-server half of #499. A tunable would be more in
keeping with commit "profiles: update the rest of the profiles to use
@{exec_path}" (2025-05-09) and with #553 -- an @{libexecdir}-style tunable
set per distribution, so this stops recurring per-profile.
SAFE REPRODUCTION -- do not simply activate the profile on a machine you
reach over SSH. Test a copy of the binary under a renamed profile instead,
so the real sshd is never confined:
# 1. isolated copy of the daemon
sudo cp -a /usr/sbin/sshd /usr/local/sbin/sshd-aatest
# 2. same profile, attachment path rewritten (2 lines only)
sed -e 's|^/usr/sbin/sshd {|/usr/local/sbin/sshd-aatest {|' \
-e 's|^\(\s*\)/usr/sbin/sshd mrix,|\1/usr/local/sbin/sshd-aatest
mrix,|' \
/usr/share/apparmor/extra-profiles/usr.sbin.sshd > /tmp/aatest.profile
sudo apparmor_parser -r /tmp/aatest.profile
# 3. run it on a verified-free port, loopback only
sudo ss -lntH 'sport = :22022' # must be empty
sudo /usr/local/sbin/sshd-aatest -p 22022 -o ListenAddress=127.0.0.1 \
-o PidFile=/tmp/aatest.pid -o LogLevel=DEBUG2 -E /tmp/aatest.log
# 4. connect and observe
ssh -p 22022 127.0.0.1
sudo ausearch -m AVC -ts recent | grep sshd-session
# 5. clean up
sudo kill "$(sudo cat /tmp/aatest.pid)"
sudo apparmor_parser -R /tmp/aatest.profile
sudo rm -f /usr/local/sbin/sshd-aatest
Confirm the connection actually reached the test daemon before drawing a
conclusion: /tmp/aatest.log should contain "rexec start in ... newsock
...". The listener does not log "Connection from"; that is sshd-session,
which never runs.
Happy to send this as a merge request instead if that is preferred -- I do
not currently have a gitlab.com account, which is why it is coming to the
list.
Regards,
James C. Owens