* [PATCH v1 0/2] Support dropping of capabilities from early userspace.
@ 2011-07-19 20:38 Mike Waychison
2011-07-19 20:38 ` [PATCH v1 1/2] syscalls: Add capset and capget Mike Waychison
2011-07-19 20:38 ` [PATCH v1 2/2] run-init: Add drop_capabilities support Mike Waychison
0 siblings, 2 replies; 13+ messages in thread
From: Mike Waychison @ 2011-07-19 20:38 UTC (permalink / raw)
To: Andrew G. Morgan, Maximilian Attems, Eric Northup, Alan Cox,
H. Peter Anvin
Cc: Eric Paris, klibc, linux-kernel
This patchset applies to klibc mainline. As is it will probably collide
with Maximilian's recent patch to rename run-init to switch_root posted
last week.
To boot an untrusted environment with certain capabilities locked out,
we'd like to be able to drop the capabilities up front from early
userspace, before we actually transition onto the root volume.
This patchset implements this by adding a "drop capabilities" ability to
both kinit and run-init in the klibc package. For kinit, it now
understands a new kernel command line option, "drop_capabilities" that
specifies a comma separated list of capability names that should be
dropped right before execing the next init binary on the next root
device.
run-init also has the ability to use this drop_capabilities function by
specifying capabilities that should be dropped with a new command line
flag, '-d'.
Given that this patchset is meant to help secure boots, we treat any
errors as total failure to boot by exiting the process with a failing
exit code.
Thanks,
Mike Waychison
Related discussions
===================
- Thread discussing my wanting to compile out kernel interfaces that
we do not want to expose to the userspace environment, with Alan
Cox convincing me that I really just want to disable certain
capabilities:
https://lkml.org/lkml/2011/7/15/412
Patchset summary
================
syscalls: Add capset and capget
run-init: Add drop_capabilities support.
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH v1 1/2] syscalls: Add capset and capget 2011-07-19 20:38 [PATCH v1 0/2] Support dropping of capabilities from early userspace Mike Waychison @ 2011-07-19 20:38 ` Mike Waychison 2011-07-29 20:41 ` Maximilian Attems 2011-07-29 23:06 ` Maximilian Attems 2011-07-19 20:38 ` [PATCH v1 2/2] run-init: Add drop_capabilities support Mike Waychison 1 sibling, 2 replies; 13+ messages in thread From: Mike Waychison @ 2011-07-19 20:38 UTC (permalink / raw) To: Andrew G. Morgan, Maximilian Attems, Eric Northup, Alan Cox, H. Peter Anvin Cc: Eric Paris, klibc, linux-kernel Add the capset and capget system calls to klibc so that userland can invoke them. Signed-off-by: Mike Waychison <mikew@google.com> --- usr/include/sys/capability.h | 10 ++++++++++ usr/klibc/SYSCALLS.def | 6 ++++++ usr/klibc/syscalls/syscommon.h | 1 + 3 files changed, 17 insertions(+), 0 deletions(-) create mode 100644 usr/include/sys/capability.h diff --git a/usr/include/sys/capability.h b/usr/include/sys/capability.h new file mode 100644 index 0000000..84ad419 --- /dev/null +++ b/usr/include/sys/capability.h @@ -0,0 +1,10 @@ +#ifndef _SYS_CAPABILITY_H +#define _SYS_CAPABILITY_H + +#include <klibc/extern.h> +#include <linux/capability.h> + +__extern int capget(cap_user_header_t hdrp, cap_user_data_t datap); +__extern int capset(cap_user_header_t hdrp, const cap_user_data_t datap); + +#endif /* _SYS_CAPABILITY_H */ diff --git a/usr/klibc/SYSCALLS.def b/usr/klibc/SYSCALLS.def index d3279c7..ee3ffa9 100644 --- a/usr/klibc/SYSCALLS.def +++ b/usr/klibc/SYSCALLS.def @@ -77,6 +77,12 @@ int setfsgid32,setfsgid::setfsgid(gid_t); int setresuid32,setresuid::setresuid(int, uid_t, uid_t, uid_t); /* + * POSIX Capabilities + */ +int capget(cap_user_header_t, cap_user_data_t); +int capset(cap_user_header_t, cap_user_data_t); + +/* * Filesystem-related system calls */ int mount(const char *, const char *, const char *, unsigned long, const void *); diff --git a/usr/klibc/syscalls/syscommon.h b/usr/klibc/syscalls/syscommon.h index 0acae12..78f8858 100644 --- a/usr/klibc/syscalls/syscommon.h +++ b/usr/klibc/syscalls/syscommon.h @@ -12,6 +12,7 @@ #include <poll.h> #include <sched.h> +#include <sys/capability.h> #include <sys/dirent.h> #include <sys/klog.h> #include <sys/mman.h> ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v1 1/2] syscalls: Add capset and capget 2011-07-19 20:38 ` [PATCH v1 1/2] syscalls: Add capset and capget Mike Waychison @ 2011-07-29 20:41 ` Maximilian Attems 2011-07-29 23:06 ` Maximilian Attems 1 sibling, 0 replies; 13+ messages in thread From: Maximilian Attems @ 2011-07-29 20:41 UTC (permalink / raw) To: Mike Waychison Cc: Andrew G. Morgan, Eric Northup, Alan Cox, H. Peter Anvin, Eric Paris, klibc, linux-kernel On Tue, 19 Jul 2011, Mike Waychison wrote: > Add the capset and capget system calls to klibc so that userland can > invoke them. > > Signed-off-by: Mike Waychison <mikew@google.com> > --- > usr/include/sys/capability.h | 10 ++++++++++ > usr/klibc/SYSCALLS.def | 6 ++++++ > usr/klibc/syscalls/syscommon.h | 1 + > 3 files changed, 17 insertions(+), 0 deletions(-) > create mode 100644 usr/include/sys/capability.h > > diff --git a/usr/include/sys/capability.h b/usr/include/sys/capability.h > new file mode 100644 > index 0000000..84ad419 > --- /dev/null > +++ b/usr/include/sys/capability.h > @@ -0,0 +1,10 @@ > +#ifndef _SYS_CAPABILITY_H > +#define _SYS_CAPABILITY_H > + > +#include <klibc/extern.h> > +#include <linux/capability.h> > + > +__extern int capget(cap_user_header_t hdrp, cap_user_data_t datap); > +__extern int capset(cap_user_header_t hdrp, const cap_user_data_t datap); > + > +#endif /* _SYS_CAPABILITY_H */ > diff --git a/usr/klibc/SYSCALLS.def b/usr/klibc/SYSCALLS.def > index d3279c7..ee3ffa9 100644 > --- a/usr/klibc/SYSCALLS.def > +++ b/usr/klibc/SYSCALLS.def > @@ -77,6 +77,12 @@ int setfsgid32,setfsgid::setfsgid(gid_t); > int setresuid32,setresuid::setresuid(int, uid_t, uid_t, uid_t); > > /* > + * POSIX Capabilities > + */ > +int capget(cap_user_header_t, cap_user_data_t); > +int capset(cap_user_header_t, cap_user_data_t); > + > +/* > * Filesystem-related system calls > */ > int mount(const char *, const char *, const char *, unsigned long, const void *); > diff --git a/usr/klibc/syscalls/syscommon.h b/usr/klibc/syscalls/syscommon.h > index 0acae12..78f8858 100644 > --- a/usr/klibc/syscalls/syscommon.h > +++ b/usr/klibc/syscalls/syscommon.h > @@ -12,6 +12,7 @@ > > #include <poll.h> > #include <sched.h> > +#include <sys/capability.h> > #include <sys/dirent.h> > #include <sys/klog.h> > #include <sys/mman.h> this looks good to me. thanks will add to klibc repo soonest. -- maks ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v1 1/2] syscalls: Add capset and capget 2011-07-19 20:38 ` [PATCH v1 1/2] syscalls: Add capset and capget Mike Waychison 2011-07-29 20:41 ` Maximilian Attems @ 2011-07-29 23:06 ` Maximilian Attems 1 sibling, 0 replies; 13+ messages in thread From: Maximilian Attems @ 2011-07-29 23:06 UTC (permalink / raw) To: Mike Waychison Cc: Andrew G. Morgan, Eric Northup, Alan Cox, H. Peter Anvin, Eric Paris, klibc, linux-kernel On Tue, 19 Jul 2011, Mike Waychison wrote: > Add the capset and capget system calls to klibc so that userland can > invoke them. > > Signed-off-by: Mike Waychison <mikew@google.com> > --- > usr/include/sys/capability.h | 10 ++++++++++ > usr/klibc/SYSCALLS.def | 6 ++++++ > usr/klibc/syscalls/syscommon.h | 1 + > 3 files changed, 17 insertions(+), 0 deletions(-) > create mode 100644 usr/include/sys/capability.h > applied and pushed. thank you. -- maks ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v1 2/2] run-init: Add drop_capabilities support. 2011-07-19 20:38 [PATCH v1 0/2] Support dropping of capabilities from early userspace Mike Waychison 2011-07-19 20:38 ` [PATCH v1 1/2] syscalls: Add capset and capget Mike Waychison @ 2011-07-19 20:38 ` Mike Waychison 2011-07-29 20:45 ` Maximilian Attems 1 sibling, 1 reply; 13+ messages in thread From: Mike Waychison @ 2011-07-19 20:38 UTC (permalink / raw) To: Andrew G. Morgan, Maximilian Attems, Eric Northup, Alan Cox, H. Peter Anvin Cc: Eric Paris, klibc, linux-kernel This patch adds the ability to run-init to allow the dropping of POSIX capabilities. This works by adding a "-d" flag to run-init, which takes a comma separated list of capability names that should be dropped right before exec'ing the real init binary. kinit is also modified by this change, such that it understands the same argument when prepended with "drop_capabilities=" on the kernel command line. When processing capabilities to drop, CAP_SETPCAP is special cased to be dropped last, so that the order that capabilities are given does not cause dropping of later enumerated capabilities to fail if it is listed early on. Dropping of capabilities happens in three parts. We explicitly drop the capability from init's inherited, permitted and effective masks. We also drop the capability from the bounding set using PR_CAPBSET_DROP. Lastly, if available, we drop the capabilities from the bset and inheritted masks exposed at /proc/sys/kernel/usermodehelper if available (introduced in v3.0.0). In all paths, we treat errors as fatal, as we do not want to continue to boot if there was a problem dropping capabilities. The only exception to this rule is the handling of /proc/sys/kernel/usermodehelper, where we print out a warning if we notice that the kernel is new enough to support this interface, but could not find the proc file (as it may or may not be available after the pivot, depending on early portions of the boot strap process). Signed-off-by: Mike Waychison <mikew@google.com> --- usr/kinit/kinit.c | 4 - usr/kinit/run-init/Kbuild | 2 usr/kinit/run-init/capabilities.c | 278 +++++++++++++++++++++++++++++++++++++ usr/kinit/run-init/capabilities.h | 6 + usr/kinit/run-init/run-init.c | 11 + usr/kinit/run-init/run-init.h | 3 usr/kinit/run-init/runinitlib.c | 11 + 7 files changed, 307 insertions(+), 8 deletions(-) create mode 100644 usr/kinit/run-init/capabilities.c create mode 100644 usr/kinit/run-init/capabilities.h diff --git a/usr/kinit/kinit.c b/usr/kinit/kinit.c index 4a1f40b..ae50ed6 100644 --- a/usr/kinit/kinit.c +++ b/usr/kinit/kinit.c @@ -307,7 +307,9 @@ int main(int argc, char *argv[]) init_argv[0] = strrchr(init_path, '/') + 1; - errmsg = run_init("/root", "/dev/console", init_path, init_argv); + errmsg = run_init("/root", "/dev/console", + get_arg(cmdc, cmdv, "drop_capabilities="), + init_path, init_argv); /* If run_init returned, something went bad */ fprintf(stderr, "%s: %s: %s\n", progname, errmsg, strerror(errno)); diff --git a/usr/kinit/run-init/Kbuild b/usr/kinit/run-init/Kbuild index bf6e140..6451dd4 100644 --- a/usr/kinit/run-init/Kbuild +++ b/usr/kinit/run-init/Kbuild @@ -6,7 +6,7 @@ static-y := static/run-init shared-y := shared/run-init # common .o files -objs := run-init.o runinitlib.o +objs := run-init.o runinitlib.o capabilities.o # TODO - do we want a stripped version # TODO - do we want the static.g + shared.g directories? diff --git a/usr/kinit/run-init/capabilities.c b/usr/kinit/run-init/capabilities.c new file mode 100644 index 0000000..d262c01 --- /dev/null +++ b/usr/kinit/run-init/capabilities.c @@ -0,0 +1,278 @@ +/* + * Copyright 2011 Google Inc. All Rights Reserved + * Author: mikew@google.com (Mike Waychison) + */ + +/* + * We have to include the klibc types.h here to keep the kernel's + * types.h from being used. + */ +#include <sys/types.h> + +#include <linux/version.h> +#include <sys/capability.h> +#include <sys/prctl.h> +#include <sys/utsname.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "capabilities.h" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +#define MAKE_CAP(cap) [cap] = { .cap_name = #cap } + +struct capability { + const char *cap_name; +} capabilities[] = { + MAKE_CAP(CAP_CHOWN), + MAKE_CAP(CAP_DAC_OVERRIDE), + MAKE_CAP(CAP_DAC_READ_SEARCH), + MAKE_CAP(CAP_FOWNER), + MAKE_CAP(CAP_FSETID), + MAKE_CAP(CAP_KILL), + MAKE_CAP(CAP_SETGID), + MAKE_CAP(CAP_SETUID), + MAKE_CAP(CAP_SETPCAP), + MAKE_CAP(CAP_LINUX_IMMUTABLE), + MAKE_CAP(CAP_NET_BIND_SERVICE), + MAKE_CAP(CAP_NET_BROADCAST), + MAKE_CAP(CAP_NET_ADMIN), + MAKE_CAP(CAP_NET_RAW), + MAKE_CAP(CAP_IPC_LOCK), + MAKE_CAP(CAP_IPC_OWNER), + MAKE_CAP(CAP_SYS_MODULE), + MAKE_CAP(CAP_SYS_RAWIO), + MAKE_CAP(CAP_SYS_CHROOT), + MAKE_CAP(CAP_SYS_PTRACE), + MAKE_CAP(CAP_SYS_PACCT), + MAKE_CAP(CAP_SYS_ADMIN), + MAKE_CAP(CAP_SYS_BOOT), + MAKE_CAP(CAP_SYS_NICE), + MAKE_CAP(CAP_SYS_RESOURCE), + MAKE_CAP(CAP_SYS_TIME), + MAKE_CAP(CAP_SYS_TTY_CONFIG), + MAKE_CAP(CAP_MKNOD), + MAKE_CAP(CAP_LEASE), + MAKE_CAP(CAP_AUDIT_WRITE), + MAKE_CAP(CAP_AUDIT_CONTROL), + MAKE_CAP(CAP_SETFCAP), + MAKE_CAP(CAP_MAC_OVERRIDE), + MAKE_CAP(CAP_MAC_ADMIN), + MAKE_CAP(CAP_SYSLOG), +}; + +static void fail(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + exit(1); +} + +/* + * Returns the currently running kernel version X.Y.Z in a format + * compatible with the KERNEL_VERSION macro. + */ +static unsigned kernel_version(void) +{ + struct utsname utsname; + int ret; + unsigned char version, patchlevel, sublevel; + + ret = uname(&utsname); + if (ret != 0) + fail("uname returned %d\n", ret); + + ret = sscanf(utsname.release, "%hhu.%hhu.%hhu", + &version, &patchlevel, &sublevel); + if (ret != 3) { + /* Try two level name? */ + sublevel = 0; + ret = sscanf(utsname.release, "%hhu.%hhu", + &version, &patchlevel); + if (ret != 2) + fail("Couldn't parse kernel version \"%s\"\n", + utsname.release); + } + + return KERNEL_VERSION(version, patchlevel, sublevel); +} + +/* + * Find the capability ordinal by name, and return its ordinal. + * Returns -1 on failure. + */ +static int find_capability(const char *s) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(capabilities); i++) { + if (capabilities[i].cap_name + && strcasecmp(s, capabilities[i].cap_name) == 0) { + return i; + } + } + return -1; +} + +static void do_capset(int cap_ordinal) +{ + struct __user_cap_header_struct hdr; + struct __user_cap_data_struct caps[2]; + + /* Get the current capability mask */ + hdr.version = _LINUX_CAPABILITY_VERSION_3; + hdr.pid = getpid(); + if (capget(&hdr, caps)) { + perror("capget()"); + exit(1); + } + + /* Drop the bits */ + if (cap_ordinal < 32) { + caps[0].effective &= ~(1U << cap_ordinal); + caps[0].permitted &= ~(1U << cap_ordinal); + caps[0].inheritable &= ~(1U << cap_ordinal); + } else { + caps[1].effective &= ~(1U << (cap_ordinal - 32)); + caps[1].permitted &= ~(1U << (cap_ordinal - 32)); + caps[1].inheritable &= ~(1U << (cap_ordinal - 32)); + } + + /* And drop the capability. */ + hdr.version = _LINUX_CAPABILITY_VERSION_3; + hdr.pid = getpid(); + if (capset(&hdr, caps)) + fail("Couldn't drop the capability \"%s\"\n", + capabilities[cap_ordinal].cap_name); +} + +static void do_bset(int cap_ordinal) +{ + int ret; + + ret = prctl(PR_CAPBSET_READ, cap_ordinal); + if (ret == 1) { + ret = prctl(PR_CAPBSET_DROP, cap_ordinal); + if (ret != 0) + fail("Error dropping capability %s from bset\n", + capabilities[cap_ordinal].cap_name); + } else if (ret < 0) + fail("Kernel doesn't recognize capability %d\n", cap_ordinal); +} + +static void do_usermodehelper_file(const char *filename, int cap_ordinal) +{ + uint32_t lo32, hi32; + FILE *file; + static const size_t buf_size = 80; + char buf[buf_size]; + char tail; + size_t bytes_read; + int ret; + + /* Try and open the file */ + file = fopen(filename, "r+"); + if (!file && errno == ENOENT) { + /* Check if this kernel even supports this interface. */ + if (kernel_version() >= KERNEL_VERSION(3, 0, 0)) { + static int printed_once; + if (!printed_once++) + fprintf(stderr, "WARNING: Could not disable " + "capabilities for usermode helpers!\n"); + } + return; + } + if (!file) + fail("Failed to access file %s errno %d\n", filename, errno); + + /* Read and process the current bits */ + bytes_read = fread(buf, 1, buf_size - 1, file); + if (bytes_read == 0) + fail("Trouble reading %s\n", filename); + buf[bytes_read] = '\0'; + ret = sscanf(buf, "%u %u%c", &lo32, &hi32, &tail); + if (ret != 2) + fail("Failed to understand %s\n", filename); + + /* Clear the bits in the local copy */ + if (cap_ordinal < 32) + lo32 &= ~(1 << cap_ordinal); + else + hi32 &= ~(1 << (cap_ordinal - 32)); + + /* Commit the new bit masks to the kernel */ + sprintf(buf, "%u %u", lo32, hi32); + ret = fwrite(buf, 1, strlen(buf) + 1, file); + if (ret != strlen(buf) + 1) + fail("Failed to commit usermode helper bitmasks: %d\n", ret); + + /* Cleanup */ + fclose(file); +} + +static void do_usermodehelper(int cap_ordinal) +{ + static const char * const files[] = { + "/proc/sys/kernel/bset", + "/proc/sys/kernel/inheritable", + }; + int i; + + for (i = 0; i < ARRAY_SIZE(files); i++) + do_usermodehelper_file(files[i], cap_ordinal); +} + +static void drop_capability(int cap_ordinal) +{ + do_usermodehelper(cap_ordinal); + do_bset(cap_ordinal); + do_capset(cap_ordinal); + + printf("Dropped capability: %s\n", capabilities[cap_ordinal].cap_name); +} + +int do_capabilities(const char *drop_capabilities) +{ + char *s, *saveptr = NULL; + char *token; + int drop_setpcap = 0; + + if (!drop_capabilities) + return 0; + + /* Create a duplicate string that can be modified. */ + s = strdup(drop_capabilities); + if (!s) + fail("Failed to drop caps as requested. Exiting\n"); + + token = strtok_r(s, ",", &saveptr); + while (token) { + int cap_ordinal = find_capability(token); + + if (cap_ordinal < 0) + fail("Could not understand capability name \"%s\" " + "on command line, failing init\n", token); + + /* We handle CAP_SETPCAP last because it is needed to + * drop all other caps. */ + if (cap_ordinal == CAP_SETPCAP) + drop_setpcap = 1; + else + drop_capability(cap_ordinal); + + token = strtok_r(NULL, ",", &saveptr); + } + + if (drop_setpcap) + drop_capability(CAP_SETPCAP); + + free(s); + return 0; +} diff --git a/usr/kinit/run-init/capabilities.h b/usr/kinit/run-init/capabilities.h new file mode 100644 index 0000000..bf51eec --- /dev/null +++ b/usr/kinit/run-init/capabilities.h @@ -0,0 +1,6 @@ +#ifndef CAPABILITIES_H +#define CAPABILITIES_H + +int do_capabilities(const char *drop_capabilities); + +#endif /* CAPABILITIES_H */ diff --git a/usr/kinit/run-init/run-init.c b/usr/kinit/run-init/run-init.c index 0f150dd..cc602ef 100644 --- a/usr/kinit/run-init/run-init.c +++ b/usr/kinit/run-init/run-init.c @@ -35,6 +35,7 @@ * - Remounts /real-root onto the root filesystem; * - Chroots; * - Opens /dev/console; + * - Drops capabilities * - Spawns the specified init program (with arguments.) */ @@ -50,7 +51,8 @@ static const char *program; static void __attribute__ ((noreturn)) usage(void) { fprintf(stderr, - "Usage: exec %s [-c consoledev] /real-root /sbin/init [args]\n", + "Usage: exec %s [-c consoledev] [-d <CAP_NAME,...>] " + "/real-root /sbin/init [args]\n", program); exit(1); } @@ -62,6 +64,7 @@ int main(int argc, char *argv[]) const char *realroot; const char *init; const char *error; + const char *drop_capabilities = NULL; char **initargs; /* Variables... */ @@ -70,9 +73,11 @@ int main(int argc, char *argv[]) /* Parse the command line */ program = argv[0]; - while ((o = getopt(argc, argv, "c:")) != -1) { + while ((o = getopt(argc, argv, "c:d:")) != -1) { if (o == 'c') { console = optarg; + } else if (o == 'd') { + drop_capabilities = optarg; } else { usage(); } @@ -85,7 +90,7 @@ int main(int argc, char *argv[]) init = argv[optind + 1]; initargs = argv + optind + 1; - error = run_init(realroot, console, init, initargs); + error = run_init(realroot, console, drop_capabilities, init, initargs); /* If run_init returns, something went wrong */ fprintf(stderr, "%s: %s: %s\n", program, error, strerror(errno)); diff --git a/usr/kinit/run-init/run-init.h b/usr/kinit/run-init/run-init.h index a95328e..30f78bf 100644 --- a/usr/kinit/run-init/run-init.h +++ b/usr/kinit/run-init/run-init.h @@ -29,6 +29,7 @@ #define RUN_INIT_H const char *run_init(const char *realroot, const char *console, - const char *init, char **initargs); + const char *drop_capabilities, const char *init, + char **initargs); #endif diff --git a/usr/kinit/run-init/runinitlib.c b/usr/kinit/run-init/runinitlib.c index 8f1562f..a5cb10c 100644 --- a/usr/kinit/run-init/runinitlib.c +++ b/usr/kinit/run-init/runinitlib.c @@ -26,7 +26,7 @@ * ----------------------------------------------------------------------- */ /* - * run_init(consoledev, realroot, init, initargs) + * run_init(consoledev, realroot, drop_capabilities, init, initargs) * * This function should be called as the last thing in kinit, * from initramfs, it does the following: @@ -35,6 +35,7 @@ * - Remounts /real-root onto the root filesystem; * - Chroots; * - Opens /dev/console; + * - Drops capabilities if needed; * - Spawns the specified init program (with arguments.) * * On failure, returns a human-readable error message. @@ -52,7 +53,9 @@ #include <sys/stat.h> #include <sys/types.h> #include <sys/vfs.h> + #include "run-init.h" +#include "capabilities.h" /* Make it possible to compile on glibc by including constants that the always-behind shipped glibc headers may not include. Classic example @@ -154,7 +157,8 @@ static int nuke(const char *what) } const char *run_init(const char *realroot, const char *console, - const char *init, char **initargs) + const char *drop_capabilities, const char *init, + char **initargs) { struct stat rst, cst; struct statfs sfs; @@ -203,6 +207,9 @@ const char *run_init(const char *realroot, const char *console, dup2(confd, 2); close(confd); + /* Drop capabilities */ + do_capabilities(drop_capabilities); + /* Spawn init */ execv(init, initargs); return init; /* Failed to spawn init */ ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v1 2/2] run-init: Add drop_capabilities support. 2011-07-19 20:38 ` [PATCH v1 2/2] run-init: Add drop_capabilities support Mike Waychison @ 2011-07-29 20:45 ` Maximilian Attems 2011-07-29 20:46 ` Mike Waychison 0 siblings, 1 reply; 13+ messages in thread From: Maximilian Attems @ 2011-07-29 20:45 UTC (permalink / raw) To: Mike Waychison Cc: Andrew G. Morgan, Eric Northup, Alan Cox, H. Peter Anvin, Eric Paris, klibc, linux-kernel On Tue, 19 Jul 2011, Mike Waychison wrote: > This patch adds the ability to run-init to allow the dropping of > POSIX capabilities. > > This works by adding a "-d" flag to run-init, which takes a comma > separated list of capability names that should be dropped right before > exec'ing the real init binary. > > kinit is also modified by this change, such that it understands the same > argument when prepended with "drop_capabilities=" on the kernel command > line. > > When processing capabilities to drop, CAP_SETPCAP is special cased to be > dropped last, so that the order that capabilities are given does not > cause dropping of later enumerated capabilities to fail if it is listed > early on. > > Dropping of capabilities happens in three parts. We explicitly drop the > capability from init's inherited, permitted and effective masks. We > also drop the capability from the bounding set using PR_CAPBSET_DROP. > Lastly, if available, we drop the capabilities from the bset and > inheritted masks exposed at /proc/sys/kernel/usermodehelper if available > (introduced in v3.0.0). hmm as 3.0 is out, I don't think we need more backward compatibility. do you have a strong arg for it? especially since this is an *optional* calling arg I really don't see the need of that backward crap. > In all paths, we treat errors as fatal, as we do not want to continue to > boot if there was a problem dropping capabilities. The only exception > to this rule is the handling of /proc/sys/kernel/usermodehelper, where > we print out a warning if we notice that the kernel is new enough to > support this interface, but could not find the proc file (as it may or > may not be available after the pivot, depending on early portions of the > boot strap process). > > Signed-off-by: Mike Waychison <mikew@google.com> > --- > usr/kinit/kinit.c | 4 - > usr/kinit/run-init/Kbuild | 2 > usr/kinit/run-init/capabilities.c | 278 +++++++++++++++++++++++++++++++++++++ > usr/kinit/run-init/capabilities.h | 6 + > usr/kinit/run-init/run-init.c | 11 + > usr/kinit/run-init/run-init.h | 3 > usr/kinit/run-init/runinitlib.c | 11 + > 7 files changed, 307 insertions(+), 8 deletions(-) > create mode 100644 usr/kinit/run-init/capabilities.c > create mode 100644 usr/kinit/run-init/capabilities.h > > diff --git a/usr/kinit/kinit.c b/usr/kinit/kinit.c > index 4a1f40b..ae50ed6 100644 > --- a/usr/kinit/kinit.c > +++ b/usr/kinit/kinit.c > @@ -307,7 +307,9 @@ int main(int argc, char *argv[]) > > init_argv[0] = strrchr(init_path, '/') + 1; > > - errmsg = run_init("/root", "/dev/console", init_path, init_argv); > + errmsg = run_init("/root", "/dev/console", > + get_arg(cmdc, cmdv, "drop_capabilities="), > + init_path, init_argv); > > /* If run_init returned, something went bad */ > fprintf(stderr, "%s: %s: %s\n", progname, errmsg, strerror(errno)); > diff --git a/usr/kinit/run-init/Kbuild b/usr/kinit/run-init/Kbuild > index bf6e140..6451dd4 100644 > --- a/usr/kinit/run-init/Kbuild > +++ b/usr/kinit/run-init/Kbuild > @@ -6,7 +6,7 @@ static-y := static/run-init > shared-y := shared/run-init > > # common .o files > -objs := run-init.o runinitlib.o > +objs := run-init.o runinitlib.o capabilities.o > > # TODO - do we want a stripped version > # TODO - do we want the static.g + shared.g directories? > diff --git a/usr/kinit/run-init/capabilities.c b/usr/kinit/run-init/capabilities.c > new file mode 100644 > index 0000000..d262c01 > --- /dev/null > +++ b/usr/kinit/run-init/capabilities.c > @@ -0,0 +1,278 @@ > +/* > + * Copyright 2011 Google Inc. All Rights Reserved > + * Author: mikew@google.com (Mike Waychison) > + */ > + > +/* > + * We have to include the klibc types.h here to keep the kernel's > + * types.h from being used. > + */ > +#include <sys/types.h> > + > +#include <linux/version.h> > +#include <sys/capability.h> > +#include <sys/prctl.h> > +#include <sys/utsname.h> > +#include <errno.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > + > +#include "capabilities.h" > + > +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) > + > +#define MAKE_CAP(cap) [cap] = { .cap_name = #cap } > + > +struct capability { > + const char *cap_name; > +} capabilities[] = { > + MAKE_CAP(CAP_CHOWN), > + MAKE_CAP(CAP_DAC_OVERRIDE), > + MAKE_CAP(CAP_DAC_READ_SEARCH), > + MAKE_CAP(CAP_FOWNER), > + MAKE_CAP(CAP_FSETID), > + MAKE_CAP(CAP_KILL), > + MAKE_CAP(CAP_SETGID), > + MAKE_CAP(CAP_SETUID), > + MAKE_CAP(CAP_SETPCAP), > + MAKE_CAP(CAP_LINUX_IMMUTABLE), > + MAKE_CAP(CAP_NET_BIND_SERVICE), > + MAKE_CAP(CAP_NET_BROADCAST), > + MAKE_CAP(CAP_NET_ADMIN), > + MAKE_CAP(CAP_NET_RAW), > + MAKE_CAP(CAP_IPC_LOCK), > + MAKE_CAP(CAP_IPC_OWNER), > + MAKE_CAP(CAP_SYS_MODULE), > + MAKE_CAP(CAP_SYS_RAWIO), > + MAKE_CAP(CAP_SYS_CHROOT), > + MAKE_CAP(CAP_SYS_PTRACE), > + MAKE_CAP(CAP_SYS_PACCT), > + MAKE_CAP(CAP_SYS_ADMIN), > + MAKE_CAP(CAP_SYS_BOOT), > + MAKE_CAP(CAP_SYS_NICE), > + MAKE_CAP(CAP_SYS_RESOURCE), > + MAKE_CAP(CAP_SYS_TIME), > + MAKE_CAP(CAP_SYS_TTY_CONFIG), > + MAKE_CAP(CAP_MKNOD), > + MAKE_CAP(CAP_LEASE), > + MAKE_CAP(CAP_AUDIT_WRITE), > + MAKE_CAP(CAP_AUDIT_CONTROL), > + MAKE_CAP(CAP_SETFCAP), > + MAKE_CAP(CAP_MAC_OVERRIDE), > + MAKE_CAP(CAP_MAC_ADMIN), > + MAKE_CAP(CAP_SYSLOG), > +}; > + > +static void fail(const char *fmt, ...) > +{ > + va_list args; > + > + va_start(args, fmt); > + vfprintf(stderr, fmt, args); > + va_end(args); > + exit(1); > +} > + > +/* > + * Returns the currently running kernel version X.Y.Z in a format > + * compatible with the KERNEL_VERSION macro. > + */ > +static unsigned kernel_version(void) > +{ > + struct utsname utsname; > + int ret; > + unsigned char version, patchlevel, sublevel; > + > + ret = uname(&utsname); > + if (ret != 0) > + fail("uname returned %d\n", ret); > + > + ret = sscanf(utsname.release, "%hhu.%hhu.%hhu", > + &version, &patchlevel, &sublevel); > + if (ret != 3) { > + /* Try two level name? */ > + sublevel = 0; > + ret = sscanf(utsname.release, "%hhu.%hhu", > + &version, &patchlevel); > + if (ret != 2) > + fail("Couldn't parse kernel version \"%s\"\n", > + utsname.release); > + } > + > + return KERNEL_VERSION(version, patchlevel, sublevel); > +} > + > +/* > + * Find the capability ordinal by name, and return its ordinal. > + * Returns -1 on failure. > + */ > +static int find_capability(const char *s) > +{ > + int i; > + > + for (i = 0; i < ARRAY_SIZE(capabilities); i++) { > + if (capabilities[i].cap_name > + && strcasecmp(s, capabilities[i].cap_name) == 0) { > + return i; > + } > + } > + return -1; > +} > + > +static void do_capset(int cap_ordinal) > +{ > + struct __user_cap_header_struct hdr; > + struct __user_cap_data_struct caps[2]; > + > + /* Get the current capability mask */ > + hdr.version = _LINUX_CAPABILITY_VERSION_3; > + hdr.pid = getpid(); > + if (capget(&hdr, caps)) { > + perror("capget()"); > + exit(1); > + } > + > + /* Drop the bits */ > + if (cap_ordinal < 32) { > + caps[0].effective &= ~(1U << cap_ordinal); > + caps[0].permitted &= ~(1U << cap_ordinal); > + caps[0].inheritable &= ~(1U << cap_ordinal); > + } else { > + caps[1].effective &= ~(1U << (cap_ordinal - 32)); > + caps[1].permitted &= ~(1U << (cap_ordinal - 32)); > + caps[1].inheritable &= ~(1U << (cap_ordinal - 32)); > + } > + > + /* And drop the capability. */ > + hdr.version = _LINUX_CAPABILITY_VERSION_3; > + hdr.pid = getpid(); > + if (capset(&hdr, caps)) > + fail("Couldn't drop the capability \"%s\"\n", > + capabilities[cap_ordinal].cap_name); > +} > + > +static void do_bset(int cap_ordinal) > +{ > + int ret; > + > + ret = prctl(PR_CAPBSET_READ, cap_ordinal); > + if (ret == 1) { > + ret = prctl(PR_CAPBSET_DROP, cap_ordinal); > + if (ret != 0) > + fail("Error dropping capability %s from bset\n", > + capabilities[cap_ordinal].cap_name); > + } else if (ret < 0) > + fail("Kernel doesn't recognize capability %d\n", cap_ordinal); > +} > + > +static void do_usermodehelper_file(const char *filename, int cap_ordinal) > +{ > + uint32_t lo32, hi32; > + FILE *file; > + static const size_t buf_size = 80; > + char buf[buf_size]; > + char tail; > + size_t bytes_read; > + int ret; > + > + /* Try and open the file */ > + file = fopen(filename, "r+"); > + if (!file && errno == ENOENT) { > + /* Check if this kernel even supports this interface. */ > + if (kernel_version() >= KERNEL_VERSION(3, 0, 0)) { > + static int printed_once; > + if (!printed_once++) > + fprintf(stderr, "WARNING: Could not disable " > + "capabilities for usermode helpers!\n"); > + } > + return; > + } > + if (!file) > + fail("Failed to access file %s errno %d\n", filename, errno); > + > + /* Read and process the current bits */ > + bytes_read = fread(buf, 1, buf_size - 1, file); > + if (bytes_read == 0) > + fail("Trouble reading %s\n", filename); > + buf[bytes_read] = '\0'; > + ret = sscanf(buf, "%u %u%c", &lo32, &hi32, &tail); > + if (ret != 2) > + fail("Failed to understand %s\n", filename); > + > + /* Clear the bits in the local copy */ > + if (cap_ordinal < 32) > + lo32 &= ~(1 << cap_ordinal); > + else > + hi32 &= ~(1 << (cap_ordinal - 32)); > + > + /* Commit the new bit masks to the kernel */ > + sprintf(buf, "%u %u", lo32, hi32); > + ret = fwrite(buf, 1, strlen(buf) + 1, file); > + if (ret != strlen(buf) + 1) > + fail("Failed to commit usermode helper bitmasks: %d\n", ret); > + > + /* Cleanup */ > + fclose(file); > +} > + > +static void do_usermodehelper(int cap_ordinal) > +{ > + static const char * const files[] = { > + "/proc/sys/kernel/bset", > + "/proc/sys/kernel/inheritable", > + }; > + int i; > + > + for (i = 0; i < ARRAY_SIZE(files); i++) > + do_usermodehelper_file(files[i], cap_ordinal); > +} > + > +static void drop_capability(int cap_ordinal) > +{ > + do_usermodehelper(cap_ordinal); > + do_bset(cap_ordinal); > + do_capset(cap_ordinal); > + > + printf("Dropped capability: %s\n", capabilities[cap_ordinal].cap_name); > +} > + > +int do_capabilities(const char *drop_capabilities) > +{ > + char *s, *saveptr = NULL; > + char *token; > + int drop_setpcap = 0; > + > + if (!drop_capabilities) > + return 0; > + > + /* Create a duplicate string that can be modified. */ > + s = strdup(drop_capabilities); > + if (!s) > + fail("Failed to drop caps as requested. Exiting\n"); > + > + token = strtok_r(s, ",", &saveptr); > + while (token) { > + int cap_ordinal = find_capability(token); > + > + if (cap_ordinal < 0) > + fail("Could not understand capability name \"%s\" " > + "on command line, failing init\n", token); > + > + /* We handle CAP_SETPCAP last because it is needed to > + * drop all other caps. */ > + if (cap_ordinal == CAP_SETPCAP) > + drop_setpcap = 1; > + else > + drop_capability(cap_ordinal); > + > + token = strtok_r(NULL, ",", &saveptr); > + } > + > + if (drop_setpcap) > + drop_capability(CAP_SETPCAP); > + > + free(s); > + return 0; > +} > diff --git a/usr/kinit/run-init/capabilities.h b/usr/kinit/run-init/capabilities.h > new file mode 100644 > index 0000000..bf51eec > --- /dev/null > +++ b/usr/kinit/run-init/capabilities.h > @@ -0,0 +1,6 @@ > +#ifndef CAPABILITIES_H > +#define CAPABILITIES_H > + > +int do_capabilities(const char *drop_capabilities); > + > +#endif /* CAPABILITIES_H */ > diff --git a/usr/kinit/run-init/run-init.c b/usr/kinit/run-init/run-init.c > index 0f150dd..cc602ef 100644 > --- a/usr/kinit/run-init/run-init.c > +++ b/usr/kinit/run-init/run-init.c > @@ -35,6 +35,7 @@ > * - Remounts /real-root onto the root filesystem; > * - Chroots; > * - Opens /dev/console; > + * - Drops capabilities > * - Spawns the specified init program (with arguments.) > */ > > @@ -50,7 +51,8 @@ static const char *program; > static void __attribute__ ((noreturn)) usage(void) > { > fprintf(stderr, > - "Usage: exec %s [-c consoledev] /real-root /sbin/init [args]\n", > + "Usage: exec %s [-c consoledev] [-d <CAP_NAME,...>] " > + "/real-root /sbin/init [args]\n", > program); > exit(1); > } > @@ -62,6 +64,7 @@ int main(int argc, char *argv[]) > const char *realroot; > const char *init; > const char *error; > + const char *drop_capabilities = NULL; > char **initargs; > > /* Variables... */ > @@ -70,9 +73,11 @@ int main(int argc, char *argv[]) > /* Parse the command line */ > program = argv[0]; > > - while ((o = getopt(argc, argv, "c:")) != -1) { > + while ((o = getopt(argc, argv, "c:d:")) != -1) { > if (o == 'c') { > console = optarg; > + } else if (o == 'd') { > + drop_capabilities = optarg; > } else { > usage(); > } > @@ -85,7 +90,7 @@ int main(int argc, char *argv[]) > init = argv[optind + 1]; > initargs = argv + optind + 1; > > - error = run_init(realroot, console, init, initargs); > + error = run_init(realroot, console, drop_capabilities, init, initargs); > > /* If run_init returns, something went wrong */ > fprintf(stderr, "%s: %s: %s\n", program, error, strerror(errno)); > diff --git a/usr/kinit/run-init/run-init.h b/usr/kinit/run-init/run-init.h > index a95328e..30f78bf 100644 > --- a/usr/kinit/run-init/run-init.h > +++ b/usr/kinit/run-init/run-init.h > @@ -29,6 +29,7 @@ > #define RUN_INIT_H > > const char *run_init(const char *realroot, const char *console, > - const char *init, char **initargs); > + const char *drop_capabilities, const char *init, > + char **initargs); > > #endif > diff --git a/usr/kinit/run-init/runinitlib.c b/usr/kinit/run-init/runinitlib.c > index 8f1562f..a5cb10c 100644 > --- a/usr/kinit/run-init/runinitlib.c > +++ b/usr/kinit/run-init/runinitlib.c > @@ -26,7 +26,7 @@ > * ----------------------------------------------------------------------- */ > > /* > - * run_init(consoledev, realroot, init, initargs) > + * run_init(consoledev, realroot, drop_capabilities, init, initargs) > * > * This function should be called as the last thing in kinit, > * from initramfs, it does the following: > @@ -35,6 +35,7 @@ > * - Remounts /real-root onto the root filesystem; > * - Chroots; > * - Opens /dev/console; > + * - Drops capabilities if needed; > * - Spawns the specified init program (with arguments.) > * > * On failure, returns a human-readable error message. > @@ -52,7 +53,9 @@ > #include <sys/stat.h> > #include <sys/types.h> > #include <sys/vfs.h> > + > #include "run-init.h" > +#include "capabilities.h" > > /* Make it possible to compile on glibc by including constants that the > always-behind shipped glibc headers may not include. Classic example > @@ -154,7 +157,8 @@ static int nuke(const char *what) > } > > const char *run_init(const char *realroot, const char *console, > - const char *init, char **initargs) > + const char *drop_capabilities, const char *init, > + char **initargs) > { > struct stat rst, cst; > struct statfs sfs; > @@ -203,6 +207,9 @@ const char *run_init(const char *realroot, const char *console, > dup2(confd, 2); > close(confd); > > + /* Drop capabilities */ > + do_capabilities(drop_capabilities); > + > /* Spawn init */ > execv(init, initargs); > return init; /* Failed to spawn init */ -- maks ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v1 2/2] run-init: Add drop_capabilities support. 2011-07-29 20:45 ` Maximilian Attems @ 2011-07-29 20:46 ` Mike Waychison 2011-08-02 21:09 ` Maximilian Attems 0 siblings, 1 reply; 13+ messages in thread From: Mike Waychison @ 2011-07-29 20:46 UTC (permalink / raw) To: Maximilian Attems Cc: Andrew G. Morgan, Eric Northup, Alan Cox, H. Peter Anvin, Eric Paris, klibc, linux-kernel On Fri, Jul 29, 2011 at 1:45 PM, Maximilian Attems <max@stro.at> wrote: > On Tue, 19 Jul 2011, Mike Waychison wrote: > >> This patch adds the ability to run-init to allow the dropping of >> POSIX capabilities. >> >> This works by adding a "-d" flag to run-init, which takes a comma >> separated list of capability names that should be dropped right before >> exec'ing the real init binary. >> >> kinit is also modified by this change, such that it understands the same >> argument when prepended with "drop_capabilities=" on the kernel command >> line. >> >> When processing capabilities to drop, CAP_SETPCAP is special cased to be >> dropped last, so that the order that capabilities are given does not >> cause dropping of later enumerated capabilities to fail if it is listed >> early on. >> >> Dropping of capabilities happens in three parts. We explicitly drop the >> capability from init's inherited, permitted and effective masks. We >> also drop the capability from the bounding set using PR_CAPBSET_DROP. >> Lastly, if available, we drop the capabilities from the bset and >> inheritted masks exposed at /proc/sys/kernel/usermodehelper if available >> (introduced in v3.0.0). > > hmm as 3.0 is out, I don't think we need more backward compatibility. > do you have a strong arg for it? > especially since this is an *optional* calling arg I really don't see > the need of that backward crap. I'd like to keep it for the time being. I'm still building both 2.6.34 and 2.6.39 kernels at the moment, though I can maintain these last few compatibility bits in-house if that makes it easier for you. > >> In all paths, we treat errors as fatal, as we do not want to continue to >> boot if there was a problem dropping capabilities. The only exception >> to this rule is the handling of /proc/sys/kernel/usermodehelper, where >> we print out a warning if we notice that the kernel is new enough to >> support this interface, but could not find the proc file (as it may or >> may not be available after the pivot, depending on early portions of the >> boot strap process). >> >> Signed-off-by: Mike Waychison <mikew@google.com> >> --- >> usr/kinit/kinit.c | 4 - >> usr/kinit/run-init/Kbuild | 2 >> usr/kinit/run-init/capabilities.c | 278 +++++++++++++++++++++++++++++++++++++ >> usr/kinit/run-init/capabilities.h | 6 + >> usr/kinit/run-init/run-init.c | 11 + >> usr/kinit/run-init/run-init.h | 3 >> usr/kinit/run-init/runinitlib.c | 11 + >> 7 files changed, 307 insertions(+), 8 deletions(-) >> create mode 100644 usr/kinit/run-init/capabilities.c >> create mode 100644 usr/kinit/run-init/capabilities.h >> >> diff --git a/usr/kinit/kinit.c b/usr/kinit/kinit.c >> index 4a1f40b..ae50ed6 100644 >> --- a/usr/kinit/kinit.c >> +++ b/usr/kinit/kinit.c >> @@ -307,7 +307,9 @@ int main(int argc, char *argv[]) >> >> init_argv[0] = strrchr(init_path, '/') + 1; >> >> - errmsg = run_init("/root", "/dev/console", init_path, init_argv); >> + errmsg = run_init("/root", "/dev/console", >> + get_arg(cmdc, cmdv, "drop_capabilities="), >> + init_path, init_argv); >> >> /* If run_init returned, something went bad */ >> fprintf(stderr, "%s: %s: %s\n", progname, errmsg, strerror(errno)); >> diff --git a/usr/kinit/run-init/Kbuild b/usr/kinit/run-init/Kbuild >> index bf6e140..6451dd4 100644 >> --- a/usr/kinit/run-init/Kbuild >> +++ b/usr/kinit/run-init/Kbuild >> @@ -6,7 +6,7 @@ static-y := static/run-init >> shared-y := shared/run-init >> >> # common .o files >> -objs := run-init.o runinitlib.o >> +objs := run-init.o runinitlib.o capabilities.o >> >> # TODO - do we want a stripped version >> # TODO - do we want the static.g + shared.g directories? >> diff --git a/usr/kinit/run-init/capabilities.c b/usr/kinit/run-init/capabilities.c >> new file mode 100644 >> index 0000000..d262c01 >> --- /dev/null >> +++ b/usr/kinit/run-init/capabilities.c >> @@ -0,0 +1,278 @@ >> +/* >> + * Copyright 2011 Google Inc. All Rights Reserved >> + * Author: mikew@google.com (Mike Waychison) >> + */ >> + >> +/* >> + * We have to include the klibc types.h here to keep the kernel's >> + * types.h from being used. >> + */ >> +#include <sys/types.h> >> + >> +#include <linux/version.h> >> +#include <sys/capability.h> >> +#include <sys/prctl.h> >> +#include <sys/utsname.h> >> +#include <errno.h> >> +#include <stdio.h> >> +#include <stdlib.h> >> +#include <string.h> >> +#include <unistd.h> >> + >> +#include "capabilities.h" >> + >> +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) >> + >> +#define MAKE_CAP(cap) [cap] = { .cap_name = #cap } >> + >> +struct capability { >> + const char *cap_name; >> +} capabilities[] = { >> + MAKE_CAP(CAP_CHOWN), >> + MAKE_CAP(CAP_DAC_OVERRIDE), >> + MAKE_CAP(CAP_DAC_READ_SEARCH), >> + MAKE_CAP(CAP_FOWNER), >> + MAKE_CAP(CAP_FSETID), >> + MAKE_CAP(CAP_KILL), >> + MAKE_CAP(CAP_SETGID), >> + MAKE_CAP(CAP_SETUID), >> + MAKE_CAP(CAP_SETPCAP), >> + MAKE_CAP(CAP_LINUX_IMMUTABLE), >> + MAKE_CAP(CAP_NET_BIND_SERVICE), >> + MAKE_CAP(CAP_NET_BROADCAST), >> + MAKE_CAP(CAP_NET_ADMIN), >> + MAKE_CAP(CAP_NET_RAW), >> + MAKE_CAP(CAP_IPC_LOCK), >> + MAKE_CAP(CAP_IPC_OWNER), >> + MAKE_CAP(CAP_SYS_MODULE), >> + MAKE_CAP(CAP_SYS_RAWIO), >> + MAKE_CAP(CAP_SYS_CHROOT), >> + MAKE_CAP(CAP_SYS_PTRACE), >> + MAKE_CAP(CAP_SYS_PACCT), >> + MAKE_CAP(CAP_SYS_ADMIN), >> + MAKE_CAP(CAP_SYS_BOOT), >> + MAKE_CAP(CAP_SYS_NICE), >> + MAKE_CAP(CAP_SYS_RESOURCE), >> + MAKE_CAP(CAP_SYS_TIME), >> + MAKE_CAP(CAP_SYS_TTY_CONFIG), >> + MAKE_CAP(CAP_MKNOD), >> + MAKE_CAP(CAP_LEASE), >> + MAKE_CAP(CAP_AUDIT_WRITE), >> + MAKE_CAP(CAP_AUDIT_CONTROL), >> + MAKE_CAP(CAP_SETFCAP), >> + MAKE_CAP(CAP_MAC_OVERRIDE), >> + MAKE_CAP(CAP_MAC_ADMIN), >> + MAKE_CAP(CAP_SYSLOG), >> +}; >> + >> +static void fail(const char *fmt, ...) >> +{ >> + va_list args; >> + >> + va_start(args, fmt); >> + vfprintf(stderr, fmt, args); >> + va_end(args); >> + exit(1); >> +} >> + >> +/* >> + * Returns the currently running kernel version X.Y.Z in a format >> + * compatible with the KERNEL_VERSION macro. >> + */ >> +static unsigned kernel_version(void) >> +{ >> + struct utsname utsname; >> + int ret; >> + unsigned char version, patchlevel, sublevel; >> + >> + ret = uname(&utsname); >> + if (ret != 0) >> + fail("uname returned %d\n", ret); >> + >> + ret = sscanf(utsname.release, "%hhu.%hhu.%hhu", >> + &version, &patchlevel, &sublevel); >> + if (ret != 3) { >> + /* Try two level name? */ >> + sublevel = 0; >> + ret = sscanf(utsname.release, "%hhu.%hhu", >> + &version, &patchlevel); >> + if (ret != 2) >> + fail("Couldn't parse kernel version \"%s\"\n", >> + utsname.release); >> + } >> + >> + return KERNEL_VERSION(version, patchlevel, sublevel); >> +} >> + >> +/* >> + * Find the capability ordinal by name, and return its ordinal. >> + * Returns -1 on failure. >> + */ >> +static int find_capability(const char *s) >> +{ >> + int i; >> + >> + for (i = 0; i < ARRAY_SIZE(capabilities); i++) { >> + if (capabilities[i].cap_name >> + && strcasecmp(s, capabilities[i].cap_name) == 0) { >> + return i; >> + } >> + } >> + return -1; >> +} >> + >> +static void do_capset(int cap_ordinal) >> +{ >> + struct __user_cap_header_struct hdr; >> + struct __user_cap_data_struct caps[2]; >> + >> + /* Get the current capability mask */ >> + hdr.version = _LINUX_CAPABILITY_VERSION_3; >> + hdr.pid = getpid(); >> + if (capget(&hdr, caps)) { >> + perror("capget()"); >> + exit(1); >> + } >> + >> + /* Drop the bits */ >> + if (cap_ordinal < 32) { >> + caps[0].effective &= ~(1U << cap_ordinal); >> + caps[0].permitted &= ~(1U << cap_ordinal); >> + caps[0].inheritable &= ~(1U << cap_ordinal); >> + } else { >> + caps[1].effective &= ~(1U << (cap_ordinal - 32)); >> + caps[1].permitted &= ~(1U << (cap_ordinal - 32)); >> + caps[1].inheritable &= ~(1U << (cap_ordinal - 32)); >> + } >> + >> + /* And drop the capability. */ >> + hdr.version = _LINUX_CAPABILITY_VERSION_3; >> + hdr.pid = getpid(); >> + if (capset(&hdr, caps)) >> + fail("Couldn't drop the capability \"%s\"\n", >> + capabilities[cap_ordinal].cap_name); >> +} >> + >> +static void do_bset(int cap_ordinal) >> +{ >> + int ret; >> + >> + ret = prctl(PR_CAPBSET_READ, cap_ordinal); >> + if (ret == 1) { >> + ret = prctl(PR_CAPBSET_DROP, cap_ordinal); >> + if (ret != 0) >> + fail("Error dropping capability %s from bset\n", >> + capabilities[cap_ordinal].cap_name); >> + } else if (ret < 0) >> + fail("Kernel doesn't recognize capability %d\n", cap_ordinal); >> +} >> + >> +static void do_usermodehelper_file(const char *filename, int cap_ordinal) >> +{ >> + uint32_t lo32, hi32; >> + FILE *file; >> + static const size_t buf_size = 80; >> + char buf[buf_size]; >> + char tail; >> + size_t bytes_read; >> + int ret; >> + >> + /* Try and open the file */ >> + file = fopen(filename, "r+"); >> + if (!file && errno == ENOENT) { >> + /* Check if this kernel even supports this interface. */ >> + if (kernel_version() >= KERNEL_VERSION(3, 0, 0)) { >> + static int printed_once; >> + if (!printed_once++) >> + fprintf(stderr, "WARNING: Could not disable " >> + "capabilities for usermode helpers!\n"); >> + } >> + return; >> + } >> + if (!file) >> + fail("Failed to access file %s errno %d\n", filename, errno); >> + >> + /* Read and process the current bits */ >> + bytes_read = fread(buf, 1, buf_size - 1, file); >> + if (bytes_read == 0) >> + fail("Trouble reading %s\n", filename); >> + buf[bytes_read] = '\0'; >> + ret = sscanf(buf, "%u %u%c", &lo32, &hi32, &tail); >> + if (ret != 2) >> + fail("Failed to understand %s\n", filename); >> + >> + /* Clear the bits in the local copy */ >> + if (cap_ordinal < 32) >> + lo32 &= ~(1 << cap_ordinal); >> + else >> + hi32 &= ~(1 << (cap_ordinal - 32)); >> + >> + /* Commit the new bit masks to the kernel */ >> + sprintf(buf, "%u %u", lo32, hi32); >> + ret = fwrite(buf, 1, strlen(buf) + 1, file); >> + if (ret != strlen(buf) + 1) >> + fail("Failed to commit usermode helper bitmasks: %d\n", ret); >> + >> + /* Cleanup */ >> + fclose(file); >> +} >> + >> +static void do_usermodehelper(int cap_ordinal) >> +{ >> + static const char * const files[] = { >> + "/proc/sys/kernel/bset", >> + "/proc/sys/kernel/inheritable", >> + }; >> + int i; >> + >> + for (i = 0; i < ARRAY_SIZE(files); i++) >> + do_usermodehelper_file(files[i], cap_ordinal); >> +} >> + >> +static void drop_capability(int cap_ordinal) >> +{ >> + do_usermodehelper(cap_ordinal); >> + do_bset(cap_ordinal); >> + do_capset(cap_ordinal); >> + >> + printf("Dropped capability: %s\n", capabilities[cap_ordinal].cap_name); >> +} >> + >> +int do_capabilities(const char *drop_capabilities) >> +{ >> + char *s, *saveptr = NULL; >> + char *token; >> + int drop_setpcap = 0; >> + >> + if (!drop_capabilities) >> + return 0; >> + >> + /* Create a duplicate string that can be modified. */ >> + s = strdup(drop_capabilities); >> + if (!s) >> + fail("Failed to drop caps as requested. Exiting\n"); >> + >> + token = strtok_r(s, ",", &saveptr); >> + while (token) { >> + int cap_ordinal = find_capability(token); >> + >> + if (cap_ordinal < 0) >> + fail("Could not understand capability name \"%s\" " >> + "on command line, failing init\n", token); >> + >> + /* We handle CAP_SETPCAP last because it is needed to >> + * drop all other caps. */ >> + if (cap_ordinal == CAP_SETPCAP) >> + drop_setpcap = 1; >> + else >> + drop_capability(cap_ordinal); >> + >> + token = strtok_r(NULL, ",", &saveptr); >> + } >> + >> + if (drop_setpcap) >> + drop_capability(CAP_SETPCAP); >> + >> + free(s); >> + return 0; >> +} >> diff --git a/usr/kinit/run-init/capabilities.h b/usr/kinit/run-init/capabilities.h >> new file mode 100644 >> index 0000000..bf51eec >> --- /dev/null >> +++ b/usr/kinit/run-init/capabilities.h >> @@ -0,0 +1,6 @@ >> +#ifndef CAPABILITIES_H >> +#define CAPABILITIES_H >> + >> +int do_capabilities(const char *drop_capabilities); >> + >> +#endif /* CAPABILITIES_H */ >> diff --git a/usr/kinit/run-init/run-init.c b/usr/kinit/run-init/run-init.c >> index 0f150dd..cc602ef 100644 >> --- a/usr/kinit/run-init/run-init.c >> +++ b/usr/kinit/run-init/run-init.c >> @@ -35,6 +35,7 @@ >> * - Remounts /real-root onto the root filesystem; >> * - Chroots; >> * - Opens /dev/console; >> + * - Drops capabilities >> * - Spawns the specified init program (with arguments.) >> */ >> >> @@ -50,7 +51,8 @@ static const char *program; >> static void __attribute__ ((noreturn)) usage(void) >> { >> fprintf(stderr, >> - "Usage: exec %s [-c consoledev] /real-root /sbin/init [args]\n", >> + "Usage: exec %s [-c consoledev] [-d <CAP_NAME,...>] " >> + "/real-root /sbin/init [args]\n", >> program); >> exit(1); >> } >> @@ -62,6 +64,7 @@ int main(int argc, char *argv[]) >> const char *realroot; >> const char *init; >> const char *error; >> + const char *drop_capabilities = NULL; >> char **initargs; >> >> /* Variables... */ >> @@ -70,9 +73,11 @@ int main(int argc, char *argv[]) >> /* Parse the command line */ >> program = argv[0]; >> >> - while ((o = getopt(argc, argv, "c:")) != -1) { >> + while ((o = getopt(argc, argv, "c:d:")) != -1) { >> if (o == 'c') { >> console = optarg; >> + } else if (o == 'd') { >> + drop_capabilities = optarg; >> } else { >> usage(); >> } >> @@ -85,7 +90,7 @@ int main(int argc, char *argv[]) >> init = argv[optind + 1]; >> initargs = argv + optind + 1; >> >> - error = run_init(realroot, console, init, initargs); >> + error = run_init(realroot, console, drop_capabilities, init, initargs); >> >> /* If run_init returns, something went wrong */ >> fprintf(stderr, "%s: %s: %s\n", program, error, strerror(errno)); >> diff --git a/usr/kinit/run-init/run-init.h b/usr/kinit/run-init/run-init.h >> index a95328e..30f78bf 100644 >> --- a/usr/kinit/run-init/run-init.h >> +++ b/usr/kinit/run-init/run-init.h >> @@ -29,6 +29,7 @@ >> #define RUN_INIT_H >> >> const char *run_init(const char *realroot, const char *console, >> - const char *init, char **initargs); >> + const char *drop_capabilities, const char *init, >> + char **initargs); >> >> #endif >> diff --git a/usr/kinit/run-init/runinitlib.c b/usr/kinit/run-init/runinitlib.c >> index 8f1562f..a5cb10c 100644 >> --- a/usr/kinit/run-init/runinitlib.c >> +++ b/usr/kinit/run-init/runinitlib.c >> @@ -26,7 +26,7 @@ >> * ----------------------------------------------------------------------- */ >> >> /* >> - * run_init(consoledev, realroot, init, initargs) >> + * run_init(consoledev, realroot, drop_capabilities, init, initargs) >> * >> * This function should be called as the last thing in kinit, >> * from initramfs, it does the following: >> @@ -35,6 +35,7 @@ >> * - Remounts /real-root onto the root filesystem; >> * - Chroots; >> * - Opens /dev/console; >> + * - Drops capabilities if needed; >> * - Spawns the specified init program (with arguments.) >> * >> * On failure, returns a human-readable error message. >> @@ -52,7 +53,9 @@ >> #include <sys/stat.h> >> #include <sys/types.h> >> #include <sys/vfs.h> >> + >> #include "run-init.h" >> +#include "capabilities.h" >> >> /* Make it possible to compile on glibc by including constants that the >> always-behind shipped glibc headers may not include. Classic example >> @@ -154,7 +157,8 @@ static int nuke(const char *what) >> } >> >> const char *run_init(const char *realroot, const char *console, >> - const char *init, char **initargs) >> + const char *drop_capabilities, const char *init, >> + char **initargs) >> { >> struct stat rst, cst; >> struct statfs sfs; >> @@ -203,6 +207,9 @@ const char *run_init(const char *realroot, const char *console, >> dup2(confd, 2); >> close(confd); >> >> + /* Drop capabilities */ >> + do_capabilities(drop_capabilities); >> + >> /* Spawn init */ >> execv(init, initargs); >> return init; /* Failed to spawn init */ > -- > maks > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v1 2/2] run-init: Add drop_capabilities support. 2011-07-29 20:46 ` Mike Waychison @ 2011-08-02 21:09 ` Maximilian Attems 2011-08-02 21:42 ` Mike Waychison 0 siblings, 1 reply; 13+ messages in thread From: Maximilian Attems @ 2011-08-02 21:09 UTC (permalink / raw) To: Mike Waychison Cc: Andrew G. Morgan, Eric Northup, Alan Cox, H. Peter Anvin, Eric Paris, klibc, linux-kernel On Fri, 29 Jul 2011, Mike Waychison wrote: > On Fri, Jul 29, 2011 at 1:45 PM, Maximilian Attems <max@stro.at> wrote: > > On Tue, 19 Jul 2011, Mike Waychison wrote: > > > >> This patch adds the ability to run-init to allow the dropping of > >> POSIX capabilities. > >> > >> This works by adding a "-d" flag to run-init, which takes a comma > >> separated list of capability names that should be dropped right before > >> exec'ing the real init binary. > >> > >> kinit is also modified by this change, such that it understands the same > >> argument when prepended with "drop_capabilities=" on the kernel command > >> line. > >> > >> When processing capabilities to drop, CAP_SETPCAP is special cased to be > >> dropped last, so that the order that capabilities are given does not > >> cause dropping of later enumerated capabilities to fail if it is listed > >> early on. > >> > >> Dropping of capabilities happens in three parts. We explicitly drop the > >> capability from init's inherited, permitted and effective masks. We > >> also drop the capability from the bounding set using PR_CAPBSET_DROP. > >> Lastly, if available, we drop the capabilities from the bset and > >> inheritted masks exposed at /proc/sys/kernel/usermodehelper if available > >> (introduced in v3.0.0). > > > > hmm as 3.0 is out, I don't think we need more backward compatibility. > > do you have a strong arg for it? > > especially since this is an *optional* calling arg I really don't see > > the need of that backward crap. > > I'd like to keep it for the time being. I'm still building both 2.6.34 > and 2.6.39 kernels at the moment, though I can maintain these last few > compatibility bits in-house if that makes it easier for you. you include anyway linux/version.h, would build disabling help you? that way that macro doesn't need duplicating. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v1 2/2] run-init: Add drop_capabilities support. 2011-08-02 21:09 ` Maximilian Attems @ 2011-08-02 21:42 ` Mike Waychison 2011-08-02 22:50 ` Andrew G. Morgan 0 siblings, 1 reply; 13+ messages in thread From: Mike Waychison @ 2011-08-02 21:42 UTC (permalink / raw) To: Maximilian Attems Cc: Andrew G. Morgan, Eric Northup, Alan Cox, H. Peter Anvin, Eric Paris, klibc, linux-kernel On Tue, Aug 2, 2011 at 2:09 PM, Maximilian Attems <max@stro.at> wrote: > On Fri, 29 Jul 2011, Mike Waychison wrote: > >> On Fri, Jul 29, 2011 at 1:45 PM, Maximilian Attems <max@stro.at> wrote: >> > On Tue, 19 Jul 2011, Mike Waychison wrote: >> > >> >> This patch adds the ability to run-init to allow the dropping of >> >> POSIX capabilities. >> >> >> >> This works by adding a "-d" flag to run-init, which takes a comma >> >> separated list of capability names that should be dropped right before >> >> exec'ing the real init binary. >> >> >> >> kinit is also modified by this change, such that it understands the same >> >> argument when prepended with "drop_capabilities=" on the kernel command >> >> line. >> >> >> >> When processing capabilities to drop, CAP_SETPCAP is special cased to be >> >> dropped last, so that the order that capabilities are given does not >> >> cause dropping of later enumerated capabilities to fail if it is listed >> >> early on. >> >> >> >> Dropping of capabilities happens in three parts. We explicitly drop the >> >> capability from init's inherited, permitted and effective masks. We >> >> also drop the capability from the bounding set using PR_CAPBSET_DROP. >> >> Lastly, if available, we drop the capabilities from the bset and >> >> inheritted masks exposed at /proc/sys/kernel/usermodehelper if available >> >> (introduced in v3.0.0). >> > >> > hmm as 3.0 is out, I don't think we need more backward compatibility. >> > do you have a strong arg for it? >> > especially since this is an *optional* calling arg I really don't see >> > the need of that backward crap. >> >> I'd like to keep it for the time being. I'm still building both 2.6.34 >> and 2.6.39 kernels at the moment, though I can maintain these last few >> compatibility bits in-house if that makes it easier for you. > > you include anyway linux/version.h, would build disabling help you? > that way that macro doesn't need duplicating. > For correctness sake, I think it's still a runtime check thing (consider the case of an image that is reused between kernel builds). Reflecting on it a bit more though, I'd be okay if we removed the version check altogether and just made it warn if the file isn't present. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v1 2/2] run-init: Add drop_capabilities support. 2011-08-02 21:42 ` Mike Waychison @ 2011-08-02 22:50 ` Andrew G. Morgan 2011-08-02 22:56 ` Mike Waychison 0 siblings, 1 reply; 13+ messages in thread From: Andrew G. Morgan @ 2011-08-02 22:50 UTC (permalink / raw) To: Mike Waychison Cc: Maximilian Attems, Eric Northup, Alan Cox, H. Peter Anvin, Eric Paris, klibc, linux-kernel Which part of the version check are you dropping? Also, I'm not clear you need/want to drop the permitted/effective bits. All that will survive the exec() are the inheritable bits. Cheers Andrew On Tue, Aug 2, 2011 at 2:42 PM, Mike Waychison <mikew@google.com> wrote: > On Tue, Aug 2, 2011 at 2:09 PM, Maximilian Attems <max@stro.at> wrote: >> On Fri, 29 Jul 2011, Mike Waychison wrote: >> >>> On Fri, Jul 29, 2011 at 1:45 PM, Maximilian Attems <max@stro.at> wrote: >>> > On Tue, 19 Jul 2011, Mike Waychison wrote: >>> > >>> >> This patch adds the ability to run-init to allow the dropping of >>> >> POSIX capabilities. >>> >> >>> >> This works by adding a "-d" flag to run-init, which takes a comma >>> >> separated list of capability names that should be dropped right before >>> >> exec'ing the real init binary. >>> >> >>> >> kinit is also modified by this change, such that it understands the same >>> >> argument when prepended with "drop_capabilities=" on the kernel command >>> >> line. >>> >> >>> >> When processing capabilities to drop, CAP_SETPCAP is special cased to be >>> >> dropped last, so that the order that capabilities are given does not >>> >> cause dropping of later enumerated capabilities to fail if it is listed >>> >> early on. >>> >> >>> >> Dropping of capabilities happens in three parts. We explicitly drop the >>> >> capability from init's inherited, permitted and effective masks. We >>> >> also drop the capability from the bounding set using PR_CAPBSET_DROP. >>> >> Lastly, if available, we drop the capabilities from the bset and >>> >> inheritted masks exposed at /proc/sys/kernel/usermodehelper if available >>> >> (introduced in v3.0.0). >>> > >>> > hmm as 3.0 is out, I don't think we need more backward compatibility. >>> > do you have a strong arg for it? >>> > especially since this is an *optional* calling arg I really don't see >>> > the need of that backward crap. >>> >>> I'd like to keep it for the time being. I'm still building both 2.6.34 >>> and 2.6.39 kernels at the moment, though I can maintain these last few >>> compatibility bits in-house if that makes it easier for you. >> >> you include anyway linux/version.h, would build disabling help you? >> that way that macro doesn't need duplicating. >> > > For correctness sake, I think it's still a runtime check thing > (consider the case of an image that is reused between kernel builds). > > Reflecting on it a bit more though, I'd be okay if we removed the > version check altogether and just made it warn if the file isn't > present. > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v1 2/2] run-init: Add drop_capabilities support. 2011-08-02 22:50 ` Andrew G. Morgan @ 2011-08-02 22:56 ` Mike Waychison 2011-08-02 23:37 ` Mike Waychison 0 siblings, 1 reply; 13+ messages in thread From: Mike Waychison @ 2011-08-02 22:56 UTC (permalink / raw) To: Andrew G. Morgan Cc: Maximilian Attems, Eric Northup, Alan Cox, H. Peter Anvin, Eric Paris, klibc, linux-kernel On Tue, Aug 2, 2011 at 3:50 PM, Andrew G. Morgan <agm@google.com> wrote: > Which part of the version check are you dropping? The version check in the patch I posted is used when access to /proc/sys/kernel/usermodehelper/{bset|inheritable} files fails with ENOENT (which looking closer is broken in the patch I sent as the wrong pathnames are used). Given that I'm only planning on using this on kernels that are v3.0 or have this code back ported anyway, and the fact the option is new, I'm going to try changing this over to _always_ failing like in all the other *something went wrong enforcing the security policy* paths. > > Also, I'm not clear you need/want to drop the permitted/effective > bits. All that will survive the exec() are the inheritable bits. Okay. Will drop these. > > Cheers > > Andrew > > On Tue, Aug 2, 2011 at 2:42 PM, Mike Waychison <mikew@google.com> wrote: >> On Tue, Aug 2, 2011 at 2:09 PM, Maximilian Attems <max@stro.at> wrote: >>> On Fri, 29 Jul 2011, Mike Waychison wrote: >>> >>>> On Fri, Jul 29, 2011 at 1:45 PM, Maximilian Attems <max@stro.at> wrote: >>>> > On Tue, 19 Jul 2011, Mike Waychison wrote: >>>> > >>>> >> This patch adds the ability to run-init to allow the dropping of >>>> >> POSIX capabilities. >>>> >> >>>> >> This works by adding a "-d" flag to run-init, which takes a comma >>>> >> separated list of capability names that should be dropped right before >>>> >> exec'ing the real init binary. >>>> >> >>>> >> kinit is also modified by this change, such that it understands the same >>>> >> argument when prepended with "drop_capabilities=" on the kernel command >>>> >> line. >>>> >> >>>> >> When processing capabilities to drop, CAP_SETPCAP is special cased to be >>>> >> dropped last, so that the order that capabilities are given does not >>>> >> cause dropping of later enumerated capabilities to fail if it is listed >>>> >> early on. >>>> >> >>>> >> Dropping of capabilities happens in three parts. We explicitly drop the >>>> >> capability from init's inherited, permitted and effective masks. We >>>> >> also drop the capability from the bounding set using PR_CAPBSET_DROP. >>>> >> Lastly, if available, we drop the capabilities from the bset and >>>> >> inheritted masks exposed at /proc/sys/kernel/usermodehelper if available >>>> >> (introduced in v3.0.0). >>>> > >>>> > hmm as 3.0 is out, I don't think we need more backward compatibility. >>>> > do you have a strong arg for it? >>>> > especially since this is an *optional* calling arg I really don't see >>>> > the need of that backward crap. >>>> >>>> I'd like to keep it for the time being. I'm still building both 2.6.34 >>>> and 2.6.39 kernels at the moment, though I can maintain these last few >>>> compatibility bits in-house if that makes it easier for you. >>> >>> you include anyway linux/version.h, would build disabling help you? >>> that way that macro doesn't need duplicating. >>> >> >> For correctness sake, I think it's still a runtime check thing >> (consider the case of an image that is reused between kernel builds). >> >> Reflecting on it a bit more though, I'd be okay if we removed the >> version check altogether and just made it warn if the file isn't >> present. >> > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v1 2/2] run-init: Add drop_capabilities support. 2011-08-02 22:56 ` Mike Waychison @ 2011-08-02 23:37 ` Mike Waychison 2011-08-03 0:48 ` H. Peter Anvin 0 siblings, 1 reply; 13+ messages in thread From: Mike Waychison @ 2011-08-02 23:37 UTC (permalink / raw) To: Andrew G. Morgan Cc: Maximilian Attems, Eric Northup, Alan Cox, H. Peter Anvin, Eric Paris, klibc, linux-kernel On Tue, Aug 2, 2011 at 3:56 PM, Mike Waychison <mikew@google.com> wrote: > On Tue, Aug 2, 2011 at 3:50 PM, Andrew G. Morgan <agm@google.com> wrote: >> Which part of the version check are you dropping? > > The version check in the patch I posted is used when access to > /proc/sys/kernel/usermodehelper/{bset|inheritable} files fails with > ENOENT (which looking closer is broken in the patch I sent as the > wrong pathnames are used). > > Given that I'm only planning on using this on kernels that are v3.0 or > have this code back ported anyway, and the fact the option is new, I'm > going to try changing this over to _always_ failing like in all the > other *something went wrong enforcing the security policy* paths. Sigh. Not sure how I missed this in the first place.. we always unmount /proc before invoking run_init() from kinit's main. To add to the confusion, mount_sys_fs() returns 0 if the mountpoint is already present, which causes kinit to bail, while we continue merrily if the mount() call fails -- oops. Perhaps the right approach is to not drop the effective and permitted masks as Andrew pointed out, and do all this from kinit, not from run-init while /proc is mounted? > >> >> Also, I'm not clear you need/want to drop the permitted/effective >> bits. All that will survive the exec() are the inheritable bits. > > Okay. Will drop these. > >> >> Cheers >> >> Andrew >> >> On Tue, Aug 2, 2011 at 2:42 PM, Mike Waychison <mikew@google.com> wrote: >>> On Tue, Aug 2, 2011 at 2:09 PM, Maximilian Attems <max@stro.at> wrote: >>>> On Fri, 29 Jul 2011, Mike Waychison wrote: >>>> >>>>> On Fri, Jul 29, 2011 at 1:45 PM, Maximilian Attems <max@stro.at> wrote: >>>>> > On Tue, 19 Jul 2011, Mike Waychison wrote: >>>>> > >>>>> >> This patch adds the ability to run-init to allow the dropping of >>>>> >> POSIX capabilities. >>>>> >> >>>>> >> This works by adding a "-d" flag to run-init, which takes a comma >>>>> >> separated list of capability names that should be dropped right before >>>>> >> exec'ing the real init binary. >>>>> >> >>>>> >> kinit is also modified by this change, such that it understands the same >>>>> >> argument when prepended with "drop_capabilities=" on the kernel command >>>>> >> line. >>>>> >> >>>>> >> When processing capabilities to drop, CAP_SETPCAP is special cased to be >>>>> >> dropped last, so that the order that capabilities are given does not >>>>> >> cause dropping of later enumerated capabilities to fail if it is listed >>>>> >> early on. >>>>> >> >>>>> >> Dropping of capabilities happens in three parts. We explicitly drop the >>>>> >> capability from init's inherited, permitted and effective masks. We >>>>> >> also drop the capability from the bounding set using PR_CAPBSET_DROP. >>>>> >> Lastly, if available, we drop the capabilities from the bset and >>>>> >> inheritted masks exposed at /proc/sys/kernel/usermodehelper if available >>>>> >> (introduced in v3.0.0). >>>>> > >>>>> > hmm as 3.0 is out, I don't think we need more backward compatibility. >>>>> > do you have a strong arg for it? >>>>> > especially since this is an *optional* calling arg I really don't see >>>>> > the need of that backward crap. >>>>> >>>>> I'd like to keep it for the time being. I'm still building both 2.6.34 >>>>> and 2.6.39 kernels at the moment, though I can maintain these last few >>>>> compatibility bits in-house if that makes it easier for you. >>>> >>>> you include anyway linux/version.h, would build disabling help you? >>>> that way that macro doesn't need duplicating. >>>> >>> >>> For correctness sake, I think it's still a runtime check thing >>> (consider the case of an image that is reused between kernel builds). >>> >>> Reflecting on it a bit more though, I'd be okay if we removed the >>> version check altogether and just made it warn if the file isn't >>> present. >>> >> > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v1 2/2] run-init: Add drop_capabilities support. 2011-08-02 23:37 ` Mike Waychison @ 2011-08-03 0:48 ` H. Peter Anvin 0 siblings, 0 replies; 13+ messages in thread From: H. Peter Anvin @ 2011-08-03 0:48 UTC (permalink / raw) To: Mike Waychison Cc: Andrew G. Morgan, Maximilian Attems, Eric Northup, Alan Cox, Eric Paris, klibc, linux-kernel On 08/02/2011 04:37 PM, Mike Waychison wrote: > > Perhaps the right approach is to not drop the effective and permitted > masks as Andrew pointed out, and do all this from kinit, not from > run-init while /proc is mounted? > Well, we should really move /proc et al into the new root, if nothing else to match switch_root. -hpa ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2011-08-03 0:49 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2011-07-19 20:38 [PATCH v1 0/2] Support dropping of capabilities from early userspace Mike Waychison 2011-07-19 20:38 ` [PATCH v1 1/2] syscalls: Add capset and capget Mike Waychison 2011-07-29 20:41 ` Maximilian Attems 2011-07-29 23:06 ` Maximilian Attems 2011-07-19 20:38 ` [PATCH v1 2/2] run-init: Add drop_capabilities support Mike Waychison 2011-07-29 20:45 ` Maximilian Attems 2011-07-29 20:46 ` Mike Waychison 2011-08-02 21:09 ` Maximilian Attems 2011-08-02 21:42 ` Mike Waychison 2011-08-02 22:50 ` Andrew G. Morgan 2011-08-02 22:56 ` Mike Waychison 2011-08-02 23:37 ` Mike Waychison 2011-08-03 0:48 ` H. Peter Anvin
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox