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/socket.h> 50 #include <sys/sysctl.h> 51 52 #include <assert.h> 53 #include <capsicum_helpers.h> 54 #include <err.h> 55 #include <errno.h> 56 #include <fcntl.h> 57 #include <ifaddrs.h> 58 #include <netdb.h> 59 #include <paths.h> 60 #include <stdbool.h> 61 #include <stdint.h> 62 #include <stdio.h> 63 #include <stdlib.h> 64 #include <string.h> 65 #include <sysexits.h> 66 #include <unistd.h> 67 68 #include <arpa/inet.h> 69 70 #include <net/if.h> 71 #include <net/if_dl.h> 72 #include <net/route.h> 73 74 #include <netinet/in.h> 75 #include <netinet/netdump/netdump.h> 76 77 #ifdef HAVE_CRYPTO 78 #include <openssl/err.h> 79 #include <openssl/pem.h> 80 #include <openssl/rand.h> 81 #include <openssl/rsa.h> 82 #endif 83 84 static int verbose; 85 86 static void _Noreturn 87 usage(void) 88 { 89 fprintf(stderr, 90 "usage: dumpon [-i index] [-r] [-v] [-k <pubkey>] [-Zz] <device>\n" 91 " dumpon [-i index] [-r] [-v] [-k <pubkey>] [-Zz]\n" 92 " [-g <gateway>] -s <server> -c <client> <iface>\n" 93 " dumpon [-v] off\n" 94 " dumpon [-v] -l\n"); 95 exit(EX_USAGE); 96 } 97 98 /* 99 * Look for a default route on the specified interface. 100 */ 101 static char * 102 find_gateway(const char *ifname) 103 { 104 struct ifaddrs *ifa, *ifap; 105 struct rt_msghdr *rtm; 106 struct sockaddr *sa; 107 struct sockaddr_dl *sdl; 108 struct sockaddr_in *dst, *mask, *gw; 109 char *buf, *next, *ret; 110 size_t sz; 111 int error, i, ifindex, mib[7]; 112 113 /* First look up the interface index. */ 114 if (getifaddrs(&ifap) != 0) 115 err(EX_OSERR, "getifaddrs"); 116 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 117 if (ifa->ifa_addr->sa_family != AF_LINK) 118 continue; 119 if (strcmp(ifa->ifa_name, ifname) == 0) { 120 sdl = (struct sockaddr_dl *)(void *)ifa->ifa_addr; 121 ifindex = sdl->sdl_index; 122 break; 123 } 124 } 125 if (ifa == NULL) 126 errx(1, "couldn't find interface index for '%s'", ifname); 127 freeifaddrs(ifap); 128 129 /* Now get the IPv4 routing table. */ 130 mib[0] = CTL_NET; 131 mib[1] = PF_ROUTE; 132 mib[2] = 0; 133 mib[3] = AF_INET; 134 mib[4] = NET_RT_DUMP; 135 mib[5] = 0; 136 mib[6] = -1; /* FIB */ 137 138 for (;;) { 139 if (sysctl(mib, nitems(mib), NULL, &sz, NULL, 0) != 0) 140 err(EX_OSERR, "sysctl(NET_RT_DUMP)"); 141 buf = malloc(sz); 142 error = sysctl(mib, nitems(mib), buf, &sz, NULL, 0); 143 if (error == 0) 144 break; 145 if (errno != ENOMEM) 146 err(EX_OSERR, "sysctl(NET_RT_DUMP)"); 147 free(buf); 148 } 149 150 ret = NULL; 151 for (next = buf; next < buf + sz; next += rtm->rtm_msglen) { 152 rtm = (struct rt_msghdr *)(void *)next; 153 if (rtm->rtm_version != RTM_VERSION) 154 continue; 155 if ((rtm->rtm_flags & RTF_GATEWAY) == 0 || 156 rtm->rtm_index != ifindex) 157 continue; 158 159 dst = gw = mask = NULL; 160 sa = (struct sockaddr *)(rtm + 1); 161 for (i = 0; i < RTAX_MAX; i++) { 162 if ((rtm->rtm_addrs & (1 << i)) != 0) { 163 switch (i) { 164 case RTAX_DST: 165 dst = (void *)sa; 166 break; 167 case RTAX_GATEWAY: 168 gw = (void *)sa; 169 break; 170 case RTAX_NETMASK: 171 mask = (void *)sa; 172 break; 173 } 174 } 175 sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa)); 176 } 177 178 if (dst->sin_addr.s_addr == INADDR_ANY && 179 mask->sin_addr.s_addr == 0) { 180 ret = inet_ntoa(gw->sin_addr); 181 break; 182 } 183 } 184 free(buf); 185 return (ret); 186 } 187 188 static void 189 check_size(int fd, const char *fn) 190 { 191 int name[] = { CTL_HW, HW_PHYSMEM }; 192 size_t namelen = nitems(name); 193 unsigned long physmem; 194 size_t len; 195 off_t mediasize; 196 int minidump; 197 198 len = sizeof(minidump); 199 if (sysctlbyname("debug.minidump", &minidump, &len, NULL, 0) == 0 && 200 minidump == 1) 201 return; 202 len = sizeof(physmem); 203 if (sysctl(name, namelen, &physmem, &len, NULL, 0) != 0) 204 err(EX_OSERR, "can't get memory size"); 205 if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) != 0) 206 err(EX_OSERR, "%s: can't get size", fn); 207 if ((uintmax_t)mediasize < (uintmax_t)physmem) 208 errx(EX_IOERR, "%s is smaller than physical memory", fn); 209 } 210 211 #ifdef HAVE_CRYPTO 212 static void 213 genkey(const char *pubkeyfile, struct diocskerneldump_arg *kdap) 214 { 215 FILE *fp; 216 RSA *pubkey; 217 218 assert(pubkeyfile != NULL); 219 assert(kdap != NULL); 220 221 fp = NULL; 222 pubkey = NULL; 223 224 fp = fopen(pubkeyfile, "r"); 225 if (fp == NULL) 226 err(1, "Unable to open %s", pubkeyfile); 227 228 /* 229 * Obsolescent OpenSSL only knows about /dev/random, and needs to 230 * pre-seed before entering cap mode. For whatever reason, 231 * RSA_pub_encrypt uses the internal PRNG. 232 */ 233 #if OPENSSL_VERSION_NUMBER < 0x10100000L 234 { 235 unsigned char c[1]; 236 RAND_bytes(c, 1); 237 } 238 #endif 239 240 if (caph_enter() < 0) 241 err(1, "Unable to enter capability mode"); 242 243 pubkey = RSA_new(); 244 if (pubkey == NULL) { 245 errx(1, "Unable to allocate an RSA structure: %s", 246 ERR_error_string(ERR_get_error(), NULL)); 247 } 248 249 pubkey = PEM_read_RSA_PUBKEY(fp, &pubkey, NULL, NULL); 250 fclose(fp); 251 fp = NULL; 252 if (pubkey == NULL) 253 errx(1, "Unable to read data from %s.", pubkeyfile); 254 255 /* 256 * RSA keys under ~1024 bits are trivially factorable (2018). OpenSSL 257 * provides an API for RSA keys to estimate the symmetric-cipher 258 * "equivalent" bits of security (defined in NIST SP800-57), which as 259 * of this writing equates a 2048-bit RSA key to 112 symmetric cipher 260 * bits. 261 * 262 * Use this API as a seatbelt to avoid suggesting to users that their 263 * privacy is protected by encryption when the key size is insufficient 264 * to prevent compromise via factoring. 265 * 266 * Future work: Sanity check for weak 'e', and sanity check for absence 267 * of 'd' (i.e., the supplied key is a public key rather than a full 268 * keypair). 269 */ 270 #if OPENSSL_VERSION_NUMBER >= 0x10100000L 271 if (RSA_security_bits(pubkey) < 112) 272 #else 273 if (RSA_size(pubkey) * 8 < 2048) 274 #endif 275 errx(1, "Small RSA keys (you provided: %db) can be " 276 "factored cheaply. Please generate a larger key.", 277 RSA_size(pubkey) * 8); 278 279 kdap->kda_encryptedkeysize = RSA_size(pubkey); 280 if (kdap->kda_encryptedkeysize > KERNELDUMP_ENCKEY_MAX_SIZE) { 281 errx(1, "Public key has to be at most %db long.", 282 8 * KERNELDUMP_ENCKEY_MAX_SIZE); 283 } 284 285 kdap->kda_encryptedkey = calloc(1, kdap->kda_encryptedkeysize); 286 if (kdap->kda_encryptedkey == NULL) 287 err(1, "Unable to allocate encrypted key"); 288 289 /* 290 * If no cipher was specified, choose a reasonable default. 291 */ 292 if (kdap->kda_encryption == KERNELDUMP_ENC_NONE) 293 kdap->kda_encryption = KERNELDUMP_ENC_CHACHA20; 294 else if (kdap->kda_encryption == KERNELDUMP_ENC_AES_256_CBC && 295 kdap->kda_compression != KERNELDUMP_COMP_NONE) 296 errx(EX_USAGE, "Unpadded AES256-CBC mode cannot be used " 297 "with compression."); 298 299 arc4random_buf(kdap->kda_key, sizeof(kdap->kda_key)); 300 if (RSA_public_encrypt(sizeof(kdap->kda_key), kdap->kda_key, 301 kdap->kda_encryptedkey, pubkey, 302 RSA_PKCS1_OAEP_PADDING) != (int)kdap->kda_encryptedkeysize) { 303 errx(1, "Unable to encrypt the one-time key: %s", 304 ERR_error_string(ERR_get_error(), NULL)); 305 } 306 RSA_free(pubkey); 307 } 308 #endif 309 310 static void 311 listdumpdev(void) 312 { 313 static char ip[200]; 314 315 char dumpdev[PATH_MAX]; 316 struct diocskerneldump_arg ndconf; 317 size_t len; 318 const char *sysctlname = "kern.shutdown.dumpdevname"; 319 int fd; 320 321 len = sizeof(dumpdev); 322 if (sysctlbyname(sysctlname, &dumpdev, &len, NULL, 0) != 0) { 323 if (errno == ENOMEM) { 324 err(EX_OSERR, "Kernel returned too large of a buffer for '%s'\n", 325 sysctlname); 326 } else { 327 err(EX_OSERR, "Sysctl get '%s'\n", sysctlname); 328 } 329 } 330 if (strlen(dumpdev) == 0) 331 (void)strlcpy(dumpdev, _PATH_DEVNULL, sizeof(dumpdev)); 332 333 if (verbose) { 334 char *ctx, *dd; 335 unsigned idx; 336 337 printf("kernel dumps on priority: device\n"); 338 idx = 0; 339 ctx = dumpdev; 340 while ((dd = strsep(&ctx, ",")) != NULL) 341 printf("%u: %s\n", idx++, dd); 342 } else 343 printf("%s\n", dumpdev); 344 345 /* If netdump is enabled, print the configuration parameters. */ 346 if (verbose) { 347 fd = open(_PATH_NETDUMP, O_RDONLY); 348 if (fd < 0) { 349 if (errno != ENOENT) 350 err(EX_OSERR, "opening %s", _PATH_NETDUMP); 351 return; 352 } 353 if (ioctl(fd, DIOCGKERNELDUMP, &ndconf) != 0) { 354 if (errno != ENXIO) 355 err(EX_OSERR, "ioctl(DIOCGKERNELDUMP)"); 356 (void)close(fd); 357 return; 358 } 359 360 printf("server address: %s\n", 361 inet_ntop(ndconf.kda_af, &ndconf.kda_server, ip, 362 sizeof(ip))); 363 printf("client address: %s\n", 364 inet_ntop(ndconf.kda_af, &ndconf.kda_client, ip, 365 sizeof(ip))); 366 printf("gateway address: %s\n", 367 inet_ntop(ndconf.kda_af, &ndconf.kda_gateway, ip, 368 sizeof(ip))); 369 (void)close(fd); 370 } 371 } 372 373 static int 374 opendumpdev(const char *arg, char *dumpdev) 375 { 376 int fd, i; 377 378 if (strncmp(arg, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 379 strlcpy(dumpdev, arg, PATH_MAX); 380 else { 381 i = snprintf(dumpdev, PATH_MAX, "%s%s", _PATH_DEV, arg); 382 if (i < 0) 383 err(EX_OSERR, "%s", arg); 384 if (i >= PATH_MAX) 385 errc(EX_DATAERR, EINVAL, "%s", arg); 386 } 387 388 fd = open(dumpdev, O_RDONLY); 389 if (fd < 0) 390 err(EX_OSFILE, "%s", dumpdev); 391 return (fd); 392 } 393 394 int 395 main(int argc, char *argv[]) 396 { 397 char dumpdev[PATH_MAX]; 398 struct diocskerneldump_arg ndconf, *kdap; 399 struct addrinfo hints, *res; 400 const char *dev, *pubkeyfile, *server, *client, *gateway; 401 int ch, error, fd, cipher; 402 bool gzip, list, netdump, zstd, insert, rflag; 403 uint8_t ins_idx; 404 405 gzip = list = netdump = zstd = insert = rflag = false; 406 kdap = NULL; 407 pubkeyfile = NULL; 408 server = client = gateway = NULL; 409 ins_idx = KDA_APPEND; 410 cipher = KERNELDUMP_ENC_NONE; 411 412 while ((ch = getopt(argc, argv, "C:c:g:i:k:lrs:vZz")) != -1) 413 switch ((char)ch) { 414 case 'C': 415 if (strcasecmp(optarg, "chacha") == 0 || 416 strcasecmp(optarg, "chacha20") == 0) 417 cipher = KERNELDUMP_ENC_CHACHA20; 418 else if (strcasecmp(optarg, "aes-cbc") == 0 || 419 strcasecmp(optarg, "aes256-cbc") == 0) 420 cipher = KERNELDUMP_ENC_AES_256_CBC; 421 else 422 errx(EX_USAGE, "Unrecognized cipher algorithm " 423 "'%s'", optarg); 424 break; 425 case 'c': 426 client = optarg; 427 break; 428 case 'g': 429 gateway = optarg; 430 break; 431 case 'i': 432 { 433 int i; 434 435 i = atoi(optarg); 436 if (i < 0 || i >= KDA_APPEND - 1) 437 errx(EX_USAGE, 438 "-i index must be between zero and %d.", 439 (int)KDA_APPEND - 2); 440 insert = true; 441 ins_idx = i; 442 } 443 break; 444 case 'k': 445 pubkeyfile = optarg; 446 break; 447 case 'l': 448 list = true; 449 break; 450 case 'r': 451 rflag = true; 452 break; 453 case 's': 454 server = optarg; 455 break; 456 case 'v': 457 verbose = 1; 458 break; 459 case 'Z': 460 zstd = true; 461 break; 462 case 'z': 463 gzip = true; 464 break; 465 default: 466 usage(); 467 } 468 469 if (gzip && zstd) 470 errx(EX_USAGE, "The -z and -Z options are mutually exclusive."); 471 472 if (insert && rflag) 473 errx(EX_USAGE, "The -i and -r options are mutually exclusive."); 474 475 argc -= optind; 476 argv += optind; 477 478 if (list) { 479 listdumpdev(); 480 exit(EX_OK); 481 } 482 483 if (argc != 1) 484 usage(); 485 486 #ifdef HAVE_CRYPTO 487 if (cipher != KERNELDUMP_ENC_NONE && pubkeyfile == NULL) { 488 errx(EX_USAGE, "-C option requires a public key file."); 489 } else if (pubkeyfile != NULL) { 490 ERR_load_crypto_strings(); 491 } 492 #else 493 if (pubkeyfile != NULL) 494 errx(EX_UNAVAILABLE,"Unable to use the public key." 495 " Recompile dumpon with OpenSSL support."); 496 #endif 497 498 if (server != NULL && client != NULL) { 499 dev = _PATH_NETDUMP; 500 netdump = true; 501 } else if (server == NULL && client == NULL && argc > 0) { 502 if (strcmp(argv[0], "off") == 0) { 503 rflag = true; 504 dev = _PATH_DEVNULL; 505 } else 506 dev = argv[0]; 507 netdump = false; 508 } else 509 usage(); 510 511 fd = opendumpdev(dev, dumpdev); 512 if (!netdump && !gzip && !zstd && !rflag) 513 check_size(fd, dumpdev); 514 515 kdap = &ndconf; 516 bzero(kdap, sizeof(*kdap)); 517 518 if (rflag) 519 kdap->kda_index = KDA_REMOVE; 520 else 521 kdap->kda_index = ins_idx; 522 523 kdap->kda_compression = KERNELDUMP_COMP_NONE; 524 if (zstd) 525 kdap->kda_compression = KERNELDUMP_COMP_ZSTD; 526 else if (gzip) 527 kdap->kda_compression = KERNELDUMP_COMP_GZIP; 528 529 if (netdump) { 530 memset(&hints, 0, sizeof(hints)); 531 hints.ai_family = AF_INET; 532 hints.ai_protocol = IPPROTO_UDP; 533 res = NULL; 534 error = getaddrinfo(server, NULL, &hints, &res); 535 if (error != 0) { 536 if (error == EAI_SYSTEM) 537 err(EX_OSERR, "%s", gai_strerror(error)); 538 errx(EX_NOHOST, "%s", gai_strerror(error)); 539 } 540 server = inet_ntoa( 541 ((struct sockaddr_in *)(void *)res->ai_addr)->sin_addr); 542 freeaddrinfo(res); 543 544 if (strlcpy(ndconf.kda_iface, argv[0], 545 sizeof(ndconf.kda_iface)) >= sizeof(ndconf.kda_iface)) 546 errx(EX_USAGE, "invalid interface name '%s'", argv[0]); 547 if (inet_aton(server, &ndconf.kda_server.in4) == 0) 548 errx(EX_USAGE, "invalid server address '%s'", server); 549 if (inet_aton(client, &ndconf.kda_client.in4) == 0) 550 errx(EX_USAGE, "invalid client address '%s'", client); 551 552 if (gateway == NULL) { 553 gateway = find_gateway(argv[0]); 554 if (gateway == NULL) { 555 if (verbose) 556 printf( 557 "failed to look up gateway for %s\n", 558 server); 559 gateway = server; 560 } 561 } 562 if (inet_aton(gateway, &ndconf.kda_gateway.in4) == 0) 563 errx(EX_USAGE, "invalid gateway address '%s'", gateway); 564 ndconf.kda_af = AF_INET; 565 } 566 567 #ifdef HAVE_CRYPTO 568 if (pubkeyfile != NULL) { 569 kdap->kda_encryption = cipher; 570 genkey(pubkeyfile, kdap); 571 } 572 #endif 573 error = ioctl(fd, DIOCSKERNELDUMP, kdap); 574 if (error != 0) 575 error = errno; 576 explicit_bzero(kdap->kda_encryptedkey, kdap->kda_encryptedkeysize); 577 free(kdap->kda_encryptedkey); 578 explicit_bzero(kdap, sizeof(*kdap)); 579 if (error != 0) { 580 if (netdump) { 581 /* 582 * Be slightly less user-hostile for some common 583 * errors, especially as users don't have any great 584 * discoverability into which NICs support netdump. 585 */ 586 if (error == ENXIO) 587 errx(EX_OSERR, "Unable to configure netdump " 588 "because the interface's link is down."); 589 else if (error == ENODEV) 590 errx(EX_OSERR, "Unable to configure netdump " 591 "because the interface driver does not yet " 592 "support netdump."); 593 } 594 errc(EX_OSERR, error, "ioctl(DIOCSKERNELDUMP)"); 595 } 596 597 if (verbose) 598 listdumpdev(); 599 600 exit(EX_OK); 601 } 602