xref: /openbmc/linux/drivers/misc/lkdtm/fortify.c (revision 7ce05074)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2020 Francis Laniel <laniel_francis@privacyrequired.com>
4  *
5  * Add tests related to fortified functions in this file.
6  */
7 #include "lkdtm.h"
8 #include <linux/string.h>
9 #include <linux/slab.h>
10 
11 
12 /*
13  * Calls fortified strscpy to test that it returns the same result as vanilla
14  * strscpy and generate a panic because there is a write overflow (i.e. src
15  * length is greater than dst length).
16  */
17 void lkdtm_FORTIFIED_STRSCPY(void)
18 {
19 	char *src;
20 	char dst[5];
21 
22 	struct {
23 		union {
24 			char big[10];
25 			char src[5];
26 		};
27 	} weird = { .big = "hello!" };
28 	char weird_dst[sizeof(weird.src) + 1];
29 
30 	src = kstrdup("foobar", GFP_KERNEL);
31 
32 	if (src == NULL)
33 		return;
34 
35 	/* Vanilla strscpy returns -E2BIG if size is 0. */
36 	if (strscpy(dst, src, 0) != -E2BIG)
37 		pr_warn("FAIL: strscpy() of 0 length did not return -E2BIG\n");
38 
39 	/* Vanilla strscpy returns -E2BIG if src is truncated. */
40 	if (strscpy(dst, src, sizeof(dst)) != -E2BIG)
41 		pr_warn("FAIL: strscpy() did not return -E2BIG while src is truncated\n");
42 
43 	/* After above call, dst must contain "foob" because src was truncated. */
44 	if (strncmp(dst, "foob", sizeof(dst)) != 0)
45 		pr_warn("FAIL: after strscpy() dst does not contain \"foob\" but \"%s\"\n",
46 			dst);
47 
48 	/* Shrink src so the strscpy() below succeeds. */
49 	src[3] = '\0';
50 
51 	/*
52 	 * Vanilla strscpy returns number of character copied if everything goes
53 	 * well.
54 	 */
55 	if (strscpy(dst, src, sizeof(dst)) != 3)
56 		pr_warn("FAIL: strscpy() did not return 3 while src was copied entirely truncated\n");
57 
58 	/* After above call, dst must contain "foo" because src was copied. */
59 	if (strncmp(dst, "foo", sizeof(dst)) != 0)
60 		pr_warn("FAIL: after strscpy() dst does not contain \"foo\" but \"%s\"\n",
61 			dst);
62 
63 	/* Test when src is embedded inside a union. */
64 	strscpy(weird_dst, weird.src, sizeof(weird_dst));
65 
66 	if (strcmp(weird_dst, "hello") != 0)
67 		pr_warn("FAIL: after strscpy() weird_dst does not contain \"hello\" but \"%s\"\n",
68 			weird_dst);
69 
70 	/* Restore src to its initial value. */
71 	src[3] = 'b';
72 
73 	/*
74 	 * Use strlen here so size cannot be known at compile time and there is
75 	 * a runtime write overflow.
76 	 */
77 	strscpy(dst, src, strlen(src));
78 
79 	pr_err("FAIL: strscpy() overflow not detected!\n");
80 	pr_expected_config(CONFIG_FORTIFY_SOURCE);
81 
82 	kfree(src);
83 }
84