The branch, master has been updated
       via  f3b380b8a38 lib:replace: Remove memset_s()
       via  3e81b73a050 Replace memset_s() with memset_explicit()
       via  2b17c9816d4 lib:replace: Add test for memset_explicit()
       via  ef08be24e91 lib:replace: Implement memset_explicit()
       via  a96cfa3025e lib:replace: Remove trailing spaces in README
      from  0835fe53cc7 lib: Introduce cp_smb_basename() helper function

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit f3b380b8a3866286244725903287211cf54a4e74
Author: Andreas Schneider <[email protected]>
Date:   Thu Oct 16 11:22:46 2025 +0200

    lib:replace: Remove memset_s()
    
    Signed-off-by: Andreas Schneider <[email protected]>
    Reviewed-by: Douglas Bagnall <[email protected]>
    
    Autobuild-User(master): Andreas Schneider <[email protected]>
    Autobuild-Date(master): Tue Nov 11 14:51:45 UTC 2025 on atb-devel-224

commit 3e81b73a050e511c658afc786478431ceef175ee
Author: Andreas Schneider <[email protected]>
Date:   Thu Oct 16 11:19:51 2025 +0200

    Replace memset_s() with memset_explicit()
    
    Signed-off-by: Andreas Schneider <[email protected]>
    Reviewed-by: Douglas Bagnall <[email protected]>

commit 2b17c9816d4373eba365de803eec10435ea038d4
Author: Douglas Bagnall <[email protected]>
Date:   Thu Oct 30 16:01:36 2025 +0100

    lib:replace: Add test for memset_explicit()
    
    Signed-off-by: Douglas Bagnall <[email protected]>
    Reviewed-by: Andreas Schneider <[email protected]>

commit ef08be24e9114b4477cc2b3f7a28a816ec66802c
Author: Andreas Schneider <[email protected]>
Date:   Thu Oct 16 11:06:56 2025 +0200

    lib:replace: Implement memset_explicit()
    
    The memset_s() implementation is a bit obscure, as it requires a
    constraint handler to be set up. You don't really find any
    implmentations out there.
    
    With C23 memset_explicit() was added and this has been implemented
    for glibc 2.43 and also in FreeBSD.
    
    See https://sourceware.org/bugzilla/show_bug.cgi?id=32378
    See https://reviews.freebsd.org/D47286
    
    Signed-off-by: Andreas Schneider <[email protected]>
    Reviewed-by: Douglas Bagnall <[email protected]>

commit a96cfa3025e58c48c16661f983b86e5bad931fb6
Author: Andreas Schneider <[email protected]>
Date:   Thu Oct 16 11:09:29 2025 +0200

    lib:replace: Remove trailing spaces in README
    
    Signed-off-by: Andreas Schneider <[email protected]>
    Reviewed-by: Douglas Bagnall <[email protected]>

-----------------------------------------------------------------------

Summary of changes:
 lib/replace/README                       | 10 ++--
 lib/replace/replace.c                    | 34 +++--------
 lib/replace/replace.h                    | 24 ++++----
 lib/replace/tests/test_memset_explicit.c | 99 ++++++++++++++++++++++++++++++++
 lib/replace/wscript                      |  7 ++-
 lib/talloc/talloc.c                      |  2 +-
 lib/util/memory.h                        | 16 +++---
 lib/util/tests/test_talloc_keep_secret.c | 19 +++---
 selftest/tests.py                        |  6 ++
 third_party/heimdal_build/roken.h        |  4 --
 third_party/heimdal_build/wscript_build  |  5 ++
 11 files changed, 159 insertions(+), 67 deletions(-)
 create mode 100644 lib/replace/tests/test_memset_explicit.c


Changeset truncated at 500 lines:

diff --git a/lib/replace/README b/lib/replace/README
index d9155aa7b99..d5972657857 100644
--- a/lib/replace/README
+++ b/lib/replace/README
@@ -1,7 +1,7 @@
-This subsystem ensures that we can always use a certain core set of 
-functions and types, that are either provided by the OS or by replacement 
-functions / definitions in this subsystem. The aim is to try to stick 
-to POSIX functions in here as much as possible. Convenience functions 
+This subsystem ensures that we can always use a certain core set of
+functions and types, that are either provided by the OS or by replacement
+functions / definitions in this subsystem. The aim is to try to stick
+to POSIX functions in here as much as possible. Convenience functions
 that are available on no platform at all belong in other subsystems
 (such as LIBUTIL).
 
@@ -72,7 +72,7 @@ symlink
 realpath
 poll
 setproctitle
