SHA256
8
0
forked from pool/pam

1 Commits

Author SHA256 Message Date
val4oss
c54daa98ec CVE-2024-10041: vulnerable to read hashed password
- Make sure that the buffer containing encrypted passwords get's erased,
  before free.
  [pam_modutil_get-overwrite-password-at-free.patch, bsc#1232234,
   CVE-2024-10041]

Signed-off-by: vlefebvre <valentin.lefebvre@suse.com>
2025-10-21 10:56:29 +02:00
5 changed files with 163 additions and 1608 deletions

View File

@@ -1,17 +1,3 @@
-------------------------------------------------------------------
Mon Sep 15 07:53:29 UTC 2025 - Valentin Lefebvre <valentin.lefebvre@suse.com>
- pam_mkhomedir: building with vendordir option allows fetching skeleton
directory from the vendor directory when creating the user home directory.
[+ pam_mkhomedir-Use-vendordir-when-defined.patch, bsc#1245524]
-------------------------------------------------------------------
Wed Aug 27 14:20:14 UTC 2025 - Thorsten Kukuk <kukuk@suse.com>
- Update to 1.7.1+git (post-v1.7.1.patch)
- disable unix_chkpwd by default, only used as fallback again
- pam_modutil_get-overwrite-password-at-free.patch is included
-------------------------------------------------------------------
Tue Aug 19 10:12:13 UTC 2025 - Valentin Lefebvre <valentin.lefebvre@suse.com>

View File

@@ -93,10 +93,7 @@ Source22: postlogin-account.pamd
Source23: postlogin-password.pamd
Source24: postlogin-session.pamd
Patch1: pam-limit-nproc.patch
# PATCH-FIX-UPSTREAM
Patch2: post-v1.7.1.patch
# PATCH-FIX-UPSTREAM
Patch3: pam_mkhomedir-Use-vendordir-when-defined.patch
Patch2: pam_modutil_get-overwrite-password-at-free.patch
BuildRequires: audit-devel
BuildRequires: bison
BuildRequires: flex
@@ -219,7 +216,6 @@ CFLAGS="$CFLAGS -fpatchable-function-entry=16,14 -fdump-ipa-clones"
-Dhtmldir=%{_docdir}/pam/html \
-Dpdfdir=%{_docdir}/pam/pdf \
-Dsecuredir=%{_pam_moduledir} \
-Dpam_unix-try-getspnam=true \
%if "%{flavor}" != "full"
-Dlogind=disabled \
-Dpam_userdb=disabled \
@@ -227,7 +223,6 @@ CFLAGS="$CFLAGS -fpatchable-function-entry=16,14 -fdump-ipa-clones"
%else
-Dlogind=enabled \
%endif
-Dpwaccess=disabled \
-Delogind=disabled \
-Dexamples=false \
-Dnis=disabled

View File

@@ -1,315 +0,0 @@
From c4a53492e1b7aebcf7a65a778d9e3a78f196d117 Mon Sep 17 00:00:00 2001
From: vlefebvre <valentin.lefebvre@suse.com>
Date: Tue, 15 Jul 2025 15:42:50 +0200
Subject: [PATCH] pam_mkhomedir: Use vendordir when defined
* When the configuration is split between /etc and vendordir,
pam_mkhomedir now takes care of the distribution-provided
skeleton directory.
* mkhomedir_helper gets a new optional argument: vendordir.
If specified, the home directory will be populated by contents of
the directory specified by skeldir argument, followed by contents
of the directory specified by vendordir argument.
Signed-off-by: vlefebvre <valentin.lefebvre@suse.com>
---
modules/pam_mkhomedir/mkhomedir_helper.8.xml | 12 ++-
modules/pam_mkhomedir/mkhomedir_helper.c | 91 +++++++++++++-------
modules/pam_mkhomedir/pam_mkhomedir.8.xml | 8 +-
modules/pam_mkhomedir/pam_mkhomedir.c | 14 ++-
4 files changed, 88 insertions(+), 37 deletions(-)
diff --git a/modules/pam_mkhomedir/mkhomedir_helper.8.xml b/modules/pam_mkhomedir/mkhomedir_helper.8.xml
index 0f4c4b40..87b83a40 100644
--- a/modules/pam_mkhomedir/mkhomedir_helper.8.xml
+++ b/modules/pam_mkhomedir/mkhomedir_helper.8.xml
@@ -24,6 +24,9 @@
<replaceable>path-to-skel</replaceable>
<arg choice="opt" rep="norepeat">
<replaceable>home_mode</replaceable>
+ <arg choice="opt" rep="norepeat">
+ <replaceable>path-to-vendor-skel</replaceable>
+ </arg>
</arg>
</arg>
</arg>
@@ -48,6 +51,13 @@
<replaceable>umask</replaceable>.
</para>
+ <para>
+ <replaceable>path-to-vendor-skel</replaceable> doesn't have default
+ value. When set to a <emphasis>path</emphasis>, home directory will be
+ populated by contents of <replaceable>path-to-skel</replaceable> first,
+ and then by contents of <emphasis>path</emphasis>.
+ </para>
+
<para>
The helper is separated from the module to not require direct access from
login SELinux domains to the contents of user home directories. The
@@ -77,4 +87,4 @@
</para>
</refsect1>
-</refentry>
\ No newline at end of file
+</refentry>
diff --git a/modules/pam_mkhomedir/mkhomedir_helper.c b/modules/pam_mkhomedir/mkhomedir_helper.c
index 0c05ee9c..1d741c5d 100644
--- a/modules/pam_mkhomedir/mkhomedir_helper.c
+++ b/modules/pam_mkhomedir/mkhomedir_helper.c
@@ -36,7 +36,7 @@ static unsigned long u_mask = 0022;
static const char *skeldir = "/etc/skel";
static int create_homedir(struct dir_spec *, const struct passwd *, mode_t,
- const char *, const char *);
+ const char *, const char *, const char *);
static int
dir_spec_open(struct dir_spec *spec, const char *path)
@@ -88,7 +88,7 @@ dir_spec_close(struct dir_spec *spec)
static int
copy_entry(struct dir_spec *parent, const struct passwd *pwd, mode_t dir_mode,
- const char *source, struct dirent *dent)
+ const char *source, struct dirent *dent, const char *vendordir)
{
char remark[BUFSIZ];
int srcfd = -1, destfd = -1;
@@ -96,6 +96,7 @@ copy_entry(struct dir_spec *parent, const struct passwd *pwd, mode_t dir_mode,
int retval = PAM_SESSION_ERR;
struct stat st;
char *newsource;
+ char *newvendordir = NULL;
/* Determine what kind of file it is. */
if ((newsource = pam_asprintf("%s/%s", source, dent->d_name)) == NULL)
@@ -114,8 +115,23 @@ copy_entry(struct dir_spec *parent, const struct passwd *pwd, mode_t dir_mode,
/* If it's a directory, recurse. */
if (S_ISDIR(st.st_mode))
{
+ if (vendordir != NULL)
+ {
+ if ((newvendordir = pam_asprintf("%s/%s", vendordir, dent->d_name)) == NULL)
+ {
+ pam_syslog(NULL, LOG_CRIT, "asprintf failed for 'newvendordir'");
+ retval = PAM_BUF_ERR;
+ goto go_out;
+ }
+ if (lstat(newvendordir, &st) != 0)
+ {
+ free(newvendordir);
+ newvendordir = NULL;
+ }
+ }
+
retval = create_homedir(parent, pwd, dir_mode & (~u_mask), newsource,
- dent->d_name);
+ dent->d_name, newvendordir);
goto go_out;
}
@@ -259,19 +275,22 @@ copy_entry(struct dir_spec *parent, const struct passwd *pwd, mode_t dir_mode,
close(destfd);
free(newsource);
-
+ free(newvendordir);
return retval;
}
/* Do the actual work of creating a home dir */
static int
create_homedir(struct dir_spec *parent, const struct passwd *pwd,
- mode_t dir_mode, const char *source, const char *dest)
+ mode_t dir_mode, const char *source, const char *dest,
+ const char *vendordir)
{
DIR *d = NULL;
struct dirent *dent;
struct dir_spec base;
int retval = PAM_SESSION_ERR;
+ const char *sourcedirs[] = {source, vendordir};
+ unsigned int idx = 0;
/* Create the new directory */
if (mkdirat(parent->fd, dest, 0700))
@@ -289,32 +308,35 @@ create_homedir(struct dir_spec *parent, const struct passwd *pwd,
goto go_out;
}
- /* See if we need to copy the skel dir over. */
- if ((source == NULL) || (strlen(source) == 0))
- {
- retval = PAM_SUCCESS;
- goto go_out;
- }
-
- /* Scan the directory */
- d = opendir(source);
- if (d == NULL)
- {
- pam_syslog(NULL, LOG_DEBUG, "unable to read directory %s: %m", source);
- retval = PAM_PERM_DENIED;
- goto go_out;
- }
-
- for (dent = readdir(d); dent != NULL; dent = readdir(d))
+ /* Scan source directories */
+ for (idx = 0; idx < PAM_ARRAY_SIZE(sourcedirs); idx++)
{
- /* Skip some files.. */
- if (strcmp(dent->d_name,".") == 0 ||
- strcmp(dent->d_name,"..") == 0)
- continue;
+ /* See if we need to copy the source skel dir over. */
+ if ((sourcedirs[idx] == NULL) || strlen(sourcedirs[idx]) == 0)
+ continue;
+ d = opendir(sourcedirs[idx]);
+ if (d == NULL)
+ {
+ pam_syslog(NULL, LOG_DEBUG, "unable to read directory %s: %m",
+ sourcedirs[idx]);
+ retval = PAM_PERM_DENIED;
+ goto go_out;
+ }
- retval = copy_entry(&base, pwd, dir_mode, source, dent);
- if (retval != PAM_SUCCESS)
- goto go_out;
+ for (dent = readdir(d); dent != NULL; dent = readdir(d))
+ {
+ /* Skip some files.. */
+ if (strcmp(dent->d_name,".") == 0 ||
+ strcmp(dent->d_name,"..") == 0)
+ continue;
+
+ retval = copy_entry(&base, pwd, dir_mode, sourcedirs[idx], dent,
+ sourcedirs[idx] == vendordir ? NULL : vendordir);
+ if (retval != PAM_SUCCESS)
+ goto go_out;
+ }
+ closedir(d);
+ d = NULL;
}
retval = PAM_SUCCESS;
@@ -340,7 +362,8 @@ create_homedir(struct dir_spec *parent, const struct passwd *pwd,
static int
create_homedir_helper(const struct passwd *_pwd, mode_t home_mode,
- const char *_skeldir, const char *_homedir)
+ const char *_skeldir, const char *_homedir,
+ const char *_vendordir)
{
int retval = PAM_SESSION_ERR;
struct dir_spec base;
@@ -357,7 +380,7 @@ create_homedir_helper(const struct passwd *_pwd, mode_t home_mode,
}
*cp = '/';
- retval = create_homedir(&base, _pwd, home_mode, _skeldir, cp + 1);
+ retval = create_homedir(&base, _pwd, home_mode, _skeldir, cp + 1, _vendordir);
go_out:
dir_spec_close(&base);
@@ -399,6 +422,7 @@ main(int argc, char *argv[])
struct stat st;
char *eptr;
unsigned long home_mode = 0;
+ const char *vendordir = NULL;
if (argc < 2) {
fprintf(stderr, "Usage: %s <username> [<umask> [<skeldir> [<home_mode>]]]\n", argv[0]);
@@ -433,6 +457,9 @@ main(int argc, char *argv[])
}
}
+ if (argc >= 6)
+ vendordir = argv[5];
+
if (home_mode == 0)
home_mode = 0777 & ~u_mask;
@@ -449,5 +476,5 @@ main(int argc, char *argv[])
if (make_parent_dirs(pwd->pw_dir, 0) != PAM_SUCCESS)
return PAM_PERM_DENIED;
- return create_homedir_helper(pwd, home_mode, skeldir, pwd->pw_dir);
+ return create_homedir_helper(pwd, home_mode, skeldir, pwd->pw_dir, vendordir);
}
diff --git a/modules/pam_mkhomedir/pam_mkhomedir.8.xml b/modules/pam_mkhomedir/pam_mkhomedir.8.xml
index ad957248..42f42c58 100644
--- a/modules/pam_mkhomedir/pam_mkhomedir.8.xml
+++ b/modules/pam_mkhomedir/pam_mkhomedir.8.xml
@@ -46,6 +46,12 @@
<filename>/etc/skel/</filename>) is used to copy default files
and also sets a umask for the creation.
</para>
+
+ <para condition="with_vendordir">
+ <emphasis>%vendordir%/skel</emphasis> will also be used unless
+ <replaceable>skel</replaceable> option is specified.
+ </para>
+
<para>
The new users home directory will not be removed after logout
of the user.
@@ -213,4 +219,4 @@
pam_mkhomedir was written by Jason Gunthorpe &lt;jgg@debian.org&gt;.
</para>
</refsect1>
-</refentry>
\ No newline at end of file
+</refentry>
diff --git a/modules/pam_mkhomedir/pam_mkhomedir.c b/modules/pam_mkhomedir/pam_mkhomedir.c
index f090deee..5b08b6fd 100644
--- a/modules/pam_mkhomedir/pam_mkhomedir.c
+++ b/modules/pam_mkhomedir/pam_mkhomedir.c
@@ -60,6 +60,11 @@
#define LOGIN_DEFS "/etc/login.defs"
#define UMASK_DEFAULT "0022"
+#define SKELDIR "/etc/skel"
+#ifdef VENDORDIR
+#define VENDOR_SKELDIR (VENDORDIR "/skel")
+#endif
+
struct options_t {
int ctrl;
const char *umask;
@@ -73,7 +78,7 @@ _pam_parse (const pam_handle_t *pamh, int flags, int argc, const char **argv,
{
opt->ctrl = 0;
opt->umask = NULL;
- opt->skeldir = "/etc/skel";
+ opt->skeldir = NULL;
/* does the application require quiet? */
if ((flags & PAM_SILENT) == PAM_SILENT)
@@ -154,7 +159,7 @@ create_homedir (pam_handle_t *pamh, options_t *opt,
child = fork();
if (child == 0) {
static char *envp[] = { NULL };
- const char *args[] = { NULL, NULL, NULL, NULL, NULL, NULL };
+ const char *args[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
if (pam_modutil_sanitize_helper_fds(pamh, PAM_MODUTIL_PIPE_FD,
PAM_MODUTIL_PIPE_FD,
@@ -165,8 +170,11 @@ create_homedir (pam_handle_t *pamh, options_t *opt,
args[0] = MKHOMEDIR_HELPER;
args[1] = user;
args[2] = opt->umask ? opt->umask : UMASK_DEFAULT;
- args[3] = opt->skeldir;
+ args[3] = opt->skeldir ? opt->skeldir : SKELDIR;
args[4] = login_homemode;
+#ifdef VENDORDIR
+ args[5] = opt->skeldir ? NULL : VENDOR_SKELDIR;
+#endif
DIAG_PUSH_IGNORE_CAST_QUAL;
execve(MKHOMEDIR_HELPER, (char **)args, envp);
--
2.51.0

View File

@@ -0,0 +1,162 @@
From e2fdc55d9d8d277c9395f96c3bf2938bacc84f62 Mon Sep 17 00:00:00 2001
From: Thorsten Kukuk <kukuk@suse.com>
Date: Thu, 14 Aug 2025 12:01:25 +0200
Subject: [PATCH] pam_modutil_get*: overwrite password at free (#846)
Make sure that the buffer containing encrypted passwords (struct group,
passwd and shadow) get's erased before free, so that they are not
available anymore if the memory get allocated again.
---
libpam/pam_modutil_cleanup.c | 40 +++++++++++++++++++++++++++++++++++
libpam/pam_modutil_getgrgid.c | 2 +-
libpam/pam_modutil_getgrnam.c | 2 +-
libpam/pam_modutil_getpwnam.c | 2 +-
libpam/pam_modutil_getpwuid.c | 2 +-
libpam/pam_modutil_getspnam.c | 2 +-
libpam/pam_modutil_private.h | 9 ++++++++
7 files changed, 54 insertions(+), 5 deletions(-)
diff --git a/libpam/pam_modutil_cleanup.c b/libpam/pam_modutil_cleanup.c
index 2077cbd7..46233736 100644
--- a/libpam/pam_modutil_cleanup.c
+++ b/libpam/pam_modutil_cleanup.c
@@ -5,8 +5,12 @@
*/
#include "pam_modutil_private.h"
+#include "pam_inline.h"
+#include <grp.h>
+#include <pwd.h>
#include <stdlib.h>
+#include <shadow.h>
void
pam_modutil_cleanup (pam_handle_t *pamh UNUSED, void *data,
@@ -15,3 +19,39 @@ pam_modutil_cleanup (pam_handle_t *pamh UNUSED, void *data,
/* junk it */
free(data);
}
+
+void
+pam_modutil_cleanup_group (pam_handle_t *pamh UNUSED, void *data,
+ int error_status UNUSED)
+{
+ struct group *gr = data;
+
+ if (gr && gr->gr_passwd)
+ pam_overwrite_string(gr->gr_passwd);
+
+ free(data);
+}
+
+void
+pam_modutil_cleanup_passwd (pam_handle_t *pamh UNUSED, void *data,
+ int error_status UNUSED)
+{
+ struct passwd *pw = data;
+
+ if (pw && pw->pw_passwd)
+ pam_overwrite_string(pw->pw_passwd);
+
+ free(data);
+}
+
+void
+pam_modutil_cleanup_shadow (pam_handle_t *pamh UNUSED, void *data,
+ int error_status UNUSED)
+{
+ struct spwd *sp = data;
+
+ if (sp && sp->sp_pwdp)
+ pam_overwrite_string(sp->sp_pwdp);
+
+ free(data);
+}
diff --git a/libpam/pam_modutil_getgrgid.c b/libpam/pam_modutil_getgrgid.c
index 6c2bb31b..fa3436c5 100644
--- a/libpam/pam_modutil_getgrgid.c
+++ b/libpam/pam_modutil_getgrgid.c
@@ -62,7 +62,7 @@ pam_modutil_getgrgid(pam_handle_t *pamh, gid_t gid)
status = PAM_NO_MODULE_DATA;
if (pam_get_data(pamh, data_name, &ignore) != PAM_SUCCESS) {
status = pam_set_data(pamh, data_name,
- result, pam_modutil_cleanup);
+ result, pam_modutil_cleanup_group);
}
free(data_name);
if (status == PAM_SUCCESS) {
diff --git a/libpam/pam_modutil_getgrnam.c b/libpam/pam_modutil_getgrnam.c
index 418b9e47..533a8ce6 100644
--- a/libpam/pam_modutil_getgrnam.c
+++ b/libpam/pam_modutil_getgrnam.c
@@ -62,7 +62,7 @@ pam_modutil_getgrnam(pam_handle_t *pamh, const char *group)
status = PAM_NO_MODULE_DATA;
if (pam_get_data(pamh, data_name, &ignore) != PAM_SUCCESS) {
status = pam_set_data(pamh, data_name,
- result, pam_modutil_cleanup);
+ result, pam_modutil_cleanup_group);
}
free(data_name);
if (status == PAM_SUCCESS) {
diff --git a/libpam/pam_modutil_getpwnam.c b/libpam/pam_modutil_getpwnam.c
index 5701ba9c..de654aeb 100644
--- a/libpam/pam_modutil_getpwnam.c
+++ b/libpam/pam_modutil_getpwnam.c
@@ -62,7 +62,7 @@ pam_modutil_getpwnam(pam_handle_t *pamh, const char *user)
status = PAM_NO_MODULE_DATA;
if (pam_get_data(pamh, data_name, &ignore) != PAM_SUCCESS) {
status = pam_set_data(pamh, data_name,
- result, pam_modutil_cleanup);
+ result, pam_modutil_cleanup_passwd);
}
free(data_name);
if (status == PAM_SUCCESS) {
diff --git a/libpam/pam_modutil_getpwuid.c b/libpam/pam_modutil_getpwuid.c
index d3bb7231..6534958c 100644
--- a/libpam/pam_modutil_getpwuid.c
+++ b/libpam/pam_modutil_getpwuid.c
@@ -62,7 +62,7 @@ pam_modutil_getpwuid(pam_handle_t *pamh, uid_t uid)
status = PAM_NO_MODULE_DATA;
if (pam_get_data(pamh, data_name, &ignore) != PAM_SUCCESS) {
status = pam_set_data(pamh, data_name,
- result, pam_modutil_cleanup);
+ result, pam_modutil_cleanup_passwd);
}
free(data_name);
if (status == PAM_SUCCESS) {
diff --git a/libpam/pam_modutil_getspnam.c b/libpam/pam_modutil_getspnam.c
index 9aa6ac9a..9733eda0 100644
--- a/libpam/pam_modutil_getspnam.c
+++ b/libpam/pam_modutil_getspnam.c
@@ -62,7 +62,7 @@ pam_modutil_getspnam(pam_handle_t *pamh, const char *user)
status = PAM_NO_MODULE_DATA;
if (pam_get_data(pamh, data_name, &ignore) != PAM_SUCCESS) {
status = pam_set_data(pamh, data_name,
- result, pam_modutil_cleanup);
+ result, pam_modutil_cleanup_shadow);
}
free(data_name);
if (status == PAM_SUCCESS) {
diff --git a/libpam/pam_modutil_private.h b/libpam/pam_modutil_private.h
index 98a30f68..611c7696 100644
--- a/libpam/pam_modutil_private.h
+++ b/libpam/pam_modutil_private.h
@@ -20,5 +20,14 @@
extern void
pam_modutil_cleanup(pam_handle_t *pamh, void *data,
int error_status);
+extern void
+pam_modutil_cleanup_group(pam_handle_t *pamh, void *data,
+ int error_status);
+extern void
+pam_modutil_cleanup_passwd(pam_handle_t *pamh, void *data,
+ int error_status);
+extern void
+pam_modutil_cleanup_shadow(pam_handle_t *pamh, void *data,
+ int error_status);
#endif /* PAMMODUTIL_PRIVATE_H */
--
2.50.1

File diff suppressed because it is too large Load Diff