aboutsummaryrefslogtreecommitdiff
path: root/cap/flags.go
diff options
context:
space:
mode:
authorAndrew G. Morgan <morgan@kernel.org>2019-12-15 10:54:19 -0800
committerAndrew G. Morgan <morgan@kernel.org>2019-12-15 11:17:17 -0800
commit3165de92058397670409dac6091f9358f2772328 (patch)
tree44e79ec1fa4ec74a8be542228554018044aa962d /cap/flags.go
parentdada271ca4e9604a0373e39bc7621c95084d78ea (diff)
downloadlibcap-3165de92058397670409dac6091f9358f2772328.tar.gz
More convenience functionality for libcap.
As well as substantial updates to the man pages, including an explanation of how capabilities can be robustly used with pthreads, implement a set of convenience functions in libcap to make dropping privilege in careful ways straightforward. These include adding the abstraction of libcap recommended "modes" and cap_setuid() and cap_setgroups() functions. The progs/quicktest.sh script and capsh has been extended to validate each of these new functions. Add convenience functions to the libcap/cap Go package. Specifically, added Compare(), Differs(), GetSecbits() & Secbits.Set(), GetMode() & Mode.Set(), SetUID() and SetGroups(). Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
Diffstat (limited to 'cap/flags.go')
-rw-r--r--cap/flags.go142
1 files changed, 142 insertions, 0 deletions
diff --git a/cap/flags.go b/cap/flags.go
new file mode 100644
index 0000000..8e4fcd7
--- /dev/null
+++ b/cap/flags.go
@@ -0,0 +1,142 @@
+package cap
+
+import "errors"
+
+// GetFlag determines if the requested bit is enabled in the Flag
+// vector of the capability Set.
+func (c *Set) GetFlag(vec Flag, val Value) (bool, error) {
+ if c == nil || len(c.flat) == 0 {
+ // Checked this first, because otherwise we are sure
+ // cInit has been called.
+ return false, ErrBadSet
+ }
+ offset, mask, err := bitOf(vec, val)
+ if err != nil {
+ return false, err
+ }
+ c.mu.RLock()
+ defer c.mu.RUnlock()
+ return c.flat[offset][vec]&mask != 0, nil
+}
+
+// SetFlag sets the requested bits to the indicated enable state. This
+// function does not perform any security checks, so values can be set
+// out-of-order. Only when the Set is used to SetProc() etc., will the
+// bits be checked for validity and permission by the kernel. If the
+// function returns an error, the Set will not be modified.
+func (c *Set) SetFlag(vec Flag, enable bool, val ...Value) error {
+ if c == nil || len(c.flat) == 0 {
+ // Checked this first, because otherwise we are sure
+ // cInit has been called.
+ return ErrBadSet
+ }
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ // Make a backup.
+ replace := make([]uint32, words)
+ for i := range replace {
+ replace[i] = c.flat[i][vec]
+ }
+ var err error
+ for _, v := range val {
+ offset, mask, err2 := bitOf(vec, v)
+ if err2 != nil {
+ err = err2
+ break
+ }
+ if enable {
+ c.flat[offset][vec] |= mask
+ } else {
+ c.flat[offset][vec] &= ^mask
+ }
+ }
+ if err == nil {
+ return nil
+ }
+ // Clean up.
+ for i, bits := range replace {
+ c.flat[i][vec] = bits
+ }
+ return err
+}
+
+// Clear fully clears a capability set.
+func (c *Set) Clear() error {
+ if c == nil || len(c.flat) == 0 {
+ return ErrBadSet
+ }
+ // startUp.Do(cInit) is not called here because c cannot be
+ // initialized except via this package and doing that will
+ // perform that call at least once (sic).
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ c.flat = make([]data, words)
+ c.nsRoot = 0
+ return nil
+}
+
+// ErrBadValue indicates a bad capability value was specified.
+var ErrBadValue = errors.New("bad capability value")
+
+// bitOf converts from a Value into the offset and mask for a
+// specific Value bit in the compressed (kernel ABI) representation of
+// a capability vector. If the requested bit is unsupported, an error
+// is returned.
+func bitOf(vec Flag, val Value) (uint, uint32, error) {
+ if vec > Inheritable || val > Value(words*32) {
+ return 0, 0, ErrBadValue
+ }
+ u := uint(val)
+ return u / 32, uint32(1) << (u % 32), nil
+}
+
+// forceFlag sets all capability values of a flag vector to enable.
+func (c *Set) forceFlag(vec Flag, enable bool) error {
+ if c == nil || len(c.flat) == 0 || vec > Inheritable {
+ return ErrBadSet
+ }
+ m := uint32(0)
+ if enable {
+ m = ^m
+ }
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ for i := range c.flat {
+ c.flat[i][vec] = m
+ }
+ return nil
+}
+
+// ClearFlag clears a specific vector of Values associated with the
+// specified Flag.
+func (c *Set) ClearFlag(vec Flag) error {
+ return c.forceFlag(vec, false)
+}
+
+// Compare returns 0 if c and d are identical in content. Otherwise,
+// this function returns a non-zero value of 3 independent bits:
+// (differE ? 1:0) | (differP ? 2:0) | (differI ? 4:0).
+func (c *Set) Compare(d *Set) (uint, error) {
+ if c == nil || len(c.flat) == 0 || d == nil || len(d.flat) == 0 {
+ return 0, ErrBadSet
+ }
+ var cf uint
+ for i := 0; i < words; i++ {
+ if c.flat[i][Effective]^d.flat[i][Effective] != 0 {
+ cf |= (1 << Effective)
+ }
+ if c.flat[i][Permitted]^d.flat[i][Permitted] != 0 {
+ cf |= (1 << Permitted)
+ }
+ if c.flat[i][Inheritable]^d.flat[i][Inheritable] != 0 {
+ cf |= (1 << Inheritable)
+ }
+ }
+ return cf, nil
+}
+
+// Differs processes the result of Compare and determines if the
+// Flag's components were different.
+func Differs(cf uint, vec Flag) bool {
+ return cf&(1<<vec) != 0
+}