-memset_s
+memset_explicit
 
 Types:
 bool
diff --git a/lib/replace/replace.c b/lib/replace/replace.c
index e8ff9908322..dd07e6c3da5 100644
--- a/lib/replace/replace.c
+++ b/lib/replace/replace.c
@@ -1131,36 +1131,18 @@ void rep_setproctitle_init(int argc, char *argv[], char 
*envp[])
 }
 #endif
 
-#ifndef HAVE_MEMSET_S
-# ifndef RSIZE_MAX
-#  define RSIZE_MAX (SIZE_MAX >> 1)
-# endif
-
-int rep_memset_s(void *dest, size_t destsz, int ch, size_t count)
+#ifndef HAVE_MEMSET_EXPLICIT
+void *rep_memset_explicit(void *block, int c, size_t size)
 {
-       if (dest == NULL) {
-               return EINVAL;
-       }
-
-       if (destsz > RSIZE_MAX ||
-           count > RSIZE_MAX ||
-           count > destsz) {
-               return ERANGE;
-       }
-
-#if defined(HAVE_MEMSET_EXPLICIT)
-       memset_explicit(dest, ch, count);
-#else /* HAVE_MEMSET_EXPLICIT */
-       memset(dest, ch, count);
-# if defined(HAVE_GCC_VOLATILE_MEMORY_PROTECTION)
+       void *ptr = memset(block, c, size);
+#ifdef HAVE_GCC_VOLATILE_MEMORY_PROTECTION
        /* See http://llvm.org/bugs/show_bug.cgi?id=15495 */
-       __asm__ volatile("" : : "g"(dest) : "memory");
-# endif /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */
-#endif /* HAVE_MEMSET_EXPLICIT */
+       __asm__ volatile("" : : "g"(block) : "memory");
+#endif /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */
 
-       return 0;
+       return ptr;
 }
-#endif /* HAVE_MEMSET_S */
+#endif
 
 #ifndef HAVE_GETPROGNAME
 # ifndef HAVE_PROGRAM_INVOCATION_SHORT_NAME
diff --git a/lib/replace/replace.h b/lib/replace/replace.h
index 4923e1f301d..49757e0f60d 100644
--- a/lib/replace/replace.h
+++ b/lib/replace/replace.h
@@ -811,50 +811,50 @@ typedef unsigned long long ptrdiff_t ;
 /**
  * Zero a structure.
  */
-#define ZERO_STRUCT(x) memset_s((char *)&(x), sizeof(x), 0, sizeof(x))
+#define ZERO_STRUCT(x) memset_explicit((char *)&(x), 0, sizeof(x))
 
 /**
  * Zero a structure given a pointer to the structure.
  */
 #define ZERO_STRUCTP(x) do { \
        if ((x) != NULL) { \
-               memset_s((char *)(x), sizeof(*(x)), 0, sizeof(*(x))); \
+               memset_explicit((char *)(x), 0, sizeof(*(x))); \
        } \
 } while(0)
 
 /**
  * Zero a structure given a pointer to the structure - no zero check
  */
-#define ZERO_STRUCTPN(x) memset_s((char *)(x), sizeof(*(x)), 0, sizeof(*(x)))
+#define ZERO_STRUCTPN(x) memset_explicit((char *)(x), 0, sizeof(*(x)))
 
 /**
  * Zero an array - note that sizeof(array) must work - ie. it must not be a
  * pointer
  */
-#define ZERO_ARRAY(x) memset_s((char *)(x), sizeof(x), 0, sizeof(x))
+#define ZERO_ARRAY(x) memset_explicit((char *)(x), 0, sizeof(x))
 
 /**
  * Zero a given len of an array
  */
-#define ZERO_ARRAY_LEN(x, l) memset_s((char *)(x), (l), 0, (l))
+#define ZERO_ARRAY_LEN(x, l) memset_explicit((char *)(x), 0, (l))
 
 /**
  * Explicitly zero data from memory. This is guaranteed to be not optimized
  * away.
  */
-#define BURN_DATA(x) memset_s((char *)&(x), sizeof(x), 0, sizeof(x))
+#define BURN_DATA(x) memset_explicit((char *)&(x), 0, sizeof(x))
 
 /**
  * Explicitly zero data from memory. This is guaranteed to be not optimized
  * away.
  */
-#define BURN_DATA_SIZE(x, s) memset_s((char *)&(x), (s), 0, (s))
+#define BURN_DATA_SIZE(x, s) memset_explicit((char *)&(x), 0, (s))
 
 /**
  * Explicitly zero data from memory. This is guaranteed to be not optimized
  * away.
  */
