From f9b20fc804e13a9c1dcd70817708faf8cff9e29b Mon Sep 17 00:00:00 2001 From: Pawel Jakub Dawidek Date: Tue, 28 May 2013 21:25:28 +0000 Subject: [PATCH] MFp4 @229086: Make use of Capsicum to protect kdump(1), as it might be used to parse data from untrusted sources: - Sandbox kdump(1) using capability mode. - Limit stdin descriptor (where opened file is moved to) to only CAP_READ and CAP_FSTAT rights. - Limit stdout descriptor to only CAP_WRITE, CAP_FSTAT and CAP_IOCTL. Plus limit allowed ioctls to TIOCGETA only, which is needed for isatty() to work. - Limit stderr descriptor to only CAP_WRITE and CAP_FSTAT. In addition if the -s option is not given, grant CAP_IOCTL right, but allow for TIOCGWINSZ ioctl only, as we need screen width to dump the data. - Before entering capability mode call catopen("libc", NL_CAT_LOCALE), which opens message catalogs and caches data, so that strerror(3) and strsignal(3) can work in a sandbox. Sponsored by: The FreeBSD Foundation Discussed with: rwatson --- usr.bin/kdump/kdump.c | 50 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/usr.bin/kdump/kdump.c b/usr.bin/kdump/kdump.c index b06b4ab0a4c..0343a8cabca 100644 --- a/usr.bin/kdump/kdump.c +++ b/usr.bin/kdump/kdump.c @@ -46,6 +46,7 @@ extern int errno; #include #undef _KERNEL #include +#include #include #define _KERNEL #include @@ -73,10 +74,12 @@ extern int errno; #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -105,6 +108,7 @@ void ktrstruct(char *, size_t); void ktrcapfail(struct ktr_cap_fail *); void ktrfault(struct ktr_fault *); void ktrfaultend(struct ktr_faultend *); +void limitfd(int fd); void usage(void); void ioctlname(unsigned long, int); @@ -230,6 +234,18 @@ main(int argc, char *argv[]) errx(1, "%s", strerror(ENOMEM)); if (!freopen(tracefile, "r", stdin)) err(1, "%s", tracefile); + + /* + * Cache NLS data before entering capability mode. + * XXXPJD: There should be strerror_init() and strsignal_init() in libc. + */ + (void)catopen("libc", NL_CAT_LOCALE); + if (cap_enter() < 0 && errno != ENOSYS) + err(1, "unable to enter capability mode"); + limitfd(STDIN_FILENO); + limitfd(STDOUT_FILENO); + limitfd(STDERR_FILENO); + TAILQ_INIT(&trace_procs); drop_logged = 0; while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) { @@ -331,6 +347,40 @@ main(int argc, char *argv[]) return 0; } +void +limitfd(int fd) +{ + cap_rights_t rights; + unsigned long cmd; + + rights = CAP_FSTAT; + cmd = -1; + + switch (fd) { + case STDIN_FILENO: + rights |= CAP_READ; + break; + case STDOUT_FILENO: + rights |= CAP_IOCTL | CAP_WRITE; + cmd = TIOCGETA; /* required by isatty(3) in printf(3) */ + break; + case STDERR_FILENO: + rights |= CAP_WRITE; + if (!suppressdata) { + rights |= CAP_IOCTL; + cmd = TIOCGWINSZ; + } + break; + default: + abort(); + } + + if (cap_rights_limit(fd, rights) < 0 && errno != ENOSYS) + err(1, "unable to limit rights for descriptor %d", fd); + if (cmd != -1 && cap_ioctls_limit(fd, &cmd, 1) < 0 && errno != ENOSYS) + err(1, "unable to limit ioctls for descriptor %d", fd); +} + int fread_tail(void *buf, int size, int num) {