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