Compare commits

1 Commits
main ... 1.1

6 changed files with 1583 additions and 1 deletions

View File

@@ -1,3 +1,19 @@
-------------------------------------------------------------------
Thu Jun 12 18:36:14 UTC 2025 - Valentin Lefebvre <valentin.lefebvre@suse.com>
- pam_namespace: convert functions that may operate on a user-controlled path
to operate on file descriptors instead of absolute path. And keep the
bind-mount protection from protect_mount() as a defense in depthmeasure.
[bsc#1244509, CVE-2025-6020,
pam_inline-introduce-pam_asprintf-pam_snprintf-and-p.patch,
pam_namespace-fix-potential-privilege-escalation.patch,
pam_namespace-add-flags-to-indicate-path-safety.patch,
pam_namespace-secure_opendir-do-not-look-at-the-grou.patch]
- pam_namespace-fix-potential-privilege-escalation.patch adapted and includes
changes from upstream commits: ds6242a, bc856cd.
* pam_namespace fix logic in return value handling
* pam_namespace move functions around
-------------------------------------------------------------------
Thu Dec 5 12:44:33 UTC 2024 - Valentin Lefebvre <valentin.lefebvre@suse.com>
@@ -1199,7 +1215,6 @@ Wed Feb 23 12:45:03 UTC 2011 - vcizek@novell.com
* correct parsing of "quiet" option
-------------------------------------------------------------------
Wed Feb 23 10:00:22 UTC 2011 - vcizek@novell.com
- fix for bnc#673826 (pam_listfile)

View File

@@ -99,6 +99,11 @@ Patch1: pam-limit-nproc.patch
Patch2: pam-bsc1194818-cursor-escape.patch
# https://github.com/linux-pam/linux-pam/pull/854
Patch3: pam_access-rework-resolving-of-tokens-as-hostname.patch
# CVE-2025-6020
Patch4: pam_inline-introduce-pam_asprintf-pam_snprintf-and-p.patch
Patch5: pam_namespace-fix-potential-privilege-escalation.patch
Patch6: pam_namespace-add-flags-to-indicate-path-safety.patch
Patch7: pam_namespace-secure_opendir-do-not-look-at-the-grou.patch
BuildRequires: audit-devel
BuildRequires: bison
BuildRequires: flex

View File