-#define BURN_PTR_SIZE(x, s) memset_s((x), (s), 0, (s))
+#define BURN_PTR_SIZE(x, s) memset_explicit((x), 0, (s))
 
 /**
  * Explicitly zero data in string. This is guaranteed to be not optimized
@@ -863,7 +863,7 @@ typedef unsigned long long ptrdiff_t ;
 #define BURN_STR(x)    do { \
                                if ((x) != NULL) { \
                                        size_t s = strlen(x); \
-                                       memset_s((x), s, 0, s); \
+                                       memset_explicit((x), 0, s); \
                                } \
                        } while(0)
 
@@ -990,9 +990,9 @@ void rep_setproctitle(const char *fmt, ...) 
PRINTF_ATTRIBUTE(1, 2);
 void rep_setproctitle_init(int argc, char *argv[], char *envp[]);
 #endif
 
-#ifndef HAVE_MEMSET_S
-#define memset_s rep_memset_s
-int rep_memset_s(void *dest, size_t destsz, int ch, size_t count);
+#ifndef HAVE_MEMSET_EXPLICIT
+#define memset_explicit rep_memset_explicit
+void *rep_memset_explicit(void *block, int c, size_t size);
 #endif
 
 #ifndef HAVE_GETPROGNAME
diff --git a/lib/replace/tests/test_memset_explicit.c 
b/lib/replace/tests/test_memset_explicit.c
new file mode 100644
index 00000000000..4e56d7a9aee
--- /dev/null
+++ b/lib/replace/tests/test_memset_explicit.c
@@ -0,0 +1,99 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "lib/replace/replace.h"
+
+
+/*
+ * To check that a memset_explicit string is being memset when it
+ * appears unused, we meed to be sneaky in our check -- otherwise the
+ * check counts as a use.
+ *
+ * We are sneaky by using a function that seens to take an int
+ * argument which is really a pointer, and we hide that it is a
+ * pointer by masking it.
+ *
+ * For these tests we don't use talloc because the talloc magic gets
+ * in the way a little bit.
+ */
+
+#define MASK 0x12345678
+
+__attribute__((noinline))
+static void check_memset_explicit(intmax_t p, const char *expected, size_t len)
+{
+       size_t i;
+       char *secret = (char *) (p ^ MASK);
+       for (i = 0; i < len; i++) {
+               assert_int_equal(secret[i], expected[i]);
+       }
+}
+
+
+__attribute__((noinline))
+static char *get_secret(off_t offset)
+{
+       char * secret = malloc(7 + offset);
+       memset(secret, 0, 7 + offset);
+       memcpy(secret + offset, "secret", 7);
+       /* avoiding *this* being elided */
+       print_message("secret is '%s'\n", secret);
+       asm("");
+       return secret;
+}
+
+
+static void test_memset_explicit(void ** state)
+{
+       uintptr_t p;
+       char zeros[7] = {0};
+       char *secret = get_secret(0);
+       p = ((uintptr_t)secret) ^ MASK;
+       memset_explicit(secret, 'o', 3);
+       check_memset_explicit(p, "oooret", 7);
+       memset_explicit(secret, 0, 7);
+       check_memset_explicit(p, zeros, 7);
+       free(secret);
+}
+
+static void test_memset_explicit_double_alloc(void ** state)
+{
+       size_t i, found;
+       uintptr_t p, q;
+       char *secret = get_secret(20);
+       p = (uintptr_t)secret ^ MASK;
+       memset_explicit(secret, 'x', 23);
+       free(secret);
+       /*
+        * Now we malloc the same size again, and hope we got the
+        * block we just freed.
+        */
+       found = 0;
+       for (i = 0; i < 1000; i++) {
+               secret = malloc(27);
+               q = (uintptr_t)secret ^ MASK;
+               if (q == p) {
+                       q = (uintptr_t)(secret + 20) ^ MASK;
+                       check_memset_explicit(q, "xxxret", 7);
+                       found ++;
+               }
+               free(secret);
+       }
+       print_message("found freed pointer %zu/1000 times \n",
+               found);
+}
+
+int main(void)
+{
+       const struct CMUnitTest tests[] = {
+               cmocka_unit_test(test_memset_explicit),
+               cmocka_unit_test(test_memset_explicit_double_alloc),
+       };
+       if (! isatty(1)) {
+               cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+       }
+       return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/lib/replace/wscript b/lib/replace/wscript
index e351b5d19f2..4621d90a70a 100644
--- a/lib/replace/wscript
+++ b/lib/replace/wscript
@@ -890,7 +890,7 @@ REPLACEMENT_FUNCTIONS = {
                   'utime', 'utimes', 'dup2', 'chown', 'link', 'readlink',
                   'symlink', 'lchown', 'realpath', 'memmem', 'vdprintf',
                   'dprintf', 'get_current_dir_name', 'copy_file_range',
-                  'strerror_r', 'clock_gettime', 'memset_s'],
+                  'strerror_r', 'clock_gettime', 'memset_explicit'],
     'timegm.c': ['timegm'],
     # Note: C99_VSNPRINTF is not a function, but a special condition
     # for replacement
