aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew G. Morgan <morgan@kernel.org>2016-02-06 19:49:07 -0800
committerAndrew G. Morgan <morgan@kernel.org>2016-02-06 19:49:07 -0800
commit0f0eca489e979b4a8526e521f962455e474a27a0 (patch)
tree0e8027ecad22b844deb36f5bee73712f5cc57b77
parentdce069b617cf5e42fde707196eaf2ee8d62bc96c (diff)
downloadlibcap-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.c69
-rw-r--r--libcap/include/sys/capability.h6
-rw-r--r--libcap/include/uapi/linux/prctl.h48
-rw-r--r--progs/capsh.c174
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;