@@ -0,0 +1,69 @@
Index: Linux-PAM-1.6.1/libpam/include/pam_cc_compat.h
===================================================================
--- Linux-PAM-1.6.1.orig/libpam/include/pam_cc_compat.h
+++ Linux-PAM-1.6.1/libpam/include/pam_cc_compat.h
@@ -21,6 +21,12 @@
# define PAM_ATTRIBUTE_ALIGNED(arg) /* empty */
#endif
+#if PAM_GNUC_PREREQ(3, 0)
+# define PAM_ATTRIBUTE_MALLOC __attribute__((__malloc__))
+#else
+# define PAM_ATTRIBUTE_MALLOC /* empty */
+#endif
+
#if PAM_GNUC_PREREQ(4, 6)
# define DIAG_PUSH_IGNORE_CAST_QUAL \
_Pragma("GCC diagnostic push"); \
Index: Linux-PAM-1.6.1/libpam/include/pam_inline.h
===================================================================
--- Linux-PAM-1.6.1.orig/libpam/include/pam_inline.h
+++ Linux-PAM-1.6.1/libpam/include/pam_inline.h
@@ -9,6 +9,8 @@
#define PAM_INLINE_H
#include "pam_cc_compat.h"
+#include <stdarg.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -125,6 +127,38 @@ pam_drop_response(struct pam_response *r
free(reply);
}
+static inline char * PAM_FORMAT((printf, 1, 2)) PAM_NONNULL((1)) PAM_ATTRIBUTE_MALLOC
+pam_asprintf(const char *fmt, ...)
+{
+ int rc;
+ char *res;
+ va_list ap;
+
+ va_start(ap, fmt);
+ rc = vasprintf(&res, fmt, ap);
+ va_end(ap);
+
+ return rc < 0 ? NULL : res;
+}
+
+static inline int PAM_FORMAT((printf, 3, 4)) PAM_NONNULL((3))
+pam_snprintf(char *str, size_t size, const char *fmt, ...)
+{
+ int rc;
+ va_list ap;
+
+ va_start(ap, fmt);
+ rc = vsnprintf(str, size, fmt, ap);
+ va_end(ap);
+
+ if (rc < 0 || (unsigned int) rc >= size)
+ return -1;
+ return rc;
+}
+
+#define pam_sprintf(str_, fmt_, ...) \
+ pam_snprintf((str_), sizeof(str_) + PAM_MUST_BE_ARRAY(str_), (fmt_), \
+ ##__VA_ARGS__)
static inline int
pam_read_passwords(int fd, int npass, char **passwords)

View File

@@ -0,0 +1,179 @@
Adapted from commit:
From a195c0daaba325aa09180b9492bf78ba03c5af89 Mon Sep 17 00:00:00 2001
From: Olivier Bal-Petre <olivier.bal-petre@ssi.gouv.fr>
Date: Tue, 4 Mar 2025 14:37:02 +0100
Subject: [PATCH 2/3] pam_namespace: add flags to indicate path safety
Add two flags in the script to indicate if the paths to the polydir
and the instance directories are safe (root owned and writable by
root only).
Signed-off-by: Olivier Bal-Petre <olivier.bal-petre@ssi.gouv.fr>
Signed-off-by: Dmitry V. Levin <ldv@strace.io>
Signed-off-by: Valentin Lefebvre <valentin.lefebvre@suse.com>
Index: Linux-PAM-1.6.1/modules/pam_namespace/namespace.init
===================================================================
--- Linux-PAM-1.6.1.orig/modules/pam_namespace/namespace.init
+++ Linux-PAM-1.6.1/modules/pam_namespace/namespace.init
@@ -1,25 +1,43 @@
#!/bin/sh
-# It receives polydir path as $1, the instance path as $2,
-# a flag whether the instance dir was newly created (0 - no, 1 - yes) in $3,
-# and user name in $4.
+# It receives as arguments:
+# - $1 polydir path (see WARNING below)
+# - $2 instance path (see WARNING below)
+# - $3 flag whether the instance dir was newly created (0 - no, 1 - yes)
+# - $4 user name
+# - $5 flag whether the polydir path ($1) is safe (0 - unsafe, 1 -safe)
+# - $6 flag whether the instance path ($2) is safe (0 - unsafe, 1 - safe)
+#
+# WARNING: This script is invoked with full root privileges. Accessing
+# the polydir ($1) and the instance ($2) directories in this context may be
+# extremely dangerous as those can be under user control. The flags $5 and $6
+# are provided to let you know if all the segments part of the path (except the
+# last one) are owned by root and are writable by root only. If the path does
+# not meet these criteria, you expose yourself to possible symlink attacks when
+# accessing these path.
+# However, even if the path components are safe, the content of the
+# directories may still be owned/writable by a user, so care must be taken!
#
# The following section will copy the contents of /etc/skel if this is a
# newly created home directory.
-if [ "$3" = 1 ]; then
- # This line will fix the labeling on all newly created directories
- [ -x /sbin/restorecon ] && /sbin/restorecon "$1"
- user="$4"
- passwd=$(getent passwd "$user")
- homedir=$(echo "$passwd" | cut -f6 -d":")
- if [ "$1" = "$homedir" ]; then
- gid=$(echo "$passwd" | cut -f4 -d":")
- cp -rT /etc/skel "$homedir"
- chown -R "$user":"$gid" "$homedir"
- mask=$(sed -E -n 's/^UMASK[[:space:]]+([^#[:space:]]+).*/\1/p' /etc/login.defs)
- mode=$(printf "%o" $((0777 & ~mask)))
- chmod ${mode:-700} "$homedir"
- [ -x /sbin/restorecon ] && /sbin/restorecon -R "$homedir"
- fi
-fi
+# Executes only if the polydir path is safe
+if [ "$5" = 1 ]; then
+
+ if [ "$3" = 1 ]; then
+ # This line will fix the labeling on all newly created directories
+ [ -x /sbin/restorecon ] && /sbin/restorecon "$1"
+ user="$4"
+ passwd=$(getent passwd "$user")
+ homedir=$(echo "$passwd" | cut -f6 -d":")
+ if [ "$1" = "$homedir" ]; then
+ gid=$(echo "$passwd" | cut -f4 -d":")
+ cp -rT /etc/skel "$homedir"
+ chown -R "$user":"$gid" "$homedir"
+ mask=$(sed -E -n 's/^UMASK[[:space:]]+([^#[:space:]]+).*/\1/p' /etc/login.defs)
+ mode=$(printf "%o" $((0777 & ~mask)))
+ chmod ${mode:-700} "$homedir"
+ [ -x /sbin/restorecon ] && /sbin/restorecon -R "$homedir"
+ fi
+ fi
+fi
exit 0
Index: Linux-PAM-1.6.1/modules/pam_namespace/pam_namespace.c
===================================================================
--- Linux-PAM-1.6.1.orig/modules/pam_namespace/pam_namespace.c
+++ Linux-PAM-1.6.1/modules/pam_namespace/pam_namespace.c
@@ -1478,6 +1478,79 @@ static int check_inst_parent(int dfd, st
}
/*
+ * Check for a given absolute path that all segments except the last one are:
+ * 1. a directory owned by root and not writable by group or others
+ * 2. a symlink owned by root and referencing a directory respecting 1.
+ * Returns 0 if safe, -1 is unsafe.
+ * If the path is not accessible (does not exist, hidden under a mount...),
+ * returns -1 (unsafe).
+ */
+static int check_safe_path(const char *path, struct instance_data *idata)
+{
+ char *p = strdup(path);
+ char *d;
+ char *dir = p;
+ struct stat st;
+
+ if (p == NULL)
+ return -1;
+
+ /* Check path is absolute */
+ if (p[0] != '/')
+ goto error;
+
+ strip_trailing_slashes(p);
+
+ /* Last segment of the path may be owned by the user */
+ if ((d = strrchr(dir, '/')) != NULL)
+ *d = '\0';
+
+ while ((d=strrchr(dir, '/')) != NULL) {
+
+ /* Do not follow symlinks */
+ if (lstat(dir, &st) != 0)
+ goto error;
+
+ if (S_ISLNK(st.st_mode)) {
+ if (st.st_uid != 0) {
+ if (idata->flags & PAMNS_DEBUG)
+ pam_syslog(idata->pamh, LOG_DEBUG,
+ "Path deemed unsafe: Symlink %s should be owned by root", dir);
+ goto error;
+ }
+
+ /* Follow symlinks */
+ if (stat(dir, &st) != 0)
+ goto error;
+ }
+
+ if (!S_ISDIR(st.st_mode)) {
+ if (idata->flags & PAMNS_DEBUG)
+ pam_syslog(idata->pamh, LOG_DEBUG,
+ "Path deemed unsafe: %s is expected to be a directory", dir);
+ goto error;
+ }
+
+ if (st.st_uid != 0 ||
+ ((st.st_mode & (S_IWGRP|S_IWOTH)) && !(st.st_mode & S_ISVTX))) {
+ if (idata->flags & PAMNS_DEBUG)
+ pam_syslog(idata->pamh, LOG_DEBUG,
+ "Path deemed unsafe: %s should be owned by root, and not be writable by group or others", dir);
+ goto error;
+ }
+
+ *d = '\0';
+ }
+
+ free(p);
+ return 0;
+
+error:
+ free(p);
+ return -1;
+}
+
+/*
* Check to see if there is a namespace initialization script in
* the /etc/security directory. If such a script exists
* execute it and pass directory to polyinstantiate and instance
@@ -1535,7 +1608,11 @@ static int inst_init(const struct polydi
close_fds_pre_exec(idata);
if (execle(init_script, init_script,
- polyptr->dir, ipath, newdir?"1":"0", idata->user, NULL, envp) < 0)
+ polyptr->dir, ipath,
+ newdir ? "1":"0", idata->user,
+ (check_safe_path(polyptr->dir, idata) == -1) ? "0":"1",
+ (check_safe_path(ipath, idata) == -1) ? "0":"1",
+ NULL, envp) < 0)
_exit(1);
} else if (pid > 0) {
while (((rc = waitpid(pid, &status, 0)) == (pid_t)-1) &&

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,28 @@
Adapted from commit:
From 2c978bab94a0a62e5b8bc0d52a777dca394d90cb Mon Sep 17 00:00:00 2001
From: "Dmitry V. Levin" <ldv@strace.io>
Date: Tue, 27 May 2025 08:00:00 +0000
Subject: [PATCH 3/3] pam_namespace: secure_opendir: do not look at the group
ownership
When the directory is not group-writable, the group ownership does
not matter, and when it is group-writable, there should not be any
exceptions for the root group as there is no guarantee that the root
group does not include non-root users.
Signed-off-by: Valentin Lefebvre <valentin.lefebvre@suse.com>
Index: Linux-PAM-1.3.0/modules/pam_namespace/pam_namespace.c
===================================================================
--- Linux-PAM-1.3.0.orig/modules/pam_namespace/pam_namespace.c
+++ Linux-PAM-1.3.0/modules/pam_namespace/pam_namespace.c
@@ -1139,8 +1139,7 @@ static int secure_opendir(const char *pa
if (dfd_next == -1)
goto error;
} else if (st.st_uid != 0
- || (st.st_gid != 0 && (st.st_mode & S_IWGRP))
- || (st.st_mode & S_IWOTH)) {
+ || (st.st_mode & (S_IWGRP|S_IWOTH))) {
/* do not follow symlinks on subdirectories */
flags |= O_NOFOLLOW;
}