Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2020 Francis Laniel <laniel_francis@privacyrequired.com>
0004  *
0005  * Add tests related to fortified functions in this file.
0006  */
0007 #include "lkdtm.h"
0008 #include <linux/string.h>
0009 #include <linux/slab.h>
0010 
0011 static volatile int fortify_scratch_space;
0012 
0013 static void lkdtm_FORTIFIED_OBJECT(void)
0014 {
0015     struct target {
0016         char a[10];
0017     } target[2] = {};
0018     /*
0019      * Using volatile prevents the compiler from determining the value of
0020      * 'size' at compile time. Without that, we would get a compile error
0021      * rather than a runtime error.
0022      */
0023     volatile int size = 11;
0024 
0025     pr_info("trying to read past the end of a struct\n");
0026 
0027     /* Store result to global to prevent the code from being eliminated */
0028     fortify_scratch_space = memcmp(&target[0], &target[1], size);
0029 
0030     pr_err("FAIL: fortify did not block an object overread!\n");
0031     pr_expected_config(CONFIG_FORTIFY_SOURCE);
0032 }
0033 
0034 static void lkdtm_FORTIFIED_SUBOBJECT(void)
0035 {
0036     struct target {
0037         char a[10];
0038         char b[10];
0039     } target;
0040     volatile int size = 20;
0041     char *src;
0042 
0043     src = kmalloc(size, GFP_KERNEL);
0044     strscpy(src, "over ten bytes", size);
0045     size = strlen(src) + 1;
0046 
0047     pr_info("trying to strncpy past the end of a member of a struct\n");
0048 
0049     /*
0050      * strncpy(target.a, src, 20); will hit a compile error because the
0051      * compiler knows at build time that target.a < 20 bytes. Use a
0052      * volatile to force a runtime error.
0053      */
0054     strncpy(target.a, src, size);
0055 
0056     /* Store result to global to prevent the code from being eliminated */
0057     fortify_scratch_space = target.a[3];
0058 
0059     pr_err("FAIL: fortify did not block an sub-object overrun!\n");
0060     pr_expected_config(CONFIG_FORTIFY_SOURCE);
0061 
0062     kfree(src);
0063 }
0064 
0065 /*
0066  * Calls fortified strscpy to test that it returns the same result as vanilla
0067  * strscpy and generate a panic because there is a write overflow (i.e. src
0068  * length is greater than dst length).
0069  */
0070 static void lkdtm_FORTIFIED_STRSCPY(void)
0071 {
0072     char *src;
0073     char dst[5];
0074 
0075     struct {
0076         union {
0077             char big[10];
0078             char src[5];
0079         };
0080     } weird = { .big = "hello!" };
0081     char weird_dst[sizeof(weird.src) + 1];
0082 
0083     src = kstrdup("foobar", GFP_KERNEL);
0084 
0085     if (src == NULL)
0086         return;
0087 
0088     /* Vanilla strscpy returns -E2BIG if size is 0. */
0089     if (strscpy(dst, src, 0) != -E2BIG)
0090         pr_warn("FAIL: strscpy() of 0 length did not return -E2BIG\n");
0091 
0092     /* Vanilla strscpy returns -E2BIG if src is truncated. */
0093     if (strscpy(dst, src, sizeof(dst)) != -E2BIG)
0094         pr_warn("FAIL: strscpy() did not return -E2BIG while src is truncated\n");
0095 
0096     /* After above call, dst must contain "foob" because src was truncated. */
0097     if (strncmp(dst, "foob", sizeof(dst)) != 0)
0098         pr_warn("FAIL: after strscpy() dst does not contain \"foob\" but \"%s\"\n",
0099             dst);
0100 
0101     /* Shrink src so the strscpy() below succeeds. */
0102     src[3] = '\0';
0103 
0104     /*
0105      * Vanilla strscpy returns number of character copied if everything goes
0106      * well.
0107      */
0108     if (strscpy(dst, src, sizeof(dst)) != 3)
0109         pr_warn("FAIL: strscpy() did not return 3 while src was copied entirely truncated\n");
0110 
0111     /* After above call, dst must contain "foo" because src was copied. */
0112     if (strncmp(dst, "foo", sizeof(dst)) != 0)
0113         pr_warn("FAIL: after strscpy() dst does not contain \"foo\" but \"%s\"\n",
0114             dst);
0115 
0116     /* Test when src is embedded inside a union. */
0117     strscpy(weird_dst, weird.src, sizeof(weird_dst));
0118 
0119     if (strcmp(weird_dst, "hello") != 0)
0120         pr_warn("FAIL: after strscpy() weird_dst does not contain \"hello\" but \"%s\"\n",
0121             weird_dst);
0122 
0123     /* Restore src to its initial value. */
0124     src[3] = 'b';
0125 
0126     /*
0127      * Use strlen here so size cannot be known at compile time and there is
0128      * a runtime write overflow.
0129      */
0130     strscpy(dst, src, strlen(src));
0131 
0132     pr_err("FAIL: strscpy() overflow not detected!\n");
0133     pr_expected_config(CONFIG_FORTIFY_SOURCE);
0134 
0135     kfree(src);
0136 }
0137 
0138 static struct crashtype crashtypes[] = {
0139     CRASHTYPE(FORTIFIED_OBJECT),
0140     CRASHTYPE(FORTIFIED_SUBOBJECT),
0141     CRASHTYPE(FORTIFIED_STRSCPY),
0142 };
0143 
0144 struct crashtype_category fortify_crashtypes = {
0145     .crashtypes = crashtypes,
0146     .len        = ARRAY_SIZE(crashtypes),
0147 };