diff options
author | Andrew G. Morgan <morgan@kernel.org> | 2021-12-11 14:56:07 -0800 |
---|---|---|
committer | Andrew G. Morgan <morgan@kernel.org> | 2021-12-11 14:56:07 -0800 |
commit | e458889fbda4052919b61fd9f727bb1ac906d436 (patch) | |
tree | 40a2c13b15ad211a2108622aa75f85750e7e7e86 | |
parent | 806b53d13a792d834622b2e546cfdceecc5af699 (diff) | |
download | libcap-e458889fbda4052919b61fd9f727bb1ac906d436.tar.gz |
Complete launch thread exit sequence.
This should complete the fix for:
https://bugzilla.kernel.org/show_bug.cgi?id=215283
Simplify the code, and add a test that the kernel has confirmed that
the thread is no longer running.
Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
-rw-r--r-- | cap/launch.go | 49 |
1 files changed, 29 insertions, 20 deletions
diff --git a/cap/launch.go b/cap/launch.go index b67a856..cc3be50 100644 --- a/cap/launch.go +++ b/cap/launch.go @@ -181,6 +181,10 @@ func (attr *Launcher) SetChroot(root string) { // lResult is used to get the result from the doomed launcher thread. type lResult struct { + // tgid holds the thread group id, which is an alias for the + // shared process id of the parent program. + tgid int + // tid holds the tid of the locked launching thread which dies // as the launch completes. tid int @@ -232,13 +236,14 @@ func launch(result chan<- lResult, attr *Launcher, data interface{}, quit chan<- defer close(quit) } - pid := syscall.Getpid() + tgid := syscall.Getpid() + // This code waits until we are not scheduled on the parent // thread. We will exit this thread once the child has // launched. runtime.LockOSThread() tid := syscall.Gettid() - if tid == pid { + if tid == tgid { // Force the go runtime to find a new thread to run // on. (It is really awkward to have a process' // PID=TID thread in effectively a zombie state. The @@ -291,12 +296,12 @@ func launch(result chan<- lResult, attr *Launcher, data interface{}, quit chan<- } } + var pid int if attr.callbackFn != nil { if err = attr.callbackFn(pa, data); err != nil { goto abort } if attr.path == "" { - pid = 0 goto abort } } @@ -343,12 +348,24 @@ abort: pid = -1 } result <- lResult{ - tid: tid, - pid: pid, - err: err, + tgid: tgid, + tid: tid, + pid: pid, + err: err, } } +// pollForThreadExit waits for a thread to terminate. +func (v lResult) pollForThreadExit() { + if v.tid == -1 { + return + } + for syscall.Tgkill(v.tgid, v.tid, 0) == nil { + runtime.Gosched() + } + scwSetState(launchActive, launchIdle, v.tid) +} + // Launch performs a callback function and/or new program launch with // a disposable security state. The data object, when not nil, can be // used to communicate with the callback. It can also be used to @@ -393,19 +410,11 @@ func (attr *Launcher) Launch(data interface{}) (int, error) { result := make(chan lResult) go launch(result, attr, data, nil) - for { - select { - case v, ok := <-result: - <-result // blocks until the launch() goroutine exits - if !ok { - return -1, ErrLaunchFailed - } - if v.tid != -1 { - defer scwSetState(launchActive, launchIdle, v.tid) - } - return v.pid, v.err - default: - runtime.Gosched() - } + v, ok := <-result + if !ok { + return -1, ErrLaunchFailed } + <-result // blocks until the launch() goroutine exits + v.pollForThreadExit() + return v.pid, v.err } |