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

session: Use pidfd for determining ws peer cgroup #21341

Merged
merged 3 commits into from
Nov 27, 2024

Conversation

martinpitt
Copy link
Member

We can get a reliable, PID recycling resistant, /proc query for
cockpit-session's ws peer (i.e. the far end of its stdin Unix socket) by
getting a pidfd instead of an ucred. This is always the pidfd for the
process that started the communication, it cannot be recycled. If the
original process does go away, querying the pidfd will just fail, even
if a new process with the same pid comes along.

We still need to "resolve" the pidfd to a pid to open /proc/pid/cgroup
(there is no direct kernel API to get a pidfd's cgroup). But validate
the pid after that query to ensure it didn't get recycled.

This is much easier and safer to do than parsing /proc/pid/stat.
However, this requires kernel 6.5, so is not yet available in e.g.
Debian 12 or RHEL 9. So keep the pid+time comparison fallback for these
older OSes.

Thanks to @bluca for the helpful technical advice!
#16808 (comment)

https://issues.redhat.com/browse/COCKPIT-1207

@martinpitt
Copy link
Member Author

Needs a little more love for Ubuntu 22.04 and RHEL 9, which don't have sys/pidfd.h yet.

@martinpitt
Copy link
Member Author

martinpitt commented Nov 27, 2024

Once more with feeling. This is a bit frustrating -- autoconf supports checking for function availability and header availability, but not whether a function is in a particular header. But it turns out that AC_CHECK_FUNCS(pidfd_getpid) works, I think that checks the glibc library, not the headers. So I'm using that one, that's also rather simple.

@martinpitt martinpitt marked this pull request as ready for review November 27, 2024 09:10
configure.ac Outdated Show resolved Hide resolved
@martinpitt martinpitt force-pushed the pidfd branch 2 times, most recently from 56fc74b to 47cbfe5 Compare November 27, 2024 09:14
Copy link
Member

@allisonkarlitskaya allisonkarlitskaya left a comment

Choose a reason for hiding this comment

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

I really like the structure you've chosen here: turning "get the dirfd of the /proc entry of the process which opened the other end of this socket, performing whatever checks you can" into a simple API is a really cool approach.

I wonder if you'd consider moving this growing pile of code to a separate file. Maybe that's too much...

src/session/client-certificate.c Outdated Show resolved Hide resolved
src/session/client-certificate.c Show resolved Hide resolved
src/session/client-certificate.c Show resolved Hide resolved
src/session/client-certificate.c Outdated Show resolved Hide resolved
src/session/client-certificate.c Show resolved Hide resolved
src/session/client-certificate.c Outdated Show resolved Hide resolved
@bluca
Copy link

bluca commented Nov 27, 2024

We still need to "resolve" the pidfd to a pid to open /proc/pid/cgroup
(there is no direct kernel API to get a pidfd's cgroup). But validate
the pid after that query to ensure it didn't get recycled.

Note that kernel 6.13 has a new IOCTL PIDFD_GET_INFO that I just added, that gives you the cgroup id from a pidfd. Of course that's extremely new, not even rc1 yet, but just leaving it as FYI

@martinpitt
Copy link
Member Author

@bluca Right, thanks! I saw that on LWN somewhere even. I'm happy to put that in once it's in any OS that we support (Debian testing or Fedora 42 once it gets released, presumably).

Copy link
Member

@allisonkarlitskaya allisonkarlitskaya left a comment

Choose a reason for hiding this comment

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

I can't see anything wrong here -- just very minor cosmetic stuff for if you were going to do another round anyway. Maybe @bluca also wants to take a look, though?

src/session/client-certificate.c Outdated Show resolved Hide resolved
src/session/client-certificate.c Outdated Show resolved Hide resolved
src/session/client-certificate.c Show resolved Hide resolved
src/session/client-certificate.c Outdated Show resolved Hide resolved
We are about to make this code more complex, so let's break up the already long
cockpit_session_client_certificate_map_user() function. This is a clean code
move, aside from:

 - renaming `ws_pid_dirfd` to `ws_proc_dirfd` (which is more accurate
   with that new structure)
 - fixing two typos in the comment
 - drop the redundant assert(ucred_len) (already done in the if
   condition, forgotten to be cleaned up when introducing this code)
We don't expect getsockopt() to write more data than we allocated, that
would mess up our stack.
We can get a reliable, PID recycling resistant, /proc query for
cockpit-session's ws peer (i.e. the far end of its stdin Unix socket) by
getting a pidfd instead of an ucred. This is always the pidfd for the
process that started the communication, it cannot be recycled. If the
original process does go away, querying the pidfd will just fail, even
if a new process with the same pid comes along.

We still need to "resolve" the pidfd to a pid to open /proc/pid/cgroup
(there is no direct kernel API to get a pidfd's cgroup). But validate
the pid *after* that query to ensure it didn't get recycled.

This is much easier and safer to do than parsing /proc/pid/stat.
However, this requires kernel 6.5, so is not yet available in e.g.
Debian 12 or RHEL 9. So keep the pid+time comparison fallback for these
older OSes.

Thanks to @bluca for the helpful technical advice!
cockpit-project#16808 (comment)

https://issues.redhat.com/browse/COCKPIT-1207
Copy link
Member

@allisonkarlitskaya allisonkarlitskaya left a comment

Choose a reason for hiding this comment

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

Let's get this merged before I find more trivial things to complain about :)

(pending a review from @bluca, if he's willing)

@martinpitt martinpitt removed the request for review from mvollmer November 27, 2024 14:49
Copy link

@bluca bluca left a comment

Choose a reason for hiding this comment

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

Looks great to me. Would you mind dropping the @ to me in the last commit message, please? I appreciate the effort to give credit, but the PR description is enough - the issue is that every time the commit gets pushed/backported/cherry-picked I'll get an email from Github, and that's a lot of emails :-)

@martinpitt
Copy link
Member Author

@bluca heh, of course. It'd require another force-push/round of CI though. However, we don't actually do that backporting stuff (on almost everything, except very rare security issues), we just keep updating all OSes to the latest upstream version. So you won't get extra noise.

That said, if you still want me to change this, I'll happily do it of course. Thanks again!

@allisonkarlitskaya
Copy link
Member

It'd require another force-push/round of CI though

https://github.com/cockpit-project/bots/blob/main/push-rewrite

@bluca
Copy link

bluca commented Nov 27, 2024

@bluca heh, of course. It'd require another force-push/round of CI though. However, we don't actually do that backporting stuff (on almost everything, except very rare security issues), we just keep updating all OSes to the latest upstream version. So you won't get extra noise.

That said, if you still want me to change this, I'll happily do it of course. Thanks again!

No problem, if it's unlikely to be forked around by users then it's ok to leave it, thanks

@martinpitt martinpitt merged commit 7090fab into cockpit-project:main Nov 27, 2024
82 of 85 checks passed
@martinpitt martinpitt deleted the pidfd branch November 27, 2024 16:55
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.

3 participants