-
Notifications
You must be signed in to change notification settings - Fork 453
Don't kill processes when cleaning up PID files #6311
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
Conversation
c983be6 to
8d2dd2b
Compare
juanluisvaladas
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with the first 5 commits in their current state but it's not clear to me why it's better to bail out instead of just terminating the process.
I can't think of a scenario where killing the process is a bad idea, I guess I'm missing something?
pkg/supervisor/prochandle_linux.go
Outdated
| } | ||
|
|
||
| func isZombie(pid int) (bool, error) { | ||
| // https://man7.org/linux/man-pages/man5/proc_pid_stat.5.html |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Maybe it's worth adding another comment with the relevant kernel source (I had to search it to understand the fields and all)
https://github.com/torvalds/linux/blob/v4.19/fs/proc/array.c#L152
I picked 4.19 so that it's not a very recent version and people reading it don't think it's a new feature but it doesn't really matter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's also worth noting that we already depend indirectly on github.com/prometheus/procfs, which handles this, but actually I prefer this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Maybe it's worth adding another comment with the relevant kernel source (I had to search it to understand the fields and all)
TBH, I found the man pages to be very clear and approachable for this. They mention field names, their order, their sprintf format directive, and a comprehensive description. I tried to pick that up in the comments below: "pid" and "comm" are the first two fields, "state" is the third one. Maybe we can make those comments more clear?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we already depend indirectly on github.com/prometheus/procfs
Yeah, I think there's quite a few indirect dependencies dealing with procfs. I think containerd might have something into that direction, too. But I think they're all coming from a different angle to the problem: Prometheus is about monitoring, i.e. gathering data in a bunch, containerd, again, might be more concerned about security aspects when querying procfs data.
During review of #6203 @ncopa raised concerns about killing processes. He would prefer to leave that decision to the users. There's always the chance to break something when killing processes, e.g., say, etcd while it's doing stuff on disk. |
pkg/supervisor/prochandle_unix.go
Outdated
| if errors.Is(err, os.ErrProcessDone) { | ||
| return nil, syscall.ESRCH | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test should be removed. The process can disappear right after the test is performed and before the return of function, so we need to handle the case of missing process late. No need to handle it twice.
pkg/supervisor/prochandle_linux.go
Outdated
| } | ||
|
|
||
| // Do a last TOCTOU check: We now know the state of the process with the | ||
| // referenced PID. We go back to os.Process, once again, to ensure that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We actually don't know the state of the process at this point. The state may have changed after we did the test(s).
For that reason I think the entire hasTerminated function should be removed.
This does not work. We can not rely on a |
Good catch! Seems to be since go 1.4. |
8d2dd2b to
24422a4
Compare
3b370d3 to
6e5d7a0
Compare
It models the /proc mount, particularly the /proc/<pid> directories and their contents. It focuses on the requirements of the supervisor. Signed-off-by: Tom Wieczorek <[email protected]>
The Dir newtype around os.File provides methods for opening, reading, statting and listing files or directories relative to a dirfd file descriptor. Provides robust handling of directory relative operations, maintaining directory access consistency across rename/move operations, potentially mitigating symbolic link attacks. Signed-off-by: Tom Wieczorek <[email protected]>
The os package uses ErrProcessDone ("os: process already finished"), not
syscall.ESRCH ("no such process"). Reflect that usage in the procHandle
implementation. Make the openPID function actually check for the
existence of the process, and in that case, return an ESRCH.
This fixes a bug in which errors returned from procHandle's
requestGracefulShutdown and kill methods were checked against ESRCH,
where they should have been checked against ErrProcessDone.
Signed-off-by: Tom Wieczorek <[email protected]>
This is in preparation for disabling the code paths on macOS that rely on Linux-only proc filesystem parts. Signed-off-by: Tom Wieczorek <[email protected]>
There is no proc filesystem on macOS. Split things up and leave a minimal implementation in place to reflect this fact. This allows most of the unit tests to run on macOS while making it clear that proc stuff doesn't exist on macOS. Also enable the bogus PID file test unconditionally. This is just about the PID file parsing, which doesn't require platform-specific APIs. Signed-off-by: Tom Wieczorek <[email protected]>
Also adjust logging a bit. Signed-off-by: Tom Wieczorek <[email protected]>
Don't misuse shouldKillProcess to check if a process has terminated or not. Rename it to isK0sManaged and add appropriate docs. Instead, introduce a purpose-built hasTerminated function. This better reflects what this is about. Signed-off-by: Tom Wieczorek <[email protected]>
This allows for using the pidfd_send_signal syscall. Signed-off-by: Tom Wieczorek <[email protected]>
It's better to leave the decision what to do about a lingering process to the users. Try to terminate the process gracefully once and poll for process termination. If the process didn't terminate in time, bail out with an error. Re-implement the Supervisor proc handle without the stdlib. The os/exec API is not a good fit for implementing the PID file cleanup. Instead, use a combination of dirfds to /proc/<pid> directories, along with pidfd_send_signal (if available) to implement a race-free process termination. Signed-off-by: Tom Wieczorek <[email protected]>
6e5d7a0 to
4b1861c
Compare
ncopa
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Description
It's better to leave the decision what to do about a lingering process to the users. Try to terminate the process gracefully once and poll for process termination. If the process didn't terminate in time, bail out with an error.
Re-implement the Supervisor proc handle without the stdlib. The os/exec API is not a good fit for implementing the PID file cleanup. Instead, use a combination of dirfds to
/proc/<pid>directories, along withpidfd_send_signal(if available) to implement a race-free process termination.Don't misuse
shouldKillProcessto check if a process has terminated or not. Rename it toisK0sManagedand add appropriate docs. Instead, introduce a purpose-builthasTerminatedfunction.Split up Linux and macOS process handling. There is no proc filesystem on macOS. Split things up and leave a minimal implementation in place to reflect this fact. This allows most of the unit tests to run on macOS while making it clear that proc stuff doesn't exist on macOS.
Also enable the bogus PID file test unconditionally. This is just about the PID file parsing, which doesn't require platform-specific APIs.
See:
Type of change
How Has This Been Tested?
Checklist