Skip to content

Commit 26f812b

Browse files
committed
kunit/fortify: Add memcpy() tests
Add fortify tests for memcpy() and memmove(). This can use a similar method to the fortify_panic() replacement, only we can do it for what was the WARN_ONCE(), which can be redefined. Since this is primarily testing the fortify behaviors of the memcpy() and memmove() defenses, the tests for memcpy() and memmove() are identical. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Kees Cook <[email protected]>
1 parent 091f79e commit 26f812b

File tree

2 files changed

+87
-4
lines changed

2 files changed

+87
-4
lines changed

include/linux/fortify-string.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,14 @@
1515
#define FORTIFY_REASON(func, write) (FIELD_PREP(BIT(0), write) | \
1616
FIELD_PREP(GENMASK(7, 1), func))
1717

18+
/* Overridden by KUnit tests. */
1819
#ifndef fortify_panic
1920
# define fortify_panic(func, write, avail, size, retfail) \
2021
__fortify_panic(FORTIFY_REASON(func, write), avail, size)
2122
#endif
23+
#ifndef fortify_warn_once
24+
# define fortify_warn_once(x...) WARN_ONCE(x)
25+
#endif
2226

2327
#define FORTIFY_READ 0
2428
#define FORTIFY_WRITE 1
@@ -609,7 +613,7 @@ __FORTIFY_INLINE bool fortify_memcpy_chk(__kernel_size_t size,
609613
const size_t __q_size = (q_size); \
610614
const size_t __p_size_field = (p_size_field); \
611615
const size_t __q_size_field = (q_size_field); \
612-
WARN_ONCE(fortify_memcpy_chk(__fortify_size, __p_size, \
616+
fortify_warn_once(fortify_memcpy_chk(__fortify_size, __p_size, \
613617
__q_size, __p_size_field, \
614618
__q_size_field, FORTIFY_FUNC_ ##op), \
615619
#op ": detected field-spanning write (size %zu) of single %s (size %zu)\n", \

lib/fortify_kunit.c

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: GPL-2.0
22
/*
3-
* Runtime test cases for CONFIG_FORTIFY_SOURCE. For testing memcpy(),
4-
* see FORTIFY_MEM_* tests in LKDTM (drivers/misc/lkdtm/fortify.c).
3+
* Runtime test cases for CONFIG_FORTIFY_SOURCE. For additional memcpy()
4+
* testing see FORTIFY_MEM_* tests in LKDTM (drivers/misc/lkdtm/fortify.c).
55
*
66
* For corner cases with UBSAN, try testing with:
77
*
@@ -18,8 +18,10 @@
1818
/* We don't need to fill dmesg with the fortify WARNs during testing. */
1919
#ifdef DEBUG
2020
# define FORTIFY_REPORT_KUNIT(x...) __fortify_report(x)
21+
# define FORTIFY_WARN_KUNIT(x...) WARN_ONCE(x)
2122
#else
2223
# define FORTIFY_REPORT_KUNIT(x...) do { } while (0)
24+
# define FORTIFY_WARN_KUNIT(x...) do { } while (0)
2325
#endif
2426

2527
/* Redefine fortify_panic() to track failures. */
@@ -30,6 +32,14 @@ void fortify_add_kunit_error(int write);
3032
return (retfail); \
3133
} while (0)
3234

35+
/* Redefine fortify_warn_once() to track memcpy() failures. */
36+
#define fortify_warn_once(chk_func, x...) do { \
37+
bool __result = chk_func; \
38+
FORTIFY_WARN_KUNIT(__result, x); \
39+
if (__result) \
40+
fortify_add_kunit_error(1); \
41+
} while (0)
42+
3343
#include <kunit/device.h>
3444
#include <kunit/test.h>
3545
#include <kunit/test-bug.h>
@@ -818,6 +828,74 @@ static void fortify_test_strlcat(struct kunit *test)
818828
KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
819829
}
820830

831+
/* Check for 0-sized arrays... */
832+
struct fortify_zero_sized {
833+
unsigned long bytes_before;
834+
char buf[0];
835+
unsigned long bytes_after;
836+
};
837+
838+
#define __fortify_test(memfunc) \
839+
static void fortify_test_##memfunc(struct kunit *test) \
840+
{ \
841+
struct fortify_zero_sized zero = { }; \
842+
struct fortify_padding pad = { }; \
843+
char srcA[sizeof(pad.buf) + 2]; \
844+
char srcB[sizeof(pad.buf) + 2]; \
845+
size_t len = sizeof(pad.buf) + unconst; \
846+
\
847+
memset(srcA, 'A', sizeof(srcA)); \
848+
KUNIT_ASSERT_EQ(test, srcA[0], 'A'); \
849+
memset(srcB, 'B', sizeof(srcB)); \
850+
KUNIT_ASSERT_EQ(test, srcB[0], 'B'); \
851+
\
852+
memfunc(pad.buf, srcA, 0 + unconst); \
853+
KUNIT_EXPECT_EQ(test, pad.buf[0], '\0'); \
854+
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
855+
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); \
856+
memfunc(pad.buf + 1, srcB, 1 + unconst); \
857+
KUNIT_EXPECT_EQ(test, pad.buf[0], '\0'); \
858+
KUNIT_EXPECT_EQ(test, pad.buf[1], 'B'); \
859+
KUNIT_EXPECT_EQ(test, pad.buf[2], '\0'); \
860+
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
861+
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); \
862+
memfunc(pad.buf, srcA, 1 + unconst); \
863+
KUNIT_EXPECT_EQ(test, pad.buf[0], 'A'); \
864+
KUNIT_EXPECT_EQ(test, pad.buf[1], 'B'); \
865+
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
866+
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); \
867+
memfunc(pad.buf, srcA, len - 1); \
868+
KUNIT_EXPECT_EQ(test, pad.buf[1], 'A'); \
869+
KUNIT_EXPECT_EQ(test, pad.buf[len - 1], '\0'); \
870+
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
871+
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); \
872+
memfunc(pad.buf, srcA, len); \
873+
KUNIT_EXPECT_EQ(test, pad.buf[1], 'A'); \
874+
KUNIT_EXPECT_EQ(test, pad.buf[len - 1], 'A'); \
875+
KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); \
876+
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
877+
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); \
878+
memfunc(pad.buf, srcA, len + 1); \
879+
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
880+
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 1); \
881+
memfunc(pad.buf + 1, srcB, len); \
882+
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
883+
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 2); \
884+
\
885+
/* Reset error counter. */ \
886+
fortify_write_overflows = 0; \
887+
/* Copy nothing into nothing: no errors. */ \
888+
memfunc(zero.buf, srcB, 0 + unconst); \
889+
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
890+
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); \
891+
/* We currently explicitly ignore zero-sized dests. */ \
892+
memfunc(zero.buf, srcB, 1 + unconst); \
893+
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
894+
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); \
895+
}
896+
__fortify_test(memcpy)
897+
__fortify_test(memmove)
898+
821899
static void fortify_test_memscan(struct kunit *test)
822900
{
823901
char haystack[] = "Where oh where is my memory range?";
@@ -977,7 +1055,8 @@ static struct kunit_case fortify_test_cases[] = {
9771055
KUNIT_CASE(fortify_test_strncat),
9781056
KUNIT_CASE(fortify_test_strlcat),
9791057
/* skip memset: performs bounds checking on whole structs */
980-
/* skip memcpy: still using warn-and-overwrite instead of hard-fail */
1058+
KUNIT_CASE(fortify_test_memcpy),
1059+
KUNIT_CASE(fortify_test_memmove),
9811060
KUNIT_CASE(fortify_test_memscan),
9821061
KUNIT_CASE(fortify_test_memchr),
9831062
KUNIT_CASE(fortify_test_memchr_inv),

0 commit comments

Comments
 (0)