From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS22989 209.51.188.0/24 X-Spam-Status: No, score=-3.2 required=3.0 tests=AWL,BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,LONGWORDS, MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI,RCVD_IN_MSPIKE_H2,SPF_HELO_PASS, SPF_PASS shortcircuit=no autolearn=no autolearn_force=no version=3.4.2 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dcvr.yhbt.net (Postfix) with ESMTPS id 92DCD1F93C for ; Mon, 28 Nov 2022 04:56:17 +0000 (UTC) Authentication-Results: dcvr.yhbt.net; dkim=pass (1024-bit key; unprotected) header.d=cs.ucla.edu header.i=@cs.ucla.edu header.b="kTaYKmTu"; dkim-atps=neutral Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ozWBU-0007pu-TM; Sun, 27 Nov 2022 23:56:00 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ozWBS-0007oJ-6s for bug-gnulib@gnu.org; Sun, 27 Nov 2022 23:55:58 -0500 Received: from zimbra.cs.ucla.edu ([131.179.128.68]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ozWBO-00005g-CJ for bug-gnulib@gnu.org; Sun, 27 Nov 2022 23:55:57 -0500 Received: from localhost (localhost [127.0.0.1]) by zimbra.cs.ucla.edu (Postfix) with ESMTP id 5FA30160066 for ; Sun, 27 Nov 2022 20:55:53 -0800 (PST) Received: from zimbra.cs.ucla.edu ([127.0.0.1]) by localhost (zimbra.cs.ucla.edu [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id Hs5elcVkygXY; Sun, 27 Nov 2022 20:55:51 -0800 (PST) Received: from localhost (localhost [127.0.0.1]) by zimbra.cs.ucla.edu (Postfix) with ESMTP id 08E33160048; Sun, 27 Nov 2022 20:55:51 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.9.2 zimbra.cs.ucla.edu 08E33160048 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cs.ucla.edu; s=78364E5A-2AF3-11ED-87FA-8298ECA2D365; t=1669611351; bh=TIGte0ewkln+c+s6zZyc9LZ+tZ2aD4omEUe7cp4xKvY=; h=From:To:Subject:Date:Message-Id:MIME-Version: Content-Transfer-Encoding; b=kTaYKmTuyhCMA+8ueuoaaqU+CqEQW/9SKC/jB3xOq1xiwm681bLUON4mup2EKbJH/ 7R3wNjymPOfZZHR3CtCC1Alt3ezkEDLxUXOQ8Hq8Hw7pSGCNgbjRaGtX4QT4OrJztQ 5h0Hccd5mPql+1mugo5R4yxh75NgZGAxSAF4G3fA= X-Virus-Scanned: amavisd-new at zimbra.cs.ucla.edu Received: from zimbra.cs.ucla.edu ([127.0.0.1]) by localhost (zimbra.cs.ucla.edu [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id VxMBNw4RnX4m; Sun, 27 Nov 2022 20:55:50 -0800 (PST) Received: from localhost.localdomain (cpe-172-91-119-151.socal.res.rr.com [172.91.119.151]) by zimbra.cs.ucla.edu (Postfix) with ESMTPSA id C75CA160043; Sun, 27 Nov 2022 20:55:50 -0800 (PST) From: Paul Eggert To: bug-gnulib@gnu.org Cc: Paul Eggert Subject: [PROPOSED 1/4] memset_explicit: new module Date: Sun, 27 Nov 2022 20:55:40 -0800 Message-Id: <20221128045543.1355731-2-eggert@cs.ucla.edu> X-Mailer: git-send-email 2.37.2 In-Reply-To: <20221128045543.1355731-1-eggert@cs.ucla.edu> References: <20221128045543.1355731-1-eggert@cs.ucla.edu> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass client-ip=131.179.128.68; envelope-from=eggert@cs.ucla.edu; helo=zimbra.cs.ucla.edu X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, LONGWORDS=2.035, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: bug-gnulib@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gnulib discussion list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnulib-bounces+normalperson=yhbt.net@gnu.org Sender: bug-gnulib-bounces+normalperson=yhbt.net@gnu.org * doc/posix-functions/memset_explicit.texi, lib/memset_explicit.c: * m4/memset_explicit.m4, modules/memset_explicit: * modules/memset_explicit-tests, tests/test-memset_explicit.c: New files. * lib/string.in.h (memset_explict): New decl. * m4/string_h.m4 (gl_STRING_H, gl_STRING_H_REQUIRE_DEFAULTS) (gl_STRING_H_DEFAULTS): * modules/string (string.h): Support memset_explicit. --- ChangeLog | 11 ++ MODULES.html.sh | 8 + doc/gnulib.texi | 2 + doc/posix-functions/memset_explicit.texi | 43 +++++ lib/memset_explicit.c | 62 +++++++ lib/string.in.h | 17 ++ m4/memset_explicit.m4 | 20 +++ m4/string_h.m4 | 6 +- modules/memset_explicit | 31 ++++ modules/memset_explicit-tests | 14 ++ modules/string | 2 + tests/test-memset_explicit.c | 203 +++++++++++++++++++++++ 12 files changed, 417 insertions(+), 2 deletions(-) create mode 100644 doc/posix-functions/memset_explicit.texi create mode 100644 lib/memset_explicit.c create mode 100644 m4/memset_explicit.m4 create mode 100644 modules/memset_explicit create mode 100644 modules/memset_explicit-tests create mode 100644 tests/test-memset_explicit.c diff --git a/ChangeLog b/ChangeLog index 14283da87e..80f8d2c9cd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,16 @@ 2022-11-27 Paul Eggert =20 + memset_explicit: new module + * doc/posix-functions/memset_explicit.texi, lib/memset_explicit.c: + * m4/memset_explicit.m4, modules/memset_explicit: + * modules/memset_explicit-tests, tests/test-memset_explicit.c: + New files. + * lib/string.in.h (memset_explict): New decl. + * m4/string_h.m4 (gl_STRING_H, gl_STRING_H_REQUIRE_DEFAULTS) + (gl_STRING_H_DEFAULTS): + * modules/string (string.h): + Support memset_explicit. + explicit_bzero: add poison * m4/string_h.m4 (gl_STRING_H): Poison explicit_bzero. This was inadvertently omitted when explicit_bzero was added. diff --git a/MODULES.html.sh b/MODULES.html.sh index 02cfe32f06..7222459c69 100755 --- a/MODULES.html.sh +++ b/MODULES.html.sh @@ -2386,6 +2386,14 @@ func_all_modules () func_module stdckdint func_end_table =20 + element=3D"String handling " + element=3D`printf "%s" "$element" | sed -e "$sed_lt" -e "$sed_gt"` + func_section_wrap c23_ext_string + func_wrap H3 + func_echo "$element" + + func_module memset_explicit + element=3D"Support for GNU multiple precision arithmetic" func_section_wrap gmp func_wrap H2 diff --git a/doc/gnulib.texi b/doc/gnulib.texi index e1debc9742..eeb9b81f8a 100644 --- a/doc/gnulib.texi +++ b/doc/gnulib.texi @@ -1744,6 +1744,7 @@ problems are not worked around by Gnulib. * memcpy:: * memmove:: * memset:: +* memset_explicit:: * mkdir:: * mkdirat:: * mkdtemp:: @@ -3036,6 +3037,7 @@ problems are not worked around by Gnulib. @include posix-functions/memcpy.texi @include posix-functions/memmove.texi @include posix-functions/memset.texi +@include posix-functions/memset_explicit.texi @include posix-functions/mkdir.texi @include posix-functions/mkdirat.texi @include posix-functions/mkdtemp.texi diff --git a/doc/posix-functions/memset_explicit.texi b/doc/posix-functio= ns/memset_explicit.texi new file mode 100644 index 0000000000..528cee4e2b --- /dev/null +++ b/doc/posix-functions/memset_explicit.texi @@ -0,0 +1,43 @@ +@node memset_explicit +@subsection @code{memset_explicit} +@findex memset_explicit + +Documentation: +@itemize +@item +@ifinfo +@ref{Erasing Sensitive Data,,Erasing Sensitive Data,libc}, +@end ifinfo +@ifnotinfo +@url{https://www.gnu.org/software/libc/manual/html_node/Erasing-Sensitiv= e-Data.html}, +@end ifnotinfo +@c Not yet present: +@c @item +@c @uref{https://www.kernel.org/doc/man-pages/online/pages/man3/memset_e= xplicit.3.html,,man memset_explicit}. +@end itemize + +Gnulib module: memset_explicit + +The @code{memset_explicit} function is an approximation to what is +needed, and does not suffice in general to erase information. +Although calling @code{memset_explicit} should clear the memory in +question, the information that was in memory may still be available +elsewhere on the machine. Proper implementation of information +erasure requires support from levels below C code. + +Portability problems fixed by Gnulib: +@itemize +@item +This function is missing on some platforms: +glibc 2.36, FreeBSD 13.1, NetBSD 9.3, OpenBSD 7.2, macOS 13, Solaris 11.= 4, Android 13, +and many other systems. +@end itemize + +Portability problems not fixed by Gnulib: +@itemize +@item +Although the module's implementation should set the memory on +platforms compatible with GCC and on platforms using traditional +linkers, it may not set the memory on non-GCC platforms that use +whole-program optimization. +@end itemize diff --git a/lib/memset_explicit.c b/lib/memset_explicit.c new file mode 100644 index 0000000000..27fb16a9ba --- /dev/null +++ b/lib/memset_explicit.c @@ -0,0 +1,62 @@ +/* Erase sensitive data from memory. + Copyright 2022 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public Lice= nse + along with this program. If not, see = . */ + +#include + +/* memset_s need this define */ +#if HAVE_MEMSET_S +# define __STDC_WANT_LIB_EXT1__ 1 +#endif + +#include + +#if defined _WIN32 && !defined __CYGWIN__ +# define WIN32_LEAN_AND_MEAN +# include +#endif + +/* Set S's bytes to C, where S has LEN bytes. The compiler will not + optimize effects away, even if S is dead after the call. */ +void * +memset_explicit (void *s, int c, size_t len) +{ +#if defined _WIN32 && !defined __CYGWIN__ + if (!c) + return SecureZeroMemory (s, len); +#endif +#if HAVE_EXPLICIT_MEMSET + return explicit_memset (s, '\0', len); +#elif HAVE_MEMSET_S + (void) memset_s (s, len, '\0', len); + return s; +#elif defined __GNUC__ && !defined __clang__ + return memset (s, c, len); + /* Compiler barrier. */ + __asm__ volatile ("" ::: "memory"); +#elif defined __clang__ + return memset (s, c, len); + /* Compiler barrier. */ + /* With asm ("" ::: "memory") LLVM analyzes uses of 's' and finds that= the + whole thing is dead and eliminates it. Use 'g' to work around this + problem. See . = */ + __asm__ volatile ("" : : "g"(s) : "memory"); +#else + /* Invoke memset through a volatile function pointer. This defeats co= mpiler + optimizations. */ + void * (* const volatile volatile_memset) (void *, int, size_t) =3D me= mset; + return volatile_memset (s, c, len); +#endif +} diff --git a/lib/string.in.h b/lib/string.in.h index e56f6db0c9..21356914e2 100644 --- a/lib/string.in.h +++ b/lib/string.in.h @@ -347,6 +347,23 @@ _GL_WARN_ON_USE (memrchr, "memrchr is unportable - " # endif #endif =20 +/* Overwrite a block of memory. The compiler will not optimize + effects away, even if the block is dead after the call. */ +#if @GNULIB_MEMSET_EXPLICIT@ +# if ! @HAVE_MEMSET_EXPLICIT@ +_GL_FUNCDECL_SYS (memset_explicit, void *, + (void *__dest, int __c, size_t __n) _GL_ARG_NONNULL ((= 1))); +# endif +_GL_CXXALIAS_SYS (memset_explicit, void *, (void *__dest, int __c, size_= t __n)); +_GL_CXXALIASWARN (memset_explicit); +#elif defined GNULIB_POSIXCHECK +# undef memset_explicit +# if HAVE_RAW_DECL_MEMSET_EXPLICIT +_GL_WARN_ON_USE (memset_explicit, "memset_explicit is unportable - " + "use gnulib module memset_explicit for portability"); +# endif +#endif + /* Find the first occurrence of C in S. More efficient than memchr(S,C,N), at the expense of undefined behavior if C does not occur within N bytes. */ diff --git a/m4/memset_explicit.m4 b/m4/memset_explicit.m4 new file mode 100644 index 0000000000..3d4dcb3095 --- /dev/null +++ b/m4/memset_explicit.m4 @@ -0,0 +1,20 @@ +dnl Copyright 2022 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_MEMSET_EXPLICIT], +[ + AC_REQUIRE([gl_STRING_H_DEFAULTS]) + + AC_CHECK_FUNCS_ONCE([memset_explicit]) + if test $ac_cv_func_memset_explicit =3D no; then + HAVE_MEMSET_EXPLICIT=3D0 + fi +]) + +AC_DEFUN([gl_PREREQ_MEMSET_EXPLICIT], +[ + AC_CHECK_FUNCS([explicit_memset]) + AC_CHECK_FUNCS_ONCE([memset_s]) +]) diff --git a/m4/string_h.m4 b/m4/string_h.m4 index df44e85e59..6069d4a752 100644 --- a/m4/string_h.m4 +++ b/m4/string_h.m4 @@ -5,7 +5,7 @@ # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. =20 -# serial 34 +# serial 35 =20 # Written by Paul Eggert. =20 @@ -21,7 +21,7 @@ AC_DEFUN_ONCE([gl_STRING_H], dnl guaranteed by C89. gl_WARN_ON_USE_PREPARE([[#include ]], - [explicit_bzero ffsl ffsll memmem mempcpy memrchr + [explicit_bzero ffsl ffsll memmem mempcpy memrchr memset_explicit rawmemchr stpcpy stpncpy strchrnul strdup strncat strndup strnlen strpbrk strsep strcasestr strtok_r strerror_r strerrorname_np sigabbrev_np sigdescr_np strsignal strve= rscmp]) @@ -55,6 +55,7 @@ AC_DEFUN([gl_STRING_H_REQUIRE_DEFAULTS], gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MEMMEM]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MEMPCPY]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MEMRCHR]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MEMSET_EXPLICIT]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RAWMEMCHR]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STPCPY]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STPNCPY]) @@ -108,6 +109,7 @@ AC_DEFUN([gl_STRING_H_DEFAULTS], HAVE_FFSLL=3D1; AC_SUBST([HAVE_FFSLL]) HAVE_DECL_MEMMEM=3D1; AC_SUBST([HAVE_DECL_MEMMEM]) HAVE_MEMPCPY=3D1; AC_SUBST([HAVE_MEMPCPY]) + HAVE_MEMSET_EXPLICIT=3D1; AC_SUBST([HAVE_MEMSET_EXPLICIT]) HAVE_DECL_MEMRCHR=3D1; AC_SUBST([HAVE_DECL_MEMRCHR]) HAVE_RAWMEMCHR=3D1; AC_SUBST([HAVE_RAWMEMCHR]) HAVE_STPCPY=3D1; AC_SUBST([HAVE_STPCPY]) diff --git a/modules/memset_explicit b/modules/memset_explicit new file mode 100644 index 0000000000..3290bd3679 --- /dev/null +++ b/modules/memset_explicit @@ -0,0 +1,31 @@ +Description: +Erase sensitive data from memory. + +Files: +lib/memset_explicit.c +m4/memset_explicit.m4 + +Depends-on: +string + +configure.ac: +gl_FUNC_MEMSET_EXPLICIT +gl_CONDITIONAL([GL_COND_OBJ_MEMSET_EXPLICIT], [test $HAVE_MEMSET_EXPLICI= T =3D 0]) +AM_COND_IF([GL_COND_OBJ_MEMSET_EXPLICIT], [ + gl_PREREQ_MEMSET_EXPLICIT +]) +gl_STRING_MODULE_INDICATOR([memset_explicit]) + +Makefile.am: +if GL_COND_OBJ_MEMSET_EXPLICIT +lib_SOURCES +=3D memset_explicit.c +endif + +Include: + + +License: +LGPLv2+ + +Maintainer: +all diff --git a/modules/memset_explicit-tests b/modules/memset_explicit-test= s new file mode 100644 index 0000000000..3bb133fc11 --- /dev/null +++ b/modules/memset_explicit-tests @@ -0,0 +1,14 @@ +Files: +tests/test-memset_explicit.c +tests/signature.h +tests/macros.h + +Depends-on: +stdint +vma-iter + +configure.ac: + +Makefile.am: +TESTS +=3D test-memset_explicit +check_PROGRAMS +=3D test-memset_explicit diff --git a/modules/string b/modules/string index 6711ed74ab..70bf2b869f 100644 --- a/modules/string +++ b/modules/string @@ -55,6 +55,7 @@ string.h: string.in.h $(top_builddir)/config.status $(C= XXDEFS_H) $(ARG_NONNULL_H -e 's/@''GNULIB_MEMMEM''@/$(GNULIB_MEMMEM)/g' \ -e 's/@''GNULIB_MEMPCPY''@/$(GNULIB_MEMPCPY)/g' \ -e 's/@''GNULIB_MEMRCHR''@/$(GNULIB_MEMRCHR)/g' \ + -e 's/@''GNULIB_MEMSET_EXPLICIT''@/$(GNULIB_MEMSET_EXPLICIT)/g' \ -e 's/@''GNULIB_RAWMEMCHR''@/$(GNULIB_RAWMEMCHR)/g' \ -e 's/@''GNULIB_STPCPY''@/$(GNULIB_STPCPY)/g' \ -e 's/@''GNULIB_STPNCPY''@/$(GNULIB_STPNCPY)/g' \ @@ -86,6 +87,7 @@ string.h: string.in.h $(top_builddir)/config.status $(C= XXDEFS_H) $(ARG_NONNULL_H -e 's|@''HAVE_DECL_MEMMEM''@|$(HAVE_DECL_MEMMEM)|g' \ -e 's|@''HAVE_MEMPCPY''@|$(HAVE_MEMPCPY)|g' \ -e 's|@''HAVE_DECL_MEMRCHR''@|$(HAVE_DECL_MEMRCHR)|g' \ + -e 's|@''HAVE_MEMSET_EXPLICIT''@|$(HAVE_MEMSET_EXPLICIT)|g' \ -e 's|@''HAVE_RAWMEMCHR''@|$(HAVE_RAWMEMCHR)|g' \ -e 's|@''HAVE_STPCPY''@|$(HAVE_STPCPY)|g' \ -e 's|@''HAVE_STPNCPY''@|$(HAVE_STPNCPY)|g' \ diff --git a/tests/test-memset_explicit.c b/tests/test-memset_explicit.c new file mode 100644 index 0000000000..29d2730ac9 --- /dev/null +++ b/tests/test-memset_explicit.c @@ -0,0 +1,203 @@ +/* Test memset_explicit. + Copyright 2020-2022 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see = . */ + +/* Written by Bruno Haible , 2020. */ +/* Adapted for memset_explicit by Paul Eggert , 2022= . */ + +#include + +/* Specification. */ +#include + +#include "signature.h" +SIGNATURE_CHECK (memset_explicit, void, (void *, int, size_t)); + +#include +#include +#include +#include + +#include "vma-iter.h" +#include "macros.h" + +#define SECRET "xyzzy1729" +#define SECRET_SIZE 9 + +static char zero[SECRET_SIZE] =3D { 0 }; + +/* Enable this to verify that the test is effective. */ +#if 0 +# define memset_explicit(a, c, n) memset (a, c, n) +#endif + +/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Verify oper= ation on static memory =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D */ + +static char stbuf[SECRET_SIZE]; + +static void +test_static (void) +{ + memcpy (stbuf, SECRET, SECRET_SIZE); + memset_explicit (stbuf, 0, SECRET_SIZE); + ASSERT (memcmp (zero, stbuf, SECRET_SIZE) =3D=3D 0); + for (int i =3D 1; i <=3D UCHAR_MAX; i++) + { + char checkbuf[SECRET_SIZE]; + memset (checkbuf, i, SECRET_SIZE); + memset_explicit (stbuf, i, SECRET_SIZE); + ASSERT (memcmp (checkbuf, stbuf, SECRET_SIZE) =3D=3D 0); + } +} + +/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Verify operation on hea= p-allocated memory =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D */ + +/* Test whether an address range is mapped in memory. */ +#if VMA_ITERATE_SUPPORTED + +struct locals +{ + uintptr_t range_start; + uintptr_t range_end; +}; + +static int +vma_iterate_callback (void *data, uintptr_t start, uintptr_t end, + unsigned int flags) +{ + struct locals *lp =3D (struct locals *) data; + + /* Remove from [range_start, range_end) the part at the beginning or a= t the + end that is covered by [start, end). */ + if (start <=3D lp->range_start && end > lp->range_start) + lp->range_start =3D (end < lp->range_end ? end : lp->range_end); + if (start < lp->range_end && end >=3D lp->range_end) + lp->range_end =3D (start > lp->range_start ? start : lp->range_start= ); + + return 0; +} + +static bool +is_range_mapped (uintptr_t range_start, uintptr_t range_end) +{ + struct locals l; + + l.range_start =3D range_start; + l.range_end =3D range_end; + vma_iterate (vma_iterate_callback, &l); + return l.range_start =3D=3D l.range_end; +} + +#else + +static bool +is_range_mapped (uintptr_t range_start, uintptr_t range_end) +{ + return true; +} + +#endif + +static void +test_heap (void) +{ + char *heapbuf =3D (char *) malloc (SECRET_SIZE); + ASSERT (heapbuf); + uintptr_t volatile addr =3D (uintptr_t) heapbuf; + memcpy (heapbuf, SECRET, SECRET_SIZE); + memset_explicit (heapbuf, 0, SECRET_SIZE); + free (heapbuf); + heapbuf =3D (char *) addr; + if (is_range_mapped (addr, addr + SECRET_SIZE)) + { + /* some implementation could override freed memory by canaries so + compare against secret */ + ASSERT (memcmp (heapbuf, SECRET, SECRET_SIZE) !=3D 0); + printf ("test_heap: address range is still mapped after free().\n"= ); + } + else + printf ("test_heap: address range is unmapped after free().\n"); +} + +/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Verify operation on sta= ck-allocated memory =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D */ + +/* There are two passes: + 1. Put a secret in memory and invoke memset_explicit on it. + 2. Verify that the memory has been erased. + Implement them in the same function, so that they access the same mem= ory + range on the stack. Declare the local scalars to be volatile so they + are not optimized away. That way, the test verifies that the compile= r + does not eliminate a call to memset_explicit, even if data flow analy= sis + reveals that the stack area is dead at the end of the function. */ +static bool _GL_ATTRIBUTE_NOINLINE +do_secret_stuff (int volatile pass, char *volatile *volatile last_stackb= uf) +{ + char stackbuf[SECRET_SIZE]; + if (pass =3D=3D 1) + { + memcpy (stackbuf, SECRET, SECRET_SIZE); + memset_explicit (stackbuf, 0, SECRET_SIZE); + *last_stackbuf =3D stackbuf; + return false; + } + else /* pass =3D=3D 2 */ + { + /* Use *last_stackbuf here, because stackbuf may be allocated at a + different address than *last_stackbuf. This can happen + when the compiler splits this function into different functions= , + one for pass =3D=3D 1 and one for pass !=3D 1. */ + return memcmp (zero, *last_stackbuf, SECRET_SIZE) !=3D 0; + } +} + +static void +test_stack (void) +{ + int count =3D 0; + int repeat; + char *volatile last_stackbuf; + + for (repeat =3D 2 * 1000; repeat > 0; repeat--) + { + /* This odd way of writing two consecutive statements + do_secret_stuff (1, &last_stackbuf); + count +=3D do_secret_stuff (2, &last_stackbuf); + ensures that the two do_secret_stuff calls are performed with t= he same + stack pointer value, on m68k. */ + if ((repeat % 2) =3D=3D 0) + do_secret_stuff (1, &last_stackbuf); + else + count +=3D do_secret_stuff (2, &last_stackbuf); + } + /* If memset_explicit works, count is near 0. (It may be > 0 if there= were + some asynchronous signal invocations between the two calls of + do_secret_stuff.) + If memset_explicit is optimized away by the compiler, count comes o= ut as + approximately 1000. */ + printf ("test_stack: count =3D %d\n", count); + ASSERT (count < 50); +} + +/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D */ + +int +main () +{ + test_static (); + test_heap (); + test_stack (); + + return 0; +} --=20 2.37.2