@@ -973,6 +973,11 @@ def build(bld):
                      deps='replace replace-test',
                      install=False)
 
+    bld.SAMBA_BINARY('test_memset_explicit',
+                     source='tests/test_memset_explicit.c',
+                     deps='cmocka replace',
+                     for_selftest=True)
+
     # build replacements for stdint.h and stdbool.h if needed
     bld.SAMBA_GENERATOR('replace_stdint_h',
                         rule='cp ${SRC} ${TGT}',
diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index ac3d26fcb52..2f13a2c64a9 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -2837,7 +2837,7 @@ _PUBLIC_ void *_talloc_realloc_array_zero(const void *ctx,
 
        if (newsize > existing) {
                size_t to_zero = newsize - existing;
-               memset_s(((char *)newptr) + existing, to_zero, 0, to_zero);
+               memset_explicit(((char *)newptr) + existing, 0, to_zero);
        }
 
        return newptr;
diff --git a/lib/util/memory.h b/lib/util/memory.h
index 40c66d824a1..ff51a6ebe49 100644
--- a/lib/util/memory.h
+++ b/lib/util/memory.h
@@ -40,7 +40,7 @@
 #define BURN_FREE_STR(x) do { \
                                if ((x) != NULL) { \
                                        size_t s = strlen(x); \
-                                       memset_s((x), s, 0, s); \
+                                       memset_explicit((x), 0, s); \
                                        free(x); (x) = NULL; \
                                } \
                        } while(0)
@@ -53,7 +53,7 @@
  **/
 #define BURN_FREE(x, s) do { \
                                if ((x) != NULL) { \
-                                       memset_s((x), (s), 0, (s)); \
+                                       memset_explicit((x), 0, (s)); \
                                        free(x); (x) = NULL; \
                                } \
                        } while(0)
@@ -78,7 +78,7 @@
  * Zero a structure.
  */
 #ifndef ZERO_STRUCT
-#define ZERO_STRUCT(x) memset_s((char *)&(x), sizeof(x), 0, sizeof(x))
+#define ZERO_STRUCT(x) memset_explicit((char *)&(x), 0, sizeof(x))
 #endif
 
 /**
@@ -87,7 +87,7 @@
 #ifndef ZERO_STRUCTP
 #define ZERO_STRUCTP(x) do { \
        if ((x) != NULL) { \
-               memset_s((char *)(x), sizeof(*(x)), 0, sizeof(*(x))); \
+               memset_explicit((char *)(x), 0, sizeof(*(x))); \
        } \
 } while(0)
 #endif
@@ -96,7 +96,7 @@
  * Zero a structure given a pointer to the structure - no zero check.
  */
 #ifndef ZERO_STRUCTPN
-#define ZERO_STRUCTPN(x) memset_s((char *)(x), sizeof(*(x)), 0, sizeof(*(x)))
+#define ZERO_STRUCTPN(x) memset_explicit((char *)(x), 0, sizeof(*(x)))
 #endif
 
 /**
@@ -104,13 +104,15 @@
  * pointer.
  */
 #ifndef ZERO_ARRAY
-#define ZERO_ARRAY(x) memset_s((char *)(x), sizeof(x), 0, sizeof(x))
+#define ZERO_ARRAY(x) memset_explicit((char *)(x), 0, sizeof(x))
 #endif
 
 /**
  * Zero a given len of an array
  */
