Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added goroutine to wait on systray process so it does not zombie when dies, now only spin up systray where uid less than 501, call to systray.Quit on exit #859

Merged

Conversation

James-Pickett
Copy link
Contributor

No description provided.

Copy link
Contributor

@directionless directionless left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given your comment -- that the parent need to stick around for some process cleanup -- this makes sense. But I'm a little leery about some fragility.

The biggest (potential) issue I see, is that a misbehaving process, will cause the parent to block on exiting. I feel like that sort of thing needs some protections. Which probably means something hooked to the runner's interrupt maybe? Not sure?

The other thing I see, which is more of a feature than bug, is that this adds a go routine to the parent that's watching this child. That would be an obvious place to do signaling. If we want to exit, send a STOP, and if it doesn't die, send a KILL. Etc.

directionless
directionless previously approved these changes Aug 16, 2022
@@ -58,16 +62,42 @@ func (r *SystrayUsersProcessesRunner) Execute() error {
// Interrupt stops creating launcher systray processes and kills any existing ones.
func (r *SystrayUsersProcessesRunner) Interrupt(err error) {
r.interrupt <- struct{}{}

for _, proc := range r.uidProcs {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this for loop feel a little weird, but I can't quite say why. I think it's probably fine to merge, and at worst will be noisy and we'll iterate.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea, it's weird ....

how about ...

if !processExists(proc.Pid) {
	continue
} else if err := proc.Signal(syscall.SIGTERM); err != nil {
	level.Error(r.logger).Log(
		"msg", "error sending SIGTERM to systray process after interrupt",
		"err", err,
	)
} else if err := proc.Kill(); err != nil {
	level.Error(r.logger).Log(
		"msg", "error killing systray process after interrupt",
		"err", err,
	)
}

could use a switch statement, but then you can't capture the err in a variable for logging

switch {
case !processExists(proc.Pid):
	continue
case proc.Signal(syscall.SIGTERM) == nil:
	continue
case proc.Kill() == nil:
	continue
default:
	level.Error(r.logger).Log(
		"msg", "sigterm and kill failed for process",
		"pid", proc.Pid,
	)
}

Copy link
Contributor

@directionless directionless Aug 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, these are both getting at what I mean... Though Ideally you want a small sleep between the kills.

I almost want something like:

for _, proc := range r.uidProcs {
   proc.Signal(syscall.SIGTERM)
}

select {
case <-wgDone:
    return
case <-time.NewTimer(time.Second * 1).C:
    for _, proc := range r.uidProcs {
        proc.Kill()
    }
case <-time.NewTimer(time.Second * 5).C:
    level.Error(r.logger).Log("msg", "timeout waiting for systray processes to finish")
}

can't quite tell if that's correct, or too complicated, or what

@James-Pickett James-Pickett force-pushed the james/systray-zombie-processes branch from 7e8956f to 604c12f Compare August 22, 2022 20:00
// CPU consumtion go way up.

// To get around the issue mentioned above, build the binary first and set it's path as the executable path on the runner.
executablePath := filepath.Join(t.TempDir(), "systray")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
executablePath := filepath.Join(t.TempDir(), "systray")
executablePath := filepath.Join(t.TempDir(), "systray.exe")

Somewhat optional, but if/when windows, we'll need .exe

@James-Pickett James-Pickett merged commit ab5cc8b into kolide:main Aug 22, 2022
@James-Pickett James-Pickett deleted the james/systray-zombie-processes branch August 22, 2022 20:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants