1*2810ac1bSKiyoung Kimpackage cap 2*2810ac1bSKiyoung Kim 3*2810ac1bSKiyoung Kimimport ( 4*2810ac1bSKiyoung Kim "bufio" 5*2810ac1bSKiyoung Kim "errors" 6*2810ac1bSKiyoung Kim "strconv" 7*2810ac1bSKiyoung Kim "strings" 8*2810ac1bSKiyoung Kim) 9*2810ac1bSKiyoung Kim 10*2810ac1bSKiyoung Kim// String converts a capability Value into its canonical text 11*2810ac1bSKiyoung Kim// representation. 12*2810ac1bSKiyoung Kimfunc (v Value) String() string { 13*2810ac1bSKiyoung Kim name, ok := names[v] 14*2810ac1bSKiyoung Kim if ok { 15*2810ac1bSKiyoung Kim return name 16*2810ac1bSKiyoung Kim } 17*2810ac1bSKiyoung Kim // Un-named capabilities are referred to numerically (in decimal). 18*2810ac1bSKiyoung Kim return strconv.Itoa(int(v)) 19*2810ac1bSKiyoung Kim} 20*2810ac1bSKiyoung Kim 21*2810ac1bSKiyoung Kim// FromName converts a named capability Value to its binary 22*2810ac1bSKiyoung Kim// representation. 23*2810ac1bSKiyoung Kimfunc FromName(name string) (Value, error) { 24*2810ac1bSKiyoung Kim startUp.Do(multisc.cInit) 25*2810ac1bSKiyoung Kim v, ok := bits[name] 26*2810ac1bSKiyoung Kim if ok { 27*2810ac1bSKiyoung Kim if v >= Value(words*32) { 28*2810ac1bSKiyoung Kim return 0, ErrBadValue 29*2810ac1bSKiyoung Kim } 30*2810ac1bSKiyoung Kim return v, nil 31*2810ac1bSKiyoung Kim } 32*2810ac1bSKiyoung Kim i, err := strconv.Atoi(name) 33*2810ac1bSKiyoung Kim if err != nil { 34*2810ac1bSKiyoung Kim return 0, err 35*2810ac1bSKiyoung Kim } 36*2810ac1bSKiyoung Kim if i >= 0 && i < int(words*32) { 37*2810ac1bSKiyoung Kim return Value(i), nil 38*2810ac1bSKiyoung Kim } 39*2810ac1bSKiyoung Kim return 0, ErrBadValue 40*2810ac1bSKiyoung Kim} 41*2810ac1bSKiyoung Kim 42*2810ac1bSKiyoung Kimconst ( 43*2810ac1bSKiyoung Kim eBin uint = (1 << Effective) 44*2810ac1bSKiyoung Kim pBin = (1 << Permitted) 45*2810ac1bSKiyoung Kim iBin = (1 << Inheritable) 46*2810ac1bSKiyoung Kim) 47*2810ac1bSKiyoung Kim 48*2810ac1bSKiyoung Kimvar combos = []string{"", "e", "p", "ep", "i", "ei", "ip", "eip"} 49*2810ac1bSKiyoung Kim 50*2810ac1bSKiyoung Kim// histo generates a histogram of flag state combinations. 51*2810ac1bSKiyoung Kim// Note: c is locked by or private to the caller. 52*2810ac1bSKiyoung Kimfunc (c *Set) histo(bins []int, patterns []uint, from, limit Value) uint { 53*2810ac1bSKiyoung Kim for v := from; v < limit; v++ { 54*2810ac1bSKiyoung Kim b := uint(v & 31) 55*2810ac1bSKiyoung Kim u, bit, err := bitOf(0, v) 56*2810ac1bSKiyoung Kim if err != nil { 57*2810ac1bSKiyoung Kim break 58*2810ac1bSKiyoung Kim } 59*2810ac1bSKiyoung Kim x := uint((c.flat[u][Effective]&bit)>>b) * eBin 60*2810ac1bSKiyoung Kim x |= uint((c.flat[u][Permitted]&bit)>>b) * pBin 61*2810ac1bSKiyoung Kim x |= uint((c.flat[u][Inheritable]&bit)>>b) * iBin 62*2810ac1bSKiyoung Kim bins[x]++ 63*2810ac1bSKiyoung Kim patterns[uint(v)] = x 64*2810ac1bSKiyoung Kim } 65*2810ac1bSKiyoung Kim // Note, in the loop, we use >= to pick the smallest value for 66*2810ac1bSKiyoung Kim // m with the highest bin value. That is ties break towards 67*2810ac1bSKiyoung Kim // m=0. 68*2810ac1bSKiyoung Kim m := uint(7) 69*2810ac1bSKiyoung Kim for t := m; t > 0; { 70*2810ac1bSKiyoung Kim t-- 71*2810ac1bSKiyoung Kim if bins[t] >= bins[m] { 72*2810ac1bSKiyoung Kim m = t 73*2810ac1bSKiyoung Kim } 74*2810ac1bSKiyoung Kim } 75*2810ac1bSKiyoung Kim return m 76*2810ac1bSKiyoung Kim} 77*2810ac1bSKiyoung Kim 78*2810ac1bSKiyoung Kim// String converts a full capability Set into a single short readable 79*2810ac1bSKiyoung Kim// string representation (which may contain spaces). See the 80*2810ac1bSKiyoung Kim// cap.FromText() function for an explanation of its return values. 81*2810ac1bSKiyoung Kim// 82*2810ac1bSKiyoung Kim// Note (*cap.Set).String() may evolve to generate more compact 83*2810ac1bSKiyoung Kim// strings representing the a given Set over time, but it should 84*2810ac1bSKiyoung Kim// maintain compatibility with the libcap:cap_to_text() function for 85*2810ac1bSKiyoung Kim// any given release. Further, it will always be an inverse of 86*2810ac1bSKiyoung Kim// cap.FromText(). 87*2810ac1bSKiyoung Kimfunc (c *Set) String() string { 88*2810ac1bSKiyoung Kim if err := c.good(); err != nil { 89*2810ac1bSKiyoung Kim return "<invalid>" 90*2810ac1bSKiyoung Kim } 91*2810ac1bSKiyoung Kim bins := make([]int, 8) 92*2810ac1bSKiyoung Kim patterns := make([]uint, maxValues) 93*2810ac1bSKiyoung Kim 94*2810ac1bSKiyoung Kim c.mu.RLock() 95*2810ac1bSKiyoung Kim defer c.mu.RUnlock() 96*2810ac1bSKiyoung Kim 97*2810ac1bSKiyoung Kim // Note, in order to have a *Set pointer, startUp.Do(cInit) 98*2810ac1bSKiyoung Kim // must have been called which sets maxValues. 99*2810ac1bSKiyoung Kim m := c.histo(bins, patterns, 0, Value(maxValues)) 100*2810ac1bSKiyoung Kim 101*2810ac1bSKiyoung Kim // Background state is the most popular of the named bits. 102*2810ac1bSKiyoung Kim vs := []string{"=" + combos[m]} 103*2810ac1bSKiyoung Kim for i := uint(8); i > 0; { 104*2810ac1bSKiyoung Kim i-- 105*2810ac1bSKiyoung Kim if i == m || bins[i] == 0 { 106*2810ac1bSKiyoung Kim continue 107*2810ac1bSKiyoung Kim } 108*2810ac1bSKiyoung Kim var list []string 109*2810ac1bSKiyoung Kim for j, p := range patterns { 110*2810ac1bSKiyoung Kim if p != i { 111*2810ac1bSKiyoung Kim continue 112*2810ac1bSKiyoung Kim } 113*2810ac1bSKiyoung Kim list = append(list, Value(j).String()) 114*2810ac1bSKiyoung Kim } 115*2810ac1bSKiyoung Kim x := strings.Join(list, ",") 116*2810ac1bSKiyoung Kim var y, z string 117*2810ac1bSKiyoung Kim if cf := i & ^m; cf != 0 { 118*2810ac1bSKiyoung Kim op := "+" 119*2810ac1bSKiyoung Kim if len(vs) == 1 && vs[0] == "=" { 120*2810ac1bSKiyoung Kim // Special case "= foo+..." == "foo=...". 121*2810ac1bSKiyoung Kim // Prefer because it 122*2810ac1bSKiyoung Kim vs = nil 123*2810ac1bSKiyoung Kim op = "=" 124*2810ac1bSKiyoung Kim } 125*2810ac1bSKiyoung Kim y = op + combos[cf] 126*2810ac1bSKiyoung Kim } 127*2810ac1bSKiyoung Kim if cf := m & ^i; cf != 0 { 128*2810ac1bSKiyoung Kim z = "-" + combos[cf] 129*2810ac1bSKiyoung Kim } 130*2810ac1bSKiyoung Kim vs = append(vs, x+y+z) 131*2810ac1bSKiyoung Kim } 132*2810ac1bSKiyoung Kim 133*2810ac1bSKiyoung Kim // The unnamed bits can only add to the above named ones since 134*2810ac1bSKiyoung Kim // unnamed ones are always defaulted to lowered. 135*2810ac1bSKiyoung Kim uBins := make([]int, 8) 136*2810ac1bSKiyoung Kim uPatterns := make([]uint, 32*words) 137*2810ac1bSKiyoung Kim c.histo(uBins, uPatterns, Value(maxValues), 32*Value(words)) 138*2810ac1bSKiyoung Kim for i := uint(7); i > 0; i-- { 139*2810ac1bSKiyoung Kim if uBins[i] == 0 { 140*2810ac1bSKiyoung Kim continue 141*2810ac1bSKiyoung Kim } 142*2810ac1bSKiyoung Kim var list []string 143*2810ac1bSKiyoung Kim for j, p := range uPatterns { 144*2810ac1bSKiyoung Kim if p != i { 145*2810ac1bSKiyoung Kim continue 146*2810ac1bSKiyoung Kim } 147*2810ac1bSKiyoung Kim list = append(list, Value(j).String()) 148*2810ac1bSKiyoung Kim } 149*2810ac1bSKiyoung Kim vs = append(vs, strings.Join(list, ",")+"+"+combos[i]) 150*2810ac1bSKiyoung Kim } 151*2810ac1bSKiyoung Kim 152*2810ac1bSKiyoung Kim return strings.Join(vs, " ") 153*2810ac1bSKiyoung Kim} 154*2810ac1bSKiyoung Kim 155*2810ac1bSKiyoung Kim// ErrBadText is returned if the text for a capability set cannot be parsed. 156*2810ac1bSKiyoung Kimvar ErrBadText = errors.New("bad text") 157*2810ac1bSKiyoung Kim 158*2810ac1bSKiyoung Kim// FromText converts the canonical text representation for a Set into 159*2810ac1bSKiyoung Kim// a freshly allocated Set. 160*2810ac1bSKiyoung Kim// 161*2810ac1bSKiyoung Kim// The format follows the following pattern: a set of space separated 162*2810ac1bSKiyoung Kim// sequences. Each sequence applies over the previous sequence to 163*2810ac1bSKiyoung Kim// build up a Set. The format of a sequence is: 164*2810ac1bSKiyoung Kim// 165*2810ac1bSKiyoung Kim// [comma list of cap_values][[ops][flags]]* 166*2810ac1bSKiyoung Kim// 167*2810ac1bSKiyoung Kim// Examples: 168*2810ac1bSKiyoung Kim// 169*2810ac1bSKiyoung Kim// "all=ep" 170*2810ac1bSKiyoung Kim// "cap_chown,cap_setuid=ip cap_setuid+e" 171*2810ac1bSKiyoung Kim// "=p cap_setpcap-p+i" 172*2810ac1bSKiyoung Kim// 173*2810ac1bSKiyoung Kim// Here "all" refers to all named capabilities known to the hosting 174*2810ac1bSKiyoung Kim// kernel, and "all" is assumed if no capabilities are listed before 175*2810ac1bSKiyoung Kim// an "=". 176*2810ac1bSKiyoung Kim// 177*2810ac1bSKiyoung Kim// The ops values, "=", "+" and "-" imply "reset and raise", "raise" 178*2810ac1bSKiyoung Kim// and "lower" respectively. The "e", "i" and "p" characters 179*2810ac1bSKiyoung Kim// correspond to the capabilities of the corresponding Flag: "e" 180*2810ac1bSKiyoung Kim// (Effective); "i" (Inheritable); "p" (Permitted). 181*2810ac1bSKiyoung Kim// 182*2810ac1bSKiyoung Kim// This syntax is overspecified and there are many ways of building 183*2810ac1bSKiyoung Kim// the same final Set state. Any sequence that includes a '=' resets 184*2810ac1bSKiyoung Kim// the accumulated state of all Flags ignoring earlier sequences. On 185*2810ac1bSKiyoung Kim// each of the following lines we give three or more examples of ways 186*2810ac1bSKiyoung Kim// to specify a common Set. The last entry on each line is the one 187*2810ac1bSKiyoung Kim// generated by (*cap.Set).String() from that Set. 188*2810ac1bSKiyoung Kim// 189*2810ac1bSKiyoung Kim// "=p all+ei" "all=pie" "=pi all+e" "=eip" 190*2810ac1bSKiyoung Kim// 191*2810ac1bSKiyoung Kim// "cap_setuid=p cap_chown=i" "cap_chown=ip-p" "cap_chown=i" 192*2810ac1bSKiyoung Kim// 193*2810ac1bSKiyoung Kim// "cap_chown=-p" "all=" "cap_setuid=pie-pie" "=" 194*2810ac1bSKiyoung Kim// 195*2810ac1bSKiyoung Kim// Note: FromText() is tested at release time to completely match the 196*2810ac1bSKiyoung Kim// import ability of the libcap:cap_from_text() function. 197*2810ac1bSKiyoung Kimfunc FromText(text string) (*Set, error) { 198*2810ac1bSKiyoung Kim c := NewSet() 199*2810ac1bSKiyoung Kim scanner := bufio.NewScanner(strings.NewReader(text)) 200*2810ac1bSKiyoung Kim scanner.Split(bufio.ScanWords) 201*2810ac1bSKiyoung Kim chunks := 0 202*2810ac1bSKiyoung Kim for scanner.Scan() { 203*2810ac1bSKiyoung Kim chunks++ 204*2810ac1bSKiyoung Kim 205*2810ac1bSKiyoung Kim // Parsing for xxx([-+=][eip]+)+ 206*2810ac1bSKiyoung Kim t := scanner.Text() 207*2810ac1bSKiyoung Kim i := strings.IndexAny(t, "=+-") 208*2810ac1bSKiyoung Kim if i < 0 { 209*2810ac1bSKiyoung Kim return nil, ErrBadText 210*2810ac1bSKiyoung Kim } 211*2810ac1bSKiyoung Kim var vs []Value 212*2810ac1bSKiyoung Kim sep := t[i] 213*2810ac1bSKiyoung Kim if vals := t[:i]; vals == "all" { 214*2810ac1bSKiyoung Kim for v := Value(0); v < Value(maxValues); v++ { 215*2810ac1bSKiyoung Kim vs = append(vs, v) 216*2810ac1bSKiyoung Kim } 217*2810ac1bSKiyoung Kim } else if vals != "" { 218*2810ac1bSKiyoung Kim for _, name := range strings.Split(vals, ",") { 219*2810ac1bSKiyoung Kim v, err := FromName(name) 220*2810ac1bSKiyoung Kim if err != nil { 221*2810ac1bSKiyoung Kim return nil, ErrBadText 222*2810ac1bSKiyoung Kim } 223*2810ac1bSKiyoung Kim vs = append(vs, v) 224*2810ac1bSKiyoung Kim } 225*2810ac1bSKiyoung Kim } else if sep != '=' { 226*2810ac1bSKiyoung Kim if vals == "" { 227*2810ac1bSKiyoung Kim // Only "=" supports ""=="all". 228*2810ac1bSKiyoung Kim return nil, ErrBadText 229*2810ac1bSKiyoung Kim } 230*2810ac1bSKiyoung Kim } else if j := i + 1; j+1 < len(t) { 231*2810ac1bSKiyoung Kim switch t[j] { 232*2810ac1bSKiyoung Kim case '+': 233*2810ac1bSKiyoung Kim sep = 'P' 234*2810ac1bSKiyoung Kim i++ 235*2810ac1bSKiyoung Kim case '-': 236*2810ac1bSKiyoung Kim sep = 'M' 237*2810ac1bSKiyoung Kim i++ 238*2810ac1bSKiyoung Kim } 239*2810ac1bSKiyoung Kim } 240*2810ac1bSKiyoung Kim i++ 241*2810ac1bSKiyoung Kim 242*2810ac1bSKiyoung Kim // There are 5 ways to set: =, =+, =-, +, -. We call 243*2810ac1bSKiyoung Kim // the 2nd and 3rd of these 'P' and 'M'. 244*2810ac1bSKiyoung Kim 245*2810ac1bSKiyoung Kim for { 246*2810ac1bSKiyoung Kim // read [eip]+ setting flags. 247*2810ac1bSKiyoung Kim var fE, fP, fI bool 248*2810ac1bSKiyoung Kim for ok := true; ok && i < len(t); i++ { 249*2810ac1bSKiyoung Kim switch t[i] { 250*2810ac1bSKiyoung Kim case 'e': 251*2810ac1bSKiyoung Kim fE = true 252*2810ac1bSKiyoung Kim case 'i': 253*2810ac1bSKiyoung Kim fI = true 254*2810ac1bSKiyoung Kim case 'p': 255*2810ac1bSKiyoung Kim fP = true 256*2810ac1bSKiyoung Kim default: 257*2810ac1bSKiyoung Kim ok = false 258*2810ac1bSKiyoung Kim } 259*2810ac1bSKiyoung Kim if !ok { 260*2810ac1bSKiyoung Kim break 261*2810ac1bSKiyoung Kim } 262*2810ac1bSKiyoung Kim } 263*2810ac1bSKiyoung Kim 264*2810ac1bSKiyoung Kim if !(fE || fI || fP) { 265*2810ac1bSKiyoung Kim if sep != '=' { 266*2810ac1bSKiyoung Kim return nil, ErrBadText 267*2810ac1bSKiyoung Kim } 268*2810ac1bSKiyoung Kim } 269*2810ac1bSKiyoung Kim 270*2810ac1bSKiyoung Kim switch sep { 271*2810ac1bSKiyoung Kim case '=', 'P', 'M', '+': 272*2810ac1bSKiyoung Kim if sep != '+' { 273*2810ac1bSKiyoung Kim c.Clear() 274*2810ac1bSKiyoung Kim if sep == 'M' { 275*2810ac1bSKiyoung Kim break 276*2810ac1bSKiyoung Kim } 277*2810ac1bSKiyoung Kim } 278*2810ac1bSKiyoung Kim if keep := len(vs) == 0; keep { 279*2810ac1bSKiyoung Kim if sep != '=' { 280*2810ac1bSKiyoung Kim return nil, ErrBadText 281*2810ac1bSKiyoung Kim } 282*2810ac1bSKiyoung Kim c.forceFlag(Effective, fE) 283*2810ac1bSKiyoung Kim c.forceFlag(Permitted, fP) 284*2810ac1bSKiyoung Kim c.forceFlag(Inheritable, fI) 285*2810ac1bSKiyoung Kim break 286*2810ac1bSKiyoung Kim } 287*2810ac1bSKiyoung Kim // =, + and P for specific values are left. 288*2810ac1bSKiyoung Kim if fE { 289*2810ac1bSKiyoung Kim c.SetFlag(Effective, true, vs...) 290*2810ac1bSKiyoung Kim } 291*2810ac1bSKiyoung Kim if fP { 292*2810ac1bSKiyoung Kim c.SetFlag(Permitted, true, vs...) 293*2810ac1bSKiyoung Kim } 294*2810ac1bSKiyoung Kim if fI { 295*2810ac1bSKiyoung Kim c.SetFlag(Inheritable, true, vs...) 296*2810ac1bSKiyoung Kim } 297*2810ac1bSKiyoung Kim case '-': 298*2810ac1bSKiyoung Kim if fE { 299*2810ac1bSKiyoung Kim c.SetFlag(Effective, false, vs...) 300*2810ac1bSKiyoung Kim } 301*2810ac1bSKiyoung Kim if fP { 302*2810ac1bSKiyoung Kim c.SetFlag(Permitted, false, vs...) 303*2810ac1bSKiyoung Kim } 304*2810ac1bSKiyoung Kim if fI { 305*2810ac1bSKiyoung Kim c.SetFlag(Inheritable, false, vs...) 306*2810ac1bSKiyoung Kim } 307*2810ac1bSKiyoung Kim } 308*2810ac1bSKiyoung Kim 309*2810ac1bSKiyoung Kim if i == len(t) { 310*2810ac1bSKiyoung Kim break 311*2810ac1bSKiyoung Kim } 312*2810ac1bSKiyoung Kim 313*2810ac1bSKiyoung Kim switch t[i] { 314*2810ac1bSKiyoung Kim case '+', '-': 315*2810ac1bSKiyoung Kim sep = t[i] 316*2810ac1bSKiyoung Kim i++ 317*2810ac1bSKiyoung Kim default: 318*2810ac1bSKiyoung Kim return nil, ErrBadText 319*2810ac1bSKiyoung Kim } 320*2810ac1bSKiyoung Kim } 321*2810ac1bSKiyoung Kim } 322*2810ac1bSKiyoung Kim if chunks == 0 { 323*2810ac1bSKiyoung Kim return nil, ErrBadText 324*2810ac1bSKiyoung Kim } 325*2810ac1bSKiyoung Kim return c, nil 326*2810ac1bSKiyoung Kim} 327