Package: release.debian.org
Control: affects -1 + src:cockpit
X-Debbugs-Cc: Salvatore Bonaccorso <car...@debian.org>
User: release.debian....@packages.debian.org
Usertags: pu
Tags: bookworm
Severity: normal

[ Reason ]
CVE-2024-6126

[ Impact ]
Local authenticated DoS via privilege escalation: kill arbitrary process with
root privileges.

See https://cockpit-project.org/blog/cockpit-320.html for details about the
vulnerability.

[ Fix ]
https://github.com/cockpit-project/cockpit/commit/08965365ac311f906a520cbf65427742d5f84ba4

This is included in version 320, which is in unstable, testing, and
bookworm-backports now.

[ Tests ]
The patch includes an integration test which reproduces the attack scenario,
and it passes.

[ Risks ]
The patch is fairly small and easy to read, and has been tested in the field in
Debian, Ubuntu devel series, and Fedora 39/40 since last Wednesday. The worst
possible impact is that pam_ssh_add.so stops working, which would break
automatic SSH agent key preloading in Cockpit -- that's mostly a convenience
feature, the key can always be unlocked inside of Cockpit by re-entering the
password.

[ Checklist ]
  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in stable-security
  [x] the issue is verified as fixed in unstable

[ Changes ]
See attached debdiff, just a backport of the upstream patch.

[ Other info ]
Security team (Salvatore Bonaccorso <car...@debian.org>) asked for this to go
via updates, not DSA.

I already uploaded the update to the review queue.

Thanks,

Martin
diff -Nru cockpit-287.1/debian/changelog cockpit-287.1/debian/changelog
--- cockpit-287.1/debian/changelog      2024-04-16 09:20:17.000000000 +0200
+++ cockpit-287.1/debian/changelog      2024-07-05 06:15:50.000000000 +0200
@@ -1,3 +1,16 @@
+cockpit (287.1-0+deb12u3) bookworm; urgency=medium
+
+  * Add 0002-pam-ssh-add-Fix-insecure-killing-of-session-ssh-agen.patch:
+    Cockpit’s pam_ssh_add module had a vulnerability when user_readenv is
+    enabled in /etc/pam.d/cockpit (which is the default on Debian). This could
+    cause a Denial of Service if a locally-authenticated user crafted a
+    ~/.pam_environment file: it would kill an arbitrary process on the
+    system with root privileges when logging out of a Cockpit session.
+    Patch cherry-picked from upstream (08965365ac311f906a5).
+    [CVE-2024-6126]
+
+ -- Martin Pitt <mp...@debian.org>  Fri, 05 Jul 2024 06:15:50 +0200
+
 cockpit (287.1-0+deb12u2) bookworm-security; urgency=medium
 
   * Add 0001-ssh-Use-valid-host-name-in-test-sshbridge.patch:
diff -Nru 
cockpit-287.1/debian/patches/0002-pam-ssh-add-Fix-insecure-killing-of-session-ssh-agen.patch
 
cockpit-287.1/debian/patches/0002-pam-ssh-add-Fix-insecure-killing-of-session-ssh-agen.patch
--- 
cockpit-287.1/debian/patches/0002-pam-ssh-add-Fix-insecure-killing-of-session-ssh-agen.patch
        1970-01-01 01:00:00.000000000 +0100
+++ 
cockpit-287.1/debian/patches/0002-pam-ssh-add-Fix-insecure-killing-of-session-ssh-agen.patch
        2024-07-05 06:15:35.000000000 +0200
