Changeset View
Changeset View
Standalone View
Standalone View
sbin/dumpon/dumpon.c
Show All 36 Lines | |||||
#ifndef lint | #ifndef lint | ||||
static char sccsid[] = "From: @(#)swapon.c 8.1 (Berkeley) 6/5/93"; | static char sccsid[] = "From: @(#)swapon.c 8.1 (Berkeley) 6/5/93"; | ||||
#endif /* not lint */ | #endif /* not lint */ | ||||
#endif | #endif | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/capsicum.h> | |||||
#include <sys/disk.h> | #include <sys/disk.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <assert.h> | |||||
#include <err.h> | #include <err.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <fcntl.h> | #include <fcntl.h> | ||||
#include <paths.h> | #include <paths.h> | ||||
#include <stdbool.h> | |||||
#include <stdint.h> | #include <stdint.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <sysexits.h> | #include <sysexits.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#ifdef HAVE_CRYPTO | |||||
#include <openssl/err.h> | |||||
#include <openssl/pem.h> | |||||
#include <openssl/rsa.h> | |||||
#endif | |||||
static int verbose; | static int verbose; | ||||
static void | static void | ||||
usage(void) | usage(void) | ||||
{ | { | ||||
fprintf(stderr, "%s\n%s\n%s\n", | fprintf(stderr, "%s\n%s\n%s\n", | ||||
"usage: dumpon [-v] special_file", | "usage: dumpon [-v] [-k public_key_file] special_file", | ||||
" dumpon [-v] off", | " dumpon [-v] off", | ||||
" dumpon [-v] -l"); | " dumpon [-v] -l"); | ||||
exit(EX_USAGE); | exit(EX_USAGE); | ||||
} | } | ||||
static void | static void | ||||
check_size(int fd, const char *fn) | check_size(int fd, const char *fn) | ||||
{ | { | ||||
Show All 15 Lines | if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) != 0) | ||||
err(EX_OSERR, "%s: can't get size", fn); | err(EX_OSERR, "%s: can't get size", fn); | ||||
if ((uintmax_t)mediasize < (uintmax_t)physmem) { | if ((uintmax_t)mediasize < (uintmax_t)physmem) { | ||||
if (verbose) | if (verbose) | ||||
printf("%s is smaller than physical memory\n", fn); | printf("%s is smaller than physical memory\n", fn); | ||||
exit(EX_IOERR); | exit(EX_IOERR); | ||||
} | } | ||||
} | } | ||||
#ifdef HAVE_CRYPTO | |||||
static void | static void | ||||
genkey(const char *pubkeyfile, struct diocskerneldump_arg *kda) | |||||
{ | |||||
FILE *fp; | |||||
RSA *pubkey; | |||||
assert(pubkeyfile != NULL); | |||||
assert(kda != NULL); | |||||
fp = NULL; | |||||
pubkey = NULL; | |||||
fp = fopen(pubkeyfile, "r"); | |||||
if (fp == NULL) | |||||
err(1, "Unable to open %s", pubkeyfile); | |||||
if (cap_enter() < 0 && errno != ENOSYS) | |||||
err(1, "Unable to enter capability mode"); | |||||
pubkey = RSA_new(); | |||||
if (pubkey == NULL) { | |||||
errx(1, "Unable to allocate an RSA structure: %s", | |||||
ERR_error_string(ERR_get_error(), NULL)); | |||||
} | |||||
pubkey = PEM_read_RSA_PUBKEY(fp, &pubkey, NULL, NULL); | |||||
fclose(fp); | |||||
fp = NULL; | |||||
if (pubkey == NULL) | |||||
errx(1, "Unable to read data from %s.", pubkeyfile); | |||||
kda->kda_encryptedkeysize = RSA_size(pubkey); | |||||
if (kda->kda_encryptedkeysize > KERNELDUMP_ENCKEY_MAX_SIZE) { | |||||
errx(1, "Public key has to be at most %db long.", | |||||
8 * KERNELDUMP_ENCKEY_MAX_SIZE); | |||||
} | |||||
kda->kda_encryptedkey = calloc(1, kda->kda_encryptedkeysize); | |||||
if (kda->kda_encryptedkey == NULL) | |||||
err(1, "Unable to allocate encrypted key"); | |||||
kda->kda_encryption = KERNELDUMP_ENC_AES_256_CBC; | |||||
arc4random_buf(kda->kda_key, sizeof(kda->kda_key)); | |||||
if (RSA_public_encrypt(sizeof(kda->kda_key), kda->kda_key, | |||||
kda->kda_encryptedkey, pubkey, | |||||
RSA_PKCS1_PADDING) != (int)kda->kda_encryptedkeysize) { | |||||
errx(1, "Unable to encrypt the one-time key."); | |||||
} | |||||
RSA_free(pubkey); | |||||
} | |||||
#endif | |||||
static void | |||||
listdumpdev(void) | listdumpdev(void) | ||||
{ | { | ||||
char dumpdev[PATH_MAX]; | char dumpdev[PATH_MAX]; | ||||
size_t len; | size_t len; | ||||
const char *sysctlname = "kern.shutdown.dumpdevname"; | const char *sysctlname = "kern.shutdown.dumpdevname"; | ||||
len = sizeof(dumpdev); | len = sizeof(dumpdev); | ||||
if (sysctlbyname(sysctlname, &dumpdev, &len, NULL, 0) != 0) { | if (sysctlbyname(sysctlname, &dumpdev, &len, NULL, 0) != 0) { | ||||
if (errno == ENOMEM) { | if (errno == ENOMEM) { | ||||
err(EX_OSERR, "Kernel returned too large of a buffer for '%s'\n", | err(EX_OSERR, "Kernel returned too large of a buffer for '%s'\n", | ||||
sysctlname); | sysctlname); | ||||
} else { | } else { | ||||
err(EX_OSERR, "Sysctl get '%s'\n", sysctlname); | err(EX_OSERR, "Sysctl get '%s'\n", sysctlname); | ||||
} | } | ||||
} | } | ||||
if (verbose) { | if (verbose) { | ||||
oshogbo: errno check. | |||||
printf("kernel dumps on "); | printf("kernel dumps on "); | ||||
} | } | ||||
if (strlen(dumpdev) == 0) { | if (strlen(dumpdev) == 0) { | ||||
printf("%s\n", _PATH_DEVNULL); | printf("%s\n", _PATH_DEVNULL); | ||||
} else { | } else { | ||||
printf("%s\n", dumpdev); | printf("%s\n", dumpdev); | ||||
} | } | ||||
} | } | ||||
int | int | ||||
main(int argc, char *argv[]) | main(int argc, char *argv[]) | ||||
{ | { | ||||
struct diocskerneldump_arg kda; | |||||
const char *pubkeyfile; | |||||
int ch; | int ch; | ||||
int i, fd; | int i, fd; | ||||
u_int u; | |||||
int do_listdumpdev = 0; | int do_listdumpdev = 0; | ||||
bool enable; | |||||
while ((ch = getopt(argc, argv, "lv")) != -1) | pubkeyfile = NULL; | ||||
while ((ch = getopt(argc, argv, "k:lv")) != -1) | |||||
switch((char)ch) { | switch((char)ch) { | ||||
case 'k': | |||||
pubkeyfile = optarg; | |||||
break; | |||||
case 'l': | case 'l': | ||||
do_listdumpdev = 1; | do_listdumpdev = 1; | ||||
break; | break; | ||||
case 'v': | case 'v': | ||||
verbose = 1; | verbose = 1; | ||||
break; | break; | ||||
default: | default: | ||||
usage(); | usage(); | ||||
} | } | ||||
argc -= optind; | argc -= optind; | ||||
argv += optind; | argv += optind; | ||||
if (do_listdumpdev) { | if (do_listdumpdev) { | ||||
listdumpdev(); | listdumpdev(); | ||||
exit(EX_OK); | exit(EX_OK); | ||||
} | } | ||||
if (argc != 1) | if (argc != 1) | ||||
usage(); | usage(); | ||||
if (strcmp(argv[0], "off") != 0) { | enable = (strcmp(argv[0], "off") != 0); | ||||
#ifndef HAVE_CRYPTO | |||||
if (pubkeyfile != NULL) { | |||||
enable = false; | |||||
warnx("Unable to use the public key. Recompile dumpon with OpenSSL support."); | |||||
} | |||||
#endif | |||||
if (enable) { | |||||
char tmp[PATH_MAX]; | char tmp[PATH_MAX]; | ||||
char *dumpdev; | char *dumpdev; | ||||
if (strncmp(argv[0], _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) { | if (strncmp(argv[0], _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) { | ||||
dumpdev = argv[0]; | dumpdev = argv[0]; | ||||
} else { | } else { | ||||
i = snprintf(tmp, PATH_MAX, "%s%s", _PATH_DEV, argv[0]); | i = snprintf(tmp, PATH_MAX, "%s%s", _PATH_DEV, argv[0]); | ||||
if (i < 0) { | if (i < 0) { | ||||
err(EX_OSERR, "%s", argv[0]); | err(EX_OSERR, "%s", argv[0]); | ||||
} else if (i >= PATH_MAX) { | } else if (i >= PATH_MAX) { | ||||
errno = EINVAL; | errno = EINVAL; | ||||
err(EX_DATAERR, "%s", argv[0]); | err(EX_DATAERR, "%s", argv[0]); | ||||
} | } | ||||
dumpdev = tmp; | dumpdev = tmp; | ||||
} | } | ||||
fd = open(dumpdev, O_RDONLY); | fd = open(dumpdev, O_RDONLY); | ||||
if (fd < 0) | if (fd < 0) | ||||
err(EX_OSFILE, "%s", dumpdev); | err(EX_OSFILE, "%s", dumpdev); | ||||
check_size(fd, dumpdev); | check_size(fd, dumpdev); | ||||
u = 0; | bzero(&kda, sizeof(kda)); | ||||
i = ioctl(fd, DIOCSKERNELDUMP, &u); | |||||
u = 1; | kda.kda_enable = 0; | ||||
i = ioctl(fd, DIOCSKERNELDUMP, &u); | i = ioctl(fd, DIOCSKERNELDUMP, &kda); | ||||
explicit_bzero(&kda, sizeof(kda)); | |||||
#ifdef HAVE_CRYPTO | |||||
if (pubkeyfile != NULL) | |||||
genkey(pubkeyfile, &kda); | |||||
#endif | |||||
kda.kda_enable = 1; | |||||
i = ioctl(fd, DIOCSKERNELDUMP, &kda); | |||||
explicit_bzero(kda.kda_encryptedkey, kda.kda_encryptedkeysize); | |||||
free(kda.kda_encryptedkey); | |||||
explicit_bzero(&kda, sizeof(kda)); | |||||
Done Inline Actionsexplicit_bzero? delphij: explicit_bzero? | |||||
if (i == 0 && verbose) | if (i == 0 && verbose) | ||||
printf("kernel dumps on %s\n", dumpdev); | printf("kernel dumps on %s\n", dumpdev); | ||||
} else { | } else { | ||||
fd = open(_PATH_DEVNULL, O_RDONLY); | fd = open(_PATH_DEVNULL, O_RDONLY); | ||||
if (fd < 0) | if (fd < 0) | ||||
err(EX_OSFILE, "%s", _PATH_DEVNULL); | err(EX_OSFILE, "%s", _PATH_DEVNULL); | ||||
u = 0; | |||||
i = ioctl(fd, DIOCSKERNELDUMP, &u); | kda.kda_enable = 0; | ||||
i = ioctl(fd, DIOCSKERNELDUMP, &kda); | |||||
explicit_bzero(&kda, sizeof(kda)); | |||||
Done Inline Actionsexplicit_bzero? delphij: explicit_bzero? | |||||
if (i == 0 && verbose) | if (i == 0 && verbose) | ||||
printf("kernel dumps disabled\n"); | printf("kernel dumps disabled\n"); | ||||
} | } | ||||
if (i < 0) | if (i < 0) | ||||
err(EX_OSERR, "ioctl(DIOCSKERNELDUMP)"); | err(EX_OSERR, "ioctl(DIOCSKERNELDUMP)"); | ||||
exit (0); | exit (0); | ||||
} | } |
errno check.