summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Göttsche <cgzones@googlemail.com>2023-01-30 17:53:24 +0100
committerChristian Göttsche <cgzones@googlemail.com>2023-02-28 15:11:18 +0100
commit19a29268178951988eca29a7830f24bfef300c3c (patch)
tree23024993a88582f13a3d63a60446c6ab4207b12e
parentbde2277d2aa1cd9d4a14a1a1f89241d5e86b0bad (diff)
downloadlinux-pam-git-19a29268178951988eca29a7830f24bfef300c3c.tar.gz
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.
-rw-r--r--configure.ac1
-rw-r--r--libpam/include/pam_inline.h60
-rw-r--r--libpam/include/security/_pam_macros.h28
-rw-r--r--libpam/include/security/_pam_types.h6
4 files changed, 85 insertions, 10 deletions
diff --git a/configure.ac b/configure.ac
index 8b89124e..8844eb35 100644
--- a/configure.ac
+++ b/configure.ac
@@ -615,6 +615,7 @@ AC_CHECK_FUNCS(getgrouplist getline getdelim)
AC_CHECK_FUNCS(inet_ntop inet_pton innetgr)
AC_CHECK_FUNCS(quotactl)
AC_CHECK_FUNCS(unshare)
+AC_CHECK_FUNCS(explicit_bzero memset_explicit)
AC_CHECK_FUNCS([ruserok_af ruserok], [break])
AC_ARG_ENABLE([regenerate-docu],
diff --git a/libpam/include/pam_inline.h b/libpam/include/pam_inline.h
index ec2f3bf0..6fe37857 100644
--- a/libpam/include/pam_inline.h
+++ b/libpam/include/pam_inline.h
@@ -9,6 +9,7 @@
#define PAM_INLINE_H
#include "pam_cc_compat.h"
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
@@ -33,6 +34,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_))
@@ -66,6 +73,59 @@ pam_str_skip_icase_prefix_len(const char *str, const char *prefix, size_t prefix
#define pam_str_skip_icase_prefix(str_, prefix_) \
pam_str_skip_icase_prefix_len((str_), (prefix_), sizeof(prefix_) - 1 + PAM_MUST_BE_ARRAY(prefix_))
+
+/*
+ * 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)
{
diff --git a/libpam/include/security/_pam_macros.h b/libpam/include/security/_pam_macros.h
index e891e226..b5129d2a 100644
--- a/libpam/include/security/_pam_macros.h
+++ b/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) { \
diff --git a/libpam/include/security/_pam_types.h b/libpam/include/security/_pam_types.h
index 2abb7ee5..4d6909e8 100644
--- a/libpam/include/security/_pam_types.h
+++ b/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