1package cap 2 3import "strings" 4 5// omask returns the offset and mask for a specific capability. 6func omask(c Value) (uint, uint32) { 7 u := uint(c) 8 return u >> 5, uint32(1) << (u & 31) 9} 10 11// IAB holds a summary of all of the inheritable capability vectors: 12// Inh, Amb and Bound. The Bound vector is the logical inverse (two's 13// complement) of the process' Bounding set. That is, raising a Value 14// in the Bound (think blocked) vector is equivalent to dropping that 15// Value from the process' Bounding set. This convention is used to 16// support the empty IAB as being mostly harmless. 17type IAB struct { 18 a, i, nb []uint32 19} 20 21// Vector enumerates which of the inheritable IAB capability vectors 22// is being manipulated. 23type Vector uint 24 25// Inh, Amb, Bound enumerate the IAB vector components. (Vector) Inh 26// is equivalent to (Flag) Inheritable. They are named differently for 27// syntax/type checking reasons. 28const ( 29 Inh Vector = iota 30 Amb 31 Bound 32) 33 34// String identifies a Vector value by its conventional I A or B 35// string abbreviation. 36func (v Vector) String() string { 37 switch v { 38 case Inh: 39 return "I" 40 case Amb: 41 return "A" 42 case Bound: 43 return "B" 44 default: 45 return "<Error>" 46 } 47} 48 49// IABInit returns an empty IAB. 50func IABInit() *IAB { 51 startUp.Do(multisc.cInit) 52 return &IAB{ 53 i: make([]uint32, words), 54 a: make([]uint32, words), 55 nb: make([]uint32, words), 56 } 57} 58 59// IABGetProc summarizes the Inh, Amb and Bound capabilty vectors of 60// the current process. 61func IABGetProc() *IAB { 62 iab := IABInit() 63 current := GetProc() 64 iab.Fill(Inh, current, Inheritable) 65 for c := MaxBits(); c > 0; { 66 c-- 67 offset, mask := omask(c) 68 if a, _ := GetAmbient(c); a { 69 iab.a[offset] |= mask 70 } 71 if b, err := GetBound(c); err == nil && !b { 72 iab.nb[offset] |= mask 73 } 74 } 75 return iab 76} 77 78// IABFromText parses a string representing an IAB, as generated 79// by IAB.String(), to generate an IAB. 80func IABFromText(text string) (*IAB, error) { 81 iab := IABInit() 82 if len(text) == 0 { 83 return iab, nil 84 } 85 for _, f := range strings.Split(text, ",") { 86 var i, a, nb bool 87 var j int 88 for j = 0; j < len(f); j++ { 89 switch f[j : j+1] { 90 case "!": 91 nb = true 92 case "^": 93 i = true 94 a = true 95 case "%": 96 i = true 97 default: 98 goto done 99 } 100 } 101 done: 102 c, err := FromName(f[j:]) 103 if err != nil { 104 return nil, err 105 } 106 offset, mask := omask(c) 107 if i || !nb { 108 iab.i[offset] |= mask 109 } 110 if a { 111 iab.a[offset] |= mask 112 } 113 if nb { 114 iab.nb[offset] |= mask 115 } 116 } 117 return iab, nil 118} 119 120// String serializes an IAB to a string format. 121func (iab *IAB) String() string { 122 var vs []string 123 for c := Value(0); c < Value(maxValues); c++ { 124 offset, mask := omask(c) 125 i := (iab.i[offset] & mask) != 0 126 a := (iab.a[offset] & mask) != 0 127 nb := (iab.nb[offset] & mask) != 0 128 var cs []string 129 if nb { 130 cs = append(cs, "!") 131 } 132 if a { 133 cs = append(cs, "^") 134 } else if nb && i { 135 cs = append(cs, "%") 136 } 137 if nb || a || i { 138 vs = append(vs, strings.Join(cs, "")+c.String()) 139 } 140 } 141 return strings.Join(vs, ",") 142} 143 144func (sc *syscaller) iabSetProc(iab *IAB) (err error) { 145 temp := GetProc() 146 var raising uint32 147 for i := 0; i < words; i++ { 148 newI := iab.i[i] 149 oldIP := temp.flat[i][Inheritable] | temp.flat[i][Permitted] 150 raising |= (newI & ^oldIP) | iab.a[i] | iab.nb[i] 151 temp.flat[i][Inheritable] = newI 152 } 153 working, err2 := temp.Dup() 154 if err2 != nil { 155 err = err2 156 return 157 } 158 if raising != 0 { 159 if err = working.SetFlag(Effective, true, SETPCAP); err != nil { 160 return 161 } 162 if err = sc.setProc(working); err != nil { 163 return 164 } 165 } 166 defer func() { 167 if err2 := sc.setProc(temp); err == nil { 168 err = err2 169 } 170 }() 171 if err = sc.resetAmbient(); err != nil { 172 return 173 } 174 for c := Value(maxValues); c > 0; { 175 c-- 176 offset, mask := omask(c) 177 if iab.a[offset]&mask != 0 { 178 err = sc.setAmbient(true, c) 179 } 180 if err == nil && iab.nb[offset]&mask != 0 { 181 err = sc.dropBound(c) 182 } 183 if err != nil { 184 return 185 } 186 } 187 return 188} 189 190// SetProc attempts to change the Inheritable, Ambient and Bounding 191// capabilty vectors of the current process using the content, 192// iab. The Bounding vector strongly affects the potential for setting 193// other bits, so this function carefully performs the the combined 194// operation in the most flexible manner. 195func (iab *IAB) SetProc() error { 196 scwMu.Lock() 197 defer scwMu.Unlock() 198 return multisc.iabSetProc(iab) 199} 200 201// GetVector returns the raised state of the specific capability bit 202// of the indicated vector. 203func (iab *IAB) GetVector(vec Vector, val Value) (bool, error) { 204 if val >= MaxBits() { 205 return false, ErrBadValue 206 } 207 offset, mask := omask(val) 208 switch vec { 209 case Inh: 210 return (iab.i[offset] & mask) != 0, nil 211 case Amb: 212 return (iab.a[offset] & mask) != 0, nil 213 case Bound: 214 return (iab.nb[offset] & mask) != 0, nil 215 default: 216 return false, ErrBadValue 217 } 218} 219 220// SetVector sets all of the vals in the specified vector to the 221// raised value. Note, the Ambient vector cannot contain values not raised 222// in the Inh vector, so setting values directly in one vector may have 223// the side effect of mirroring the value in the other vector to 224// maintain this constraint. Note, raising a Bound vector bit is 225// equivalent to lowering the Bounding vector of the process (when 226// successfully applied with (*IAB).SetProc()). 227func (iab *IAB) SetVector(vec Vector, raised bool, vals ...Value) error { 228 for _, val := range vals { 229 if val >= Value(maxValues) { 230 return ErrBadValue 231 } 232 offset, mask := omask(val) 233 switch vec { 234 case Inh: 235 if raised { 236 iab.i[offset] |= mask 237 } else { 238 iab.i[offset] &= ^mask 239 iab.a[offset] &= ^mask 240 } 241 case Amb: 242 if raised { 243 iab.a[offset] |= mask 244 iab.i[offset] |= mask 245 } else { 246 iab.a[offset] &= ^mask 247 } 248 case Bound: 249 if raised { 250 iab.nb[offset] |= mask 251 } else { 252 iab.nb[offset] &= ^mask 253 } 254 default: 255 return ErrBadValue 256 } 257 } 258 return nil 259} 260 261// Fill fills one of the Inh, Amb and Bound capability vectors from 262// one of the flag vectors of a Set. Note, filling the Inh vector 263// will mask the Amb vector, and filling the Amb vector may raise 264// entries in the Inh vector. Further, when filling the Bound vector, 265// the bits are inverted from what you might expect - that is lowered 266// bits from the Set will be raised in the Bound vector. 267func (iab *IAB) Fill(vec Vector, c *Set, flag Flag) error { 268 if len(c.flat) != 0 || flag > Inheritable { 269 return ErrBadSet 270 } 271 for i := 0; i < words; i++ { 272 flat := c.flat[i][flag] 273 switch vec { 274 case Inh: 275 iab.i[i] = flat 276 iab.a[i] &= ^flat 277 case Amb: 278 iab.a[i] = flat 279 iab.i[i] |= ^flat 280 case Bound: 281 iab.nb[i] = ^flat 282 default: 283 return ErrBadSet 284 } 285 } 286 return nil 287} 288