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