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.
Unified · Split
| @@ -131,27 +131,32 @@ value of strcpy() was used, since strscpy() does not return a pointer to · 130 unmodified lines | |||
| 131 | the destination, but rather a count of non-NUL bytes copied (or negative | 131 | the destination, but rather a count of non-NUL bytes copied (or negative |
| 132 | errno when it truncates). | 132 | errno when it truncates). |
| 133 | 133 | ||
| 134 | strncpy() on NUL-terminated strings | 134 | strncpy() |
| 135 | ----------------------------------- | 135 | --------- |
| 136 | Use of strncpy() does not guarantee that the destination buffer will | 136 | strncpy() has been removed from the kernel. All former callers have |
| 137 | be NUL terminated. This can lead to various linear read overflows and | 137 | been migrated to safer alternatives. |
| 138 | other misbehavior due to the missing termination. It also NUL-pads | 138 | |
| 139 | the destination buffer if the source contents are shorter than the | 139 | strncpy() did not guarantee NUL-termination of the destination buffer, |
| 140 | destination buffer size, which may be a needless performance penalty | 140 | leading to linear read overflows and other misbehavior. It also |
| 141 | for callers using only NUL-terminated strings. | 141 | unconditionally NUL-padded the destination, which was a needless |
| 142 | 142 | performance penalty for callers using only NUL-terminated strings. Due | |
| 143 | When the destination is required to be NUL-terminated, the replacement is | 143 | to its various behaviors, it was an ambiguous API for determining what |
| 144 | strscpy(), though care must be given to any cases where the return value | 144 | an author's true intent was for the copy. |
| 145 | of strncpy() was used, since strscpy() does not return a pointer to the | 145 | |
| 146 | destination, but rather a count of non-NUL bytes copied (or negative | 146 | The replacements for strncpy() are: |
| 147 | errno when it truncates). Any cases still needing NUL-padding should | 147 | |
| 148 | instead use strscpy_pad(). | 148 | - strscpy() when the destination must be NUL-terminated. |
| 149 | 149 | - strscpy_pad() when the destination must be NUL-terminated and | |
| 150 | If a caller is using non-NUL-terminated strings, strtomem() should be | 150 | zero-padded (e.g., structs crossing privilege boundaries). |
| 151 | used, and the destinations should be marked with the `__nonstring | 151 | - memtostr() for NUL-terminated destinations from non-NUL-terminated |
| 152 | <https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html>`_ | 152 | fixed-width sources (with the `__nonstring` attribute on the source). |
| 153 | attribute to avoid future compiler warnings. For cases still needing | 153 | - memtostr_pad() for the same, but with zero-padding. |
| 154 | NUL-padding, strtomem_pad() can be used. | 154 | - strtomem() for non-NUL-terminated fixed-width destinations, with |
| 155 | the `__nonstring` attribute on the destination. | ||
| 156 | - strtomem_pad() for non-NUL-terminated destinations that also need | ||
| 157 | zero-padding. | ||
| 158 | - memcpy_and_pad() for bounded copies from potentially unterminated | ||
| 159 | sources where the destination size is a runtime value. | ||
| 155 | 160 | ||
| 156 | strlcpy() | 161 | strlcpy() |
| 157 | --------- | 162 | --------- |
| @@ -98,7 +98,7 @@ static void lkdtm_FORTIFY_MEM_MEMBER(void) · 97 unmodified lines | |||
| 98 | pr_info("trying to memcpy() past the end of a struct member...\n"); | 98 | pr_info("trying to memcpy() past the end of a struct member...\n"); |
| 99 | 99 | ||
| 100 | /* | 100 | /* |
| 101 | * strncpy(target.a, src, 20); will hit a compile error because the | 101 | * memcpy(target.a, src, 20); will hit a compile error because the |
| 102 | * compiler knows at build time that target.a < 20 bytes. Use a | 102 | * compiler knows at build time that target.a < 20 bytes. Use a |
| 103 | * volatile to force a runtime error. | 103 | * volatile to force a runtime error. |
| 104 | */ | 104 | */ |
| @@ -26,7 +26,6 @@ · 25 unmodified lines | |||
| 26 | #define FORTIFY_WRITE 1 | 26 | #define FORTIFY_WRITE 1 |
| 27 | 27 | ||
| 28 | #define EACH_FORTIFY_FUNC(macro) \ | 28 | #define EACH_FORTIFY_FUNC(macro) \ |
| 29 | macro(strncpy), \ | ||
| 30 | macro(strnlen), \ | 29 | macro(strnlen), \ |
| 31 | macro(strlen), \ | 30 | macro(strlen), \ |
| 32 | macro(strscpy), \ | 31 | macro(strscpy), \ |
| @@ -95,8 +94,6 @@ extern char *__underlying_strcat(char *p, const char *q) __RENAME(strcat); · 62 unmodified lines | |||
| 95 | extern char *__underlying_strcpy(char *p, const char *q) __RENAME(strcpy); | 94 | extern char *__underlying_strcpy(char *p, const char *q) __RENAME(strcpy); |
| 96 | extern __kernel_size_t __underlying_strlen(const char *p) __RENAME(strlen); | 95 | extern __kernel_size_t __underlying_strlen(const char *p) __RENAME(strlen); |
| 97 | extern char *__underlying_strncat(char *p, const char *q, __kernel_size_t count) __RENAME(strncat); | 96 | extern char *__underlying_strncat(char *p, const char *q, __kernel_size_t count) __RENAME(strncat); |
| 98 | extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) __RENAME(strncpy); | ||
| 99 | |||
| 100 | #else | 97 | #else |
| 101 | 98 | ||
| 102 | #if defined(__SANITIZE_MEMORY__) | 99 | #if defined(__SANITIZE_MEMORY__) |
| @@ -120,7 +117,6 @@ extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) · 17 unmodified lines | |||
| 120 | #define __underlying_strcpy __builtin_strcpy | 117 | #define __underlying_strcpy __builtin_strcpy |
| 121 | #define __underlying_strlen __builtin_strlen | 118 | #define __underlying_strlen __builtin_strlen |
| 122 | #define __underlying_strncat __builtin_strncat | 119 | #define __underlying_strncat __builtin_strncat |
| 123 | #define __underlying_strncpy __builtin_strncpy | ||
| 124 | 120 | ||
| 125 | #endif | 121 | #endif |
| 126 | 122 | ||
| @@ -159,50 +155,6 @@ extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) · 32 unmodified lines | |||
| 159 | (bounds) < (length) \ | 155 | (bounds) < (length) \ |
| 160 | ) | 156 | ) |
| 161 | 157 | ||
| 162 | /** | ||
| 163 | * strncpy - Copy a string to memory with non-guaranteed NUL padding | ||
| 164 | * | ||
| 165 | * @p: pointer to destination of copy | ||
| 166 | * @q: pointer to NUL-terminated source string to copy | ||
| 167 | * @size: bytes to write at @p | ||
| 168 | * | ||
| 169 | * If strlen(@q) >= @size, the copy of @q will stop after @size bytes, | ||
| 170 | * and @p will NOT be NUL-terminated | ||
| 171 | * | ||
| 172 | * If strlen(@q) < @size, following the copy of @q, trailing NUL bytes | ||
| 173 | * will be written to @p until @size total bytes have been written. | ||
| 174 | * | ||
| 175 | * Do not use this function. While FORTIFY_SOURCE tries to avoid | ||
| 176 | * over-reads of @q, it cannot defend against writing unterminated | ||
| 177 | * results to @p. Using strncpy() remains ambiguous and fragile. | ||
| 178 | * Instead, please choose an alternative, so that the expectation | ||
| 179 | * of @p's contents is unambiguous: | ||
| 180 | * | ||
| 181 | * +--------------------+--------------------+------------+ | ||
| 182 | * | **p** needs to be: | padded to **size** | not padded | | ||
| 183 | * +====================+====================+============+ | ||
| 184 | * | NUL-terminated | strscpy_pad() | strscpy() | | ||
| 185 | * +--------------------+--------------------+------------+ | ||
| 186 | * | not NUL-terminated | strtomem_pad() | strtomem() | | ||
| 187 | * +--------------------+--------------------+------------+ | ||
| 188 | * | ||
| 189 | * Note strscpy*()'s differing return values for detecting truncation, | ||
| 190 | * and strtomem*()'s expectation that the destination is marked with | ||
| 191 | * __nonstring when it is a character array. | ||
| 192 | * | ||
| 193 | */ | ||
| 194 | __FORTIFY_INLINE __diagnose_as(__builtin_strncpy, 1, 2, 3) | ||
| 195 | char *strncpy(char * const POS p, const char *q, __kernel_size_t size) | ||
| 196 | { | ||
| 197 | const size_t p_size = __member_size(p); | ||
| 198 | |||
| 199 | if (__compiletime_lessthan(p_size, size)) | ||
| 200 | __write_overflow(); | ||
| 201 | if (p_size < size) | ||
| 202 | fortify_panic(FORTIFY_FUNC_strncpy, FORTIFY_WRITE, p_size, size, p); | ||
| 203 | return __underlying_strncpy(p, q, size); | ||
| 204 | } | ||
| 205 | |||
| 206 | extern __kernel_size_t __real_strnlen(const char *, __kernel_size_t) __RENAME(strnlen); | 158 | extern __kernel_size_t __real_strnlen(const char *, __kernel_size_t) __RENAME(strnlen); |
| 207 | /** | 159 | /** |
| 208 | * strnlen - Return bounded count of characters in a NUL-terminated string | 160 | * strnlen - Return bounded count of characters in a NUL-terminated string |
| @@ -809,7 +761,6 @@ char *strcpy(char * const POS p, const char * const POS q) · 600 unmodified lines | |||
| 809 | #undef __underlying_strcpy | 761 | #undef __underlying_strcpy |
| 810 | #undef __underlying_strlen | 762 | #undef __underlying_strlen |
| 811 | #undef __underlying_strncat | 763 | #undef __underlying_strncat |
| 812 | #undef __underlying_strncpy | ||
| 813 | 764 | ||
| 814 | #undef POS | 765 | #undef POS |
| 815 | #undef POS0 | 766 | #undef POS0 |
| @@ -67,9 +67,6 @@ void *vmemdup_array_user(const void __user *src, size_t n, size_t size) · 66 unmodified lines | |||
| 67 | #ifndef __HAVE_ARCH_STRCPY | 67 | #ifndef __HAVE_ARCH_STRCPY |
| 68 | extern char * strcpy(char *,const char *); | 68 | extern char * strcpy(char *,const char *); |
| 69 | #endif | 69 | #endif |
| 70 | #ifndef __HAVE_ARCH_STRNCPY | ||
| 71 | extern char * strncpy(char *,const char *, __kernel_size_t); | ||
| 72 | #endif | ||
| 73 | ssize_t sized_strscpy(char *, const char *, size_t); | 70 | ssize_t sized_strscpy(char *, const char *, size_t); |
| 74 | 71 | ||
| 75 | /* | 72 | /* |
| @@ -88,22 +88,6 @@ char *strcpy(char *dest, const char *src) · 87 unmodified lines | |||
| 88 | EXPORT_SYMBOL(strcpy); | 88 | EXPORT_SYMBOL(strcpy); |
| 89 | #endif | 89 | #endif |
| 90 | 90 | ||
| 91 | #ifndef __HAVE_ARCH_STRNCPY | ||
| 92 | char *strncpy(char *dest, const char *src, size_t count) | ||
| 93 | { | ||
| 94 | char *tmp = dest; | ||
| 95 | |||
| 96 | while (count) { | ||
| 97 | if ((*tmp = *src) != 0) | ||
| 98 | src++; | ||
| 99 | tmp++; | ||
| 100 | count--; | ||
| 101 | } | ||
| 102 | return dest; | ||
| 103 | } | ||
| 104 | EXPORT_SYMBOL(strncpy); | ||
| 105 | #endif | ||
| 106 | |||
| 107 | #ifdef __BIG_ENDIAN | 91 | #ifdef __BIG_ENDIAN |
| 108 | # define ALLBUTLAST_BYTE_MASK (~255ul) | 92 | # define ALLBUTLAST_BYTE_MASK (~255ul) |
| 109 | #else | 93 | #else |
| @@ -1,5 +0,0 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | #define TEST \ | ||
| 3 | strncpy(small, large_src, sizeof(small) + 1) | ||
| 4 | |||
| 5 | #include "test_fortify.h" | ||
| @@ -1,5 +0,0 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | #define TEST \ | ||
| 3 | strncpy(instance.buf, large_src, sizeof(instance.buf) + 1) | ||
| 4 | |||
| 5 | #include "test_fortify.h" | ||
| @@ -458,7 +458,7 @@ static void fortify_test_strnlen(struct kunit *test) · 457 unmodified lines | |||
| 458 | /* Make string unterminated, and recount. */ | 458 | /* Make string unterminated, and recount. */ |
| 459 | pad.buf[end] = 'A'; | 459 | pad.buf[end] = 'A'; |
| 460 | end = sizeof(pad.buf); | 460 | end = sizeof(pad.buf); |
| 461 | /* Reading beyond with strncpy() will fail. */ | 461 | /* Reading beyond will fail. */ |
| 462 | KUNIT_EXPECT_EQ(test, strnlen(pad.buf, end + 1), end); | 462 | KUNIT_EXPECT_EQ(test, strnlen(pad.buf, end + 1), end); |
| 463 | KUNIT_EXPECT_EQ(test, fortify_read_overflows, 1); | 463 | KUNIT_EXPECT_EQ(test, fortify_read_overflows, 1); |
| 464 | KUNIT_EXPECT_EQ(test, strnlen(pad.buf, end + 2), end); | 464 | KUNIT_EXPECT_EQ(test, strnlen(pad.buf, end + 2), end); |
| @@ -531,64 +531,6 @@ static void fortify_test_strcpy(struct kunit *test) · 66 unmodified lines | |||
| 531 | KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); | 531 | KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); |
| 532 | } | 532 | } |
| 533 | 533 | ||
| 534 | static void fortify_test_strncpy(struct kunit *test) | ||
| 535 | { | ||
| 536 | struct fortify_padding pad = { }; | ||
| 537 | char src[] = "Copy me fully into a small buffer and I will overflow!"; | ||
| 538 | size_t sizeof_buf = sizeof(pad.buf); | ||
| 539 | |||
| 540 | OPTIMIZER_HIDE_VAR(sizeof_buf); | ||
| 541 | |||
| 542 | /* Destination is %NUL-filled to start with. */ | ||
| 543 | KUNIT_EXPECT_EQ(test, pad.bytes_before, 0); | ||
| 544 | KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 1], '\0'); | ||
| 545 | KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 2], '\0'); | ||
| 546 | KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 3], '\0'); | ||
| 547 | KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); | ||
| 548 | |||
| 549 | /* Legitimate strncpy() 1 less than of max size. */ | ||
| 550 | KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, sizeof_buf - 1) | ||
| 551 | == pad.buf); | ||
| 552 | KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); | ||
| 553 | /* Only last byte should be %NUL */ | ||
| 554 | KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 1], '\0'); | ||
| 555 | KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0'); | ||
| 556 | KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 3], '\0'); | ||
| 557 | |||
| 558 | /* Legitimate (though unterminated) max-size strncpy. */ | ||
| 559 | KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, sizeof_buf) | ||
| 560 | == pad.buf); | ||
| 561 | KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); | ||
| 562 | /* No trailing %NUL -- thanks strncpy API. */ | ||
| 563 | KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 1], '\0'); | ||
| 564 | KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0'); | ||
| 565 | KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0'); | ||
| 566 | /* But we will not have gone beyond. */ | ||
| 567 | KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); | ||
| 568 | |||
| 569 | /* Now verify that FORTIFY is working... */ | ||
| 570 | KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, sizeof_buf + 1) | ||
| 571 | == pad.buf); | ||
| 572 | /* Should catch the overflow. */ | ||
| 573 | KUNIT_EXPECT_EQ(test, fortify_write_overflows, 1); | ||
| 574 | KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 1], '\0'); | ||
| 575 | KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0'); | ||
| 576 | KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0'); | ||
| 577 | /* And we will not have gone beyond. */ | ||
| 578 | KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); | ||
| 579 | |||
| 580 | /* And further... */ | ||
| 581 | KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, sizeof_buf + 2) | ||
| 582 | == pad.buf); | ||
| 583 | /* Should catch the overflow. */ | ||
| 584 | KUNIT_EXPECT_EQ(test, fortify_write_overflows, 2); | ||
| 585 | KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 1], '\0'); | ||
| 586 | KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0'); | ||
| 587 | KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0'); | ||
| 588 | /* And we will not have gone beyond. */ | ||
| 589 | KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); | ||
| 590 | } | ||
| 591 | |||
| 592 | static void fortify_test_strscpy(struct kunit *test) | 534 | static void fortify_test_strscpy(struct kunit *test) |
| 593 | { | 535 | { |
| 594 | struct fortify_padding pad = { }; | 536 | struct fortify_padding pad = { }; |
| @@ -1100,7 +1042,6 @@ static struct kunit_case fortify_test_cases[] = { · 505 unmodified lines | |||
| 1100 | KUNIT_CASE(fortify_test_strlen), | 1042 | KUNIT_CASE(fortify_test_strlen), |
| 1101 | KUNIT_CASE(fortify_test_strnlen), | 1043 | KUNIT_CASE(fortify_test_strnlen), |
| 1102 | KUNIT_CASE(fortify_test_strcpy), | 1044 | KUNIT_CASE(fortify_test_strcpy), |
| 1103 | KUNIT_CASE(fortify_test_strncpy), | ||
| 1104 | KUNIT_CASE(fortify_test_strscpy), | 1045 | KUNIT_CASE(fortify_test_strscpy), |
| 1105 | KUNIT_CASE(fortify_test_strcat), | 1046 | KUNIT_CASE(fortify_test_strcat), |
| 1106 | KUNIT_CASE(fortify_test_strncat), | 1047 | KUNIT_CASE(fortify_test_strncat), |