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