aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew G. Morgan <agm@google.com>2021-10-01 21:45:23 +0000
committerAndrew G. Morgan <morgan@kernel.org>2021-10-01 19:18:48 -0700
commit2ffbc9d2488e044cbb4851f3218f19171bafa46c (patch)
tree57316de33fb61d9c887e5475aecafa64cc24868b
parent6c0e37a5dc19842ba7c8111611789b0297e2ea1a (diff)
downloadlibcap-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.go29
-rw-r--r--doc/Makefile1
-rw-r--r--doc/cap_clear.314
-rw-r--r--doc/cap_fill.31
-rw-r--r--doc/cap_fill_flag.31
-rw-r--r--libcap/cap_flag.c19
-rw-r--r--libcap/cap_test.c16
-rw-r--r--libcap/include/sys/capability.h2
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)