Sync from SUSE:ALP:Source:Standard:1.0 cockpit revision ceae2a1bfb3a5166c79a2adc4ce3fc44
This commit is contained in:
parent
9e567cd89d
commit
4b95db9a69
137
0001-users-Support-for-watching-lastlog2-and-wutmp-on-ove.patch
Normal file
137
0001-users-Support-for-watching-lastlog2-and-wutmp-on-ove.patch
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
From b95268ea4002fe7bcc7839d0bc7587c4e76306c5 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Luna <luna.dragon@suse.com>
|
||||||
|
Date: Wed, 5 Jun 2024 10:34:15 +0530
|
||||||
|
Subject: [PATCH] users: Support for watching lastlog2 and wutmp on overview
|
||||||
|
page
|
||||||
|
|
||||||
|
---
|
||||||
|
pkg/users/account-details.js | 27 ++++++++++++++++++---------
|
||||||
|
pkg/users/users.js | 22 ++++++++++++++--------
|
||||||
|
pkg/users/utils.js | 14 ++++++++++++++
|
||||||
|
3 files changed, 46 insertions(+), 17 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/pkg/users/account-details.js b/pkg/users/account-details.js
|
||||||
|
index 9edd70c41..94710912a 100644
|
||||||
|
--- a/pkg/users/account-details.js
|
||||||
|
+++ b/pkg/users/account-details.js
|
||||||
|
@@ -48,7 +48,8 @@ import { account_shell_dialog } from "./shell-dialog.js";
|
||||||
|
import { set_password_dialog, reset_password_dialog } from "./password-dialogs.js";
|
||||||
|
import { AccountLogs } from "./account-logs-panel.jsx";
|
||||||
|
import { AuthorizedKeys } from "./authorized-keys-panel.js";
|
||||||
|
-import { get_locked } from "./utils.js";
|
||||||
|
+import { get_locked, getUtmpPath } from "./utils.js";
|
||||||
|
+import { useInit } from 'hooks.js';
|
||||||
|
|
||||||
|
const _ = cockpit.gettext;
|
||||||
|
|
||||||
|
@@ -98,16 +99,24 @@ function get_expire(name) {
|
||||||
|
|
||||||
|
export function AccountDetails({ accounts, groups, current_user, user, shells }) {
|
||||||
|
const [expiration, setExpiration] = useState(null);
|
||||||
|
- useEffect(() => {
|
||||||
|
- get_expire(user).then(setExpiration);
|
||||||
|
+ const [utmppath, setUtmpPath] = useState(null);
|
||||||
|
+
|
||||||
|
+ useInit(async () => {
|
||||||
|
+ setUtmpPath(await getUtmpPath());
|
||||||
|
+ });
|
||||||
|
|
||||||
|
- // Watch `/var/run/utmp` to register when user logs in or out
|
||||||
|
- const handle = cockpit.file("/var/run/utmp", { superuser: "try", binary: true });
|
||||||
|
- handle.watch(() => {
|
||||||
|
+ useEffect(() => {
|
||||||
|
+ if (utmppath !== null) {
|
||||||
|
get_expire(user).then(setExpiration);
|
||||||
|
- });
|
||||||
|
- return handle.close;
|
||||||
|
- }, [user, accounts]);
|
||||||
|
+
|
||||||
|
+ // Watch `/var/run/utmp` to register when user logs in or out
|
||||||
|
+ const handle = cockpit.file("/var/run/utmp", { superuser: "try", binary: true });
|
||||||
|
+ handle.watch(() => {
|
||||||
|
+ get_expire(user).then(setExpiration);
|
||||||
|
+ });
|
||||||
|
+ return handle.close;
|
||||||
|
+ }
|
||||||
|
+ }, [user, accounts, utmppath]);
|
||||||
|
|
||||||
|
const [edited_real_name, set_edited_real_name] = useState(null);
|
||||||
|
const [committing_real_name, set_committing_real_name] = useState(false);
|
||||||
|
diff --git a/pkg/users/users.js b/pkg/users/users.js
|
||||||
|
index 8f35be519..ecafc3472 100755
|
||||||
|
--- a/pkg/users/users.js
|
||||||
|
+++ b/pkg/users/users.js
|
||||||
|
@@ -29,7 +29,7 @@ import { usePageLocation, useLoggedInUser, useFile, useInit } from "hooks.js";
|
||||||
|
import { etc_passwd_syntax, etc_group_syntax, etc_shells_syntax } from "pam_user_parser.js";
|
||||||
|
import { EmptyStatePanel } from "cockpit-components-empty-state.jsx";
|
||||||
|
|
||||||
|
-import { get_locked } from "./utils.js";
|
||||||
|
+import { get_locked, getUtmpPath } from "./utils.js";
|
||||||
|
import { AccountsMain } from "./accounts-list.js";
|
||||||
|
import { AccountDetails } from "./account-details.js";
|
||||||
|
|
||||||
|
@@ -86,13 +86,17 @@ function AccountsPage() {
|
||||||
|
}, [logindef]);
|
||||||
|
|
||||||
|
const [details, setDetails] = useState(null);
|
||||||
|
- useInit(() => {
|
||||||
|
+ useInit(async () => {
|
||||||
|
+ const utmppath = await getUtmpPath();
|
||||||
|
+
|
||||||
|
getLogins().then(setDetails);
|
||||||
|
|
||||||
|
// Watch `/var/run/utmp` to register when user logs in or out
|
||||||
|
- const handleUtmp = cockpit.file("/var/run/utmp", { superuser: "try", binary: true });
|
||||||
|
- handleUtmp.watch(() => getLogins().then(setDetails), { read: false });
|
||||||
|
-
|
||||||
|
+ let handleUtmp;
|
||||||
|
+ if (utmppath !== null) {
|
||||||
|
+ handleUtmp = cockpit.file("/var/run/utmp", { superuser: "try", binary: true });
|
||||||
|
+ handleUtmp.watch(() => getLogins().then(setDetails), { read: false });
|
||||||
|
+ }
|
||||||
|
// Watch /etc/shadow to register lock/unlock/expire changes; but avoid reading it, it's sensitive data
|
||||||
|
const handleShadow = cockpit.file("/etc/shadow", { superuser: "try" });
|
||||||
|
handleShadow.watch(() => getLogins().then(setDetails), { read: false });
|
||||||
|
@@ -151,12 +155,14 @@ function AccountsPage() {
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getLogins() {
|
||||||
|
- let lastlog = "";
|
||||||
|
+ let LastLogPath;
|
||||||
|
try {
|
||||||
|
- lastlog = await cockpit.spawn(["lastlog"], { environ: ["LC_ALL=C"] });
|
||||||
|
+ await cockpit.spawn(["test", "-e", "/var/lib/lastlog/lastlog2.db"], { err: "ignore" });
|
||||||
|
+ LastLogPath = "lastlog2";
|
||||||
|
} catch (err) {
|
||||||
|
- console.warn("Unexpected error when getting last login information", err);
|
||||||
|
+ LastLogPath = "lastlog";
|
||||||
|
}
|
||||||
|
+ const lastlog = await cockpit.spawn([LastLogPath], { environ: ["LC_ALL=C"] });
|
||||||
|
|
||||||
|
let currentLogins = [];
|
||||||
|
try {
|
||||||
|
diff --git a/pkg/users/utils.js b/pkg/users/utils.js
|
||||||
|
index 7b2efed05..3cbe295a5 100644
|
||||||
|
--- a/pkg/users/utils.js
|
||||||
|
+++ b/pkg/users/utils.js
|
||||||
|
@@ -8,3 +8,17 @@ export const get_locked = name =>
|
||||||
|
return status == "LK" || status == "L";
|
||||||
|
})
|
||||||
|
.catch(() => null);
|
||||||
|
+
|
||||||
|
+export async function getUtmpPath() {
|
||||||
|
+ try {
|
||||||
|
+ await cockpit.spawn(["test", "-e", "/var/run/utmp"], { err: "ignore" });
|
||||||
|
+ return "/var/run/utmp";
|
||||||
|
+ } catch (err1) {
|
||||||
|
+ try {
|
||||||
|
+ await cockpit.spawn(["test", "-e", "/var/lib/wtmpdb/wtmp.db"], { err: "ignore" });
|
||||||
|
+ return "/var/lib/wtmpdb/wtmp.db";
|
||||||
|
+ } catch (err2) {
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
--
|
||||||
|
2.45.1
|
||||||
|
|
156
CVE-2024-6126.patch
Normal file
156
CVE-2024-6126.patch
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
From 2274359df6feffc990831c7d7a32a56d9244d38a Mon Sep 17 00:00:00 2001
|
||||||
|
From: Martin Pitt <mpitt@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.perego@suse.com> for discovering,
|
||||||
|
and Luna Dragon <luna.dragon@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 | 30 +++++++++++++++++++++++
|
||||||
|
2 files changed, 67 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 f771b5f69..939d29428 100755
|
||||||
|
--- a/test/verify/check-session
|
||||||
|
+++ b/test/verify/check-session
|
||||||
|
@@ -76,6 +76,36 @@ class TestSession(testlib.MachineCase):
|
||||||
|
b.logout()
|
||||||
|
wait_session(should_exist=False)
|
||||||
|
|
||||||
|
+ # try to pwn $SSH_AGENT_PID via pam_env's user_readenv=1
|
||||||
|
+
|
||||||
|
+ if m.image in ["fedora-39", "fedora-40"]:
|
||||||
|
+ # pam_env user_readenv crashes in Fedora, skip the test
|
||||||
|
+ # https://bugzilla.redhat.com/show_bug.cgi?id=2293045
|
||||||
|
+ 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__':
|
||||||
|
testlib.test_main()
|
||||||
|
--
|
||||||
|
2.45.2
|
||||||
|
|
@ -1,3 +1,13 @@
|
|||||||
|
-------------------------------------------------------------------
|
||||||
|
Wed Jul 3 06:04:40 UTC 2024 - Luna D Dragon <luna.dragon@suse.com>
|
||||||
|
|
||||||
|
- add CVE-2024-6126.patch to resolve CVE-2024-6126
|
||||||
|
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
Wed Jun 5 05:11:19 UTC 2024 - Luna D Dragon <luna.dragon@suse.com>
|
||||||
|
|
||||||
|
- add 0001-users-Support-for-watching-lastlog2-and-wutmp-on-ove.patch to fix bsc#1220551
|
||||||
|
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
Wed Mar 13 11:26:28 UTC 2024 - Miika Alikirri <miika.alikirri@suse.com>
|
Wed Mar 13 11:26:28 UTC 2024 - Miika Alikirri <miika.alikirri@suse.com>
|
||||||
|
|
||||||
|
@ -66,11 +66,13 @@ Patch2: suse_docs.patch
|
|||||||
Patch3: suse-microos-branding.patch
|
Patch3: suse-microos-branding.patch
|
||||||
Patch4: css-overrides.patch
|
Patch4: css-overrides.patch
|
||||||
Patch5: storage-btrfs.patch
|
Patch5: storage-btrfs.patch
|
||||||
|
Patch6: 0001-users-Support-for-watching-lastlog2-and-wutmp-on-ove.patch
|
||||||
|
Patch7: CVE-2024-6126.patch
|
||||||
# SLE Micro specific patches
|
# SLE Micro specific patches
|
||||||
Patch101: hide-pcp.patch
|
Patch101: hide-pcp.patch
|
||||||
Patch102: 0002-selinux-temporary-remove-setroubleshoot-section.patch
|
Patch102: 0002-selinux-temporary-remove-setroubleshoot-section.patch
|
||||||
# For anything based on SLES 15 codebase (including Leap, SLE Micro)
|
# For anything based on SLES 15 codebase (including Leap, SLE Micro)
|
||||||
Patch103: 0004-leap-gnu18-removal.patch
|
#Patch103: 0004-leap-gnu18-removal.patch
|
||||||
Patch104: selinux_libdir.patch
|
Patch104: selinux_libdir.patch
|
||||||
|
|
||||||
%if 0%{?fedora} >= 38 || 0%{?rhel} >= 9
|
%if 0%{?fedora} >= 38 || 0%{?rhel} >= 9
|
||||||
@ -247,6 +249,8 @@ BuildRequires: python3-tox-current-env
|
|||||||
%patch3 -p1
|
%patch3 -p1
|
||||||
%patch4 -p1
|
%patch4 -p1
|
||||||
%patch5 -p1
|
%patch5 -p1
|
||||||
|
%patch6 -p1
|
||||||
|
%patch7 -p1
|
||||||
|
|
||||||
# SLE Micro specific patches
|
# SLE Micro specific patches
|
||||||
%if 0%{?is_smo}
|
%if 0%{?is_smo}
|
||||||
|
Loading…
Reference in New Issue
Block a user