xref: /aosp_15_r20/external/libcap/cap/iab.go (revision 2810ac1b38eead2603277920c78344c84ddf3aff)
1*2810ac1bSKiyoung Kimpackage cap
2*2810ac1bSKiyoung Kim
3*2810ac1bSKiyoung Kimimport (
4*2810ac1bSKiyoung Kim	"fmt"
5*2810ac1bSKiyoung Kim	"io/ioutil"
6*2810ac1bSKiyoung Kim	"strconv"
7*2810ac1bSKiyoung Kim	"strings"
8*2810ac1bSKiyoung Kim	"sync"
9*2810ac1bSKiyoung Kim)
10*2810ac1bSKiyoung Kim
11*2810ac1bSKiyoung Kim// omask returns the offset and mask for a specific capability.
12*2810ac1bSKiyoung Kimfunc omask(c Value) (uint, uint32) {
13*2810ac1bSKiyoung Kim	u := uint(c)
14*2810ac1bSKiyoung Kim	return u >> 5, uint32(1) << (u & 31)
15*2810ac1bSKiyoung Kim}
16*2810ac1bSKiyoung Kim
17*2810ac1bSKiyoung Kim// IAB holds a summary of all of the inheritable capability vectors:
18*2810ac1bSKiyoung Kim// Inh, Amb and Bound. The Bound vector is the logical inverse (two's
19*2810ac1bSKiyoung Kim// complement) of the process' Bounding set. That is, raising a Value
20*2810ac1bSKiyoung Kim// in the Bound (think blocked) vector is equivalent to dropping that
21*2810ac1bSKiyoung Kim// Value from the process' Bounding set. This convention is used to
22*2810ac1bSKiyoung Kim// support the empty IAB as being mostly harmless.
23*2810ac1bSKiyoung Kimtype IAB struct {
24*2810ac1bSKiyoung Kim	mu       sync.RWMutex
25*2810ac1bSKiyoung Kim	a, i, nb []uint32
26*2810ac1bSKiyoung Kim}
27*2810ac1bSKiyoung Kim
28*2810ac1bSKiyoung Kim// Vector enumerates which of the inheritable IAB capability vectors
29*2810ac1bSKiyoung Kim// is being manipulated.
30*2810ac1bSKiyoung Kimtype Vector uint
31*2810ac1bSKiyoung Kim
32*2810ac1bSKiyoung Kim// Inh, Amb, Bound enumerate the IAB vector components. (Vector) Inh
33*2810ac1bSKiyoung Kim// is equivalent to (Flag) Inheritable. They are named differently for
34*2810ac1bSKiyoung Kim// syntax/type checking reasons.
35*2810ac1bSKiyoung Kimconst (
36*2810ac1bSKiyoung Kim	Inh Vector = iota
37*2810ac1bSKiyoung Kim	Amb
38*2810ac1bSKiyoung Kim	Bound
39*2810ac1bSKiyoung Kim)
40*2810ac1bSKiyoung Kim
41*2810ac1bSKiyoung Kim// IABDiff holds the non-error result of an (*IAB).Cf()
42*2810ac1bSKiyoung Kim// function call. It can be interpreted with the function
43*2810ac1bSKiyoung Kim// (IABDiff).Has().
44*2810ac1bSKiyoung Kimtype IABDiff uint
45*2810ac1bSKiyoung Kim
46*2810ac1bSKiyoung Kim// iBits, iBits and bBits track the (semi-)independent parts of an
47*2810ac1bSKiyoung Kim// IABDiff.
48*2810ac1bSKiyoung Kimconst (
49*2810ac1bSKiyoung Kim	iBits IABDiff = 1 << Inh
50*2810ac1bSKiyoung Kim	aBits IABDiff = 1 << Amb
51*2810ac1bSKiyoung Kim	bBits IABDiff = 1 << Bound
52*2810ac1bSKiyoung Kim)
53*2810ac1bSKiyoung Kim
54*2810ac1bSKiyoung Kim// Has determines if an IAB comparison differs in a specific vector.
55*2810ac1bSKiyoung Kimfunc (d IABDiff) Has(v Vector) bool {
56*2810ac1bSKiyoung Kim	return d&(1<<v) != 0
57*2810ac1bSKiyoung Kim}
58*2810ac1bSKiyoung Kim
59*2810ac1bSKiyoung Kim// String identifies a Vector value by its conventional I A or B
60*2810ac1bSKiyoung Kim// string abbreviation.
61*2810ac1bSKiyoung Kimfunc (v Vector) String() string {
62*2810ac1bSKiyoung Kim	switch v {
63*2810ac1bSKiyoung Kim	case Inh:
64*2810ac1bSKiyoung Kim		return "I"
65*2810ac1bSKiyoung Kim	case Amb:
66*2810ac1bSKiyoung Kim		return "A"
67*2810ac1bSKiyoung Kim	case Bound:
68*2810ac1bSKiyoung Kim		return "B"
69*2810ac1bSKiyoung Kim	default:
70*2810ac1bSKiyoung Kim		return "<Error>"
71*2810ac1bSKiyoung Kim	}
72*2810ac1bSKiyoung Kim}
73*2810ac1bSKiyoung Kim
74*2810ac1bSKiyoung Kim// NewIAB returns an empty IAB.
75*2810ac1bSKiyoung Kimfunc NewIAB() *IAB {
76*2810ac1bSKiyoung Kim	startUp.Do(multisc.cInit)
77*2810ac1bSKiyoung Kim	return &IAB{
78*2810ac1bSKiyoung Kim		i:  make([]uint32, words),
79*2810ac1bSKiyoung Kim		a:  make([]uint32, words),
80*2810ac1bSKiyoung Kim		nb: make([]uint32, words),
81*2810ac1bSKiyoung Kim	}
82*2810ac1bSKiyoung Kim}
83*2810ac1bSKiyoung Kim
84*2810ac1bSKiyoung Kim// good confirms the iab looks to be initialized.
85*2810ac1bSKiyoung Kimfunc (iab *IAB) good() error {
86*2810ac1bSKiyoung Kim	if iab == nil || len(iab.i) == 0 || len(iab.i) != words || len(iab.a) != words || len(iab.nb) != words {
87*2810ac1bSKiyoung Kim		return ErrBadValue
88*2810ac1bSKiyoung Kim	}
89*2810ac1bSKiyoung Kim	return nil
90*2810ac1bSKiyoung Kim}
91*2810ac1bSKiyoung Kim
92*2810ac1bSKiyoung Kim// Dup returns a duplicate copy of the IAB.
93*2810ac1bSKiyoung Kimfunc (iab *IAB) Dup() (*IAB, error) {
94*2810ac1bSKiyoung Kim	if err := iab.good(); err != nil {
95*2810ac1bSKiyoung Kim		return nil, err
96*2810ac1bSKiyoung Kim	}
97*2810ac1bSKiyoung Kim	v := NewIAB()
98*2810ac1bSKiyoung Kim	iab.mu.RLock()
99*2810ac1bSKiyoung Kim	defer iab.mu.RUnlock()
100*2810ac1bSKiyoung Kim	copy(v.i, iab.i)
101*2810ac1bSKiyoung Kim	copy(v.a, iab.a)
102*2810ac1bSKiyoung Kim	copy(v.nb, iab.nb)
103*2810ac1bSKiyoung Kim	return v, nil
104*2810ac1bSKiyoung Kim}
105*2810ac1bSKiyoung Kim
106*2810ac1bSKiyoung Kim// IABInit allocates a new IAB tuple.
107*2810ac1bSKiyoung Kim//
108*2810ac1bSKiyoung Kim// Deprecated: Replace with NewIAB.
109*2810ac1bSKiyoung Kim//
110*2810ac1bSKiyoung Kim// Example, replace this:
111*2810ac1bSKiyoung Kim//
112*2810ac1bSKiyoung Kim//    iab := IABInit()
113*2810ac1bSKiyoung Kim//
114*2810ac1bSKiyoung Kim// with this:
115*2810ac1bSKiyoung Kim//
116*2810ac1bSKiyoung Kim//    iab := NewIAB()
117*2810ac1bSKiyoung Kimfunc IABInit() *IAB {
118*2810ac1bSKiyoung Kim	return NewIAB()
119*2810ac1bSKiyoung Kim}
120*2810ac1bSKiyoung Kim
121*2810ac1bSKiyoung Kim// IABGetProc summarizes the Inh, Amb and Bound capability vectors of
122*2810ac1bSKiyoung Kim// the current process.
123*2810ac1bSKiyoung Kimfunc IABGetProc() *IAB {
124*2810ac1bSKiyoung Kim	iab := NewIAB()
125*2810ac1bSKiyoung Kim	current := GetProc()
126*2810ac1bSKiyoung Kim	iab.Fill(Inh, current, Inheritable)
127*2810ac1bSKiyoung Kim	for c := MaxBits(); c > 0; {
128*2810ac1bSKiyoung Kim		c--
129*2810ac1bSKiyoung Kim		offset, mask := omask(c)
130*2810ac1bSKiyoung Kim		if a, _ := GetAmbient(c); a {
131*2810ac1bSKiyoung Kim			iab.a[offset] |= mask
132*2810ac1bSKiyoung Kim		}
133*2810ac1bSKiyoung Kim		if b, err := GetBound(c); err == nil && !b {
134*2810ac1bSKiyoung Kim			iab.nb[offset] |= mask
135*2810ac1bSKiyoung Kim		}
136*2810ac1bSKiyoung Kim	}
137*2810ac1bSKiyoung Kim	return iab
138*2810ac1bSKiyoung Kim}
139*2810ac1bSKiyoung Kim
140*2810ac1bSKiyoung Kim// IABFromText parses a string representing an IAB, as generated
141*2810ac1bSKiyoung Kim// by IAB.String(), to generate an IAB.
142*2810ac1bSKiyoung Kimfunc IABFromText(text string) (*IAB, error) {
143*2810ac1bSKiyoung Kim	iab := NewIAB()
144*2810ac1bSKiyoung Kim	if len(text) == 0 {
145*2810ac1bSKiyoung Kim		return iab, nil
146*2810ac1bSKiyoung Kim	}
147*2810ac1bSKiyoung Kim	for _, f := range strings.Split(text, ",") {
148*2810ac1bSKiyoung Kim		var i, a, nb bool
149*2810ac1bSKiyoung Kim		var j int
150*2810ac1bSKiyoung Kim		for j = 0; j < len(f); j++ {
151*2810ac1bSKiyoung Kim			switch f[j : j+1] {
152*2810ac1bSKiyoung Kim			case "!":
153*2810ac1bSKiyoung Kim				nb = true
154*2810ac1bSKiyoung Kim			case "^":
155*2810ac1bSKiyoung Kim				i = true
156*2810ac1bSKiyoung Kim				a = true
157*2810ac1bSKiyoung Kim			case "%":
158*2810ac1bSKiyoung Kim				i = true
159*2810ac1bSKiyoung Kim			default:
160*2810ac1bSKiyoung Kim				goto done
161*2810ac1bSKiyoung Kim			}
162*2810ac1bSKiyoung Kim		}
163*2810ac1bSKiyoung Kim	done:
164*2810ac1bSKiyoung Kim		c, err := FromName(f[j:])
165*2810ac1bSKiyoung Kim		if err != nil {
166*2810ac1bSKiyoung Kim			return nil, err
167*2810ac1bSKiyoung Kim		}
168*2810ac1bSKiyoung Kim		offset, mask := omask(c)
169*2810ac1bSKiyoung Kim		if i || !nb {
170*2810ac1bSKiyoung Kim			iab.i[offset] |= mask
171*2810ac1bSKiyoung Kim		}
172*2810ac1bSKiyoung Kim		if a {
173*2810ac1bSKiyoung Kim			iab.a[offset] |= mask
174*2810ac1bSKiyoung Kim		}
175*2810ac1bSKiyoung Kim		if nb {
176*2810ac1bSKiyoung Kim			iab.nb[offset] |= mask
177*2810ac1bSKiyoung Kim		}
178*2810ac1bSKiyoung Kim	}
179*2810ac1bSKiyoung Kim	return iab, nil
180*2810ac1bSKiyoung Kim}
181*2810ac1bSKiyoung Kim
182*2810ac1bSKiyoung Kim// String serializes an IAB to a string format.
183*2810ac1bSKiyoung Kimfunc (iab *IAB) String() string {
184*2810ac1bSKiyoung Kim	if err := iab.good(); err != nil {
185*2810ac1bSKiyoung Kim		return "<invalid>"
186*2810ac1bSKiyoung Kim	}
187*2810ac1bSKiyoung Kim	var vs []string
188*2810ac1bSKiyoung Kim	iab.mu.RLock()
189*2810ac1bSKiyoung Kim	defer iab.mu.RUnlock()
190*2810ac1bSKiyoung Kim	for c := Value(0); c < Value(maxValues); c++ {
191*2810ac1bSKiyoung Kim		offset, mask := omask(c)
192*2810ac1bSKiyoung Kim		i := (iab.i[offset] & mask) != 0
193*2810ac1bSKiyoung Kim		a := (iab.a[offset] & mask) != 0
194*2810ac1bSKiyoung Kim		nb := (iab.nb[offset] & mask) != 0
195*2810ac1bSKiyoung Kim		var cs []string
196*2810ac1bSKiyoung Kim		if nb {
197*2810ac1bSKiyoung Kim			cs = append(cs, "!")
198*2810ac1bSKiyoung Kim		}
199*2810ac1bSKiyoung Kim		if a {
200*2810ac1bSKiyoung Kim			cs = append(cs, "^")
201*2810ac1bSKiyoung Kim		} else if nb && i {
202*2810ac1bSKiyoung Kim			cs = append(cs, "%")
203*2810ac1bSKiyoung Kim		}
204*2810ac1bSKiyoung Kim		if nb || a || i {
205*2810ac1bSKiyoung Kim			vs = append(vs, strings.Join(cs, "")+c.String())
206*2810ac1bSKiyoung Kim		}
207*2810ac1bSKiyoung Kim	}
208*2810ac1bSKiyoung Kim	return strings.Join(vs, ",")
209*2810ac1bSKiyoung Kim}
210*2810ac1bSKiyoung Kim
211*2810ac1bSKiyoung Kim// iabSetProc uses a syscaller to apply an IAB tuple to the process.
212*2810ac1bSKiyoung Kim// The iab is known to be locked by the caller.
213*2810ac1bSKiyoung Kimfunc (sc *syscaller) iabSetProc(iab *IAB) (err error) {
214*2810ac1bSKiyoung Kim	temp := GetProc()
215*2810ac1bSKiyoung Kim	var raising uint32
216*2810ac1bSKiyoung Kim	for i := 0; i < words; i++ {
217*2810ac1bSKiyoung Kim		newI := iab.i[i]
218*2810ac1bSKiyoung Kim		oldIP := temp.flat[i][Inheritable] | temp.flat[i][Permitted]
219*2810ac1bSKiyoung Kim		raising |= (newI & ^oldIP) | iab.a[i] | iab.nb[i]
220*2810ac1bSKiyoung Kim		temp.flat[i][Inheritable] = newI
221*2810ac1bSKiyoung Kim	}
222*2810ac1bSKiyoung Kim	working, err2 := temp.Dup()
223*2810ac1bSKiyoung Kim	if err2 != nil {
224*2810ac1bSKiyoung Kim		err = err2
225*2810ac1bSKiyoung Kim		return
226*2810ac1bSKiyoung Kim	}
227*2810ac1bSKiyoung Kim	if raising != 0 {
228*2810ac1bSKiyoung Kim		if err = working.SetFlag(Effective, true, SETPCAP); err != nil {
229*2810ac1bSKiyoung Kim			return
230*2810ac1bSKiyoung Kim		}
231*2810ac1bSKiyoung Kim		if err = sc.setProc(working); err != nil {
232*2810ac1bSKiyoung Kim			return
233*2810ac1bSKiyoung Kim		}
234*2810ac1bSKiyoung Kim	}
235*2810ac1bSKiyoung Kim	defer func() {
236*2810ac1bSKiyoung Kim		if err2 := sc.setProc(temp); err == nil {
237*2810ac1bSKiyoung Kim			err = err2
238*2810ac1bSKiyoung Kim		}
239*2810ac1bSKiyoung Kim	}()
240*2810ac1bSKiyoung Kim	if err = sc.resetAmbient(); err != nil {
241*2810ac1bSKiyoung Kim		return
242*2810ac1bSKiyoung Kim	}
243*2810ac1bSKiyoung Kim	for c := Value(maxValues); c > 0; {
244*2810ac1bSKiyoung Kim		c--
245*2810ac1bSKiyoung Kim		offset, mask := omask(c)
246*2810ac1bSKiyoung Kim		if iab.a[offset]&mask != 0 {
247*2810ac1bSKiyoung Kim			err = sc.setAmbient(true, c)
248*2810ac1bSKiyoung Kim		}
249*2810ac1bSKiyoung Kim		if err == nil && iab.nb[offset]&mask != 0 {
250*2810ac1bSKiyoung Kim			err = sc.dropBound(c)
251*2810ac1bSKiyoung Kim		}
252*2810ac1bSKiyoung Kim		if err != nil {
253*2810ac1bSKiyoung Kim			return
254*2810ac1bSKiyoung Kim		}
255*2810ac1bSKiyoung Kim	}
256*2810ac1bSKiyoung Kim	return
257*2810ac1bSKiyoung Kim}
258*2810ac1bSKiyoung Kim
259*2810ac1bSKiyoung Kim// SetProc attempts to change the Inheritable, Ambient and Bounding
260*2810ac1bSKiyoung Kim// capability vectors of the current process using the content,
261*2810ac1bSKiyoung Kim// iab. The Bounding vector strongly affects the potential for setting
262*2810ac1bSKiyoung Kim// other bits, so this function carefully performs the combined
263*2810ac1bSKiyoung Kim// operation in the most flexible manner.
264*2810ac1bSKiyoung Kimfunc (iab *IAB) SetProc() error {
265*2810ac1bSKiyoung Kim	if err := iab.good(); err != nil {
266*2810ac1bSKiyoung Kim		return err
267*2810ac1bSKiyoung Kim	}
268*2810ac1bSKiyoung Kim	state, sc := scwStateSC()
269*2810ac1bSKiyoung Kim	defer scwSetState(launchBlocked, state, -1)
270*2810ac1bSKiyoung Kim	iab.mu.RLock()
271*2810ac1bSKiyoung Kim	defer iab.mu.RUnlock()
272*2810ac1bSKiyoung Kim	return sc.iabSetProc(iab)
273*2810ac1bSKiyoung Kim}
274*2810ac1bSKiyoung Kim
275*2810ac1bSKiyoung Kim// GetVector returns the raised state of the specific capability bit
276*2810ac1bSKiyoung Kim// of the indicated vector.
277*2810ac1bSKiyoung Kimfunc (iab *IAB) GetVector(vec Vector, val Value) (bool, error) {
278*2810ac1bSKiyoung Kim	if err := iab.good(); err != nil {
279*2810ac1bSKiyoung Kim		return false, err
280*2810ac1bSKiyoung Kim	}
281*2810ac1bSKiyoung Kim	if val >= MaxBits() {
282*2810ac1bSKiyoung Kim		return false, ErrBadValue
283*2810ac1bSKiyoung Kim	}
284*2810ac1bSKiyoung Kim	iab.mu.RLock()
285*2810ac1bSKiyoung Kim	defer iab.mu.RUnlock()
286*2810ac1bSKiyoung Kim	offset, mask := omask(val)
287*2810ac1bSKiyoung Kim	switch vec {
288*2810ac1bSKiyoung Kim	case Inh:
289*2810ac1bSKiyoung Kim		return (iab.i[offset] & mask) != 0, nil
290*2810ac1bSKiyoung Kim	case Amb:
291*2810ac1bSKiyoung Kim		return (iab.a[offset] & mask) != 0, nil
292*2810ac1bSKiyoung Kim	case Bound:
293*2810ac1bSKiyoung Kim		return (iab.nb[offset] & mask) != 0, nil
294*2810ac1bSKiyoung Kim	default:
295*2810ac1bSKiyoung Kim		return false, ErrBadValue
296*2810ac1bSKiyoung Kim	}
297*2810ac1bSKiyoung Kim}
298*2810ac1bSKiyoung Kim
299*2810ac1bSKiyoung Kim// SetVector sets all of the vals in the specified vector to the
300*2810ac1bSKiyoung Kim// raised value.  Note, the Ambient vector cannot contain values not raised
301*2810ac1bSKiyoung Kim// in the Inh vector, so setting values directly in one vector may have
302*2810ac1bSKiyoung Kim// the side effect of mirroring the value in the other vector to
303*2810ac1bSKiyoung Kim// maintain this constraint. Note, raising a Bound vector bit is
304*2810ac1bSKiyoung Kim// equivalent to lowering the Bounding vector of the process (when
305*2810ac1bSKiyoung Kim// successfully applied with (*IAB).SetProc()).
306*2810ac1bSKiyoung Kimfunc (iab *IAB) SetVector(vec Vector, raised bool, vals ...Value) error {
307*2810ac1bSKiyoung Kim	if err := iab.good(); err != nil {
308*2810ac1bSKiyoung Kim		return err
309*2810ac1bSKiyoung Kim	}
310*2810ac1bSKiyoung Kim	iab.mu.Lock()
311*2810ac1bSKiyoung Kim	defer iab.mu.Unlock()
312*2810ac1bSKiyoung Kim	for _, val := range vals {
313*2810ac1bSKiyoung Kim		if val >= Value(maxValues) {
314*2810ac1bSKiyoung Kim			return ErrBadValue
315*2810ac1bSKiyoung Kim		}
316*2810ac1bSKiyoung Kim		offset, mask := omask(val)
317*2810ac1bSKiyoung Kim		switch vec {
318*2810ac1bSKiyoung Kim		case Inh:
319*2810ac1bSKiyoung Kim			if raised {
320*2810ac1bSKiyoung Kim				iab.i[offset] |= mask
321*2810ac1bSKiyoung Kim			} else {
322*2810ac1bSKiyoung Kim				iab.i[offset] &= ^mask
323*2810ac1bSKiyoung Kim				iab.a[offset] &= ^mask
324*2810ac1bSKiyoung Kim			}
325*2810ac1bSKiyoung Kim		case Amb:
326*2810ac1bSKiyoung Kim			if raised {
327*2810ac1bSKiyoung Kim				iab.a[offset] |= mask
328*2810ac1bSKiyoung Kim				iab.i[offset] |= mask
329*2810ac1bSKiyoung Kim			} else {
330*2810ac1bSKiyoung Kim				iab.a[offset] &= ^mask
331*2810ac1bSKiyoung Kim			}
332*2810ac1bSKiyoung Kim		case Bound:
333*2810ac1bSKiyoung Kim			if raised {
334*2810ac1bSKiyoung Kim				iab.nb[offset] |= mask
335*2810ac1bSKiyoung Kim			} else {
336*2810ac1bSKiyoung Kim				iab.nb[offset] &= ^mask
337*2810ac1bSKiyoung Kim			}
338*2810ac1bSKiyoung Kim		default:
339*2810ac1bSKiyoung Kim			return ErrBadValue
340*2810ac1bSKiyoung Kim		}
341*2810ac1bSKiyoung Kim	}
342*2810ac1bSKiyoung Kim	return nil
343*2810ac1bSKiyoung Kim}
344*2810ac1bSKiyoung Kim
345*2810ac1bSKiyoung Kim// Fill fills one of the Inh, Amb and Bound capability vectors from
346*2810ac1bSKiyoung Kim// one of the flag vectors of a Set.  Note, filling the Inh vector
347*2810ac1bSKiyoung Kim// will mask the Amb vector, and filling the Amb vector may raise
348*2810ac1bSKiyoung Kim// entries in the Inh vector. Further, when filling the Bound vector,
349*2810ac1bSKiyoung Kim// the bits are inverted from what you might expect - that is lowered
350*2810ac1bSKiyoung Kim// bits from the Set will be raised in the Bound vector.
351*2810ac1bSKiyoung Kimfunc (iab *IAB) Fill(vec Vector, c *Set, flag Flag) error {
352*2810ac1bSKiyoung Kim	if err := iab.good(); err != nil {
353*2810ac1bSKiyoung Kim		return err
354*2810ac1bSKiyoung Kim	}
355*2810ac1bSKiyoung Kim	// work with a copy to avoid potential deadlock.
356*2810ac1bSKiyoung Kim	s, err := c.Dup()
357*2810ac1bSKiyoung Kim	if err != nil {
358*2810ac1bSKiyoung Kim		return err
359*2810ac1bSKiyoung Kim	}
360*2810ac1bSKiyoung Kim	iab.mu.Lock()
361*2810ac1bSKiyoung Kim	defer iab.mu.Unlock()
362*2810ac1bSKiyoung Kim	for i := 0; i < words; i++ {
363*2810ac1bSKiyoung Kim		flat := s.flat[i][flag]
364*2810ac1bSKiyoung Kim		switch vec {
365*2810ac1bSKiyoung Kim		case Inh:
366*2810ac1bSKiyoung Kim			iab.i[i] = flat
367*2810ac1bSKiyoung Kim			iab.a[i] &= flat
368*2810ac1bSKiyoung Kim		case Amb:
369*2810ac1bSKiyoung Kim			iab.a[i] = flat
370*2810ac1bSKiyoung Kim			iab.i[i] |= flat
371*2810ac1bSKiyoung Kim		case Bound:
372*2810ac1bSKiyoung Kim			iab.nb[i] = ^flat
373*2810ac1bSKiyoung Kim		default:
374*2810ac1bSKiyoung Kim			return ErrBadSet
375*2810ac1bSKiyoung Kim		}
376*2810ac1bSKiyoung Kim	}
377*2810ac1bSKiyoung Kim	return nil
378*2810ac1bSKiyoung Kim}
379*2810ac1bSKiyoung Kim
380*2810ac1bSKiyoung Kim// Cf compares two IAB values. Its return value is 0 if the compared
381*2810ac1bSKiyoung Kim// tuples are considered identical. The macroscopic differences can be
382*2810ac1bSKiyoung Kim// investigated with (IABDiff).Has().
383*2810ac1bSKiyoung Kimfunc (iab *IAB) Cf(alt *IAB) (IABDiff, error) {
384*2810ac1bSKiyoung Kim	if err := iab.good(); err != nil {
385*2810ac1bSKiyoung Kim		return 0, err
386*2810ac1bSKiyoung Kim	}
387*2810ac1bSKiyoung Kim	if iab == alt {
388*2810ac1bSKiyoung Kim		return 0, nil
389*2810ac1bSKiyoung Kim	}
390*2810ac1bSKiyoung Kim	// Avoid holding two locks at once.
391*2810ac1bSKiyoung Kim	ref, err := alt.Dup()
392*2810ac1bSKiyoung Kim	if err != nil {
393*2810ac1bSKiyoung Kim		return 0, err
394*2810ac1bSKiyoung Kim	}
395*2810ac1bSKiyoung Kim	iab.mu.RLock()
396*2810ac1bSKiyoung Kim	defer iab.mu.RUnlock()
397*2810ac1bSKiyoung Kim
398*2810ac1bSKiyoung Kim	var cf IABDiff
399*2810ac1bSKiyoung Kim	for i := 0; i < words; i++ {
400*2810ac1bSKiyoung Kim		if iab.i[i] != ref.i[i] {
401*2810ac1bSKiyoung Kim			cf |= iBits
402*2810ac1bSKiyoung Kim		}
403*2810ac1bSKiyoung Kim		if iab.a[i] != ref.a[i] {
404*2810ac1bSKiyoung Kim			cf |= aBits
405*2810ac1bSKiyoung Kim		}
406*2810ac1bSKiyoung Kim		if iab.nb[i] != ref.nb[i] {
407*2810ac1bSKiyoung Kim			cf |= bBits
408*2810ac1bSKiyoung Kim		}
409*2810ac1bSKiyoung Kim	}
410*2810ac1bSKiyoung Kim	return cf, nil
411*2810ac1bSKiyoung Kim}
412*2810ac1bSKiyoung Kim
413*2810ac1bSKiyoung Kim// parseHex converts the /proc/*/status string into an array of
414*2810ac1bSKiyoung Kim// uint32s suitable for storage in an IAB structure.
415*2810ac1bSKiyoung Kimfunc parseHex(hex string, invert bool) []uint32 {
416*2810ac1bSKiyoung Kim	if len(hex) != 8*words {
417*2810ac1bSKiyoung Kim		// Invalid string
418*2810ac1bSKiyoung Kim		return nil
419*2810ac1bSKiyoung Kim	}
420*2810ac1bSKiyoung Kim	var result []uint32
421*2810ac1bSKiyoung Kim	for i := 0; i < words; i++ {
422*2810ac1bSKiyoung Kim		upper := 8 * (words - i)
423*2810ac1bSKiyoung Kim		raw, err := strconv.ParseUint(hex[upper-8:upper], 16, 32)
424*2810ac1bSKiyoung Kim		if err != nil {
425*2810ac1bSKiyoung Kim			return nil
426*2810ac1bSKiyoung Kim		}
427*2810ac1bSKiyoung Kim		if invert {
428*2810ac1bSKiyoung Kim			raw = ^raw
429*2810ac1bSKiyoung Kim		}
430*2810ac1bSKiyoung Kim		bits := allMask(uint(i)) & uint32(raw)
431*2810ac1bSKiyoung Kim		result = append(result, bits)
432*2810ac1bSKiyoung Kim	}
433*2810ac1bSKiyoung Kim	return result
434*2810ac1bSKiyoung Kim}
435*2810ac1bSKiyoung Kim
436*2810ac1bSKiyoung Kimvar procRoot = "/proc"
437*2810ac1bSKiyoung Kim
438*2810ac1bSKiyoung Kim// ProcRoot sets the local mount point for the Linux /proc filesystem.
439*2810ac1bSKiyoung Kim// It defaults to "/proc", but might be mounted elsewhere on any given
440*2810ac1bSKiyoung Kim// system. The function returns the previous value of the local mount
441*2810ac1bSKiyoung Kim// point. If the user attempts to set it to "", the value is left
442*2810ac1bSKiyoung Kim// unchanged.
443*2810ac1bSKiyoung Kimfunc ProcRoot(path string) string {
444*2810ac1bSKiyoung Kim	was := procRoot
445*2810ac1bSKiyoung Kim	if path != "" {
446*2810ac1bSKiyoung Kim		procRoot = path
447*2810ac1bSKiyoung Kim	}
448*2810ac1bSKiyoung Kim	return was
449*2810ac1bSKiyoung Kim}
450*2810ac1bSKiyoung Kim
451*2810ac1bSKiyoung Kim// IABGetPID returns the IAB tuple of a specified process. The kernel
452*2810ac1bSKiyoung Kim// ABI does not support this query via system calls, so the function
453*2810ac1bSKiyoung Kim// works by parsing the /proc/<pid>/status file content.
454*2810ac1bSKiyoung Kimfunc IABGetPID(pid int) (*IAB, error) {
455*2810ac1bSKiyoung Kim	tf := fmt.Sprintf("%s/%d/status", procRoot, pid)
456*2810ac1bSKiyoung Kim	d, err := ioutil.ReadFile(tf)
457*2810ac1bSKiyoung Kim	if err != nil {
458*2810ac1bSKiyoung Kim		return nil, err
459*2810ac1bSKiyoung Kim	}
460*2810ac1bSKiyoung Kim	iab := &IAB{}
461*2810ac1bSKiyoung Kim	for _, line := range strings.Split(string(d), "\n") {
462*2810ac1bSKiyoung Kim		if !strings.HasPrefix(line, "Cap") {
463*2810ac1bSKiyoung Kim			continue
464*2810ac1bSKiyoung Kim		}
465*2810ac1bSKiyoung Kim		flavor := line[3:]
466*2810ac1bSKiyoung Kim		if strings.HasPrefix(flavor, "Inh:\t") {
467*2810ac1bSKiyoung Kim			iab.i = parseHex(line[8:], false)
468*2810ac1bSKiyoung Kim			continue
469*2810ac1bSKiyoung Kim		}
470*2810ac1bSKiyoung Kim		if strings.HasPrefix(flavor, "Bnd:\t") {
471*2810ac1bSKiyoung Kim			iab.nb = parseHex(line[8:], true)
472*2810ac1bSKiyoung Kim			continue
473*2810ac1bSKiyoung Kim		}
474*2810ac1bSKiyoung Kim		if strings.HasPrefix(flavor, "Amb:\t") {
475*2810ac1bSKiyoung Kim			iab.a = parseHex(line[8:], false)
476*2810ac1bSKiyoung Kim			continue
477*2810ac1bSKiyoung Kim		}
478*2810ac1bSKiyoung Kim	}
479*2810ac1bSKiyoung Kim	if len(iab.i) != words || len(iab.a) != words || len(iab.nb) != words {
480*2810ac1bSKiyoung Kim		return nil, ErrBadValue
481*2810ac1bSKiyoung Kim	}
482*2810ac1bSKiyoung Kim	return iab, nil
483*2810ac1bSKiyoung Kim}
484