Skip to content

Commit 62e1cbf

Browse files
committed
fortify: Short-circuit known-safe calls to strscpy()
Replacing compile-time safe calls of strcpy()-related functions with strscpy() was always calling the full strscpy() logic when a builtin would be better. For example: char buf[16]; strcpy(buf, "yes"); would reduce to __builtin_memcpy(buf, "yes", 4), but not if it was: strscpy(buf, yes, sizeof(buf)); Fix this by checking if all sizes are known at compile-time. Cc: [email protected] Tested-by: Nathan Chancellor <[email protected]> Signed-off-by: Kees Cook <[email protected]>
1 parent 41eefc4 commit 62e1cbf

File tree

2 files changed

+23
-0
lines changed

2 files changed

+23
-0
lines changed

include/linux/fortify-string.h

+10
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,16 @@ __FORTIFY_INLINE ssize_t strscpy(char * const POS p, const char * const POS q, s
314314
if (__compiletime_lessthan(p_size, size))
315315
__write_overflow();
316316

317+
/* Short-circuit for compile-time known-safe lengths. */
318+
if (__compiletime_lessthan(p_size, SIZE_MAX)) {
319+
len = __compiletime_strlen(q);
320+
321+
if (len < SIZE_MAX && __compiletime_lessthan(len, size)) {
322+
__underlying_memcpy(p, q, len + 1);
323+
return len;
324+
}
325+
}
326+
317327
/*
318328
* This call protects from read overflow, because len will default to q
319329
* length if it smaller than size.

lib/strscpy_kunit.c

+13
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ static void tc(struct kunit *test, char *src, int count, int expected,
8181

8282
static void strscpy_test(struct kunit *test)
8383
{
84+
char dest[8];
85+
8486
/*
8587
* tc() uses a destination buffer of size 6 and needs at
8688
* least 2 characters spare (one for null and one to check for
@@ -111,6 +113,17 @@ static void strscpy_test(struct kunit *test)
111113
tc(test, "ab", 4, 2, 2, 1, 1);
112114
tc(test, "a", 4, 1, 1, 1, 2);
113115
tc(test, "", 4, 0, 0, 1, 3);
116+
117+
/* Compile-time-known source strings. */
118+
KUNIT_EXPECT_EQ(test, strscpy(dest, "", ARRAY_SIZE(dest)), 0);
119+
KUNIT_EXPECT_EQ(test, strscpy(dest, "", 3), 0);
120+
KUNIT_EXPECT_EQ(test, strscpy(dest, "", 1), 0);
121+
KUNIT_EXPECT_EQ(test, strscpy(dest, "", 0), -E2BIG);
122+
KUNIT_EXPECT_EQ(test, strscpy(dest, "Fixed", ARRAY_SIZE(dest)), 5);
123+
KUNIT_EXPECT_EQ(test, strscpy(dest, "Fixed", 3), -E2BIG);
124+
KUNIT_EXPECT_EQ(test, strscpy(dest, "Fixed", 1), -E2BIG);
125+
KUNIT_EXPECT_EQ(test, strscpy(dest, "Fixed", 0), -E2BIG);
126+
KUNIT_EXPECT_EQ(test, strscpy(dest, "This is too long", ARRAY_SIZE(dest)), -E2BIG);
114127
}
115128

116129
static struct kunit_case strscpy_test_cases[] = {

0 commit comments

Comments
 (0)