aboutsummaryrefslogtreecommitdiff
path: root/libcap
diff options
context:
space:
mode:
authorAndrew G. Morgan <morgan@kernel.org>2021-08-22 20:58:04 -0700
committerAndrew G. Morgan <morgan@kernel.org>2021-08-22 21:13:56 -0700
commit4f45bcc83545efdb4ffc5b9c05e1dbabe196339d (patch)
treeb72863f7b40f62a16b9c1446a4bf33d6e1e2f9a9 /libcap
parent596850bf55899c0217aa53fcff99491fbecdc2b2 (diff)
downloadlibcap-4f45bcc83545efdb4ffc5b9c05e1dbabe196339d.tar.gz
Add cap_iab_{compare,get_pid} functions to libcap; --iab to getpcaps.
This brings libcap back to parity with the Go 'cap' package. We provide a CAP_IAB_DIFFERS(result, vector) macro to evaluate the result of cap_iab_compare(). Extend the getpcaps arguments to include --iab. This causes the utility to explore the IAB tuple for the specified process. When used, this outputs a text representation in a similar format to that of the 'captree' (Go) utility. Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
Diffstat (limited to 'libcap')
-rw-r--r--libcap/cap_file.c2
-rw-r--r--libcap/cap_flag.c23
-rw-r--r--libcap/cap_text.c103
-rw-r--r--libcap/include/sys/capability.h3
4 files changed, 126 insertions, 5 deletions
diff --git a/libcap/cap_file.c b/libcap/cap_file.c
index 84ae3e1..95c0572 100644
--- a/libcap/cap_file.c
+++ b/libcap/cap_file.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 1997,2007,2016 Andrew G Morgan <morgan@kernel.org>
*
- * This file deals with setting capabilities on files.
+ * This file deals with getting/setting capabilities from/on files.
*/
#ifndef _DEFAULT_SOURCE
diff --git a/libcap/cap_flag.c b/libcap/cap_flag.c
index 51799b0..1f561f7 100644
--- a/libcap/cap_flag.c
+++ b/libcap/cap_flag.c
@@ -65,13 +65,10 @@ int cap_set_flag(cap_t cap_d, cap_flag_t set,
}
}
return 0;
-
} else {
-
_cap_debug("invalid arguments");
errno = EINVAL;
return -1;
-
}
}
@@ -283,3 +280,23 @@ int cap_iab_fill(cap_iab_t iab, cap_iab_vector_t vec,
return 0;
}
+
+/*
+ * cap_iab_compare compares two iab tuples.
+ */
+int cap_iab_compare(cap_iab_t a, cap_iab_t b)
+{
+ int j, result;
+ if (!(good_cap_iab_t(a) && good_cap_iab_t(b))) {
+ _cap_debug("invalid arguments");
+ errno = EINVAL;
+ return -1;
+ }
+ for (j=0, result=0; j<_LIBCAP_CAPABILITY_U32S; j++) {
+ result |=
+ (a->i[j] == b->i[j] ? 0 : (1 << CAP_IAB_INH)) |
+ (a->a[j] == b->a[j] ? 0 : (1 << CAP_IAB_AMB)) |
+ (a->nb[j] == b->nb[j] ? 0 : (1 << CAP_IAB_BOUND));
+ }
+ return result;
+}
diff --git a/libcap/cap_text.c b/libcap/cap_text.c
index 25c5ef5..17072f7 100644
--- a/libcap/cap_text.c
+++ b/libcap/cap_text.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-8,2007-8,2019 Andrew G Morgan <morgan@kernel.org>
+ * Copyright (c) 1997-8,2007-8,2019,2021 Andrew G Morgan <morgan@kernel.org>
* Copyright (c) 1997 Andrew Main <zefram@dcs.warwick.ac.uk>
*
* This file deals with exchanging internal and textual
@@ -609,3 +609,104 @@ cleanup:
errno = EINVAL;
return NULL;
}
+
+static __u32 _parse_hex32(const char *c)
+{
+ int i;
+ __u32 v = 0;
+ for (i=0; i < 8; i++, c++) {
+ v <<= 4;
+ if (*c == 0 || *c < '0') {
+ return 0;
+ } else if (*c <= '9') {
+ v += *c - '0';
+ } else if (*c > 'f') {
+ return 0;
+ } else if (*c >= 'a') {
+ v += *c + 10 - 'a';
+ } else if (*c < 'A') {
+ return 0;
+ } else if (*c <= 'F') {
+ v += *c + 10 - 'A';
+ } else {
+ return 0;
+ }
+ }
+ return v;
+}
+
+/*
+ * _parse_vec_string converts the hex dumps in /proc/<pid>/current into
+ * an array of u32s - masked as per the forceall() mask.
+ */
+static __u32 _parse_vec_string(__u32 *vals, const char *c, int invert)
+{
+ int i;
+ int words = strlen(c)/8;
+ if (words > _LIBCAP_CAPABILITY_U32S) {
+ return 0;
+ }
+ forceall(vals, ~0, words);
+ for (i = 0; i < words; i++) {
+ __u32 val = _parse_hex32(c+8*(words-1-i));
+ if (invert) {
+ val = ~val;
+ }
+ vals[i] &= val;
+ }
+ return ~0;
+}
+
+#define PROC_LINE_MAX (8 + 8*_LIBCAP_CAPABILITY_U32S + 100)
+/*
+ * cap_iab_get_pid fills an IAB tuple from the content of
+ * /proc/<pid>/status. Linux doesn't support syscall access to the
+ * needed information, so we parse it out of that file.
+ */
+cap_iab_t cap_iab_get_pid(pid_t pid)
+{
+ cap_iab_t iab;
+ char *path;
+ FILE *file;
+ char line[PROC_LINE_MAX];
+
+ if (asprintf(&path, "/proc/%d/status", pid) <= 0) {
+ return NULL;
+ }
+ file = fopen(path, "r");
+ free(path);
+ if (file == NULL) {
+ return NULL;
+ }
+
+ iab = cap_iab_init();
+ uint ok = 0;
+ if (iab != NULL) {
+ while (fgets(line, PROC_LINE_MAX-1, file) != NULL) {
+ if (strncmp("Cap", line, 3) != 0) {
+ continue;
+ }
+ if (strncmp("Inh:\t", line+3, 5) == 0) {
+ ok = (_parse_vec_string(iab->i, line+8, 0) &
+ LIBCAP_IAB_I_FLAG) | ok;
+ continue;
+ }
+ if (strncmp("Bnd:\t", line+3, 5) == 0) {
+ ok = (_parse_vec_string(iab->nb, line+8, 1) &
+ LIBCAP_IAB_NB_FLAG) | ok;
+ continue;
+ }
+ if (strncmp("Amb:\t", line+3, 5) == 0) {
+ ok = (_parse_vec_string(iab->a, line+8, 0) &
+ LIBCAP_IAB_A_FLAG) | ok;
+ continue;
+ }
+ }
+ }
+ if (ok != (LIBCAP_IAB_IA_FLAG | LIBCAP_IAB_NB_FLAG)) {
+ cap_free(iab);
+ iab = NULL;
+ }
+ fclose(file);
+ return iab;
+}
diff --git a/libcap/include/sys/capability.h b/libcap/include/sys/capability.h
index d172ddc..f98da5a 100644
--- a/libcap/include/sys/capability.h
+++ b/libcap/include/sys/capability.h
@@ -119,6 +119,8 @@ extern int cap_fill(cap_t, cap_flag_t, cap_flag_t);
#define CAP_DIFFERS(result, flag) (((result) & (1 << (flag))) != 0)
extern int cap_compare(cap_t, cap_t);
+#define CAP_IAB_DIFFERS(result, vector) (((result) & (1 << (vector))) != 0)
+extern int cap_iab_compare(cap_iab_t, cap_iab_t);
extern cap_flag_value_t cap_iab_get_vector(cap_iab_t, cap_iab_vector_t,
cap_value_t);
@@ -185,6 +187,7 @@ extern int cap_setuid(uid_t uid);
extern int cap_setgroups(gid_t gid, size_t ngroups, const gid_t groups[]);
extern cap_iab_t cap_iab_get_proc(void);
+extern cap_iab_t cap_iab_get_pid(pid_t);
extern int cap_iab_set_proc(cap_iab_t iab);
typedef struct cap_launch_s *cap_launch_t;