diff options
author | Andrew G. Morgan <agm@google.com> | 2021-10-01 21:45:23 +0000 |
---|---|---|
committer | Andrew G. Morgan <morgan@kernel.org> | 2021-10-01 19:18:48 -0700 |
commit | 2ffbc9d2488e044cbb4851f3218f19171bafa46c (patch) | |
tree | 57316de33fb61d9c887e5475aecafa64cc24868b | |
parent | 6c0e37a5dc19842ba7c8111611789b0297e2ea1a (diff) | |
download | libcap-2ffbc9d2488e044cbb4851f3218f19171bafa46c.tar.gz |
Implement cap_fill_flag() and cap.FillFlag() APIs.
This API avoids a complex use case that requires substantially
more code outside of libcap.
Signed-off-by: Andrew G. Morgan <agm@google.com>
Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
-rw-r--r-- | cap/flags.go | 29 | ||||
-rw-r--r-- | doc/Makefile | 1 | ||||
-rw-r--r-- | doc/cap_clear.3 | 14 | ||||
-rw-r--r-- | doc/cap_fill.3 | 1 | ||||
-rw-r--r-- | doc/cap_fill_flag.3 | 1 | ||||
-rw-r--r-- | libcap/cap_flag.c | 19 | ||||
-rw-r--r-- | libcap/cap_test.c | 16 | ||||
-rw-r--r-- | libcap/include/sys/capability.h | 2 |
8 files changed, 68 insertions, 15 deletions
diff --git a/cap/flags.go b/cap/flags.go index df7a9a5..57c0443 100644 --- a/cap/flags.go +++ b/cap/flags.go @@ -75,24 +75,41 @@ 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 { +// FillFlag copies the from flag values of ref into the to flag of +// c. With this function, you can raise all of the permitted values in +// the c Set from those in ref with c.Fill(cap.Permitted, ref, +// cap.Permitted). +func (c *Set) FillFlag(to Flag, ref *Set, from Flag) error { + if c == nil || len(c.flat) == 0 || ref == nil || len(ref.flat) == 0 { return ErrBadSet } if to > Inheritable || from > Inheritable { return ErrBadValue } + + // Avoid deadlock by copying to intermediate memory. + a := make([]uint32, len(ref.flat)) + ref.mu.Lock() + for i := range ref.flat { + a[i] = ref.flat[i][from] + } + ref.mu.Unlock() + c.mu.Lock() defer c.mu.Unlock() for i := range c.flat { - c.flat[i][to] = c.flat[i][from] + c.flat[i][to] = a[i] } 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 { + return c.FillFlag(to, c, from) +} + // ErrBadValue indicates a bad capability value was specified. var ErrBadValue = errors.New("bad capability value") diff --git a/doc/Makefile b/doc/Makefile index 9614180..4fc9ea5 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -8,6 +8,7 @@ include $(topdir)/Make.Rules MAN1S = capsh.1 MAN3S = cap_init.3 cap_free.3 cap_dup.3 \ cap_clear.3 cap_clear_flag.3 cap_get_flag.3 cap_set_flag.3 \ + cap_fill.3 cap_fill_flag.3 \ cap_compare.3 cap_get_proc.3 cap_get_pid.3 cap_set_proc.3 \ cap_get_file.3 cap_get_fd.3 cap_set_file.3 cap_set_fd.3 \ cap_copy_ext.3 cap_size.3 cap_copy_int.3 cap_mode.3 \ diff --git a/doc/cap_clear.3 b/doc/cap_clear.3 index eb8f4ec..a1c40d5 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" +.TH CAP_CLEAR 3 "2021-10-01" "" "Linux Programmer's Manual" .SH NAME -cap_clear, cap_clear_flag, cap_get_flag, cap_set_flag, cap_fill, cap_compare \- capability data object manipulation +cap_clear, cap_clear_flag, cap_get_flag, cap_set_flag, cap_fill_flag, cap_fill, cap_compare \- capability data object manipulation .SH SYNOPSIS .nf #include <sys/capability.h> @@ -11,6 +11,8 @@ 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_flag(cap_t cap_p, cap_flag_t to, + const cap_t ref, cap_flag_t from); 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 @@ -20,7 +22,7 @@ Link with \fI\-lcap\fP. These functions work on a capability state held in working storage. A .I cap_t -holds information about the capabilities in each of the three sets, +holds information about the capabilities in each of the three flags, Permitted, Inheritable, and Effective. Each capability in a set may be clear (disabled, 0) or set (enabled, 1). .PP @@ -32,7 +34,7 @@ identifies a capability, such as .TP .I cap_flag_t identifies one of the three flags associated with a capability -(i.e., it identifies one of the three capability sets). +(i.e., it identifies one of the three capability dimensions). Valid values for this type are .BR CAP_EFFECTIVE , .B CAP_INHERITABLE @@ -81,6 +83,10 @@ The argument, is used to specify the number of capabilities in the array, .IR caps . .PP +.BR cap_fill_flag () +fills the to flag of one capability set, with the values in the from +flag of a reference capability set. +.PP .BR cap_fill () fills the to flag values by copying all of the from flag values. .PP diff --git a/doc/cap_fill.3 b/doc/cap_fill.3 new file mode 100644 index 0000000..db506c6 --- /dev/null +++ b/doc/cap_fill.3 @@ -0,0 +1 @@ +.so man3/cap_clear.3 diff --git a/doc/cap_fill_flag.3 b/doc/cap_fill_flag.3 new file mode 100644 index 0000000..db506c6 --- /dev/null +++ b/doc/cap_fill_flag.3 @@ -0,0 +1 @@ +.so man3/cap_clear.3 diff --git a/libcap/cap_flag.c b/libcap/cap_flag.c index 9df1842..d94232b 100644 --- a/libcap/cap_flag.c +++ b/libcap/cap_flag.c @@ -143,12 +143,12 @@ 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. + * cap_fill_flag copies a bit-vector of capability state in one cap_t from one + * flag to another flag of another cap_t. */ -int cap_fill(cap_t cap_d, cap_flag_t to, cap_flag_t from) +int cap_fill_flag(cap_t cap_d, cap_flag_t to, const cap_t ref, cap_flag_t from) { - if (!good_cap_t(cap_d)) { + if (!good_cap_t(cap_d) || !good_cap_t(ref)) { errno = EINVAL; return -1; } @@ -161,13 +161,22 @@ int cap_fill(cap_t cap_d, cap_flag_t to, cap_flag_t from) int i; for (i = 0; i < _LIBCAP_CAPABILITY_U32S; i++) { - cap_d->u[i].flat[to] = cap_d->u[i].flat[from]; + cap_d->u[i].flat[to] = ref->u[i].flat[from]; } return 0; } /* + * 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) +{ + return cap_fill_flag(cap_d, to, cap_d, from); +} + +/* * 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 b523091..b7fb2c5 100644 --- a/libcap/cap_test.c +++ b/libcap/cap_test.c @@ -84,6 +84,22 @@ static int test_cap_flags(void) printf("permuted cap_fill()ing failed to perform net no-op\n"); retval = -1; } + if (cap_fill_flag(NULL, CAP_EFFECTIVE, c, CAP_INHERITABLE) == 0) { + printf("filling NULL flag should fail\n"); + retval = -1; + } + if (cap_fill_flag(d, CAP_PERMITTED, c, CAP_INHERITABLE) != 0) { + perror("filling PERMITEED flag should work"); + retval = -1; + } + if (cap_fill_flag(c, CAP_PERMITTED, d, CAP_PERMITTED) != 0) { + perror("filling PERMITTED flag from another cap_t should work"); + retval = -1; + } + if (cap_compare(c, d)) { + printf("permuted cap_fill()ing failed to perform net no-op\n"); + retval = -1; + } drop_d: if (cap_free(d) != 0) { diff --git a/libcap/include/sys/capability.h b/libcap/include/sys/capability.h index 80171b0..429d8ad 100644 --- a/libcap/include/sys/capability.h +++ b/libcap/include/sys/capability.h @@ -135,6 +135,8 @@ 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_flag(cap_t cap_d, cap_flag_t to, + const cap_t ref, cap_flag_t from); extern int cap_fill(cap_t, cap_flag_t, cap_flag_t); #define CAP_DIFFERS(result, flag) (((result) & (1 << (flag))) != 0) |