diff options
author | Christian Göttsche <cgzones@googlemail.com> | 2023-01-30 17:53:24 +0100 |
---|---|---|
committer | Christian Göttsche <cgzones@googlemail.com> | 2023-02-28 15:11:18 +0100 |
commit | 19a29268178951988eca29a7830f24bfef300c3c (patch) | |
tree | 23024993a88582f13a3d63a60446c6ab4207b12e | |
parent | bde2277d2aa1cd9d4a14a1a1f89241d5e86b0bad (diff) | |
download | pam-19a29268178951988eca29a7830f24bfef300c3c.tar.gz pam-19a29268178951988eca29a7830f24bfef300c3c.tar.bz2 pam-19a29268178951988eca29a7830f24bfef300c3c.zip |
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.ac | 1 | ||||
-rw-r--r-- | libpam/include/pam_inline.h | 60 | ||||
-rw-r--r-- | libpam/include/security/_pam_macros.h | 28 | ||||
-rw-r--r-- | libpam/include/security/_pam_types.h | 6 |
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 |