diff options
author | Andrew G. Morgan <morgan@kernel.org> | 2021-06-19 13:58:36 -0700 |
---|---|---|
committer | Andrew G. Morgan <morgan@kernel.org> | 2021-06-19 13:58:36 -0700 |
commit | c89405455d3b730e933aa0520ca3c57a07117b80 (patch) | |
tree | dd8d178cba462cc30055c11cc6b8ecd469f80a5c | |
parent | 1a5a67b48cbcb83a968f973b2207c1d4b833a6dd (diff) | |
download | libcap2-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.go | 14 | ||||
-rw-r--r-- | cap/flags.go | 18 | ||||
-rw-r--r-- | doc/cap_clear.3 | 6 | ||||
-rw-r--r-- | libcap/Makefile | 4 | ||||
-rw-r--r-- | libcap/cap_flag.c | 25 | ||||
-rw-r--r-- | libcap/cap_test.c | 45 | ||||
-rw-r--r-- | libcap/include/sys/capability.h | 7 |
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), |