cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fortify.c (3983B)


      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
     11static volatile int fortify_scratch_space;
     12
     13static void lkdtm_FORTIFIED_OBJECT(void)
     14{
     15	struct target {
     16		char a[10];
     17	} target[2] = {};
     18	/*
     19	 * Using volatile prevents the compiler from determining the value of
     20	 * 'size' at compile time. Without that, we would get a compile error
     21	 * rather than a runtime error.
     22	 */
     23	volatile int size = 11;
     24
     25	pr_info("trying to read past the end of a struct\n");
     26
     27	/* Store result to global to prevent the code from being eliminated */
     28	fortify_scratch_space = memcmp(&target[0], &target[1], size);
     29
     30	pr_err("FAIL: fortify did not block an object overread!\n");
     31	pr_expected_config(CONFIG_FORTIFY_SOURCE);
     32}
     33
     34static void lkdtm_FORTIFIED_SUBOBJECT(void)
     35{
     36	struct target {
     37		char a[10];
     38		char b[10];
     39	} target;
     40	volatile int size = 20;
     41	char *src;
     42
     43	src = kmalloc(size, GFP_KERNEL);
     44	strscpy(src, "over ten bytes", size);
     45	size = strlen(src) + 1;
     46
     47	pr_info("trying to strncpy past the end of a member of a struct\n");
     48
     49	/*
     50	 * strncpy(target.a, src, 20); will hit a compile error because the
     51	 * compiler knows at build time that target.a < 20 bytes. Use a
     52	 * volatile to force a runtime error.
     53	 */
     54	strncpy(target.a, src, size);
     55
     56	/* Store result to global to prevent the code from being eliminated */
     57	fortify_scratch_space = target.a[3];
     58
     59	pr_err("FAIL: fortify did not block an sub-object overrun!\n");
     60	pr_expected_config(CONFIG_FORTIFY_SOURCE);
     61
     62	kfree(src);
     63}
     64
     65/*
     66 * Calls fortified strscpy to test that it returns the same result as vanilla
     67 * strscpy and generate a panic because there is a write overflow (i.e. src
     68 * length is greater than dst length).
     69 */
     70static void lkdtm_FORTIFIED_STRSCPY(void)
     71{
     72	char *src;
     73	char dst[5];
     74
     75	struct {
     76		union {
     77			char big[10];
     78			char src[5];
     79		};
     80	} weird = { .big = "hello!" };
     81	char weird_dst[sizeof(weird.src) + 1];
     82
     83	src = kstrdup("foobar", GFP_KERNEL);
     84
     85	if (src == NULL)
     86		return;
     87
     88	/* Vanilla strscpy returns -E2BIG if size is 0. */
     89	if (strscpy(dst, src, 0) != -E2BIG)
     90		pr_warn("FAIL: strscpy() of 0 length did not return -E2BIG\n");
     91
     92	/* Vanilla strscpy returns -E2BIG if src is truncated. */
     93	if (strscpy(dst, src, sizeof(dst)) != -E2BIG)
     94		pr_warn("FAIL: strscpy() did not return -E2BIG while src is truncated\n");
     95
     96	/* After above call, dst must contain "foob" because src was truncated. */
     97	if (strncmp(dst, "foob", sizeof(dst)) != 0)
     98		pr_warn("FAIL: after strscpy() dst does not contain \"foob\" but \"%s\"\n",
     99			dst);
    100
    101	/* Shrink src so the strscpy() below succeeds. */
    102	src[3] = '\0';
    103
    104	/*
    105	 * Vanilla strscpy returns number of character copied if everything goes
    106	 * well.
    107	 */
    108	if (strscpy(dst, src, sizeof(dst)) != 3)
    109		pr_warn("FAIL: strscpy() did not return 3 while src was copied entirely truncated\n");
    110
    111	/* After above call, dst must contain "foo" because src was copied. */
    112	if (strncmp(dst, "foo", sizeof(dst)) != 0)
    113		pr_warn("FAIL: after strscpy() dst does not contain \"foo\" but \"%s\"\n",
    114			dst);
    115
    116	/* Test when src is embedded inside a union. */
    117	strscpy(weird_dst, weird.src, sizeof(weird_dst));
    118
    119	if (strcmp(weird_dst, "hello") != 0)
    120		pr_warn("FAIL: after strscpy() weird_dst does not contain \"hello\" but \"%s\"\n",
    121			weird_dst);
    122
    123	/* Restore src to its initial value. */
    124	src[3] = 'b';
    125
    126	/*
    127	 * Use strlen here so size cannot be known at compile time and there is
    128	 * a runtime write overflow.
    129	 */
    130	strscpy(dst, src, strlen(src));
    131
    132	pr_err("FAIL: strscpy() overflow not detected!\n");
    133	pr_expected_config(CONFIG_FORTIFY_SOURCE);
    134
    135	kfree(src);
    136}
    137
    138static struct crashtype crashtypes[] = {
    139	CRASHTYPE(FORTIFIED_OBJECT),
    140	CRASHTYPE(FORTIFIED_SUBOBJECT),
    141	CRASHTYPE(FORTIFIED_STRSCPY),
    142};
    143
    144struct crashtype_category fortify_crashtypes = {
    145	.crashtypes = crashtypes,
    146	.len	    = ARRAY_SIZE(crashtypes),
    147};