diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/i915/gt/uc/intel_guc_log.c | 2 | ||||
-rw-r--r-- | drivers/misc/lkdtm/Makefile | 1 | ||||
-rw-r--r-- | drivers/misc/lkdtm/bugs.c | 50 | ||||
-rw-r--r-- | drivers/misc/lkdtm/core.c | 3 | ||||
-rw-r--r-- | drivers/misc/lkdtm/fortify.c | 82 | ||||
-rw-r--r-- | drivers/misc/lkdtm/lkdtm.h | 19 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/spectral.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath11k/spectral.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/common-spectral.c | 2 | ||||
-rw-r--r-- | drivers/rapidio/rio.c | 81 |
10 files changed, 152 insertions, 92 deletions
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c index 9bbe8a795cb8..c92f2c056db4 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c @@ -134,7 +134,7 @@ static int remove_buf_file_callback(struct dentry *dentry) } /* relay channel callbacks */ -static struct rchan_callbacks relay_callbacks = { +static const struct rchan_callbacks relay_callbacks = { .subbuf_start = subbuf_start_callback, .create_buf_file = create_buf_file_callback, .remove_buf_file = remove_buf_file_callback, diff --git a/drivers/misc/lkdtm/Makefile b/drivers/misc/lkdtm/Makefile index 1ef7888a12b5..7727bfd32be9 100644 --- a/drivers/misc/lkdtm/Makefile +++ b/drivers/misc/lkdtm/Makefile @@ -10,6 +10,7 @@ lkdtm-$(CONFIG_LKDTM) += rodata_objcopy.o lkdtm-$(CONFIG_LKDTM) += usercopy.o lkdtm-$(CONFIG_LKDTM) += stackleak.o lkdtm-$(CONFIG_LKDTM) += cfi.o +lkdtm-$(CONFIG_LKDTM) += fortify.o KASAN_SANITIZE_rodata.o := n KASAN_SANITIZE_stackleak.o := n diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c index a0675d4154d2..110f5a8538e9 100644 --- a/drivers/misc/lkdtm/bugs.c +++ b/drivers/misc/lkdtm/bugs.c @@ -482,3 +482,53 @@ noinline void lkdtm_CORRUPT_PAC(void) pr_err("XFAIL: this test is arm64-only\n"); #endif } + +void lkdtm_FORTIFY_OBJECT(void) +{ + struct target { + char a[10]; + } target[2] = {}; + int result; + + /* + * Using volatile prevents the compiler from determining the value of + * 'size' at compile time. Without that, we would get a compile error + * rather than a runtime error. + */ + volatile int size = 11; + + pr_info("trying to read past the end of a struct\n"); + + result = memcmp(&target[0], &target[1], size); + + /* Print result to prevent the code from being eliminated */ + pr_err("FAIL: fortify did not catch an object overread!\n" + "\"%d\" was the memcmp result.\n", result); +} + +void lkdtm_FORTIFY_SUBOBJECT(void) +{ + struct target { + char a[10]; + char b[10]; + } target; + char *src; + + src = kmalloc(20, GFP_KERNEL); + strscpy(src, "over ten bytes", 20); + + pr_info("trying to strcpy past the end of a member of a struct\n"); + + /* + * strncpy(target.a, src, 20); will hit a compile error because the + * compiler knows at build time that target.a < 20 bytes. Use strcpy() + * to force a runtime error. + */ + strcpy(target.a, src); + + /* Use target.a to prevent the code from being eliminated */ + pr_err("FAIL: fortify did not catch an sub-object overrun!\n" + "\"%s\" was copied.\n", target.a); + + kfree(src); +} diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index 97803f213d9d..3c0a67f072c0 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c @@ -117,6 +117,8 @@ static const struct crashtype crashtypes[] = { CRASHTYPE(UNSET_SMEP), CRASHTYPE(CORRUPT_PAC), CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE), + CRASHTYPE(FORTIFY_OBJECT), + CRASHTYPE(FORTIFY_SUBOBJECT), CRASHTYPE(OVERWRITE_ALLOCATION), CRASHTYPE(WRITE_AFTER_FREE), CRASHTYPE(READ_AFTER_FREE), @@ -173,6 +175,7 @@ static const struct crashtype crashtypes[] = { CRASHTYPE(USERCOPY_KERNEL), CRASHTYPE(STACKLEAK_ERASING), CRASHTYPE(CFI_FORWARD_PROTO), + CRASHTYPE(FORTIFIED_STRSCPY), #ifdef CONFIG_X86_32 CRASHTYPE(DOUBLE_FAULT), #endif diff --git a/drivers/misc/lkdtm/fortify.c b/drivers/misc/lkdtm/fortify.c new file mode 100644 index 000000000000..faf29cf04baa --- /dev/null +++ b/drivers/misc/lkdtm/fortify.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Francis Laniel <laniel_francis@privacyrequired.com> + * + * Add tests related to fortified functions in this file. + */ +#include "lkdtm.h" +#include <linux/string.h> +#include <linux/slab.h> + + +/* + * Calls fortified strscpy to test that it returns the same result as vanilla + * strscpy and generate a panic because there is a write overflow (i.e. src + * length is greater than dst length). + */ +void lkdtm_FORTIFIED_STRSCPY(void) +{ + char *src; + char dst[5]; + + struct { + union { + char big[10]; + char src[5]; + }; + } weird = { .big = "hello!" }; + char weird_dst[sizeof(weird.src) + 1]; + + src = kstrdup("foobar", GFP_KERNEL); + + if (src == NULL) + return; + + /* Vanilla strscpy returns -E2BIG if size is 0. */ + if (strscpy(dst, src, 0) != -E2BIG) + pr_warn("FAIL: strscpy() of 0 length did not return -E2BIG\n"); + + /* Vanilla strscpy returns -E2BIG if src is truncated. */ + if (strscpy(dst, src, sizeof(dst)) != -E2BIG) + pr_warn("FAIL: strscpy() did not return -E2BIG while src is truncated\n"); + + /* After above call, dst must contain "foob" because src was truncated. */ + if (strncmp(dst, "foob", sizeof(dst)) != 0) + pr_warn("FAIL: after strscpy() dst does not contain \"foob\" but \"%s\"\n", + dst); + + /* Shrink src so the strscpy() below succeeds. */ + src[3] = '\0'; + + /* + * Vanilla strscpy returns number of character copied if everything goes + * well. + */ + if (strscpy(dst, src, sizeof(dst)) != 3) + pr_warn("FAIL: strscpy() did not return 3 while src was copied entirely truncated\n"); + + /* After above call, dst must contain "foo" because src was copied. */ + if (strncmp(dst, "foo", sizeof(dst)) != 0) + pr_warn("FAIL: after strscpy() dst does not contain \"foo\" but \"%s\"\n", + dst); + + /* Test when src is embedded inside a union. */ + strscpy(weird_dst, weird.src, sizeof(weird_dst)); + + if (strcmp(weird_dst, "hello") != 0) + pr_warn("FAIL: after strscpy() weird_dst does not contain \"hello\" but \"%s\"\n", + weird_dst); + + /* Restore src to its initial value. */ + src[3] = 'b'; + + /* + * Use strlen here so size cannot be known at compile time and there is + * a runtime write overflow. + */ + strscpy(dst, src, strlen(src)); + + pr_warn("FAIL: No overflow in above strscpy()\n"); + + kfree(src); +} diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h index 6dec4c9b442f..6aa6d6a1a839 100644 --- a/drivers/misc/lkdtm/lkdtm.h +++ b/drivers/misc/lkdtm/lkdtm.h @@ -6,7 +6,7 @@ #include <linux/kernel.h> -/* lkdtm_bugs.c */ +/* bugs.c */ void __init lkdtm_bugs_init(int *recur_param); void lkdtm_PANIC(void); void lkdtm_BUG(void); @@ -32,8 +32,10 @@ void lkdtm_STACK_GUARD_PAGE_TRAILING(void); void lkdtm_UNSET_SMEP(void); void lkdtm_DOUBLE_FAULT(void); void lkdtm_CORRUPT_PAC(void); +void lkdtm_FORTIFY_OBJECT(void); +void lkdtm_FORTIFY_SUBOBJECT(void); -/* lkdtm_heap.c */ +/* heap.c */ void __init lkdtm_heap_init(void); void __exit lkdtm_heap_exit(void); void lkdtm_OVERWRITE_ALLOCATION(void); @@ -45,7 +47,7 @@ void lkdtm_SLAB_FREE_DOUBLE(void); void lkdtm_SLAB_FREE_CROSS(void); void lkdtm_SLAB_FREE_PAGE(void); -/* lkdtm_perms.c */ +/* perms.c */ void __init lkdtm_perms_init(void); void lkdtm_WRITE_RO(void); void lkdtm_WRITE_RO_AFTER_INIT(void); @@ -60,7 +62,7 @@ void lkdtm_EXEC_NULL(void); void lkdtm_ACCESS_USERSPACE(void); void lkdtm_ACCESS_NULL(void); -/* lkdtm_refcount.c */ +/* refcount.c */ void lkdtm_REFCOUNT_INC_OVERFLOW(void); void lkdtm_REFCOUNT_ADD_OVERFLOW(void); void lkdtm_REFCOUNT_INC_NOT_ZERO_OVERFLOW(void); @@ -81,10 +83,10 @@ void lkdtm_REFCOUNT_SUB_AND_TEST_SATURATED(void); void lkdtm_REFCOUNT_TIMING(void); void lkdtm_ATOMIC_TIMING(void); -/* lkdtm_rodata.c */ +/* rodata.c */ void lkdtm_rodata_do_nothing(void); -/* lkdtm_usercopy.c */ +/* usercopy.c */ void __init lkdtm_usercopy_init(void); void __exit lkdtm_usercopy_exit(void); void lkdtm_USERCOPY_HEAP_SIZE_TO(void); @@ -96,10 +98,13 @@ void lkdtm_USERCOPY_STACK_FRAME_FROM(void); void lkdtm_USERCOPY_STACK_BEYOND(void); void lkdtm_USERCOPY_KERNEL(void); -/* lkdtm_stackleak.c */ +/* stackleak.c */ void lkdtm_STACKLEAK_ERASING(void); /* cfi.c */ void lkdtm_CFI_FORWARD_PROTO(void); +/* fortify.c */ +void lkdtm_FORTIFIED_STRSCPY(void); + #endif diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c index 5db6bff5193b..68254a967ccb 100644 --- a/drivers/net/wireless/ath/ath10k/spectral.c +++ b/drivers/net/wireless/ath/ath10k/spectral.c @@ -497,7 +497,7 @@ static int remove_buf_file_handler(struct dentry *dentry) return 0; } -static struct rchan_callbacks rfs_spec_scan_cb = { +static const struct rchan_callbacks rfs_spec_scan_cb = { .create_buf_file = create_buf_file_handler, .remove_buf_file = remove_buf_file_handler, }; diff --git a/drivers/net/wireless/ath/ath11k/spectral.c b/drivers/net/wireless/ath/ath11k/spectral.c index ac2a8cfdc1c0..1afe67759659 100644 --- a/drivers/net/wireless/ath/ath11k/spectral.c +++ b/drivers/net/wireless/ath/ath11k/spectral.c @@ -148,7 +148,7 @@ static int remove_buf_file_handler(struct dentry *dentry) return 0; } -static struct rchan_callbacks rfs_scan_cb = { +static const struct rchan_callbacks rfs_scan_cb = { .create_buf_file = create_buf_file_handler, .remove_buf_file = remove_buf_file_handler, }; diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c index 21191955a7c1..e055adfb5361 100644 --- a/drivers/net/wireless/ath/ath9k/common-spectral.c +++ b/drivers/net/wireless/ath/ath9k/common-spectral.c @@ -1053,7 +1053,7 @@ static int remove_buf_file_handler(struct dentry *dentry) return 0; } -static struct rchan_callbacks rfs_spec_scan_cb = { +static const struct rchan_callbacks rfs_spec_scan_cb = { .create_buf_file = create_buf_file_handler, .remove_buf_file = remove_buf_file_handler, }; diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index 606986c5ba2c..c2b79736a92b 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -1413,71 +1413,6 @@ rio_mport_get_feature(struct rio_mport * port, int local, u16 destid, EXPORT_SYMBOL_GPL(rio_mport_get_feature); /** - * rio_get_asm - Begin or continue searching for a RIO device by vid/did/asm_vid/asm_did - * @vid: RIO vid to match or %RIO_ANY_ID to match all vids - * @did: RIO did to match or %RIO_ANY_ID to match all dids - * @asm_vid: RIO asm_vid to match or %RIO_ANY_ID to match all asm_vids - * @asm_did: RIO asm_did to match or %RIO_ANY_ID to match all asm_dids - * @from: Previous RIO device found in search, or %NULL for new search - * - * Iterates through the list of known RIO devices. If a RIO device is - * found with a matching @vid, @did, @asm_vid, @asm_did, the reference - * count to the device is incrememted and a pointer to its device - * structure is returned. Otherwise, %NULL is returned. A new search - * is initiated by passing %NULL to the @from argument. Otherwise, if - * @from is not %NULL, searches continue from next device on the global - * list. The reference count for @from is always decremented if it is - * not %NULL. - */ -struct rio_dev *rio_get_asm(u16 vid, u16 did, - u16 asm_vid, u16 asm_did, struct rio_dev *from) -{ - struct list_head *n; - struct rio_dev *rdev; - - WARN_ON(in_interrupt()); - spin_lock(&rio_global_list_lock); - n = from ? from->global_list.next : rio_devices.next; - - while (n && (n != &rio_devices)) { - rdev = rio_dev_g(n); - if ((vid == RIO_ANY_ID || rdev->vid == vid) && - (did == RIO_ANY_ID || rdev->did == did) && - (asm_vid == RIO_ANY_ID || rdev->asm_vid == asm_vid) && - (asm_did == RIO_ANY_ID || rdev->asm_did == asm_did)) - goto exit; - n = n->next; - } - rdev = NULL; - exit: - rio_dev_put(from); - rdev = rio_dev_get(rdev); - spin_unlock(&rio_global_list_lock); - return rdev; -} -EXPORT_SYMBOL_GPL(rio_get_asm); - -/** - * rio_get_device - Begin or continue searching for a RIO device by vid/did - * @vid: RIO vid to match or %RIO_ANY_ID to match all vids - * @did: RIO did to match or %RIO_ANY_ID to match all dids - * @from: Previous RIO device found in search, or %NULL for new search - * - * Iterates through the list of known RIO devices. If a RIO device is - * found with a matching @vid and @did, the reference count to the - * device is incrememted and a pointer to its device structure is returned. - * Otherwise, %NULL is returned. A new search is initiated by passing %NULL - * to the @from argument. Otherwise, if @from is not %NULL, searches - * continue from next device on the global list. The reference count for - * @from is always decremented if it is not %NULL. - */ -struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *from) -{ - return rio_get_asm(vid, did, RIO_ANY_ID, RIO_ANY_ID, from); -} -EXPORT_SYMBOL_GPL(rio_get_device); - -/** * rio_std_route_add_entry - Add switch route table entry using standard * registers defined in RIO specification rev.1.3 * @mport: Master port to issue transaction @@ -2106,20 +2041,6 @@ found: return rc; } -static void rio_fixup_device(struct rio_dev *dev) -{ -} - -static int rio_init(void) -{ - struct rio_dev *dev = NULL; - - while ((dev = rio_get_device(RIO_ANY_ID, RIO_ANY_ID, dev)) != NULL) { - rio_fixup_device(dev); - } - return 0; -} - static struct workqueue_struct *rio_wq; struct rio_disc_work { @@ -2206,8 +2127,6 @@ int rio_init_mports(void) kfree(work); no_disc: - rio_init(); - return 0; } EXPORT_SYMBOL_GPL(rio_init_mports); |