aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2023-06-14 18:10:08 +0200
committerFlorian Weimer <fweimer@redhat.com>2023-06-14 18:10:08 +0200
commit454a20c8756c9c1d55419153255fc7692b3d2199 (patch)
treea65ad84288a247995183089f4400e4fd080ecc9d
parent7ba426a1115318fc11f4355f3161f35817a06ba4 (diff)
downloadglibc-454a20c8756c9c1d55419153255fc7692b3d2199.tar.xz
glibc-454a20c8756c9c1d55419153255fc7692b3d2199.zip
Implement strlcpy and strlcat [BZ #178]
These functions are about to be added to POSIX, under Austin Group issue 986. The fortified strlcat implementation does not raise SIGABRT if the destination buffer does not contain a null terminator, it just inherits the non-failing regular strlcat behavior. Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
-rw-r--r--NEWS3
-rw-r--r--debug/Makefile2
-rw-r--r--debug/Versions4
-rw-r--r--debug/strlcat_chk.c31
-rw-r--r--debug/strlcpy_chk.c31
-rw-r--r--debug/tst-fortify.c31
-rw-r--r--include/string.h4
-rw-r--r--string/Makefile4
-rw-r--r--string/Versions4
-rw-r--r--string/bits/string_fortified.h36
-rw-r--r--string/string.h13
-rw-r--r--string/strlcat.c59
-rw-r--r--string/strlcpy.c46
-rw-r--r--string/tst-strlcat.c84
-rw-r--r--string/tst-strlcpy.c68
-rw-r--r--sysdeps/mach/hurd/i386/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/aarch64/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/alpha/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/arc/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/arm/be/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/arm/le/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/csky/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/hppa/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/i386/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/ia64/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/microblaze/be/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/microblaze/le/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/nios2/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/or1k/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/sh/be/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/sh/le/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/64/libc.abilist4
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist4
50 files changed, 560 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index 23051cf139..7a4df85f08 100644
--- a/NEWS
+++ b/NEWS
@@ -35,6 +35,9 @@ Major new features:
The symbol names follow the AArch64 vector ABI, they are declared
in math.h and have to be called manually at this point.
+* The strlcpy and strlcat functions have been added. They are derived
+ from OpenBSD, and are expected to be added to a future POSIX version.
+
Deprecated and removed features, and other changes affecting compatibility:
* In the Linux kernel for the hppa/parisc architecture some of the
diff --git a/debug/Makefile b/debug/Makefile
index 096df27aeb..55e2aadec9 100644
--- a/debug/Makefile
+++ b/debug/Makefile
@@ -84,6 +84,8 @@ routines = \
stpncpy_chk \
strcat_chk \
strcpy_chk \
+ strlcat_chk \
+ strlcpy_chk \
strncat_chk \
strncpy_chk \
swprintf_chk \
diff --git a/debug/Versions b/debug/Versions
index a6628db356..94dfa5f428 100644
--- a/debug/Versions
+++ b/debug/Versions
@@ -58,6 +58,10 @@ libc {
GLIBC_2.25 {
__explicit_bzero_chk;
}
+ GLIBC_2.38 {
+ __strlcat_chk;
+ __strlcpy_chk;
+ }
GLIBC_PRIVATE {
__fortify_fail;
}
diff --git a/debug/strlcat_chk.c b/debug/strlcat_chk.c
new file mode 100644
index 0000000000..888a62fad5
--- /dev/null
+++ b/debug/strlcat_chk.c
@@ -0,0 +1,31 @@
+/* Fortified version of strlcat.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library 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.
+
+ The GNU C Library 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
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <string.h>
+
+/* Check that the user-supplied size does not exceed the
+ compiler-determined size, and then forward to strlcat. */
+size_t
+__strlcat_chk (char *__restrict s1, const char *__restrict s2,
+ size_t n, size_t s1len)
+{
+ if (__glibc_unlikely (s1len < n))
+ __chk_fail ();
+
+ return __strlcat (s1, s2, n);
+}
diff --git a/debug/strlcpy_chk.c b/debug/strlcpy_chk.c
new file mode 100644
index 0000000000..768a3af686
--- /dev/null
+++ b/debug/strlcpy_chk.c
@@ -0,0 +1,31 @@
+/* Fortified version of strlcpy.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library 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.
+
+ The GNU C Library 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
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <string.h>
+
+/* Check that the user-supplied size does not exceed the
+ compiler-determined size, and then forward to strlcpy. */
+size_t
+__strlcpy_chk (char *__restrict s1, const char *__restrict s2,
+ size_t n, size_t s1len)
+{
+ if (__glibc_unlikely (s1len < n))
+ __chk_fail ();
+
+ return __strlcpy (s1, s2, n);
+}
diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c
index 9f962f2a75..0f823a85d0 100644
--- a/debug/tst-fortify.c
+++ b/debug/tst-fortify.c
@@ -535,6 +535,20 @@ do_test (void)
strncpy (a.buf1 + (O + 6), "X", l0 + 4);
CHK_FAIL_END
+ CHK_FAIL_START
+ strlcpy (a.buf1 + (O + 6), "X", 4);
+ CHK_FAIL_END
+
+ CHK_FAIL_START
+ strlcpy (a.buf1 + (O + 6), "X", l0 + 4);
+ CHK_FAIL_END
+
+ {
+ char *volatile buf2 = buf;
+ if (strlcpy (buf2, "a", sizeof (buf) + 1) != 1)
+ FAIL ();
+ }
+
# if !defined __cplusplus || defined __va_arg_pack
CHK_FAIL_START
sprintf (a.buf1 + (O + 7), "%d", num1);
@@ -558,6 +572,23 @@ do_test (void)
CHK_FAIL_START
strncat (a.buf1, "ZYXWV", l0 + 3);
CHK_FAIL_END
+
+ memset (a.buf1, 0, sizeof (a.buf1));
+ CHK_FAIL_START
+ strlcat (a.buf1 + (O + 6), "X", 4);
+ CHK_FAIL_END
+
+ memset (a.buf1, 0, sizeof (a.buf1));
+ CHK_FAIL_START
+ strlcat (a.buf1 + (O + 6), "X", l0 + 4);
+ CHK_FAIL_END
+
+ {
+ buf[0] = '\0';
+ char *volatile buf2 = buf;
+ if (strlcat (buf2, "a", sizeof (buf) + 1) != 1)
+ FAIL ();
+ }
#endif
diff --git a/include/string.h b/include/string.h
index 673cfd7272..0c78ad2539 100644
--- a/include/string.h
+++ b/include/string.h
@@ -88,6 +88,10 @@ libc_hidden_proto (__stpcpy)
# define __stpcpy(dest, src) __builtin_stpcpy (dest, src)
#endif
libc_hidden_proto (__stpncpy)
+extern __typeof (strlcpy) __strlcpy;
+libc_hidden_proto (__strlcpy)
+extern __typeof (strlcat) __strlcat;
+libc_hidden_proto (__strlcat)
libc_hidden_proto (__rawmemchr)
libc_hidden_proto (__strcasecmp)
libc_hidden_proto (__strcasecmp_l)
diff --git a/string/Makefile b/string/Makefile
index 2eef6f1dfc..0ad276cc6a 100644
--- a/string/Makefile
+++ b/string/Makefile
@@ -92,6 +92,8 @@ routines := \
strerrorname_np \
strfry \
string-inlines \
+ strlcat \
+ strlcpy \
strlen \
strncase \
strncase_l \
@@ -177,6 +179,8 @@ tests := \
tst-inlcall \
tst-memmove-overflow \
tst-strfry \
+ tst-strlcat \
+ tst-strlcpy \
tst-strlen \
tst-strtok \
tst-strtok_r \
diff --git a/string/Versions b/string/Versions
index 864c4cf7a4..c56e372a3c 100644
--- a/string/Versions
+++ b/string/Versions
@@ -92,4 +92,8 @@ libc {
GLIBC_2.35 {
__memcmpeq;
}
+ GLIBC_2.38 {
+ strlcat;
+ strlcpy;
+ }
}
diff --git a/string/bits/string_fortified.h b/string/bits/string_fortified.h
index 9900df6104..23ef064168 100644
--- a/string/bits/string_fortified.h
+++ b/string/bits/string_fortified.h
@@ -139,4 +139,40 @@ __NTH (strncat (char *__restrict __dest, const char *__restrict __src,
__glibc_objsize (__dest));
}
+#ifdef __USE_MISC
+extern size_t __strlcpy_chk (char *__dest, const char *__src, size_t __n,
+ size_t __destlen) __THROW;
+extern size_t __REDIRECT_NTH (__strlcpy_alias,
+ (char *__dest, const char *__src, size_t __n),
+ strlcpy);
+
+__fortify_function size_t
+__NTH (strlcpy (char *__restrict __dest, const char *__restrict __src,
+ size_t __n))
+{
+ if (__glibc_objsize (__dest) != (size_t) -1
+ && (!__builtin_constant_p (__n > __glibc_objsize (__dest))
+ || __n > __glibc_objsize (__dest)))
+ return __strlcpy_chk (__dest, __src, __n, __glibc_objsize (__dest));
+ return __strlcpy_alias (__dest, __src, __n);
+}
+
+extern size_t __strlcat_chk (char *__dest, const char *__src, size_t __n,
+ size_t __destlen) __THROW;
+extern size_t __REDIRECT_NTH (__strlcat_alias,
+ (char *__dest, const char *__src, size_t __n),
+ strlcat);
+
+__fortify_function size_t
+__NTH (strlcat (char *__restrict __dest, const char *__restrict __src,
+ size_t __n))
+{
+ if (__glibc_objsize (__dest) != (size_t) -1
+ && (!__builtin_constant_p (__n > __glibc_objsize (__dest))
+ || __n > __glibc_objsize (__dest)))
+ return __strlcat_chk (__dest, __src, __n, __glibc_objsize (__dest));
+ return __strlcat_alias (__dest, __src, __n);
+}
+#endif /* __USE_MISC */
+
#endif /* bits/string_fortified.h */
diff --git a/string/string.h b/string/string.h
index 4927879ecf..c0773d11d8 100644
--- a/string/string.h
+++ b/string/string.h
@@ -501,6 +501,19 @@ extern char *stpncpy (char *__restrict __dest,
__THROW __nonnull ((1, 2));
#endif
+#ifdef __USE_MISC
+/* Copy at most N - 1 characters from SRC to DEST. */
+extern size_t strlcpy (char *__restrict __dest,
+ const char *__restrict __src, size_t __n)
+ __THROW __nonnull ((1, 2)) __attr_access ((__write_only__, 1, 3));
+
+/* Append SRC to DEST, possibly with truncation to keep the total size
+ below N. */
+extern size_t strlcat (char *__restrict __dest,
+ const char *__restrict __src, size_t __n)
+ __THROW __nonnull ((1, 2)) __attr_access ((__read_write__, 1, 3));
+#endif
+
#ifdef __USE_GNU
/* Compare S1 and S2 as strings holding name & indices/version numbers. */
extern int strverscmp (const char *__s1, const char *__s2)
diff --git a/string/strlcat.c b/string/strlcat.c
new file mode 100644
index 0000000000..dce4c255d1
--- /dev/null
+++ b/string/strlcat.c
@@ -0,0 +1,59 @@
+/* Append a null-terminated string to another string, with length checking.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library 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.
+
+ The GNU C Library 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
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/l