diff options
author | Andrew G. Morgan <morgan@kernel.org> | 2019-12-15 10:54:19 -0800 |
---|---|---|
committer | Andrew G. Morgan <morgan@kernel.org> | 2019-12-15 11:17:17 -0800 |
commit | 3165de92058397670409dac6091f9358f2772328 (patch) | |
tree | 44e79ec1fa4ec74a8be542228554018044aa962d /cap/flags.go | |
parent | dada271ca4e9604a0373e39bc7621c95084d78ea (diff) | |
download | libcap-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.go | 142 |
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 +} |