From 984b3c0058b663c8ae40250dfe1c69ed128873439553a455166c4b5577daa4ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Schr=C3=B6ter?= Date: Wed, 5 Mar 2025 15:42:10 +0100 Subject: [PATCH] Sync from SUSE:SLFO:1.1 pam_u2f revision e3e363bb81edefdaa7b088e2a909d498 --- 0001_fix_for_CVE_2025_23013.patch | 297 ++++++++++++++++++++ 0002_soften_authfile_permission_check.patch | 36 +++ pam_u2f-1.3.0.tar.gz | 3 + pam_u2f-1.3.0.tar.gz.sig | Bin 0 -> 119 bytes pam_u2f-1.3.2.tar.gz | 3 - pam_u2f-1.3.2.tar.gz.sig | Bin 119 -> 0 bytes pam_u2f.changes | 18 +- pam_u2f.spec | 8 +- 8 files changed, 351 insertions(+), 14 deletions(-) create mode 100644 0001_fix_for_CVE_2025_23013.patch create mode 100644 0002_soften_authfile_permission_check.patch create mode 100644 pam_u2f-1.3.0.tar.gz create mode 100644 pam_u2f-1.3.0.tar.gz.sig delete mode 100644 pam_u2f-1.3.2.tar.gz delete mode 100644 pam_u2f-1.3.2.tar.gz.sig diff --git a/0001_fix_for_CVE_2025_23013.patch b/0001_fix_for_CVE_2025_23013.patch new file mode 100644 index 0000000..589311c --- /dev/null +++ b/0001_fix_for_CVE_2025_23013.patch @@ -0,0 +1,297 @@ +diff --git a/pam-u2f.c b/pam-u2f.c +index e17470d..d154ae4 100644 +--- a/pam-u2f.c ++++ b/pam-u2f.c +@@ -176,7 +176,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, + cfg_t *cfg = &cfg_st; + char buffer[BUFSIZE]; + int pgu_ret, gpn_ret; +- int retval = PAM_IGNORE; ++ int retval = PAM_ABORT; + device_t *devices = NULL; + unsigned n_devices = 0; + int openasuser = 0; +@@ -192,10 +192,10 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, + if (!cfg->origin) { + if (!cfg->sshformat) { + strcpy(buffer, DEFAULT_ORIGIN_PREFIX); +- + if (gethostname(buffer + strlen(DEFAULT_ORIGIN_PREFIX), + BUFSIZE - strlen(DEFAULT_ORIGIN_PREFIX)) == -1) { + debug_dbg(cfg, "Unable to get host name"); ++ retval = PAM_SYSTEM_ERR; + goto done; + } + } else { +@@ -205,6 +205,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, + cfg->origin = strdup(buffer); + if (!cfg->origin) { + debug_dbg(cfg, "Unable to allocate memory"); ++ retval = PAM_BUF_ERR; + goto done; + } else { + should_free_origin = 1; +@@ -217,6 +218,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, + cfg->appid = strdup(cfg->origin); + if (!cfg->appid) { + debug_dbg(cfg, "Unable to allocate memory"); ++ retval = PAM_BUF_ERR; + goto done; + } else { + should_free_appid = 1; +@@ -236,7 +238,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, + devices = calloc(cfg->max_devs, sizeof(device_t)); + if (!devices) { + debug_dbg(cfg, "Unable to allocate memory"); +- retval = PAM_IGNORE; ++ retval = PAM_BUF_ERR; + goto done; + } + +@@ -254,7 +256,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, + pw->pw_dir[0] != '/') { + debug_dbg(cfg, "Unable to retrieve credentials for user %s, (%s)", user, + strerror(errno)); +- retval = PAM_USER_UNKNOWN; ++ retval = PAM_SYSTEM_ERR; + goto done; + } + +@@ -265,7 +267,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, + if (cfg->expand && cfg->auth_file) { + if ((cfg->auth_file = expand_variables(cfg->auth_file, user)) == NULL) { + debug_dbg(cfg, "Failed to perform variable expansion"); +- retval = PAM_AUTHINFO_UNAVAIL; ++ retval = PAM_BUF_ERR; + goto done; + } + should_free_auth_file = 1; +@@ -275,7 +277,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, + char *tmp = resolve_authfile_path(cfg, pw, &openasuser); + if (tmp == NULL) { + debug_dbg(cfg, "Could not resolve authfile path"); +- retval = PAM_IGNORE; ++ retval = PAM_BUF_ERR; + goto done; + } + if (should_free_auth_file) { +@@ -294,7 +296,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, + debug_dbg(cfg, "Dropping privileges"); + if (pam_modutil_drop_priv(pamh, &privs, pw)) { + debug_dbg(cfg, "Unable to switch user to uid %i", pw->pw_uid); +- retval = PAM_IGNORE; ++ retval = PAM_SYSTEM_ERR; + goto done; + } + debug_dbg(cfg, "Switched to uid %i", pw->pw_uid); +@@ -304,33 +306,14 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, + if (openasuser) { + if (pam_modutil_regain_priv(pamh, &privs)) { + debug_dbg(cfg, "could not restore privileges"); +- retval = PAM_IGNORE; ++ retval = PAM_SYSTEM_ERR; + goto done; + } + debug_dbg(cfg, "Restored privileges"); + } + +- if (retval != 1) { +- // for nouserok; make sure errors in get_devices_from_authfile don't +- // result in valid devices +- n_devices = 0; +- } +- +- if (n_devices == 0) { +- if (cfg->nouserok) { +- debug_dbg(cfg, "Found no devices but nouserok specified. Skipping " +- "authentication"); +- retval = PAM_SUCCESS; +- goto done; +- } else if (retval != 1) { +- debug_dbg(cfg, "Unable to get devices from authentication file"); +- retval = PAM_AUTHINFO_UNAVAIL; +- goto done; +- } else { +- debug_dbg(cfg, "Found no devices. Aborting."); +- retval = PAM_AUTHINFO_UNAVAIL; +- goto done; +- } ++ if (retval != PAM_SUCCESS) { ++ goto done; + } + + // Determine the full path for authpending_file in order to emit touch request +@@ -388,14 +371,6 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, + } + } + +- if (retval != 1) { +- debug_dbg(cfg, "do_authentication returned %d", retval); +- retval = PAM_AUTH_ERR; +- goto done; +- } +- +- retval = PAM_SUCCESS; +- + done: + free_devices(devices, n_devices); + +diff --git a/util.c b/util.c +index 10476b2..4ef3dcd 100644 +--- a/util.c ++++ b/util.c +@@ -678,12 +678,9 @@ out: + int get_devices_from_authfile(const cfg_t *cfg, const char *username, + device_t *devices, unsigned *n_devs) { + +- int retval = 0; ++ int r = PAM_AUTHINFO_UNAVAIL; + int fd = -1; + struct stat st; +- struct passwd *pw = NULL, pw_s; +- char buffer[BUFSIZE]; +- int gpu_ret; + FILE *opwfile = NULL; + size_t opwfile_size; + unsigned i; +@@ -693,6 +690,9 @@ int get_devices_from_authfile(const cfg_t *cfg, const char *username, + + fd = open(cfg->auth_file, O_RDONLY | O_CLOEXEC | O_NOCTTY); + if (fd < 0) { ++ if (errno == ENOENT && cfg->nouserok) { ++ r = PAM_IGNORE; ++ } + debug_dbg(cfg, "Cannot open authentication file: %s", strerror(errno)); + goto err; + } +@@ -706,28 +706,10 @@ int get_devices_from_authfile(const cfg_t *cfg, const char *username, + debug_dbg(cfg, "Authentication file is not a regular file"); + goto err; + } +- +- if (st.st_size == 0) { +- debug_dbg(cfg, "Authentication file is empty"); +- goto err; +- } + opwfile_size = st.st_size; + +- gpu_ret = getpwuid_r(st.st_uid, &pw_s, buffer, sizeof(buffer), &pw); +- if (gpu_ret != 0 || pw == NULL) { +- debug_dbg(cfg, "Unable to retrieve credentials for uid %u, (%s)", st.st_uid, +- strerror(errno)); +- goto err; +- } +- +- if (strcmp(pw->pw_name, username) != 0 && strcmp(pw->pw_name, "root") != 0) { +- if (strcmp(username, "root") != 0) { +- debug_dbg(cfg, +- "The owner of the authentication file is neither %s nor root", +- username); +- } else { +- debug_dbg(cfg, "The owner of the authentication file is not root"); +- } ++ if (st.st_uid != 0 && st.st_uid != geteuid()) { ++ debug_dbg(cfg, "Authentication file has insecure ownership"); + goto err; + } + +@@ -740,26 +722,26 @@ int get_devices_from_authfile(const cfg_t *cfg, const char *username, + } + + if (cfg->sshformat == 0) { +- retval = parse_native_format(cfg, username, opwfile, devices, n_devs); ++ if (parse_native_format(cfg, username, opwfile, devices, n_devs) != 1) { ++ goto err; ++ } + } else { +- retval = parse_ssh_format(cfg, opwfile, opwfile_size, devices, n_devs); +- } +- +- if (retval != 1) { +- // NOTE(adma): error message is logged by the previous function +- goto err; ++ if (parse_ssh_format(cfg, opwfile, opwfile_size, devices, n_devs) != 1) { ++ goto err; ++ } + } + + debug_dbg(cfg, "Found %d device(s) for user %s", *n_devs, username); +- +- retval = 1; ++ r = PAM_SUCCESS; + + err: +- if (retval != 1) { ++ if (r != PAM_SUCCESS) { + for (i = 0; i < *n_devs; i++) { + reset_device(&devices[i]); + } + *n_devs = 0; ++ } else if (*n_devs == 0) { ++ r = cfg->nouserok ? PAM_IGNORE : PAM_USER_UNKNOWN; + } + + if (opwfile) +@@ -768,7 +750,7 @@ err: + if (fd != -1) + close(fd); + +- return retval; ++ return r; + } + + void free_devices(device_t *devices, const unsigned n_devs) { +@@ -1139,7 +1121,7 @@ int do_authentication(const cfg_t *cfg, const device_t *devices, + fido_dev_t **authlist = NULL; + int cued = 0; + int r; +- int retval = -2; ++ int retval = PAM_AUTH_ERR; + size_t ndevs = 0; + size_t ndevs_prev = 0; + unsigned i = 0; +@@ -1183,8 +1165,6 @@ int do_authentication(const cfg_t *cfg, const device_t *devices, + + i = 0; + while (i < n_devs) { +- retval = -2; +- + debug_dbg(cfg, "Attempting authentication with device number %d", i + 1); + + init_opts(&opts); /* used during authenticator discovery */ +@@ -1254,7 +1234,7 @@ int do_authentication(const cfg_t *cfg, const device_t *devices, + } + r = fido_assert_verify(assert, 0, pk.type, pk.ptr); + if (r == FIDO_OK) { +- retval = 1; ++ retval = PAM_SUCCESS; + goto out; + } + } +@@ -1379,7 +1359,7 @@ int do_manual_authentication(const cfg_t *cfg, const device_t *devices, + char *b64_challenge = NULL; + char prompt[MAX_PROMPT_LEN]; + char buf[MAX_PROMPT_LEN]; +- int retval = -2; ++ int retval = PAM_AUTH_ERR; + int n; + int r; + unsigned i = 0; +@@ -1446,8 +1426,6 @@ int do_manual_authentication(const cfg_t *cfg, const device_t *devices, + "Please pass the challenge(s) above to fido2-assert, and " + "paste the results in the prompt below."); + +- retval = -1; +- + for (i = 0; i < n_devs; ++i) { + n = snprintf(prompt, sizeof(prompt), "Response #%d: ", i + 1); + if (n <= 0 || (size_t) n >= sizeof(prompt)) { +@@ -1462,7 +1440,7 @@ int do_manual_authentication(const cfg_t *cfg, const device_t *devices, + + r = fido_assert_verify(assert[i], 0, pk[i].type, pk[i].ptr); + if (r == FIDO_OK) { +- retval = 1; ++ retval = PAM_SUCCESS; + break; + } + } diff --git a/0002_soften_authfile_permission_check.patch b/0002_soften_authfile_permission_check.patch new file mode 100644 index 0000000..de24040 --- /dev/null +++ b/0002_soften_authfile_permission_check.patch @@ -0,0 +1,36 @@ +diff --color -ruN pam_u2f-1.3.0/util.c pam_u2f-1.3.0-patched/util.c +--- pam_u2f-1.3.0/util.c 2025-01-21 15:23:47.543942428 +0100 ++++ pam_u2f-1.3.0-patched/util.c 2025-01-21 15:30:44.396946756 +0100 +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -709,8 +710,22 @@ + opwfile_size = st.st_size; + + if (st.st_uid != 0 && st.st_uid != geteuid()) { +- debug_dbg(cfg, "Authentication file has insecure ownership"); +- goto err; ++ /* XXX: attempt to prevent two messages to syslog */ ++ if (cfg->debug_file) { ++ debug_dbg(cfg, ++ "Permissions %04o for '%s' are too open. Please change the " ++ "file mode bits to 0644 or more restrictive. This may become " ++ "an error in the future!", ++ (unsigned int) st.st_mode & 0777, cfg->auth_file); ++ } ++#ifndef WITH_FUZZING ++ /* XXX: force a message to syslog, regardless of the debug level */ ++ syslog(LOG_AUTHPRIV | LOG_WARNING, ++ "warning(pam_u2f): Permissions %04o for '%s' are too open. Please " ++ "change the file mode bits to 0644 or more restrictive. This may " ++ "become an error in the future!", ++ (unsigned int) st.st_mode & 0777, cfg->auth_file); ++#endif + } + + opwfile = fdopen(fd, "r"); diff --git a/pam_u2f-1.3.0.tar.gz b/pam_u2f-1.3.0.tar.gz new file mode 100644 index 0000000..ee4b5ed --- /dev/null +++ b/pam_u2f-1.3.0.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:72360c6875485eb4df409da8f8f52b17893f05e4d998529c238814480e115220 +size 456281 diff --git a/pam_u2f-1.3.0.tar.gz.sig b/pam_u2f-1.3.0.tar.gz.sig new file mode 100644 index 0000000000000000000000000000000000000000000000000000000000000000..ac26fa1d9d7cec7456c8f62a803cdca78fe13f918da25d9a0128b76454f83fb6 GIT binary patch literal 119 zcmeAuWnmEGVvrS6WZ7K6{9klI#uDMD+%mRVo==WE*jCKSlp4lA>el6;D!M(K@sY8nS99Q1+ehbaGBTVC`RdWvpu9U_!u10O+)n4H UUb}RW^VmB#^VCVM4se-)Q=dGXk V@PN$|J>~Y75^t>1_pkZK2>|?RGu8kA diff --git a/pam_u2f.changes b/pam_u2f.changes index 7b5b30a..e823990 100644 --- a/pam_u2f.changes +++ b/pam_u2f.changes @@ -1,14 +1,14 @@ ------------------------------------------------------------------- -Fri Jan 17 11:19:20 UTC 2025 - Paolo Perego +Tue Jan 21 14:37:36 UTC 2025 - Paolo Perego -- update to 1.3.1: - * Fix incorrect usage of PAM_IGNORE (YSA-2025-01, CVE-2025-23013, bsc#1233517). - * Changed return value when nouserok is enabled and the user has no - credentials, PAM_IGNORE is used instead of PAM_SUCCESS. - * Hardened checks of authfile permissions. - * Hardened checks for nouserok. - * Improved debug messages. - * Improved documentation. +- Add 0002_soften_authfile_permission_check.patch introduced upstream to fix an + issue when authfile has flaky permissions. + +------------------------------------------------------------------- +Fri Jan 10 10:38:01 UTC 2025 - Paolo Perego + +- Fix for CVE-2025-23013 (bsc#1233517): + * Add 0001_fix_for_CVE_2025_23013.patch patch ------------------------------------------------------------------- Sat Apr 15 12:01:02 UTC 2023 - Dirk Müller diff --git a/pam_u2f.spec b/pam_u2f.spec index ff3551e..912b81f 100644 --- a/pam_u2f.spec +++ b/pam_u2f.spec @@ -1,7 +1,7 @@ # # spec file for package pam_u2f # -# Copyright (c) 2025 SUSE LLC +# Copyright (c) 2023 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -19,7 +19,7 @@ %{!?_pam_moduledir: %define _pam_moduledir /%{_lib}/security} Name: pam_u2f -Version: 1.3.2 +Version: 1.3.0 Release: 0 Summary: U2F authentication integration into PAM License: BSD-2-Clause @@ -29,6 +29,8 @@ Source0: https://developers.yubico.com/pam-u2f/Releases/%{name}-%{version Source1: https://developers.yubico.com/pam-u2f/Releases/%{name}-%{version}.tar.gz.sig Source2: baselib.conf Source99: pam_u2f.keyring +Patch0: 0001_fix_for_CVE_2025_23013.patch +Patch1: 0002_soften_authfile_permission_check.patch BuildRequires: pam-devel BuildRequires: pkgconfig BuildRequires: pkgconfig(libcrypto) @@ -41,6 +43,8 @@ authentication infrastructure. %prep %setup -q +%patch0 -p1 +%patch1 -p1 %build %configure --with-pam-dir=%{_pam_moduledir} \