summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew G. Morgan <morgan@kernel.org>2021-06-19 13:58:36 -0700
committerAndrew G. Morgan <morgan@kernel.org>2021-06-19 13:58:36 -0700
commitc89405455d3b730e933aa0520ca3c57a07117b80 (patch)
treedd8d178cba462cc30055c11cc6b8ecd469f80a5c
parent1a5a67b48cbcb83a968f973b2207c1d4b833a6dd (diff)
downloadlibcap2-c89405455d3b730e933aa0520ca3c57a07117b80.tar.gz
Add fill support for the 1e capabilities
We previously added a cap_iab_fill() etc, functions. Bring the regular capability flag manipulation API into alignment by adding libcap.cap_fill() and (*cap.Set).Fill(). Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
-rw-r--r--cap/cap_test.go14
-rw-r--r--cap/flags.go18
-rw-r--r--doc/cap_clear.36
-rw-r--r--libcap/Makefile4
-rw-r--r--libcap/cap_flag.c25
-rw-r--r--libcap/cap_test.c45
-rw-r--r--libcap/include/sys/capability.h7
7 files changed, 112 insertions, 7 deletions
diff --git a/cap/cap_test.go b/cap/cap_test.go
index f2c8ed0..d7c7970 100644
--- a/cap/cap_test.go
+++ b/cap/cap_test.go
@@ -284,3 +284,17 @@ func TestFuncLaunch(t *testing.T) {
}
}
}
+
+func TestFill(t *testing.T) {
+ c, err := FromText("cap_setfcap=p")
+ if err != nil {
+ t.Fatalf("failed to parse: %v", err)
+ }
+ c.Fill(Effective, Permitted)
+ c.ClearFlag(Permitted)
+ c.Fill(Inheritable, Effective)
+ c.ClearFlag(Effective)
+ if got, want := c.String(), "cap_setfcap=i"; got != want {
+ t.Errorf("Fill failed: got=%q want=%q", got, want)
+ }
+}
diff --git a/cap/flags.go b/cap/flags.go
index b800a2d..83a871a 100644
--- a/cap/flags.go
+++ b/cap/flags.go
@@ -75,6 +75,24 @@ func (c *Set) Clear() error {
return nil
}
+// Fill copies the from flag values into the to flag. With this
+// function, you can raise all of the permitted values in the
+// effective flag with c.Fill(cap.Effective, cap.Permitted).
+func (c *Set) Fill(to, from Flag) error {
+ if c == nil || len(c.flat) == 0 {
+ return ErrBadSet
+ }
+ if to > Inheritable || from > Inheritable {
+ return ErrBadValue
+ }
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ for i := range c.flat {
+ c.flat[i][to] = c.flat[i][from]
+ }
+ return nil
+}
+
// ErrBadValue indicates a bad capability value was specified.
var ErrBadValue = errors.New("bad capability value")
diff --git a/doc/cap_clear.3 b/doc/cap_clear.3
index 954b32e..6d06049 100644
--- a/doc/cap_clear.3
+++ b/doc/cap_clear.3
@@ -1,6 +1,6 @@
.TH CAP_CLEAR 3 "2021-03-06" "" "Linux Programmer's Manual"
.SH NAME
-cap_clear, cap_clear_flag, cap_get_flag, cap_set_flag, cap_compare \- capability data object manipulation
+cap_clear, cap_clear_flag, cap_get_flag, cap_set_flag, cap_fill, cap_compare \- capability data object manipulation
.SH SYNOPSIS
.nf
#include <sys/capability.h>
@@ -11,6 +11,7 @@ int cap_get_flag(cap_t cap_p, cap_value_t cap,
cap_flag_t flag, cap_flag_value_t *value_p);
int cap_set_flag(cap_t cap_p, cap_flag_t flag, int ncap,
const cap_value_t *caps, cap_flag_value_t value);
+int cap_fill(cap_t cap_p, cap_flag_t to, cap_flag_t from);
int cap_compare(cap_t cap_a, cap_t cap_b);
.fi
.sp
@@ -80,6 +81,9 @@ The argument,
is used to specify the number of capabilities in the array,
.IR caps .
.PP
+.BR cap_fill ()
+fills the to flag values by copying all of the from flag values.
+.PP
.BR cap_compare ()
compares two full capability sets and, in the spirit of
.BR memcmp (),
diff --git a/libcap/Makefile b/libcap/Makefile
index 9563d88..bdd32a9 100644
--- a/libcap/Makefile
+++ b/libcap/Makefile
@@ -110,8 +110,8 @@ endif
cap_text.o: cap_text.c $(USE_GPERF_OUTPUT) $(INCLS)
$(CC) $(CFLAGS) $(IPATH) $(INCLUDE_GPERF_OUTPUT) -c $< -o $@
-cap_test: cap_test.c libcap.h
- $(CC) $(CFLAGS) $(IPATH) $< -o $@
+cap_test: cap_test.c libcap.h $(CAPOBJS)
+ $(CC) $(CFLAGS) $(IPATH) $< $(CAPOBJS) -o $@
test: cap_test
./cap_test
diff --git a/libcap/cap_flag.c b/libcap/cap_flag.c
index c1ffa0d..51799b0 100644
--- a/libcap/cap_flag.c
+++ b/libcap/cap_flag.c
@@ -147,6 +147,31 @@ int cap_compare(cap_t a, cap_t b)
}
/*
+ * cap_fill copies a bit-vector of capability state in a cap_t from
+ * one flag to another.
+ */
+int cap_fill(cap_t cap_d, cap_flag_t to, cap_flag_t from)
+{
+ if (!good_cap_t(cap_d)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (to < CAP_EFFECTIVE || to > CAP_INHERITABLE ||
+ from < CAP_EFFECTIVE || from > CAP_INHERITABLE) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ int i;
+ for (i = 0; i < _LIBCAP_CAPABILITY_U32S; i++) {
+ cap_d->u[i].flat[to] = cap_d->u[i].flat[from];
+ }
+
+ return 0;
+}
+
+/*
* cap_iab_get_vector reads the single bit value from an IAB vector set.
*/
cap_flag_value_t cap_iab_get_vector(cap_iab_t iab, cap_iab_vector_t vec,
diff --git a/libcap/cap_test.c b/libcap/cap_test.c
index 4ea83c8..c9e83de 100644
--- a/libcap/cap_test.c
+++ b/libcap/cap_test.c
@@ -29,11 +29,54 @@ static int test_cap_bits(void) {
return failed;
}
+static int test_cap_flags(void) {
+ cap_t c, d;
+ cap_flag_t f = CAP_INHERITABLE, t;
+ cap_value_t v;
+
+ c = cap_init();
+ if (c == NULL) {
+ printf("test_flags failed to allocate a set\n");
+ return -1;
+ }
+
+ for (v = 0; v < __CAP_MAXBITS; v += 3) {
+ if (cap_set_flag(c, CAP_INHERITABLE, 1, &v, CAP_SET)) {
+ printf("unable to set inheritable bit %d\n", v);
+ return -1;
+ }
+ }
+
+ d = cap_dup(c);
+ for (t = CAP_EFFECTIVE; t <= CAP_INHERITABLE; t++) {
+ if (cap_fill(c, t, f)) {
+ printf("cap_fill failed %d -> %d\n", f, t);
+ return -1;
+ }
+ if (cap_clear_flag(c, f)) {
+ printf("cap_fill unable to clear flag %d\n", f);
+ return -1;
+ }
+ f = t;
+ }
+ if (cap_compare(c, d)) {
+ printf("permuted cap_fill()ing failed to perform net no-op\n");
+ return -1;
+ }
+ cap_free(d);
+ cap_free(c);
+ return 0;
+}
+
int main(int argc, char **argv) {
int result = 0;
+
result = test_cap_bits() | result;
+ result = test_cap_flags() | result;
+
if (result) {
- printf("test FAILED\n");
+ printf("cap_test FAILED\n");
exit(1);
}
+ printf("cap_test PASS\n");
}
diff --git a/libcap/include/sys/capability.h b/libcap/include/sys/capability.h
index 17cdcd5..d172ddc 100644
--- a/libcap/include/sys/capability.h
+++ b/libcap/include/sys/capability.h
@@ -115,6 +115,10 @@ extern int cap_set_flag(cap_t, cap_flag_t, int, const cap_value_t *,
cap_flag_value_t);
extern int cap_clear(cap_t);
extern int cap_clear_flag(cap_t, cap_flag_t);
+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);
extern cap_flag_value_t cap_iab_get_vector(cap_iab_t, cap_iab_vector_t,
cap_value_t);
@@ -159,9 +163,6 @@ extern char * cap_to_name(cap_value_t);
extern char * cap_iab_to_text(cap_iab_t iab);
extern cap_iab_t cap_iab_from_text(const char *text);
-#define CAP_DIFFERS(result, flag) (((result) & (1 << (flag))) != 0)
-extern int cap_compare(cap_t, cap_t);
-
/* libcap/cap_proc.c */
extern void cap_set_syscall(long int (*new_syscall)(long int,
long int, long int, long int),