xref: /aosp_15_r20/external/libcap/cap/convenience.go (revision 2810ac1b38eead2603277920c78344c84ddf3aff)
1package cap
2
3import (
4	"errors"
5	"fmt"
6	"syscall"
7	"unsafe"
8)
9
10// This file contains convenience functions for libcap, to help
11// users do the right thing with respect to capabilities for
12// common actions.
13
14// Secbits capture the prctl settable secure-bits of a process.
15type Secbits uint
16
17// SecbitNoRoot etc are the bitmasks associated with the supported
18// Secbit masks.  Source: uapi/linux/securebits.h
19const (
20	SecbitNoRoot Secbits = 1 << iota
21	SecbitNoRootLocked
22	SecbitNoSetUIDFixup
23	SecbitNoSetUIDFixupLocked
24	SecbitKeepCaps
25	SecbitKeepCapsLocked
26	SecbitNoCapAmbientRaise
27	SecbitNoCapAmbientRaiseLocked
28)
29
30const (
31	securedBasicBits   = SecbitNoRoot | SecbitNoRootLocked | SecbitNoSetUIDFixup | SecbitNoSetUIDFixupLocked | SecbitKeepCapsLocked
32	securedAmbientBits = securedBasicBits | SecbitNoCapAmbientRaise | SecbitNoCapAmbientRaiseLocked
33)
34
35// defines from uapi/linux/prctl.h
36const (
37	prGetKeepCaps   = 7
38	prSetKeepCaps   = 8
39	prGetSecureBits = 27
40	prSetSecureBits = 28
41	prSetNoNewPrivs = 38
42)
43
44// GetSecbits returns the current setting of the process' Secbits.
45func GetSecbits() Secbits {
46	v, err := multisc.prctlrcall(prGetSecureBits, 0, 0)
47	if err != nil {
48		panic(err)
49	}
50	return Secbits(v)
51}
52
53func (sc *syscaller) setSecbits(s Secbits) error {
54	_, err := sc.prctlwcall(prSetSecureBits, uintptr(s), 0)
55	return err
56}
57
58// Set attempts to force the process Secbits to a value. This function
59// will raise cap.SETPCAP in order to achieve this operation, and will
60// completely lower the Effective Flag of the process upon returning.
61func (s Secbits) Set() error {
62	state, sc := scwStateSC()
63	defer scwSetState(launchBlocked, state, -1)
64	return sc.setSecbits(s)
65}
66
67// Mode summarizes a complicated secure-bits and capability mode in a
68// libcap preferred way.
69type Mode uint
70
71// ModeUncertain etc are how libcap summarizes security modes
72// involving capabilities and secure-bits.
73const (
74	ModeUncertain Mode = iota
75	ModeNoPriv
76	ModePure1EInit
77	ModePure1E
78	ModeHybrid
79)
80
81// GetMode assesses the current process state and summarizes it as
82// a Mode. This function always succeeds. Unfamiliar modes are
83// declared ModeUncertain.
84func GetMode() Mode {
85	b := GetSecbits()
86	if b == 0 {
87		return ModeHybrid
88	}
89	if b&securedBasicBits != securedBasicBits {
90		return ModeUncertain
91	}
92
93	for c := Value(0); ; c++ {
94		v, err := GetAmbient(c)
95		if err != nil {
96			if c != 0 && b != securedAmbientBits {
97				return ModeUncertain
98			}
99			break
100		}
101		if v {
102			return ModeUncertain
103		}
104	}
105
106	w := GetProc()
107	e := NewSet()
108	cf, _ := w.Cf(e)
109
110	if cf.Has(Inheritable) {
111		return ModePure1E
112	}
113	if cf.Has(Permitted) || cf.Has(Effective) {
114		return ModePure1EInit
115	}
116
117	for c := Value(0); ; c++ {
118		v, err := GetBound(c)
119		if err != nil {
120			break
121		}
122		if v {
123			return ModePure1EInit
124		}
125	}
126
127	return ModeNoPriv
128}
129
130// ErrBadMode is the error returned when an attempt is made to set an
131// unrecognized libcap security mode.
132var ErrBadMode = errors.New("unsupported mode")
133
134func (sc *syscaller) setMode(m Mode) error {
135	w := GetProc()
136	defer func() {
137		w.ClearFlag(Effective)
138		sc.setProc(w)
139	}()
140
141	if err := w.SetFlag(Effective, true, SETPCAP); err != nil {
142		return err
143	}
144	if err := sc.setProc(w); err != nil {
145		return err
146	}
147
148	if m == ModeHybrid {
149		return sc.setSecbits(0)
150	}
151
152	if m == ModeNoPriv || m == ModePure1EInit {
153		w.ClearFlag(Inheritable)
154	} else if m != ModePure1E {
155		return ErrBadMode
156	}
157
158	sb := securedAmbientBits
159	if _, err := GetAmbient(0); err != nil {
160		sb = securedBasicBits
161	} else if err := sc.resetAmbient(); err != nil {
162		return err
163	}
164
165	if err := sc.setSecbits(sb); err != nil {
166		return err
167	}
168
169	if m != ModeNoPriv {
170		return nil
171	}
172
173	for c := Value(0); sc.dropBound(c) == nil; c++ {
174	}
175	w.ClearFlag(Permitted)
176
177	// For good measure.
178	sc.prctlwcall6(prSetNoNewPrivs, 1, 0, 0, 0, 0)
179
180	return nil
181}
182
183// Set attempts to enter the specified mode. An attempt is made to
184// enter the mode, so if you prefer this operation to be a no-op if
185// entering the same mode, call only if CurrentMode() disagrees with
186// the desired mode.
187//
188// This function will raise cap.SETPCAP in order to achieve this
189// operation, and will completely lower the Effective Flag of the
190// process' Set before returning. This function may fail for lack of
191// permission or because (some of) the Secbits are already locked for
192// the current process.
193func (m Mode) Set() error {
194	state, sc := scwStateSC()
195	defer scwSetState(launchBlocked, state, -1)
196	return sc.setMode(m)
197}
198
199// String returns the libcap conventional string for this mode.
200func (m Mode) String() string {
201	switch m {
202	case ModeUncertain:
203		return "UNCERTAIN"
204	case ModeNoPriv:
205		return "NOPRIV"
206	case ModePure1EInit:
207		return "PURE1E_INIT"
208	case ModePure1E:
209		return "PURE1E"
210	case ModeHybrid:
211		return "HYBRID"
212	default:
213		return "UNKNOWN"
214	}
215}
216
217func (sc *syscaller) setUID(uid int) error {
218	w := GetProc()
219	defer func() {
220		w.ClearFlag(Effective)
221		sc.setProc(w)
222	}()
223
224	if err := w.SetFlag(Effective, true, SETUID); err != nil {
225		return err
226	}
227
228	// these may or may not work depending on whether or not they
229	// are locked. We try them just in case.
230	sc.prctlwcall(prSetKeepCaps, 1, 0)
231	defer sc.prctlwcall(prSetKeepCaps, 0, 0)
232
233	if err := sc.setProc(w); err != nil {
234		return err
235	}
236
237	if _, _, err := sc.w3(syscall.SYS_SETUID, uintptr(uid), 0, 0); err != 0 {
238		return err
239	}
240	return nil
241}
242
243// SetUID is a convenience function for robustly setting the UID and
244// all other variants of UID (EUID etc) to the specified value without
245// dropping the privilege of the current process. This function will
246// raise cap.SETUID in order to achieve this operation, and will
247// completely lower the Effective Flag of the process before
248// returning. Unlike the traditional method of dropping privilege when
249// changing from [E]UID=0 to some other UID, this function only can
250// perform any change of UID if cap.SETUID is available, and this
251// operation will not alter the Permitted Flag of the process' Set.
252func SetUID(uid int) error {
253	state, sc := scwStateSC()
254	defer scwSetState(launchBlocked, state, -1)
255	return sc.setUID(uid)
256}
257
258//go:uintptrescapes
259func (sc *syscaller) setGroups(gid int, suppl []int) error {
260	w := GetProc()
261	defer func() {
262		w.ClearFlag(Effective)
263		sc.setProc(w)
264	}()
265
266	if err := w.SetFlag(Effective, true, SETGID); err != nil {
267		return err
268	}
269	if err := sc.setProc(w); err != nil {
270		return err
271	}
272
273	if _, _, err := sc.w3(syscall.SYS_SETGID, uintptr(gid), 0, 0); err != 0 {
274		return err
275	}
276	if len(suppl) == 0 {
277		if _, _, err := sc.w3(sysSetGroupsVariant, 0, 0, 0); err != 0 {
278			return err
279		}
280		return nil
281	}
282
283	// On linux gid values are 32-bits.
284	gs := make([]uint32, len(suppl))
285	for i, g := range suppl {
286		gs[i] = uint32(g)
287	}
288	if _, _, err := sc.w3(sysSetGroupsVariant, uintptr(len(suppl)), uintptr(unsafe.Pointer(&gs[0])), 0); err != 0 {
289		return err
290	}
291	return nil
292}
293
294// SetGroups is a convenience function for robustly setting the GID
295// and all other variants of GID (EGID etc) to the specified value, as
296// well as setting all of the supplementary groups. This function will
297// raise cap.SETGID in order to achieve this operation, and will
298// completely lower the Effective Flag of the process Set before
299// returning.
300func SetGroups(gid int, suppl ...int) error {
301	state, sc := scwStateSC()
302	defer scwSetState(launchBlocked, state, -1)
303	return sc.setGroups(gid, suppl)
304}
305
306//go:uintptrescapes
307
308// Prctlw is a convenience function for performing a syscall.Prctl()
309// call that executes on all the threads of the process. It is called
310// Prctlw because it is only appropriate to call this function when it
311// is writing thread state that the caller wants to set on all OS
312// threads of the process to observe POSIX semantics when Linux
313// doesn't natively honor them. (Check prctl documentation for when it
314// is appropriate to use this vs. a normal syscall.Prctl() call.)
315func Prctlw(prVal uintptr, args ...uintptr) (int, error) {
316	if n := len(args); n > 5 {
317		return -1, fmt.Errorf("prctl supports up to 5 arguments (not %d)", n)
318	}
319	state, sc := scwStateSC()
320	defer scwSetState(launchBlocked, state, -1)
321	as := make([]uintptr, 5)
322	copy(as, args)
323	return sc.prctlwcall6(prVal, as[0], as[1], as[2], as[3], as[4])
324}
325
326//go:uintptrescapes
327
328// Prctl is a convenience function that performs a syscall.Prctl()
329// that either reads state using a single OS thread, or performs a
330// Prctl that is treated as a process wide setting. It is provided for
331// symmetry reasons, but is equivalent to simply calling the
332// corresponding syscall function.
333func Prctl(prVal uintptr, args ...uintptr) (int, error) {
334	if n := len(args); n > 5 {
335		return -1, fmt.Errorf("prctl supports up to 5 arguments (not %d)", n)
336	}
337	as := make([]uintptr, 5)
338	copy(as, args)
339	return singlesc.prctlrcall6(prVal, as[0], as[1], as[2], as[3], as[4])
340}
341