diff options
author | Linus Torvalds | 2020-12-15 23:26:37 -0800 |
---|---|---|
committer | Linus Torvalds | 2020-12-15 23:26:37 -0800 |
commit | f986e350833347cb605d9d1ed517325c9a97808d (patch) | |
tree | 460a60e107791f64d1d897c97763298781824c54 | |
parent | d01e7f10dae29eba0f9ada82b65d24e035d5b2f9 (diff) | |
parent | 8958b2491104d7f254cff0698505392582dbc13a (diff) |
Merge branch 'akpm' (patches from Andrew)
Merge yet more updates from Andrew Morton:
- lots of little subsystems
- a few post-linux-next MM material. Most of the rest awaits more
merging of other trees.
Subsystems affected by this series: alpha, procfs, misc, core-kernel,
bitmap, lib, lz4, checkpatch, nilfs, kdump, rapidio, gcov, bfs, relay,
resource, ubsan, reboot, fault-injection, lzo, apparmor, and mm (swap,
memory-hotplug, pagemap, cleanups, and gup).
* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (86 commits)
mm: fix some spelling mistakes in comments
mm: simplify follow_pte{,pmd}
mm: unexport follow_pte_pmd
apparmor: remove duplicate macro list_entry_is_head()
lib/lzo/lzo1x_compress.c: make lzogeneric1x_1_compress() static
fault-injection: handle EI_ETYPE_TRUE
reboot: hide from sysfs not applicable settings
reboot: allow to override reboot type if quirks are found
reboot: remove cf9_safe from allowed types and rename cf9_force
reboot: allow to specify reboot mode via sysfs
reboot: refactor and comment the cpu selection code
lib/ubsan.c: mark type_check_kinds with static keyword
kcov: don't instrument with UBSAN
ubsan: expand tests and reporting
ubsan: remove UBSAN_MISC in favor of individual options
ubsan: enable for all*config builds
ubsan: disable UBSAN_TRAP for all*config
ubsan: disable object-size sanitizer under GCC
ubsan: move cc-option tests into Kconfig
ubsan: remove redundant -Wno-maybe-uninitialized
...
87 files changed, 1568 insertions, 724 deletions
diff --git a/Documentation/ABI/testing/sysfs-kernel-reboot b/Documentation/ABI/testing/sysfs-kernel-reboot new file mode 100644 index 000000000000..837330fb2511 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-kernel-reboot @@ -0,0 +1,32 @@ +What: /sys/kernel/reboot +Date: November 2020 +KernelVersion: 5.11 +Contact: Matteo Croce <mcroce@microsoft.com> +Description: Interface to set the kernel reboot behavior, similarly to + what can be done via the reboot= cmdline option. + (see Documentation/admin-guide/kernel-parameters.txt) + +What: /sys/kernel/reboot/mode +Date: November 2020 +KernelVersion: 5.11 +Contact: Matteo Croce <mcroce@microsoft.com> +Description: Reboot mode. Valid values are: cold warm hard soft gpio + +What: /sys/kernel/reboot/type +Date: November 2020 +KernelVersion: 5.11 +Contact: Matteo Croce <mcroce@microsoft.com> +Description: Reboot type. Valid values are: bios acpi kbd triple efi pci + +What: /sys/kernel/reboot/cpu +Date: November 2020 +KernelVersion: 5.11 +Contact: Matteo Croce <mcroce@microsoft.com> +Description: CPU number to use to reboot. + +What: /sys/kernel/reboot/force +Date: November 2020 +KernelVersion: 5.11 +Contact: Matteo Croce <mcroce@microsoft.com> +Description: Don't wait for any other CPUs on reboot and + avoid anything that could hang. diff --git a/Documentation/admin-guide/kdump/vmcoreinfo.rst b/Documentation/admin-guide/kdump/vmcoreinfo.rst index e44a6c01f336..3861a25faae1 100644 --- a/Documentation/admin-guide/kdump/vmcoreinfo.rst +++ b/Documentation/admin-guide/kdump/vmcoreinfo.rst @@ -39,6 +39,12 @@ call. User-space tools can get the kernel name, host name, kernel release number, kernel version, architecture name and OS type from it. +(uts_namespace, name) +--------------------- + +Offset of the name's member. Crash Utility and Makedumpfile get +the start address of the init_uts_ns.name from this. + node_online_map --------------- diff --git a/Documentation/dev-tools/ubsan.rst b/Documentation/dev-tools/ubsan.rst index 655e6b63c227..1be6618e232d 100644 --- a/Documentation/dev-tools/ubsan.rst +++ b/Documentation/dev-tools/ubsan.rst @@ -86,3 +86,4 @@ References .. _1: https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/Debugging-Options.html .. _2: https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html +.. _3: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html diff --git a/Documentation/filesystems/proc.rst b/Documentation/filesystems/proc.rst index e5fa972d4c76..2fa69f710e2a 100644 --- a/Documentation/filesystems/proc.rst +++ b/Documentation/filesystems/proc.rst @@ -210,6 +210,7 @@ read the file /proc/PID/status:: NoNewPrivs: 0 Seccomp: 0 Speculation_Store_Bypass: thread vulnerable + SpeculationIndirectBranch: conditional enabled voluntary_ctxt_switches: 0 nonvoluntary_ctxt_switches: 1 @@ -292,6 +293,7 @@ It's slow but very precise. NoNewPrivs no_new_privs, like prctl(PR_GET_NO_NEW_PRIV, ...) Seccomp seccomp mode, like prctl(PR_GET_SECCOMP, ...) Speculation_Store_Bypass speculative store bypass mitigation status + SpeculationIndirectBranch indirect branch speculation mode Cpus_allowed mask of CPUs on which this process may run Cpus_allowed_list Same as previous, but in "list format" Mems_allowed mask of memory nodes allowed to this process diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 4c7b0414a3ff..6c71554206cc 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -134,7 +134,7 @@ common_shutdown_1(void *generic_ptr) #ifdef CONFIG_DUMMY_CONSOLE /* If we've gotten here after SysRq-b, leave interrupt context before taking over the console. */ - if (in_interrupt()) + if (in_irq()) irq_exit(); /* This has the effect of resetting the VGA video origin. */ console_lock(); diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 6db90cdf11da..e184d17387f6 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -313,6 +313,10 @@ SECTIONS #else .data : AT(ADDR(.data) - LOAD_OFFSET) { DATA_DATA +#ifdef CONFIG_UBSAN + *(.data..Lubsan_data*) + *(.data..Lubsan_type*) +#endif *(.data.rel*) *(.toc1) *(.branch_lt) diff --git a/arch/s390/pci/pci_mmio.c b/arch/s390/pci/pci_mmio.c index de3bdbed8881..18f2d10c3176 100644 --- a/arch/s390/pci/pci_mmio.c +++ b/arch/s390/pci/pci_mmio.c @@ -170,7 +170,7 @@ SYSCALL_DEFINE3(s390_pci_mmio_write, unsigned long, mmio_addr, if (!(vma->vm_flags & VM_WRITE)) goto out_unlock_mmap; - ret = follow_pte_pmd(vma->vm_mm, mmio_addr, NULL, &ptep, NULL, &ptl); + ret = follow_pte(vma->vm_mm, mmio_addr, NULL, &ptep, NULL, &ptl); if (ret) goto out_unlock_mmap; @@ -311,7 +311,7 @@ SYSCALL_DEFINE3(s390_pci_mmio_read, unsigned long, mmio_addr, if (!(vma->vm_flags & VM_WRITE)) goto out_unlock_mmap; - ret = follow_pte_pmd(vma->vm_mm, mmio_addr, NULL, &ptep, NULL, &ptl); + ret = follow_pte(vma->vm_mm, mmio_addr, NULL, &ptep, NULL, &ptl); if (ret) goto out_unlock_mmap; 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); diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index 3ac7611ef7ce..fd691e4815c5 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -350,7 +350,7 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) info->si_lasti = (le32_to_cpu(bfs_sb->s_start) - BFS_BSIZE) / sizeof(struct bfs_inode) + BFS_ROOT_INO - 1; if (info->si_lasti == BFS_MAX_LASTI) - printf("WARNING: filesystem %s was created with 512 inodes, the real maximum is 511, mounting anyway\n", s->s_id); + printf("NOTE: filesystem %s was created with 512 inodes, the real maximum is 511, mounting anyway\n", s->s_id); else if (info->si_lasti > BFS_MAX_LASTI) { printf("Impossible last inode number %lu > %d on %s\n", info->si_lasti, BFS_MAX_LASTI, s->s_id); goto out1; @@ -810,12 +810,11 @@ static void dax_entry_mkclean(struct address_space *mapping, pgoff_t index, address = pgoff_address(index, vma); /* - * Note because we provide range to follow_pte_pmd it will - * call mmu_notifier_invalidate_range_start() on our behalf - * before taking any lock. + * Note because we provide range to follow_pte it will call + * mmu_notifier_invalidate_range_start() on our behalf before + * taking any lock. */ - if (follow_pte_pmd(vma->vm_mm, address, &range, - &ptep, &pmdp, &ptl)) + if (follow_pte(vma->vm_mm, address, &range, &ptep, &pmdp, &ptl)) continue; /* diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index e61dbc9b86ae..f7786e00a6a7 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -6,10 +6,15 @@ * * NFSv4 callback procedures */ + +#include <linux/errno.h> +#include <linux/math.h> #include <linux/nfs4.h> #include <linux/nfs_fs.h> #include <linux/slab.h> #include <linux/rcupdate.h> +#include <linux/types.h> + #include "nfs4_fs.h" #include "callback.h" #include "delegation.h" diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index e3726aca28ed..cd4da9535aed 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -134,14 +134,9 @@ static void nilfs_segctor_do_flush(struct nilfs_sc_info *, int); static void nilfs_segctor_do_immediate_flush(struct nilfs_sc_info *); static void nilfs_dispose_list(struct the_nilfs *, struct list_head *, int); -#define nilfs_cnt32_gt(a, b) \ - (typecheck(__u32, a) && typecheck(__u32, b) && \ - ((__s32)(b) - (__s32)(a) < 0)) #define nilfs_cnt32_ge(a, b) \ (typecheck(__u32, a) && typecheck(__u32, b) && \ ((__s32)(a) - (__s32)(b) >= 0)) -#define nilfs_cnt32_lt(a, b) nilfs_cnt32_gt(b, a) -#define nilfs_cnt32_le(a, b) nilfs_cnt32_ge(b, a) static int nilfs_prepare_segment_lock(struct super_block *sb, struct nilfs_transaction_info *ti) diff --git a/fs/proc/array.c b/fs/proc/array.c index a23c3e220a5f..bb87e4d89cd8 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -369,6 +369,34 @@ static inline void task_seccomp(struct seq_file *m, struct task_struct *p) seq_puts(m, "vulnerable"); break; } + + seq_puts(m, "\nSpeculationIndirectBranch:\t"); + switch (arch_prctl_spec_ctrl_get(p, PR_SPEC_INDIRECT_BRANCH)) { + case -EINVAL: + seq_puts(m, "unsupported"); + break; + case PR_SPEC_NOT_AFFECTED: + seq_puts(m, "not affected"); + break; + case PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE: + seq_puts(m, "conditional force disabled"); + break; + case PR_SPEC_PRCTL | PR_SPEC_DISABLE: + seq_puts(m, "conditional disabled"); + break; + case PR_SPEC_PRCTL | PR_SPEC_ENABLE: + seq_puts(m, "conditional enabled"); + break; + case PR_SPEC_ENABLE: + seq_puts(m, "always enabled"); + break; + case PR_SPEC_DISABLE: + seq_puts(m, "always disabled"); + break; + default: + seq_puts(m, "unknown"); + break; + } seq_putc(m, '\n'); } diff --git a/fs/proc/base.c b/fs/proc/base.c index 55ce0ee9c5c7..e71040b68991 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -2021,7 +2021,7 @@ const struct dentry_operations pid_dentry_operations = * file type from dcache entry. * * Since all of the proc inode numbers are dynamically generated, the inode - * numbers do not exist until the inode is cache. This means creating the + * numbers do not exist until the inode is cache. This means creating * the dcache entry in readdir is necessary to keep the inode numbers * reported by readdir in sync with the inode numbers reported * by stat. diff --git a/fs/proc/generic.c b/fs/proc/generic.c index b84663252add..6c0a05f55d6b 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -349,6 +349,16 @@ static const struct file_operations proc_dir_operations = { .iterate_shared = proc_readdir, }; +static int proc_net_d_revalidate(struct dentry *dentry, unsigned int flags) +{ + return 0; +} + +const struct dentry_operations proc_net_dentry_ops = { + .d_revalidate = proc_net_d_revalidate, + .d_delete = always_delete_dentry, +}; + /* * proc directories can do almost nothing.. */ @@ -471,8 +481,8 @@ struct proc_dir_entry *proc_symlink(const char *name, } EXPORT_SYMBOL(proc_symlink); -struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode, - struct proc_dir_entry *parent, void *data) +struct proc_dir_entry *_proc_mkdir(const char *name, umode_t mode, + struct proc_dir_entry *parent, void *data, bool force_lookup) { struct proc_dir_entry *ent; @@ -484,10 +494,20 @@ struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode, ent->data = data; ent->proc_dir_ops = &proc_dir_operations; ent->proc_iops = &proc_dir_inode_operations; + if (force_lookup) { + pde_force_lookup(ent); + } ent = proc_register(parent, ent); } return ent; } +EXPORT_SYMBOL_GPL(_proc_mkdir); + +struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode, + struct proc_dir_entry *parent, void *data) +{ + return _proc_mkdir(name, mode, parent, data, false); +} EXPORT_SYMBOL_GPL(proc_mkdir_data); struct proc_dir_entry *proc_mkdir_mode(const char *name, umode_t mode, diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 917cc85e3466..f60b379dcdc7 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -190,10 +190,9 @@ struct dentry *proc_lookup_de(struct inode *, struct dentry *, struct proc_dir_e extern int proc_readdir(struct file *, struct dir_context *); int proc_readdir_de(struct file *, struct dir_context *, struct proc_dir_entry *); -static inline struct proc_dir_entry *pde_get(struct proc_dir_entry *pde) +static inline void pde_get(struct proc_dir_entry *pde) { refcount_inc(&pde->refcnt); - return pde; } extern void pde_put(struct proc_dir_entry *); @@ -310,3 +309,10 @@ extern unsigned long task_statm(struct mm_struct *, unsigned long *, unsigned long *, unsigned long *, unsigned long *); extern void task_mem(struct seq_file *, struct mm_struct *); + +extern const struct dentry_operations proc_net_dentry_ops; +static inline void pde_force_lookup(struct proc_dir_entry *pde) +{ + /* /proc/net/ entries can be changed under us by setns(CLONE_NEWNET) */ + pde->proc_dops = &proc_net_dentry_ops; +} diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c index ed8a6306990c..18601042af99 100644 --- a/fs/proc/proc_net.c +++ b/fs/proc/proc_net.c @@ -39,22 +39,6 @@ static struct net *get_proc_net(const struct inode *inode) return maybe_get_net(PDE_NET(PDE(inode))); } -static int proc_net_d_revalidate(struct dentry *dentry, unsigned int flags) -{ - return 0; -} - -static const struct dentry_operations proc_net_dentry_ops = { - .d_revalidate = proc_net_d_revalidate, - .d_delete = always_delete_dentry, -}; - -static void pde_force_lookup(struct proc_dir_entry *pde) -{ - /* /proc/net/ entries can be changed under us by setns(CLONE_NEWNET) */ - pde->proc_dops = &proc_net_dentry_ops; -} - static int seq_open_net(struct inode *inode, struct file *file) { unsigned int state_size = PDE(inode)->state_size; @@ -140,7 +124,7 @@ EXPORT_SYMBOL_GPL(proc_create_net_data); * @mode: The file's access mode. * @parent: The parent directory in which to create. * @ops: The seq_file ops with which to read the file. - * @write: The write method which which to 'modify' the file. + * @write: The write method with which to 'modify' the file. * @data: Data for retrieval by PDE_DATA(). * * Create a network namespaced proc file in the @parent directory with the @@ -232,7 +216,7 @@ EXPORT_SYMBOL_GPL(proc_create_net_single); * @mode: The file's access mode. * @parent: The parent directory in which to create. * @show: The seqfile show method with which to read the file. - * @write: The write method which which to 'modify' the file. + * @write: The write method with which to 'modify' the file. * @data: Data for retrieval by PDE_DATA(). * * Create a network-namespaced proc file in the @parent directory with the diff --git a/include/asm-generic/getorder.h b/include/asm-generic/getorder.h index e9f20b813a69..f2979e3a96b6 100644 --- a/include/asm-generic/getorder.h +++ b/include/asm-generic/getorder.h @@ -26,7 +26,7 @@ * * The result is undefined if the size is 0. */ -static inline __attribute_const__ int get_order(unsigned long size) +static __always_inline __attribute_const__ int get_order(unsigned long size) { if (__builtin_constant_p(size)) { if (!size) diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h index 99058eb81042..70a932470b2d 100644 --- a/include/linux/bitmap.h +++ b/include/linux/bitmap.h @@ -126,8 +126,6 @@ extern void bitmap_free(const unsigned long *bitmap); * lib/bitmap.c provides these functions: */ -extern int __bitmap_empty(const unsigned long *bitmap, unsigned int nbits); -extern int __bitmap_full(const unsigned long *bitmap, unsigned int nbits); extern int __bitmap_equal(const unsigned long *bitmap1, const unsigned long *bitmap2, unsigned int nbits); extern bool __pure __bitmap_or_equal(const unsigned long *src1, @@ -379,7 +377,7 @@ static inline int bitmap_subset(const unsigned long *src1, return __bitmap_subset(src1, src2, nbits); } -static inline int bitmap_empty(const unsigned long *src, unsigned nbits) +static inline bool bitmap_empty(const unsigned long *src, unsigned nbits) { if (small_const_nbits(nbits)) return ! (*src & BITMAP_LAST_WORD_MASK(nbits)); @@ -387,7 +385,7 @@ static inline int bitmap_empty(const unsigned long *src, unsigned nbits) return find_first_bit(src, nbits) == nbits; } -static inline int bitmap_full(const unsigned long *src, unsigned int nbits) +static inline bool bitmap_full(const unsigned long *src, unsigned int nbits) { if (small_const_nbits(nbits)) return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits)); diff --git a/include/linux/bitops.h b/include/linux/bitops.h index 5b74bdf159d6..a61f192c096b 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h @@ -1,9 +1,12 @@ /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_BITOPS_H #define _LINUX_BITOPS_H + #include <asm/types.h> #include <linux/bits.h> +#include <uapi/linux/kernel.h> + /* Set bits in the first 'n' bytes when loaded from memory */ #ifdef __LITTLE_ENDIAN # define aligned_byte_mask(n) ((1UL << 8*(n))-1) @@ -12,10 +15,10 @@ #endif #define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE) -#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(long)) -#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(u64)) -#define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(u32)) -#define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(char)) +#define BITS_TO_LONGS(nr) __KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(long)) +#define BITS_TO_U64(nr) __KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(u64)) +#define BITS_TO_U32(nr) __KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(u32)) +#define BITS_TO_BYTES(nr) __KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(char)) extern unsigned int __sw_hweight8(unsigned int w); extern unsigned int __sw_hweight16(unsigned int w); diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 6f95c3300cbb..d7b369fc15d3 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -4,6 +4,7 @@ #include <linux/atomic.h> #include <linux/list.h> +#include <linux/math.h> #include <linux/rculist.h> #include <linux/rculist_bl.h> #include <linux/spinlock.h> diff --git a/include/linux/iommu-helper.h b/include/linux/iommu-helper.h index 70d01edcbf8b..74be34f3a20a 100644 --- a/include/linux/iommu-helper.h +++ b/include/linux/iommu-helper.h @@ -3,7 +3,9 @@ #define _LINUX_IOMMU_HELPER_H #include <linux/bug.h> -#include <linux/kernel.h> +#include <linux/log2.h> +#include <linux/math.h> +#include <linux/types.h> static inline unsigned long iommu_device_max_index(unsigned long size, unsigned long offset, diff --git a/include/linux/kernel.h b/include/linux/kernel.h index dbf6018fc312..f7902d8c1048 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -2,7 +2,6 @@ #ifndef _LINUX_KERNEL_H #define _LINUX_KERNEL_H - #include <stdarg.h> #include <linux/limits.h> #include <linux/linkage.h> @@ -11,12 +10,14 @@ #include <linux/compiler.h> #include <linux/bitops.h> #include <linux/log2.h> +#include <linux/math.h> #include <linux/minmax.h> #include <linux/typecheck.h> #include <linux/printk.h> #include <linux/build_bug.h> + #include <asm/byteorder.h> -#include <asm/div64.h> + #include <uapi/linux/kernel.h> #define STACK_MAGIC 0xdeadbeef @@ -54,125 +55,11 @@ } \ ) -/* - * This looks more complex than it should be. But we need to - * get the type for the ~ right in round_down (it needs to be - * as wide as the result!), and we want to evaluate the macro - * arguments just once each. - */ -#define __round_mask(x, y) ((__typeof__(x))((y)-1)) -/** - * round_up - round up to next specified power of 2 - * @x: the value to round - * @y: multiple to round up to (must be a power of 2) - * - * Rounds @x up to next multiple of @y (which must be a power of 2). - * To perform arbitrary rounding up, use roundup() below. - */ -#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) -/** - * round_down - round down to next specified power of 2 - * @x: the value to round - * @y: multiple to round down to (must be a power of 2) - * - * Rounds @x down to next multiple of @y (which must be a power of 2). - * To perform arbitrary rounding down, use rounddown() below. - */ -#define round_down(x, y) ((x) & ~__round_mask(x, y)) - #define typeof_member(T, m) typeof(((T*)0)->m) -#define DIV_ROUND_UP __KERNEL_DIV_ROUND_UP - -#define DIV_ROUND_DOWN_ULL(ll, d) \ - ({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; }) - -#define DIV_ROUND_UP_ULL(ll, d) \ - DIV_ROUND_DOWN_ULL((unsigned long long)(ll) + (d) - 1, (d)) - -#if BITS_PER_LONG == 32 -# define DIV_ROUND_UP_SECTOR_T(ll,d) DIV_ROUND_UP_ULL(ll, d) -#else -# define DIV_ROUND_UP_SECTOR_T(ll,d) DIV_ROUND_UP(ll,d) -#endif - -/** - * roundup - round up to the next specified multiple - * @x: the value to up - * @y: multiple to round up to - * - * Rounds @x up to next multiple of @y. If @y will always be a power - * of 2, consider using the faster round_up(). - */ -#define roundup(x, y) ( \ -{ \ - typeof(y) __y = y; \ - (((x) + (__y - 1)) / __y) * __y; \ -} \ -) -/** - * rounddown - round down to next specified multiple - * @x: the value to round - * @y: multiple to round down to - * - * Rounds @x down to next multiple of @y. If @y will always be a power - * of 2, consider using the faster round_down(). - */ -#define rounddown(x, y) ( \ -{ \ - typeof(x) __x = (x); \ - __x - (__x % (y)); \ -} \ -) - -/* - * Divide positive or negative dividend by positive or negative divisor - * and round to closest integer. Result is undefined for negative - * divisors if the dividend variable type is unsigned and for negative - * dividends if the divisor variable type is unsigned. - */ -#define DIV_ROUND_CLOSEST(x, divisor)( \ -{ \ - typeof(x) __x = x; \ - typeof(divisor) __d = divisor; \ - (((typeof(x))-1) > 0 || \ - ((typeof(divisor))-1) > 0 || \ - (((__x) > 0) == ((__d) > 0))) ? \ - (((__x) + ((__d) / 2)) / (__d)) : \ - (((__x) - ((__d) / 2)) / (__d)); \ -} \ -) -/* - * Same as above but for u64 dividends. divisor must be a 32-bit - * number. - */ -#define DIV_ROUND_CLOSEST_ULL(x, divisor)( \ -{ \ - typeof(divisor) __d = divisor; \ - unsigned long long _tmp = (x) + (__d) / 2; \ - do_div(_tmp, __d); \ - _tmp; \ -} \ -) - -/* - * Multiplies an integer by a fraction, while avoiding unnecessary - * overflow or loss of precision. - */ -#define mult_frac(x, numer, denom)( \ -{ \ - typeof(x) quot = (x) / (denom); \ - typeof(x) rem = (x) % (denom); \ - (quot * (numer)) + ((rem * (numer)) / (denom)); \ -} \ -) - - #define _RET_IP_ (unsigned long)__builtin_return_address(0) #define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; }) -#define sector_div(a, b) do_div(a, b) - /** * upper_32_bits - return bits 32-63 of a number * @n: the number we're accessing @@ -272,48 +159,6 @@ extern void __cant_migrate(const char *file, int line); #define might_sleep_if(cond) do { if (cond) might_sleep(); } while (0) -/** - * abs - return absolute value of an argument - * @x: the value. If it is unsigned type, it is converted to signed type first. - * char is treated as if it was signed (regardless of whether it really is) - * but the macro's return type is preserved as char. - * - * Return: an absolute value of x. - */ -#define abs(x) __abs_choose_expr(x, long long, \ - __abs_choose_expr(x, long, \ - __abs_choose_expr(x, int, \ - __abs_choose_expr(x, short, \ - __abs_choose_expr(x, char, \ - __builtin_choose_expr( \ - __builtin_types_compatible_p(typeof(x), char), \ - (char)({ signed char __x = (x); __x<0?-__x:__x; }), \ - ((void)0))))))) - -#define __abs_choose_expr(x, type, other) __builtin_choose_expr( \ - __builtin_types_compatible_p(typeof(x), signed type) || \ - __builtin_types_compatible_p(typeof(x), unsigned type), \ - ({ signed type __x = (x); __x < 0 ? -__x : __x; }), other) - -/** - * reciprocal_scale - "scale" a value into range [0, ep_ro) - * @val: value - * @ep_ro: right open interval endpoint - * - * Perform a "reciprocal multiplication" in order to "scale" a value into - * range [0, @ep_ro), where the upper interval endpoint is right-open. - * This is useful, e.g. for accessing a index of an array containing - * @ep_ro elements, for example. Think of it as sort of modulus, only that - * the result isn't that of modulo. ;) Note that if initial input is a - * small value, then result will return 0. - * - * Return: a result based on @val in interval [0, @ep_ro). - */ -static inline u32 reciprocal_scale(u32 val, u32 ep_ro) -{ - return (u32)(((u64) val * ep_ro) >> 32); -} - #if defined(CONFIG_MMU) && \ (defined(CONFIG_PROVE_LOCKING) || defined(CONFIG_DEBUG_ATOMIC_SLEEP)) #define might_fault() __might_fault(__FILE__, __LINE__) @@ -515,18 +360,6 @@ extern int __kernel_text_address(unsigned long addr); extern int kernel_text_address(unsigned long addr); extern int func_ptr_is_kernel_text(void *ptr); -u64 int_pow(u64 base, unsigned int exp); -unsigned long int_sqrt(unsigned long); - -#if BITS_PER_LONG < 64 -u32 int_sqrt64(u64 x); -#else -static inline u32 int_sqrt64(u64 x) -{ - return (u32)int_sqrt(x); -} -#endif - #ifdef CONFIG_SMP extern unsigned int sysctl_oops_all_cpu_backtrace; #else diff --git a/include/linux/log2.h b/include/linux/log2.h index c619ec6eff4a..df0b155c2141 100644 --- a/include/linux/log2.h +++ b/include/linux/log2.h @@ -156,7 +156,8 @@ unsigned long __rounddown_pow_of_two(unsigned long n) #define ilog2(n) \ ( \ __builtin_constant_p(n) ? \ - const_ilog2(n) : \ + ((n) < 2 ? 0 : \ + 63 - __builtin_clzll(n)) : \ (sizeof(n) <= 4) ? \ __ilog2_u32(n) : \ __ilog2_u64(n) \ diff --git a/include/linux/math.h b/include/linux/math.h new file mode 100644 index 000000000000..53674a327e39 --- /dev/null +++ b/include/linux/math.h @@ -0,0 +1,177 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_MATH_H +#define _LINUX_MATH_H + +#include <asm/div64.h> +#include <uapi/linux/kernel.h> + +/* + * This looks more complex than it should be. But we need to + * get the type for the ~ right in round_down (it needs to be + * as wide as the result!), and we want to evaluate the macro + * arguments just once each. + */ +#define __round_mask(x, y) ((__typeof__(x))((y)-1)) + +/** + * round_up - round up to next specified power of 2 + * @x: the value to round + * @y: multiple to round up to (must be a power of 2) + * + * Rounds @x up to next multiple of @y (which must be a power of 2). + * To perform arbitrary rounding up, use roundup() below. + */ +#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) + +/** + * round_down - round down to next specified power of 2 + * @x: the value to round + * @y: multiple to round down to (must be a power of 2) + * + * Rounds @x down to next multiple of @y (which must be a power of 2). + * To perform arbitrary rounding down, use rounddown() below. + */ +#define round_down(x, y) ((x) & ~__round_mask(x, y)) + +#define DIV_ROUND_UP __KERNEL_DIV_ROUND_UP + +#define DIV_ROUND_DOWN_ULL(ll, d) \ + ({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; }) + +#define DIV_ROUND_UP_ULL(ll, d) \ + DIV_ROUND_DOWN_ULL((unsigned long long)(ll) + (d) - 1, (d)) + +#if BITS_PER_LONG == 32 +# define DIV_ROUND_UP_SECTOR_T(ll,d) DIV_ROUND_UP_ULL(ll, d) +#else +# define DIV_ROUND_UP_SECTOR_T(ll,d) DIV_ROUND_UP(ll,d) +#endif + +/** + * roundup - round up to the next specified multiple + * @x: the value to up + * @y: multiple to round up to + * + * Rounds @x up to next multiple of @y. If @y will always be a power + * of 2, consider using the faster round_up(). + */ +#define roundup(x, y) ( \ +{ \ + typeof(y) __y = y; \ + (((x) + (__y - 1)) / __y) * __y; \ +} \ +) +/** + * rounddown - round down to next specified multiple + * @x: the value to round + * @y: multiple to round down to + * + * Rounds @x down to next multiple of @y. If @y will always be a power + * of 2, consider using the faster round_down(). + */ +#define rounddown(x, y) ( \ +{ \ + typeof(x) __x = (x); \ + __x - (__x % (y)); \ +} \ +) + +/* + * Divide positive or negative dividend by positive or negative divisor + * and round to closest integer. Result is undefined for negative + * divisors if the dividend variable type is unsigned and for negative + * dividends if the divisor variable type is unsigned. + */ +#define DIV_ROUND_CLOSEST(x, divisor)( \ +{ \ + typeof(x) __x = x; \ + typeof(divisor) __d = divisor; \ + (((typeof(x))-1) > 0 || \ + ((typeof(divisor))-1) > 0 || \ + (((__x) > 0) == ((__d) > 0))) ? \ + (((__x) + ((__d) / 2)) / (__d)) : \ + (((__x) - ((__d) / 2)) / (__d)); \ +} \ +) +/* + * Same as above but for u64 dividends. divisor must be a 32-bit + * number. + */ +#define DIV_ROUND_CLOSEST_ULL(x, divisor)( \ +{ \ + typeof(divisor) __d = divisor; \ + unsigned long long _tmp = (x) + (__d) / 2; \ + do_div(_tmp, __d); \ + _tmp; \ +} \ +) + +/* + * Multiplies an integer by a fraction, while avoiding unnecessary + * overflow or loss of precision. + */ +#define mult_frac(x, numer, denom)( \ +{ \ + typeof(x) quot = (x) / (denom); \ + typeof(x) rem = (x) % (denom); \ + (quot * (numer)) + ((rem * (numer)) / (denom)); \ +} \ +) + +#define sector_div(a, b) do_div(a, b) + +/** + * abs - return absolute value of an argument + * @x: the value. If it is unsigned type, it is converted to signed type first. + * char is treated as if it was signed (regardless of whether it really is) + * but the macro's return type is preserved as char. + * + * Return: an absolute value of x. + */ +#define abs(x) __abs_choose_expr(x, long long, \ + __abs_choose_expr(x, long, \ + __abs_choose_expr(x, int, \ + __abs_choose_expr(x, short, \ + __abs_choose_expr(x, char, \ + __builtin_choose_expr( \ + __builtin_types_compatible_p(typeof(x), char), \ + (char)({ signed char __x = (x); __x<0?-__x:__x; }), \ + ((void)0))))))) + +#define __abs_choose_expr(x, type, other) __builtin_choose_expr( \ + __builtin_types_compatible_p(typeof(x), signed type) || \ + __builtin_types_compatible_p(typeof(x), unsigned type), \ + ({ signed type __x = (x); __x < 0 ? -__x : __x; }), other) + +/** + * reciprocal_scale - "scale" a value into range [0, ep_ro) + * @val: value + * @ep_ro: right open interval endpoint + * + * Perform a "reciprocal multiplication" in order to "scale" a value into + * range [0, @ep_ro), where the upper interval endpoint is right-open. + * This is useful, e.g. for accessing a index of an array containing + * @ep_ro elements, for example. Think of it as sort of modulus, only that + * the result isn't that of modulo. ;) Note that if initial input is a + * small value, then result will return 0. + * + * Return: a result based on @val in interval [0, @ep_ro). + */ +static inline u32 reciprocal_scale(u32 val, u32 ep_ro) +{ + return (u32)(((u64) val * ep_ro) >> 32); +} + +u64 int_pow(u64 base, unsigned int exp); +unsigned long int_sqrt(unsigned long); + +#if BITS_PER_LONG < 64 +u32 int_sqrt64(u64 x); +#else +static inline u32 int_sqrt64(u64 x) +{ + return (u32)int_sqrt(x); +} +#endif + +#endif /* _LINUX_MATH_H */ diff --git a/include/linux/mm.h b/include/linux/mm.h index abc7b3154298..855161080f18 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1641,9 +1641,9 @@ void free_pgd_range(struct mmu_gather *tlb, unsigned long addr, unsigned long end, unsigned long floor, unsigned long ceiling); int copy_page_range(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma); -int follow_pte_pmd(struct mm_struct *mm, unsigned long address, - struct mmu_notifier_range *range, - pte_t **ptepp, pmd_t **pmdpp, spinlock_t **ptlp); +int follow_pte(struct mm_struct *mm, unsigned long address, + struct mmu_notifier_range *range, pte_t **ptepp, pmd_t **pmdpp, + spinlock_t **ptlp); int follow_pfn(struct vm_area_struct *vma, unsigned long address, unsigned long *pfn); int follow_phys(struct vm_area_struct *vma, unsigned long address, diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 270cab43ca3d..000cc0533c33 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -80,6 +80,7 @@ extern void proc_flush_pid(struct pid *); extern struct proc_dir_entry *proc_symlink(const char *, struct proc_dir_entry *, const char *); +struct proc_dir_entry *_proc_mkdir(const char *, umode_t, struct proc_dir_entry *, void *, bool); extern struct proc_dir_entry *proc_mkdir(const char *, struct proc_dir_entry *); extern struct proc_dir_entry *proc_mkdir_data(const char *, umode_t, struct proc_dir_entry *, void *); @@ -162,6 +163,11 @@ static inline struct proc_dir_entry *proc_symlink(const char *name, static inline struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent) {return NULL;} static inline struct proc_dir_entry *proc_create_mount_point(const char *name) { return NULL; } +static inline struct proc_dir_entry *_proc_mkdir(const char *name, umode_t mode, + struct proc_dir_entry *parent, void *data, bool force_lookup) +{ + return NULL; +} static inline struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode, struct proc_dir_entry *parent, void *data) { return NULL; } static inline struct proc_dir_entry *proc_mkdir_mode(const char *name, @@ -199,7 +205,7 @@ struct net; static inline struct proc_dir_entry *proc_net_mkdir( struct net *net, const char *name, struct proc_dir_entry *parent) { - return proc_mkdir_data(name, 0, parent, net); + return _proc_mkdir(name, 0, parent, net, true); } struct ns_common; diff --git a/include/linux/rcu_node_tree.h b/include/linux/rcu_node_tree.h index b8e094b125ee..78feb8ba7358 100644 --- a/include/linux/rcu_node_tree.h +++ b/include/linux/rcu_node_tree.h @@ -20,6 +20,8 @@ #ifndef __LINUX_RCU_NODE_TREE_H #define __LINUX_RCU_NODE_TREE_H +#include <linux/math.h> + /* * Define shape of hierarchy based on NR_CPUS, CONFIG_RCU_FANOUT, and * CONFIG_RCU_FANOUT_LEAF. diff --git a/include/linux/relay.h b/include/linux/relay.h index e13a333e7c37..72b876dd5cb8 100644 --- a/include/linux/relay.h +++ b/include/linux/relay.h @@ -62,7 +62,7 @@ struct rchan size_t subbuf_size; /* sub-buffer size */ size_t n_subbufs; /* number of sub-buffers per buffer */ size_t alloc_size; /* total buffer size allocated */ - struct rchan_callbacks *cb; /* client callbacks */ + const struct rchan_callbacks *cb; /* client callbacks */ struct kref kref; /* channel refcount */ void *private_data; /* for user-defined data */ size_t last_toobig; /* tried to log event > subbuf size */ @@ -89,6 +89,8 @@ struct rchan_callbacks * The client should return 1 to continue logging, 0 to stop * logging. * + * This callback is optional. + * * NOTE: subbuf_start will also be invoked when the buffer is * created, so that the first sub-buffer can be initialized * if necessary. In this case, prev_subbuf will be NULL. @@ -102,25 +104,6 @@ struct rchan_callbacks size_t prev_padding); /* - * buf_mapped - relay buffer mmap notification - * @buf: the channel buffer - * @filp: relay file pointer - * - * Called when a relay file is successfully mmapped - */ - void (*buf_mapped)(struct rchan_buf *buf, - struct file *filp); - - /* - * buf_unmapped - relay buffer unmap notification - * @buf: the channel buffer - * @filp: relay file pointer - * - * Called when a relay file is successfully unmapped - */ - void (*buf_unmapped)(struct rchan_buf *buf, - struct file *filp); - /* * create_buf_file - create file to represent a relay channel buffer * @filename: the name of the file to create * @parent: the parent of the file to create @@ -141,6 +124,8 @@ struct rchan_callbacks * cause relay_open() to create a single global buffer rather * than the default set of per-cpu buffers. * + * This callback is mandatory. + * * See Documentation/filesystems/relay.rst for more info. */ struct dentry *(*create_buf_file)(const char *filename, @@ -158,6 +143,8 @@ struct rchan_callbacks * channel buffer. * * The callback should return 0 if successful, negative if not. + * + * This callback is mandatory. */ int (*remove_buf_file)(struct dentry *dentry); }; @@ -170,7 +157,7 @@ struct rchan *relay_open(const char *base_filename, struct dentry *parent, size_t subbuf_size, size_t n_subbufs, - struct rchan_callbacks *cb, + const struct rchan_callbacks *cb, void *private_data); extern int relay_late_setup_files(struct rchan *chan, const char *base_filename, diff --git a/include/linux/rio_drv.h b/include/linux/rio_drv.h index d637742e5039..e49c32b0f394 100644 --- a/include/linux/rio_drv.h +++ b/include/linux/rio_drv.h @@ -444,9 +444,6 @@ static inline void rio_set_drvdata(struct rio_dev *rdev, void *data) /* Misc driver helpers */ extern u16 rio_local_get_device_id(struct rio_mport *port); extern void rio_local_set_device_id(struct rio_mport *port, u16 did); -extern struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *from); -extern struct rio_dev *rio_get_asm(u16 vid, u16 did, u16 asm_vid, u16 asm_did, - struct rio_dev *from); extern int rio_init_mports(void); #endif /* LINUX_RIO_DRV_H */ diff --git a/include/linux/string.h b/include/linux/string.h index b1f3894a0a3e..1cd63a8a23ab 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -6,6 +6,7 @@ #include <linux/compiler.h> /* for inline */ #include <linux/types.h> /* for size_t */ #include <linux/stddef.h> /* for NULL */ +#include <linux/errno.h> /* for E2BIG */ #include <stdarg.h> #include <uapi/linux/string.h> @@ -292,7 +293,7 @@ extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) __FORTIFY_INLINE char *strncpy(char *p, const char *q, __kernel_size_t size) { - size_t p_size = __builtin_object_size(p, 0); + size_t p_size = __builtin_object_size(p, 1); if (__builtin_constant_p(size) && p_size < size) __write_overflow(); if (p_size < size) @@ -302,7 +303,7 @@ __FORTIFY_INLINE char *strncpy(char *p, const char *q, __kernel_size_t size) __FORTIFY_INLINE char *strcat(char *p, const char *q) { - size_t p_size = __builtin_object_size(p, 0); + size_t p_size = __builtin_object_size(p, 1); if (p_size == (size_t)-1) return __underlying_strcat(p, q); if (strlcat(p, q, p_size) >= p_size) @@ -313,7 +314,7 @@ __FORTIFY_INLINE char *strcat(char *p, const char *q) __FORTIFY_INLINE __kernel_size_t strlen(const char *p) { __kernel_size_t ret; - size_t p_size = __builtin_object_size(p, 0); + size_t p_size = __builtin_object_size(p, 1); /* Work around gcc excess stack consumption issue */ if (p_size == (size_t)-1 || @@ -328,7 +329,7 @@ __FORTIFY_INLINE __kernel_size_t strlen(const char *p) extern __kernel_size_t __real_strnlen(const char *, __kernel_size_t) __RENAME(strnlen); __FORTIFY_INLINE __kernel_size_t strnlen(const char *p, __kernel_size_t maxlen) { - size_t p_size = __builtin_object_size(p, 0); + size_t p_size = __builtin_object_size(p, 1); __kernel_size_t ret = __real_strnlen(p, maxlen < p_size ? maxlen : p_size); if (p_size <= ret && maxlen != ret) fortify_panic(__func__); @@ -340,8 +341,8 @@ extern size_t __real_strlcpy(char *, const char *, size_t) __RENAME(strlcpy); __FORTIFY_INLINE size_t strlcpy(char *p, const char *q, size_t size) { size_t ret; - size_t p_size = __builtin_object_size(p, 0); - size_t q_size = __builtin_object_size(q, 0); + size_t p_size = __builtin_object_size(p, 1); + size_t q_size = __builtin_object_size(q, 1); if (p_size == (size_t)-1 && q_size == (size_t)-1) return __real_strlcpy(p, q, size); ret = strlen(q); @@ -357,12 +358,59 @@ __FORTIFY_INLINE size_t strlcpy(char *p, const char *q, size_t size) return ret; } +/* defined after fortified strnlen to reuse it */ +extern ssize_t __real_strscpy(char *, const char *, size_t) __RENAME(strscpy); +__FORTIFY_INLINE ssize_t strscpy(char *p, const char *q, size_t size) +{ + size_t len; + /* Use string size rather than possible enclosing struct size. */ + size_t p_size = __builtin_object_size(p, 1); + size_t q_size = __builtin_object_size(q, 1); + + /* If we cannot get size of p and q default to call strscpy. */ + if (p_size == (size_t) -1 && q_size == (size_t) -1) + return __real_strscpy(p, q, size); + + /* + * If size can be known at compile time and is greater than + * p_size, generate a compile time write overflow error. + */ + if (__builtin_constant_p(size) && size > p_size) + __write_overflow(); + + /* + * This call protects from read overflow, because len will default to q + * length if it smaller than size. + */ + len = strnlen(q, size); + /* + * If len equals size, we will copy only size bytes which leads to + * -E2BIG being returned. + * Otherwise we will copy len + 1 because of the final '\O'. + */ + len = len == size ? size : len + 1; + + /* + * Generate a runtime write overflow error if len is greater than + * p_size. + */ + if (len > p_size) + fortify_panic(__func__); + + /* + * We can now safely call vanilla strscpy because we are protected from: + * 1. Read overflow thanks to call to strnlen(). + * 2. Write overflow thanks to above ifs. + */ + return __real_strscpy(p, q, len); +} + /* defined after fortified strlen and strnlen to reuse them */ __FORTIFY_INLINE char *strncat(char *p, const char *q, __kernel_size_t count) { size_t p_len, copy_len; - size_t p_size = __builtin_object_size(p, 0); - size_t q_size = __builtin_object_size(q, 0); + size_t p_size = __builtin_object_size(p, 1); + size_t q_size = __builtin_object_size(q, 1); if (p_size == (size_t)-1 && q_size == (size_t)-1) return __underlying_strncat(p, q, count); p_len = strlen(p); @@ -475,11 +523,16 @@ __FORTIFY_INLINE void *kmemdup(const void *p, size_t size, gfp_t gfp) /* defined after fortified strlen and memcpy to reuse them */ __FORTIFY_INLINE char *strcpy(char *p, const char *q) { - size_t p_size = __builtin_object_size(p, 0); - size_t q_size = __builtin_object_size(q, 0); + size_t p_size = __builtin_object_size(p, 1); + size_t q_size = __builtin_object_size(q, 1); + size_t size; if (p_size == (size_t)-1 && q_size == (size_t)-1) return __underlying_strcpy(p, q); - memcpy(p, q, strlen(q) + 1); + size = strlen(q) + 1; + /* test here to use the more stringent object size */ + if (p_size < size) + fortify_panic(__func__); + memcpy(p, q, size); return p; } diff --git a/include/linux/units.h b/include/linux/units.h index aaf716364ec3..5c115c809507 100644 --- a/include/linux/units.h +++ b/include/linux/units.h @@ -2,7 +2,7 @@ #ifndef _LINUX_UNITS_H #define _LINUX_UNITS_H -#include <linux/kernel.h> +#include <linux/math.h> #define ABSOLUTE_ZERO_MILLICELSIUS -273150 diff --git a/kernel/Makefile b/kernel/Makefile index dddf51266719..aa7368c7eabf 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -34,8 +34,11 @@ KCOV_INSTRUMENT_extable.o := n KCOV_INSTRUMENT_stacktrace.o := n # Don't self-instrument. KCOV_INSTRUMENT_kcov.o := n +# If sanitizers detect any issues in kcov, it may lead to recursion +# via printk, etc. KASAN_SANITIZE_kcov.o := n KCSAN_SANITIZE_kcov.o := n +UBSAN_SANITIZE_kcov.o := n CFLAGS_kcov.o := $(call cc-option, -fno-conserve-stack) -fno-stack-protector obj-y += sched/ diff --git a/kernel/acct.c b/kernel/acct.c index f175df8f6aa4..a64102be2bb0 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -381,9 +381,7 @@ static comp2_t encode_comp2_t(u64 value) return (value & (MAXFRACT2>>1)) | (exp << (MANTSIZE2-1)); } } -#endif - -#if ACCT_VERSION == 3 +#elif ACCT_VERSION == 3 /* * encode an u64 into a 32 bit IEEE float */ @@ -500,8 +498,7 @@ static void do_acct_process(struct bsd_acct_struct *acct) /* backward-compatible 16 bit fields */ ac.ac_uid16 = ac.ac_uid; ac.ac_gid16 = ac.ac_gid; -#endif -#if ACCT_VERSION == 3 +#elif ACCT_VERSION == 3 { struct pid_namespace *ns = acct->ns; diff --git a/kernel/crash_core.c b/kernel/crash_core.c index 4fcfe0b70c4e..825284baaf46 100644 --- a/kernel/crash_core.c +++ b/kernel/crash_core.c @@ -447,6 +447,7 @@ static int __init crash_save_vmcoreinfo_init(void) VMCOREINFO_PAGESIZE(PAGE_SIZE); VMCOREINFO_SYMBOL(init_uts_ns); + VMCOREINFO_OFFSET(uts_namespace, name); VMCOREINFO_SYMBOL(node_online_map); #ifdef CONFIG_MMU VMCOREINFO_SYMBOL_ARRAY(swapper_pg_dir); diff --git a/kernel/fail_function.c b/kernel/fail_function.c index b0b1ad93fa95..60dc825ecc2b 100644 --- a/kernel/fail_function.c +++ b/kernel/fail_function.c @@ -37,9 +37,7 @@ static unsigned long adjust_error_retval(unsigned long addr, unsigned long retv) { switch (get_injectable_error_type(addr)) { case EI_ETYPE_NULL: - if (retv != 0) - return 0; - break; + return 0; case EI_ETYPE_ERRNO: if (retv < (unsigned long)-MAX_ERRNO) return (unsigned long)-EINVAL; @@ -48,6 +46,8 @@ static unsigned long adjust_error_retval(unsigned long addr, unsigned long retv) if (retv != 0 && retv < (unsigned long)-MAX_ERRNO) return (unsigned long)-EINVAL; break; + case EI_ETYPE_TRUE: + return 1; } return retv; diff --git a/kernel/gcov/gcc_4_7.c b/kernel/gcov/gcc_4_7.c index 53c67c87f141..c53408a00d0b 100644 --- a/kernel/gcov/gcc_4_7.c +++ b/kernel/gcov/gcc_4_7.c @@ -25,10 +25,8 @@ #define GCOV_COUNTERS 9 #elif (__GNUC__ > 5) || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1) #define GCOV_COUNTERS 10 -#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 9 -#define GCOV_COUNTERS 9 #else -#define GCOV_COUNTERS 8 +#define GCOV_COUNTERS 9 #endif #define GCOV_TAG_FUNCTION_LENGTH 3 @@ -229,10 +227,10 @@ int gcov_info_is_compatible(struct gcov_info *info1, struct gcov_info *info2) /** * gcov_info_add - add up profiling data - * @dest: profiling data set to which data is added - * @source: profiling data set which is added + * @dst: profiling data set to which data is added + * @src: profiling data set which is added * - * Adds profiling counts of @source to @dest. + * Adds profiling counts of @src to @dst. */ void gcov_info_add(struct gcov_info *dst, struct gcov_info *src) { diff --git a/kernel/reboot.c b/kernel/reboot.c index 2a18b76ffc06..eb1b15850761 100644 --- a/kernel/reboot.c +++ b/kernel/reboot.c @@ -553,20 +553,24 @@ static int __init reboot_setup(char *str) break; case 's': - if (isdigit(*(str+1))) - reboot_cpu = simple_strtoul(str+1, NULL, 0); - else if (str[1] == 'm' && str[2] == 'p' && - isdigit(*(str+3))) - reboot_cpu = simple_strtoul(str+3, NULL, 0); - else + /* + * reboot_cpu is s[mp]#### with #### being the processor + * to be used for rebooting. Skip 's' or 'smp' prefix. + */ + str += str[1] == 'm' && str[2] == 'p' ? 3 : 1; + + if (isdigit(str[0])) { + int cpu = simple_strtoul(str, NULL, 0); + + if (cpu >= num_possible_cpus()) { + pr_err("Ignoring the CPU number in reboot= option. " + "CPU %d exceeds possible cpu number %d\n", + cpu, num_possible_cpus()); + break; + } + reboot_cpu = cpu; + } else *mode = REBOOT_SOFT; - if (reboot_cpu >= num_possible_cpus()) { - pr_err("Ignoring the CPU number in reboot= option. " - "CPU %d exceeds possible cpu number %d\n", - reboot_cpu, num_possible_cpus()); - reboot_cpu = 0; - break; - } break; case 'g': @@ -596,3 +600,217 @@ static int __init reboot_setup(char *str) return 1; } __setup("reboot=", reboot_setup); + +#ifdef CONFIG_SYSFS + +#define REBOOT_COLD_STR "cold" +#define REBOOT_WARM_STR "warm" +#define REBOOT_HARD_STR "hard" +#define REBOOT_SOFT_STR "soft" +#define REBOOT_GPIO_STR "gpio" +#define REBOOT_UNDEFINED_STR "undefined" + +#define BOOT_TRIPLE_STR "triple" +#define BOOT_KBD_STR "kbd" +#define BOOT_BIOS_STR "bios" +#define BOOT_ACPI_STR "acpi" +#define BOOT_EFI_STR "efi" +#define BOOT_PCI_STR "pci" + +static ssize_t mode_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + const char *val; + + switch (reboot_mode) { + case REBOOT_COLD: + val = REBOOT_COLD_STR; + break; + case REBOOT_WARM: + val = REBOOT_WARM_STR; + break; + case REBOOT_HARD: + val = REBOOT_HARD_STR; + break; + case REBOOT_SOFT: + val = REBOOT_SOFT_STR; + break; + case REBOOT_GPIO: + val = REBOOT_GPIO_STR; + break; + default: + val = REBOOT_UNDEFINED_STR; + } + + return sprintf(buf, "%s\n", val); +} +static ssize_t mode_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + if (!capable(CAP_SYS_BOOT)) + return -EPERM; + + if (!strncmp(buf, REBOOT_COLD_STR, strlen(REBOOT_COLD_STR))) + reboot_mode = REBOOT_COLD; + else if (!strncmp(buf, REBOOT_WARM_STR, strlen(REBOOT_WARM_STR))) + reboot_mode = REBOOT_WARM; + else if (!strncmp(buf, REBOOT_HARD_STR, strlen(REBOOT_HARD_STR))) + reboot_mode = REBOOT_HARD; + else if (!strncmp(buf, REBOOT_SOFT_STR, strlen(REBOOT_SOFT_STR))) + reboot_mode = REBOOT_SOFT; + else if (!strncmp(buf, REBOOT_GPIO_STR, strlen(REBOOT_GPIO_STR))) + reboot_mode = REBOOT_GPIO; + else + return -EINVAL; + + reboot_default = 0; + + return count; +} +static struct kobj_attribute reboot_mode_attr = __ATTR_RW(mode); + +#ifdef CONFIG_X86 +static ssize_t force_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", reboot_force); +} +static ssize_t force_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + bool res; + + if (!capable(CAP_SYS_BOOT)) + return -EPERM; + + if (kstrtobool(buf, &res)) + return -EINVAL; + + reboot_default = 0; + reboot_force = res; + + return count; +} +static struct kobj_attribute reboot_force_attr = __ATTR_RW(force); + +static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + const char *val; + + switch (reboot_type) { + case BOOT_TRIPLE: + val = BOOT_TRIPLE_STR; + break; + case BOOT_KBD: + val = BOOT_KBD_STR; + break; + case BOOT_BIOS: + val = BOOT_BIOS_STR; + break; + case BOOT_ACPI: + val = BOOT_ACPI_STR; + break; + case BOOT_EFI: + val = BOOT_EFI_STR; + break; + case BOOT_CF9_FORCE: + val = BOOT_PCI_STR; + break; + default: + val = REBOOT_UNDEFINED_STR; + } + + return sprintf(buf, "%s\n", val); +} +static ssize_t type_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + if (!capable(CAP_SYS_BOOT)) + return -EPERM; + + if (!strncmp(buf, BOOT_TRIPLE_STR, strlen(BOOT_TRIPLE_STR))) + reboot_type = BOOT_TRIPLE; + else if (!strncmp(buf, BOOT_KBD_STR, strlen(BOOT_KBD_STR))) + reboot_type = BOOT_KBD; + else if (!strncmp(buf, BOOT_BIOS_STR, strlen(BOOT_BIOS_STR))) + reboot_type = BOOT_BIOS; + else if (!strncmp(buf, BOOT_ACPI_STR, strlen(BOOT_ACPI_STR))) + reboot_type = BOOT_ACPI; + else if (!strncmp(buf, BOOT_EFI_STR, strlen(BOOT_EFI_STR))) + reboot_type = BOOT_EFI; + else if (!strncmp(buf, BOOT_PCI_STR, strlen(BOOT_PCI_STR))) + reboot_type = BOOT_CF9_FORCE; + else + return -EINVAL; + + reboot_default = 0; + + return count; +} +static struct kobj_attribute reboot_type_attr = __ATTR_RW(type); +#endif + +#ifdef CONFIG_SMP +static ssize_t cpu_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", reboot_cpu); +} +static ssize_t cpu_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + unsigned int cpunum; + int rc; + + if (!capable(CAP_SYS_BOOT)) + return -EPERM; + + rc = kstrtouint(buf, 0, &cpunum); + + if (rc) + return rc; + + if (cpunum >= num_possible_cpus()) + return -ERANGE; + + reboot_default = 0; + reboot_cpu = cpunum; + + return count; +} +static struct kobj_attribute reboot_cpu_attr = __ATTR_RW(cpu); +#endif + +static struct attribute *reboot_attrs[] = { + &reboot_mode_attr.attr, +#ifdef CONFIG_X86 + &reboot_force_attr.attr, + &reboot_type_attr.attr, +#endif +#ifdef CONFIG_SMP + &reboot_cpu_attr.attr, +#endif + NULL, +}; + +static const struct attribute_group reboot_attr_group = { + .attrs = reboot_attrs, +}; + +static int __init reboot_ksysfs_init(void) +{ + struct kobject *reboot_kobj; + int ret; + + reboot_kobj = kobject_create_and_add("reboot", kernel_kobj); + if (!reboot_kobj) + return -ENOMEM; + + ret = sysfs_create_group(reboot_kobj, &reboot_attr_group); + if (ret) { + kobject_put(reboot_kobj); + return ret; + } + + return 0; +} +late_initcall(reboot_ksysfs_init); + +#endif diff --git a/kernel/relay.c b/kernel/relay.c index b08d936d5fa7..d1a67fbb819d 100644 --- a/kernel/relay.c +++ b/kernel/relay.c @@ -28,15 +28,6 @@ static DEFINE_MUTEX(relay_channels_mutex); static LIST_HEAD(relay_channels); /* - * close() vm_op implementation for relay file mapping. - */ -static void relay_file_mmap_close(struct vm_area_struct *vma) -{ - struct rchan_buf *buf = vma->vm_private_data; - buf->chan->cb->buf_unmapped(buf, vma->vm_file); -} - -/* * fault() vm_op implementation for relay file mapping. */ static vm_fault_t relay_buf_fault(struct vm_fault *vmf) @@ -62,7 +53,6 @@ static vm_fault_t relay_buf_fault(struct vm_fault *vmf) */ static const struct vm_operations_struct relay_file_mmap_ops = { .fault = relay_buf_fault, - .close = relay_file_mmap_close, }; /* @@ -96,7 +86,6 @@ static void relay_free_page_array(struct page **array) static int relay_mmap_buf(struct rchan_buf *buf, struct vm_area_struct *vma) { unsigned long length = vma->vm_end - vma->vm_start; - struct file *filp = vma->vm_file; if (!buf) return -EBADF; @@ -107,7 +96,6 @@ static int relay_mmap_buf(struct rchan_buf *buf, struct vm_area_struct *vma) vma->vm_ops = &relay_file_mmap_ops; vma->vm_flags |= VM_DONTEXPAND; vma->vm_private_data = buf; - buf->chan->cb->buf_mapped(buf, filp); return 0; } @@ -264,70 +252,16 @@ EXPORT_SYMBOL_GPL(relay_buf_full); * High-level relay kernel API and associated functions. */ -/* - * rchan_callback implementations defining default channel behavior. Used - * in place of corresponding NULL values in client callback struct. - */ - -/* - * subbuf_start() default callback. Does nothing. - */ -static int subbuf_start_default_callback (struct rchan_buf *buf, - void *subbuf, - void *prev_subbuf, - size_t prev_padding) -{ - if (relay_buf_full(buf)) - return 0; - - return 1; -} - -/* - * buf_mapped() default callback. Does nothing. - */ -static void buf_mapped_default_callback(struct rchan_buf *buf, - struct file *filp) -{ -} - -/* - * buf_unmapped() default callback. Does nothing. - */ -static void buf_unmapped_default_callback(struct rchan_buf *buf, - struct file *filp) -{ -} - -/* - * create_buf_file_create() default callback. Does nothing. - */ -static struct dentry *create_buf_file_default_callback(const char *filename, - struct dentry *parent, - umode_t mode, - struct rchan_buf *buf, - int *is_global) +static int relay_subbuf_start(struct rchan_buf *buf, void *subbuf, + void *prev_subbuf, size_t prev_padding) { - return NULL; -} + if (!buf->chan->cb->subbuf_start) + return !relay_buf_full(buf); -/* - * remove_buf_file() default callback. Does nothing. - */ -static int remove_buf_file_default_callback(struct dentry *dentry) -{ - return -EINVAL; + return buf->chan->cb->subbuf_start(buf, subbuf, + prev_subbuf, prev_padding); } -/* relay channel default callbacks */ -static struct rchan_callbacks default_channel_callbacks = { - .subbuf_start = subbuf_start_default_callback, - .buf_mapped = buf_mapped_default_callback, - .buf_unmapped = buf_unmapped_default_callback, - .create_buf_file = create_buf_file_default_callback, - .remove_buf_file = remove_buf_file_default_callback, -}; - /** * wakeup_readers - wake up readers waiting on a channel * @work: contains the channel buffer @@ -371,7 +305,7 @@ static void __relay_reset(struct rchan_buf *buf, unsigned int init) for (i = 0; i < buf->chan->n_subbufs; i++) buf->padding[i] = 0; - buf->chan->cb->subbuf_start(buf, buf->data, NULL, 0); + relay_subbuf_start(buf, buf->data, NULL, 0); } /** @@ -499,27 +433,6 @@ static void relay_close_buf(struct rchan_buf *buf) kref_put(&buf->kref, relay_remove_buf); } -static void setup_callbacks(struct rchan *chan, - struct rchan_callbacks *cb) -{ - if (!cb) { - chan->cb = &default_channel_callbacks; - return; - } - - if (!cb->subbuf_start) - cb->subbuf_start = subbuf_start_default_callback; - if (!cb->buf_mapped) - cb->buf_mapped = buf_mapped_default_callback; - if (!cb->buf_unmapped) - cb->buf_unmapped = buf_unmapped_default_callback; - if (!cb->create_buf_file) - cb->create_buf_file = create_buf_file_default_callback; - if (!cb->remove_buf_file) - cb->remove_buf_file = remove_buf_file_default_callback; - chan->cb = cb; -} - int relay_prepare_cpu(unsigned int cpu) { struct rchan *chan; @@ -565,7 +478,7 @@ struct rchan *relay_open(const char *base_filename, struct dentry *parent, size_t subbuf_size, size_t n_subbufs, - struct rchan_callbacks *cb, + const struct rchan_callbacks *cb, void *private_data) { unsigned int i; @@ -576,6 +489,8 @@ struct rchan *relay_open(const char *base_filename, return NULL; if (subbuf_size > UINT_MAX / n_subbufs) return NULL; + if (!cb || !cb->create_buf_file || !cb->remove_buf_file) + return NULL; chan = kzalloc(sizeof(struct rchan), GFP_KERNEL); if (!chan) @@ -597,7 +512,7 @@ struct rchan *relay_open(const char *base_filename, chan->has_base_filename = 1; strlcpy(chan->base_filename, base_filename, NAME_MAX); } - setup_callbacks(chan, cb); + chan->cb = cb; kref_init(&chan->kref); mutex_lock(&relay_channels_mutex); @@ -780,7 +695,7 @@ size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length) new_subbuf = buf->subbufs_produced % buf->chan->n_subbufs; new = buf->start + new_subbuf * buf->chan->subbuf_size; buf->offset = 0; - if (!buf->chan->cb->subbuf_start(buf, new, old, buf->prev_padding)) { + if (!relay_subbuf_start(buf, new, old, buf->prev_padding)) { buf->offset = buf->chan->subbuf_size + 1; return 0; } diff --git a/kernel/resource.c b/kernel/resource.c index 82df80417489..833394f9c608 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -320,9 +320,8 @@ int release_resource(struct resource *old) EXPORT_SYMBOL(release_resource); /** - * Finds the lowest iomem resource that covers part of [@start..@end]. The - * caller must specify @start, @end, @flags, and @desc (which may be - * IORES_DESC_NONE). + * find_next_iomem_res - Finds the lowest iomem resource that covers part of + * [@start..@end]. * * If a resource is found, returns 0 and @*res is overwritten with the part * of the resource that's within [@start..@end]; if none is found, returns @@ -337,6 +336,9 @@ EXPORT_SYMBOL(release_resource); * @desc: descriptor the resource must have * @first_lvl: walk only the first level children, if set * @res: return ptr, if resource found + * + * The caller must specify @start, @end, @flags, and @desc + * (which may be IORES_DESC_NONE). */ static int find_next_iomem_res(resource_size_t start, resource_size_t end, unsigned long flags, unsigned long desc, @@ -416,11 +418,9 @@ static int __walk_iomem_res_desc(resource_size_t start, resource_size_t end, } /** - * Walks through iomem resources and calls func() with matching resource - * ranges. This walks through whole tree and not just first level children. - * All the memory ranges which overlap start,end and also match flags and - * desc are valid candidates. - * + * walk_iomem_res_desc - Walks through iomem resources and calls func() + * with matching resource ranges. + * * * @desc: I/O resource descriptor. Use IORES_DESC_NONE to skip @desc check. * @flags: I/O resource flags * @start: start addr @@ -428,6 +428,10 @@ static int __walk_iomem_res_desc(resource_size_t start, resource_size_t end, * @arg: function argument for the callback @func * @func: callback function that is called for each qualifying resource area * + * This walks through whole tree and not just first level children. + * All the memory ranges which overlap start,end and also match flags and + * desc are valid candidates. + * * NOTE: For a new descriptor search, define a new IORES_DESC in * <linux/ioport.h> and set it in 'desc' of a target resource entry. */ @@ -1372,9 +1376,9 @@ static bool system_ram_resources_mergeable(struct resource *r1, !r1->child && !r2->child; } -/* +/** * merge_system_ram_resource - mark the System RAM resource mergeable and try to - * merge it with adjacent, mergeable resources + * merge it with adjacent, mergeable resources * @res: resource descriptor * * This interface is intended for memory hotplug, whereby lots of contiguous diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index f1022945e346..b5c4b9ade960 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -449,7 +449,7 @@ static struct dentry *blk_create_buf_file_callback(const char *filename, &relay_file_operations); } -static struct rchan_callbacks blk_relay_callbacks = { +static const struct rchan_callbacks blk_relay_callbacks = { .subbuf_start = blk_subbuf_start_callback, .create_buf_file = blk_create_buf_file_callback, .remove_buf_file = blk_remove_buf_file_callback, diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 7c70521d2a22..7d7097c5dc58 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2311,6 +2311,17 @@ config LINEAR_RANGES_TEST If unsure, say N. +config CMDLINE_KUNIT_TEST + tristate "KUnit test for cmdline API" + depends on KUNIT + help + This builds the cmdline API unit test. + Tests the logic of API provided by cmdline.c. + For more information on KUnit and unit tests in general please refer + to the KUnit documentation in Documentation/dev-tools/kunit/. + + If unsure, say N. + config BITS_TEST tristate "KUnit test for bits.h" depends on KUNIT diff --git a/lib/Kconfig.ubsan b/lib/Kconfig.ubsan index 58f8d03d037b..8b635fd75fe4 100644 --- a/lib/Kconfig.ubsan +++ b/lib/Kconfig.ubsan @@ -14,6 +14,7 @@ if UBSAN config UBSAN_TRAP bool "On Sanitizer warnings, abort the running kernel code" + depends on !COMPILE_TEST depends on $(cc-option, -fsanitize-undefined-trap-on-error) help Building kernels with Sanitizer features enabled tends to grow @@ -36,10 +37,17 @@ config UBSAN_KCOV_BROKEN See https://bugs.llvm.org/show_bug.cgi?id=45831 for the status in newer releases. +config CC_HAS_UBSAN_BOUNDS + def_bool $(cc-option,-fsanitize=bounds) + +config CC_HAS_UBSAN_ARRAY_BOUNDS + def_bool $(cc-option,-fsanitize=array-bounds) + config UBSAN_BOUNDS bool "Perform array index bounds checking" default UBSAN depends on !UBSAN_KCOV_BROKEN + depends on CC_HAS_UBSAN_ARRAY_BOUNDS || CC_HAS_UBSAN_BOUNDS help This option enables detection of directly indexed out of bounds array accesses, where the array size is known at compile time. @@ -47,36 +55,121 @@ config UBSAN_BOUNDS to the {str,mem}*cpy() family of functions (that is addressed by CONFIG_FORTIFY_SOURCE). +config UBSAN_ONLY_BOUNDS + def_bool CC_HAS_UBSAN_BOUNDS && !CC_HAS_UBSAN_ARRAY_BOUNDS + depends on UBSAN_BOUNDS + help + This is a weird case: Clang's -fsanitize=bounds includes + -fsanitize=local-bounds, but it's trapping-only, so for + Clang, we must use -fsanitize=array-bounds when we want + traditional array bounds checking enabled. For GCC, we + want -fsanitize=bounds. + +config UBSAN_ARRAY_BOUNDS + def_bool CC_HAS_UBSAN_ARRAY_BOUNDS + depends on UBSAN_BOUNDS + config UBSAN_LOCAL_BOUNDS bool "Perform array local bounds checking" depends on UBSAN_TRAP - depends on CC_IS_CLANG depends on !UBSAN_KCOV_BROKEN + depends on $(cc-option,-fsanitize=local-bounds) help This option enables -fsanitize=local-bounds which traps when an - exception/error is detected. Therefore, it should be enabled only - if trapping is expected. + exception/error is detected. Therefore, it may only be enabled + with CONFIG_UBSAN_TRAP. + Enabling this option detects errors due to accesses through a pointer that is derived from an object of a statically-known size, where an added offset (which may not be known statically) is out-of-bounds. -config UBSAN_MISC - bool "Enable all other Undefined Behavior sanity checks" +config UBSAN_SHIFT + bool "Perform checking for bit-shift overflows" + default UBSAN + depends on $(cc-option,-fsanitize=shift) + help + This option enables -fsanitize=shift which checks for bit-shift + operations that overflow to the left or go switch to negative + for signed types. + +config UBSAN_DIV_ZERO + bool "Perform checking for integer divide-by-zero" + depends on $(cc-option,-fsanitize=integer-divide-by-zero) + help + This option enables -fsanitize=integer-divide-by-zero which checks + for integer division by zero. This is effectively redundant with the + kernel's existing exception handling, though it can provide greater + debugging information under CONFIG_UBSAN_REPORT_FULL. + +config UBSAN_UNREACHABLE + bool "Perform checking for unreachable code" + # objtool already handles unreachable checking and gets angry about + # seeing UBSan instrumentation located in unreachable places. + depends on !STACK_VALIDATION + depends on $(cc-option,-fsanitize=unreachable) + help + This option enables -fsanitize=unreachable which checks for control + flow reaching an expected-to-be-unreachable position. + +config UBSAN_SIGNED_OVERFLOW + bool "Perform checking for signed arithmetic overflow" + default UBSAN + depends on $(cc-option,-fsanitize=signed-integer-overflow) + help + This option enables -fsanitize=signed-integer-overflow which checks + for overflow of any arithmetic operations with signed integers. + +config UBSAN_UNSIGNED_OVERFLOW + bool "Perform checking for unsigned arithmetic overflow" + depends on $(cc-option,-fsanitize=unsigned-integer-overflow) + help + This option enables -fsanitize=unsigned-integer-overflow which checks + for overflow of any arithmetic operations with unsigned integers. This + currently causes x86 to fail to boot. + +config UBSAN_OBJECT_SIZE + bool "Perform checking for accesses beyond the end of objects" + default UBSAN + # gcc hugely expands stack usage with -fsanitize=object-size + # https://lore.kernel.org/lkml/CAHk-=wjPasyJrDuwDnpHJS2TuQfExwe=px-SzLeN8GFMAQJPmQ@mail.gmail.com/ + depends on !CC_IS_GCC + depends on $(cc-option,-fsanitize=object-size) + help + This option enables -fsanitize=object-size which checks for accesses + beyond the end of objects where the optimizer can determine both the + object being operated on and its size, usually seen with bad downcasts, + or access to struct members from NULL pointers. + +config UBSAN_BOOL + bool "Perform checking for non-boolean values used as boolean" + default UBSAN + depends on $(cc-option,-fsanitize=bool) + help + This option enables -fsanitize=bool which checks for boolean values being + loaded that are neither 0 nor 1. + +config UBSAN_ENUM + bool "Perform checking for out of bounds enum values" default UBSAN + depends on $(cc-option,-fsanitize=enum) help - This option enables all sanity checks that don't have their - own Kconfig options. Disable this if you only want to have - individually selected checks. + This option enables -fsanitize=enum which checks for values being loaded + into an enum that are outside the range of given values for the given enum. + +config UBSAN_ALIGNMENT + bool "Perform checking for misaligned pointer usage" + default !HAVE_EFFICIENT_UNALIGNED_ACCESS + depends on !UBSAN_TRAP && !COMPILE_TEST + depends on $(cc-option,-fsanitize=alignment) + help + This option enables the check of unaligned memory accesses. + Enabling this option on architectures that support unaligned + accesses may produce a lot of false positives. config UBSAN_SANITIZE_ALL bool "Enable instrumentation for the entire kernel" depends on ARCH_HAS_UBSAN_SANITIZE_ALL - - # We build with -Wno-maybe-uninitilzed, but we still want to - # use -Wmaybe-uninitilized in allmodconfig builds. - # So dependsy bellow used to disable this option in allmodconfig - depends on !COMPILE_TEST default y help This option activates instrumentation for the entire kernel. @@ -85,15 +178,6 @@ config UBSAN_SANITIZE_ALL Enabling this option will get kernel image size increased significantly. -config UBSAN_ALIGNMENT - bool "Enable checks for pointers alignment" - default !HAVE_EFFICIENT_UNALIGNED_ACCESS - depends on !UBSAN_TRAP - help - This option enables the check of unaligned memory accesses. - Enabling this option on architectures that support unaligned - accesses may produce a lot of false positives. - config TEST_UBSAN tristate "Module for testing for undefined behavior detection" depends on m diff --git a/lib/Makefile b/lib/Makefile index d415fc7067c5..8598e8796edf 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -353,3 +353,4 @@ obj-$(CONFIG_BITFIELD_KUNIT) += bitfield_kunit.o obj-$(CONFIG_LIST_KUNIT_TEST) += list-test.o obj-$(CONFIG_LINEAR_RANGES_TEST) += test_linear_ranges.o obj-$(CONFIG_BITS_TEST) += test_bits.o +obj-$(CONFIG_CMDLINE_KUNIT_TEST) += cmdline_kunit.o diff --git a/lib/cmdline.c b/lib/cmdline.c index fbb9981a04a4..9e186234edc0 100644 --- a/lib/cmdline.c +++ b/lib/cmdline.c @@ -35,25 +35,37 @@ static int get_range(char **str, int *pint, int n) /** * get_option - Parse integer from an option string * @str: option string - * @pint: (output) integer value parsed from @str + * @pint: (optional output) integer value parsed from @str * * Read an int from an option string; if available accept a subsequent * comma as well. * + * When @pint is NULL the function can be used as a validator of + * the current option in the string. + * * Return values: * 0 - no int in string * 1 - int found, no subsequent comma * 2 - int found including a subsequent comma * 3 - hyphen found to denote a range + * + * Leading hyphen without integer is no integer case, but we consume it + * for the sake of simplification. */ int get_option(char **str, int *pint) { char *cur = *str; + int value; if (!cur || !(*cur)) return 0; - *pint = simple_strtol(cur, str, 0); + if (*cur == '-') + value = -simple_strtoull(++cur, str, 0); + else + value = simple_strtoull(cur, str, 0); + if (pint) + *pint = value; if (cur == *str) return 0; if (**str == ',') { diff --git a/lib/cmdline_kunit.c b/lib/cmdline_kunit.c new file mode 100644 index 000000000000..550e7a47fd24 --- /dev/null +++ b/lib/cmdline_kunit.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test cases for API provided by cmdline.c + */ + +#include <kunit/test.h> +#include <linux/kernel.h> +#include <linux/random.h> +#include <linux/string.h> + +static const char *cmdline_test_strings[] = { + "\"\"", "" , "=" , "\"-", "," , "-," , ",-" , "-" , + "+," , "--", ",,", "''" , "\"\",", "\",\"", "-\"\"", "\"", +}; + +static const int cmdline_test_values[] = { + 1, 1, 1, 1, 2, 3, 2, 3, + 1, 3, 2, 1, 1, 1, 3, 1, +}; + +static void cmdline_do_one_test(struct kunit *test, const char *in, int rc, int offset) +{ + const char *fmt = "Pattern: %s"; + const char *out = in; + int dummy; + int ret; + + ret = get_option((char **)&out, &dummy); + + KUNIT_EXPECT_EQ_MSG(test, ret, rc, fmt, in); + KUNIT_EXPECT_PTR_EQ_MSG(test, out, in + offset, fmt, in); +} + +static void cmdline_test_noint(struct kunit *test) +{ + unsigned int i = 0; + + do { + const char *str = cmdline_test_strings[i]; + int rc = 0; + int offset; + + /* Only first and leading '-' will advance the pointer */ + offset = !!(*str == '-'); + cmdline_do_one_test(test, str, rc, offset); + } while (++i < ARRAY_SIZE(cmdline_test_strings)); +} + +static void cmdline_test_lead_int(struct kunit *test) +{ + unsigned int i = 0; + char in[32]; + + do { + const char *str = cmdline_test_strings[i]; + int rc = cmdline_test_values[i]; + int offset; + + sprintf(in, "%u%s", get_random_int() % 256, str); + /* Only first '-' after the number will advance the pointer */ + offset = strlen(in) - strlen(str) + !!(rc == 2); + cmdline_do_one_test(test, in, rc, offset); + } while (++i < ARRAY_SIZE(cmdline_test_strings)); +} + +static void cmdline_test_tail_int(struct kunit *test) +{ + unsigned int i = 0; + char in[32]; + + do { + const char *str = cmdline_test_strings[i]; + /* When "" or "-" the result will be valid integer */ + int rc = strcmp(str, "") ? (strcmp(str, "-") ? 0 : 1) : 1; + int offset; + + sprintf(in, "%s%u", str, get_random_int() % 256); + /* + * Only first and leading '-' not followed by integer + * will advance the pointer. + */ + offset = rc ? strlen(in) : !!(*str == '-'); + cmdline_do_one_test(test, in, rc, offset); + } while (++i < ARRAY_SIZE(cmdline_test_strings)); +} + +static struct kunit_case cmdline_test_cases[] = { + KUNIT_CASE(cmdline_test_noint), + KUNIT_CASE(cmdline_test_lead_int), + KUNIT_CASE(cmdline_test_tail_int), + {} +}; + +static struct kunit_suite cmdline_test_suite = { + .name = "cmdline", + .test_cases = cmdline_test_cases, +}; +kunit_test_suite(cmdline_test_suite); + +MODULE_LICENSE("GPL"); diff --git a/lib/errname.c b/lib/errname.c index 0c4d3e66170e..05cbf731545f 100644 --- a/lib/errname.c +++ b/lib/errname.c @@ -3,6 +3,7 @@ #include <linux/errno.h> #include <linux/errname.h> #include <linux/kernel.h> +#include <linux/math.h> /* * Ensure these tables do not accidentally become gigantic if some diff --git a/lib/error-inject.c b/lib/error-inject.c index aa63751c916f..c73651b15b76 100644 --- a/lib/error-inject.c +++ b/lib/error-inject.c @@ -180,6 +180,8 @@ static const char *error_type_string(int etype) return "ERRNO"; case EI_ETYPE_ERRNO_NULL: return "ERRNO_NULL"; + case EI_ETYPE_TRUE: + return "TRUE"; default: return "(unknown)"; } diff --git a/lib/errseq.c b/lib/errseq.c index 81f9e33aa7e7..93e9b94358dc 100644 --- a/lib/errseq.c +++ b/lib/errseq.c @@ -3,6 +3,7 @@ #include <linux/bug.h> #include <linux/atomic.h> #include <linux/errseq.h> +#include <linux/log2.h> /* * An errseq_t is a way of recording errors in one place, and allowing any diff --git a/lib/find_bit.c b/lib/find_bit.c index 4a8751010d59..f67f86fd2f62 100644 --- a/lib/find_bit.c +++ b/lib/find_bit.c @@ -15,8 +15,9 @@ #include <linux/bitops.h> #include <linux/bitmap.h> #include <linux/export.h> -#include <linux/kernel.h> +#include <linux/math.h> #include <linux/minmax.h> +#include <linux/swab.h> #if !defined(find_next_bit) || !defined(find_next_zero_bit) || \ !defined(find_next_bit_le) || !defined(find_next_zero_bit_le) || \ diff --git a/lib/lz4/lz4_decompress.c b/lib/lz4/lz4_decompress.c index 00cb0d0b73e1..8a7724a6ce2f 100644 --- a/lib/lz4/lz4_decompress.c +++ b/lib/lz4/lz4_decompress.c @@ -263,7 +263,11 @@ static FORCE_INLINE int LZ4_decompress_generic( } } - LZ4_memcpy(op, ip, length); + /* + * supports overlapping memory regions; only matters + * for in-place decompression scenarios + */ + LZ4_memmove(op, ip, length); ip += length; op += length; diff --git a/lib/lz4/lz4defs.h b/lib/lz4/lz4defs.h index c91dd96ef629..673bd206aa98 100644 --- a/lib/lz4/lz4defs.h +++ b/lib/lz4/lz4defs.h @@ -146,6 +146,7 @@ static FORCE_INLINE void LZ4_writeLE16(void *memPtr, U16 value) * environments. This is needed when decompressing the Linux Kernel, for example. */ #define LZ4_memcpy(dst, src, size) __builtin_memcpy(dst, src, size) +#define LZ4_memmove(dst, src, size) __builtin_memmove(dst, src, size) static FORCE_INLINE void LZ4_copy8(void *dst, const void *src) { diff --git a/lib/lzo/lzo1x_compress.c b/lib/lzo/lzo1x_compress.c index 8ad5ba2b86e2..76758e9296ba 100644 --- a/lib/lzo/lzo1x_compress.c +++ b/lib/lzo/lzo1x_compress.c @@ -301,7 +301,7 @@ finished_writing_instruction: return in_end - (ii - ti); } -int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len, +static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len, unsigned char *out, size_t *out_len, void *wrkmem, const unsigned char bitstream_version) { diff --git a/lib/math/div64.c b/lib/math/div64.c index 3952a07130d8..064d68a5391a 100644 --- a/lib/math/div64.c +++ b/lib/math/div64.c @@ -18,9 +18,11 @@ * or by defining a preprocessor macro in arch/include/asm/div64.h. */ +#include <linux/bitops.h> #include <linux/export.h> -#include <linux/kernel.h> +#include <linux/math.h> #include <linux/math64.h> +#include <linux/log2.h> /* Not needed on 64bit architectures */ #if BITS_PER_LONG == 32 diff --git a/lib/math/int_pow.c b/lib/math/int_pow.c index 622fc1ab3c74..0cf426e69bda 100644 --- a/lib/math/int_pow.c +++ b/lib/math/int_pow.c @@ -6,7 +6,7 @@ */ #include <linux/export.h> -#include <linux/kernel.h> +#include <linux/math.h> #include <linux/types.h> /** diff --git a/lib/math/int_sqrt.c b/lib/math/int_sqrt.c index 30e0f9770f88..a8170bb9142f 100644 --- a/lib/math/int_sqrt.c +++ b/lib/math/int_sqrt.c @@ -6,9 +6,10 @@ * square root from Guy L. Steele. */ -#include <linux/kernel.h> #include <linux/export.h> #include <linux/bitops.h> +#include <linux/limits.h> +#include <linux/math.h> /** * int_sqrt - computes the integer square root diff --git a/lib/math/reciprocal_div.c b/lib/math/reciprocal_div.c index 32436dd4171e..6cb4adbb81d2 100644 --- a/lib/math/reciprocal_div.c +++ b/lib/math/reciprocal_div.c @@ -1,10 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 +#include <linux/bitops.h> #include <linux/bug.h> -#include <linux/kernel.h> -#include <asm/div64.h> -#include <linux/reciprocal_div.h> #include <linux/export.h> +#include <linux/limits.h> +#include <linux/math.h> #include <linux/minmax.h> +#include <linux/types.h> + +#include <linux/reciprocal_div.h> /* * For a description of the algorithm please have a look at diff --git a/lib/stackdepot.c b/lib/stackdepot.c index 2caffc64e4c8..890dcc2e984e 100644 --- a/lib/stackdepot.c +++ b/lib/stackdepot.c @@ -62,7 +62,7 @@ struct stack_record { u32 hash; /* Hash in the hastable */ u32 size; /* Number of frames in the stack */ union handle_parts handle; - unsigned long entries[1]; /* Variable-sized array of entries. */ + unsigned long entries[]; /* Variable-sized array of entries. */ }; static void *stack_slabs[STACK_ALLOC_MAX_SLABS]; @@ -104,9 +104,8 @@ static bool init_stack_slab(void **prealloc) static struct stack_record *depot_alloc_stack(unsigned long *entries, int size, u32 hash, void **prealloc, gfp_t alloc_flags) { - int required_size = offsetof(struct stack_record, entries) + - sizeof(unsigned long) * size; struct stack_record *stack; + size_t required_size = struct_size(stack, entries, size); required_size = ALIGN(required_size, 1 << STACK_ALLOC_ALIGN); @@ -136,7 +135,7 @@ static struct stack_record *depot_alloc_stack(unsigned long *entries, int size, stack->handle.slabindex = depot_index; stack->handle.offset = depot_offset >> STACK_ALLOC_ALIGN; stack->handle.valid = 1; - memcpy(stack->entries, entries, size * sizeof(unsigned long)); + memcpy(stack->entries, entries, flex_array_size(stack, entries, size)); depot_offset += required_size; return stack; @@ -155,8 +154,8 @@ static struct stack_record *stack_table[STACK_HASH_SIZE] = { static inline u32 hash_stack(unsigned long *entries, unsigned int size) { return jhash2((u32 *)entries, - size * sizeof(unsigned long) / sizeof(u32), - STACK_HASH_SEED); + array_size(size, sizeof(*entries)) / sizeof(u32), + STACK_HASH_SEED); } /* Use our own, non-instrumented version of memcmp(). diff --git a/lib/string.c b/lib/string.c index 4288e0158d47..7548eb715ddb 100644 --- a/lib/string.c +++ b/lib/string.c @@ -85,7 +85,6 @@ EXPORT_SYMBOL(strcasecmp); * @dest: Where to copy the string to * @src: Where to copy the string from */ -#undef strcpy char *strcpy(char *dest, const char *src) { char *tmp = dest; @@ -302,7 +301,6 @@ EXPORT_SYMBOL(stpcpy); * @dest: The string to be appended to * @src: The string to append to it */ -#undef strcat char *strcat(char *dest, const char *src) { char *tmp = dest; @@ -378,7 +376,6 @@ EXPORT_SYMBOL(strlcat); * @cs: One string * @ct: Another string */ -#undef strcmp int strcmp(const char *cs, const char *ct) { unsigned char c1, c2; @@ -958,7 +955,6 @@ EXPORT_SYMBOL(memcmp); * while this particular implementation is a simple (tail) call to memcmp, do * not rely on anything but whether the return value is zero or non-zero. */ -#undef bcmp int bcmp(const void *a, const void *b, size_t len) { return memcmp(a, b, len); diff --git a/lib/test_firmware.c b/lib/test_firmware.c index 2baa275a6ddf..b6fe89add9fe 100644 --- a/lib/test_firmware.c +++ b/lib/test_firmware.c @@ -364,18 +364,15 @@ static ssize_t test_dev_config_show_int(char *buf, int val) static int test_dev_config_update_u8(const char *buf, size_t size, u8 *cfg) { + u8 val; int ret; - long new; - ret = kstrtol(buf, 10, &new); + ret = kstrtou8(buf, 10, &val); if (ret) return ret; - if (new > U8_MAX) - return -EINVAL; - mutex_lock(&test_fw_mutex); - *(u8 *)cfg = new; + *(u8 *)cfg = val; mutex_unlock(&test_fw_mutex); /* Always return full write size even if we didn't consume all */ diff --git a/lib/test_free_pages.c b/lib/test_free_pages.c index 074e76bd76b2..25ae1ac2624a 100644 --- a/lib/test_free_pages.c +++ b/lib/test_free_pages.c @@ -5,6 +5,8 @@ * Author: Matthew Wilcox <willy@infradead.org> */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/gfp.h> #include <linux/mm.h> #include <linux/module.h> @@ -26,8 +28,11 @@ static void test_free_pages(gfp_t gfp) static int m_in(void) { + pr_info("Testing with GFP_KERNEL\n"); test_free_pages(GFP_KERNEL); + pr_info("Testing with GFP_KERNEL | __GFP_COMP\n"); test_free_pages(GFP_KERNEL | __GFP_COMP); + pr_info("Test completed\n"); return 0; } diff --git a/lib/test_kmod.c b/lib/test_kmod.c index eab52770070d..38c250fbace3 100644 --- a/lib/test_kmod.c +++ b/lib/test_kmod.c @@ -877,20 +877,17 @@ static int test_dev_config_update_uint_sync(struct kmod_test_device *test_dev, int (*test_sync)(struct kmod_test_device *test_dev)) { int ret; - unsigned long new; + unsigned int val; unsigned int old_val; - ret = kstrtoul(buf, 10, &new); + ret = kstrtouint(buf, 10, &val); if (ret) return ret; - if (new > UINT_MAX) - return -EINVAL; - mutex_lock(&test_dev->config_mutex); old_val = *config; - *(unsigned int *)config = new; + *(unsigned int *)config = val; ret = test_sync(test_dev); if (ret) { @@ -914,18 +911,18 @@ static int test_dev_config_update_uint_range(struct kmod_test_device *test_dev, unsigned int min, unsigned int max) { + unsigned int val; int ret; - unsigned long new; - ret = kstrtoul(buf, 10, &new); + ret = kstrtouint(buf, 10, &val); if (ret) return ret; - if (new < min || new > max) + if (val < min || val > max) return -EINVAL; mutex_lock(&test_dev->config_mutex); - *config = new; + *config = val; mutex_unlock(&test_dev->config_mutex); /* Always return full write size even if we didn't consume all */ @@ -936,18 +933,15 @@ static int test_dev_config_update_int(struct kmod_test_device *test_dev, const char *buf, size_t size, int *config) { + int val; int ret; - long new; - ret = kstrtol(buf, 10, &new); + ret = kstrtoint(buf, 10, &val); if (ret) return ret; - if (new < INT_MIN || new > INT_MAX) - return -EINVAL; - mutex_lock(&test_dev->config_mutex); - *config = new; + *config = val; mutex_unlock(&test_dev->config_mutex); /* Always return full write size even if we didn't consume all */ return size; diff --git a/lib/test_lockup.c b/lib/test_lockup.c index f1a020bcc763..864554e76973 100644 --- a/lib/test_lockup.c +++ b/lib/test_lockup.c @@ -480,6 +480,21 @@ static int __init test_lockup_init(void) return -EINVAL; #ifdef CONFIG_DEBUG_SPINLOCK +#ifdef CONFIG_PREEMPT_RT + if (test_magic(lock_spinlock_ptr, + offsetof(spinlock_t, lock.wait_lock.magic), + SPINLOCK_MAGIC) || + test_magic(lock_rwlock_ptr, + offsetof(rwlock_t, rtmutex.wait_lock.magic), + SPINLOCK_MAGIC) || + test_magic(lock_mutex_ptr, + offsetof(struct mutex, lock.wait_lock.magic), + SPINLOCK_MAGIC) || + test_magic(lock_rwsem_ptr, + offsetof(struct rw_semaphore, rtmutex.wait_lock.magic), + SPINLOCK_MAGIC)) + return -EINVAL; +#else if (test_magic(lock_spinlock_ptr, offsetof(spinlock_t, rlock.magic), SPINLOCK_MAGIC) || @@ -494,6 +509,7 @@ static int __init test_lockup_init(void) SPINLOCK_MAGIC)) return -EINVAL; #endif +#endif if ((wait_state != TASK_RUNNING || (call_cond_resched && !reacquire_locks) || diff --git a/lib/test_ubsan.c b/lib/test_ubsan.c index 9ea10adf7a66..5e5d9355ef49 100644 --- a/lib/test_ubsan.c +++ b/lib/test_ubsan.c @@ -5,32 +5,54 @@ typedef void(*test_ubsan_fp)(void); +#define UBSAN_TEST(config, ...) do { \ + pr_info("%s " __VA_ARGS__ "%s(%s=%s)\n", __func__, \ + sizeof(" " __VA_ARGS__) > 2 ? " " : "", \ + #config, IS_ENABLED(config) ? "y" : "n"); \ + } while (0) + static void test_ubsan_add_overflow(void) { volatile int val = INT_MAX; + volatile unsigned int uval = UINT_MAX; + UBSAN_TEST(CONFIG_UBSAN_SIGNED_OVERFLOW); val += 2; + + UBSAN_TEST(CONFIG_UBSAN_UNSIGNED_OVERFLOW); + uval += 2; } static void test_ubsan_sub_overflow(void) { volatile int val = INT_MIN; + volatile unsigned int uval = 0; volatile int val2 = 2; + UBSAN_TEST(CONFIG_UBSAN_SIGNED_OVERFLOW); val -= val2; + + UBSAN_TEST(CONFIG_UBSAN_UNSIGNED_OVERFLOW); + uval -= val2; } static void test_ubsan_mul_overflow(void) { volatile int val = INT_MAX / 2; + volatile unsigned int uval = UINT_MAX / 2; + UBSAN_TEST(CONFIG_UBSAN_SIGNED_OVERFLOW); val *= 3; + + UBSAN_TEST(CONFIG_UBSAN_UNSIGNED_OVERFLOW); + uval *= 3; } static void test_ubsan_negate_overflow(void) { volatile int val = INT_MIN; + UBSAN_TEST(CONFIG_UBSAN_SIGNED_OVERFLOW); val = -val; } @@ -39,37 +61,67 @@ static void test_ubsan_divrem_overflow(void) volatile int val = 16; volatile int val2 = 0; + UBSAN_TEST(CONFIG_UBSAN_DIV_ZERO); val /= val2; } static void test_ubsan_shift_out_of_bounds(void) { - volatile int val = -1; - int val2 = 10; + volatile int neg = -1, wrap = 4; + int val1 = 10; + int val2 = INT_MAX; + + UBSAN_TEST(CONFIG_UBSAN_SHIFT, "negative exponent"); + val1 <<= neg; - val2 <<= val; + UBSAN_TEST(CONFIG_UBSAN_SHIFT, "left overflow"); + val2 <<= wrap; } static void test_ubsan_out_of_bounds(void) { - volatile int i = 4, j = 5; + volatile int i = 4, j = 5, k = -1; + volatile char above[4] = { }; /* Protect surrounding memory. */ volatile int arr[4]; + volatile char below[4] = { }; /* Protect surrounding memory. */ + above[0] = below[0]; + + UBSAN_TEST(CONFIG_UBSAN_BOUNDS, "above"); arr[j] = i; + + UBSAN_TEST(CONFIG_UBSAN_BOUNDS, "below"); + arr[k] = i; } +enum ubsan_test_enum { + UBSAN_TEST_ZERO = 0, + UBSAN_TEST_ONE, + UBSAN_TEST_MAX, +}; + static void test_ubsan_load_invalid_value(void) { volatile char *dst, *src; bool val, val2, *ptr; - char c = 4; + enum ubsan_test_enum eval, eval2, *eptr; + unsigned char c = 0xff; + UBSAN_TEST(CONFIG_UBSAN_BOOL, "bool"); dst = (char *)&val; src = &c; *dst = *src; ptr = &val2; val2 = val; + + UBSAN_TEST(CONFIG_UBSAN_ENUM, "enum"); + dst = (char *)&eval; + src = &c; + *dst = *src; + + eptr = &eval2; + eval2 = eval; } static void test_ubsan_null_ptr_deref(void) @@ -77,6 +129,7 @@ static void test_ubsan_null_ptr_deref(void) volatile int *ptr = NULL; int val; + UBSAN_TEST(CONFIG_UBSAN_OBJECT_SIZE); val = *ptr; } @@ -85,6 +138,7 @@ static void test_ubsan_misaligned_access(void) volatile char arr[5] __aligned(4) = {1, 2, 3, 4, 5}; volatile int *ptr, val = 6; + UBSAN_TEST(CONFIG_UBSAN_ALIGNMENT); ptr = (int *)(arr + 1); *ptr = val; } @@ -95,6 +149,7 @@ static void test_ubsan_object_size_mismatch(void) volatile int val __aligned(8) = 4; volatile long long *ptr, val2; + UBSAN_TEST(CONFIG_UBSAN_OBJECT_SIZE); ptr = (long long *)&val; val2 = *ptr; } @@ -104,15 +159,19 @@ static const test_ubsan_fp test_ubsan_array[] = { test_ubsan_sub_overflow, test_ubsan_mul_overflow, test_ubsan_negate_overflow, - test_ubsan_divrem_overflow, test_ubsan_shift_out_of_bounds, test_ubsan_out_of_bounds, test_ubsan_load_invalid_value, - //test_ubsan_null_ptr_deref, /* exclude it because there is a crash */ test_ubsan_misaligned_access, test_ubsan_object_size_mismatch, }; +/* Excluded because they Oops the module. */ +static const test_ubsan_fp skip_ubsan_array[] = { + test_ubsan_divrem_overflow, + test_ubsan_null_ptr_deref, +}; + static int __init test_ubsan_init(void) { unsigned int i; @@ -120,7 +179,6 @@ static int __init test_ubsan_init(void) for (i = 0; i < ARRAY_SIZE(test_ubsan_array); i++) test_ubsan_array[i](); - (void)test_ubsan_null_ptr_deref; /* to avoid unsed-function warning */ return 0; } module_init(test_ubsan_init); diff --git a/lib/ubsan.c b/lib/ubsan.c index cb9af3f6b77e..3e3352f3d0da 100644 --- a/lib/ubsan.c +++ b/lib/ubsan.c @@ -17,7 +17,7 @@ #include "ubsan.h" -const char *type_check_kinds[] = { +static const char * const type_check_kinds[] = { "load of", "store to", "reference binding to", diff --git a/mm/filemap.c b/mm/filemap.c index c178022d7893..2e16daf98bf9 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1359,7 +1359,7 @@ static int __wait_on_page_locked_async(struct page *page, else ret = PageLocked(page); /* - * If we were succesful now, we know we're still on the + * If we were successful now, we know we're still on the * waitqueue as we're still under the lock. This means it's * safe to remove and return success, we know the callback * isn't going to trigger. diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 1efe2b5ad59a..9237976abe72 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2391,7 +2391,7 @@ static void __split_huge_page_tail(struct page *head, int tail, * Clone page flags before unfreezing refcount. * * After successful get_page_unless_zero() might follow flags change, - * for exmaple lock_page() which set PG_waiters. + * for example lock_page() which set PG_waiters. */ page_tail->flags &= ~PAGE_FLAGS_CHECK_AT_PREP; page_tail->flags |= (head->flags & diff --git a/mm/khugepaged.c b/mm/khugepaged.c index ad316d2e1fee..67ab391a5373 100644 --- a/mm/khugepaged.c +++ b/mm/khugepaged.c @@ -1275,7 +1275,7 @@ static int khugepaged_scan_pmd(struct mm_struct *mm, * PTEs are armed with uffd write protection. * Here we can also mark the new huge pmd as * write protected if any of the small ones is - * marked but that could bring uknown + * marked but that could bring unknown * userfault messages that falls outside of * the registered range. So, just be simple. */ diff --git a/mm/memblock.c b/mm/memblock.c index 049df4163a97..a3c406070f4d 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -871,7 +871,7 @@ int __init_memblock memblock_physmem_add(phys_addr_t base, phys_addr_t size) * @base: base address of the region * @size: size of the region * @set: set or clear the flag - * @flag: the flag to udpate + * @flag: the flag to update * * This function isolates region [@base, @base + @size), and sets/clears flag * diff --git a/mm/memory.c b/mm/memory.c index 4a42a74a2240..7d608765932b 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -4707,9 +4707,9 @@ int __pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address) } #endif /* __PAGETABLE_PMD_FOLDED */ -static int __follow_pte_pmd(struct mm_struct *mm, unsigned long address, - struct mmu_notifier_range *range, - pte_t **ptepp, pmd_t **pmdpp, spinlock_t **ptlp) +int follow_pte(struct mm_struct *mm, unsigned long address, + struct mmu_notifier_range *range, pte_t **ptepp, pmd_t **pmdpp, + spinlock_t **ptlp) { pgd_t *pgd; p4d_t *p4d; @@ -4774,32 +4774,6 @@ out: return -EINVAL; } -static inline int follow_pte(struct mm_struct *mm, unsigned long address, - pte_t **ptepp, spinlock_t **ptlp) -{ - int res; - - /* (void) is needed to make gcc happy */ - (void) __cond_lock(*ptlp, - !(res = __follow_pte_pmd(mm, address, NULL, - ptepp, NULL, ptlp))); - return res; -} - -int follow_pte_pmd(struct mm_struct *mm, unsigned long address, - struct mmu_notifier_range *range, - pte_t **ptepp, pmd_t **pmdpp, spinlock_t **ptlp) -{ - int res; - - /* (void) is needed to make gcc happy */ - (void) __cond_lock(*ptlp, - !(res = __follow_pte_pmd(mm, address, range, - ptepp, pmdpp, ptlp))); - return res; -} -EXPORT_SYMBOL(follow_pte_pmd); - /** * follow_pfn - look up PFN at a user virtual address * @vma: memory mapping @@ -4820,7 +4794,7 @@ int follow_pfn(struct vm_area_struct *vma, unsigned long address, if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) return ret; - ret = follow_pte(vma->vm_mm, address, &ptep, &ptl); + ret = follow_pte(vma->vm_mm, address, NULL, &ptep, NULL, &ptl); if (ret) return ret; *pfn = pte_pfn(*ptep); @@ -4841,7 +4815,7 @@ int follow_phys(struct vm_area_struct *vma, if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) goto out; - if (follow_pte(vma->vm_mm, address, &ptep, &ptl)) + if (follow_pte(vma->vm_mm, address, NULL, &ptep, NULL, &ptl)) goto out; pte = *ptep; diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index e0a561c550b3..c01604224299 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -1561,7 +1561,7 @@ int __ref offline_pages(unsigned long start_pfn, unsigned long nr_pages) /* Mark all sections offline and remove free pages from the buddy. */ __offline_isolated_pages(start_pfn, end_pfn); - pr_info("Offlined Pages %ld\n", nr_pages); + pr_debug("Offlined Pages %ld\n", nr_pages); /* * The memory sections are marked offline, and the pageblock flags diff --git a/mm/migrate.c b/mm/migrate.c index ee802cb509a3..ee5e612b4cd8 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -2594,7 +2594,7 @@ static bool migrate_vma_check_page(struct page *page) * will bump the page reference count. Sadly there is no way to * differentiate a regular pin from migration wait. Hence to * avoid 2 racing thread trying to migrate back to CPU to enter - * infinite loop (one stoping migration because the other is + * infinite loop (one stopping migration because the other is * waiting on pte migration entry). We always return true here. * * FIXME proper solution is to rework migration_entry_wait() so diff --git a/mm/page_ext.c b/mm/page_ext.c index 16b161f28a31..df6f74aac8e1 100644 --- a/mm/page_ext.c +++ b/mm/page_ext.c @@ -34,7 +34,7 @@ * * The need callback is used to decide whether extended memory allocation is * needed or not. Sometimes users want to deactivate some features in this - * boot and extra memory would be unneccessary. In this case, to avoid + * boot and extra memory would be unnecessary. In this case, to avoid * allocating huge chunk of memory, each clients represent their need of * extra memory through the need callback. If one of the need callbacks * returns true, it means that someone needs extra memory so that diff --git a/mm/swapfile.c b/mm/swapfile.c index 1c0a829f7311..9fffc5af29d1 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1042,16 +1042,18 @@ int get_swap_pages(int n_goal, swp_entry_t swp_entries[], int entry_size) /* Only single cluster request supported */ WARN_ON_ONCE(n_goal > 1 && size == SWAPFILE_CLUSTER); + spin_lock(&swap_avail_lock); + avail_pgs = atomic_long_read(&nr_swap_pages) / size; - if (avail_pgs <= 0) + if (avail_pgs <= 0) { + spin_unlock(&swap_avail_lock); goto noswap; + } n_goal = min3((long)n_goal, (long)SWAP_BATCH, avail_pgs); atomic_long_sub(n_goal * size, &nr_swap_pages); - spin_lock(&swap_avail_lock); - start_over: node = numa_node_id(); plist_for_each_entry_safe(si, next, &swap_avail_heads[node], avail_lists[node]) { @@ -1125,14 +1127,13 @@ swp_entry_t get_swap_page_of_type(int type) spin_lock(&si->lock); if (si->flags & SWP_WRITEOK) { - atomic_long_dec(&nr_swap_pages); /* This is called for allocating swap entry, not cache */ offset = scan_swap_map(si, 1); if (offset) { + atomic_long_dec(&nr_swap_pages); spin_unlock(&si->lock); return swp_entry(type, offset); } - atomic_long_inc(&nr_swap_pages); } spin_unlock(&si->lock); fail: diff --git a/scripts/Makefile.ubsan b/scripts/Makefile.ubsan index 9716dab06bc7..0e53a93e8f15 100644 --- a/scripts/Makefile.ubsan +++ b/scripts/Makefile.ubsan @@ -1,37 +1,18 @@ # SPDX-License-Identifier: GPL-2.0 -export CFLAGS_UBSAN := +# Enable available and selected UBSAN features. +ubsan-cflags-$(CONFIG_UBSAN_ALIGNMENT) += -fsanitize=alignment +ubsan-cflags-$(CONFIG_UBSAN_ONLY_BOUNDS) += -fsanitize=bounds +ubsan-cflags-$(CONFIG_UBSAN_ARRAY_BOUNDS) += -fsanitize=array-bounds +ubsan-cflags-$(CONFIG_UBSAN_LOCAL_BOUNDS) += -fsanitize=local-bounds +ubsan-cflags-$(CONFIG_UBSAN_SHIFT) += -fsanitize=shift +ubsan-cflags-$(CONFIG_UBSAN_DIV_ZERO) += -fsanitize=integer-divide-by-zero +ubsan-cflags-$(CONFIG_UBSAN_UNREACHABLE) += -fsanitize=unreachable +ubsan-cflags-$(CONFIG_UBSAN_SIGNED_OVERFLOW) += -fsanitize=signed-integer-overflow +ubsan-cflags-$(CONFIG_UBSAN_UNSIGNED_OVERFLOW) += -fsanitize=unsigned-integer-overflow +ubsan-cflags-$(CONFIG_UBSAN_OBJECT_SIZE) += -fsanitize=object-size +ubsan-cflags-$(CONFIG_UBSAN_BOOL) += -fsanitize=bool +ubsan-cflags-$(CONFIG_UBSAN_ENUM) += -fsanitize=enum +ubsan-cflags-$(CONFIG_UBSAN_TRAP) += -fsanitize-undefined-trap-on-error -ifdef CONFIG_UBSAN_ALIGNMENT - CFLAGS_UBSAN += $(call cc-option, -fsanitize=alignment) -endif - -ifdef CONFIG_UBSAN_BOUNDS - ifdef CONFIG_CC_IS_CLANG - CFLAGS_UBSAN += -fsanitize=array-bounds - else - CFLAGS_UBSAN += $(call cc-option, -fsanitize=bounds) - endif -endif - -ifdef CONFIG_UBSAN_LOCAL_BOUNDS - CFLAGS_UBSAN += -fsanitize=local-bounds -endif - -ifdef CONFIG_UBSAN_MISC - CFLAGS_UBSAN += $(call cc-option, -fsanitize=shift) - CFLAGS_UBSAN += $(call cc-option, -fsanitize=integer-divide-by-zero) - CFLAGS_UBSAN += $(call cc-option, -fsanitize=unreachable) - CFLAGS_UBSAN += $(call cc-option, -fsanitize=signed-integer-overflow) - CFLAGS_UBSAN += $(call cc-option, -fsanitize=object-size) - CFLAGS_UBSAN += $(call cc-option, -fsanitize=bool) - CFLAGS_UBSAN += $(call cc-option, -fsanitize=enum) -endif - -ifdef CONFIG_UBSAN_TRAP - CFLAGS_UBSAN += $(call cc-option, -fsanitize-undefined-trap-on-error) -endif - - # -fsanitize=* options makes GCC less smart than usual and - # increase number of 'maybe-uninitialized false-positives - CFLAGS_UBSAN += $(call cc-option, -Wno-maybe-uninitialized) +export CFLAGS_UBSAN := $(ubsan-cflags-y) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index fab38b493cef..00085308ed9d 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -506,6 +506,64 @@ our $signature_tags = qr{(?xi: Cc: )}; +sub edit_distance_min { + my (@arr) = @_; + my $len = scalar @arr; + if ((scalar @arr) < 1) { + # if underflow, return + return; + } + my $min = $arr[0]; + for my $i (0 .. ($len-1)) { + if ($arr[$i] < $min) { + $min = $arr[$i]; + } + } + return $min; +} + +sub get_edit_distance { + my ($str1, $str2) = @_; + $str1 = lc($str1); + $str2 = lc($str2); + $str1 =~ s/-//g; + $str2 =~ s/-//g; + my $len1 = length($str1); + my $len2 = length($str2); + # two dimensional array storing minimum edit distance + my @distance; + for my $i (0 .. $len1) { + for my $j (0 .. $len2) { + if ($i == 0) { + $distance[$i][$j] = $j; + } elsif ($j == 0) { + $distance[$i][$j] = $i; + } elsif (substr($str1, $i-1, 1) eq substr($str2, $j-1, 1)) { + $distance[$i][$j] = $distance[$i - 1][$j - 1]; + } else { + my $dist1 = $distance[$i][$j - 1]; #insert distance + my $dist2 = $distance[$i - 1][$j]; # remove + my $dist3 = $distance[$i - 1][$j - 1]; #replace + $distance[$i][$j] = 1 + edit_distance_min($dist1, $dist2, $dist3); + } + } + } + return $distance[$len1][$len2]; +} + +sub find_standard_signature { + my ($sign_off) = @_; + my @standard_signature_tags = ( + 'Signed-off-by:', 'Co-developed-by:', 'Acked-by:', 'Tested-by:', + 'Reviewed-by:', 'Reported-by:', 'Suggested-by:' + ); + foreach my $signature (@standard_signature_tags) { + return $signature if (get_edit_distance($sign_off, $signature) <= 2); + } + + return ""; +} + our @typeListMisordered = ( qr{char\s+(?:un)?signed}, qr{int\s+(?:(?:un)?signed\s+)?short\s}, @@ -853,6 +911,13 @@ our $declaration_macros = qr{(?x: (?:SKCIPHER_REQUEST|SHASH_DESC|AHASH_REQUEST)_ON_STACK\s*\( )}; +our %allow_repeated_words = ( + add => '', + added => '', + bad => '', + be => '', +); + sub deparenthesize { my ($string) = @_; return "" if (!defined($string)); @@ -1152,6 +1217,7 @@ sub parse_email { my ($formatted_email) = @_; my $name = ""; + my $quoted = ""; my $name_comment = ""; my $address = ""; my $comment = ""; @@ -1183,14 +1249,20 @@ sub parse_email { } } - $comment = trim($comment); - $name = trim($name); - $name =~ s/^\"|\"$//g; - if ($name =~ s/(\s*\([^\)]+\))\s*//) { - $name_comment = trim($1); + # Extract comments from names excluding quoted parts + # "John D. (Doe)" - Do not extract + if ($name =~ s/\"(.+)\"//) { + $quoted = $1; } + while ($name =~ s/\s*($balanced_parens)\s*/ /) { + $name_comment .= trim($1); + } + $name =~ s/^[ \"]+|[ \"]+$//g; + $name = trim("$quoted $name"); + $address = trim($address); $address =~ s/^\<|\>$//g; + $comment = trim($comment); if ($name =~ /[^\w \-]/i) { ##has "must quote" chars $name =~ s/(?<!\\)"/\\"/g; ##escape quotes @@ -1205,17 +1277,20 @@ sub format_email { my $formatted_email; - $name_comment = trim($name_comment); - $comment = trim($comment); - $name = trim($name); - $name =~ s/^\"|\"$//g; + $name =~ s/^[ \"]+|[ \"]+$//g; $address = trim($address); + $address =~ s/(?:\.|\,|\")+$//; ##trailing commas, dots or quotes if ($name =~ /[^\w \-]/i) { ##has "must quote" chars $name =~ s/(?<!\\)"/\\"/g; ##escape quotes $name = "\"$name\""; } + $name_comment = trim($name_comment); + $name_comment = " $name_comment" if ($name_comment ne ""); + $comment = trim($comment); + $comment = " $comment" if ($comment ne ""); + if ("$name" eq "") { $formatted_email = "$address"; } else { @@ -1233,15 +1308,11 @@ sub reformat_email { } sub same_email_addresses { - my ($email1, $email2, $match_comment) = @_; + my ($email1, $email2) = @_; my ($email1_name, $name1_comment, $email1_address, $comment1) = parse_email($email1); my ($email2_name, $name2_comment, $email2_address, $comment2) = parse_email($email2); - if ($match_comment != 1) { - return $email1_name eq $email2_name && - $email1_address eq $email2_address; - } return $email1_name eq $email2_name && $email1_address eq $email2_address && $name1_comment eq $name2_comment && @@ -2704,7 +2775,7 @@ sub process { $signoff++; $in_commit_log = 0; if ($author ne '' && $authorsignoff != 1) { - if (same_email_addresses($1, $author, 1)) { + if (same_email_addresses($1, $author)) { $authorsignoff = 1; } else { my $ctx = $1; @@ -2760,8 +2831,17 @@ sub process { my $ucfirst_sign_off = ucfirst(lc($sign_off)); if ($sign_off !~ /$signature_tags/) { - WARN("BAD_SIGN_OFF", - "Non-standard signature: $sign_off\n" . $herecurr); + my $suggested_signature = find_standard_signature($sign_off); + if ($suggested_signature eq "") { + WARN("BAD_SIGN_OFF", + "Non-standard signature: $sign_off\n" . $herecurr); + } else { + if (WARN("BAD_SIGN_OFF", + "Non-standard signature: '$sign_off' - perhaps '$suggested_signature'?\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/$sign_off/$suggested_signature/; + } + } } if (defined $space_before && $space_before ne "") { if (WARN("BAD_SIGN_OFF", @@ -2800,9 +2880,77 @@ sub process { $dequoted =~ s/" </ </; # Don't force email to have quotes # Allow just an angle bracketed address - if (!same_email_addresses($email, $suggested_email, 0)) { + if (!same_email_addresses($email, $suggested_email)) { + if (WARN("BAD_SIGN_OFF", + "email address '$email' might be better as '$suggested_email'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\Q$email\E/$suggested_email/; + } + } + + # Address part shouldn't have comments + my $stripped_address = $email_address; + $stripped_address =~ s/\([^\(\)]*\)//g; + if ($email_address ne $stripped_address) { + if (WARN("BAD_SIGN_OFF", + "address part of email should not have comments: '$email_address'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\Q$email_address\E/$stripped_address/; + } + } + + # Only one name comment should be allowed + my $comment_count = () = $name_comment =~ /\([^\)]+\)/g; + if ($comment_count > 1) { WARN("BAD_SIGN_OFF", - "email address '$email' might be better as '$suggested_email'\n" . $herecurr); + "Use a single name comment in email: '$email'\n" . $herecurr); + } + + + # stable@vger.kernel.org or stable@kernel.org shouldn't + # have an email name. In addition comments should strictly + # begin with a # + if ($email =~ /^.*stable\@(?:vger\.)?kernel\.org/i) { + if (($comment ne "" && $comment !~ /^#.+/) || + ($email_name ne "")) { + my $cur_name = $email_name; + my $new_comment = $comment; + $cur_name =~ s/[a-zA-Z\s\-\"]+//g; + + # Remove brackets enclosing comment text + # and # from start of comments to get comment text + $new_comment =~ s/^\((.*)\)$/$1/; + $new_comment =~ s/^\[(.*)\]$/$1/; + $new_comment =~ s/^[\s\#]+|\s+$//g; + + $new_comment = trim("$new_comment $cur_name") if ($cur_name ne $new_comment); + $new_comment = " # $new_comment" if ($new_comment ne ""); + my $new_email = "$email_address$new_comment"; + + if (WARN("BAD_STABLE_ADDRESS_STYLE", + "Invalid email format for stable: '$email', prefer '$new_email'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\Q$email\E/$new_email/; + } + } + } elsif ($comment ne "" && $comment !~ /^(?:#.+|\(.+\))$/) { + my $new_comment = $comment; + + # Extract comment text from within brackets or + # c89 style /*...*/ comments + $new_comment =~ s/^\[(.*)\]$/$1/; + $new_comment =~ s/^\/\*(.*)\*\/$/$1/; + + $new_comment = trim($new_comment); + $new_comment =~ s/^[^\w]$//; # Single lettered comment with non word character is usually a typo + $new_comment = "($new_comment)" if ($new_comment ne ""); + my $new_email = format_email($email_name, $name_comment, $email_address, $new_comment); + + if (WARN("BAD_SIGN_OFF", + "Unexpected content after email: '$email', should be: '$new_email'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\Q$email\E/$new_email/; + } } } @@ -2845,8 +2993,11 @@ sub process { # Check for Gerrit Change-Ids not in any patch context if ($realfile eq '' && !$has_patch_separator && $line =~ /^\s*change-id:/i) { - ERROR("GERRIT_CHANGE_ID", - "Remove Gerrit Change-Id's before submitting upstream\n" . $herecurr); + if (ERROR("GERRIT_CHANGE_ID", + "Remove Gerrit Change-Id's before submitting upstream\n" . $herecurr) && + $fix) { + fix_delete_line($fixlinenr, $rawline); + } } # Check if the commit log is in a possible stack dump @@ -2868,8 +3019,8 @@ sub process { # file delta changes $line =~ /^\s*(?:[\w\.\-]+\/)++[\w\.\-]+:/ || # filename then : - $line =~ /^\s*(?:Fixes:|Link:)/i || - # A Fixes: or Link: line + $line =~ /^\s*(?:Fixes:|Link:|$signature_tags)/i || + # A Fixes: or Link: line or signature tag line $commit_log_possible_stack_dump)) { WARN("COMMIT_LOG_LONG_LINE", "Possible unwrapped commit description (prefer a maximum 75 chars per line)\n" . $herecurr); @@ -2882,6 +3033,15 @@ sub process { $commit_log_possible_stack_dump = 0; } +# Check for lines starting with a # + if ($in_commit_log && $line =~ /^#/) { + if (WARN("COMMIT_COMMENT_SYMBOL", + "Commit log lines starting with '#' are dropped by git as comments\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/^/ /; + } + } + # Check for git id commit length and improperly formed commit descriptions if ($in_commit_log && !$commit_log_possible_stack_dump && $line !~ /^\s*(?:Link|Patchwork|http|https|BugLink|base-commit):/i && @@ -3022,15 +3182,18 @@ sub process { # Check for various typo / spelling mistakes if (defined($misspellings) && ($in_commit_log || $line =~ /^(?:\+|Subject:)/i)) { - while ($rawline =~ /(?:^|[^a-z@])($misspellings)(?:\b|$|[^a-z@])/gi) { + while ($rawline =~ /(?:^|[^\w\-'`])($misspellings)(?:[^\w\-'`]|$)/gi) { my $typo = $1; + my $blank = copy_spacing($rawline); + my $ptr = substr($blank, 0, $-[1]) . "^" x length($typo); + my $hereptr = "$hereline$ptr\n"; my $typo_fix = $spelling_fix{lc($typo)}; $typo_fix = ucfirst($typo_fix) if ($typo =~ /^[A-Z]/); $typo_fix = uc($typo_fix) if ($typo =~ /^[A-Z]+$/); my $msg_level = \&WARN; $msg_level = \&CHK if ($file); if (&{$msg_level}("TYPO_SPELLING", - "'$typo' may be misspelled - perhaps '$typo_fix'?\n" . $herecurr) && + "'$typo' may be misspelled - perhaps '$typo_fix'?\n" . $hereptr) && $fix) { $fixed[$fixlinenr] =~ s/(^|[^A-Za-z@])($typo)($|[^A-Za-z@])/$1$typo_fix$3/; } @@ -3049,20 +3212,38 @@ sub process { } # check for repeated words separated by a single space - if ($rawline =~ /^\+/ || $in_commit_log) { +# avoid false positive from list command eg, '-rw-r--r-- 1 root root' + if (($rawline =~ /^\+/ || $in_commit_log) && + $rawline !~ /[bcCdDlMnpPs\?-][rwxsStT-]{9}/) { + pos($rawline) = 1 if (!$in_commit_log); while ($rawline =~ /\b($word_pattern) (?=($word_pattern))/g) { my $first = $1; my $second = $2; - + my $start_pos = $-[1]; + my $end_pos = $+[2]; if ($first =~ /(?:struct|union|enum)/) { pos($rawline) += length($first) + length($second) + 1; next; } - next if ($first ne $second); + next if (lc($first) ne lc($second)); next if ($first eq 'long'); + # check for character before and after the word matches + my $start_char = ''; + my $end_char = ''; + $start_char = substr($rawline, $start_pos - 1, 1) if ($start_pos > ($in_commit_log ? 0 : 1)); + $end_char = substr($rawline, $end_pos, 1) if ($end_pos < length($rawline)); + + next if ($start_char =~ /^\S$/); + next if (index(" \t.,;?!", $end_char) == -1); + + # avoid repeating hex occurrences like 'ff ff fe 09 ...' + if ($first =~ /\b[0-9a-f]{2,}\b/i) { + next if (!exists($allow_repeated_words{lc($first)})); + } + if (WARN("REPEATED_WORD", "Possible repeated word: '$first'\n" . $herecurr) && $fix) { @@ -3393,8 +3574,11 @@ sub process { # check for adding lines without a newline. if ($line =~ /^\+/ && defined $lines[$linenr] && $lines[$linenr] =~ /^\\ No newline at end of file/) { - WARN("MISSING_EOF_NEWLINE", - "adding a line without newline at end of file\n" . $herecurr); + if (WARN("MISSING_EOF_NEWLINE", + "adding a line without newline at end of file\n" . $herecurr) && + $fix) { + fix_delete_line($fixlinenr+1, "No newline at end of file"); + } } # check we are in a valid source file C or perl if not then ignore this hunk @@ -3428,14 +3612,28 @@ sub process { # check for assignments on the start of a line if ($sline =~ /^\+\s+($Assignment)[^=]/) { - CHK("ASSIGNMENT_CONTINUATIONS", - "Assignment operator '$1' should be on the previous line\n" . $hereprev); + my $operator = $1; + if (CHK("ASSIGNMENT_CONTINUATIONS", + "Assignment operator '$1' should be on the previous line\n" . $hereprev) && + $fix && $prevrawline =~ /^\+/) { + # add assignment operator to the previous line, remove from current line + $fixed[$fixlinenr - 1] .= " $operator"; + $fixed[$fixlinenr] =~ s/\Q$operator\E\s*//; + } } # check for && or || at the start of a line if ($rawline =~ /^\+\s*(&&|\|\|)/) { - CHK("LOGICAL_CONTINUATIONS", - "Logical continuations should be on the previous line\n" . $hereprev); + my $operator = $1; + if (CHK("LOGICAL_CONTINUATIONS", + "Logical continuations should be on the previous line\n" . $hereprev) && + $fix && $prevrawline =~ /^\+/) { + # insert logical operator at last non-comment, non-whitepsace char on previous line + $prevline =~ /[\s$;]*$/; + my $line_end = substr($prevrawline, $-[0]); + $fixed[$fixlinenr - 1] =~ s/\Q$line_end\E$/ $operator$line_end/; + $fixed[$fixlinenr] =~ s/\Q$operator\E\s*//; + } } # check indentation starts on a tab stop @@ -3674,12 +3872,16 @@ sub process { } # check indentation of a line with a break; -# if the previous line is a goto or return and is indented the same # of tabs +# if the previous line is a goto, return or break +# and is indented the same # of tabs if ($sline =~ /^\+([\t]+)break\s*;\s*$/) { my $tabs = $1; - if ($prevline =~ /^\+$tabs(?:goto|return)\b/) { - WARN("UNNECESSARY_BREAK", - "break is not useful after a goto or return\n" . $hereprev); + if ($prevline =~ /^\+$tabs(goto|return|break)\b/) { + if (WARN("UNNECESSARY_BREAK", + "break is not useful after a $1\n" . $hereprev) && + $fix) { + fix_delete_line($fixlinenr, $rawline); + } } } @@ -4207,6 +4409,18 @@ sub process { } } +# check for const static or static <non ptr type> const declarations +# prefer 'static const <foo>' over 'const static <foo>' and 'static <foo> const' + if ($sline =~ /^\+\s*const\s+static\s+($Type)\b/ || + $sline =~ /^\+\s*static\s+($BasicType)\s+const\b/) { + if (WARN("STATIC_CONST", + "Move const after static - use 'static const $1'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bconst\s+static\b/static const/; + $fixed[$fixlinenr] =~ s/\bstatic\s+($BasicType)\s+const\b/static const $1/; + } + } + # check for non-global char *foo[] = {"bar", ...} declarations. if ($line =~ /^.\s+(?:static\s+|const\s+)?char\s+\*\s*\w+\s*\[\s*\]\s*=\s*\{/) { WARN("STATIC_CONST_CHAR_ARRAY", @@ -4329,16 +4543,23 @@ sub process { "printk() should include KERN_<LEVEL> facility level\n" . $herecurr); } - if ($line =~ /\bprintk\s*\(\s*KERN_([A-Z]+)/) { - my $orig = $1; +# prefer variants of (subsystem|netdev|dev|pr)_<level> to printk(KERN_<LEVEL> + if ($line =~ /\b(printk(_once|_ratelimited)?)\s*\(\s*KERN_([A-Z]+)/) { + my $printk = $1; + my $modifier = $2; + my $orig = $3; + $modifier = "" if (!defined($modifier)); my $level = lc($orig); $level = "warn" if ($level eq "warning"); my $level2 = $level; $level2 = "dbg" if ($level eq "debug"); + $level .= $modifier; + $level2 .= $modifier; WARN("PREFER_PR_LEVEL", - "Prefer [subsystem eg: netdev]_$level2([subsystem]dev, ... then dev_$level2(dev, ... then pr_$level(... to printk(KERN_$orig ...\n" . $herecurr); + "Prefer [subsystem eg: netdev]_$level2([subsystem]dev, ... then dev_$level2(dev, ... then pr_$level(... to $printk(KERN_$orig ...\n" . $herecurr); } +# prefer dev_<level> to dev_printk(KERN_<LEVEL> if ($line =~ /\bdev_printk\s*\(\s*KERN_([A-Z]+)/) { my $orig = $1; my $level = lc($orig); @@ -4384,7 +4605,7 @@ sub process { $fix) { fix_delete_line($fixlinenr, $rawline); my $fixed_line = $rawline; - $fixed_line =~ /(^..*$Type\s*$Ident\(.*\)\s*){(.*)$/; + $fixed_line =~ /(^..*$Type\s*$Ident\(.*\)\s*)\{(.*)$/; my $line1 = $1; my $line2 = $2; fix_insert_line($fixlinenr, ltrim($line1)); @@ -4879,7 +5100,7 @@ sub process { ## $line !~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Type\s*$Ident.*/) { ## ## # Remove any bracketed sections to ensure we do not -## # falsly report the parameters of functions. +## # falsely report the parameters of functions. ## my $ln = $line; ## while ($ln =~ s/\([^\(\)]*\)//g) { ## } @@ -5295,6 +5516,8 @@ sub process { #CamelCase if ($var !~ /^$Constant$/ && $var =~ /[A-Z][a-z]|[a-z][A-Z]/ && +#Ignore some autogenerated defines and enum values + $var !~ /^(?:[A-Z]+_){1,5}[A-Z]{1,3}[a-z]/ && #Ignore Page<foo> variants $var !~ /^(?:Clear|Set|TestClear|TestSet|)Page[A-Z]/ && #Ignore SI style variants like nS, mV and dB @@ -5898,6 +6121,28 @@ sub process { "Avoid logging continuation uses where feasible\n" . $herecurr); } +# check for unnecessary use of %h[xudi] and %hh[xudi] in logging functions + if (defined $stat && + $line =~ /\b$logFunctions\s*\(/ && + index($stat, '"') >= 0) { + my $lc = $stat =~ tr@\n@@; + $lc = $lc + $linenr; + my $stat_real = get_stat_real($linenr, $lc); + pos($stat_real) = index($stat_real, '"'); + while ($stat_real =~ /[^\"%]*(%[\#\d\.\*\-]*(h+)[idux])/g) { + my $pspec = $1; + my $h = $2; + my $lineoff = substr($stat_real, 0, $-[1]) =~ tr@\n@@; + if (WARN("UNNECESSARY_MODIFIER", + "Integer promotion: Using '$h' in '$pspec' is unnecessary\n" . "$here\n$stat_real\n") && + $fix && $fixed[$fixlinenr + $lineoff] =~ /^\+/) { + my $nspec = $pspec; + $nspec =~ s/h//g; + $fixed[$fixlinenr + $lineoff] =~ s/\Q$pspec\E/$nspec/; + } + } + } + # check for mask then right shift without a parentheses if ($perl_version_ok && $line =~ /$LvalOrFunc\s*\&\s*($LvalOrFunc)\s*>>/ && @@ -6144,50 +6389,68 @@ sub process { } } -# Check for __attribute__ packed, prefer __packed - if ($realfile !~ m@\binclude/uapi/@ && - $line =~ /\b__attribute__\s*\(\s*\(.*\bpacked\b/) { - WARN("PREFER_PACKED", - "__packed is preferred over __attribute__((packed))\n" . $herecurr); - } - -# Check for __attribute__ aligned, prefer __aligned - if ($realfile !~ m@\binclude/uapi/@ && - $line =~ /\b__attribute__\s*\(\s*\(.*aligned/) { - WARN("PREFER_ALIGNED", - "__aligned(size) is preferred over __attribute__((aligned(size)))\n" . $herecurr); - } - -# Check for __attribute__ section, prefer __section +# Check for compiler attributes if ($realfile !~ m@\binclude/uapi/@ && - $line =~ /\b__attribute__\s*\(\s*\(.*_*section_*\s*\(\s*("[^"]*")/) { - my $old = substr($rawline, $-[1], $+[1] - $-[1]); - my $new = substr($old, 1, -1); - if (WARN("PREFER_SECTION", - "__section($new) is preferred over __attribute__((section($old)))\n" . $herecurr) && - $fix) { - $fixed[$fixlinenr] =~ s/\b__attribute__\s*\(\s*\(\s*_*section_*\s*\(\s*\Q$old\E\s*\)\s*\)\s*\)/__section($new)/; - } - } - -# Check for __attribute__ format(printf, prefer __printf - if ($realfile !~ m@\binclude/uapi/@ && - $line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf/) { - if (WARN("PREFER_PRINTF", - "__printf(string-index, first-to-check) is preferred over __attribute__((format(printf, string-index, first-to-check)))\n" . $herecurr) && - $fix) { - $fixed[$fixlinenr] =~ s/\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf\s*,\s*(.*)\)\s*\)\s*\)/"__printf(" . trim($1) . ")"/ex; - + $rawline =~ /\b__attribute__\s*\(\s*($balanced_parens)\s*\)/) { + my $attr = $1; + $attr =~ s/\s*\(\s*(.*)\)\s*/$1/; + + my %attr_list = ( + "alias" => "__alias", + "aligned" => "__aligned", + "always_inline" => "__always_inline", + "assume_aligned" => "__assume_aligned", + "cold" => "__cold", + "const" => "__attribute_const__", + "copy" => "__copy", + "designated_init" => "__designated_init", + "externally_visible" => "__visible", + "format" => "printf|scanf", + "gnu_inline" => "__gnu_inline", + "malloc" => "__malloc", + "mode" => "__mode", + "no_caller_saved_registers" => "__no_caller_saved_registers", + "noclone" => "__noclone", + "noinline" => "noinline", + "nonstring" => "__nonstring", + "noreturn" => "__noreturn", + "packed" => "__packed", + "pure" => "__pure", + "section" => "__section", + "used" => "__used", + "weak" => "__weak" + ); + + while ($attr =~ /\s*(\w+)\s*(${balanced_parens})?/g) { + my $orig_attr = $1; + my $params = ''; + $params = $2 if defined($2); + my $curr_attr = $orig_attr; + $curr_attr =~ s/^[\s_]+|[\s_]+$//g; + if (exists($attr_list{$curr_attr})) { + my $new = $attr_list{$curr_attr}; + if ($curr_attr eq "format" && $params) { + $params =~ /^\s*\(\s*(\w+)\s*,\s*(.*)/; + $new = "__$1\($2"; + } else { + $new = "$new$params"; + } + if (WARN("PREFER_DEFINED_ATTRIBUTE_MACRO", + "Prefer $new over __attribute__(($orig_attr$params))\n" . $herecurr) && + $fix) { + my $remove = "\Q$orig_attr\E" . '\s*' . "\Q$params\E" . '(?:\s*,\s*)?'; + $fixed[$fixlinenr] =~ s/$remove//; + $fixed[$fixlinenr] =~ s/\b__attribute__/$new __attribute__/; + $fixed[$fixlinenr] =~ s/\}\Q$new\E/} $new/; + $fixed[$fixlinenr] =~ s/ __attribute__\s*\(\s*\(\s*\)\s*\)//; + } + } } - } -# Check for __attribute__ format(scanf, prefer __scanf - if ($realfile !~ m@\binclude/uapi/@ && - $line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\b/) { - if (WARN("PREFER_SCANF", - "__scanf(string-index, first-to-check) is preferred over __attribute__((format(scanf, string-index, first-to-check)))\n" . $herecurr) && - $fix) { - $fixed[$fixlinenr] =~ s/\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\s*,\s*(.*)\)\s*\)\s*\)/"__scanf(" . trim($1) . ")"/ex; + # Check for __attribute__ unused, prefer __always_unused or __maybe_unused + if ($attr =~ /^_*unused/) { + WARN("PREFER_DEFINED_ATTRIBUTE_MACRO", + "__always_unused or __maybe_unused is preferred over __attribute__((__unused__))\n" . $herecurr); } } @@ -6968,7 +7231,7 @@ sub process { exit(0); } - # This is not a patch, and we are are in 'no-patch' mode so + # This is not a patch, and we are in 'no-patch' mode so # just keep quiet. if (!$chk_patch && !$is_patch) { exit(0); diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 5fd4a64e431f..f95c6bfa8b8e 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -2046,9 +2046,6 @@ fail2: return error; } - -#define list_entry_is_head(pos, head, member) (&pos->member == (head)) - /** * __next_ns - find the next namespace to list * @root: root namespace to stop search at (NOT NULL) diff --git a/tools/testing/selftests/lkdtm/tests.txt b/tools/testing/selftests/lkdtm/tests.txt index 74a8d329a72c..92ba4cc41314 100644 --- a/tools/testing/selftests/lkdtm/tests.txt +++ b/tools/testing/selftests/lkdtm/tests.txt @@ -68,3 +68,4 @@ USERCOPY_STACK_BEYOND USERCOPY_KERNEL STACKLEAK_ERASING OK: the rest of the thread stack is properly erased CFI_FORWARD_PROTO +FORTIFIED_STRSCPY |