You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
288 lines
6.6 KiB
288 lines
6.6 KiB
package cap
|
|
|
|
import "strings"
|
|
|
|
// omask returns the offset and mask for a specific capability.
|
|
func omask(c Value) (uint, uint32) {
|
|
u := uint(c)
|
|
return u >> 5, uint32(1) << (u & 31)
|
|
}
|
|
|
|
// IAB holds a summary of all of the inheritable capability vectors:
|
|
// Inh, Amb and Bound. The Bound vector is the logical inverse (two's
|
|
// complement) of the process' Bounding set. That is, raising a Value
|
|
// in the Bound (think blocked) vector is equivalent to dropping that
|
|
// Value from the process' Bounding set. This convention is used to
|
|
// support the empty IAB as being mostly harmless.
|
|
type IAB struct {
|
|
a, i, nb []uint32
|
|
}
|
|
|
|
// Vector enumerates which of the inheritable IAB capability vectors
|
|
// is being manipulated.
|
|
type Vector uint
|
|
|
|
// Inh, Amb, Bound enumerate the IAB vector components. (Vector) Inh
|
|
// is equivalent to (Flag) Inheritable. They are named differently for
|
|
// syntax/type checking reasons.
|
|
const (
|
|
Inh Vector = iota
|
|
Amb
|
|
Bound
|
|
)
|
|
|
|
// String identifies a Vector value by its conventional I A or B
|
|
// string abbreviation.
|
|
func (v Vector) String() string {
|
|
switch v {
|
|
case Inh:
|
|
return "I"
|
|
case Amb:
|
|
return "A"
|
|
case Bound:
|
|
return "B"
|
|
default:
|
|
return "<Error>"
|
|
}
|
|
}
|
|
|
|
// IABInit returns an empty IAB.
|
|
func IABInit() *IAB {
|
|
startUp.Do(multisc.cInit)
|
|
return &IAB{
|
|
i: make([]uint32, words),
|
|
a: make([]uint32, words),
|
|
nb: make([]uint32, words),
|
|
}
|
|
}
|
|
|
|
// IABGetProc summarizes the Inh, Amb and Bound capabilty vectors of
|
|
// the current process.
|
|
func IABGetProc() *IAB {
|
|
iab := IABInit()
|
|
current := GetProc()
|
|
iab.Fill(Inh, current, Inheritable)
|
|
for c := MaxBits(); c > 0; {
|
|
c--
|
|
offset, mask := omask(c)
|
|
if a, _ := GetAmbient(c); a {
|
|
iab.a[offset] |= mask
|
|
}
|
|
if b, err := GetBound(c); err == nil && !b {
|
|
iab.nb[offset] |= mask
|
|
}
|
|
}
|
|
return iab
|
|
}
|
|
|
|
// IABFromText parses a string representing an IAB, as generated
|
|
// by IAB.String(), to generate an IAB.
|
|
func IABFromText(text string) (*IAB, error) {
|
|
iab := IABInit()
|
|
if len(text) == 0 {
|
|
return iab, nil
|
|
}
|
|
for _, f := range strings.Split(text, ",") {
|
|
var i, a, nb bool
|
|
var j int
|
|
for j = 0; j < len(f); j++ {
|
|
switch f[j : j+1] {
|
|
case "!":
|
|
nb = true
|
|
case "^":
|
|
i = true
|
|
a = true
|
|
case "%":
|
|
i = true
|
|
default:
|
|
goto done
|
|
}
|
|
}
|
|
done:
|
|
c, err := FromName(f[j:])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
offset, mask := omask(c)
|
|
if i || !nb {
|
|
iab.i[offset] |= mask
|
|
}
|
|
if a {
|
|
iab.a[offset] |= mask
|
|
}
|
|
if nb {
|
|
iab.nb[offset] |= mask
|
|
}
|
|
}
|
|
return iab, nil
|
|
}
|
|
|
|
// String serializes an IAB to a string format.
|
|
func (iab *IAB) String() string {
|
|
var vs []string
|
|
for c := Value(0); c < Value(maxValues); c++ {
|
|
offset, mask := omask(c)
|
|
i := (iab.i[offset] & mask) != 0
|
|
a := (iab.a[offset] & mask) != 0
|
|
nb := (iab.nb[offset] & mask) != 0
|
|
var cs []string
|
|
if nb {
|
|
cs = append(cs, "!")
|
|
}
|
|
if a {
|
|
cs = append(cs, "^")
|
|
} else if nb && i {
|
|
cs = append(cs, "%")
|
|
}
|
|
if nb || a || i {
|
|
vs = append(vs, strings.Join(cs, "")+c.String())
|
|
}
|
|
}
|
|
return strings.Join(vs, ",")
|
|
}
|
|
|
|
func (sc *syscaller) iabSetProc(iab *IAB) (err error) {
|
|
temp := GetProc()
|
|
var raising uint32
|
|
for i := 0; i < words; i++ {
|
|
newI := iab.i[i]
|
|
oldIP := temp.flat[i][Inheritable] | temp.flat[i][Permitted]
|
|
raising |= (newI & ^oldIP) | iab.a[i] | iab.nb[i]
|
|
temp.flat[i][Inheritable] = newI
|
|
}
|
|
working, err2 := temp.Dup()
|
|
if err2 != nil {
|
|
err = err2
|
|
return
|
|
}
|
|
if raising != 0 {
|
|
if err = working.SetFlag(Effective, true, SETPCAP); err != nil {
|
|
return
|
|
}
|
|
if err = sc.setProc(working); err != nil {
|
|
return
|
|
}
|
|
}
|
|
defer func() {
|
|
if err2 := sc.setProc(temp); err == nil {
|
|
err = err2
|
|
}
|
|
}()
|
|
if err = sc.resetAmbient(); err != nil {
|
|
return
|
|
}
|
|
for c := Value(maxValues); c > 0; {
|
|
c--
|
|
offset, mask := omask(c)
|
|
if iab.a[offset]&mask != 0 {
|
|
err = sc.setAmbient(true, c)
|
|
}
|
|
if err == nil && iab.nb[offset]&mask != 0 {
|
|
err = sc.dropBound(c)
|
|
}
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// SetProc attempts to change the Inheritable, Ambient and Bounding
|
|
// capabilty vectors of the current process using the content,
|
|
// iab. The Bounding vector strongly affects the potential for setting
|
|
// other bits, so this function carefully performs the the combined
|
|
// operation in the most flexible manner.
|
|
func (iab *IAB) SetProc() error {
|
|
scwMu.Lock()
|
|
defer scwMu.Unlock()
|
|
return multisc.iabSetProc(iab)
|
|
}
|
|
|
|
// GetVector returns the raised state of the specific capability bit
|
|
// of the indicated vector.
|
|
func (iab *IAB) GetVector(vec Vector, val Value) (bool, error) {
|
|
if val >= MaxBits() {
|
|
return false, ErrBadValue
|
|
}
|
|
offset, mask := omask(val)
|
|
switch vec {
|
|
case Inh:
|
|
return (iab.i[offset] & mask) != 0, nil
|
|
case Amb:
|
|
return (iab.a[offset] & mask) != 0, nil
|
|
case Bound:
|
|
return (iab.nb[offset] & mask) != 0, nil
|
|
default:
|
|
return false, ErrBadValue
|
|
}
|
|
}
|
|
|
|
// SetVector sets all of the vals in the specified vector to the
|
|
// raised value. Note, the Ambient vector cannot contain values not raised
|
|
// in the Inh vector, so setting values directly in one vector may have
|
|
// the side effect of mirroring the value in the other vector to
|
|
// maintain this constraint. Note, raising a Bound vector bit is
|
|
// equivalent to lowering the Bounding vector of the process (when
|
|
// successfully applied with (*IAB).SetProc()).
|
|
func (iab *IAB) SetVector(vec Vector, raised bool, vals ...Value) error {
|
|
for _, val := range vals {
|
|
if val >= Value(maxValues) {
|
|
return ErrBadValue
|
|
}
|
|
offset, mask := omask(val)
|
|
switch vec {
|
|
case Inh:
|
|
if raised {
|
|
iab.i[offset] |= mask
|
|
} else {
|
|
iab.i[offset] &= ^mask
|
|
iab.a[offset] &= ^mask
|
|
}
|
|
case Amb:
|
|
if raised {
|
|
iab.a[offset] |= mask
|
|
iab.i[offset] |= mask
|
|
} else {
|
|
iab.a[offset] &= ^mask
|
|
}
|
|
case Bound:
|
|
if raised {
|
|
iab.nb[offset] |= mask
|
|
} else {
|
|
iab.nb[offset] &= ^mask
|
|
}
|
|
default:
|
|
return ErrBadValue
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Fill fills one of the Inh, Amb and Bound capability vectors from
|
|
// one of the flag vectors of a Set. Note, filling the Inh vector
|
|
// will mask the Amb vector, and filling the Amb vector may raise
|
|
// entries in the Inh vector. Further, when filling the Bound vector,
|
|
// the bits are inverted from what you might expect - that is lowered
|
|
// bits from the Set will be raised in the Bound vector.
|
|
func (iab *IAB) Fill(vec Vector, c *Set, flag Flag) error {
|
|
if len(c.flat) != 0 || flag > Inheritable {
|
|
return ErrBadSet
|
|
}
|
|
for i := 0; i < words; i++ {
|
|
flat := c.flat[i][flag]
|
|
switch vec {
|
|
case Inh:
|
|
iab.i[i] = flat
|
|
iab.a[i] &= ^flat
|
|
case Amb:
|
|
iab.a[i] = flat
|
|
iab.i[i] |= ^flat
|
|
case Bound:
|
|
iab.nb[i] = ^flat
|
|
default:
|
|
return ErrBadSet
|
|
}
|
|
}
|
|
return nil
|
|
}
|