summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorKees Cook <kees@kernel.org>2026-03-23 04:27:25 +0300
committerKees Cook <kees@kernel.org>2026-06-19 02:39:31 +0300
commit079a028d6327e68cfa5d38b36123637b321c19a7 (patch)
treed6bed2ef9b0f5969d1105f010d8b4a8804a13f61 /lib
parent58c4ce8cd6cd1fbf1bca2e1d1f42f9e2899fa934 (diff)
downloadlinux-079a028d6327e68cfa5d38b36123637b321c19a7.tar.xz
string: Remove strncpy() from the kernel
strncpy() has been a persistent source of bugs due to its ambiguous intended usage and frequently counter-intuitive semantics: it may not NUL-terminate the destination, and it unconditionally zero-pads to the full length, which isn't always needed. All former callers have been migrated[1] to: - strscpy() for NUL-terminated destinations - strscpy_pad() for NUL-terminated destinations needing zero-padding - strtomem_pad() for non-NUL-terminated fixed-width fields - memcpy_and_pad() for bounded copies with explicit padding - memcpy() for known-length copies Remove the generic implementation, its declaration, the FORTIFY_SOURCE wrapper, and associated tests. Link: https://github.com/KSPP/linux/issues/90 [1] Signed-off-by: Kees Cook <kees@kernel.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/string.c16
-rw-r--r--lib/test_fortify/write_overflow-strncpy-src.c5
-rw-r--r--lib/test_fortify/write_overflow-strncpy.c5
-rw-r--r--lib/tests/fortify_kunit.c61
4 files changed, 1 insertions, 86 deletions
diff --git a/lib/string.c b/lib/string.c
index b632c71df1a5..45ca1cfe0184 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -88,22 +88,6 @@ char *strcpy(char *dest, const char *src)
EXPORT_SYMBOL(strcpy);
#endif
-#ifndef __HAVE_ARCH_STRNCPY
-char *strncpy(char *dest, const char *src, size_t count)
-{
- char *tmp = dest;
-
- while (count) {
- if ((*tmp = *src) != 0)
- src++;
- tmp++;
- count--;
- }
- return dest;
-}
-EXPORT_SYMBOL(strncpy);
-#endif
-
#ifdef __BIG_ENDIAN
# define ALLBUTLAST_BYTE_MASK (~255ul)
#else
diff --git a/lib/test_fortify/write_overflow-strncpy-src.c b/lib/test_fortify/write_overflow-strncpy-src.c
deleted file mode 100644
index 8dcfb8c788dd..000000000000
--- a/lib/test_fortify/write_overflow-strncpy-src.c
+++ /dev/null
@@ -1,5 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-#define TEST \
- strncpy(small, large_src, sizeof(small) + 1)
-
-#include "test_fortify.h"
diff --git a/lib/test_fortify/write_overflow-strncpy.c b/lib/test_fortify/write_overflow-strncpy.c
deleted file mode 100644
index b85f079c815d..000000000000
--- a/lib/test_fortify/write_overflow-strncpy.c
+++ /dev/null
@@ -1,5 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-#define TEST \
- strncpy(instance.buf, large_src, sizeof(instance.buf) + 1)
-
-#include "test_fortify.h"
diff --git a/lib/tests/fortify_kunit.c b/lib/tests/fortify_kunit.c
index fc9c76f026d6..413cdbf3dc0d 100644
--- a/lib/tests/fortify_kunit.c
+++ b/lib/tests/fortify_kunit.c
@@ -458,7 +458,7 @@ static void fortify_test_strnlen(struct kunit *test)
/* Make string unterminated, and recount. */
pad.buf[end] = 'A';
end = sizeof(pad.buf);
- /* Reading beyond with strncpy() will fail. */
+ /* Reading beyond will fail. */
KUNIT_EXPECT_EQ(test, strnlen(pad.buf, end + 1), end);
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 1);
KUNIT_EXPECT_EQ(test, strnlen(pad.buf, end + 2), end);
@@ -531,64 +531,6 @@ static void fortify_test_strcpy(struct kunit *test)
KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
}
-static void fortify_test_strncpy(struct kunit *test)
-{
- struct fortify_padding pad = { };
- char src[] = "Copy me fully into a small buffer and I will overflow!";
- size_t sizeof_buf = sizeof(pad.buf);
-
- OPTIMIZER_HIDE_VAR(sizeof_buf);
-
- /* Destination is %NUL-filled to start with. */
- KUNIT_EXPECT_EQ(test, pad.bytes_before, 0);
- KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 1], '\0');
- KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 2], '\0');
- KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 3], '\0');
- KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
-
- /* Legitimate strncpy() 1 less than of max size. */
- KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, sizeof_buf - 1)
- == pad.buf);
- KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0);
- /* Only last byte should be %NUL */
- KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 1], '\0');
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 3], '\0');
-
- /* Legitimate (though unterminated) max-size strncpy. */
- KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, sizeof_buf)
- == pad.buf);
- KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0);
- /* No trailing %NUL -- thanks strncpy API. */
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 1], '\0');
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
- /* But we will not have gone beyond. */
- KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
-
- /* Now verify that FORTIFY is working... */
- KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, sizeof_buf + 1)
- == pad.buf);
- /* Should catch the overflow. */
- KUNIT_EXPECT_EQ(test, fortify_write_overflows, 1);
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 1], '\0');
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
- /* And we will not have gone beyond. */
- KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
-
- /* And further... */
- KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, sizeof_buf + 2)
- == pad.buf);
- /* Should catch the overflow. */
- KUNIT_EXPECT_EQ(test, fortify_write_overflows, 2);
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 1], '\0');
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
- KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
- /* And we will not have gone beyond. */
- KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
-}
-
static void fortify_test_strscpy(struct kunit *test)
{
struct fortify_padding pad = { };
@@ -1100,7 +1042,6 @@ static struct kunit_case fortify_test_cases[] = {
KUNIT_CASE(fortify_test_strlen),
KUNIT_CASE(fortify_test_strnlen),
KUNIT_CASE(fortify_test_strcpy),
- KUNIT_CASE(fortify_test_strncpy),
KUNIT_CASE(fortify_test_strscpy),
KUNIT_CASE(fortify_test_strcat),
KUNIT_CASE(fortify_test_strncat),