xref: /aosp_15_r20/external/libcap/cap/launch.go (revision 2810ac1b38eead2603277920c78344c84ddf3aff)
1*2810ac1bSKiyoung Kimpackage cap
2*2810ac1bSKiyoung Kim
3*2810ac1bSKiyoung Kimimport (
4*2810ac1bSKiyoung Kim	"errors"
5*2810ac1bSKiyoung Kim	"os"
6*2810ac1bSKiyoung Kim	"runtime"
7*2810ac1bSKiyoung Kim	"sync"
8*2810ac1bSKiyoung Kim	"syscall"
9*2810ac1bSKiyoung Kim	"unsafe"
10*2810ac1bSKiyoung Kim)
11*2810ac1bSKiyoung Kim
12*2810ac1bSKiyoung Kim// Launcher holds a configuration for executing an optional callback
13*2810ac1bSKiyoung Kim// function and/or launching a child process with capability state
14*2810ac1bSKiyoung Kim// different from the parent.
15*2810ac1bSKiyoung Kim//
16*2810ac1bSKiyoung Kim// Note, go1.10 is the earliest version of the Go toolchain that can
17*2810ac1bSKiyoung Kim// support this abstraction.
18*2810ac1bSKiyoung Kimtype Launcher struct {
19*2810ac1bSKiyoung Kim	mu sync.RWMutex
20*2810ac1bSKiyoung Kim
21*2810ac1bSKiyoung Kim	// Note, path and args must be set, or callbackFn. They cannot
22*2810ac1bSKiyoung Kim	// both be empty. In such cases .Launch() will error out.
23*2810ac1bSKiyoung Kim	path string
24*2810ac1bSKiyoung Kim	args []string
25*2810ac1bSKiyoung Kim	env  []string
26*2810ac1bSKiyoung Kim
27*2810ac1bSKiyoung Kim	callbackFn func(pa *syscall.ProcAttr, data interface{}) error
28*2810ac1bSKiyoung Kim
29*2810ac1bSKiyoung Kim	// The following are only honored when path is non empty.
30*2810ac1bSKiyoung Kim	changeUIDs bool
31*2810ac1bSKiyoung Kim	uid        int
32*2810ac1bSKiyoung Kim
33*2810ac1bSKiyoung Kim	changeGIDs bool
34*2810ac1bSKiyoung Kim	gid        int
35*2810ac1bSKiyoung Kim	groups     []int
36*2810ac1bSKiyoung Kim
37*2810ac1bSKiyoung Kim	changeMode bool
38*2810ac1bSKiyoung Kim	mode       Mode
39*2810ac1bSKiyoung Kim
40*2810ac1bSKiyoung Kim	iab *IAB
41*2810ac1bSKiyoung Kim
42*2810ac1bSKiyoung Kim	chroot string
43*2810ac1bSKiyoung Kim}
44*2810ac1bSKiyoung Kim
45*2810ac1bSKiyoung Kim// NewLauncher returns a new launcher for the specified program path
46*2810ac1bSKiyoung Kim// and args with the specified environment.
47*2810ac1bSKiyoung Kimfunc NewLauncher(path string, args []string, env []string) *Launcher {
48*2810ac1bSKiyoung Kim	return &Launcher{
49*2810ac1bSKiyoung Kim		path: path,
50*2810ac1bSKiyoung Kim		args: args,
51*2810ac1bSKiyoung Kim		env:  env,
52*2810ac1bSKiyoung Kim	}
53*2810ac1bSKiyoung Kim}
54*2810ac1bSKiyoung Kim
55*2810ac1bSKiyoung Kim// FuncLauncher returns a new launcher whose purpose is to only
56*2810ac1bSKiyoung Kim// execute fn in a disposable security context. This is a more bare
57*2810ac1bSKiyoung Kim// bones variant of the more elaborate program launcher returned by
58*2810ac1bSKiyoung Kim// cap.NewLauncher().
59*2810ac1bSKiyoung Kim//
60*2810ac1bSKiyoung Kim// Note, this launcher will fully ignore any overrides provided by the
61*2810ac1bSKiyoung Kim// (*Launcher).SetUID() etc. methods. Should your fn() code want to
62*2810ac1bSKiyoung Kim// run with a different capability state or other privilege, it should
63*2810ac1bSKiyoung Kim// use the cap.*() functions to set them directly. The cap package
64*2810ac1bSKiyoung Kim// will ensure that their effects are limited to the runtime of this
65*2810ac1bSKiyoung Kim// individual function invocation. Warning: executing non-cap.*()
66*2810ac1bSKiyoung Kim// syscall functions may corrupt the state of the program runtime and
67*2810ac1bSKiyoung Kim// lead to unpredictable results.
68*2810ac1bSKiyoung Kim//
69*2810ac1bSKiyoung Kim// The properties of fn are similar to those supplied via
70*2810ac1bSKiyoung Kim// (*Launcher).Callback(fn) method. However, this launcher is bare
71*2810ac1bSKiyoung Kim// bones because, when launching, all privilege management performed
72*2810ac1bSKiyoung Kim// by the fn() is fully discarded when the fn() completes
73*2810ac1bSKiyoung Kim// execution. That is, it does not end by exec()ing some program.
74*2810ac1bSKiyoung Kimfunc FuncLauncher(fn func(interface{}) error) *Launcher {
75*2810ac1bSKiyoung Kim	return &Launcher{
76*2810ac1bSKiyoung Kim		callbackFn: func(ignored *syscall.ProcAttr, data interface{}) error {
77*2810ac1bSKiyoung Kim			return fn(data)
78*2810ac1bSKiyoung Kim		},
79*2810ac1bSKiyoung Kim	}
80*2810ac1bSKiyoung Kim}
81*2810ac1bSKiyoung Kim
82*2810ac1bSKiyoung Kim// Callback changes the callback function for Launch() to call before
83*2810ac1bSKiyoung Kim// changing privilege. The only thing that is assumed is that the OS
84*2810ac1bSKiyoung Kim// thread in use to call this callback function at launch time will be
85*2810ac1bSKiyoung Kim// the one that ultimately calls fork to complete the launch of a path
86*2810ac1bSKiyoung Kim// specified executable. Any returned error value of said function
87*2810ac1bSKiyoung Kim// will terminate the launch process.
88*2810ac1bSKiyoung Kim//
89*2810ac1bSKiyoung Kim// A nil fn causes there to be no callback function invoked during a
90*2810ac1bSKiyoung Kim// Launch() sequence - it will remove any pre-existing callback.
91*2810ac1bSKiyoung Kim//
92*2810ac1bSKiyoung Kim// If the non-nil fn requires any effective capabilities in order to
93*2810ac1bSKiyoung Kim// run, they can be raised prior to calling .Launch() or inside the
94*2810ac1bSKiyoung Kim// callback function itself.
95*2810ac1bSKiyoung Kim//
96*2810ac1bSKiyoung Kim// If the specified callback fn should call any "cap" package
97*2810ac1bSKiyoung Kim// functions that change privilege state, these calls will only affect
98*2810ac1bSKiyoung Kim// the launch goroutine itself. While the launch is in progress, other
99*2810ac1bSKiyoung Kim// (non-launch) goroutines will block if they attempt to change
100*2810ac1bSKiyoung Kim// privilege state. These routines will unblock once there are no
101*2810ac1bSKiyoung Kim// in-flight launches.
102*2810ac1bSKiyoung Kim//
103*2810ac1bSKiyoung Kim// Note, the first argument provided to the callback function is the
104*2810ac1bSKiyoung Kim// *syscall.ProcAttr value to be used when a process launch is taking
105*2810ac1bSKiyoung Kim// place. A non-nil structure pointer can be modified by the callback
106*2810ac1bSKiyoung Kim// to enhance the launch. For example, the .Files field can be
107*2810ac1bSKiyoung Kim// overridden to affect how the launched process' stdin/out/err are
108*2810ac1bSKiyoung Kim// handled.
109*2810ac1bSKiyoung Kim//
110*2810ac1bSKiyoung Kim// Further, the 2nd argument to the callback function is provided at
111*2810ac1bSKiyoung Kim// Launch() invocation and can communicate contextual info to and from
112*2810ac1bSKiyoung Kim// the callback and the main process.
113*2810ac1bSKiyoung Kimfunc (attr *Launcher) Callback(fn func(*syscall.ProcAttr, interface{}) error) {
114*2810ac1bSKiyoung Kim	if attr == nil {
115*2810ac1bSKiyoung Kim		return
116*2810ac1bSKiyoung Kim	}
117*2810ac1bSKiyoung Kim	attr.mu.Lock()
118*2810ac1bSKiyoung Kim	defer attr.mu.Unlock()
119*2810ac1bSKiyoung Kim	attr.callbackFn = fn
120*2810ac1bSKiyoung Kim}
121*2810ac1bSKiyoung Kim
122*2810ac1bSKiyoung Kim// SetUID specifies the UID to be used by the launched command.
123*2810ac1bSKiyoung Kimfunc (attr *Launcher) SetUID(uid int) {
124*2810ac1bSKiyoung Kim	if attr == nil {
125*2810ac1bSKiyoung Kim		return
126*2810ac1bSKiyoung Kim	}
127*2810ac1bSKiyoung Kim	attr.mu.Lock()
128*2810ac1bSKiyoung Kim	defer attr.mu.Unlock()
129*2810ac1bSKiyoung Kim	attr.changeUIDs = true
130*2810ac1bSKiyoung Kim	attr.uid = uid
131*2810ac1bSKiyoung Kim}
132*2810ac1bSKiyoung Kim
133*2810ac1bSKiyoung Kim// SetGroups specifies the GID and supplementary groups for the
134*2810ac1bSKiyoung Kim// launched command.
135*2810ac1bSKiyoung Kimfunc (attr *Launcher) SetGroups(gid int, groups []int) {
136*2810ac1bSKiyoung Kim	if attr == nil {
137*2810ac1bSKiyoung Kim		return
138*2810ac1bSKiyoung Kim	}
139*2810ac1bSKiyoung Kim	attr.mu.Lock()
140*2810ac1bSKiyoung Kim	defer attr.mu.Unlock()
141*2810ac1bSKiyoung Kim	attr.changeGIDs = true
142*2810ac1bSKiyoung Kim	attr.gid = gid
143*2810ac1bSKiyoung Kim	attr.groups = groups
144*2810ac1bSKiyoung Kim}
145*2810ac1bSKiyoung Kim
146*2810ac1bSKiyoung Kim// SetMode specifies the libcap Mode to be used by the launched command.
147*2810ac1bSKiyoung Kimfunc (attr *Launcher) SetMode(mode Mode) {
148*2810ac1bSKiyoung Kim	if attr == nil {
149*2810ac1bSKiyoung Kim		return
150*2810ac1bSKiyoung Kim	}
151*2810ac1bSKiyoung Kim	attr.mu.Lock()
152*2810ac1bSKiyoung Kim	defer attr.mu.Unlock()
153*2810ac1bSKiyoung Kim	attr.changeMode = true
154*2810ac1bSKiyoung Kim	attr.mode = mode
155*2810ac1bSKiyoung Kim}
156*2810ac1bSKiyoung Kim
157*2810ac1bSKiyoung Kim// SetIAB specifies the IAB capability vectors to be inherited by the
158*2810ac1bSKiyoung Kim// launched command. A nil value means the prevailing vectors of the
159*2810ac1bSKiyoung Kim// parent will be inherited. Note, a duplicate of the provided IAB
160*2810ac1bSKiyoung Kim// tuple is actually stored, so concurrent modification of the iab
161*2810ac1bSKiyoung Kim// value does not affect the launcher.
162*2810ac1bSKiyoung Kimfunc (attr *Launcher) SetIAB(iab *IAB) {
163*2810ac1bSKiyoung Kim	if attr == nil {
164*2810ac1bSKiyoung Kim		return
165*2810ac1bSKiyoung Kim	}
166*2810ac1bSKiyoung Kim	attr.mu.Lock()
167*2810ac1bSKiyoung Kim	defer attr.mu.Unlock()
168*2810ac1bSKiyoung Kim	attr.iab, _ = iab.Dup()
169*2810ac1bSKiyoung Kim}
170*2810ac1bSKiyoung Kim
171*2810ac1bSKiyoung Kim// SetChroot specifies the chroot value to be used by the launched
172*2810ac1bSKiyoung Kim// command. An empty value means no-change from the prevailing value.
173*2810ac1bSKiyoung Kimfunc (attr *Launcher) SetChroot(root string) {
174*2810ac1bSKiyoung Kim	if attr == nil {
175*2810ac1bSKiyoung Kim		return
176*2810ac1bSKiyoung Kim	}
177*2810ac1bSKiyoung Kim	attr.mu.Lock()
178*2810ac1bSKiyoung Kim	defer attr.mu.Unlock()
179*2810ac1bSKiyoung Kim	attr.chroot = root
180*2810ac1bSKiyoung Kim}
181*2810ac1bSKiyoung Kim
182*2810ac1bSKiyoung Kim// lResult is used to get the result from the doomed launcher thread.
183*2810ac1bSKiyoung Kimtype lResult struct {
184*2810ac1bSKiyoung Kim	// tgid holds the thread group id, which is an alias for the
185*2810ac1bSKiyoung Kim	// shared process id of the parent program.
186*2810ac1bSKiyoung Kim	tgid int
187*2810ac1bSKiyoung Kim
188*2810ac1bSKiyoung Kim	// tid holds the tid of the locked launching thread which dies
189*2810ac1bSKiyoung Kim	// as the launch completes.
190*2810ac1bSKiyoung Kim	tid int
191*2810ac1bSKiyoung Kim
192*2810ac1bSKiyoung Kim	// pid is the pid of the launched program (path, args). In
193*2810ac1bSKiyoung Kim	// the case of a FuncLaunch() this value is zero on success.
194*2810ac1bSKiyoung Kim	// pid holds -1 in the case of error.
195*2810ac1bSKiyoung Kim	pid int
196*2810ac1bSKiyoung Kim
197*2810ac1bSKiyoung Kim	// err is nil on success, but otherwise holds the reason the
198*2810ac1bSKiyoung Kim	// launch failed.
199*2810ac1bSKiyoung Kim	err error
200*2810ac1bSKiyoung Kim}
201*2810ac1bSKiyoung Kim
202*2810ac1bSKiyoung Kim// ErrLaunchFailed is returned if a launch was aborted with no more
203*2810ac1bSKiyoung Kim// specific error.
204*2810ac1bSKiyoung Kimvar ErrLaunchFailed = errors.New("launch failed")
205*2810ac1bSKiyoung Kim
206*2810ac1bSKiyoung Kim// ErrNoLaunch indicates the go runtime available to this binary does
207*2810ac1bSKiyoung Kim// not reliably support launching. See cap.LaunchSupported.
208*2810ac1bSKiyoung Kimvar ErrNoLaunch = errors.New("launch not supported")
209*2810ac1bSKiyoung Kim
210*2810ac1bSKiyoung Kim// ErrAmbiguousChroot indicates that the Launcher is being used in
211*2810ac1bSKiyoung Kim// addition to a callback supplied Chroot. The former should be used
212*2810ac1bSKiyoung Kim// exclusively for this.
213*2810ac1bSKiyoung Kimvar ErrAmbiguousChroot = errors.New("use Launcher for chroot")
214*2810ac1bSKiyoung Kim
215*2810ac1bSKiyoung Kim// ErrAmbiguousIDs indicates that the Launcher is being used in
216*2810ac1bSKiyoung Kim// addition to a callback supplied Credentials. The former should be
217*2810ac1bSKiyoung Kim// used exclusively for this.
218*2810ac1bSKiyoung Kimvar ErrAmbiguousIDs = errors.New("use Launcher for uids and gids")
219*2810ac1bSKiyoung Kim
220*2810ac1bSKiyoung Kim// ErrAmbiguousAmbient indicates that the Launcher is being used in
221*2810ac1bSKiyoung Kim// addition to a callback supplied ambient set and the former should
222*2810ac1bSKiyoung Kim// be used exclusively in a Launch call.
223*2810ac1bSKiyoung Kimvar ErrAmbiguousAmbient = errors.New("use Launcher for ambient caps")
224*2810ac1bSKiyoung Kim
225*2810ac1bSKiyoung Kim// lName is the name we temporarily give to the launcher thread. Note,
226*2810ac1bSKiyoung Kim// this will likely stick around in the process tree if the Go runtime
227*2810ac1bSKiyoung Kim// is not cleaning up locked launcher OS threads.
228*2810ac1bSKiyoung Kimvar lName = []byte("cap-launcher\000")
229*2810ac1bSKiyoung Kim
230*2810ac1bSKiyoung Kim// <uapi/linux/prctl.h>
231*2810ac1bSKiyoung Kimconst prSetName = 15
232*2810ac1bSKiyoung Kim
233*2810ac1bSKiyoung Kim//go:uintptrescapes
234*2810ac1bSKiyoung Kimfunc launch(result chan<- lResult, attr *Launcher, data interface{}, quit chan<- struct{}) {
235*2810ac1bSKiyoung Kim	if quit != nil {
236*2810ac1bSKiyoung Kim		defer close(quit)
237*2810ac1bSKiyoung Kim	}
238*2810ac1bSKiyoung Kim
239*2810ac1bSKiyoung Kim	// Thread group ID is the process ID.
240*2810ac1bSKiyoung Kim	tgid := syscall.Getpid()
241*2810ac1bSKiyoung Kim
242*2810ac1bSKiyoung Kim	// This code waits until we are not scheduled on the parent
243*2810ac1bSKiyoung Kim	// thread.  We will exit this thread once the child has
244*2810ac1bSKiyoung Kim	// launched.
245*2810ac1bSKiyoung Kim	runtime.LockOSThread()
246*2810ac1bSKiyoung Kim	tid := syscall.Gettid()
247*2810ac1bSKiyoung Kim	if tid == tgid {
248*2810ac1bSKiyoung Kim		// Force the go runtime to find a new thread to run
249*2810ac1bSKiyoung Kim		// on.  (It is really awkward to have a process'
250*2810ac1bSKiyoung Kim		// PID=TID thread in effectively a zombie state. The
251*2810ac1bSKiyoung Kim		// Go runtime has support for it, but pstree gives
252*2810ac1bSKiyoung Kim		// ugly output since the prSetName value sticks around
253*2810ac1bSKiyoung Kim		// after launch completion...
254*2810ac1bSKiyoung Kim		//
255*2810ac1bSKiyoung Kim		// (Optimize for time to debug by reducing ugly spam
256*2810ac1bSKiyoung Kim		// like this.)
257*2810ac1bSKiyoung Kim		quit := make(chan struct{})
258*2810ac1bSKiyoung Kim		go launch(result, attr, data, quit)
259*2810ac1bSKiyoung Kim
260*2810ac1bSKiyoung Kim		// Wait for that go routine to complete.
261*2810ac1bSKiyoung Kim		<-quit
262*2810ac1bSKiyoung Kim		runtime.UnlockOSThread()
263*2810ac1bSKiyoung Kim		return
264*2810ac1bSKiyoung Kim	}
265*2810ac1bSKiyoung Kim
266*2810ac1bSKiyoung Kim	// Provide a way to serialize the caller on the thread
267*2810ac1bSKiyoung Kim	// completing. This should be done by the one locked tid that
268*2810ac1bSKiyoung Kim	// does the ForkExec(). All the other threads have a different
269*2810ac1bSKiyoung Kim	// security context.
270*2810ac1bSKiyoung Kim	defer close(result)
271*2810ac1bSKiyoung Kim
272*2810ac1bSKiyoung Kim	// By never releasing the LockOSThread here, we guarantee that
273*2810ac1bSKiyoung Kim	// the runtime will terminate the current OS thread once this
274*2810ac1bSKiyoung Kim	// function returns.
275*2810ac1bSKiyoung Kim	scwSetState(launchIdle, launchActive, tid)
276*2810ac1bSKiyoung Kim
277*2810ac1bSKiyoung Kim	// Name the launcher thread - transient, but helps to debug if
278*2810ac1bSKiyoung Kim	// the callbackFn or something else hangs up.
279*2810ac1bSKiyoung Kim	singlesc.prctlrcall(prSetName, uintptr(unsafe.Pointer(&lName[0])), 0)
280*2810ac1bSKiyoung Kim
281*2810ac1bSKiyoung Kim	var pa *syscall.ProcAttr
282*2810ac1bSKiyoung Kim	var err error
283*2810ac1bSKiyoung Kim	var needChroot bool
284*2810ac1bSKiyoung Kim
285*2810ac1bSKiyoung Kim	// Only prepare a non-nil pa value if a path is provided.
286*2810ac1bSKiyoung Kim	if attr.path != "" {
287*2810ac1bSKiyoung Kim		// By default the following file descriptors are preserved for
288*2810ac1bSKiyoung Kim		// the child. The user should modify them in the callback for
289*2810ac1bSKiyoung Kim		// stdin/out/err redirection.
290*2810ac1bSKiyoung Kim		pa = &syscall.ProcAttr{
291*2810ac1bSKiyoung Kim			Files: []uintptr{0, 1, 2},
292*2810ac1bSKiyoung Kim		}
293*2810ac1bSKiyoung Kim		if len(attr.env) != 0 {
294*2810ac1bSKiyoung Kim			pa.Env = attr.env
295*2810ac1bSKiyoung Kim		} else {
296*2810ac1bSKiyoung Kim			pa.Env = os.Environ()
297*2810ac1bSKiyoung Kim		}
298*2810ac1bSKiyoung Kim	}
299*2810ac1bSKiyoung Kim
300*2810ac1bSKiyoung Kim	var pid int
301*2810ac1bSKiyoung Kim	if attr.callbackFn != nil {
302*2810ac1bSKiyoung Kim		if err = attr.callbackFn(pa, data); err != nil {
303*2810ac1bSKiyoung Kim			goto abort
304*2810ac1bSKiyoung Kim		}
305*2810ac1bSKiyoung Kim		if attr.path == "" {
306*2810ac1bSKiyoung Kim			goto abort
307*2810ac1bSKiyoung Kim		}
308*2810ac1bSKiyoung Kim	}
309*2810ac1bSKiyoung Kim
310*2810ac1bSKiyoung Kim	if needChroot, err = validatePA(pa, attr.chroot); err != nil {
311*2810ac1bSKiyoung Kim		goto abort
312*2810ac1bSKiyoung Kim	}
313*2810ac1bSKiyoung Kim	if attr.changeUIDs {
314*2810ac1bSKiyoung Kim		if err = singlesc.setUID(attr.uid); err != nil {
315*2810ac1bSKiyoung Kim			goto abort
316*2810ac1bSKiyoung Kim		}
317*2810ac1bSKiyoung Kim	}
318*2810ac1bSKiyoung Kim	if attr.changeGIDs {
319*2810ac1bSKiyoung Kim		if err = singlesc.setGroups(attr.gid, attr.groups); err != nil {
320*2810ac1bSKiyoung Kim			goto abort
321*2810ac1bSKiyoung Kim		}
322*2810ac1bSKiyoung Kim	}
323*2810ac1bSKiyoung Kim	if attr.changeMode {
324*2810ac1bSKiyoung Kim		if err = singlesc.setMode(attr.mode); err != nil {
325*2810ac1bSKiyoung Kim			goto abort
326*2810ac1bSKiyoung Kim		}
327*2810ac1bSKiyoung Kim	}
328*2810ac1bSKiyoung Kim	if attr.iab != nil {
329*2810ac1bSKiyoung Kim		// Note, since .iab is a private copy we don't need to
330*2810ac1bSKiyoung Kim		// lock it around this call.
331*2810ac1bSKiyoung Kim		if err = singlesc.iabSetProc(attr.iab); err != nil {
332*2810ac1bSKiyoung Kim			goto abort
333*2810ac1bSKiyoung Kim		}
334*2810ac1bSKiyoung Kim	}
335*2810ac1bSKiyoung Kim
336*2810ac1bSKiyoung Kim	if needChroot {
337*2810ac1bSKiyoung Kim		c := GetProc()
338*2810ac1bSKiyoung Kim		if err = c.SetFlag(Effective, true, SYS_CHROOT); err != nil {
339*2810ac1bSKiyoung Kim			goto abort
340*2810ac1bSKiyoung Kim		}
341*2810ac1bSKiyoung Kim		if err = singlesc.setProc(c); err != nil {
342*2810ac1bSKiyoung Kim			goto abort
343*2810ac1bSKiyoung Kim		}
344*2810ac1bSKiyoung Kim	}
345*2810ac1bSKiyoung Kim	pid, err = syscall.ForkExec(attr.path, attr.args, pa)
346*2810ac1bSKiyoung Kim
347*2810ac1bSKiyoung Kimabort:
348*2810ac1bSKiyoung Kim	if err != nil {
349*2810ac1bSKiyoung Kim		pid = -1
350*2810ac1bSKiyoung Kim	}
351*2810ac1bSKiyoung Kim	result <- lResult{
352*2810ac1bSKiyoung Kim		tgid: tgid,
353*2810ac1bSKiyoung Kim		tid:  tid,
354*2810ac1bSKiyoung Kim		pid:  pid,
355*2810ac1bSKiyoung Kim		err:  err,
356*2810ac1bSKiyoung Kim	}
357*2810ac1bSKiyoung Kim}
358*2810ac1bSKiyoung Kim
359*2810ac1bSKiyoung Kim// pollForThreadExit waits for a thread to terminate. Only after the
360*2810ac1bSKiyoung Kim// thread has safely exited is it safe to resume POSIX semantics
361*2810ac1bSKiyoung Kim// security state mirroring for the rest of the process threads.
362*2810ac1bSKiyoung Kimfunc (v lResult) pollForThreadExit() {
363*2810ac1bSKiyoung Kim	if v.tid == -1 {
364*2810ac1bSKiyoung Kim		return
365*2810ac1bSKiyoung Kim	}
366*2810ac1bSKiyoung Kim	for syscall.Tgkill(v.tgid, v.tid, 0) == nil {
367*2810ac1bSKiyoung Kim		runtime.Gosched()
368*2810ac1bSKiyoung Kim	}
369*2810ac1bSKiyoung Kim	scwSetState(launchActive, launchIdle, v.tid)
370*2810ac1bSKiyoung Kim}
371*2810ac1bSKiyoung Kim
372*2810ac1bSKiyoung Kim// Launch performs a callback function and/or new program launch with
373*2810ac1bSKiyoung Kim// a disposable security state. The data object, when not nil, can be
374*2810ac1bSKiyoung Kim// used to communicate with the callback. It can also be used to
375*2810ac1bSKiyoung Kim// return details from the callback function's execution.
376*2810ac1bSKiyoung Kim//
377*2810ac1bSKiyoung Kim// If the attr was created with NewLauncher(), this present function
378*2810ac1bSKiyoung Kim// will return the pid of the launched process, or -1 and a non-nil
379*2810ac1bSKiyoung Kim// error.
380*2810ac1bSKiyoung Kim//
381*2810ac1bSKiyoung Kim// If the attr was created with FuncLauncher(), this present function
382*2810ac1bSKiyoung Kim// will return 0, nil if the callback function exits without
383*2810ac1bSKiyoung Kim// error. Otherwise it will return -1 and the non-nil error of the
384*2810ac1bSKiyoung Kim// callback return value.
385*2810ac1bSKiyoung Kim//
386*2810ac1bSKiyoung Kim// Note, while the disposable security state thread makes some
387*2810ac1bSKiyoung Kim// operations seem more isolated - they are *not securely
388*2810ac1bSKiyoung Kim// isolated*. Launching is inherently violating the POSIX semantics
389*2810ac1bSKiyoung Kim// maintained by the rest of the "libcap/cap" package, so think of
390*2810ac1bSKiyoung Kim// launching as a convenience wrapper around fork()ing.
391*2810ac1bSKiyoung Kim//
392*2810ac1bSKiyoung Kim// Advanced user note: if the caller of this function thinks they know
393*2810ac1bSKiyoung Kim// what they are doing by using runtime.LockOSThread() before invoking
394*2810ac1bSKiyoung Kim// this function, they should understand that the OS thread invoking
395*2810ac1bSKiyoung Kim// (*Launcher).Launch() is *not* guaranteed to be the one used for the
396*2810ac1bSKiyoung Kim// disposable security state to perform the launch. If said caller
397*2810ac1bSKiyoung Kim// needs to run something on the disposable security state thread,
398*2810ac1bSKiyoung Kim// they should do it via the launch callback function mechanism. (The
399*2810ac1bSKiyoung Kim// Go runtime is complicated and this is why this Launch mechanism
400*2810ac1bSKiyoung Kim// provides the optional callback function.)
401*2810ac1bSKiyoung Kimfunc (attr *Launcher) Launch(data interface{}) (int, error) {
402*2810ac1bSKiyoung Kim	if !LaunchSupported {
403*2810ac1bSKiyoung Kim		return -1, ErrNoLaunch
404*2810ac1bSKiyoung Kim	}
405*2810ac1bSKiyoung Kim	if attr == nil {
406*2810ac1bSKiyoung Kim		return -1, ErrLaunchFailed
407*2810ac1bSKiyoung Kim	}
408*2810ac1bSKiyoung Kim	attr.mu.RLock()
409*2810ac1bSKiyoung Kim	defer attr.mu.RUnlock()
410*2810ac1bSKiyoung Kim	if attr.callbackFn == nil && (attr.path == "" || len(attr.args) == 0) {
411*2810ac1bSKiyoung Kim		return -1, ErrLaunchFailed
412*2810ac1bSKiyoung Kim	}
413*2810ac1bSKiyoung Kim
414*2810ac1bSKiyoung Kim	result := make(chan lResult)
415*2810ac1bSKiyoung Kim	go launch(result, attr, data, nil)
416*2810ac1bSKiyoung Kim	v, ok := <-result
417*2810ac1bSKiyoung Kim	if !ok {
418*2810ac1bSKiyoung Kim		return -1, ErrLaunchFailed
419*2810ac1bSKiyoung Kim	}
420*2810ac1bSKiyoung Kim	<-result // blocks until the launch() goroutine exits
421*2810ac1bSKiyoung Kim	v.pollForThreadExit()
422*2810ac1bSKiyoung Kim	return v.pid, v.err
423*2810ac1bSKiyoung Kim}
424