File libpam-introduce-secure-memory-erasure-helpers.patch of Package pam.40283

From 19a29268178951988eca29a7830f24bfef300c3c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
Date: Mon, 30 Jan 2023 17:53:24 +0100
Subject: [PATCH] libpam: introduce secure memory erasure helpers

Avoid compiler optimizations to elide the memory erasure by using a
secure method: either memset_explicit() [C23], bzero_explicit() [glibc
2.25] or a manual memory barrier.

Since the current helpers _pam_overwrite*() and _pam_drop_reply() are
publicly exported, create new ones in "pam_inline.h" and deprecate the
old ones.

[vlefebvre: adjust context]
---
 configure.ac                          |  1 +
 libpam/include/pam_inline.h           | 60 +++++++++++++++++++++++++++
 libpam/include/security/_pam_macros.h | 28 ++++++++-----
 libpam/include/security/_pam_types.h  |  6 +++
 4 files changed, 85 insertions(+), 10 deletions(-)

Index: Linux-PAM-1.3.0/configure.ac
===================================================================
--- Linux-PAM-1.3.0.orig/configure.ac
+++ Linux-PAM-1.3.0/configure.ac
@@ -537,6 +537,8 @@ AC_CHECK_FUNCS(inet_ntop inet_pton innet
 AC_CHECK_FUNCS(unshare, [UNSHARE=yes], [UNSHARE=no])
 AM_CONDITIONAL([HAVE_UNSHARE], [test "$UNSHARE" = yes])
 
+AC_CHECK_FUNCS(explicit_bzero memset_explicit)
+
 AC_ARG_ENABLE([regenerate-docu],
   AS_HELP_STRING([--disable-regenerate-docu],[Don't re-build documentation from XML sources]),
   [enable_docu=$enableval], [enable_docu=yes])
Index: Linux-PAM-1.3.0/libpam/include/pam_inline.h
===================================================================
--- Linux-PAM-1.3.0.orig/libpam/include/pam_inline.h
+++ Linux-PAM-1.3.0/libpam/include/pam_inline.h
@@ -9,6 +9,7 @@
 #define PAM_INLINE_H
 
 #include "pam_cc_compat.h"
+#include <stdlib.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
@@ -35,6 +36,12 @@
  * 0, otherwise.
  */
 #define PAM_MUST_BE_ARRAY(a_)		PAM_FAIL_BUILD_ON_ZERO(!PAM_IS_NOT_ARRAY(a_))
+/*
+ * Evaluates to
+ * - a syntax error if the argument is an array,
+ * 0, otherwise.
+ */
+#define PAM_MUST_NOT_BE_ARRAY(a_)	PAM_FAIL_BUILD_ON_ZERO(PAM_IS_NOT_ARRAY(a_))
 
 /* Evaluates to the number of elements in the specified array.  */
 #define PAM_ARRAY_SIZE(a_)		(sizeof(a_) / sizeof((a_)[0]) + PAM_MUST_BE_ARRAY(a_))
@@ -101,6 +108,59 @@ pam_snprintf(char *str, size_t size, con
        pam_snprintf((str_), sizeof(str_) + PAM_MUST_BE_ARRAY(str_), (fmt_),    \
                     ##__VA_ARGS__)
 
+
+/*
+ * Macros to securely erase memory
+ */
+
+#ifdef HAVE_MEMSET_EXPLICIT
+static inline void pam_overwrite_n(void *ptr, size_t len)
+{
+	if (ptr)
+		memset_explicit(ptr, len);
+}
+#elif defined HAVE_EXPLICIT_BZERO
+static inline void pam_overwrite_n(void *ptr, size_t len)
+{
+	if (ptr)
+		explicit_bzero(ptr, len);
+}
+#else
+static inline void pam_overwrite_n(void *ptr, size_t len)
+{
+	if (ptr) {
+		ptr = memset(ptr, '\0', len);
+		__asm__ __volatile__ ("" : : "r"(ptr) : "memory");
+	}
+}
+#endif
+
+#define pam_overwrite_string(x)                      \
+do {                                                 \
+	char *xx__ = (x) + PAM_MUST_NOT_BE_ARRAY(x); \
+	if (xx__)                                    \
+		pam_overwrite_n(xx__, strlen(xx__)); \
+} while(0)
+
+#define pam_overwrite_array(x) pam_overwrite_n(x, sizeof(x) + PAM_MUST_BE_ARRAY(x))
+
+#define pam_overwrite_object(x) pam_overwrite_n(x, sizeof(*(x)) + PAM_MUST_NOT_BE_ARRAY(x))
+
+static inline void
+pam_drop_response(struct pam_response *reply, int replies)
+{
+	int reply_i;
+
+	for (reply_i = 0; reply_i < replies; ++reply_i) {
+		if (reply[reply_i].resp) {
+			pam_overwrite_string(reply[reply_i].resp);
+			free(reply[reply_i].resp);
+		}
+	}
+	free(reply);
+}
+
+
 static inline int
 pam_read_passwords(int fd, int npass, char **passwords)
 {
Index: Linux-PAM-1.3.0/libpam/include/security/_pam_macros.h
===================================================================
--- Linux-PAM-1.3.0.orig/libpam/include/security/_pam_macros.h
+++ Linux-PAM-1.3.0/libpam/include/security/_pam_macros.h
@@ -7,6 +7,8 @@
  * Organized by Cristian Gafton <gafton@redhat.com>
  */
 
+#include "_pam_types.h"
+
 /* a 'safe' version of strdup */
 
 #include <stdlib.h>
@@ -14,20 +16,22 @@
 
 #define  x_strdup(s)  ( (s) ? strdup(s):NULL )
 
-/* Good policy to strike out passwords with some characters not just
-   free the memory */
+/*
+ * WARNING: Do NOT use these overwrite macros, as they do not reliable
+ * override the memory.
+ */
 
-#define _pam_overwrite(x)        \
-do {                             \
-     register char *__xx__;      \
-     if ((__xx__=(x)))           \
-          while (*__xx__)        \
-               *__xx__++ = '\0'; \
+#define _pam_overwrite(x)                  \
+do {                                       \
+     PAM_DEPRECATED register char *__xx__; \
+     if ((__xx__=(x)))                     \
+          while (*__xx__)                  \
+               *__xx__++ = '\0';           \
 } while (0)
 
 #define _pam_overwrite_n(x,n)   \
 do {                             \
-     register char *__xx__;      \
+     PAM_DEPRECATED register char *__xx__; \
      register unsigned int __i__ = 0;    \
      if ((__xx__=(x)))           \
         for (;__i__<n; __i__++) \
@@ -46,9 +50,13 @@ do {                 \
     }                \
 } while (0)
 
+/*
+ * WARNING: Do NOT use this macro, as it does not reliable override the memory.
+ */
+
 #define _pam_drop_reply(/* struct pam_response * */ reply, /* int */ replies) \
 do {                                              \
-    int reply_i;                                  \
+    PAM_DEPRECATED int reply_i;                   \
                                                   \
     for (reply_i=0; reply_i<replies; ++reply_i) { \
 	if (reply[reply_i].resp) {                \
Index: Linux-PAM-1.3.0/libpam/include/security/_pam_types.h
===================================================================
--- Linux-PAM-1.3.0.orig/libpam/include/security/_pam_types.h
+++ Linux-PAM-1.3.0/libpam/include/security/_pam_types.h
@@ -160,6 +160,12 @@ typedef struct pam_handle pam_handle_t;
 # define PAM_FORMAT(params)
 #endif
 
+#if PAM_GNUC_PREREQ(3,1)
+# define PAM_DEPRECATED __attribute__((__deprecated__))
+#else
+# define PAM_DEPRECATED
+#endif
+
 #if PAM_GNUC_PREREQ(3,3) && !defined(LIBPAM_COMPILE)
 # define PAM_NONNULL(params) __attribute__((__nonnull__ params))
 #else
openSUSE Build Service is sponsored by