Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'lkdtm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux into char-misc-testing

Kees writes:

Become maintainer, add hardening tests for use-after-free and atomic wrapping.

+399 -9
+4
Documentation/watchdog/watchdog-parameters.txt
··· 400 400 nowayout: Watchdog cannot be stopped once started 401 401 (default=kernel config parameter) 402 402 ------------------------------------------------- 403 + sun4v_wdt: 404 + timeout_ms: Watchdog timeout in milliseconds 1..180000, default=60000) 405 + nowayout: Watchdog cannot be stopped once started 406 + -------------------------------------------------
+5
MAINTAINERS
··· 6581 6581 L: live-patching@vger.kernel.org 6582 6582 T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching.git 6583 6583 6584 + LINUX KERNEL DUMP TEST MODULE (LKDTM) 6585 + M: Kees Cook <keescook@chromium.org> 6586 + S: Maintained 6587 + F: drivers/misc/lkdtm.c 6588 + 6584 6589 LLC (802.2) 6585 6590 M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net> 6586 6591 S: Maintained
+6
arch/sparc/Makefile
··· 24 24 export BITS := 32 25 25 UTS_MACHINE := sparc 26 26 27 + # We are adding -Wa,-Av8 to KBUILD_CFLAGS to deal with a specs bug in some 28 + # versions of gcc. Some gcc versions won't pass -Av8 to binutils when you 29 + # give -mcpu=v8. This silently worked with older bintutils versions but 30 + # does not any more. 27 31 KBUILD_CFLAGS += -m32 -mcpu=v8 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7 32 + KBUILD_CFLAGS += -Wa,-Av8 33 + 28 34 KBUILD_AFLAGS += -m32 -Wa,-Av8 29 35 30 36 else
+2 -1
arch/sparc/include/uapi/asm/unistd.h
··· 422 422 #define __NR_listen 354 423 423 #define __NR_setsockopt 355 424 424 #define __NR_mlock2 356 425 + #define __NR_copy_file_range 357 425 426 426 - #define NR_syscalls 357 427 + #define NR_syscalls 358 427 428 428 429 /* Bitmask values returned from kern_features system call. */ 429 430 #define KERN_FEATURE_MIXED_MODE_STACK 0x00000001
+17
arch/sparc/kernel/entry.S
··· 948 948 cmp %o0, 0 949 949 bne 3f 950 950 mov -ENOSYS, %o0 951 + 952 + /* Syscall tracing can modify the registers. */ 953 + ld [%sp + STACKFRAME_SZ + PT_G1], %g1 954 + sethi %hi(sys_call_table), %l7 955 + ld [%sp + STACKFRAME_SZ + PT_I0], %i0 956 + or %l7, %lo(sys_call_table), %l7 957 + ld [%sp + STACKFRAME_SZ + PT_I1], %i1 958 + ld [%sp + STACKFRAME_SZ + PT_I2], %i2 959 + ld [%sp + STACKFRAME_SZ + PT_I3], %i3 960 + ld [%sp + STACKFRAME_SZ + PT_I4], %i4 961 + ld [%sp + STACKFRAME_SZ + PT_I5], %i5 962 + cmp %g1, NR_syscalls 963 + bgeu 3f 964 + mov -ENOSYS, %o0 965 + 966 + sll %g1, 2, %l4 951 967 mov %i0, %o0 968 + ld [%l7 + %l4], %l7 952 969 mov %i1, %o1 953 970 mov %i2, %o2 954 971 mov %i3, %o3
+2 -1
arch/sparc/kernel/hvcalls.S
··· 338 338 mov %o1, %o4 339 339 mov HV_FAST_MACH_SET_WATCHDOG, %o5 340 340 ta HV_FAST_TRAP 341 + brnz,a,pn %o4, 0f 341 342 stx %o1, [%o4] 342 - retl 343 + 0: retl 343 344 nop 344 345 ENDPROC(sun4v_mach_set_watchdog) 345 346
+1 -1
arch/sparc/kernel/signal_64.c
··· 52 52 unsigned char fenab; 53 53 int err; 54 54 55 - flush_user_windows(); 55 + synchronize_user_stack(); 56 56 if (get_thread_wsaved() || 57 57 (((unsigned long)ucp) & (sizeof(unsigned long)-1)) || 58 58 (!__access_ok(ucp, sizeof(*ucp))))
+1
arch/sparc/kernel/sparc_ksyms_64.c
··· 37 37 EXPORT_SYMBOL(sun4v_niagara_setperf); 38 38 EXPORT_SYMBOL(sun4v_niagara2_getperf); 39 39 EXPORT_SYMBOL(sun4v_niagara2_setperf); 40 + EXPORT_SYMBOL(sun4v_mach_set_watchdog); 40 41 41 42 /* from hweight.S */ 42 43 EXPORT_SYMBOL(__arch_hweight8);
+36
arch/sparc/kernel/syscalls.S
··· 158 158 add %sp, PTREGS_OFF, %o0 159 159 brnz,pn %o0, 3f 160 160 mov -ENOSYS, %o0 161 + 162 + /* Syscall tracing can modify the registers. */ 163 + ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1 164 + sethi %hi(sys_call_table32), %l7 165 + ldx [%sp + PTREGS_OFF + PT_V9_I0], %i0 166 + or %l7, %lo(sys_call_table32), %l7 167 + ldx [%sp + PTREGS_OFF + PT_V9_I1], %i1 168 + ldx [%sp + PTREGS_OFF + PT_V9_I2], %i2 169 + ldx [%sp + PTREGS_OFF + PT_V9_I3], %i3 170 + ldx [%sp + PTREGS_OFF + PT_V9_I4], %i4 171 + ldx [%sp + PTREGS_OFF + PT_V9_I5], %i5 172 + 173 + cmp %g1, NR_syscalls 174 + bgeu,pn %xcc, 3f 175 + mov -ENOSYS, %o0 176 + 177 + sll %g1, 2, %l4 161 178 srl %i0, 0, %o0 179 + lduw [%l7 + %l4], %l7 162 180 srl %i4, 0, %o4 163 181 srl %i1, 0, %o1 164 182 srl %i2, 0, %o2 ··· 188 170 add %sp, PTREGS_OFF, %o0 189 171 brnz,pn %o0, 3f 190 172 mov -ENOSYS, %o0 173 + 174 + /* Syscall tracing can modify the registers. */ 175 + ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1 176 + sethi %hi(sys_call_table64), %l7 177 + ldx [%sp + PTREGS_OFF + PT_V9_I0], %i0 178 + or %l7, %lo(sys_call_table64), %l7 179 + ldx [%sp + PTREGS_OFF + PT_V9_I1], %i1 180 + ldx [%sp + PTREGS_OFF + PT_V9_I2], %i2 181 + ldx [%sp + PTREGS_OFF + PT_V9_I3], %i3 182 + ldx [%sp + PTREGS_OFF + PT_V9_I4], %i4 183 + ldx [%sp + PTREGS_OFF + PT_V9_I5], %i5 184 + 185 + cmp %g1, NR_syscalls 186 + bgeu,pn %xcc, 3f 187 + mov -ENOSYS, %o0 188 + 189 + sll %g1, 2, %l4 191 190 mov %i0, %o0 191 + lduw [%l7 + %l4], %l7 192 192 mov %i1, %o1 193 193 mov %i2, %o2 194 194 mov %i3, %o3
+1 -1
arch/sparc/kernel/systbls_32.S
··· 88 88 /*340*/ .long sys_ni_syscall, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr 89 89 /*345*/ .long sys_renameat2, sys_seccomp, sys_getrandom, sys_memfd_create, sys_bpf 90 90 /*350*/ .long sys_execveat, sys_membarrier, sys_userfaultfd, sys_bind, sys_listen 91 - /*355*/ .long sys_setsockopt, sys_mlock2 91 + /*355*/ .long sys_setsockopt, sys_mlock2, sys_copy_file_range
+2 -2
arch/sparc/kernel/systbls_64.S
··· 89 89 /*340*/ .word sys_kern_features, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr 90 90 .word sys32_renameat2, sys_seccomp, sys_getrandom, sys_memfd_create, sys_bpf 91 91 /*350*/ .word sys32_execveat, sys_membarrier, sys_userfaultfd, sys_bind, sys_listen 92 - .word compat_sys_setsockopt, sys_mlock2 92 + .word compat_sys_setsockopt, sys_mlock2, sys_copy_file_range 93 93 94 94 #endif /* CONFIG_COMPAT */ 95 95 ··· 170 170 /*340*/ .word sys_kern_features, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr 171 171 .word sys_renameat2, sys_seccomp, sys_getrandom, sys_memfd_create, sys_bpf 172 172 /*350*/ .word sys64_execveat, sys_membarrier, sys_userfaultfd, sys_bind, sys_listen 173 - .word sys_setsockopt, sys_mlock2 173 + .word sys_setsockopt, sys_mlock2, sys_copy_file_range
+119 -3
drivers/misc/lkdtm.c
··· 92 92 CT_UNALIGNED_LOAD_STORE_WRITE, 93 93 CT_OVERWRITE_ALLOCATION, 94 94 CT_WRITE_AFTER_FREE, 95 + CT_READ_AFTER_FREE, 96 + CT_WRITE_BUDDY_AFTER_FREE, 97 + CT_READ_BUDDY_AFTER_FREE, 95 98 CT_SOFTLOCKUP, 96 99 CT_HARDLOCKUP, 97 100 CT_SPINLOCKUP, ··· 107 104 CT_ACCESS_USERSPACE, 108 105 CT_WRITE_RO, 109 106 CT_WRITE_KERN, 107 + CT_WRAP_ATOMIC 110 108 }; 111 109 112 110 static char* cp_name[] = { ··· 133 129 "UNALIGNED_LOAD_STORE_WRITE", 134 130 "OVERWRITE_ALLOCATION", 135 131 "WRITE_AFTER_FREE", 132 + "READ_AFTER_FREE", 133 + "WRITE_BUDDY_AFTER_FREE", 134 + "READ_BUDDY_AFTER_FREE", 136 135 "SOFTLOCKUP", 137 136 "HARDLOCKUP", 138 137 "SPINLOCKUP", ··· 148 141 "ACCESS_USERSPACE", 149 142 "WRITE_RO", 150 143 "WRITE_KERN", 144 + "WRAP_ATOMIC" 151 145 }; 152 146 153 147 static struct jprobe lkdtm; ··· 417 409 break; 418 410 } 419 411 case CT_WRITE_AFTER_FREE: { 412 + int *base, *again; 420 413 size_t len = 1024; 421 - u32 *data = kmalloc(len, GFP_KERNEL); 414 + /* 415 + * The slub allocator uses the first word to store the free 416 + * pointer in some configurations. Use the middle of the 417 + * allocation to avoid running into the freelist 418 + */ 419 + size_t offset = (len / sizeof(*base)) / 2; 422 420 423 - kfree(data); 421 + base = kmalloc(len, GFP_KERNEL); 422 + pr_info("Allocated memory %p-%p\n", base, &base[offset * 2]); 423 + pr_info("Attempting bad write to freed memory at %p\n", 424 + &base[offset]); 425 + kfree(base); 426 + base[offset] = 0x0abcdef0; 427 + /* Attempt to notice the overwrite. */ 428 + again = kmalloc(len, GFP_KERNEL); 429 + kfree(again); 430 + if (again != base) 431 + pr_info("Hmm, didn't get the same memory range.\n"); 432 + 433 + break; 434 + } 435 + case CT_READ_AFTER_FREE: { 436 + int *base, *val, saw; 437 + size_t len = 1024; 438 + /* 439 + * The slub allocator uses the first word to store the free 440 + * pointer in some configurations. Use the middle of the 441 + * allocation to avoid running into the freelist 442 + */ 443 + size_t offset = (len / sizeof(*base)) / 2; 444 + 445 + base = kmalloc(len, GFP_KERNEL); 446 + if (!base) 447 + break; 448 + 449 + val = kmalloc(len, GFP_KERNEL); 450 + if (!val) 451 + break; 452 + 453 + *val = 0x12345678; 454 + base[offset] = *val; 455 + pr_info("Value in memory before free: %x\n", base[offset]); 456 + 457 + kfree(base); 458 + 459 + pr_info("Attempting bad read from freed memory\n"); 460 + saw = base[offset]; 461 + if (saw != *val) { 462 + /* Good! Poisoning happened, so declare a win. */ 463 + pr_info("Memory correctly poisoned (%x)\n", saw); 464 + BUG(); 465 + } 466 + pr_info("Memory was not poisoned\n"); 467 + 468 + kfree(val); 469 + break; 470 + } 471 + case CT_WRITE_BUDDY_AFTER_FREE: { 472 + unsigned long p = __get_free_page(GFP_KERNEL); 473 + if (!p) 474 + break; 475 + pr_info("Writing to the buddy page before free\n"); 476 + memset((void *)p, 0x3, PAGE_SIZE); 477 + free_page(p); 424 478 schedule(); 425 - memset(data, 0x78, len); 479 + pr_info("Attempting bad write to the buddy page after free\n"); 480 + memset((void *)p, 0x78, PAGE_SIZE); 481 + /* Attempt to notice the overwrite. */ 482 + p = __get_free_page(GFP_KERNEL); 483 + free_page(p); 484 + schedule(); 485 + 486 + break; 487 + } 488 + case CT_READ_BUDDY_AFTER_FREE: { 489 + unsigned long p = __get_free_page(GFP_KERNEL); 490 + int saw, *val = kmalloc(1024, GFP_KERNEL); 491 + int *base; 492 + 493 + if (!p) 494 + break; 495 + 496 + if (!val) 497 + break; 498 + 499 + base = (int *)p; 500 + 501 + *val = 0x12345678; 502 + base[0] = *val; 503 + pr_info("Value in memory before free: %x\n", base[0]); 504 + free_page(p); 505 + pr_info("Attempting to read from freed memory\n"); 506 + saw = base[0]; 507 + if (saw != *val) { 508 + /* Good! Poisoning happened, so declare a win. */ 509 + pr_info("Memory correctly poisoned (%x)\n", saw); 510 + BUG(); 511 + } 512 + pr_info("Buddy page was not poisoned\n"); 513 + 514 + kfree(val); 426 515 break; 427 516 } 428 517 case CT_SOFTLOCKUP: ··· 632 527 633 528 do_overwritten(); 634 529 break; 530 + } 531 + case CT_WRAP_ATOMIC: { 532 + atomic_t under = ATOMIC_INIT(INT_MIN); 533 + atomic_t over = ATOMIC_INIT(INT_MAX); 534 + 535 + pr_info("attempting atomic underflow\n"); 536 + atomic_dec(&under); 537 + pr_info("attempting atomic overflow\n"); 538 + atomic_inc(&over); 539 + 540 + return; 635 541 } 636 542 case CT_NONE: 637 543 default:
+11
drivers/watchdog/Kconfig
··· 1584 1584 machines. The watchdog timeout period is normally one minute but 1585 1585 can be changed with a boot-time parameter. 1586 1586 1587 + config WATCHDOG_SUN4V 1588 + tristate "Sun4v Watchdog support" 1589 + select WATCHDOG_CORE 1590 + depends on SPARC64 1591 + help 1592 + Say Y here to support the hypervisor watchdog capability embedded 1593 + in the SPARC sun4v architecture. 1594 + 1595 + To compile this driver as a module, choose M here. The module will 1596 + be called sun4v_wdt. 1597 + 1587 1598 # XTENSA Architecture 1588 1599 1589 1600 # Xen Architecture
+1
drivers/watchdog/Makefile
··· 180 180 181 181 obj-$(CONFIG_WATCHDOG_RIO) += riowd.o 182 182 obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwd.o 183 + obj-$(CONFIG_WATCHDOG_SUN4V) += sun4v_wdt.o 183 184 184 185 # XTENSA Architecture 185 186
+191
drivers/watchdog/sun4v_wdt.c
··· 1 + /* 2 + * sun4v watchdog timer 3 + * (c) Copyright 2016 Oracle Corporation 4 + * 5 + * Implement a simple watchdog driver using the built-in sun4v hypervisor 6 + * watchdog support. If time expires, the hypervisor stops or bounces 7 + * the guest domain. 8 + * 9 + * This program is free software; you can redistribute it and/or 10 + * modify it under the terms of the GNU General Public License 11 + * as published by the Free Software Foundation; either version 12 + * 2 of the License, or (at your option) any later version. 13 + */ 14 + 15 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 16 + 17 + #include <linux/errno.h> 18 + #include <linux/init.h> 19 + #include <linux/kernel.h> 20 + #include <linux/module.h> 21 + #include <linux/moduleparam.h> 22 + #include <linux/watchdog.h> 23 + #include <asm/hypervisor.h> 24 + #include <asm/mdesc.h> 25 + 26 + #define WDT_TIMEOUT 60 27 + #define WDT_MAX_TIMEOUT 31536000 28 + #define WDT_MIN_TIMEOUT 1 29 + #define WDT_DEFAULT_RESOLUTION_MS 1000 /* 1 second */ 30 + 31 + static unsigned int timeout; 32 + module_param(timeout, uint, 0); 33 + MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=" 34 + __MODULE_STRING(WDT_TIMEOUT) ")"); 35 + 36 + static bool nowayout = WATCHDOG_NOWAYOUT; 37 + module_param(nowayout, bool, S_IRUGO); 38 + MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" 39 + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 40 + 41 + static int sun4v_wdt_stop(struct watchdog_device *wdd) 42 + { 43 + sun4v_mach_set_watchdog(0, NULL); 44 + 45 + return 0; 46 + } 47 + 48 + static int sun4v_wdt_ping(struct watchdog_device *wdd) 49 + { 50 + int hverr; 51 + 52 + /* 53 + * HV watchdog timer will round up the timeout 54 + * passed in to the nearest multiple of the 55 + * watchdog resolution in milliseconds. 56 + */ 57 + hverr = sun4v_mach_set_watchdog(wdd->timeout * 1000, NULL); 58 + if (hverr == HV_EINVAL) 59 + return -EINVAL; 60 + 61 + return 0; 62 + } 63 + 64 + static int sun4v_wdt_set_timeout(struct watchdog_device *wdd, 65 + unsigned int timeout) 66 + { 67 + wdd->timeout = timeout; 68 + 69 + return 0; 70 + } 71 + 72 + static const struct watchdog_info sun4v_wdt_ident = { 73 + .options = WDIOF_SETTIMEOUT | 74 + WDIOF_MAGICCLOSE | 75 + WDIOF_KEEPALIVEPING, 76 + .identity = "sun4v hypervisor watchdog", 77 + .firmware_version = 0, 78 + }; 79 + 80 + static struct watchdog_ops sun4v_wdt_ops = { 81 + .owner = THIS_MODULE, 82 + .start = sun4v_wdt_ping, 83 + .stop = sun4v_wdt_stop, 84 + .ping = sun4v_wdt_ping, 85 + .set_timeout = sun4v_wdt_set_timeout, 86 + }; 87 + 88 + static struct watchdog_device wdd = { 89 + .info = &sun4v_wdt_ident, 90 + .ops = &sun4v_wdt_ops, 91 + .min_timeout = WDT_MIN_TIMEOUT, 92 + .max_timeout = WDT_MAX_TIMEOUT, 93 + .timeout = WDT_TIMEOUT, 94 + }; 95 + 96 + static int __init sun4v_wdt_init(void) 97 + { 98 + struct mdesc_handle *handle; 99 + u64 node; 100 + const u64 *value; 101 + int err = 0; 102 + unsigned long major = 1, minor = 1; 103 + 104 + /* 105 + * There are 2 properties that can be set from the control 106 + * domain for the watchdog. 107 + * watchdog-resolution 108 + * watchdog-max-timeout 109 + * 110 + * We can expect a handle to be returned otherwise something 111 + * serious is wrong. Correct to return -ENODEV here. 112 + */ 113 + 114 + handle = mdesc_grab(); 115 + if (!handle) 116 + return -ENODEV; 117 + 118 + node = mdesc_node_by_name(handle, MDESC_NODE_NULL, "platform"); 119 + err = -ENODEV; 120 + if (node == MDESC_NODE_NULL) 121 + goto out_release; 122 + 123 + /* 124 + * This is a safe way to validate if we are on the right 125 + * platform. 126 + */ 127 + if (sun4v_hvapi_register(HV_GRP_CORE, major, &minor)) 128 + goto out_hv_unreg; 129 + 130 + /* Allow value of watchdog-resolution up to 1s (default) */ 131 + value = mdesc_get_property(handle, node, "watchdog-resolution", NULL); 132 + err = -EINVAL; 133 + if (value) { 134 + if (*value == 0 || 135 + *value > WDT_DEFAULT_RESOLUTION_MS) 136 + goto out_hv_unreg; 137 + } 138 + 139 + value = mdesc_get_property(handle, node, "watchdog-max-timeout", NULL); 140 + if (value) { 141 + /* 142 + * If the property value (in ms) is smaller than 143 + * min_timeout, return -EINVAL. 144 + */ 145 + if (*value < wdd.min_timeout * 1000) 146 + goto out_hv_unreg; 147 + 148 + /* 149 + * If the property value is smaller than 150 + * default max_timeout then set watchdog max_timeout to 151 + * the value of the property in seconds. 152 + */ 153 + if (*value < wdd.max_timeout * 1000) 154 + wdd.max_timeout = *value / 1000; 155 + } 156 + 157 + watchdog_init_timeout(&wdd, timeout, NULL); 158 + 159 + watchdog_set_nowayout(&wdd, nowayout); 160 + 161 + err = watchdog_register_device(&wdd); 162 + if (err) 163 + goto out_hv_unreg; 164 + 165 + pr_info("initialized (timeout=%ds, nowayout=%d)\n", 166 + wdd.timeout, nowayout); 167 + 168 + mdesc_release(handle); 169 + 170 + return 0; 171 + 172 + out_hv_unreg: 173 + sun4v_hvapi_unregister(HV_GRP_CORE); 174 + 175 + out_release: 176 + mdesc_release(handle); 177 + return err; 178 + } 179 + 180 + static void __exit sun4v_wdt_exit(void) 181 + { 182 + sun4v_hvapi_unregister(HV_GRP_CORE); 183 + watchdog_unregister_device(&wdd); 184 + } 185 + 186 + module_init(sun4v_wdt_init); 187 + module_exit(sun4v_wdt_exit); 188 + 189 + MODULE_AUTHOR("Wim Coekaerts <wim.coekaerts@oracle.com>"); 190 + MODULE_DESCRIPTION("sun4v watchdog driver"); 191 + MODULE_LICENSE("GPL");