diff --git a/MANIFEST b/MANIFEST index fcd66bfac..d2d32e9a0 100644 --- a/MANIFEST +++ b/MANIFEST @@ -142,6 +142,7 @@ lib/util/explicit_bzero.c lib/util/fatal.c lib/util/fchmodat.c lib/util/fnmatch.c +lib/util/freezero.c lib/util/fstatat.c lib/util/getaddrinfo.c lib/util/getcwd.c diff --git a/config.h.in b/config.h.in index c36333910..6a3f07351 100644 --- a/config.h.in +++ b/config.h.in @@ -285,6 +285,9 @@ /* Define to 1 if you have the `freeifaddrs' function. */ #undef HAVE_FREEIFADDRS +/* Define to 1 if you have the `freezero' function. */ +#undef HAVE_FREEZERO + /* Define to 1 if you have the `fseeko' function. */ #undef HAVE_FSEEKO diff --git a/configure b/configure index 8e3af5fd0..aca575a72 100755 --- a/configure +++ b/configure @@ -20673,6 +20673,32 @@ esac done +fi +done + +for ac_func in freezero +do : + ac_fn_c_check_func "$LINENO" "freezero" "ac_cv_func_freezero" +if test "x$ac_cv_func_freezero" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FREEZERO 1 +_ACEOF + +else + + case " $LIBOBJS " in + *" freezero.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS freezero.$ac_objext" + ;; +esac + + + for _sym in sudo_freezero; do + COMPAT_EXP="${COMPAT_EXP}${_sym} +" + done + + fi done diff --git a/configure.ac b/configure.ac index 3b3d047f3..3784cc9d7 100644 --- a/configure.ac +++ b/configure.ac @@ -2825,6 +2825,10 @@ AC_CHECK_FUNCS([memrchr], [], [ AC_LIBOBJ(memrchr) SUDO_APPEND_COMPAT_EXP(sudo_memrchr) ]) +AC_CHECK_FUNCS([freezero], [], [ + AC_LIBOBJ(freezero) + SUDO_APPEND_COMPAT_EXP(sudo_freezero) +]) AC_CHECK_FUNCS(nanosleep, [], [ # On Solaris, nanosleep is in librt AC_CHECK_LIB(rt, nanosleep, [ diff --git a/include/sudo_compat.h b/include/sudo_compat.h index 03e256828..72d62e5ef 100644 --- a/include/sudo_compat.h +++ b/include/sudo_compat.h @@ -441,6 +441,11 @@ __dso_public void sudo_explicit_bzero(void *s, size_t n); # undef explicit_bzero # define explicit_bzero(_a, _b) sudo_explicit_bzero((_a), (_b)) #endif /* HAVE_EXPLICIT_BZERO */ +#ifndef HAVE_FREEZERO +__dso_public void sudo_freezero(void *p, size_t n); +# undef freezero +# define freezero(_a, _b) sudo_freezero((_a), (_b)) +#endif /* HAVE_FREEZERO */ #ifdef PREFER_PORTABLE_GETCWD __dso_public char *sudo_getcwd(char *, size_t size); # undef getcwd diff --git a/lib/util/Makefile.in b/lib/util/Makefile.in index 342489f0f..6988f1847 100644 --- a/lib/util/Makefile.in +++ b/lib/util/Makefile.in @@ -609,6 +609,14 @@ fnmatch.i: $(srcdir)/fnmatch.c $(incdir)/compat/charclass.h \ $(CC) -E -o $@ $(CPPFLAGS) $< fnmatch.plog: fnmatch.i rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/fnmatch.c --i-file $< --output-file $@ +freezero.lo: $(srcdir)/freezero.c $(incdir)/sudo_compat.h \ + $(top_builddir)/config.h + $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/freezero.c +freezero.i: $(srcdir)/freezero.c $(incdir)/sudo_compat.h \ + $(top_builddir)/config.h + $(CC) -E -o $@ $(CPPFLAGS) $< +freezero.plog: freezero.i + rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/freezero.c --i-file $< --output-file $@ fstatat.lo: $(srcdir)/fstatat.c $(incdir)/sudo_compat.h $(top_builddir)/config.h $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/fstatat.c fstatat.i: $(srcdir)/fstatat.c $(incdir)/sudo_compat.h $(top_builddir)/config.h diff --git a/lib/util/freezero.c b/lib/util/freezero.c new file mode 100644 index 000000000..e2d2e8a2a --- /dev/null +++ b/lib/util/freezero.c @@ -0,0 +1,38 @@ +/* + * SPDX-License-Identifier: ISC + * + * Copyright (c) 2020 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This is an open source non-commercial project. Dear PVS-Studio, please check it. + * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + */ + +#include + +#include +#include + +#include "sudo_compat.h" + +#ifndef HAVE_FREEZERO +void +sudo_freezero(void *p, size_t n) +{ + explicit_bzero(p, n); + free(p); +} +#endif /* HAVE_FREEZERO */ diff --git a/lib/util/getentropy.c b/lib/util/getentropy.c index 694eb52b5..510283550 100644 --- a/lib/util/getentropy.c +++ b/lib/util/getentropy.c @@ -613,10 +613,8 @@ getentropy_fallback(void *buf, size_t len) } done: sudo_digest_free(ctx); - if (results != NULL) { - explicit_bzero(results, sizeof(results)); - free(results); - } + if (results != NULL) + freezero(results, sizeof(results)); return (ret); } diff --git a/plugins/sudoers/auth/aix_auth.c b/plugins/sudoers/auth/aix_auth.c index 598350363..fed2c46fa 100644 --- a/plugins/sudoers/auth/aix_auth.c +++ b/plugins/sudoers/auth/aix_auth.c @@ -243,8 +243,7 @@ sudo_aix_verify(struct passwd *pw, char *prompt, sudo_auth *auth, struct sudo_co free(message); message = NULL; result = authenticate(pw->pw_name, pass, &reenter, &message); - explicit_bzero(pass, strlen(pass)); - free(pass); + freezero(pass, strlen(pass)); prompt = message; } while (reenter); diff --git a/plugins/sudoers/auth/bsdauth.c b/plugins/sudoers/auth/bsdauth.c index 3ed6c458a..1c321340f 100644 --- a/plugins/sudoers/auth/bsdauth.c +++ b/plugins/sudoers/auth/bsdauth.c @@ -151,8 +151,7 @@ bsdauth_verify(struct passwd *pw, char *prompt, sudo_auth *auth, struct sudo_con if (pass) { authok = auth_userresponse(as, pass, 1); - explicit_bzero(pass, strlen(pass)); - free(pass); + freezero(pass, strlen(pass)); } /* restore old signal handler */ diff --git a/plugins/sudoers/auth/fwtk.c b/plugins/sudoers/auth/fwtk.c index 4c99a84a6..c9ab06b7f 100644 --- a/plugins/sudoers/auth/fwtk.c +++ b/plugins/sudoers/auth/fwtk.c @@ -134,8 +134,7 @@ restart: error = AUTH_FAILURE; done: explicit_bzero(buf, sizeof(buf)); - explicit_bzero(pass, strlen(pass)); - free(pass); + freezero(pass, strlen(pass)); debug_return_int(error); } diff --git a/plugins/sudoers/auth/pam.c b/plugins/sudoers/auth/pam.c index a725f1f62..526675f53 100644 --- a/plugins/sudoers/auth/pam.c +++ b/plugins/sudoers/auth/pam.c @@ -732,8 +732,7 @@ done: struct pam_response *pr = &reply[n]; if (pr->resp != NULL) { - explicit_bzero(pr->resp, strlen(pr->resp)); - free(pr->resp); + freezero(pr->resp, strlen(pr->resp)); pr->resp = NULL; } } diff --git a/plugins/sudoers/auth/passwd.c b/plugins/sudoers/auth/passwd.c index 305354196..18e7f30b6 100644 --- a/plugins/sudoers/auth/passwd.c +++ b/plugins/sudoers/auth/passwd.c @@ -100,9 +100,8 @@ sudo_passwd_cleanup(struct passwd *pw, sudo_auth *auth, bool force) char *pw_epasswd = auth->data; debug_decl(sudo_passwd_cleanup, SUDOERS_DEBUG_AUTH); - if (pw_epasswd != NULL) { - explicit_bzero(pw_epasswd, strlen(pw_epasswd)); - free(pw_epasswd); - } + if (pw_epasswd != NULL) + freezero(pw_epasswd, strlen(pw_epasswd)); + debug_return_int(AUTH_SUCCESS); } diff --git a/plugins/sudoers/auth/secureware.c b/plugins/sudoers/auth/secureware.c index dd02f515e..dd7aa42eb 100644 --- a/plugins/sudoers/auth/secureware.c +++ b/plugins/sudoers/auth/secureware.c @@ -101,10 +101,8 @@ sudo_secureware_cleanup(struct passwd *pw, sudo_auth *auth, bool force) char *pw_epasswd = auth->data; debug_decl(sudo_secureware_cleanup, SUDOERS_DEBUG_AUTH); - if (pw_epasswd != NULL) { - explicit_bzero(pw_epasswd, strlen(pw_epasswd)); - free(pw_epasswd); - } + if (pw_epasswd != NULL) + freezero(pw_epasswd, strlen(pw_epasswd)); debug_return_int(AUTH_SUCCESS); } diff --git a/plugins/sudoers/auth/securid5.c b/plugins/sudoers/auth/securid5.c index e8eebdf2e..d5804011b 100644 --- a/plugins/sudoers/auth/securid5.c +++ b/plugins/sudoers/auth/securid5.c @@ -176,10 +176,8 @@ sudo_securid_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_ /* Sometimes (when current token close to expire?) ACE challenges for the next token displayed (entered without the PIN) */ - if (pass != NULL) { - explicit_bzero(pass, strlen(pass)); - free(pass); - } + if (pass != NULL) + freezero(pass, strlen(pass)); pass = auth_getpass("\ !!! ATTENTION !!!\n\ Wait for the token code to change, \n\ @@ -217,10 +215,8 @@ then enter the new token code.\n", \ /* Free resources */ SD_Close(*sd); - if (pass != NULL) { - explicit_bzero(pass, strlen(pass)); - free(pass); - } + if (pass != NULL) + freezero(pass, strlen(pass)); /* Return stored state to calling process */ debug_return_int(ret); diff --git a/plugins/sudoers/auth/sia.c b/plugins/sudoers/auth/sia.c index 414a64b46..7feb19e03 100644 --- a/plugins/sudoers/auth/sia.c +++ b/plugins/sudoers/auth/sia.c @@ -90,8 +90,7 @@ sudo_sia_verify(struct passwd *pw, char *prompt, sudo_auth *auth, /* Check password and zero out plaintext copy. */ rc = sia_ses_authent(NULL, pass, siah); - explicit_bzero(pass, strlen(pass)); - free(pass); + freezero(pass, strlen(pass)); if (rc == SIASUCCESS) debug_return_int(AUTH_SUCCESS); diff --git a/plugins/sudoers/auth/sudo_auth.c b/plugins/sudoers/auth/sudo_auth.c index 5570c78b3..188b65fde 100644 --- a/plugins/sudoers/auth/sudo_auth.c +++ b/plugins/sudoers/auth/sudo_auth.c @@ -325,10 +325,8 @@ verify_user(struct passwd *pw, char *prompt, int validated, if (success != AUTH_FAILURE) break; } - if (pass != NULL) { - explicit_bzero(pass, strlen(pass)); - free(pass); - } + if (pass != NULL) + freezero(pass, strlen(pass)); if (success != AUTH_FAILURE) goto done; diff --git a/scripts/mkdep.pl b/scripts/mkdep.pl index b42de26ee..5299c0fe2 100755 --- a/scripts/mkdep.pl +++ b/scripts/mkdep.pl @@ -116,7 +116,7 @@ sub mkdep { # XXX - fill in AUTH_OBJS from contents of the auth dir instead $makefile =~ s:\@AUTH_OBJS\@:afs.lo aix_auth.lo bsdauth.lo dce.lo fwtk.lo getspwuid.lo kerb5.lo pam.lo passwd.lo rfc1938.lo secureware.lo securid5.lo sia.lo:; $makefile =~ s:\@DIGEST\@:digest.lo digest_openssl.lo digest_gcrypt.lo:; - $makefile =~ s:\@LTLIBOBJS\@:arc4random.lo arc4random_uniform.lo closefrom.lo dup3.lo explicit_bzero.lo fchmodat.lo fstatat.lo fnmatch.lo getaddrinfo.lo getcwd.lo getentropy.lo getgrouplist.lo getdelim.lo getopt_long.lo getusershell.lo glob.lo inet_ntop_lo inet_pton.lo isblank.lo memrchr.lo mksiglist.lo mksigname.lo mktemp.lo nanosleep.lo openat.lo pipe2.lo pw_dup.lo reallocarray.lo sha2.lo sig2str.lo siglist.lo signame.lo snprintf.lo str2sig.lo strlcat.lo strlcpy.lo strndup.lo strnlen.lo strsignal.lo unlinkat.lo utimens.lo vsyslog.lo:; + $makefile =~ s:\@LTLIBOBJS\@:arc4random.lo arc4random_uniform.lo closefrom.lo dup3.lo explicit_bzero.lo fchmodat.lo freezero.lo fstatat.lo fnmatch.lo getaddrinfo.lo getcwd.lo getentropy.lo getgrouplist.lo getdelim.lo getopt_long.lo getusershell.lo glob.lo inet_ntop_lo inet_pton.lo isblank.lo memrchr.lo mksiglist.lo mksigname.lo mktemp.lo nanosleep.lo openat.lo pipe2.lo pw_dup.lo reallocarray.lo sha2.lo sig2str.lo siglist.lo signame.lo snprintf.lo str2sig.lo strlcat.lo strlcpy.lo strndup.lo strnlen.lo strsignal.lo unlinkat.lo utimens.lo vsyslog.lo:; # Parse OBJS lines my %objs; diff --git a/src/conversation.c b/src/conversation.c index 7a9f01ff2..95ecadde4 100644 --- a/src/conversation.c +++ b/src/conversation.c @@ -135,8 +135,7 @@ err: struct sudo_conv_reply *repl = &replies[n]; if (repl->reply == NULL) continue; - explicit_bzero(repl->reply, strlen(repl->reply)); - free(repl->reply); + freezero(repl->reply, strlen(repl->reply)); repl->reply = NULL; } while (n--); }