1ad4240feSJulian Elischer /*- 251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 351369649SPedro F. Giffuni * 4ad4240feSJulian Elischer * Copyright (c) 1986, 1988, 1991, 1993 5ad4240feSJulian Elischer * The Regents of the University of California. All rights reserved. 6ad4240feSJulian Elischer * (c) UNIX System Laboratories, Inc. 7ad4240feSJulian Elischer * All or some portions of this file are derived from material licensed 8ad4240feSJulian Elischer * to the University of California by American Telephone and Telegraph 9ad4240feSJulian Elischer * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10ad4240feSJulian Elischer * the permission of UNIX System Laboratories, Inc. 11ad4240feSJulian Elischer * 12ad4240feSJulian Elischer * Redistribution and use in source and binary forms, with or without 13ad4240feSJulian Elischer * modification, are permitted provided that the following conditions 14ad4240feSJulian Elischer * are met: 15ad4240feSJulian Elischer * 1. Redistributions of source code must retain the above copyright 16ad4240feSJulian Elischer * notice, this list of conditions and the following disclaimer. 17ad4240feSJulian Elischer * 2. Redistributions in binary form must reproduce the above copyright 18ad4240feSJulian Elischer * notice, this list of conditions and the following disclaimer in the 19ad4240feSJulian Elischer * documentation and/or other materials provided with the distribution. 2069a28758SEd Maste * 3. Neither the name of the University nor the names of its contributors 21ad4240feSJulian Elischer * may be used to endorse or promote products derived from this software 22ad4240feSJulian Elischer * without specific prior written permission. 23ad4240feSJulian Elischer * 24ad4240feSJulian Elischer * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25ad4240feSJulian Elischer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26ad4240feSJulian Elischer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27ad4240feSJulian Elischer * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28ad4240feSJulian Elischer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29ad4240feSJulian Elischer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30ad4240feSJulian Elischer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31ad4240feSJulian Elischer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32ad4240feSJulian Elischer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33ad4240feSJulian Elischer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34ad4240feSJulian Elischer * SUCH DAMAGE. 35ad4240feSJulian Elischer * 36ad4240feSJulian Elischer * @(#)kern_shutdown.c 8.3 (Berkeley) 1/21/94 37ad4240feSJulian Elischer */ 38ad4240feSJulian Elischer 39677b542eSDavid E. O'Brien #include <sys/cdefs.h> 40677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 41677b542eSDavid E. O'Brien 42618c7db3SRobert Watson #include "opt_ddb.h" 43480f31c2SKonrad Witaszczyk #include "opt_ekcd.h" 442d50560aSMarcel Moolenaar #include "opt_kdb.h" 456d58e6cbSBruce Evans #include "opt_panic.h" 466b6e2954SConrad Meyer #include "opt_printf.h" 479923b511SScott Long #include "opt_sched.h" 482be767e0SAttilio Rao #include "opt_watchdog.h" 49ad4240feSJulian Elischer 50ad4240feSJulian Elischer #include <sys/param.h> 51ad4240feSJulian Elischer #include <sys/systm.h> 529626b608SPoul-Henning Kamp #include <sys/bio.h> 53fc8f7066SBruce Evans #include <sys/buf.h> 541d79f1bbSJohn Baldwin #include <sys/conf.h> 5578f57a9cSMark Johnston #include <sys/compressor.h> 561d79f1bbSJohn Baldwin #include <sys/cons.h> 576b6e2954SConrad Meyer #include <sys/disk.h> 581d79f1bbSJohn Baldwin #include <sys/eventhandler.h> 590d3d0cc3SEdward Tomasz Napierala #include <sys/filedesc.h> 6076ca6f88SJamie Gritton #include <sys/jail.h> 612d50560aSMarcel Moolenaar #include <sys/kdb.h> 62ad4240feSJulian Elischer #include <sys/kernel.h> 63e6592ee5SPeter Wemm #include <sys/kerneldump.h> 645e950839SLuoqi Chen #include <sys/kthread.h> 653945a964SAlfred Perlstein #include <sys/ktr.h> 66dcd7d9b7SMaxim Sobolev #include <sys/malloc.h> 67bd92e6b6SMark Johnston #include <sys/mbuf.h> 68ac0ad63fSBruce Evans #include <sys/mount.h> 69acd3428bSRobert Watson #include <sys/priv.h> 701d79f1bbSJohn Baldwin #include <sys/proc.h> 711d79f1bbSJohn Baldwin #include <sys/reboot.h> 721d79f1bbSJohn Baldwin #include <sys/resourcevar.h> 7389f6b863SAttilio Rao #include <sys/rwlock.h> 746b6e2954SConrad Meyer #include <sys/sbuf.h> 7520e25d7dSPeter Wemm #include <sys/sched.h> 76248bb937SAttilio Rao #include <sys/smp.h> 77ad4240feSJulian Elischer #include <sys/sysctl.h> 78ad4240feSJulian Elischer #include <sys/sysproto.h> 79c3982007SKonstantin Belousov #include <sys/taskqueue.h> 80fa2b39a1SAttilio Rao #include <sys/vnode.h> 812be767e0SAttilio Rao #include <sys/watchdog.h> 82ad4240feSJulian Elischer 8382985292SConrad Meyer #include <crypto/chacha20/chacha.h> 84480f31c2SKonrad Witaszczyk #include <crypto/rijndael/rijndael-api-fst.h> 85480f31c2SKonrad Witaszczyk #include <crypto/sha2/sha256.h> 86480f31c2SKonrad Witaszczyk 87618c7db3SRobert Watson #include <ddb/ddb.h> 88618c7db3SRobert Watson 8926502503SMarcel Moolenaar #include <machine/cpu.h> 90bdb9ab0dSMark Johnston #include <machine/dump.h> 91d39e457bSPoul-Henning Kamp #include <machine/pcb.h> 92752dff3dSJake Burkholder #include <machine/smp.h> 93ad4240feSJulian Elischer 94aed55708SRobert Watson #include <security/mac/mac_framework.h> 95aed55708SRobert Watson 960909f38aSPawel Jakub Dawidek #include <vm/vm.h> 970909f38aSPawel Jakub Dawidek #include <vm/vm_object.h> 980909f38aSPawel Jakub Dawidek #include <vm/vm_page.h> 990909f38aSPawel Jakub Dawidek #include <vm/vm_pager.h> 1000909f38aSPawel Jakub Dawidek #include <vm/swap_pager.h> 1010909f38aSPawel Jakub Dawidek 102ad4240feSJulian Elischer #include <sys/signalvar.h> 103ad4240feSJulian Elischer 1045dc5dab6SConrad Meyer static MALLOC_DEFINE(M_DUMPER, "dumper", "dumper block buffer"); 1055dc5dab6SConrad Meyer 106ad4240feSJulian Elischer #ifndef PANIC_REBOOT_WAIT_TIME 107ad4240feSJulian Elischer #define PANIC_REBOOT_WAIT_TIME 15 /* default to 15 seconds */ 108ad4240feSJulian Elischer #endif 1093b251028SColin Percival static int panic_reboot_wait_time = PANIC_REBOOT_WAIT_TIME; 110af3b2549SHans Petter Selasky SYSCTL_INT(_kern, OID_AUTO, panic_reboot_wait_time, CTLFLAG_RWTUN, 1111cdbb9edSColin Percival &panic_reboot_wait_time, 0, 1121cdbb9edSColin Percival "Seconds to wait before rebooting after a panic"); 113ad4240feSJulian Elischer 114ad4240feSJulian Elischer /* 115ad4240feSJulian Elischer * Note that stdarg.h and the ANSI style va_start macro is used for both 116ad4240feSJulian Elischer * ANSI and traditional C compilers. 117ad4240feSJulian Elischer */ 118ad4240feSJulian Elischer #include <machine/stdarg.h> 119ad4240feSJulian Elischer 1202d50560aSMarcel Moolenaar #ifdef KDB 1212d50560aSMarcel Moolenaar #ifdef KDB_UNATTENDED 122b317cfd4SJohn Baldwin static int debugger_on_panic = 0; 123ad4240feSJulian Elischer #else 124b317cfd4SJohn Baldwin static int debugger_on_panic = 1; 125ad4240feSJulian Elischer #endif 1263d7618d8SDavid E. O'Brien SYSCTL_INT(_debug, OID_AUTO, debugger_on_panic, 127af3b2549SHans Petter Selasky CTLFLAG_RWTUN | CTLFLAG_SECURE, 1281c5151f3SDavid E. O'Brien &debugger_on_panic, 0, "Run debugger on kernel panic"); 129e485b64bSJohn Baldwin 130b317cfd4SJohn Baldwin int debugger_on_trap = 0; 131b317cfd4SJohn Baldwin SYSCTL_INT(_debug, OID_AUTO, debugger_on_trap, 132b317cfd4SJohn Baldwin CTLFLAG_RWTUN | CTLFLAG_SECURE, 133b317cfd4SJohn Baldwin &debugger_on_trap, 0, "Run debugger on kernel trap before panic"); 134b317cfd4SJohn Baldwin 1352d50560aSMarcel Moolenaar #ifdef KDB_TRACE 13608a9c205SAndriy Gapon static int trace_on_panic = 1; 137ad1fc315SConrad Meyer static bool trace_all_panics = true; 138e485b64bSJohn Baldwin #else 13908a9c205SAndriy Gapon static int trace_on_panic = 0; 140ad1fc315SConrad Meyer static bool trace_all_panics = false; 141e485b64bSJohn Baldwin #endif 1423d7618d8SDavid E. O'Brien SYSCTL_INT(_debug, OID_AUTO, trace_on_panic, 143af3b2549SHans Petter Selasky CTLFLAG_RWTUN | CTLFLAG_SECURE, 1441c5151f3SDavid E. O'Brien &trace_on_panic, 0, "Print stack trace on kernel panic"); 145ad1fc315SConrad Meyer SYSCTL_BOOL(_debug, OID_AUTO, trace_all_panics, CTLFLAG_RWTUN, 146ad1fc315SConrad Meyer &trace_all_panics, 0, "Print stack traces on secondary kernel panics"); 1472d50560aSMarcel Moolenaar #endif /* KDB */ 148ad4240feSJulian Elischer 14908a9c205SAndriy Gapon static int sync_on_panic = 0; 150af3b2549SHans Petter Selasky SYSCTL_INT(_kern, OID_AUTO, sync_on_panic, CTLFLAG_RWTUN, 151259ed917SPeter Wemm &sync_on_panic, 0, "Do a sync before rebooting from a panic"); 152259ed917SPeter Wemm 15348f1a492SWarner Losh static bool poweroff_on_panic = 0; 15448f1a492SWarner Losh SYSCTL_BOOL(_kern, OID_AUTO, poweroff_on_panic, CTLFLAG_RWTUN, 15548f1a492SWarner Losh &poweroff_on_panic, 0, "Do a power off instead of a reboot on a panic"); 15648f1a492SWarner Losh 15748f1a492SWarner Losh static bool powercycle_on_panic = 0; 15848f1a492SWarner Losh SYSCTL_BOOL(_kern, OID_AUTO, powercycle_on_panic, CTLFLAG_RWTUN, 15948f1a492SWarner Losh &powercycle_on_panic, 0, "Do a power cycle instead of a reboot on a panic"); 16048f1a492SWarner Losh 161*7029da5cSPawel Biernacki static SYSCTL_NODE(_kern, OID_AUTO, shutdown, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 1626472ac3dSEd Schouten "Shutdown environment"); 163db82a982SMike Smith 164fa2b39a1SAttilio Rao #ifndef DIAGNOSTIC 165fa2b39a1SAttilio Rao static int show_busybufs; 166fa2b39a1SAttilio Rao #else 167fa2b39a1SAttilio Rao static int show_busybufs = 1; 168fa2b39a1SAttilio Rao #endif 169fa2b39a1SAttilio Rao SYSCTL_INT(_kern_shutdown, OID_AUTO, show_busybufs, CTLFLAG_RW, 170fa2b39a1SAttilio Rao &show_busybufs, 0, ""); 171fa2b39a1SAttilio Rao 1722eb0015aSColin Percival int suspend_blocked = 0; 1732eb0015aSColin Percival SYSCTL_INT(_kern, OID_AUTO, suspend_blocked, CTLFLAG_RW, 1742eb0015aSColin Percival &suspend_blocked, 0, "Block suspend due to a pending shutdown"); 1752eb0015aSColin Percival 176480f31c2SKonrad Witaszczyk #ifdef EKCD 177480f31c2SKonrad Witaszczyk FEATURE(ekcd, "Encrypted kernel crash dumps support"); 178480f31c2SKonrad Witaszczyk 179480f31c2SKonrad Witaszczyk MALLOC_DEFINE(M_EKCD, "ekcd", "Encrypted kernel crash dumps data"); 180480f31c2SKonrad Witaszczyk 181480f31c2SKonrad Witaszczyk struct kerneldumpcrypto { 182480f31c2SKonrad Witaszczyk uint8_t kdc_encryption; 183480f31c2SKonrad Witaszczyk uint8_t kdc_iv[KERNELDUMP_IV_MAX_SIZE]; 18482985292SConrad Meyer union { 18582985292SConrad Meyer struct { 18682985292SConrad Meyer keyInstance aes_ki; 18782985292SConrad Meyer cipherInstance aes_ci; 18882985292SConrad Meyer } u_aes; 18982985292SConrad Meyer struct chacha_ctx u_chacha; 19082985292SConrad Meyer } u; 19182985292SConrad Meyer #define kdc_ki u.u_aes.aes_ki 19282985292SConrad Meyer #define kdc_ci u.u_aes.aes_ci 19382985292SConrad Meyer #define kdc_chacha u.u_chacha 194480f31c2SKonrad Witaszczyk uint32_t kdc_dumpkeysize; 195480f31c2SKonrad Witaszczyk struct kerneldumpkey kdc_dumpkey[]; 196480f31c2SKonrad Witaszczyk }; 197480f31c2SKonrad Witaszczyk #endif 198480f31c2SKonrad Witaszczyk 19978f57a9cSMark Johnston struct kerneldumpcomp { 2006026dcd7SMark Johnston uint8_t kdc_format; 20178f57a9cSMark Johnston struct compressor *kdc_stream; 20278f57a9cSMark Johnston uint8_t *kdc_buf; 20378f57a9cSMark Johnston size_t kdc_resid; 20464a16434SMark Johnston }; 20564a16434SMark Johnston 20678f57a9cSMark Johnston static struct kerneldumpcomp *kerneldumpcomp_create(struct dumperinfo *di, 20764a16434SMark Johnston uint8_t compression); 20878f57a9cSMark Johnston static void kerneldumpcomp_destroy(struct dumperinfo *di); 20978f57a9cSMark Johnston static int kerneldumpcomp_write_cb(void *base, size_t len, off_t off, void *arg); 21064a16434SMark Johnston 21164a16434SMark Johnston static int kerneldump_gzlevel = 6; 21264a16434SMark Johnston SYSCTL_INT(_kern, OID_AUTO, kerneldump_gzlevel, CTLFLAG_RWTUN, 21364a16434SMark Johnston &kerneldump_gzlevel, 0, 21478f57a9cSMark Johnston "Kernel crash dump compression level"); 21564a16434SMark Johnston 2165230cfd2SJulian Elischer /* 217ad4240feSJulian Elischer * Variable panicstr contains argument to first call to panic; used as flag 218ad4240feSJulian Elischer * to indicate that the kernel has already called panic. 219ad4240feSJulian Elischer */ 220d199ad3bSMateusz Guzik const char *panicstr; 221d199ad3bSMateusz Guzik bool __read_frequently panicked; 222ad4240feSJulian Elischer 22361322a0aSAlexander Motin int __read_mostly dumping; /* system is dumping */ 22436a52c3cSJeff Roberson int rebooting; /* system is rebooting */ 2256b6e2954SConrad Meyer /* 2266b6e2954SConrad Meyer * Used to serialize between sysctl kern.shutdown.dumpdevname and list 2276b6e2954SConrad Meyer * modifications via ioctl. 2286b6e2954SConrad Meyer */ 2296b6e2954SConrad Meyer static struct mtx dumpconf_list_lk; 2306b6e2954SConrad Meyer MTX_SYSINIT(dumper_configs, &dumpconf_list_lk, "dumper config list", MTX_DEF); 2316b6e2954SConrad Meyer 2326b6e2954SConrad Meyer /* Our selected dumper(s). */ 2336b6e2954SConrad Meyer static TAILQ_HEAD(dumpconflist, dumperinfo) dumper_configs = 2346b6e2954SConrad Meyer TAILQ_HEAD_INITIALIZER(dumper_configs); 2352d50560aSMarcel Moolenaar 2362d50560aSMarcel Moolenaar /* Context information for dump-debuggers. */ 2372d50560aSMarcel Moolenaar static struct pcb dumppcb; /* Registers. */ 238ac6e25ecSHartmut Brandt lwpid_t dumptid; /* Thread ID. */ 23916a011f9SPaul Saab 2400d3d0cc3SEdward Tomasz Napierala static struct cdevsw reroot_cdevsw = { 2410d3d0cc3SEdward Tomasz Napierala .d_version = D_VERSION, 2420d3d0cc3SEdward Tomasz Napierala .d_name = "reroot", 2430d3d0cc3SEdward Tomasz Napierala }; 2440d3d0cc3SEdward Tomasz Napierala 24582acbcf5SPeter Wemm static void poweroff_wait(void *, int); 24682acbcf5SPeter Wemm static void shutdown_halt(void *junk, int howto); 24782acbcf5SPeter Wemm static void shutdown_panic(void *junk, int howto); 24882acbcf5SPeter Wemm static void shutdown_reset(void *junk, int howto); 2490d3d0cc3SEdward Tomasz Napierala static int kern_reroot(void); 250f06a54f0SPoul-Henning Kamp 251fcb893a8SMike Smith /* register various local shutdown events */ 252fcb893a8SMike Smith static void 253fcb893a8SMike Smith shutdown_conf(void *unused) 254fcb893a8SMike Smith { 255e95499bdSAlfred Perlstein 256e95499bdSAlfred Perlstein EVENTHANDLER_REGISTER(shutdown_final, poweroff_wait, NULL, 257fd104c15SRebecca Cran SHUTDOWN_PRI_FIRST); 258e95499bdSAlfred Perlstein EVENTHANDLER_REGISTER(shutdown_final, shutdown_halt, NULL, 259e95499bdSAlfred Perlstein SHUTDOWN_PRI_LAST + 100); 260e95499bdSAlfred Perlstein EVENTHANDLER_REGISTER(shutdown_final, shutdown_panic, NULL, 261e95499bdSAlfred Perlstein SHUTDOWN_PRI_LAST + 100); 262e95499bdSAlfred Perlstein EVENTHANDLER_REGISTER(shutdown_final, shutdown_reset, NULL, 263e95499bdSAlfred Perlstein SHUTDOWN_PRI_LAST + 200); 264fcb893a8SMike Smith } 265ad4240feSJulian Elischer 266237fdd78SRobert Watson SYSINIT(shutdown_conf, SI_SUB_INTRINSIC, SI_ORDER_ANY, shutdown_conf, NULL); 267fcb893a8SMike Smith 268ad4240feSJulian Elischer /* 2690d3d0cc3SEdward Tomasz Napierala * The only reason this exists is to create the /dev/reroot/ directory, 2700d3d0cc3SEdward Tomasz Napierala * used by reroot code in init(8) as a mountpoint for tmpfs. 2710d3d0cc3SEdward Tomasz Napierala */ 2720d3d0cc3SEdward Tomasz Napierala static void 2730d3d0cc3SEdward Tomasz Napierala reroot_conf(void *unused) 2740d3d0cc3SEdward Tomasz Napierala { 2750d3d0cc3SEdward Tomasz Napierala int error; 2760d3d0cc3SEdward Tomasz Napierala struct cdev *cdev; 2770d3d0cc3SEdward Tomasz Napierala 2780d3d0cc3SEdward Tomasz Napierala error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK, &cdev, 2790d3d0cc3SEdward Tomasz Napierala &reroot_cdevsw, NULL, UID_ROOT, GID_WHEEL, 0600, "reroot/reroot"); 2800d3d0cc3SEdward Tomasz Napierala if (error != 0) { 2810d3d0cc3SEdward Tomasz Napierala printf("%s: failed to create device node, error %d", 2820d3d0cc3SEdward Tomasz Napierala __func__, error); 2830d3d0cc3SEdward Tomasz Napierala } 2840d3d0cc3SEdward Tomasz Napierala } 2850d3d0cc3SEdward Tomasz Napierala 2860d3d0cc3SEdward Tomasz Napierala SYSINIT(reroot_conf, SI_SUB_DEVFS, SI_ORDER_ANY, reroot_conf, NULL); 2870d3d0cc3SEdward Tomasz Napierala 2880d3d0cc3SEdward Tomasz Napierala /* 2890c14ff0eSRobert Watson * The system call that results in a reboot. 290ad4240feSJulian Elischer */ 291835a82eeSMatthew Dillon /* ARGSUSED */ 292ad4240feSJulian Elischer int 2938451d0ddSKip Macy sys_reboot(struct thread *td, struct reboot_args *uap) 294ad4240feSJulian Elischer { 295ad4240feSJulian Elischer int error; 296ad4240feSJulian Elischer 297a2ecb9b7SRobert Watson error = 0; 298a2ecb9b7SRobert Watson #ifdef MAC 29930d239bcSRobert Watson error = mac_system_check_reboot(td->td_ucred, uap->opt); 300a2ecb9b7SRobert Watson #endif 301a2ecb9b7SRobert Watson if (error == 0) 302acd3428bSRobert Watson error = priv_check(td, PRIV_REBOOT); 303a2ecb9b7SRobert Watson if (error == 0) { 304d5292812SWarner Losh if (uap->opt & RB_REROOT) 3050d3d0cc3SEdward Tomasz Napierala error = kern_reroot(); 306d5292812SWarner Losh else 30776e18b25SMarcel Moolenaar kern_reboot(uap->opt); 3080d3d0cc3SEdward Tomasz Napierala } 309835a82eeSMatthew Dillon return (error); 310ad4240feSJulian Elischer } 311ad4240feSJulian Elischer 312c3982007SKonstantin Belousov static void 313c3982007SKonstantin Belousov shutdown_nice_task_fn(void *arg, int pending __unused) 314ad4240feSJulian Elischer { 315c3982007SKonstantin Belousov int howto; 316e95499bdSAlfred Perlstein 317c3982007SKonstantin Belousov howto = (uintptr_t)arg; 318912d5937SEd Schouten /* Send a signal to init(8) and have it shutdown the world. */ 31987729a2bSJohn Baldwin PROC_LOCK(initproc); 320912d5937SEd Schouten if (howto & RB_POWEROFF) 321912d5937SEd Schouten kern_psignal(initproc, SIGUSR2); 3227d41b6f0SWarner Losh else if (howto & RB_POWERCYCLE) 3237d41b6f0SWarner Losh kern_psignal(initproc, SIGWINCH); 324912d5937SEd Schouten else if (howto & RB_HALT) 325912d5937SEd Schouten kern_psignal(initproc, SIGUSR1); 326912d5937SEd Schouten else 3278451d0ddSKip Macy kern_psignal(initproc, SIGINT); 32887729a2bSJohn Baldwin PROC_UNLOCK(initproc); 329c3982007SKonstantin Belousov } 330c3982007SKonstantin Belousov 331c3982007SKonstantin Belousov static struct task shutdown_nice_task = TASK_INITIALIZER(0, 332c3982007SKonstantin Belousov &shutdown_nice_task_fn, NULL); 333c3982007SKonstantin Belousov 334c3982007SKonstantin Belousov /* 335c3982007SKonstantin Belousov * Called by events that want to shut down.. e.g <CTL><ALT><DEL> on a PC 336c3982007SKonstantin Belousov */ 337c3982007SKonstantin Belousov void 338c3982007SKonstantin Belousov shutdown_nice(int howto) 339c3982007SKonstantin Belousov { 340c3982007SKonstantin Belousov 341c3982007SKonstantin Belousov if (initproc != NULL && !SCHEDULER_STOPPED()) { 342c3982007SKonstantin Belousov shutdown_nice_task.ta_context = (void *)(uintptr_t)howto; 343c3982007SKonstantin Belousov taskqueue_enqueue(taskqueue_fast, &shutdown_nice_task); 344ad4240feSJulian Elischer } else { 345c3982007SKonstantin Belousov /* 346c3982007SKonstantin Belousov * No init(8) running, or scheduler would not allow it 347c3982007SKonstantin Belousov * to run, so simply reboot. 348c3982007SKonstantin Belousov */ 3498f5b107bSEd Schouten kern_reboot(howto | RB_NOSYNC); 350ad4240feSJulian Elischer } 351ad4240feSJulian Elischer } 352ad4240feSJulian Elischer 35372dfe7a3SPoul-Henning Kamp static void 35482acbcf5SPeter Wemm print_uptime(void) 35572dfe7a3SPoul-Henning Kamp { 35672dfe7a3SPoul-Henning Kamp int f; 35772dfe7a3SPoul-Henning Kamp struct timespec ts; 35872dfe7a3SPoul-Henning Kamp 35972dfe7a3SPoul-Henning Kamp getnanouptime(&ts); 36072dfe7a3SPoul-Henning Kamp printf("Uptime: "); 36172dfe7a3SPoul-Henning Kamp f = 0; 36272dfe7a3SPoul-Henning Kamp if (ts.tv_sec >= 86400) { 3634a6404dfSJohn Baldwin printf("%ldd", (long)ts.tv_sec / 86400); 36472dfe7a3SPoul-Henning Kamp ts.tv_sec %= 86400; 36572dfe7a3SPoul-Henning Kamp f = 1; 36672dfe7a3SPoul-Henning Kamp } 36772dfe7a3SPoul-Henning Kamp if (f || ts.tv_sec >= 3600) { 3684a6404dfSJohn Baldwin printf("%ldh", (long)ts.tv_sec / 3600); 36972dfe7a3SPoul-Henning Kamp ts.tv_sec %= 3600; 37072dfe7a3SPoul-Henning Kamp f = 1; 37172dfe7a3SPoul-Henning Kamp } 37272dfe7a3SPoul-Henning Kamp if (f || ts.tv_sec >= 60) { 3734a6404dfSJohn Baldwin printf("%ldm", (long)ts.tv_sec / 60); 37472dfe7a3SPoul-Henning Kamp ts.tv_sec %= 60; 37572dfe7a3SPoul-Henning Kamp f = 1; 37672dfe7a3SPoul-Henning Kamp } 3774a6404dfSJohn Baldwin printf("%lds\n", (long)ts.tv_sec); 37872dfe7a3SPoul-Henning Kamp } 37972dfe7a3SPoul-Henning Kamp 380299cceefSMarcel Moolenaar int 381299cceefSMarcel Moolenaar doadump(boolean_t textdump) 382d39e457bSPoul-Henning Kamp { 383299cceefSMarcel Moolenaar boolean_t coredump; 384f6b4f5caSGavin Atkinson int error; 385e95499bdSAlfred Perlstein 386f6b4f5caSGavin Atkinson error = 0; 387299cceefSMarcel Moolenaar if (dumping) 388299cceefSMarcel Moolenaar return (EBUSY); 3896b6e2954SConrad Meyer if (TAILQ_EMPTY(&dumper_configs)) 390299cceefSMarcel Moolenaar return (ENXIO); 391f6449d9dSJulian Elischer 392d39e457bSPoul-Henning Kamp savectx(&dumppcb); 3932d50560aSMarcel Moolenaar dumptid = curthread->td_tid; 394d39e457bSPoul-Henning Kamp dumping++; 395299cceefSMarcel Moolenaar 396299cceefSMarcel Moolenaar coredump = TRUE; 397618c7db3SRobert Watson #ifdef DDB 398299cceefSMarcel Moolenaar if (textdump && textdump_pending) { 399299cceefSMarcel Moolenaar coredump = FALSE; 4006b6e2954SConrad Meyer textdump_dumpsys(TAILQ_FIRST(&dumper_configs)); 401299cceefSMarcel Moolenaar } 402618c7db3SRobert Watson #endif 4036b6e2954SConrad Meyer if (coredump) { 4046b6e2954SConrad Meyer struct dumperinfo *di; 4056b6e2954SConrad Meyer 4066b6e2954SConrad Meyer TAILQ_FOREACH(di, &dumper_configs, di_next) { 4076b6e2954SConrad Meyer error = dumpsys(di); 4086b6e2954SConrad Meyer if (error == 0) 4096b6e2954SConrad Meyer break; 4106b6e2954SConrad Meyer } 4116b6e2954SConrad Meyer } 412299cceefSMarcel Moolenaar 4139e473363SRuslan Ermilov dumping--; 414f6b4f5caSGavin Atkinson return (error); 415d39e457bSPoul-Henning Kamp } 416d39e457bSPoul-Henning Kamp 417ad4240feSJulian Elischer /* 41870ce93f4SNate Lawson * Shutdown the system cleanly to prepare for reboot, halt, or power off. 419ad4240feSJulian Elischer */ 42076e18b25SMarcel Moolenaar void 42176e18b25SMarcel Moolenaar kern_reboot(int howto) 422ad4240feSJulian Elischer { 42398082691SJeff Roberson static int once = 0; 424ad4240feSJulian Elischer 425f0d847afSWarner Losh /* 426f0d847afSWarner Losh * Normal paths here don't hold Giant, but we can wind up here 427f0d847afSWarner Losh * unexpectedly with it held. Drop it now so we don't have to 428f0d847afSWarner Losh * drop and pick it up elsewhere. The paths it is locking will 429f0d847afSWarner Losh * never be returned to, and it is preferable to preclude 430f0d847afSWarner Losh * deadlock than to lock against code that won't ever 431f0d847afSWarner Losh * continue. 432f0d847afSWarner Losh */ 433f0d847afSWarner Losh while (mtx_owned(&Giant)) 434f0d847afSWarner Losh mtx_unlock(&Giant); 435f0d847afSWarner Losh 436f7ebc7ceSMarcel Moolenaar #if defined(SMP) 43770ce93f4SNate Lawson /* 438efe67753SNathan Whitehorn * Bind us to the first CPU so that all shutdown code runs there. Some 43970ce93f4SNate Lawson * systems don't shutdown properly (i.e., ACPI power off) if we 44070ce93f4SNate Lawson * run on another processor. 44170ce93f4SNate Lawson */ 44235370593SAndriy Gapon if (!SCHEDULER_STOPPED()) { 443982d11f8SJeff Roberson thread_lock(curthread); 444efe67753SNathan Whitehorn sched_bind(curthread, CPU_FIRST()); 445982d11f8SJeff Roberson thread_unlock(curthread); 446efe67753SNathan Whitehorn KASSERT(PCPU_GET(cpuid) == CPU_FIRST(), 447efe67753SNathan Whitehorn ("boot: not running on cpu 0")); 44835370593SAndriy Gapon } 44920e25d7dSPeter Wemm #endif 45036a52c3cSJeff Roberson /* We're in the process of rebooting. */ 45136a52c3cSJeff Roberson rebooting = 1; 45220e25d7dSPeter Wemm 45361e96500SJohn Baldwin /* We are out of the debugger now. */ 4542d50560aSMarcel Moolenaar kdb_active = 0; 45561e96500SJohn Baldwin 4565230cfd2SJulian Elischer /* 4575230cfd2SJulian Elischer * Do any callouts that should be done BEFORE syncing the filesystems. 4585230cfd2SJulian Elischer */ 459fcb893a8SMike Smith EVENTHANDLER_INVOKE(shutdown_pre_sync, howto); 4605230cfd2SJulian Elischer 4615230cfd2SJulian Elischer /* 4625230cfd2SJulian Elischer * Now sync filesystems 4635230cfd2SJulian Elischer */ 46498082691SJeff Roberson if (!cold && (howto & RB_NOSYNC) == 0 && once == 0) { 46598082691SJeff Roberson once = 1; 46698082691SJeff Roberson bufshutdown(show_busybufs); 467ad4240feSJulian Elischer } 4685230cfd2SJulian Elischer 46972dfe7a3SPoul-Henning Kamp print_uptime(); 47072dfe7a3SPoul-Henning Kamp 471bf8696b4SAndriy Gapon cngrab(); 472bf8696b4SAndriy Gapon 4735230cfd2SJulian Elischer /* 4745230cfd2SJulian Elischer * Ok, now do things that assume all filesystem activity has 4755230cfd2SJulian Elischer * been completed. 4765230cfd2SJulian Elischer */ 477fcb893a8SMike Smith EVENTHANDLER_INVOKE(shutdown_post_sync, howto); 47870ce93f4SNate Lawson 479f6449d9dSJulian Elischer if ((howto & (RB_HALT|RB_DUMP)) == RB_DUMP && !cold && !dumping) 480299cceefSMarcel Moolenaar doadump(TRUE); 4812cfa0a03SJustin T. Gibbs 4822cfa0a03SJustin T. Gibbs /* Now that we're going to really halt the system... */ 483fcb893a8SMike Smith EVENTHANDLER_INVOKE(shutdown_final, howto); 4842cfa0a03SJustin T. Gibbs 485fcb893a8SMike Smith for(;;) ; /* safety against shutdown_reset not working */ 486fcb893a8SMike Smith /* NOTREACHED */ 487fcb893a8SMike Smith } 488fcb893a8SMike Smith 489fcb893a8SMike Smith /* 4900d3d0cc3SEdward Tomasz Napierala * The system call that results in changing the rootfs. 4910d3d0cc3SEdward Tomasz Napierala */ 4920d3d0cc3SEdward Tomasz Napierala static int 4930d3d0cc3SEdward Tomasz Napierala kern_reroot(void) 4940d3d0cc3SEdward Tomasz Napierala { 4950d3d0cc3SEdward Tomasz Napierala struct vnode *oldrootvnode, *vp; 4960d3d0cc3SEdward Tomasz Napierala struct mount *mp, *devmp; 4970d3d0cc3SEdward Tomasz Napierala int error; 4980d3d0cc3SEdward Tomasz Napierala 4990d3d0cc3SEdward Tomasz Napierala if (curproc != initproc) 5000d3d0cc3SEdward Tomasz Napierala return (EPERM); 5010d3d0cc3SEdward Tomasz Napierala 5020d3d0cc3SEdward Tomasz Napierala /* 5030d3d0cc3SEdward Tomasz Napierala * Mark the filesystem containing currently-running executable 5040d3d0cc3SEdward Tomasz Napierala * (the temporary copy of init(8)) busy. 5050d3d0cc3SEdward Tomasz Napierala */ 5060d3d0cc3SEdward Tomasz Napierala vp = curproc->p_textvp; 5070d3d0cc3SEdward Tomasz Napierala error = vn_lock(vp, LK_SHARED); 5080d3d0cc3SEdward Tomasz Napierala if (error != 0) 5090d3d0cc3SEdward Tomasz Napierala return (error); 5100d3d0cc3SEdward Tomasz Napierala mp = vp->v_mount; 5110d3d0cc3SEdward Tomasz Napierala error = vfs_busy(mp, MBF_NOWAIT); 5120d3d0cc3SEdward Tomasz Napierala if (error != 0) { 5130d3d0cc3SEdward Tomasz Napierala vfs_ref(mp); 514b249ce48SMateusz Guzik VOP_UNLOCK(vp); 5150d3d0cc3SEdward Tomasz Napierala error = vfs_busy(mp, 0); 5160d3d0cc3SEdward Tomasz Napierala vn_lock(vp, LK_SHARED | LK_RETRY); 5170d3d0cc3SEdward Tomasz Napierala vfs_rel(mp); 5180d3d0cc3SEdward Tomasz Napierala if (error != 0) { 519b249ce48SMateusz Guzik VOP_UNLOCK(vp); 5200d3d0cc3SEdward Tomasz Napierala return (ENOENT); 5210d3d0cc3SEdward Tomasz Napierala } 522abd80ddbSMateusz Guzik if (VN_IS_DOOMED(vp)) { 523b249ce48SMateusz Guzik VOP_UNLOCK(vp); 5240d3d0cc3SEdward Tomasz Napierala vfs_unbusy(mp); 5250d3d0cc3SEdward Tomasz Napierala return (ENOENT); 5260d3d0cc3SEdward Tomasz Napierala } 5270d3d0cc3SEdward Tomasz Napierala } 528b249ce48SMateusz Guzik VOP_UNLOCK(vp); 5290d3d0cc3SEdward Tomasz Napierala 5300d3d0cc3SEdward Tomasz Napierala /* 5310d3d0cc3SEdward Tomasz Napierala * Remove the filesystem containing currently-running executable 5320d3d0cc3SEdward Tomasz Napierala * from the mount list, to prevent it from being unmounted 5330d3d0cc3SEdward Tomasz Napierala * by vfs_unmountall(), and to avoid confusing vfs_mountroot(). 5340d3d0cc3SEdward Tomasz Napierala * 5350d3d0cc3SEdward Tomasz Napierala * Also preserve /dev - forcibly unmounting it could cause driver 5360d3d0cc3SEdward Tomasz Napierala * reinitialization. 5370d3d0cc3SEdward Tomasz Napierala */ 5380d3d0cc3SEdward Tomasz Napierala 5390d3d0cc3SEdward Tomasz Napierala vfs_ref(rootdevmp); 5400d3d0cc3SEdward Tomasz Napierala devmp = rootdevmp; 5410d3d0cc3SEdward Tomasz Napierala rootdevmp = NULL; 5420d3d0cc3SEdward Tomasz Napierala 5430d3d0cc3SEdward Tomasz Napierala mtx_lock(&mountlist_mtx); 5440d3d0cc3SEdward Tomasz Napierala TAILQ_REMOVE(&mountlist, mp, mnt_list); 5450d3d0cc3SEdward Tomasz Napierala TAILQ_REMOVE(&mountlist, devmp, mnt_list); 5460d3d0cc3SEdward Tomasz Napierala mtx_unlock(&mountlist_mtx); 5470d3d0cc3SEdward Tomasz Napierala 5480d3d0cc3SEdward Tomasz Napierala oldrootvnode = rootvnode; 5490d3d0cc3SEdward Tomasz Napierala 5500d3d0cc3SEdward Tomasz Napierala /* 5510d3d0cc3SEdward Tomasz Napierala * Unmount everything except for the two filesystems preserved above. 5520d3d0cc3SEdward Tomasz Napierala */ 5530d3d0cc3SEdward Tomasz Napierala vfs_unmountall(); 5540d3d0cc3SEdward Tomasz Napierala 5550d3d0cc3SEdward Tomasz Napierala /* 5560d3d0cc3SEdward Tomasz Napierala * Add /dev back; vfs_mountroot() will move it into its new place. 5570d3d0cc3SEdward Tomasz Napierala */ 5580d3d0cc3SEdward Tomasz Napierala mtx_lock(&mountlist_mtx); 5590d3d0cc3SEdward Tomasz Napierala TAILQ_INSERT_HEAD(&mountlist, devmp, mnt_list); 5600d3d0cc3SEdward Tomasz Napierala mtx_unlock(&mountlist_mtx); 5610d3d0cc3SEdward Tomasz Napierala rootdevmp = devmp; 5620d3d0cc3SEdward Tomasz Napierala vfs_rel(rootdevmp); 5630d3d0cc3SEdward Tomasz Napierala 5640d3d0cc3SEdward Tomasz Napierala /* 5650d3d0cc3SEdward Tomasz Napierala * Mount the new rootfs. 5660d3d0cc3SEdward Tomasz Napierala */ 5670d3d0cc3SEdward Tomasz Napierala vfs_mountroot(); 5680d3d0cc3SEdward Tomasz Napierala 5690d3d0cc3SEdward Tomasz Napierala /* 5700d3d0cc3SEdward Tomasz Napierala * Update all references to the old rootvnode. 5710d3d0cc3SEdward Tomasz Napierala */ 5720d3d0cc3SEdward Tomasz Napierala mountcheckdirs(oldrootvnode, rootvnode); 5730d3d0cc3SEdward Tomasz Napierala 5740d3d0cc3SEdward Tomasz Napierala /* 5750d3d0cc3SEdward Tomasz Napierala * Add the temporary filesystem back and unbusy it. 5760d3d0cc3SEdward Tomasz Napierala */ 5770d3d0cc3SEdward Tomasz Napierala mtx_lock(&mountlist_mtx); 5780d3d0cc3SEdward Tomasz Napierala TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); 5790d3d0cc3SEdward Tomasz Napierala mtx_unlock(&mountlist_mtx); 5800d3d0cc3SEdward Tomasz Napierala vfs_unbusy(mp); 5810d3d0cc3SEdward Tomasz Napierala 5820d3d0cc3SEdward Tomasz Napierala return (0); 5830d3d0cc3SEdward Tomasz Napierala } 5840d3d0cc3SEdward Tomasz Napierala 5850d3d0cc3SEdward Tomasz Napierala /* 586fcb893a8SMike Smith * If the shutdown was a clean halt, behave accordingly. 587fcb893a8SMike Smith */ 588fcb893a8SMike Smith static void 589fcb893a8SMike Smith shutdown_halt(void *junk, int howto) 590fcb893a8SMike Smith { 591e95499bdSAlfred Perlstein 592ad4240feSJulian Elischer if (howto & RB_HALT) { 593ad4240feSJulian Elischer printf("\n"); 594ad4240feSJulian Elischer printf("The operating system has halted.\n"); 595ad4240feSJulian Elischer printf("Please press any key to reboot.\n\n"); 596387df3b8SAndriy Gapon 597387df3b8SAndriy Gapon wdog_kern_pat(WD_TO_NEVER); 598387df3b8SAndriy Gapon 599d13d3630SJulian Elischer switch (cngetc()) { 600d13d3630SJulian Elischer case -1: /* No console, just die */ 601d13d3630SJulian Elischer cpu_halt(); 602d13d3630SJulian Elischer /* NOTREACHED */ 603d13d3630SJulian Elischer default: 604d13d3630SJulian Elischer break; 605d13d3630SJulian Elischer } 606fcb893a8SMike Smith } 607fcb893a8SMike Smith } 608ad4240feSJulian Elischer 609fcb893a8SMike Smith /* 610fcb893a8SMike Smith * Check to see if the system paniced, pause and then reboot 611fcb893a8SMike Smith * according to the specified delay. 612fcb893a8SMike Smith */ 613fcb893a8SMike Smith static void 614fcb893a8SMike Smith shutdown_panic(void *junk, int howto) 615fcb893a8SMike Smith { 616fcb893a8SMike Smith int loop; 617fcb893a8SMike Smith 618fcb893a8SMike Smith if (howto & RB_DUMP) { 6191cdbb9edSColin Percival if (panic_reboot_wait_time != 0) { 6201cdbb9edSColin Percival if (panic_reboot_wait_time != -1) { 6212cfa0a03SJustin T. Gibbs printf("Automatic reboot in %d seconds - " 6222cfa0a03SJustin T. Gibbs "press a key on the console to abort\n", 6231cdbb9edSColin Percival panic_reboot_wait_time); 6241cdbb9edSColin Percival for (loop = panic_reboot_wait_time * 10; 6252cfa0a03SJustin T. Gibbs loop > 0; --loop) { 626ad4240feSJulian Elischer DELAY(1000 * 100); /* 1/10th second */ 627a7f8f2abSBruce Evans /* Did user type a key? */ 628a7f8f2abSBruce Evans if (cncheckc() != -1) 629ad4240feSJulian Elischer break; 630ad4240feSJulian Elischer } 631ad4240feSJulian Elischer if (!loop) 632fcb893a8SMike Smith return; 633ad4240feSJulian Elischer } 634ad4240feSJulian Elischer } else { /* zero time specified - reboot NOW */ 635fcb893a8SMike Smith return; 636ad4240feSJulian Elischer } 637422702e9SNik Clayton printf("--> Press a key on the console to reboot,\n"); 638422702e9SNik Clayton printf("--> or switch off the system now.\n"); 639ad4240feSJulian Elischer cngetc(); 640ad4240feSJulian Elischer } 641fcb893a8SMike Smith } 642fcb893a8SMike Smith 643fcb893a8SMike Smith /* 644fcb893a8SMike Smith * Everything done, now reset 645fcb893a8SMike Smith */ 646fcb893a8SMike Smith static void 647fcb893a8SMike Smith shutdown_reset(void *junk, int howto) 648fcb893a8SMike Smith { 649e95499bdSAlfred Perlstein 650ad4240feSJulian Elischer printf("Rebooting...\n"); 651ad4240feSJulian Elischer DELAY(1000000); /* wait 1 sec for printf's to complete and be read */ 652248bb937SAttilio Rao 653248bb937SAttilio Rao /* 654248bb937SAttilio Rao * Acquiring smp_ipi_mtx here has a double effect: 655248bb937SAttilio Rao * - it disables interrupts avoiding CPU0 preemption 656248bb937SAttilio Rao * by fast handlers (thus deadlocking against other CPUs) 657248bb937SAttilio Rao * - it avoids deadlocks against smp_rendezvous() or, more 658248bb937SAttilio Rao * generally, threads busy-waiting, with this spinlock held, 659248bb937SAttilio Rao * and waiting for responses by threads on other CPUs 660248bb937SAttilio Rao * (ie. smp_tlb_shootdown()). 6610a2d5feaSAttilio Rao * 6620a2d5feaSAttilio Rao * For the !SMP case it just needs to handle the former problem. 663248bb937SAttilio Rao */ 6640a2d5feaSAttilio Rao #ifdef SMP 665248bb937SAttilio Rao mtx_lock_spin(&smp_ipi_mtx); 6660a2d5feaSAttilio Rao #else 6670a2d5feaSAttilio Rao spinlock_enter(); 6680a2d5feaSAttilio Rao #endif 669248bb937SAttilio Rao 670269fb9d7SJulian Elischer /* cpu_boot(howto); */ /* doesn't do anything at the moment */ 671ad4240feSJulian Elischer cpu_reset(); 672fcb893a8SMike Smith /* NOTREACHED */ /* assuming reset worked */ 673ad4240feSJulian Elischer } 674ad4240feSJulian Elischer 675a0d20ecbSGleb Smirnoff #if defined(WITNESS) || defined(INVARIANT_SUPPORT) 6763945a964SAlfred Perlstein static int kassert_warn_only = 0; 677a94053baSAlfred Perlstein #ifdef KDB 678a94053baSAlfred Perlstein static int kassert_do_kdb = 0; 679a94053baSAlfred Perlstein #endif 6803945a964SAlfred Perlstein #ifdef KTR 6813945a964SAlfred Perlstein static int kassert_do_ktr = 0; 6823945a964SAlfred Perlstein #endif 6833945a964SAlfred Perlstein static int kassert_do_log = 1; 6843945a964SAlfred Perlstein static int kassert_log_pps_limit = 4; 6853945a964SAlfred Perlstein static int kassert_log_mute_at = 0; 6863945a964SAlfred Perlstein static int kassert_log_panic_at = 0; 68718959b69SJonathan T. Looney static int kassert_suppress_in_panic = 0; 6883945a964SAlfred Perlstein static int kassert_warnings = 0; 6893945a964SAlfred Perlstein 690*7029da5cSPawel Biernacki SYSCTL_NODE(_debug, OID_AUTO, kassert, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 691*7029da5cSPawel Biernacki "kassert options"); 6923945a964SAlfred Perlstein 6934ca8c1efSConrad Meyer #ifdef KASSERT_PANIC_OPTIONAL 6944ca8c1efSConrad Meyer #define KASSERT_RWTUN CTLFLAG_RWTUN 6954ca8c1efSConrad Meyer #else 6964ca8c1efSConrad Meyer #define KASSERT_RWTUN CTLFLAG_RDTUN 6974ca8c1efSConrad Meyer #endif 6984ca8c1efSConrad Meyer 6994ca8c1efSConrad Meyer SYSCTL_INT(_debug_kassert, OID_AUTO, warn_only, KASSERT_RWTUN, 7003945a964SAlfred Perlstein &kassert_warn_only, 0, 7014ca8c1efSConrad Meyer "KASSERT triggers a panic (0) or just a warning (1)"); 7023945a964SAlfred Perlstein 703a94053baSAlfred Perlstein #ifdef KDB 7044ca8c1efSConrad Meyer SYSCTL_INT(_debug_kassert, OID_AUTO, do_kdb, KASSERT_RWTUN, 705a94053baSAlfred Perlstein &kassert_do_kdb, 0, "KASSERT will enter the debugger"); 706a94053baSAlfred Perlstein #endif 707a94053baSAlfred Perlstein 7083945a964SAlfred Perlstein #ifdef KTR 7094ca8c1efSConrad Meyer SYSCTL_UINT(_debug_kassert, OID_AUTO, do_ktr, KASSERT_RWTUN, 7103945a964SAlfred Perlstein &kassert_do_ktr, 0, 7113945a964SAlfred Perlstein "KASSERT does a KTR, set this to the KTRMASK you want"); 7123945a964SAlfred Perlstein #endif 7133945a964SAlfred Perlstein 7144ca8c1efSConrad Meyer SYSCTL_INT(_debug_kassert, OID_AUTO, do_log, KASSERT_RWTUN, 71507aa6ea6SConrad Meyer &kassert_do_log, 0, 71607aa6ea6SConrad Meyer "If warn_only is enabled, log (1) or do not log (0) assertion violations"); 7173945a964SAlfred Perlstein 7183ad1ce46SAndriy Gapon SYSCTL_INT(_debug_kassert, OID_AUTO, warnings, CTLFLAG_RD | CTLFLAG_STATS, 7193945a964SAlfred Perlstein &kassert_warnings, 0, "number of KASSERTs that have been triggered"); 7203945a964SAlfred Perlstein 7214ca8c1efSConrad Meyer SYSCTL_INT(_debug_kassert, OID_AUTO, log_panic_at, KASSERT_RWTUN, 7223945a964SAlfred Perlstein &kassert_log_panic_at, 0, "max number of KASSERTS before we will panic"); 7233945a964SAlfred Perlstein 7244ca8c1efSConrad Meyer SYSCTL_INT(_debug_kassert, OID_AUTO, log_pps_limit, KASSERT_RWTUN, 7253945a964SAlfred Perlstein &kassert_log_pps_limit, 0, "limit number of log messages per second"); 7263945a964SAlfred Perlstein 7274ca8c1efSConrad Meyer SYSCTL_INT(_debug_kassert, OID_AUTO, log_mute_at, KASSERT_RWTUN, 7283945a964SAlfred Perlstein &kassert_log_mute_at, 0, "max number of KASSERTS to log"); 7293945a964SAlfred Perlstein 7304ca8c1efSConrad Meyer SYSCTL_INT(_debug_kassert, OID_AUTO, suppress_in_panic, KASSERT_RWTUN, 73144b71282SJonathan T. Looney &kassert_suppress_in_panic, 0, 73244b71282SJonathan T. Looney "KASSERTs will be suppressed while handling a panic"); 7334ca8c1efSConrad Meyer #undef KASSERT_RWTUN 73444b71282SJonathan T. Looney 7353945a964SAlfred Perlstein static int kassert_sysctl_kassert(SYSCTL_HANDLER_ARGS); 7363945a964SAlfred Perlstein 7373945a964SAlfred Perlstein SYSCTL_PROC(_debug_kassert, OID_AUTO, kassert, 738*7029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE | CTLFLAG_NEEDGIANT, NULL, 0, 739*7029da5cSPawel Biernacki kassert_sysctl_kassert, "I", 740*7029da5cSPawel Biernacki "set to trigger a test kassert"); 7413945a964SAlfred Perlstein 7423945a964SAlfred Perlstein static int 7433945a964SAlfred Perlstein kassert_sysctl_kassert(SYSCTL_HANDLER_ARGS) 7443945a964SAlfred Perlstein { 7453945a964SAlfred Perlstein int error, i; 7463945a964SAlfred Perlstein 7473945a964SAlfred Perlstein error = sysctl_wire_old_buffer(req, sizeof(int)); 7483945a964SAlfred Perlstein if (error == 0) { 7493945a964SAlfred Perlstein i = 0; 7503945a964SAlfred Perlstein error = sysctl_handle_int(oidp, &i, 0, req); 7513945a964SAlfred Perlstein } 7523945a964SAlfred Perlstein if (error != 0 || req->newptr == NULL) 7533945a964SAlfred Perlstein return (error); 7543945a964SAlfred Perlstein KASSERT(0, ("kassert_sysctl_kassert triggered kassert %d", i)); 7553945a964SAlfred Perlstein return (0); 7563945a964SAlfred Perlstein } 7573945a964SAlfred Perlstein 7584ca8c1efSConrad Meyer #ifdef KASSERT_PANIC_OPTIONAL 7593945a964SAlfred Perlstein /* 7603945a964SAlfred Perlstein * Called by KASSERT, this decides if we will panic 7613945a964SAlfred Perlstein * or if we will log via printf and/or ktr. 7623945a964SAlfred Perlstein */ 7633945a964SAlfred Perlstein void 7643945a964SAlfred Perlstein kassert_panic(const char *fmt, ...) 7653945a964SAlfred Perlstein { 7663945a964SAlfred Perlstein static char buf[256]; 7673945a964SAlfred Perlstein va_list ap; 7683945a964SAlfred Perlstein 7693945a964SAlfred Perlstein va_start(ap, fmt); 7703945a964SAlfred Perlstein (void)vsnprintf(buf, sizeof(buf), fmt, ap); 7713945a964SAlfred Perlstein va_end(ap); 7723945a964SAlfred Perlstein 7733945a964SAlfred Perlstein /* 77465df1248SConrad Meyer * If we are suppressing secondary panics, log the warning but do not 77565df1248SConrad Meyer * re-enter panic/kdb. 77665df1248SConrad Meyer */ 77765df1248SConrad Meyer if (panicstr != NULL && kassert_suppress_in_panic) { 77865df1248SConrad Meyer if (kassert_do_log) { 77965df1248SConrad Meyer printf("KASSERT failed: %s\n", buf); 78065df1248SConrad Meyer #ifdef KDB 78165df1248SConrad Meyer if (trace_all_panics && trace_on_panic) 78265df1248SConrad Meyer kdb_backtrace(); 78365df1248SConrad Meyer #endif 78465df1248SConrad Meyer } 78565df1248SConrad Meyer return; 78665df1248SConrad Meyer } 78765df1248SConrad Meyer 78865df1248SConrad Meyer /* 7893945a964SAlfred Perlstein * panic if we're not just warning, or if we've exceeded 7903945a964SAlfred Perlstein * kassert_log_panic_at warnings. 7913945a964SAlfred Perlstein */ 7923945a964SAlfred Perlstein if (!kassert_warn_only || 7933945a964SAlfred Perlstein (kassert_log_panic_at > 0 && 7943945a964SAlfred Perlstein kassert_warnings >= kassert_log_panic_at)) { 7953945a964SAlfred Perlstein va_start(ap, fmt); 7963945a964SAlfred Perlstein vpanic(fmt, ap); 7973945a964SAlfred Perlstein /* NORETURN */ 7983945a964SAlfred Perlstein } 7993945a964SAlfred Perlstein #ifdef KTR 8003945a964SAlfred Perlstein if (kassert_do_ktr) 8013945a964SAlfred Perlstein CTR0(ktr_mask, buf); 8023945a964SAlfred Perlstein #endif /* KTR */ 8033945a964SAlfred Perlstein /* 8043945a964SAlfred Perlstein * log if we've not yet met the mute limit. 8053945a964SAlfred Perlstein */ 8063945a964SAlfred Perlstein if (kassert_do_log && 8073945a964SAlfred Perlstein (kassert_log_mute_at == 0 || 8083945a964SAlfred Perlstein kassert_warnings < kassert_log_mute_at)) { 8093945a964SAlfred Perlstein static struct timeval lasterr; 8103945a964SAlfred Perlstein static int curerr; 8113945a964SAlfred Perlstein 8123945a964SAlfred Perlstein if (ppsratecheck(&lasterr, &curerr, kassert_log_pps_limit)) { 8133945a964SAlfred Perlstein printf("KASSERT failed: %s\n", buf); 8143945a964SAlfred Perlstein kdb_backtrace(); 8153945a964SAlfred Perlstein } 8163945a964SAlfred Perlstein } 817a94053baSAlfred Perlstein #ifdef KDB 818a94053baSAlfred Perlstein if (kassert_do_kdb) { 819a94053baSAlfred Perlstein kdb_enter(KDB_WHY_KASSERT, buf); 820a94053baSAlfred Perlstein } 821a94053baSAlfred Perlstein #endif 8223945a964SAlfred Perlstein atomic_add_int(&kassert_warnings, 1); 8233945a964SAlfred Perlstein } 8244ca8c1efSConrad Meyer #endif /* KASSERT_PANIC_OPTIONAL */ 8253945a964SAlfred Perlstein #endif 8263945a964SAlfred Perlstein 827ad4240feSJulian Elischer /* 828ad4240feSJulian Elischer * Panic is called on unresolvable fatal errors. It prints "panic: mesg", 829ad4240feSJulian Elischer * and then reboots. If we are called twice, then we avoid trying to sync 830ad4240feSJulian Elischer * the disks as this often leads to recursive panics. 831ad4240feSJulian Elischer */ 832ad4240feSJulian Elischer void 8339a6dc4b6SPoul-Henning Kamp panic(const char *fmt, ...) 834ad4240feSJulian Elischer { 8353945a964SAlfred Perlstein va_list ap; 8363945a964SAlfred Perlstein 8373945a964SAlfred Perlstein va_start(ap, fmt); 8383945a964SAlfred Perlstein vpanic(fmt, ap); 8393945a964SAlfred Perlstein } 8403945a964SAlfred Perlstein 841da10a603SMark Johnston void 8423945a964SAlfred Perlstein vpanic(const char *fmt, va_list ap) 8433945a964SAlfred Perlstein { 84464dd590eSAndriy Gapon #ifdef SMP 84535370593SAndriy Gapon cpuset_t other_cpus; 84664dd590eSAndriy Gapon #endif 847fe799533SAndrew Gallatin struct thread *td = curthread; 848e485b64bSJohn Baldwin int bootopt, newpanic; 84999237364SAndrey A. Chernov static char buf[256]; 850ad4240feSJulian Elischer 85135370593SAndriy Gapon spinlock_enter(); 85235370593SAndriy Gapon 8530384fff8SJason Evans #ifdef SMP 8541a5333c3SJohn Baldwin /* 8556898bee9SAndriy Gapon * stop_cpus_hard(other_cpus) should prevent multiple CPUs from 8566898bee9SAndriy Gapon * concurrently entering panic. Only the winner will proceed 8576898bee9SAndriy Gapon * further. 8581a5333c3SJohn Baldwin */ 85935370593SAndriy Gapon if (panicstr == NULL && !kdb_active) { 86035370593SAndriy Gapon other_cpus = all_cpus; 86135370593SAndriy Gapon CPU_CLR(PCPU_GET(cpuid), &other_cpus); 86235370593SAndriy Gapon stop_cpus_hard(other_cpus); 86335370593SAndriy Gapon } 86442d33c1fSMark Johnston #endif 86535370593SAndriy Gapon 86635370593SAndriy Gapon /* 8679ad64f27SMark Johnston * Ensure that the scheduler is stopped while panicking, even if panic 8689ad64f27SMark Johnston * has been entered from kdb. 86935370593SAndriy Gapon */ 8705d7380f8SAttilio Rao td->td_stopsched = 1; 8710384fff8SJason Evans 872e3adb685SAttilio Rao bootopt = RB_AUTOBOOT; 873e485b64bSJohn Baldwin newpanic = 0; 874ad4240feSJulian Elischer if (panicstr) 875ad4240feSJulian Elischer bootopt |= RB_NOSYNC; 876e485b64bSJohn Baldwin else { 877e3adb685SAttilio Rao bootopt |= RB_DUMP; 878ad4240feSJulian Elischer panicstr = fmt; 879d199ad3bSMateusz Guzik panicked = true; 880e485b64bSJohn Baldwin newpanic = 1; 881e485b64bSJohn Baldwin } 882ad4240feSJulian Elischer 8834f1b4577SIan Dowse if (newpanic) { 8842127f260SArchie Cobbs (void)vsnprintf(buf, sizeof(buf), fmt, ap); 88599237364SAndrey A. Chernov panicstr = buf; 886bf8696b4SAndriy Gapon cngrab(); 8879a6dc4b6SPoul-Henning Kamp printf("panic: %s\n", buf); 8884f1b4577SIan Dowse } else { 8894f1b4577SIan Dowse printf("panic: "); 8904f1b4577SIan Dowse vprintf(fmt, ap); 8919a6dc4b6SPoul-Henning Kamp printf("\n"); 8924f1b4577SIan Dowse } 89347d81897SSteve Passe #ifdef SMP 89455c45354SJohn Baldwin printf("cpuid = %d\n", PCPU_GET(cpuid)); 8952bcc63c5SJohn Baldwin #endif 8966cf0c1dbSGleb Smirnoff printf("time = %jd\n", (intmax_t )time_second); 8972d50560aSMarcel Moolenaar #ifdef KDB 898ad1fc315SConrad Meyer if ((newpanic || trace_all_panics) && trace_on_panic) 8992d50560aSMarcel Moolenaar kdb_backtrace(); 900ad4240feSJulian Elischer if (debugger_on_panic) 9013de213ccSRobert Watson kdb_enter(KDB_WHY_PANIC, "panic"); 9021432aa0cSJohn Baldwin #endif 903982d11f8SJeff Roberson /*thread_lock(td); */ 904fe799533SAndrew Gallatin td->td_flags |= TDF_INPANIC; 905982d11f8SJeff Roberson /* thread_unlock(td); */ 906259ed917SPeter Wemm if (!sync_on_panic) 907259ed917SPeter Wemm bootopt |= RB_NOSYNC; 90848f1a492SWarner Losh if (poweroff_on_panic) 90948f1a492SWarner Losh bootopt |= RB_POWEROFF; 91048f1a492SWarner Losh if (powercycle_on_panic) 91148f1a492SWarner Losh bootopt |= RB_POWERCYCLE; 91276e18b25SMarcel Moolenaar kern_reboot(bootopt); 913ad4240feSJulian Elischer } 914ad4240feSJulian Elischer 915e0d898b4SJulian Elischer /* 916db82a982SMike Smith * Support for poweroff delay. 917b22692bdSNick Hibma * 918b22692bdSNick Hibma * Please note that setting this delay too short might power off your machine 919b22692bdSNick Hibma * before the write cache on your hard disk has been flushed, leading to 920b22692bdSNick Hibma * soft-updates inconsistencies. 921db82a982SMike Smith */ 9229eec6969SMike Smith #ifndef POWEROFF_DELAY 9239eec6969SMike Smith # define POWEROFF_DELAY 5000 9249eec6969SMike Smith #endif 9259eec6969SMike Smith static int poweroff_delay = POWEROFF_DELAY; 9269eec6969SMike Smith 927db82a982SMike Smith SYSCTL_INT(_kern_shutdown, OID_AUTO, poweroff_delay, CTLFLAG_RW, 9283eb9ab52SEitan Adler &poweroff_delay, 0, "Delay before poweroff to write disk caches (msec)"); 929db82a982SMike Smith 930fcb893a8SMike Smith static void 931fcb893a8SMike Smith poweroff_wait(void *junk, int howto) 932db82a982SMike Smith { 933e95499bdSAlfred Perlstein 9347d41b6f0SWarner Losh if ((howto & (RB_POWEROFF | RB_POWERCYCLE)) == 0 || poweroff_delay <= 0) 935db82a982SMike Smith return; 936db82a982SMike Smith DELAY(poweroff_delay * 1000); 937db82a982SMike Smith } 9385e950839SLuoqi Chen 9395e950839SLuoqi Chen /* 9405e950839SLuoqi Chen * Some system processes (e.g. syncer) need to be stopped at appropriate 9415e950839SLuoqi Chen * points in their main loops prior to a system shutdown, so that they 9425e950839SLuoqi Chen * won't interfere with the shutdown process (e.g. by holding a disk buf 9435e950839SLuoqi Chen * to cause sync to fail). For each of these system processes, register 9445e950839SLuoqi Chen * shutdown_kproc() as a handler for one of shutdown events. 9455e950839SLuoqi Chen */ 9465e950839SLuoqi Chen static int kproc_shutdown_wait = 60; 9475e950839SLuoqi Chen SYSCTL_INT(_kern_shutdown, OID_AUTO, kproc_shutdown_wait, CTLFLAG_RW, 9483eb9ab52SEitan Adler &kproc_shutdown_wait, 0, "Max wait time (sec) to stop for each process"); 9495e950839SLuoqi Chen 9505e950839SLuoqi Chen void 951ffc831daSJohn Baldwin kproc_shutdown(void *arg, int howto) 9525e950839SLuoqi Chen { 9535e950839SLuoqi Chen struct proc *p; 9545e950839SLuoqi Chen int error; 9555e950839SLuoqi Chen 9565e950839SLuoqi Chen if (panicstr) 9575e950839SLuoqi Chen return; 9585e950839SLuoqi Chen 9595e950839SLuoqi Chen p = (struct proc *)arg; 960b1c81391SNate Lawson printf("Waiting (max %d seconds) for system process `%s' to stop... ", 9614f9d48e4SJohn Baldwin kproc_shutdown_wait, p->p_comm); 9623745c395SJulian Elischer error = kproc_suspend(p, kproc_shutdown_wait * hz); 9635e950839SLuoqi Chen 9645e950839SLuoqi Chen if (error == EWOULDBLOCK) 965b1c81391SNate Lawson printf("timed out\n"); 9665e950839SLuoqi Chen else 967b1c81391SNate Lawson printf("done\n"); 9685e950839SLuoqi Chen } 96981661c94SPoul-Henning Kamp 9707ab24ea3SJulian Elischer void 9717ab24ea3SJulian Elischer kthread_shutdown(void *arg, int howto) 9727ab24ea3SJulian Elischer { 9737ab24ea3SJulian Elischer struct thread *td; 9747ab24ea3SJulian Elischer int error; 9757ab24ea3SJulian Elischer 9767ab24ea3SJulian Elischer if (panicstr) 9777ab24ea3SJulian Elischer return; 9787ab24ea3SJulian Elischer 9797ab24ea3SJulian Elischer td = (struct thread *)arg; 9807ab24ea3SJulian Elischer printf("Waiting (max %d seconds) for system thread `%s' to stop... ", 9814f9d48e4SJohn Baldwin kproc_shutdown_wait, td->td_name); 9827ab24ea3SJulian Elischer error = kthread_suspend(td, kproc_shutdown_wait * hz); 9837ab24ea3SJulian Elischer 9847ab24ea3SJulian Elischer if (error == EWOULDBLOCK) 9857ab24ea3SJulian Elischer printf("timed out\n"); 9867ab24ea3SJulian Elischer else 9877ab24ea3SJulian Elischer printf("done\n"); 9887ab24ea3SJulian Elischer } 9897ab24ea3SJulian Elischer 9906b6e2954SConrad Meyer static int 9916b6e2954SConrad Meyer dumpdevname_sysctl_handler(SYSCTL_HANDLER_ARGS) 9926b6e2954SConrad Meyer { 9936b6e2954SConrad Meyer char buf[256]; 9946b6e2954SConrad Meyer struct dumperinfo *di; 9956b6e2954SConrad Meyer struct sbuf sb; 9966b6e2954SConrad Meyer int error; 9976b6e2954SConrad Meyer 9986b6e2954SConrad Meyer error = sysctl_wire_old_buffer(req, 0); 9996b6e2954SConrad Meyer if (error != 0) 10006b6e2954SConrad Meyer return (error); 10016b6e2954SConrad Meyer 10026b6e2954SConrad Meyer sbuf_new_for_sysctl(&sb, buf, sizeof(buf), req); 10036b6e2954SConrad Meyer 10046b6e2954SConrad Meyer mtx_lock(&dumpconf_list_lk); 10056b6e2954SConrad Meyer TAILQ_FOREACH(di, &dumper_configs, di_next) { 10066b6e2954SConrad Meyer if (di != TAILQ_FIRST(&dumper_configs)) 10076b6e2954SConrad Meyer sbuf_putc(&sb, ','); 10086b6e2954SConrad Meyer sbuf_cat(&sb, di->di_devname); 10096b6e2954SConrad Meyer } 10106b6e2954SConrad Meyer mtx_unlock(&dumpconf_list_lk); 10116b6e2954SConrad Meyer 10126b6e2954SConrad Meyer error = sbuf_finish(&sb); 10136b6e2954SConrad Meyer sbuf_delete(&sb); 10146b6e2954SConrad Meyer return (error); 10156b6e2954SConrad Meyer } 1016*7029da5cSPawel Biernacki SYSCTL_PROC(_kern_shutdown, OID_AUTO, dumpdevname, 1017*7029da5cSPawel Biernacki CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, &dumper_configs, 0, 1018*7029da5cSPawel Biernacki dumpdevname_sysctl_handler, "A", 10196b6e2954SConrad Meyer "Device(s) for kernel dumps"); 1020bad7e7f3SAlfred Perlstein 102164a16434SMark Johnston static int _dump_append(struct dumperinfo *di, void *virtual, 102264a16434SMark Johnston vm_offset_t physical, size_t length); 102364a16434SMark Johnston 1024480f31c2SKonrad Witaszczyk #ifdef EKCD 1025480f31c2SKonrad Witaszczyk static struct kerneldumpcrypto * 1026480f31c2SKonrad Witaszczyk kerneldumpcrypto_create(size_t blocksize, uint8_t encryption, 1027480f31c2SKonrad Witaszczyk const uint8_t *key, uint32_t encryptedkeysize, const uint8_t *encryptedkey) 1028480f31c2SKonrad Witaszczyk { 1029480f31c2SKonrad Witaszczyk struct kerneldumpcrypto *kdc; 1030480f31c2SKonrad Witaszczyk struct kerneldumpkey *kdk; 1031480f31c2SKonrad Witaszczyk uint32_t dumpkeysize; 1032480f31c2SKonrad Witaszczyk 1033480f31c2SKonrad Witaszczyk dumpkeysize = roundup2(sizeof(*kdk) + encryptedkeysize, blocksize); 1034480f31c2SKonrad Witaszczyk kdc = malloc(sizeof(*kdc) + dumpkeysize, M_EKCD, M_WAITOK | M_ZERO); 1035480f31c2SKonrad Witaszczyk 1036480f31c2SKonrad Witaszczyk arc4rand(kdc->kdc_iv, sizeof(kdc->kdc_iv), 0); 1037480f31c2SKonrad Witaszczyk 1038480f31c2SKonrad Witaszczyk kdc->kdc_encryption = encryption; 1039480f31c2SKonrad Witaszczyk switch (kdc->kdc_encryption) { 1040480f31c2SKonrad Witaszczyk case KERNELDUMP_ENC_AES_256_CBC: 1041480f31c2SKonrad Witaszczyk if (rijndael_makeKey(&kdc->kdc_ki, DIR_ENCRYPT, 256, key) <= 0) 1042480f31c2SKonrad Witaszczyk goto failed; 1043480f31c2SKonrad Witaszczyk break; 104482985292SConrad Meyer case KERNELDUMP_ENC_CHACHA20: 104582985292SConrad Meyer chacha_keysetup(&kdc->kdc_chacha, key, 256); 104682985292SConrad Meyer break; 1047480f31c2SKonrad Witaszczyk default: 1048480f31c2SKonrad Witaszczyk goto failed; 1049480f31c2SKonrad Witaszczyk } 1050480f31c2SKonrad Witaszczyk 1051480f31c2SKonrad Witaszczyk kdc->kdc_dumpkeysize = dumpkeysize; 1052480f31c2SKonrad Witaszczyk kdk = kdc->kdc_dumpkey; 1053480f31c2SKonrad Witaszczyk kdk->kdk_encryption = kdc->kdc_encryption; 1054480f31c2SKonrad Witaszczyk memcpy(kdk->kdk_iv, kdc->kdc_iv, sizeof(kdk->kdk_iv)); 1055480f31c2SKonrad Witaszczyk kdk->kdk_encryptedkeysize = htod32(encryptedkeysize); 1056480f31c2SKonrad Witaszczyk memcpy(kdk->kdk_encryptedkey, encryptedkey, encryptedkeysize); 1057480f31c2SKonrad Witaszczyk 1058480f31c2SKonrad Witaszczyk return (kdc); 1059480f31c2SKonrad Witaszczyk failed: 1060480f31c2SKonrad Witaszczyk explicit_bzero(kdc, sizeof(*kdc) + dumpkeysize); 1061480f31c2SKonrad Witaszczyk free(kdc, M_EKCD); 1062480f31c2SKonrad Witaszczyk return (NULL); 1063480f31c2SKonrad Witaszczyk } 1064480f31c2SKonrad Witaszczyk 106550ef60daSMark Johnston static int 1066480f31c2SKonrad Witaszczyk kerneldumpcrypto_init(struct kerneldumpcrypto *kdc) 1067480f31c2SKonrad Witaszczyk { 1068480f31c2SKonrad Witaszczyk uint8_t hash[SHA256_DIGEST_LENGTH]; 1069480f31c2SKonrad Witaszczyk SHA256_CTX ctx; 1070480f31c2SKonrad Witaszczyk struct kerneldumpkey *kdk; 1071480f31c2SKonrad Witaszczyk int error; 1072480f31c2SKonrad Witaszczyk 1073480f31c2SKonrad Witaszczyk error = 0; 1074480f31c2SKonrad Witaszczyk 1075480f31c2SKonrad Witaszczyk if (kdc == NULL) 1076480f31c2SKonrad Witaszczyk return (0); 1077480f31c2SKonrad Witaszczyk 1078480f31c2SKonrad Witaszczyk /* 1079480f31c2SKonrad Witaszczyk * When a user enters ddb it can write a crash dump multiple times. 1080480f31c2SKonrad Witaszczyk * Each time it should be encrypted using a different IV. 1081480f31c2SKonrad Witaszczyk */ 1082480f31c2SKonrad Witaszczyk SHA256_Init(&ctx); 1083480f31c2SKonrad Witaszczyk SHA256_Update(&ctx, kdc->kdc_iv, sizeof(kdc->kdc_iv)); 1084480f31c2SKonrad Witaszczyk SHA256_Final(hash, &ctx); 1085480f31c2SKonrad Witaszczyk bcopy(hash, kdc->kdc_iv, sizeof(kdc->kdc_iv)); 1086480f31c2SKonrad Witaszczyk 1087480f31c2SKonrad Witaszczyk switch (kdc->kdc_encryption) { 1088480f31c2SKonrad Witaszczyk case KERNELDUMP_ENC_AES_256_CBC: 1089480f31c2SKonrad Witaszczyk if (rijndael_cipherInit(&kdc->kdc_ci, MODE_CBC, 1090480f31c2SKonrad Witaszczyk kdc->kdc_iv) <= 0) { 1091480f31c2SKonrad Witaszczyk error = EINVAL; 1092480f31c2SKonrad Witaszczyk goto out; 1093480f31c2SKonrad Witaszczyk } 1094480f31c2SKonrad Witaszczyk break; 109582985292SConrad Meyer case KERNELDUMP_ENC_CHACHA20: 109682985292SConrad Meyer chacha_ivsetup(&kdc->kdc_chacha, kdc->kdc_iv, NULL); 109782985292SConrad Meyer break; 1098480f31c2SKonrad Witaszczyk default: 1099480f31c2SKonrad Witaszczyk error = EINVAL; 1100480f31c2SKonrad Witaszczyk goto out; 1101480f31c2SKonrad Witaszczyk } 1102480f31c2SKonrad Witaszczyk 1103480f31c2SKonrad Witaszczyk kdk = kdc->kdc_dumpkey; 1104480f31c2SKonrad Witaszczyk memcpy(kdk->kdk_iv, kdc->kdc_iv, sizeof(kdk->kdk_iv)); 1105480f31c2SKonrad Witaszczyk out: 1106480f31c2SKonrad Witaszczyk explicit_bzero(hash, sizeof(hash)); 1107480f31c2SKonrad Witaszczyk return (error); 1108480f31c2SKonrad Witaszczyk } 1109480f31c2SKonrad Witaszczyk 111001938d36SMark Johnston static uint32_t 1111480f31c2SKonrad Witaszczyk kerneldumpcrypto_dumpkeysize(const struct kerneldumpcrypto *kdc) 1112480f31c2SKonrad Witaszczyk { 1113480f31c2SKonrad Witaszczyk 1114480f31c2SKonrad Witaszczyk if (kdc == NULL) 1115480f31c2SKonrad Witaszczyk return (0); 1116480f31c2SKonrad Witaszczyk return (kdc->kdc_dumpkeysize); 1117480f31c2SKonrad Witaszczyk } 111801938d36SMark Johnston #endif /* EKCD */ 1119480f31c2SKonrad Witaszczyk 112078f57a9cSMark Johnston static struct kerneldumpcomp * 112178f57a9cSMark Johnston kerneldumpcomp_create(struct dumperinfo *di, uint8_t compression) 112264a16434SMark Johnston { 112378f57a9cSMark Johnston struct kerneldumpcomp *kdcomp; 11246026dcd7SMark Johnston int format; 112564a16434SMark Johnston 11266026dcd7SMark Johnston switch (compression) { 11276026dcd7SMark Johnston case KERNELDUMP_COMP_GZIP: 11286026dcd7SMark Johnston format = COMPRESS_GZIP; 11296026dcd7SMark Johnston break; 11306026dcd7SMark Johnston case KERNELDUMP_COMP_ZSTD: 11316026dcd7SMark Johnston format = COMPRESS_ZSTD; 11326026dcd7SMark Johnston break; 11336026dcd7SMark Johnston default: 113464a16434SMark Johnston return (NULL); 11356026dcd7SMark Johnston } 11366026dcd7SMark Johnston 113778f57a9cSMark Johnston kdcomp = malloc(sizeof(*kdcomp), M_DUMPER, M_WAITOK | M_ZERO); 11386026dcd7SMark Johnston kdcomp->kdc_format = compression; 113978f57a9cSMark Johnston kdcomp->kdc_stream = compressor_init(kerneldumpcomp_write_cb, 11406026dcd7SMark Johnston format, di->maxiosize, kerneldump_gzlevel, di); 114178f57a9cSMark Johnston if (kdcomp->kdc_stream == NULL) { 114278f57a9cSMark Johnston free(kdcomp, M_DUMPER); 114364a16434SMark Johnston return (NULL); 114464a16434SMark Johnston } 114578f57a9cSMark Johnston kdcomp->kdc_buf = malloc(di->maxiosize, M_DUMPER, M_WAITOK | M_NODUMP); 114678f57a9cSMark Johnston return (kdcomp); 114764a16434SMark Johnston } 114864a16434SMark Johnston 114964a16434SMark Johnston static void 115078f57a9cSMark Johnston kerneldumpcomp_destroy(struct dumperinfo *di) 115164a16434SMark Johnston { 115278f57a9cSMark Johnston struct kerneldumpcomp *kdcomp; 115364a16434SMark Johnston 115478f57a9cSMark Johnston kdcomp = di->kdcomp; 115578f57a9cSMark Johnston if (kdcomp == NULL) 115664a16434SMark Johnston return; 115778f57a9cSMark Johnston compressor_fini(kdcomp->kdc_stream); 115878f57a9cSMark Johnston explicit_bzero(kdcomp->kdc_buf, di->maxiosize); 115978f57a9cSMark Johnston free(kdcomp->kdc_buf, M_DUMPER); 116078f57a9cSMark Johnston free(kdcomp, M_DUMPER); 116164a16434SMark Johnston } 116264a16434SMark Johnston 11636b6e2954SConrad Meyer /* 11646b6e2954SConrad Meyer * Must not be present on global list. 11656b6e2954SConrad Meyer */ 11666b6e2954SConrad Meyer static void 11676b6e2954SConrad Meyer free_single_dumper(struct dumperinfo *di) 11686b6e2954SConrad Meyer { 11696b6e2954SConrad Meyer 11706b6e2954SConrad Meyer if (di == NULL) 11716b6e2954SConrad Meyer return; 11726b6e2954SConrad Meyer 11736b6e2954SConrad Meyer if (di->blockbuf != NULL) { 11746b6e2954SConrad Meyer explicit_bzero(di->blockbuf, di->blocksize); 11756b6e2954SConrad Meyer free(di->blockbuf, M_DUMPER); 11766b6e2954SConrad Meyer } 11776b6e2954SConrad Meyer 11786b6e2954SConrad Meyer kerneldumpcomp_destroy(di); 11796b6e2954SConrad Meyer 11806b6e2954SConrad Meyer #ifdef EKCD 11816b6e2954SConrad Meyer if (di->kdcrypto != NULL) { 11826b6e2954SConrad Meyer explicit_bzero(di->kdcrypto, sizeof(*di->kdcrypto) + 11836b6e2954SConrad Meyer di->kdcrypto->kdc_dumpkeysize); 11846b6e2954SConrad Meyer free(di->kdcrypto, M_EKCD); 11856b6e2954SConrad Meyer } 11866b6e2954SConrad Meyer #endif 11876b6e2954SConrad Meyer 11886b6e2954SConrad Meyer explicit_bzero(di, sizeof(*di)); 11896b6e2954SConrad Meyer free(di, M_DUMPER); 11906b6e2954SConrad Meyer } 11916b6e2954SConrad Meyer 119281661c94SPoul-Henning Kamp /* Registration of dumpers */ 119381661c94SPoul-Henning Kamp int 11946b6e2954SConrad Meyer dumper_insert(const struct dumperinfo *di_template, const char *devname, 11956b6e2954SConrad Meyer const struct diocskerneldump_arg *kda) 119681661c94SPoul-Henning Kamp { 11976b6e2954SConrad Meyer struct dumperinfo *newdi, *listdi; 11986b6e2954SConrad Meyer bool inserted; 11996b6e2954SConrad Meyer uint8_t index; 12005ebb15b9SPawel Jakub Dawidek int error; 12015ebb15b9SPawel Jakub Dawidek 12026b6e2954SConrad Meyer index = kda->kda_index; 12036b6e2954SConrad Meyer MPASS(index != KDA_REMOVE && index != KDA_REMOVE_DEV && 12046b6e2954SConrad Meyer index != KDA_REMOVE_ALL); 12056b6e2954SConrad Meyer 12066b6e2954SConrad Meyer error = priv_check(curthread, PRIV_SETDUMPER); 12075ebb15b9SPawel Jakub Dawidek if (error != 0) 12085ebb15b9SPawel Jakub Dawidek return (error); 1209e95499bdSAlfred Perlstein 12106b6e2954SConrad Meyer newdi = malloc(sizeof(*newdi) + strlen(devname) + 1, M_DUMPER, M_WAITOK 12116b6e2954SConrad Meyer | M_ZERO); 12126b6e2954SConrad Meyer memcpy(newdi, di_template, sizeof(*newdi)); 12136b6e2954SConrad Meyer newdi->blockbuf = NULL; 12146b6e2954SConrad Meyer newdi->kdcrypto = NULL; 12156b6e2954SConrad Meyer newdi->kdcomp = NULL; 12166b6e2954SConrad Meyer strcpy(newdi->di_devname, devname); 1217480f31c2SKonrad Witaszczyk 12186b6e2954SConrad Meyer if (kda->kda_encryption != KERNELDUMP_ENC_NONE) { 1219480f31c2SKonrad Witaszczyk #ifdef EKCD 12206b6e2954SConrad Meyer newdi->kdcrypto = kerneldumpcrypto_create(di_template->blocksize, 12216b6e2954SConrad Meyer kda->kda_encryption, kda->kda_key, 12226b6e2954SConrad Meyer kda->kda_encryptedkeysize, kda->kda_encryptedkey); 12236b6e2954SConrad Meyer if (newdi->kdcrypto == NULL) { 1224480f31c2SKonrad Witaszczyk error = EINVAL; 1225480f31c2SKonrad Witaszczyk goto cleanup; 1226480f31c2SKonrad Witaszczyk } 1227480f31c2SKonrad Witaszczyk #else 1228480f31c2SKonrad Witaszczyk error = EOPNOTSUPP; 1229480f31c2SKonrad Witaszczyk goto cleanup; 1230480f31c2SKonrad Witaszczyk #endif 1231480f31c2SKonrad Witaszczyk } 12326b6e2954SConrad Meyer if (kda->kda_compression != KERNELDUMP_COMP_NONE) { 123364a16434SMark Johnston /* 123482985292SConrad Meyer * We can't support simultaneous unpadded block cipher 123582985292SConrad Meyer * encryption and compression because there is no guarantee the 123682985292SConrad Meyer * length of the compressed result is exactly a multiple of the 123782985292SConrad Meyer * cipher block size. 123864a16434SMark Johnston */ 123982985292SConrad Meyer if (kda->kda_encryption == KERNELDUMP_ENC_AES_256_CBC) { 124064a16434SMark Johnston error = EOPNOTSUPP; 124164a16434SMark Johnston goto cleanup; 124264a16434SMark Johnston } 12436b6e2954SConrad Meyer newdi->kdcomp = kerneldumpcomp_create(newdi, 12446b6e2954SConrad Meyer kda->kda_compression); 12456b6e2954SConrad Meyer if (newdi->kdcomp == NULL) { 124664a16434SMark Johnston error = EINVAL; 124764a16434SMark Johnston goto cleanup; 124864a16434SMark Johnston } 124964a16434SMark Johnston } 125064a16434SMark Johnston 12516b6e2954SConrad Meyer newdi->blockbuf = malloc(newdi->blocksize, M_DUMPER, M_WAITOK | M_ZERO); 12526b6e2954SConrad Meyer 12536b6e2954SConrad Meyer /* Add the new configuration to the queue */ 12546b6e2954SConrad Meyer mtx_lock(&dumpconf_list_lk); 12556b6e2954SConrad Meyer inserted = false; 12566b6e2954SConrad Meyer TAILQ_FOREACH(listdi, &dumper_configs, di_next) { 12576b6e2954SConrad Meyer if (index == 0) { 12586b6e2954SConrad Meyer TAILQ_INSERT_BEFORE(listdi, newdi, di_next); 12596b6e2954SConrad Meyer inserted = true; 12606b6e2954SConrad Meyer break; 12616b6e2954SConrad Meyer } 12626b6e2954SConrad Meyer index--; 12636b6e2954SConrad Meyer } 12646b6e2954SConrad Meyer if (!inserted) 12656b6e2954SConrad Meyer TAILQ_INSERT_TAIL(&dumper_configs, newdi, di_next); 12666b6e2954SConrad Meyer mtx_unlock(&dumpconf_list_lk); 12676b6e2954SConrad Meyer 126881661c94SPoul-Henning Kamp return (0); 1269bd92e6b6SMark Johnston 1270480f31c2SKonrad Witaszczyk cleanup: 12716b6e2954SConrad Meyer free_single_dumper(newdi); 1272bd92e6b6SMark Johnston return (error); 1273bd92e6b6SMark Johnston } 1274bd92e6b6SMark Johnston 1275addccb8cSConrad Meyer #ifdef DDB 1276addccb8cSConrad Meyer void 1277addccb8cSConrad Meyer dumper_ddb_insert(struct dumperinfo *newdi) 1278addccb8cSConrad Meyer { 1279addccb8cSConrad Meyer TAILQ_INSERT_HEAD(&dumper_configs, newdi, di_next); 1280addccb8cSConrad Meyer } 1281addccb8cSConrad Meyer 1282addccb8cSConrad Meyer void 1283addccb8cSConrad Meyer dumper_ddb_remove(struct dumperinfo *di) 1284addccb8cSConrad Meyer { 1285addccb8cSConrad Meyer TAILQ_REMOVE(&dumper_configs, di, di_next); 1286addccb8cSConrad Meyer } 1287addccb8cSConrad Meyer #endif 1288addccb8cSConrad Meyer 12896b6e2954SConrad Meyer static bool 12906b6e2954SConrad Meyer dumper_config_match(const struct dumperinfo *di, const char *devname, 12916b6e2954SConrad Meyer const struct diocskerneldump_arg *kda) 12926b6e2954SConrad Meyer { 12936b6e2954SConrad Meyer if (kda->kda_index == KDA_REMOVE_ALL) 12946b6e2954SConrad Meyer return (true); 12956b6e2954SConrad Meyer 12966b6e2954SConrad Meyer if (strcmp(di->di_devname, devname) != 0) 12976b6e2954SConrad Meyer return (false); 12986b6e2954SConrad Meyer 12996b6e2954SConrad Meyer /* 13006b6e2954SConrad Meyer * Allow wildcard removal of configs matching a device on g_dev_orphan. 13016b6e2954SConrad Meyer */ 13026b6e2954SConrad Meyer if (kda->kda_index == KDA_REMOVE_DEV) 13036b6e2954SConrad Meyer return (true); 13046b6e2954SConrad Meyer 13056b6e2954SConrad Meyer if (di->kdcomp != NULL) { 13066b6e2954SConrad Meyer if (di->kdcomp->kdc_format != kda->kda_compression) 13076b6e2954SConrad Meyer return (false); 13086b6e2954SConrad Meyer } else if (kda->kda_compression != KERNELDUMP_COMP_NONE) 13096b6e2954SConrad Meyer return (false); 13106b6e2954SConrad Meyer #ifdef EKCD 13116b6e2954SConrad Meyer if (di->kdcrypto != NULL) { 13126b6e2954SConrad Meyer if (di->kdcrypto->kdc_encryption != kda->kda_encryption) 13136b6e2954SConrad Meyer return (false); 13146b6e2954SConrad Meyer /* 13156b6e2954SConrad Meyer * Do we care to verify keys match to delete? It seems weird 13166b6e2954SConrad Meyer * to expect multiple fallback dump configurations on the same 13176b6e2954SConrad Meyer * device that only differ in crypto key. 13186b6e2954SConrad Meyer */ 13196b6e2954SConrad Meyer } else 13206b6e2954SConrad Meyer #endif 13216b6e2954SConrad Meyer if (kda->kda_encryption != KERNELDUMP_ENC_NONE) 13226b6e2954SConrad Meyer return (false); 13236b6e2954SConrad Meyer 13246b6e2954SConrad Meyer return (true); 13256b6e2954SConrad Meyer } 13266b6e2954SConrad Meyer 1327bd92e6b6SMark Johnston int 13286b6e2954SConrad Meyer dumper_remove(const char *devname, const struct diocskerneldump_arg *kda) 1329bd92e6b6SMark Johnston { 13306b6e2954SConrad Meyer struct dumperinfo *di, *sdi; 13316b6e2954SConrad Meyer bool found; 1332bd92e6b6SMark Johnston int error; 1333bd92e6b6SMark Johnston 13346b6e2954SConrad Meyer error = priv_check(curthread, PRIV_SETDUMPER); 1335bd92e6b6SMark Johnston if (error != 0) 1336bd92e6b6SMark Johnston return (error); 1337bd92e6b6SMark Johnston 13386b6e2954SConrad Meyer /* 13396b6e2954SConrad Meyer * Try to find a matching configuration, and kill it. 13406b6e2954SConrad Meyer * 13416b6e2954SConrad Meyer * NULL 'kda' indicates remove any configuration matching 'devname', 13426b6e2954SConrad Meyer * which may remove multiple configurations in atypical configurations. 13436b6e2954SConrad Meyer */ 13446b6e2954SConrad Meyer found = false; 13456b6e2954SConrad Meyer mtx_lock(&dumpconf_list_lk); 13466b6e2954SConrad Meyer TAILQ_FOREACH_SAFE(di, &dumper_configs, di_next, sdi) { 13476b6e2954SConrad Meyer if (dumper_config_match(di, devname, kda)) { 13486b6e2954SConrad Meyer found = true; 13496b6e2954SConrad Meyer TAILQ_REMOVE(&dumper_configs, di, di_next); 13506b6e2954SConrad Meyer free_single_dumper(di); 1351480f31c2SKonrad Witaszczyk } 1352480f31c2SKonrad Witaszczyk } 13536b6e2954SConrad Meyer mtx_unlock(&dumpconf_list_lk); 13546b6e2954SConrad Meyer 13556b6e2954SConrad Meyer /* Only produce ENOENT if a more targeted match didn't match. */ 13566b6e2954SConrad Meyer if (!found && kda->kda_index == KDA_REMOVE) 13576b6e2954SConrad Meyer return (ENOENT); 1358bd92e6b6SMark Johnston return (0); 135981661c94SPoul-Henning Kamp } 136081661c94SPoul-Henning Kamp 1361480f31c2SKonrad Witaszczyk static int 1362480f31c2SKonrad Witaszczyk dump_check_bounds(struct dumperinfo *di, off_t offset, size_t length) 1363007b1b7bSRuslan Ermilov { 1364007b1b7bSRuslan Ermilov 1365bd92e6b6SMark Johnston if (di->mediasize > 0 && length != 0 && (offset < di->mediaoffset || 1366007b1b7bSRuslan Ermilov offset - di->mediaoffset + length > di->mediasize)) { 1367bde3b1e1SMark Johnston if (di->kdcomp != NULL && offset >= di->mediaoffset) { 1368bde3b1e1SMark Johnston printf( 1369bde3b1e1SMark Johnston "Compressed dump failed to fit in device boundaries.\n"); 1370bde3b1e1SMark Johnston return (E2BIG); 1371bde3b1e1SMark Johnston } 1372bde3b1e1SMark Johnston 137358379067SAttilio Rao printf("Attempt to write outside dump device boundaries.\n" 137458379067SAttilio Rao "offset(%jd), mediaoffset(%jd), length(%ju), mediasize(%jd).\n", 137558379067SAttilio Rao (intmax_t)offset, (intmax_t)di->mediaoffset, 137658379067SAttilio Rao (uintmax_t)length, (intmax_t)di->mediasize); 137758379067SAttilio Rao return (ENOSPC); 1378007b1b7bSRuslan Ermilov } 137946fcd1afSMark Johnston if (length % di->blocksize != 0) { 138046fcd1afSMark Johnston printf("Attempt to write partial block of length %ju.\n", 138146fcd1afSMark Johnston (uintmax_t)length); 138246fcd1afSMark Johnston return (EINVAL); 138346fcd1afSMark Johnston } 138446fcd1afSMark Johnston if (offset % di->blocksize != 0) { 138546fcd1afSMark Johnston printf("Attempt to write at unaligned offset %jd.\n", 138646fcd1afSMark Johnston (intmax_t)offset); 138746fcd1afSMark Johnston return (EINVAL); 1388480f31c2SKonrad Witaszczyk } 1389480f31c2SKonrad Witaszczyk 139046fcd1afSMark Johnston return (0); 139101938d36SMark Johnston } 139201938d36SMark Johnston 1393480f31c2SKonrad Witaszczyk #ifdef EKCD 1394480f31c2SKonrad Witaszczyk static int 1395480f31c2SKonrad Witaszczyk dump_encrypt(struct kerneldumpcrypto *kdc, uint8_t *buf, size_t size) 1396480f31c2SKonrad Witaszczyk { 1397480f31c2SKonrad Witaszczyk 1398480f31c2SKonrad Witaszczyk switch (kdc->kdc_encryption) { 1399480f31c2SKonrad Witaszczyk case KERNELDUMP_ENC_AES_256_CBC: 1400480f31c2SKonrad Witaszczyk if (rijndael_blockEncrypt(&kdc->kdc_ci, &kdc->kdc_ki, buf, 1401480f31c2SKonrad Witaszczyk 8 * size, buf) <= 0) { 1402480f31c2SKonrad Witaszczyk return (EIO); 1403480f31c2SKonrad Witaszczyk } 1404480f31c2SKonrad Witaszczyk if (rijndael_cipherInit(&kdc->kdc_ci, MODE_CBC, 1405480f31c2SKonrad Witaszczyk buf + size - 16 /* IV size for AES-256-CBC */) <= 0) { 1406480f31c2SKonrad Witaszczyk return (EIO); 1407480f31c2SKonrad Witaszczyk } 1408480f31c2SKonrad Witaszczyk break; 140982985292SConrad Meyer case KERNELDUMP_ENC_CHACHA20: 141082985292SConrad Meyer chacha_encrypt_bytes(&kdc->kdc_chacha, buf, buf, size); 141182985292SConrad Meyer break; 1412480f31c2SKonrad Witaszczyk default: 1413480f31c2SKonrad Witaszczyk return (EINVAL); 1414480f31c2SKonrad Witaszczyk } 1415480f31c2SKonrad Witaszczyk 1416480f31c2SKonrad Witaszczyk return (0); 1417480f31c2SKonrad Witaszczyk } 1418480f31c2SKonrad Witaszczyk 1419480f31c2SKonrad Witaszczyk /* Encrypt data and call dumper. */ 1420480f31c2SKonrad Witaszczyk static int 142146fcd1afSMark Johnston dump_encrypted_write(struct dumperinfo *di, void *virtual, 142246fcd1afSMark Johnston vm_offset_t physical, off_t offset, size_t length) 1423480f31c2SKonrad Witaszczyk { 1424480f31c2SKonrad Witaszczyk static uint8_t buf[KERNELDUMP_BUFFER_SIZE]; 1425480f31c2SKonrad Witaszczyk struct kerneldumpcrypto *kdc; 1426480f31c2SKonrad Witaszczyk int error; 1427480f31c2SKonrad Witaszczyk size_t nbytes; 1428480f31c2SKonrad Witaszczyk 142978f57a9cSMark Johnston kdc = di->kdcrypto; 1430480f31c2SKonrad Witaszczyk 1431480f31c2SKonrad Witaszczyk while (length > 0) { 1432480f31c2SKonrad Witaszczyk nbytes = MIN(length, sizeof(buf)); 1433480f31c2SKonrad Witaszczyk bcopy(virtual, buf, nbytes); 1434480f31c2SKonrad Witaszczyk 1435480f31c2SKonrad Witaszczyk if (dump_encrypt(kdc, buf, nbytes) != 0) 1436480f31c2SKonrad Witaszczyk return (EIO); 1437480f31c2SKonrad Witaszczyk 143846fcd1afSMark Johnston error = dump_write(di, buf, physical, offset, nbytes); 1439480f31c2SKonrad Witaszczyk if (error != 0) 1440480f31c2SKonrad Witaszczyk return (error); 1441480f31c2SKonrad Witaszczyk 1442480f31c2SKonrad Witaszczyk offset += nbytes; 1443480f31c2SKonrad Witaszczyk virtual = (void *)((uint8_t *)virtual + nbytes); 1444480f31c2SKonrad Witaszczyk length -= nbytes; 1445480f31c2SKonrad Witaszczyk } 1446480f31c2SKonrad Witaszczyk 1447480f31c2SKonrad Witaszczyk return (0); 1448480f31c2SKonrad Witaszczyk } 144901938d36SMark Johnston #endif /* EKCD */ 1450007b1b7bSRuslan Ermilov 145164a16434SMark Johnston static int 145278f57a9cSMark Johnston kerneldumpcomp_write_cb(void *base, size_t length, off_t offset, void *arg) 145364a16434SMark Johnston { 145464a16434SMark Johnston struct dumperinfo *di; 145564a16434SMark Johnston size_t resid, rlength; 145664a16434SMark Johnston int error; 145764a16434SMark Johnston 145864a16434SMark Johnston di = arg; 145964a16434SMark Johnston 146064a16434SMark Johnston if (length % di->blocksize != 0) { 146164a16434SMark Johnston /* 146264a16434SMark Johnston * This must be the final write after flushing the compression 146364a16434SMark Johnston * stream. Write as many full blocks as possible and stash the 146464a16434SMark Johnston * residual data in the dumper's block buffer. It will be 146564a16434SMark Johnston * padded and written in dump_finish(). 146664a16434SMark Johnston */ 146764a16434SMark Johnston rlength = rounddown(length, di->blocksize); 146864a16434SMark Johnston if (rlength != 0) { 146964a16434SMark Johnston error = _dump_append(di, base, 0, rlength); 147064a16434SMark Johnston if (error != 0) 147164a16434SMark Johnston return (error); 147264a16434SMark Johnston } 147364a16434SMark Johnston resid = length - rlength; 147464a16434SMark Johnston memmove(di->blockbuf, (uint8_t *)base + rlength, resid); 147578f57a9cSMark Johnston di->kdcomp->kdc_resid = resid; 147664a16434SMark Johnston return (EAGAIN); 147764a16434SMark Johnston } 147864a16434SMark Johnston return (_dump_append(di, base, 0, length)); 147964a16434SMark Johnston } 148064a16434SMark Johnston 148164a16434SMark Johnston /* 1482bd92e6b6SMark Johnston * Write kernel dump headers at the beginning and end of the dump extent. 1483bd92e6b6SMark Johnston * Write the kernel dump encryption key after the leading header if we were 1484bd92e6b6SMark Johnston * configured to do so. 148564a16434SMark Johnston */ 1486480f31c2SKonrad Witaszczyk static int 1487bd92e6b6SMark Johnston dump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh) 1488480f31c2SKonrad Witaszczyk { 1489bd92e6b6SMark Johnston #ifdef EKCD 1490bd92e6b6SMark Johnston struct kerneldumpcrypto *kdc; 1491bd92e6b6SMark Johnston #endif 1492bd92e6b6SMark Johnston void *buf, *key; 1493e9666bf6SMark Johnston size_t hdrsz; 1494bd92e6b6SMark Johnston uint64_t extent; 1495bd92e6b6SMark Johnston uint32_t keysize; 1496bd92e6b6SMark Johnston int error; 1497480f31c2SKonrad Witaszczyk 1498e9666bf6SMark Johnston hdrsz = sizeof(*kdh); 1499e9666bf6SMark Johnston if (hdrsz > di->blocksize) 1500e9666bf6SMark Johnston return (ENOMEM); 1501e9666bf6SMark Johnston 1502bd92e6b6SMark Johnston #ifdef EKCD 1503bd92e6b6SMark Johnston kdc = di->kdcrypto; 1504bd92e6b6SMark Johnston key = kdc->kdc_dumpkey; 1505bd92e6b6SMark Johnston keysize = kerneldumpcrypto_dumpkeysize(kdc); 1506bd92e6b6SMark Johnston #else 1507bd92e6b6SMark Johnston key = NULL; 1508bd92e6b6SMark Johnston keysize = 0; 1509bd92e6b6SMark Johnston #endif 1510bd92e6b6SMark Johnston 1511bd92e6b6SMark Johnston /* 1512bd92e6b6SMark Johnston * If the dump device has special handling for headers, let it take care 1513bd92e6b6SMark Johnston * of writing them out. 1514bd92e6b6SMark Johnston */ 1515bd92e6b6SMark Johnston if (di->dumper_hdr != NULL) 1516bd92e6b6SMark Johnston return (di->dumper_hdr(di, kdh, key, keysize)); 1517bd92e6b6SMark Johnston 1518e9666bf6SMark Johnston if (hdrsz == di->blocksize) 1519e9666bf6SMark Johnston buf = kdh; 1520e9666bf6SMark Johnston else { 1521e9666bf6SMark Johnston buf = di->blockbuf; 1522e9666bf6SMark Johnston memset(buf, 0, di->blocksize); 1523e9666bf6SMark Johnston memcpy(buf, kdh, hdrsz); 1524e9666bf6SMark Johnston } 1525e9666bf6SMark Johnston 1526bd92e6b6SMark Johnston extent = dtoh64(kdh->dumpextent); 1527bd92e6b6SMark Johnston #ifdef EKCD 1528bd92e6b6SMark Johnston if (kdc != NULL) { 1529bd92e6b6SMark Johnston error = dump_write(di, kdc->kdc_dumpkey, 0, 1530bd92e6b6SMark Johnston di->mediaoffset + di->mediasize - di->blocksize - extent - 1531bd92e6b6SMark Johnston keysize, keysize); 1532bd92e6b6SMark Johnston if (error != 0) 1533bd92e6b6SMark Johnston return (error); 1534bd92e6b6SMark Johnston } 1535bd92e6b6SMark Johnston #endif 1536bd92e6b6SMark Johnston 1537bd92e6b6SMark Johnston error = dump_write(di, buf, 0, 1538bd92e6b6SMark Johnston di->mediaoffset + di->mediasize - 2 * di->blocksize - extent - 1539bd92e6b6SMark Johnston keysize, di->blocksize); 1540bd92e6b6SMark Johnston if (error == 0) 1541bd92e6b6SMark Johnston error = dump_write(di, buf, 0, di->mediaoffset + di->mediasize - 1542bd92e6b6SMark Johnston di->blocksize, di->blocksize); 1543bd92e6b6SMark Johnston return (error); 15445dc5dab6SConrad Meyer } 15455dc5dab6SConrad Meyer 154650ef60daSMark Johnston /* 154750ef60daSMark Johnston * Don't touch the first SIZEOF_METADATA bytes on the dump device. This is to 154850ef60daSMark Johnston * protect us from metadata and metadata from us. 154950ef60daSMark Johnston */ 155050ef60daSMark Johnston #define SIZEOF_METADATA (64 * 1024) 155150ef60daSMark Johnston 155250ef60daSMark Johnston /* 155364a16434SMark Johnston * Do some preliminary setup for a kernel dump: initialize state for encryption, 155464a16434SMark Johnston * if requested, and make sure that we have enough space on the dump device. 155564a16434SMark Johnston * 155664a16434SMark Johnston * We set things up so that the dump ends before the last sector of the dump 155764a16434SMark Johnston * device, at which the trailing header is written. 155864a16434SMark Johnston * 155964a16434SMark Johnston * +-----------+------+-----+----------------------------+------+ 156064a16434SMark Johnston * | | lhdr | key | ... kernel dump ... | thdr | 156164a16434SMark Johnston * +-----------+------+-----+----------------------------+------+ 156264a16434SMark Johnston * 1 blk opt <------- dump extent --------> 1 blk 156364a16434SMark Johnston * 156464a16434SMark Johnston * Dumps written using dump_append() start at the beginning of the extent. 156564a16434SMark Johnston * Uncompressed dumps will use the entire extent, but compressed dumps typically 156664a16434SMark Johnston * will not. The true length of the dump is recorded in the leading and trailing 156764a16434SMark Johnston * headers once the dump has been completed. 1568bd92e6b6SMark Johnston * 1569bd92e6b6SMark Johnston * The dump device may provide a callback, in which case it will initialize 1570bd92e6b6SMark Johnston * dumpoff and take care of laying out the headers. 157150ef60daSMark Johnston */ 157250ef60daSMark Johnston int 157346fcd1afSMark Johnston dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh) 157450ef60daSMark Johnston { 1575bd92e6b6SMark Johnston uint64_t dumpextent, span; 157601938d36SMark Johnston uint32_t keysize; 1577bd92e6b6SMark Johnston int error; 157850ef60daSMark Johnston 157901938d36SMark Johnston #ifdef EKCD 1580bd92e6b6SMark Johnston error = kerneldumpcrypto_init(di->kdcrypto); 158150ef60daSMark Johnston if (error != 0) 158250ef60daSMark Johnston return (error); 158378f57a9cSMark Johnston keysize = kerneldumpcrypto_dumpkeysize(di->kdcrypto); 158401938d36SMark Johnston #else 1585bd92e6b6SMark Johnston error = 0; 158601938d36SMark Johnston keysize = 0; 158701938d36SMark Johnston #endif 158850ef60daSMark Johnston 1589bd92e6b6SMark Johnston if (di->dumper_start != NULL) { 1590bd92e6b6SMark Johnston error = di->dumper_start(di); 1591bd92e6b6SMark Johnston } else { 159264a16434SMark Johnston dumpextent = dtoh64(kdh->dumpextent); 1593bd92e6b6SMark Johnston span = SIZEOF_METADATA + dumpextent + 2 * di->blocksize + 1594bd92e6b6SMark Johnston keysize; 1595bd92e6b6SMark Johnston if (di->mediasize < span) { 1596bd92e6b6SMark Johnston if (di->kdcomp == NULL) 1597bd92e6b6SMark Johnston return (E2BIG); 1598bd92e6b6SMark Johnston 159964a16434SMark Johnston /* 160064a16434SMark Johnston * We don't yet know how much space the compressed dump 160164a16434SMark Johnston * will occupy, so try to use the whole swap partition 160264a16434SMark Johnston * (minus the first 64KB) in the hope that the 160364a16434SMark Johnston * compressed dump will fit. If that doesn't turn out to 16046026dcd7SMark Johnston * be enough, the bounds checking in dump_write() 160564a16434SMark Johnston * will catch us and cause the dump to fail. 160664a16434SMark Johnston */ 1607bd92e6b6SMark Johnston dumpextent = di->mediasize - span + dumpextent; 160864a16434SMark Johnston kdh->dumpextent = htod64(dumpextent); 160964a16434SMark Johnston } 161064a16434SMark Johnston 1611bd92e6b6SMark Johnston /* 1612bd92e6b6SMark Johnston * The offset at which to begin writing the dump. 1613bd92e6b6SMark Johnston */ 161464a16434SMark Johnston di->dumpoff = di->mediaoffset + di->mediasize - di->blocksize - 161564a16434SMark Johnston dumpextent; 1616bd92e6b6SMark Johnston } 1617bd92e6b6SMark Johnston di->origdumpoff = di->dumpoff; 1618bd92e6b6SMark Johnston return (error); 161950ef60daSMark Johnston } 162050ef60daSMark Johnston 162164a16434SMark Johnston static int 162264a16434SMark Johnston _dump_append(struct dumperinfo *di, void *virtual, vm_offset_t physical, 162346fcd1afSMark Johnston size_t length) 162446fcd1afSMark Johnston { 162546fcd1afSMark Johnston int error; 162646fcd1afSMark Johnston 162746fcd1afSMark Johnston #ifdef EKCD 162878f57a9cSMark Johnston if (di->kdcrypto != NULL) 162946fcd1afSMark Johnston error = dump_encrypted_write(di, virtual, physical, di->dumpoff, 163046fcd1afSMark Johnston length); 163146fcd1afSMark Johnston else 163246fcd1afSMark Johnston #endif 163346fcd1afSMark Johnston error = dump_write(di, virtual, physical, di->dumpoff, length); 163446fcd1afSMark Johnston if (error == 0) 163546fcd1afSMark Johnston di->dumpoff += length; 163646fcd1afSMark Johnston return (error); 163746fcd1afSMark Johnston } 163846fcd1afSMark Johnston 163964a16434SMark Johnston /* 164064a16434SMark Johnston * Write to the dump device starting at dumpoff. When compression is enabled, 164164a16434SMark Johnston * writes to the device will be performed using a callback that gets invoked 164264a16434SMark Johnston * when the compression stream's output buffer is full. 164364a16434SMark Johnston */ 164464a16434SMark Johnston int 164564a16434SMark Johnston dump_append(struct dumperinfo *di, void *virtual, vm_offset_t physical, 164664a16434SMark Johnston size_t length) 164764a16434SMark Johnston { 164864a16434SMark Johnston void *buf; 164964a16434SMark Johnston 165078f57a9cSMark Johnston if (di->kdcomp != NULL) { 165178f57a9cSMark Johnston /* Bounce through a buffer to avoid CRC errors. */ 165264a16434SMark Johnston if (length > di->maxiosize) 165364a16434SMark Johnston return (EINVAL); 165478f57a9cSMark Johnston buf = di->kdcomp->kdc_buf; 165564a16434SMark Johnston memmove(buf, virtual, length); 165678f57a9cSMark Johnston return (compressor_write(di->kdcomp->kdc_stream, buf, length)); 165764a16434SMark Johnston } 165864a16434SMark Johnston return (_dump_append(di, virtual, physical, length)); 165964a16434SMark Johnston } 166064a16434SMark Johnston 166164a16434SMark Johnston /* 166264a16434SMark Johnston * Write to the dump device at the specified offset. 166364a16434SMark Johnston */ 166446fcd1afSMark Johnston int 166546fcd1afSMark Johnston dump_write(struct dumperinfo *di, void *virtual, vm_offset_t physical, 166646fcd1afSMark Johnston off_t offset, size_t length) 166746fcd1afSMark Johnston { 166846fcd1afSMark Johnston int error; 166946fcd1afSMark Johnston 167046fcd1afSMark Johnston error = dump_check_bounds(di, offset, length); 167146fcd1afSMark Johnston if (error != 0) 167246fcd1afSMark Johnston return (error); 167346fcd1afSMark Johnston return (di->dumper(di->priv, virtual, physical, offset, length)); 167446fcd1afSMark Johnston } 167546fcd1afSMark Johnston 167650ef60daSMark Johnston /* 167764a16434SMark Johnston * Perform kernel dump finalization: flush the compression stream, if necessary, 167864a16434SMark Johnston * write the leading and trailing kernel dump headers now that we know the true 167964a16434SMark Johnston * length of the dump, and optionally write the encryption key following the 168064a16434SMark Johnston * leading header. 168150ef60daSMark Johnston */ 168250ef60daSMark Johnston int 168346fcd1afSMark Johnston dump_finish(struct dumperinfo *di, struct kerneldumpheader *kdh) 168450ef60daSMark Johnston { 168550ef60daSMark Johnston int error; 168650ef60daSMark Johnston 168778f57a9cSMark Johnston if (di->kdcomp != NULL) { 168878f57a9cSMark Johnston error = compressor_flush(di->kdcomp->kdc_stream); 168964a16434SMark Johnston if (error == EAGAIN) { 169064a16434SMark Johnston /* We have residual data in di->blockbuf. */ 169164a16434SMark Johnston error = dump_write(di, di->blockbuf, 0, di->dumpoff, 169264a16434SMark Johnston di->blocksize); 169378f57a9cSMark Johnston di->dumpoff += di->kdcomp->kdc_resid; 169478f57a9cSMark Johnston di->kdcomp->kdc_resid = 0; 169564a16434SMark Johnston } 169664a16434SMark Johnston if (error != 0) 169764a16434SMark Johnston return (error); 169864a16434SMark Johnston 169964a16434SMark Johnston /* 170064a16434SMark Johnston * We now know the size of the compressed dump, so update the 170164a16434SMark Johnston * header accordingly and recompute parity. 170264a16434SMark Johnston */ 1703bd92e6b6SMark Johnston kdh->dumplength = htod64(di->dumpoff - di->origdumpoff); 170464a16434SMark Johnston kdh->parity = 0; 170564a16434SMark Johnston kdh->parity = kerneldump_parity(kdh); 170664a16434SMark Johnston 170778f57a9cSMark Johnston compressor_reset(di->kdcomp->kdc_stream); 170864a16434SMark Johnston } 170964a16434SMark Johnston 1710bd92e6b6SMark Johnston error = dump_write_headers(di, kdh); 171150ef60daSMark Johnston if (error != 0) 171250ef60daSMark Johnston return (error); 171350ef60daSMark Johnston 171450ef60daSMark Johnston (void)dump_write(di, NULL, 0, 0, 0); 171550ef60daSMark Johnston return (0); 171650ef60daSMark Johnston } 171750ef60daSMark Johnston 1718e6592ee5SPeter Wemm void 171901938d36SMark Johnston dump_init_header(const struct dumperinfo *di, struct kerneldumpheader *kdh, 1720fe20aaecSRyan Libby const char *magic, uint32_t archver, uint64_t dumplen) 1721e6592ee5SPeter Wemm { 1722ab384d75SMark Johnston size_t dstsize; 1723e6592ee5SPeter Wemm 1724e6592ee5SPeter Wemm bzero(kdh, sizeof(*kdh)); 17257a9c38e6SAlan Somers strlcpy(kdh->magic, magic, sizeof(kdh->magic)); 17267a9c38e6SAlan Somers strlcpy(kdh->architecture, MACHINE_ARCH, sizeof(kdh->architecture)); 1727e6592ee5SPeter Wemm kdh->version = htod32(KERNELDUMPVERSION); 1728e6592ee5SPeter Wemm kdh->architectureversion = htod32(archver); 1729e6592ee5SPeter Wemm kdh->dumplength = htod64(dumplen); 173064a16434SMark Johnston kdh->dumpextent = kdh->dumplength; 1731e6592ee5SPeter Wemm kdh->dumptime = htod64(time_second); 173201938d36SMark Johnston #ifdef EKCD 173378f57a9cSMark Johnston kdh->dumpkeysize = htod32(kerneldumpcrypto_dumpkeysize(di->kdcrypto)); 173401938d36SMark Johnston #else 173501938d36SMark Johnston kdh->dumpkeysize = 0; 173601938d36SMark Johnston #endif 173701938d36SMark Johnston kdh->blocksize = htod32(di->blocksize); 17387a9c38e6SAlan Somers strlcpy(kdh->hostname, prison0.pr_hostname, sizeof(kdh->hostname)); 1739ab384d75SMark Johnston dstsize = sizeof(kdh->versionstring); 1740ab384d75SMark Johnston if (strlcpy(kdh->versionstring, version, dstsize) >= dstsize) 1741ab384d75SMark Johnston kdh->versionstring[dstsize - 2] = '\n'; 1742e6592ee5SPeter Wemm if (panicstr != NULL) 17437a9c38e6SAlan Somers strlcpy(kdh->panicstring, panicstr, sizeof(kdh->panicstring)); 174478f57a9cSMark Johnston if (di->kdcomp != NULL) 17456026dcd7SMark Johnston kdh->compression = di->kdcomp->kdc_format; 1746e6592ee5SPeter Wemm kdh->parity = kerneldump_parity(kdh); 1747e6592ee5SPeter Wemm } 17483af72c11SBjoern A. Zeeb 17493af72c11SBjoern A. Zeeb #ifdef DDB 17503af72c11SBjoern A. Zeeb DB_SHOW_COMMAND(panic, db_show_panic) 17513af72c11SBjoern A. Zeeb { 17523af72c11SBjoern A. Zeeb 17533af72c11SBjoern A. Zeeb if (panicstr == NULL) 17543af72c11SBjoern A. Zeeb db_printf("panicstr not set\n"); 17553af72c11SBjoern A. Zeeb else 17563af72c11SBjoern A. Zeeb db_printf("panic: %s\n", panicstr); 17573af72c11SBjoern A. Zeeb } 17583af72c11SBjoern A. Zeeb #endif 1759