-
Notifications
You must be signed in to change notification settings - Fork 20
feat: directly signal session action processes using CAP_KILL #196
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
feat: directly signal session action processes using CAP_KILL #196
Conversation
Signed-off-by: Josh Usiskin <[email protected]>
Signed-off-by: Josh Usiskin <[email protected]>
Signed-off-by: Josh Usiskin <[email protected]>
Signed-off-by: Josh Usiskin <[email protected]>
Signed-off-by: Josh Usiskin <[email protected]>
| # targetuser: targetuser, sharedgroup | ||
| # disjointuser: disjointuser, disjointgroup | ||
| RUN apt-get update && apt-get install -y sudo && \ | ||
| RUN apt-get update && apt-get install -y sudo psmisc libcap2-bin libcap2 libcap-dev gcc && \ |
Check notice
Code scanning / SonarCloud
Arguments in long RUN instructions should be sorted
f4ba9ba to
a1eeb1d
Compare
Signed-off-by: Josh Usiskin <[email protected]>
a1eeb1d to
621232c
Compare
| if not sys.platform.startswith("linux"): | ||
| raise OSError(f"libcap is only available on Linux, but found platform: {sys.platform}") | ||
|
|
||
| libcap = ctypes.CDLL(find_library("cap"), use_errno=True) |
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.
What happens if libcap is not installed/available? I notice that you had to install the lib into the docker container, for instance. If we get an exception, then that'll probably end up unhandled in the LoggingSubprocess?
Related: We should also update the README to let folk know that having this library available is beneficial.
…rage Signed-off-by: Josh Usiskin <[email protected]>
822b135 to
d098f25
Compare
Signed-off-by: Josh Usiskin <[email protected]>
5c58c7b to
a68707a
Compare
Signed-off-by: Josh Usiskin <[email protected]>
a68707a to
00c40ff
Compare
|



What was the problem/requirement? (What/Why)
Background:
The
Session.cancel_action()method needs to send signals to the session action subprocess. On POSIX systems, processes can only send signals to processes owned by the same user unless the process is root, or on Linux if the process has theCAP_KILLLinux capability (see capabilities(7) man page).To overcome this restriction when the
Sessionwas provided with a different user than the host process, theSession.cancel_action()method would launch a subprocess usingsudoto send the signal to the target process.Problem:
Under low memory conditions, there may not be sufficient memory to launch the subprocesses in order to send the signals and cancel the session action.
What was the solution? (How)
When sending the
SIGTERMsignal, a simplification was made to always send a signal to the subprocess sincesudowill forward signals that it can intercept, includingSIGTERM, to its child process.When the
CAP_KILLLinux capability is present, a process can send OS signals to processes belonging to other users. The code was modified to detect whenCAP_KILLis in the process' permitted/effective capability set(s) and, if so, send signals directly to the process.The implementation falls back to using the
sudoandbashapproach for signalling cross-user if the direct signaling is not possible or fails.If
CAP_KILLis in the permitted capability set, but not the effective capability set, then openjd will uselibcapviactypesto temporarily promoteCAP_KILLfrom permitted → effective and undo this after signalling.Along the way, a simplification of the process tree was made. Before,
openjd-sessionswould leave an intermediatebashprocess. This bash script had code to handle signal forwarding. This implementation turned out to be unnecessary. To simplify the process tree, the bash script was modified to use theexecbash built-in which replaces the process with the session action command. This means one less process in the process tree and we do not need signal forwarding. The process tree change is illustrated in the diagram below:flowchart TD sa([Session action]) style bash fill:red,stroke-dasharray: 5 5 openjd --> sudo sudo --> bash bash --> saWhat is the impact of this change?
CAP_KILLcapability, theSession.cancel_action()method is more robust under low-memory conditions.openjd-sessionsis simplified and there is no longer an intermediate bash process kept around and forwarding OS signalsHow was this change tested?
See DEVELOPMENT.md for information on running tests.
CAP_KILLis in the permitted and effective capability setCAP_KILLis in the permitted capability set onlyCAP_KILLis temporarily added to the effective capability set and restored after signallingCAP_KILLis not present and that the original implementation is used as a fallbackWas this change documented?
Yes
Is this a breaking change?
A breaking change is one that modifies a public contract in a way that is not backwards compatible. See the
Public Interfaces section
of the DEVELOPMENT.md for more information on the public contracts.
No, the public APIs and functional behaviours are unchanged.
Does this change impact security?
Yes, the change temporarily elevates privileges in
Session.cancel_action()for sending cross-user OS signals.openjd-sessionsis now "capability aware". IfCAP_KILLis in the process thread's permitted capability set but not in its effective capability set, it will:CAP_KILLto the thread's effective capability setCAP_KILLfrom the thread's effective capability setA integration test has been added to assert that
CAP_KILLis removed from the effective capability set.By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.