1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1980, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #if 0 33 #ifndef lint 34 static const char copyright[] = 35 "@(#) Copyright (c) 1980, 1993\n\ 36 The Regents of the University of California. All rights reserved.\n"; 37 #endif /* not lint */ 38 39 #ifndef lint 40 static char sccsid[] = "From: @(#)swapon.c 8.1 (Berkeley) 6/5/93"; 41 #endif /* not lint */ 42 #endif 43 #include <sys/cdefs.h> 44 __FBSDID("$FreeBSD$"); 45 46 #include <sys/param.h> 47 #include <sys/capsicum.h> 48 #include <sys/disk.h> 49 #include <sys/sysctl.h> 50 51 #include <assert.h> 52 #include <err.h> 53 #include <errno.h> 54 #include <fcntl.h> 55 #include <paths.h> 56 #include <stdbool.h> 57 #include <stdint.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <string.h> 61 #include <sysexits.h> 62 #include <unistd.h> 63 64 #ifdef HAVE_CRYPTO 65 #include <openssl/err.h> 66 #include <openssl/pem.h> 67 #include <openssl/rsa.h> 68 #endif 69 70 static int verbose; 71 72 static void 73 usage(void) 74 { 75 fprintf(stderr, "%s\n%s\n%s\n", 76 "usage: dumpon [-v] [-k public_key_file] [-z] special_file", 77 " dumpon [-v] off", 78 " dumpon [-v] -l"); 79 exit(EX_USAGE); 80 } 81 82 static void 83 check_size(int fd, const char *fn) 84 { 85 int name[] = { CTL_HW, HW_PHYSMEM }; 86 size_t namelen = nitems(name); 87 unsigned long physmem; 88 size_t len; 89 off_t mediasize; 90 int minidump; 91 92 len = sizeof(minidump); 93 if (sysctlbyname("debug.minidump", &minidump, &len, NULL, 0) == 0 && 94 minidump == 1) 95 return; 96 len = sizeof(physmem); 97 if (sysctl(name, namelen, &physmem, &len, NULL, 0) != 0) 98 err(EX_OSERR, "can't get memory size"); 99 if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) != 0) 100 err(EX_OSERR, "%s: can't get size", fn); 101 if ((uintmax_t)mediasize < (uintmax_t)physmem) { 102 if (verbose) 103 printf("%s is smaller than physical memory\n", fn); 104 exit(EX_IOERR); 105 } 106 } 107 108 #ifdef HAVE_CRYPTO 109 static void 110 genkey(const char *pubkeyfile, struct diocskerneldump_arg *kda) 111 { 112 FILE *fp; 113 RSA *pubkey; 114 115 assert(pubkeyfile != NULL); 116 assert(kda != NULL); 117 118 fp = NULL; 119 pubkey = NULL; 120 121 fp = fopen(pubkeyfile, "r"); 122 if (fp == NULL) 123 err(1, "Unable to open %s", pubkeyfile); 124 125 if (cap_enter() < 0 && errno != ENOSYS) 126 err(1, "Unable to enter capability mode"); 127 128 pubkey = RSA_new(); 129 if (pubkey == NULL) { 130 errx(1, "Unable to allocate an RSA structure: %s", 131 ERR_error_string(ERR_get_error(), NULL)); 132 } 133 134 pubkey = PEM_read_RSA_PUBKEY(fp, &pubkey, NULL, NULL); 135 fclose(fp); 136 fp = NULL; 137 if (pubkey == NULL) 138 errx(1, "Unable to read data from %s.", pubkeyfile); 139 140 kda->kda_encryptedkeysize = RSA_size(pubkey); 141 if (kda->kda_encryptedkeysize > KERNELDUMP_ENCKEY_MAX_SIZE) { 142 errx(1, "Public key has to be at most %db long.", 143 8 * KERNELDUMP_ENCKEY_MAX_SIZE); 144 } 145 146 kda->kda_encryptedkey = calloc(1, kda->kda_encryptedkeysize); 147 if (kda->kda_encryptedkey == NULL) 148 err(1, "Unable to allocate encrypted key"); 149 150 kda->kda_encryption = KERNELDUMP_ENC_AES_256_CBC; 151 arc4random_buf(kda->kda_key, sizeof(kda->kda_key)); 152 if (RSA_public_encrypt(sizeof(kda->kda_key), kda->kda_key, 153 kda->kda_encryptedkey, pubkey, 154 RSA_PKCS1_PADDING) != (int)kda->kda_encryptedkeysize) { 155 errx(1, "Unable to encrypt the one-time key."); 156 } 157 RSA_free(pubkey); 158 } 159 #endif 160 161 static void 162 listdumpdev(void) 163 { 164 char dumpdev[PATH_MAX]; 165 size_t len; 166 const char *sysctlname = "kern.shutdown.dumpdevname"; 167 168 len = sizeof(dumpdev); 169 if (sysctlbyname(sysctlname, &dumpdev, &len, NULL, 0) != 0) { 170 if (errno == ENOMEM) { 171 err(EX_OSERR, "Kernel returned too large of a buffer for '%s'\n", 172 sysctlname); 173 } else { 174 err(EX_OSERR, "Sysctl get '%s'\n", sysctlname); 175 } 176 } 177 if (verbose) { 178 printf("kernel dumps on "); 179 } 180 if (strlen(dumpdev) == 0) { 181 printf("%s\n", _PATH_DEVNULL); 182 } else { 183 printf("%s\n", dumpdev); 184 } 185 } 186 187 int 188 main(int argc, char *argv[]) 189 { 190 struct diocskerneldump_arg kda; 191 const char *pubkeyfile; 192 int ch; 193 int i, fd; 194 int do_listdumpdev = 0; 195 bool enable, gzip; 196 197 gzip = false; 198 pubkeyfile = NULL; 199 200 while ((ch = getopt(argc, argv, "k:lvz")) != -1) 201 switch((char)ch) { 202 case 'k': 203 pubkeyfile = optarg; 204 break; 205 case 'l': 206 do_listdumpdev = 1; 207 break; 208 case 'v': 209 verbose = 1; 210 break; 211 case 'z': 212 gzip = true; 213 break; 214 default: 215 usage(); 216 } 217 218 argc -= optind; 219 argv += optind; 220 221 if (do_listdumpdev) { 222 listdumpdev(); 223 exit(EX_OK); 224 } 225 226 if (argc != 1) 227 usage(); 228 229 enable = (strcmp(argv[0], "off") != 0); 230 #ifndef HAVE_CRYPTO 231 if (pubkeyfile != NULL) { 232 enable = false; 233 warnx("Unable to use the public key. Recompile dumpon with OpenSSL support."); 234 } 235 #endif 236 237 if (enable) { 238 char tmp[PATH_MAX]; 239 char *dumpdev; 240 241 if (strncmp(argv[0], _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) { 242 dumpdev = argv[0]; 243 } else { 244 i = snprintf(tmp, PATH_MAX, "%s%s", _PATH_DEV, argv[0]); 245 if (i < 0) { 246 err(EX_OSERR, "%s", argv[0]); 247 } else if (i >= PATH_MAX) { 248 errno = EINVAL; 249 err(EX_DATAERR, "%s", argv[0]); 250 } 251 dumpdev = tmp; 252 } 253 fd = open(dumpdev, O_RDONLY); 254 if (fd < 0) 255 err(EX_OSFILE, "%s", dumpdev); 256 257 if (!gzip) 258 check_size(fd, dumpdev); 259 260 bzero(&kda, sizeof(kda)); 261 kda.kda_enable = 0; 262 i = ioctl(fd, DIOCSKERNELDUMP, &kda); 263 explicit_bzero(&kda, sizeof(kda)); 264 265 #ifdef HAVE_CRYPTO 266 if (pubkeyfile != NULL) 267 genkey(pubkeyfile, &kda); 268 #endif 269 270 kda.kda_enable = 1; 271 kda.kda_compression = gzip ? KERNELDUMP_COMP_GZIP : 272 KERNELDUMP_COMP_NONE; 273 i = ioctl(fd, DIOCSKERNELDUMP, &kda); 274 explicit_bzero(kda.kda_encryptedkey, kda.kda_encryptedkeysize); 275 free(kda.kda_encryptedkey); 276 explicit_bzero(&kda, sizeof(kda)); 277 if (i == 0 && verbose) 278 printf("kernel dumps on %s\n", dumpdev); 279 } else { 280 fd = open(_PATH_DEVNULL, O_RDONLY); 281 if (fd < 0) 282 err(EX_OSFILE, "%s", _PATH_DEVNULL); 283 284 kda.kda_enable = 0; 285 i = ioctl(fd, DIOCSKERNELDUMP, &kda); 286 explicit_bzero(&kda, sizeof(kda)); 287 if (i == 0 && verbose) 288 printf("kernel dumps disabled\n"); 289 } 290 if (i < 0) 291 err(EX_OSERR, "ioctl(DIOCSKERNELDUMP)"); 292 293 exit (0); 294 } 295