diff options
author | Andrew G. Morgan <morgan@kernel.org> | 2016-02-06 19:49:07 -0800 |
---|---|---|
committer | Andrew G. Morgan <morgan@kernel.org> | 2016-02-06 19:49:07 -0800 |
commit | 0f0eca489e979b4a8526e521f962455e474a27a0 (patch) | |
tree | 0e8027ecad22b844deb36f5bee73712f5cc57b77 | |
parent | dce069b617cf5e42fde707196eaf2ee8d62bc96c (diff) | |
download | libcap-0f0eca489e979b4a8526e521f962455e474a27a0.tar.gz |
Add initial support for the ambient set.
The ambient set is some strangeness associated with trying to revive
naive inheritance. While personally not a fan of this feature, I
recognize it is in the kernel so libcap now supports it with
three new functions:
int cap_get_ambient(cap_value_t cap)
int cap_set_ambient(cap_value_t cap, cap_flag_value_t set)
int cap_reset_ambient(void)
Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
-rw-r--r-- | libcap/cap_proc.c | 69 | ||||
-rw-r--r-- | libcap/include/sys/capability.h | 6 | ||||
-rw-r--r-- | libcap/include/uapi/linux/prctl.h | 48 | ||||
-rw-r--r-- | progs/capsh.c | 174 |
4 files changed, 219 insertions, 78 deletions
diff --git a/libcap/cap_proc.c b/libcap/cap_proc.c index 8ecb57a..ffa0d91 100644 --- a/libcap/cap_proc.c +++ b/libcap/cap_proc.c @@ -105,13 +105,20 @@ int capsetp(pid_t pid, cap_t cap_d) return error; } +/* the kernel api requires unsigned long arguments */ +#define pr_arg(x) ((unsigned long) x) + /* get a capability from the bounding set */ int cap_get_bound(cap_value_t cap) { int result; - result = prctl(PR_CAPBSET_READ, cap); + result = prctl(PR_CAPBSET_READ, pr_arg(cap)); + if (result < 0) { + errno = -result; + return -1; + } return result; } @@ -121,6 +128,64 @@ int cap_drop_bound(cap_value_t cap) { int result; - result = prctl(PR_CAPBSET_DROP, cap); + result = prctl(PR_CAPBSET_DROP, pr_arg(cap)); + if (result < 0) { + errno = -result; + return -1; + } + return result; +} + +/* get a capability from the ambient set */ + +int cap_get_ambient(cap_value_t cap) +{ + int result; + result = prctl(PR_CAP_AMBIENT, pr_arg(PR_CAP_AMBIENT_IS_SET), + pr_arg(cap), pr_arg(0), pr_arg(0)); + if (result < 0) { + errno = -result; + return -1; + } + return result; +} + +/* modify a single ambient capability value */ + +int cap_set_ambient(cap_value_t cap, cap_flag_value_t set) +{ + int result, val; + switch (set) { + case CAP_SET: + val = PR_CAP_AMBIENT_RAISE; + break; + case CAP_CLEAR: + val = PR_CAP_AMBIENT_LOWER; + break; + default: + errno = EINVAL; + return -1; + } + result = prctl(PR_CAP_AMBIENT, pr_arg(PR_CAP_AMBIENT_RAISE), + pr_arg(cap), pr_arg(val), pr_arg(0)); + if (result < 0) { + errno = -result; + return -1; + } + return result; +} + +/* erase all ambient capabilities */ + +int cap_reset_ambient() +{ + int result; + + result = prctl(PR_CAP_AMBIENT, pr_arg(PR_CAP_AMBIENT_CLEAR_ALL), + pr_arg(0), pr_arg(0), pr_arg(0)); + if (result < 0) { + errno = -result; + return -1; + } return result; } diff --git a/libcap/include/sys/capability.h b/libcap/include/sys/capability.h index dddc75b..0976fa7 100644 --- a/libcap/include/sys/capability.h +++ b/libcap/include/sys/capability.h @@ -92,9 +92,13 @@ extern int cap_set_proc(cap_t); extern int cap_get_bound(cap_value_t); extern int cap_drop_bound(cap_value_t); - #define CAP_IS_SUPPORTED(cap) (cap_get_bound(cap) >= 0) +extern int cap_get_ambient(cap_value_t); +extern int cap_set_ambient(cap_value_t, cap_flag_value_t); +extern int cap_reset_ambient(void); +#define CAP_AMBIENT_SUPPORTED() (cap_get_ambient(CAP_CHOWN) >= 0) + /* libcap/cap_extint.c */ extern ssize_t cap_size(cap_t); extern ssize_t cap_copy_ext(void *, cap_t, ssize_t); diff --git a/libcap/include/uapi/linux/prctl.h b/libcap/include/uapi/linux/prctl.h index 289760f..a8d0759 100644 --- a/libcap/include/uapi/linux/prctl.h +++ b/libcap/include/uapi/linux/prctl.h @@ -1,6 +1,8 @@ #ifndef _LINUX_PRCTL_H #define _LINUX_PRCTL_H +#include <linux/types.h> + /* Values to pass as first argument to prctl() */ #define PR_SET_PDEATHSIG 1 /* Second arg is a signal */ @@ -119,6 +121,31 @@ # define PR_SET_MM_ENV_END 11 # define PR_SET_MM_AUXV 12 # define PR_SET_MM_EXE_FILE 13 +# define PR_SET_MM_MAP 14 +# define PR_SET_MM_MAP_SIZE 15 + +/* + * This structure provides new memory descriptor + * map which mostly modifies /proc/pid/stat[m] + * output for a task. This mostly done in a + * sake of checkpoint/restore functionality. + */ +struct prctl_mm_map { + __u64 start_code; /* code section bounds */ + __u64 end_code; + __u64 start_data; /* data section bounds */ + __u64 end_data; + __u64 start_brk; /* heap for brk() syscall */ + __u64 brk; + __u64 start_stack; /* stack starts at */ + __u64 arg_start; /* command line arguments bounds */ + __u64 arg_end; + __u64 env_start; /* environment variables bounds */ + __u64 env_end; + __u64 *auxv; /* auxiliary vector */ + __u32 auxv_size; /* vector size */ + __u32 exe_fd; /* /proc/$pid/exe link file */ +}; /* * Set specific pid that is allowed to ptrace the current task. @@ -149,4 +176,25 @@ #define PR_GET_TID_ADDRESS 40 +#define PR_SET_THP_DISABLE 41 +#define PR_GET_THP_DISABLE 42 + +/* + * Tell the kernel to start/stop helping userspace manage bounds tables. + */ +#define PR_MPX_ENABLE_MANAGEMENT 43 +#define PR_MPX_DISABLE_MANAGEMENT 44 + +#define PR_SET_FP_MODE 45 +#define PR_GET_FP_MODE 46 +# define PR_FP_MODE_FR (1 << 0) /* 64b FP registers */ +# define PR_FP_MODE_FRE (1 << 1) /* 32b compatibility */ + +/* Control the ambient capability set */ +#define PR_CAP_AMBIENT 47 +# define PR_CAP_AMBIENT_IS_SET 1 +# define PR_CAP_AMBIENT_RAISE 2 +# define PR_CAP_AMBIENT_LOWER 3 +# define PR_CAP_AMBIENT_CLEAR_ALL 4 + #endif /* _LINUX_PRCTL_H */ diff --git a/progs/capsh.c b/progs/capsh.c index 3ceadcd..9c907a7 100644 --- a/progs/capsh.c +++ b/progs/capsh.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-11 Andrew G. Morgan <morgan@kernel.org> + * Copyright (c) 2008-11,16 Andrew G. Morgan <morgan@kernel.org> * * This is a simple 'bash' wrapper program that can be used to * raise and lower both the bset and pI capabilities before invoking @@ -43,6 +43,103 @@ static char *binary(unsigned long value) return string + i; } +static void display_prctl_set(const char *name, int (*fn)(cap_value_t)) +{ + unsigned cap; + const char *sep; + int set; + + printf("%s set =", name); + for (sep = "", cap=0; (set = fn(cap)) >= 0; cap++) { + char *ptr; + if (!set) { + continue; + } + + ptr = cap_to_name(cap); + if (ptr == NULL) { + printf("%s%u", sep, cap); + } else { + printf("%s%s", sep, ptr); + cap_free(ptr); + } + sep = ","; + } + if (!cap) { + printf(" <unsupported>\n"); + } else { + printf("\n"); + } +} + +/* arg_print displays the current capability state of the process */ +static void arg_print(void) +{ + int set, status, j; + cap_t all; + char *text; + const char *sep; + struct group *g; + gid_t groups[MAX_GROUPS], gid; + uid_t uid; + struct passwd *u; + + all = cap_get_proc(); + text = cap_to_text(all, NULL); + printf("Current: %s\n", text); + cap_free(text); + cap_free(all); + + display_prctl_set("Bounding", cap_get_bound); + display_prctl_set("Ambient", cap_get_ambient); + set = prctl(PR_GET_SECUREBITS); + if (set >= 0) { + const char *b; + b = binary(set); /* use verilog convention for binary string */ + printf("Securebits: 0%o/0x%x/%u'b%s\n", set, set, + (unsigned) strlen(b), b); + printf(" secure-noroot: %s (%s)\n", + (set & SECBIT_NOROOT) ? "yes":"no", + (set & SECBIT_NOROOT_LOCKED) ? "locked":"unlocked"); + printf(" secure-no-suid-fixup: %s (%s)\n", + (set & SECBIT_NO_SETUID_FIXUP) ? "yes":"no", + (set & SECBIT_NO_SETUID_FIXUP_LOCKED) ? "locked":"unlocked"); + printf(" secure-keep-caps: %s (%s)\n", + (set & SECBIT_KEEP_CAPS) ? "yes":"no", + (set & SECBIT_KEEP_CAPS_LOCKED) ? "locked":"unlocked"); + if (CAP_AMBIENT_SUPPORTED()) { + printf(" secure-no-ambient-raise: %s (%s)\n", + (set & SECBIT_NO_CAP_AMBIENT_RAISE) ? "yes":"no", + (set & SECBIT_NO_CAP_AMBIENT_RAISE_LOCKED) ? + "locked":"unlocked"); + } + } else { + printf("[Securebits ABI not supported]\n"); + set = prctl(PR_GET_KEEPCAPS); + if (set >= 0) { + printf(" prctl-keep-caps: %s (locking not supported)\n", + set ? "yes":"no"); + } else { + printf("[Keepcaps ABI not supported]\n"); + } + } + uid = getuid(); + u = getpwuid(uid); + printf("uid=%u(%s)\n", getuid(), u ? u->pw_name : "???"); + gid = getgid(); + g = getgrgid(gid); + printf("gid=%u(%s)\n", gid, g ? g->gr_name : "???"); + printf("groups="); + status = getgroups(MAX_GROUPS, groups); + sep = ""; + for (j=0; j < status; j++) { + g = getgrgid(groups[j]); + printf("%s%u(%s)", sep, groups[j], g ? g->gr_name : "???"); + sep = ","; + } + printf("\n"); +} + int main(int argc, char *argv[], char *envp[]) { pid_t child; @@ -482,80 +579,7 @@ int main(int argc, char *argv[], char *envp[]) exit(1); } } else if (!strcmp("--print", argv[i])) { - unsigned cap; - int set, status, j; - cap_t all; - char *text; - const char *sep; - struct group *g; - gid_t groups[MAX_GROUPS], gid; - uid_t uid; - struct passwd *u; - - all = cap_get_proc(); - text = cap_to_text(all, NULL); - printf("Current: %s\n", text); - cap_free(text); - cap_free(all); - - printf("Bounding set ="); - sep = ""; - for (cap=0; (set = cap_get_bound(cap)) >= 0; cap++) { - char *ptr; - if (!set) { - continue; - } - - ptr = cap_to_name(cap); - if (ptr == NULL) { - printf("%s%u", sep, cap); - } else { - printf("%s%s", sep, ptr); - cap_free(ptr); - } - sep = ","; - } - printf("\n"); - set = prctl(PR_GET_SECUREBITS); - if (set >= 0) { - const char *b; - b = binary(set); /* use verilog convention for binary string */ - printf("Securebits: 0%o/0x%x/%u'b%s\n", set, set, - (unsigned) strlen(b), b); - printf(" secure-noroot: %s (%s)\n", - (set & 1) ? "yes":"no", - (set & 2) ? "locked":"unlocked"); - printf(" secure-no-suid-fixup: %s (%s)\n", - (set & 4) ? "yes":"no", - (set & 8) ? "locked":"unlocked"); - printf(" secure-keep-caps: %s (%s)\n", - (set & 16) ? "yes":"no", - (set & 32) ? "locked":"unlocked"); - } else { - printf("[Securebits ABI not supported]\n"); - set = prctl(PR_GET_KEEPCAPS); - if (set >= 0) { - printf(" prctl-keep-caps: %s (locking not supported)\n", - set ? "yes":"no"); - } else { - printf("[Keepcaps ABI not supported]\n"); - } - } - uid = getuid(); - u = getpwuid(uid); - printf("uid=%u(%s)\n", getuid(), u ? u->pw_name : "???"); - gid = getgid(); - g = getgrgid(gid); - printf("gid=%u(%s)\n", gid, g ? g->gr_name : "???"); - printf("groups="); - status = getgroups(MAX_GROUPS, groups); - sep = ""; - for (j=0; j < status; j++) { - g = getgrgid(groups[j]); - printf("%s%u(%s)", sep, groups[j], g ? g->gr_name : "???"); - sep = ","; - } - printf("\n"); + arg_print(); } else if ((!strcmp("--", argv[i])) || (!strcmp("==", argv[i]))) { argv[i] = strdup(argv[i][0] == '-' ? "/bin/bash" : argv[0]); argv[argc] = NULL; |