From ad9bf2a0d7e99d49fae62117b285566192d0f073 Mon Sep 17 00:00:00 2001 From: Alejandro Colomar Date: Sun, 14 Dec 2025 16:17:28 +0100 Subject: [PATCH 1/6] lib/memory/memcpy/: memmove_T(): Add API An interesting detail is that we require the second argument to be non-const, while the memmove(3) function gets a const void*. This is because the second argument should usually be just the same as the first one, plus some offset, and thus will have the same const qualification (that is, it will not be qualified). Don't return anything, as we're not using the return value. That avoids having to use a cast (we can't use a compound literal because of -Werror=unused-value). Signed-off-by: Alejandro Colomar --- lib/Makefile.am | 2 ++ lib/memory/memcpy/memmove.c | 7 +++++++ lib/memory/memcpy/memmove.h | 26 ++++++++++++++++++++++++++ lib/string/README | 3 +++ 4 files changed, 38 insertions(+) create mode 100644 lib/memory/memcpy/memmove.c create mode 100644 lib/memory/memcpy/memmove.h diff --git a/lib/Makefile.am b/lib/Makefile.am index d709345986..5f9090c61b 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -115,6 +115,8 @@ libshadow_la_SOURCES = \ lockpw.c \ loginprompt.c \ mail.c \ + memory/memcpy/memmove.c \ + memory/memcpy/memmove.h \ motd.c \ myname.c \ nss.c \ diff --git a/lib/memory/memcpy/memmove.c b/lib/memory/memcpy/memmove.c new file mode 100644 index 0000000000..44be00d303 --- /dev/null +++ b/lib/memory/memcpy/memmove.c @@ -0,0 +1,7 @@ +// SPDX-FileCopyrightText: 2025-2026, Alejandro Colomar +// SPDX-License-Identifier: BSD-3-Clause + + +#include "config.h" + +#include "memory/memcpy/memmove.h" diff --git a/lib/memory/memcpy/memmove.h b/lib/memory/memcpy/memmove.h new file mode 100644 index 0000000000..68d7867eef --- /dev/null +++ b/lib/memory/memcpy/memmove.h @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: 2025-2026, Alejandro Colomar +// SPDX-License-Identifier: BSD-3-Clause + + +#ifndef SHADOW_INCLUDE_LIB_MEMORY_MEMCPY_MEMMOVE_H_ +#define SHADOW_INCLUDE_LIB_MEMORY_MEMCPY_MEMMOVE_H_ + + +#include "config.h" + +#include + +#include "sizeof.h" + + +// memmove_T - memory move type-safe +#define memmove_T(dst, src, n, T) memmove_T_(dst, src, n, typeas(T)) +#define memmove_T_(dst, src, n, T) do \ +{ \ + _Generic(dst, T *: (void)0); \ + _Generic(src, T *: (void)0); \ + memmove(dst, src, (n) * sizeof(T)); \ +} while (0) + + +#endif // include guard diff --git a/lib/string/README b/lib/string/README index 70274d71de..8f141c658c 100644 --- a/lib/string/README +++ b/lib/string/README @@ -208,6 +208,9 @@ strcpy/ - String copying MEMCPY() Like memcpy(3), but takes two arrays. + memmove_T() + Like memmove(3), but type safe. + sprintf/ - Formatted string creation aprintf(3) From 7d370dcbf9ebd0ba44206bfe8ce59abac396d2bb Mon Sep 17 00:00:00 2001 From: Alejandro Colomar Date: Sun, 14 Dec 2025 16:47:20 +0100 Subject: [PATCH 2/6] lib/string/strcpy/: strmove(): Add function Signed-off-by: Alejandro Colomar --- lib/Makefile.am | 2 ++ lib/string/README | 4 ++++ lib/string/strcpy/strmove.c | 10 ++++++++++ lib/string/strcpy/strmove.h | 29 +++++++++++++++++++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 lib/string/strcpy/strmove.c create mode 100644 lib/string/strcpy/strmove.h diff --git a/lib/Makefile.am b/lib/Makefile.am index 5f9090c61b..a0a5d82a69 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -225,6 +225,8 @@ libshadow_la_SOURCES = \ string/strcmp/strprefix.h \ string/strcpy/stpecpy.c \ string/strcpy/stpecpy.h \ + string/strcpy/strmove.c \ + string/strcpy/strmove.h \ string/strcpy/strncat.c \ string/strcpy/strncat.h \ string/strcpy/strncpy.c \ diff --git a/lib/string/README b/lib/string/README index 8f141c658c..3db238669e 100644 --- a/lib/string/README +++ b/lib/string/README @@ -186,6 +186,10 @@ strcpy/ - String copying Do NOT use. I'll remove it soon. s/ + strmove() + Like memmove(3), for strings. It takes the length of the string + internally with strlen(3). + strtcpy() Copy from a string into another string with truncation. This is what the Linux kernel calls strscpy(). diff --git a/lib/string/strcpy/strmove.c b/lib/string/strcpy/strmove.c new file mode 100644 index 0000000000..5618f7796b --- /dev/null +++ b/lib/string/strcpy/strmove.c @@ -0,0 +1,10 @@ +// SPDX-FileCopyrightText: 2025-2026, Alejandro Colomar +// SPDX-License-Identifier: BSD-3-Clause + + +#include "config.h" + +#include "string/strcpy/strmove.h" + + +extern inline void strmove(char *dst, char *src); diff --git a/lib/string/strcpy/strmove.h b/lib/string/strcpy/strmove.h new file mode 100644 index 0000000000..299445852c --- /dev/null +++ b/lib/string/strcpy/strmove.h @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2025-2026, Alejandro Colomar +// SPDX-License-Identifier: BSD-3-Clause + + +#ifndef SHADOW_INCLUDE_LIB_STRING_STRCPY_STRMOVE_H_ +#define SHADOW_INCLUDE_LIB_STRING_STRCPY_STRMOVE_H_ + + +#include "config.h" + +#include + +#include "attr.h" +#include "memory/memcpy/memmove.h" + + +ATTR_STRING(2) +inline void strmove(char *dst, char *src); + + +// strmove - string move +inline void +strmove(char *dst, char *src) +{ + memmove_T(dst, src, strlen(src) + 1, char); +} + + +#endif // include guard From f32d45cd08e8cf99e9917a78db0537d8f521ba3d Mon Sep 17 00:00:00 2001 From: Alejandro Colomar Date: Sun, 14 Dec 2025 16:49:28 +0100 Subject: [PATCH 3/6] src/usermod.c: new_pw_passwd(): Use strmove() instead of its pattern Signed-off-by: Alejandro Colomar --- src/usermod.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/usermod.c b/src/usermod.c index bd9dc82c64..2a98ef5004 100644 --- a/src/usermod.c +++ b/src/usermod.c @@ -65,6 +65,7 @@ #include "string/sprintf/aprintf.h" #include "string/strcmp/streq.h" #include "string/strcmp/strprefix.h" +#include "string/strcpy/strmove.h" #include "string/strdup/strdup.h" #include "string/strspn/stprspn.h" #include "sysconf.h" @@ -489,7 +490,7 @@ new_pw_passwd(char *pw_pass, bool process_selinux) "updating-password", user_newname, user_newid, 1); #endif SYSLOG(LOG_INFO, "unlock user '%s' password", user_newname); - memmove(pw_pass, pw_pass + 1, strlen(pw_pass)); + strmove(pw_pass, pw_pass + 1); } else if (pflg) { #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, From b7c4823ac9567ab2fe4aec932be94688d2b68a05 Mon Sep 17 00:00:00 2001 From: Alejandro Colomar Date: Sun, 14 Dec 2025 13:46:30 +0100 Subject: [PATCH 4/6] lib/list.c: add_list(): Use realloc(3) instead of its pattern Signed-off-by: Alejandro Colomar --- lib/list.c | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/lib/list.c b/lib/list.c index bafcd14618..5340203d00 100644 --- a/lib/list.c +++ b/lib/list.c @@ -9,6 +9,7 @@ #include "config.h" #include "alloc/malloc.h" +#include "alloc/realloc.h" #include "prototypes.h" #include "defines.h" #include "string/strchr/strchrcnt.h" @@ -22,16 +23,11 @@ /* * add_list - add a member to a list of group members - * - * the array of member names is searched for the new member - * name, and if not present it is added to a freshly allocated - * list of users. */ /*@only@*/char ** add_list(/*@returned@*/ /*@only@*/char **list, const char *member) { int i; - char **tmp; assert (NULL != member); assert (NULL != list); @@ -40,36 +36,17 @@ add_list(/*@returned@*/ /*@only@*/char **list, const char *member) * Scan the list for the new name. Return the original list * pointer if it is present. */ - for (i = 0; list[i] != NULL; i++) { if (streq(list[i], member)) { return list; } } - /* - * Allocate a new list pointer large enough to hold all the - * old entries, and the new entries as well. - */ - - tmp = xmalloc_T(i + 2, char *); + list = xrealloc_T(list, i + 2, char *); + list[i] = xstrdup(member); + list[i+1] = NULL; - /* - * Copy the original list to the new list, then append the - * new member and NULL terminate the result. This new list - * is returned to the invoker. - */ - - for (i = 0; list[i] != NULL; i++) { - tmp[i] = list[i]; - } - - tmp[i] = xstrdup (member); - tmp[i+1] = NULL; - - free (list); - - return tmp; + return list; } /* From 3684c22b2ae7857f2d04181d801cd7372c92d9c8 Mon Sep 17 00:00:00 2001 From: Alejandro Colomar Date: Sun, 14 Dec 2025 14:31:10 +0100 Subject: [PATCH 5/6] lib/list.c: del_list(): Use memmove(3) and realloc(3) to simplify Signed-off-by: Alejandro Colomar --- lib/list.c | 61 ++++++++++++------------------------------------------ 1 file changed, 13 insertions(+), 48 deletions(-) diff --git a/lib/list.c b/lib/list.c index 5340203d00..106007e7aa 100644 --- a/lib/list.c +++ b/lib/list.c @@ -8,6 +8,9 @@ #include "config.h" +#include +#include + #include "alloc/malloc.h" #include "alloc/realloc.h" #include "prototypes.h" @@ -51,63 +54,25 @@ add_list(/*@returned@*/ /*@only@*/char **list, const char *member) /* * del_list - delete a member from a list of group members - * - * the array of member names is searched for the old member - * name, and if present it is deleted from a freshly allocated - * list of users. */ - /*@only@*/char ** del_list(/*@returned@*/ /*@only@*/char **list, const char *member) { - int i, j; - char **tmp; + int n, m; assert (NULL != member); assert (NULL != list); - /* - * Scan the list for the old name. Return the original list - * pointer if it is not present. - */ - - for (i = j = 0; list[i] != NULL; i++) { - if (!streq(list[i], member)) { - j++; - } - } - - if (j == i) { - return list; - } - - /* - * Allocate a new list pointer large enough to hold all the - * old entries. - */ - - tmp = xmalloc_T(j + 1, char *); - - /* - * Copy the original list except the deleted members to the - * new list, then NULL terminate the result. This new list - * is returned to the invoker. - */ + do { + for (n = 0; list[n] != NULL; n++) + continue; + for (m = 0; list[m] != NULL && !streq(list[m], member); m++) + continue; + free(list[m]); + memmove(&list[m], &list[m+1], (n-m) * sizeof(char *)); + } while (m != n); - for (i = j = 0; list[i] != NULL; i++) { - if (!streq(list[i], member)) { - tmp[j] = list[i]; - j++; - } else { - free (list[i]); - } - } - - tmp[j] = NULL; - - free (list); - - return tmp; + return xrealloc_T(list, n+1, char *); } /* From 44e4752965b808c92a2a131ea166a6efffbd5056 Mon Sep 17 00:00:00 2001 From: Alejandro Colomar Date: Sun, 14 Dec 2025 16:19:10 +0100 Subject: [PATCH 6/6] lib/list.c: del_list(): Use memmove_T() instead of its pattern This adds type safety. Signed-off-by: Alejandro Colomar --- lib/list.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/list.c b/lib/list.c index 106007e7aa..6d51662730 100644 --- a/lib/list.c +++ b/lib/list.c @@ -13,8 +13,9 @@ #include "alloc/malloc.h" #include "alloc/realloc.h" -#include "prototypes.h" #include "defines.h" +#include "memory/memcpy/memmove.h" +#include "prototypes.h" #include "string/strchr/strchrcnt.h" #include "string/strcmp/streq.h" #include "string/strdup/strdup.h" @@ -69,7 +70,7 @@ del_list(/*@returned@*/ /*@only@*/char **list, const char *member) for (m = 0; list[m] != NULL && !streq(list[m], member); m++) continue; free(list[m]); - memmove(&list[m], &list[m+1], (n-m) * sizeof(char *)); + memmove_T(&list[m], &list[m+1], n-m, char *); } while (m != n); return xrealloc_T(list, n+1, char *);