From a743806ea4868371cf182f783fdcfbf1b1f98202 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 13 Aug 2015 22:58:37 -0400 Subject: security: leverage namespaces to restrict the runtime a bit In practice this isn't terribly useful as people aren't attacking these tools, but might as well be paranoid. It'd be nice to use mount & net namespaces too, but they're way too slow. --- Makefile | 2 +- Makefile.am | 3 +++ dumpelf.c | 1 + paxinc.h | 1 + porting.h | 1 + pspax.c | 4 +++ scanelf.c | 5 ++++ scanmacho.c | 1 + security.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ security.h | 29 ++++++++++++++++++++ 10 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 security.c create mode 100644 security.h diff --git a/Makefile b/Makefile index ba3b6a2..ac5e9cc 100644 --- a/Makefile +++ b/Makefile @@ -61,7 +61,7 @@ ELF_TARGETS = scanelf dumpelf $(shell echo | $(CC) -dM -E - | grep -q __svr4__ ELF_OBJS = paxelf.o MACH_TARGETS = scanmacho MACH_OBJS = paxmacho.o -COMMON_OBJS = paxinc.o xfuncs.o +COMMON_OBJS = paxinc.o security.o xfuncs.o TARGETS = $(ELF_TARGETS) $(MACH_TARGETS) SCRIPTS_SH = lddtree symtree SCRIPTS_PY = lddtree diff --git a/Makefile.am b/Makefile.am index 5db3f75..e42dce4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -12,6 +12,7 @@ libpaxutils_la_SOURCES = \ paxelf.c \ paxinc.c \ paxmacho.c \ + security.c \ xfuncs.c LDADD = libpaxutils.la $(top_builddir)/autotools/gnulib/libgnu.a @@ -84,6 +85,8 @@ EXTRA_DIST += \ pspax.c \ scanelf.c \ scanmacho.c \ + security.c \ + security.h \ symtree.sh \ tests/Makefile \ tests/lddtree/Makefile \ diff --git a/dumpelf.c b/dumpelf.c index 3035b24..e9b1771 100644 --- a/dumpelf.c +++ b/dumpelf.c @@ -384,6 +384,7 @@ static void parseargs(int argc, char *argv[]) int main(int argc, char *argv[]) { + security_init(false); if (argc < 2) usage(EXIT_FAILURE); parseargs(argc, argv); diff --git a/paxinc.h b/paxinc.h index 0a8e08a..a8d6d9b 100644 --- a/paxinc.h +++ b/paxinc.h @@ -13,6 +13,7 @@ #include "porting.h" #include "xfuncs.h" +#include "security.h" #ifndef VERSION # define VERSION "git" diff --git a/porting.h b/porting.h index 1f989d2..9dea528 100644 --- a/porting.h +++ b/porting.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include diff --git a/pspax.c b/pspax.c index e27b7eb..c64472c 100644 --- a/pspax.c +++ b/pspax.c @@ -535,6 +535,10 @@ int main(int argc, char *argv[]) { char *name = NULL; + /* We unshare pidns but don't actually enter it. That means + * we still get to scan /proc, but just not fork children. */ + security_init(false); + color_init(false); parseargs(argc, argv); diff --git a/scanelf.c b/scanelf.c index 99192b2..7e3b077 100644 --- a/scanelf.c +++ b/scanelf.c @@ -2472,6 +2472,10 @@ static int parseargs(int argc, char *argv[]) } if (be_verbose > 2) printf("Format: %s\n", out_format); + /* Now lock down the pidns since we know whether we'll be forking. */ + if (!show_textrels || !be_verbose) + security_init_pid(); + /* now lets actually do the scanning */ if (load_cache_config) load_ld_cache_config(__PAX_UTILS_DEFAULT_LD_CACHE_CONFIG); @@ -2570,6 +2574,7 @@ static void cleanup(void) int main(int argc, char *argv[]) { int ret; + security_init(true); if (argc < 2) usage(EXIT_FAILURE); parseenv(); diff --git a/scanmacho.c b/scanmacho.c index ee713f9..5a0afd5 100644 --- a/scanmacho.c +++ b/scanmacho.c @@ -764,6 +764,7 @@ static int parseargs(int argc, char *argv[]) int main(int argc, char *argv[]) { int ret; + security_init(false); if (argc < 2) usage(EXIT_FAILURE); color_init(false); diff --git a/security.c b/security.c new file mode 100644 index 0000000..9b48a9a --- /dev/null +++ b/security.c @@ -0,0 +1,89 @@ +/* + * Copyright 2015 Gentoo Foundation + * Distributed under the terms of the GNU General Public License v2 + * + * Copyright 2015 Mike Frysinger - + */ + +#include "paxinc.h" + +#ifdef __linux__ + +#ifdef __SANITIZE_ADDRESS__ +/* ASAN does some weird stuff. */ +# define ALLOW_PIDNS 0 +#else +# define ALLOW_PIDNS 1 +#endif + +static int ns_unshare(int flags) +{ + int flag, ret = 0; + + /* Try to oneshot it. Maybe we'll get lucky! */ + if (unshare(flags) == 0) + return flags; + /* No access at all, so don't waste time below. */ + else if (errno == EPERM) + return ret; + + /* + * We have to run these one permission at a time because if any are + * not supported (too old a kernel, or it's disabled), then all of + * them will be rejected and we won't know which one is a problem. + */ + + /* First the ones that work against the current process. */ + flag = 1; + while (flags) { + if (flags & flag) { + if (unshare(flag) == 0) + ret |= flag; + flags &= ~flag; + } + flag <<= 1; + } + + return ret; +} + +void security_init_pid(void) +{ + int flags; + + if (!ALLOW_PIDNS) + return; + + flags = ns_unshare(CLONE_NEWPID); + if (USE_SLOW_SECURITY) { + if (flags & CLONE_NEWPID) + if (vfork() == 0) + _exit(0); + } +} + +void security_init(bool allow_forking) +{ + int flags; + + if (!ALLOW_PIDNS) + allow_forking = true; + + /* None of the pax tools need access to these features. */ + flags = CLONE_NEWIPC | CLONE_NEWUTS; + /* Would be nice to leverage mount/net ns, but they're just way too slow. */ + if (USE_SLOW_SECURITY) + flags |= CLONE_NEWNET | CLONE_NEWNS; + if (!allow_forking) + flags |= CLONE_NEWPID; + flags = ns_unshare(flags); + + if (USE_SLOW_SECURITY) { + /* We spawn one child and kill it so the kernel will fail in the future. */ + if (flags & CLONE_NEWPID) + if (vfork() == 0) + _exit(0); + } +} + +#endif diff --git a/security.h b/security.h new file mode 100644 index 0000000..c93ec3e --- /dev/null +++ b/security.h @@ -0,0 +1,29 @@ +/* Various security related features. + * + * Copyright 2015 Gentoo Foundation + * Distributed under the terms of the GNU General Public License v2 + * + * Copyright 2015 Mike Frysinger - + */ + +#ifndef _PAX_SECURITY_H +#define _PAX_SECURITY_H + +/* Whether to enable features that significantly impact speed. */ +#ifdef SLOW_SECURITY +# define USE_SLOW_SECURITY 1 +#else +# define USE_SLOW_SECURITY 0 +#endif + +#ifdef __linux__ +/* Lock down the runtime; allow_forking controls whether to use a pidns. */ +void security_init(bool allow_forking); +/* Disable forking; usable only when allow_forking above was true. */ +void security_init_pid(void); +#else +static inline void security_init(bool allow_forking) {} +static inline void security_init_pid(void) {} +#endif + +#endif -- cgit v1.2.3-18-g5258