-#define ZERO_ARRAY_LEN(x, l) memset_s((char *)(x), (l), 0, (l))
+#ifndef ZERO_ARRAY_LEN
+#define ZERO_ARRAY_LEN(x, l) memset_explicit((char *)(x), 0, (l))
+#endif
 
 /**
  * Work out how many elements there are in a static array
diff --git a/lib/util/tests/test_talloc_keep_secret.c 
b/lib/util/tests/test_talloc_keep_secret.c
index 1462dabe956..66c3f7f3e7a 100644
--- a/lib/util/tests/test_talloc_keep_secret.c
+++ b/lib/util/tests/test_talloc_keep_secret.c
@@ -8,12 +8,11 @@
 #include <talloc.h>
 #include "lib/util/talloc_keep_secret.h"
 
-int rep_memset_s(void *dest, size_t destsz, int ch, size_t count);
+int rep_memset_explicit(void *dest, int ch, size_t count);
 
-int rep_memset_s(void *dest, size_t destsz, int ch, size_t count)
+int rep_memset_explicit(void *dest, int ch, size_t count)
 {
        check_expected_ptr(dest);
-       check_expected(destsz);
        check_expected(ch);
        check_expected(count);
 
@@ -44,10 +43,9 @@ static void test_talloc_keep_secret(void ** state)
        ptr1_size = talloc_get_size(ptr1);
        assert_int_equal(ptr1_size, strlen(ptr1) + 1);
 
-       expect_string(rep_memset_s, dest, "secret");
-       expect_value(rep_memset_s, destsz, strlen(ptr1) + 1);
-       expect_value(rep_memset_s, ch, (int)'\0');
-       expect_value(rep_memset_s, count, strlen(ptr1) + 1);
+       expect_string(rep_memset_explicit, dest, "secret");
+       expect_value(rep_memset_explicit, ch, (int)'\0');
+       expect_value(rep_memset_explicit, count, strlen(ptr1) + 1);
 
        talloc_free(ptr1);
 
@@ -73,10 +71,9 @@ static void test_talloc_keep_secret_validate_memset(void 
**state)
        assert_non_null(password);
        talloc_keep_secret(password);
 
-       expect_string(rep_memset_s, dest, "secret");
-       expect_value(rep_memset_s, destsz, strlen(password) + 1);
-       expect_value(rep_memset_s, ch, (int)'\0');
-       expect_value(rep_memset_s, count, strlen(password) + 1);
+       expect_string(rep_memset_explicit, dest, "secret");
+       expect_value(rep_memset_explicit, ch, (int)'\0');
+       expect_value(rep_memset_explicit, count, strlen(password) + 1);
 
        talloc_free(mem_ctx);
 }
diff --git a/selftest/tests.py b/selftest/tests.py
index f466dbb9fee..4838bfd176f 100644
--- a/selftest/tests.py
+++ b/selftest/tests.py
@@ -543,6 +543,12 @@ plantestsuite("samba.unittests.smb1cli_session", "none",
 plantestsuite("samba.unittests.smb_util_translate", "none",
               [os.path.join(bindir(), 
"default/libcli/smb/test_util_translate")])
 
+plantestsuite(
+    "samba.unittests.memset_explicit",
+    "none",
+    [os.path.join(bindir(), "default/lib/replace/test_memset_explicit")],
+)
+
 plantestsuite("samba.unittests.talloc_keep_secret", "none",
               [os.path.join(bindir(), 
"default/lib/util/test_talloc_keep_secret")])
 
diff --git a/third_party/heimdal_build/roken.h 
b/third_party/heimdal_build/roken.h
index 38706099c99..4740a3d2d01 100644
--- a/third_party/heimdal_build/roken.h
+++ b/third_party/heimdal_build/roken.h
@@ -123,10 +123,6 @@
 #define HAVE_SETEUID
 #endif
 
-#ifndef HAVE_MEMSET_S
-#define HAVE_MEMSET_S
-#endif
-
 #ifndef HAVE_DIRFD
 #ifdef HAVE_DIR_DD_FD
 #define dirfd(x) ((x)->dd_fd)
diff --git a/third_party/heimdal_build/wscript_build 
b/third_party/heimdal_build/wscript_build
index 801f3277f41..ebbf9431e9a 100644
--- a/third_party/heimdal_build/wscript_build
+++ b/third_party/heimdal_build/wscript_build
@@ -375,6 +375,11 @@ if not bld.CONFIG_SET('USING_SYSTEM_ROKEN'):
         lib/roken/getuserinfo.c
     '''
 
+    if not bld.CONFIG_SET('HAVE_MEMSET_S'):
+        ROKEN_SOURCE += '''
+            lib/roken/memset_s.c
+        '''
+
     HEIMDAL_LIBRARY('roken',
         ROKEN_SOURCE,
         includes='../heimdal/lib/roken ../heimdal/include 
../heimdal_build/include',


-- 
Samba Shared Repository

Reply via email to