@@ -0,0 +1,158 @@
+From 08965365ac311f906a520cbf65427742d5f84ba4 Mon Sep 17 00:00:00 2001
+From: Martin Pitt <mp...@redhat.com>
+Date: Mon, 10 Jun 2024 10:49:56 +0200
+Subject: [PATCH] pam-ssh-add: Fix insecure killing of session ssh-agent
+ [CVE-2024-6126]
+
+Some distributions like Debian 12, or possibly some administrators
+enable pam_env's deprecated `user_readenv` option [1]. The user session
+can change the `$SSH_AGENT_PID`, so that it can pass an arbitrary pid to
+`pam_sm_close_session()`. This is a local authenticated DoS.
+
+Avoid this by storing the agent pid in a global variable. The
+cockpit-session process stays around for the entire session time, so we
+don't need to put the pid into the PAM data.
+
+It can also happen that the user session's ssh-agent gets killed, and
+some other process later on recycles the PID. Temporarily drop
+privileges to the target user so that we at least don't kill anyone
+else's process.
+
+Add an integration test which checks that changing the env variable
+works, pointing it to a different process doesn't kill that, and
+ssh-agent (the original pid) is still cleaned up correctly. However, as
+pam_so.env in Fedora crashes hard, skip the test there.
+
+Many thanks to Paolo Perego <paolo.per...@suse.com> for discovering,
+and Luna Dragon <luna.dra...@suse.com> for reporting this issue!
+
+[1] https://man7.org/linux/man-pages/man8/pam_env.8.html
+
+CVE-2024-6126
+https://bugzilla.redhat.com/show_bug.cgi?id=2290859
+---
+ src/pam-ssh-add/pam-ssh-add.c | 46 ++++++++++++++++++++++++++++-------
+ test/verify/check-session     | 33 +++++++++++++++++++++++++
+ 2 files changed, 70 insertions(+), 9 deletions(-)
+
+diff --git a/src/pam-ssh-add/pam-ssh-add.c b/src/pam-ssh-add/pam-ssh-add.c
+index a9159d710..839b797d2 100644
+--- a/src/pam-ssh-add/pam-ssh-add.c
++++ b/src/pam-ssh-add/pam-ssh-add.c
+@@ -54,6 +54,9 @@ const char *pam_ssh_agent_arg = NULL;
+ const char *pam_ssh_add_program = PATH_SSH_ADD;
+ const char *pam_ssh_add_arg = NULL;
+
++static unsigned long ssh_agent_pid;
++static uid_t ssh_agent_uid;
++
+ /* Environment */
+ #define ENVIRON_SIZE 5
+ #define PATH "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
+@@ -866,6 +869,25 @@ start_agent (pam_handle_t *pamh,
+           error ("couldn't set agent environment: %s",
+                  pam_strerror (pamh, res));
+         }
++
++      /* parse and store the agent pid for later cleanup */
++      if (strncmp (auth_pid, "SSH_AGENT_PID=", 14) == 0)
++        {
++          unsigned long pid = strtoul (auth_pid + 14, NULL, 10);
++          if (pid > 0 && pid != ULONG_MAX)
++            {
++              ssh_agent_pid = pid;
++              ssh_agent_uid = auth_pwd->pw_uid;
++            }
++          else
++            {
++              error ("invalid SSH_AGENT_PID value: %s", auth_pid);
++            }
++        }
++      else
++        {
++          error ("unexpected agent pid format: %s", auth_pid);
++        }
+     }
+
+   free (auth_socket);
+@@ -952,19 +974,25 @@ pam_sm_close_session (pam_handle_t *pamh,
+                       int argc,
+                       const char *argv[])
+ {
+-  const char *s_pid;
+-  int pid = 0;
+   parse_args (argc, argv);
+
+   /* Kill the ssh agent we started */
+-  s_pid = pam_getenv (pamh, "SSH_AGENT_PID");
+-  if (s_pid)
+-    pid = atoi (s_pid);
+-
+-  if (pid > 0)
++  if (ssh_agent_pid > 0)
+     {
+-      debug ("Closing %d", pid);
+-      kill (pid, SIGTERM);
++      debug ("Closing %lu", ssh_agent_pid);
++      /* kill as user to guard against crashing ssh-agent and PID reuse */
++      if (setresuid (ssh_agent_uid, ssh_agent_uid,  -1) < 0)
++        {
++          error ("could not drop privileges for killing ssh agent: %m");
++          return PAM_SESSION_ERR;
++        }
++      if (kill (ssh_agent_pid, SIGTERM) < 0 && errno != ESRCH)
++        message ("could not kill ssh agent %lu: %m", ssh_agent_pid);
++      if (setresuid (0, 0, -1) < 0)
++        {
++          error ("could not restore privileges after killing ssh agent: %m");
++          return PAM_SESSION_ERR;
++        }
+     }
+   return PAM_SUCCESS;
+ }
+diff --git a/test/verify/check-session b/test/verify/check-session
+index 56a0fc08c..21812f325 100755
+--- a/test/verify/check-session
++++ b/test/verify/check-session
+@@ -86,6 +86,39 @@ class TestSession(testlib.MachineCase):
+         b.logout()
+         wait_session(False)
+
++        # try to pwn $SSH_AGENT_PID via pam_env's user_readenv=1 
(CVE-2024-6126)
++
++        if m.image in ["fedora-39", "fedora-40", "centos-10", "rhel-10-0"]:
++            # pam_env user_readenv crashes in Fedora/RHEL 10, skip the test
++            # https://bugzilla.redhat.com/show_bug.cgi?id=2293045
++            return
++        if m.ostree_image:
++            # not using cockpit's PAM config
++            return
++
++        # this is enabled by default in tools/cockpit.debian.pam, as well as
++        # Debian/Ubuntu's /etc/pam.d/sshd; but not in Fedora/RHEL
++        if "debian" not in m.image and "ubuntu" not in m.image:
++            self.write_file("/etc/pam.d/cockpit", "session required 
pam_env.so user_readenv=1\n", append=True)
++        victim_pid = m.spawn("sleep infinity", "sleep.log")
++        self.addCleanup(m.execute, f"kill {victim_pid} || true")
++        self.write_file("/home/admin/.pam_environment", 
f"SSH_AGENT_PID={victim_pid}\n", owner="admin")
++
++        b.login_and_go()
++        wait_session(should_exist=True)
++        # starts ssh-agent in session
++        m.execute("pgrep -u admin ssh-agent")
++        # but the session has the modified SSH_AGENT_PID
++        bridge = m.execute("pgrep -u admin cockpit-bridge").strip()
++        agent = m.execute(f"grep --null-data SSH_AGENT_PID 
/proc/{bridge}/environ | xargs -0 | sed 's/.*=//'").strip()
++        self.assertEqual(agent, str(victim_pid))
++
++        # logging out still kills the actual ssh-agent, not the victim pid
++        b.logout()
++        wait_session(should_exist=False)
++        m.execute("while pgrep -u admin ssh-agent; do sleep 1; done", 
timeout=10)
++        m.execute(f"test -e /proc/{victim_pid}")
++
+
+ if __name__ == '__main__':
+     test_main()
+--
+2.45.2
diff -Nru cockpit-287.1/debian/patches/series 
cockpit-287.1/debian/patches/series
--- cockpit-287.1/debian/patches/series 2024-04-16 09:20:00.000000000 +0200
+++ cockpit-287.1/debian/patches/series 2024-07-05 06:11:56.000000000 +0200
@@ -1 +1,2 @@
 0001-ssh-Use-valid-host-name-in-test-sshbridge.patch
+0002-pam-ssh-add-Fix-insecure-killing-of-session-ssh-agen.patch

Reply via email to