brintos

brintos / linux-shallow public Read only

0
0
Text · 5.7 KiB · 0159276 Raw
218 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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 11static volatile int fortify_scratch_space;12 13static void lkdtm_FORTIFY_STR_OBJECT(void)14{15	struct target {16		char a[10];17		int foo;18	} target[3] = {};19	/*20	 * Using volatile prevents the compiler from determining the value of21	 * 'size' at compile time. Without that, we would get a compile error22	 * rather than a runtime error.23	 */24	volatile int size = 20;25 26	pr_info("trying to strcmp() past the end of a struct\n");27 28	strncpy(target[0].a, target[1].a, size);29 30	/* Store result to global to prevent the code from being eliminated */31	fortify_scratch_space = target[0].a[3];32 33	pr_err("FAIL: fortify did not block a strncpy() object write overflow!\n");34	pr_expected_config(CONFIG_FORTIFY_SOURCE);35}36 37static void lkdtm_FORTIFY_STR_MEMBER(void)38{39	struct target {40		char a[10];41		char b[10];42	} target;43	volatile int size = 20;44	char *src;45 46	src = kmalloc(size, GFP_KERNEL);47	strscpy(src, "over ten bytes", size);48	size = strlen(src) + 1;49 50	pr_info("trying to strncpy() past the end of a struct member...\n");51 52	/*53	 * strncpy(target.a, src, 20); will hit a compile error because the54	 * compiler knows at build time that target.a < 20 bytes. Use a55	 * volatile to force a runtime error.56	 */57	strncpy(target.a, src, size);58 59	/* Store result to global to prevent the code from being eliminated */60	fortify_scratch_space = target.a[3];61 62	pr_err("FAIL: fortify did not block a strncpy() struct member write overflow!\n");63	pr_expected_config(CONFIG_FORTIFY_SOURCE);64 65	kfree(src);66}67 68static void lkdtm_FORTIFY_MEM_OBJECT(void)69{70	int before[10];71	struct target {72		char a[10];73		int foo;74	} target = {};75	int after[10];76	/*77	 * Using volatile prevents the compiler from determining the value of78	 * 'size' at compile time. Without that, we would get a compile error79	 * rather than a runtime error.80	 */81	volatile int size = 20;82 83	memset(before, 0, sizeof(before));84	memset(after, 0, sizeof(after));85	fortify_scratch_space = before[5];86	fortify_scratch_space = after[5];87 88	pr_info("trying to memcpy() past the end of a struct\n");89 90	pr_info("0: %zu\n", __builtin_object_size(&target, 0));91	pr_info("1: %zu\n", __builtin_object_size(&target, 1));92	pr_info("s: %d\n", size);93	memcpy(&target, &before, size);94 95	/* Store result to global to prevent the code from being eliminated */96	fortify_scratch_space = target.a[3];97 98	pr_err("FAIL: fortify did not block a memcpy() object write overflow!\n");99	pr_expected_config(CONFIG_FORTIFY_SOURCE);100}101 102static void lkdtm_FORTIFY_MEM_MEMBER(void)103{104	struct target {105		char a[10];106		char b[10];107	} target;108	volatile int size = 20;109	char *src;110 111	src = kmalloc(size, GFP_KERNEL);112	strscpy(src, "over ten bytes", size);113	size = strlen(src) + 1;114 115	pr_info("trying to memcpy() past the end of a struct member...\n");116 117	/*118	 * strncpy(target.a, src, 20); will hit a compile error because the119	 * compiler knows at build time that target.a < 20 bytes. Use a120	 * volatile to force a runtime error.121	 */122	memcpy(target.a, src, size);123 124	/* Store result to global to prevent the code from being eliminated */125	fortify_scratch_space = target.a[3];126 127	pr_err("FAIL: fortify did not block a memcpy() struct member write overflow!\n");128	pr_expected_config(CONFIG_FORTIFY_SOURCE);129 130	kfree(src);131}132 133/*134 * Calls fortified strscpy to test that it returns the same result as vanilla135 * strscpy and generate a panic because there is a write overflow (i.e. src136 * length is greater than dst length).137 */138static void lkdtm_FORTIFY_STRSCPY(void)139{140	char *src;141	char dst[5];142 143	struct {144		union {145			char big[10];146			char src[5];147		};148	} weird = { .big = "hello!" };149	char weird_dst[sizeof(weird.src) + 1];150 151	src = kstrdup("foobar", GFP_KERNEL);152 153	if (src == NULL)154		return;155 156	/* Vanilla strscpy returns -E2BIG if size is 0. */157	if (strscpy(dst, src, 0) != -E2BIG)158		pr_warn("FAIL: strscpy() of 0 length did not return -E2BIG\n");159 160	/* Vanilla strscpy returns -E2BIG if src is truncated. */161	if (strscpy(dst, src, sizeof(dst)) != -E2BIG)162		pr_warn("FAIL: strscpy() did not return -E2BIG while src is truncated\n");163 164	/* After above call, dst must contain "foob" because src was truncated. */165	if (strncmp(dst, "foob", sizeof(dst)) != 0)166		pr_warn("FAIL: after strscpy() dst does not contain \"foob\" but \"%s\"\n",167			dst);168 169	/* Shrink src so the strscpy() below succeeds. */170	src[3] = '\0';171 172	/*173	 * Vanilla strscpy returns number of character copied if everything goes174	 * well.175	 */176	if (strscpy(dst, src, sizeof(dst)) != 3)177		pr_warn("FAIL: strscpy() did not return 3 while src was copied entirely truncated\n");178 179	/* After above call, dst must contain "foo" because src was copied. */180	if (strncmp(dst, "foo", sizeof(dst)) != 0)181		pr_warn("FAIL: after strscpy() dst does not contain \"foo\" but \"%s\"\n",182			dst);183 184	/* Test when src is embedded inside a union. */185	strscpy(weird_dst, weird.src, sizeof(weird_dst));186 187	if (strcmp(weird_dst, "hello") != 0)188		pr_warn("FAIL: after strscpy() weird_dst does not contain \"hello\" but \"%s\"\n",189			weird_dst);190 191	/* Restore src to its initial value. */192	src[3] = 'b';193 194	/*195	 * Use strlen here so size cannot be known at compile time and there is196	 * a runtime write overflow.197	 */198	strscpy(dst, src, strlen(src));199 200	pr_err("FAIL: strscpy() overflow not detected!\n");201	pr_expected_config(CONFIG_FORTIFY_SOURCE);202 203	kfree(src);204}205 206static struct crashtype crashtypes[] = {207	CRASHTYPE(FORTIFY_STR_OBJECT),208	CRASHTYPE(FORTIFY_STR_MEMBER),209	CRASHTYPE(FORTIFY_MEM_OBJECT),210	CRASHTYPE(FORTIFY_MEM_MEMBER),211	CRASHTYPE(FORTIFY_STRSCPY),212};213 214struct crashtype_category fortify_crashtypes = {215	.crashtypes = crashtypes,216	.len	    = ARRAY_SIZE(crashtypes),217};218