LWN: Comments on "process_madvise(), pidfd capabilities, and the revenge of the PIDs" https://lwn.net/Articles/810076/ This is a special feed containing comments posted to the individual LWN article titled "process_madvise(), pidfd capabilities, and the revenge of the PIDs". en-us Mon, 15 Sep 2025 11:53:10 +0000 Mon, 15 Sep 2025 11:53:10 +0000 https://www.rssboard.org/rss-specification lwn@lwn.net process_madvise(), pidfd capabilities, and the revenge of the PIDs https://lwn.net/Articles/811405/ https://lwn.net/Articles/811405/ nix <div class="FormattedComment"> This is a very silly argument, though. You can easily wrap the pidfd_open/pidfd-operation/_close in a function, and as for CPU time wastage -- two transitions to kernel space will likely be utterly minor compared to the large number of transitions that almost all pidfd operations are likely to incur; and if they only incur one, then the tripling of CPU time is *still* utterly irrelevant unless they're being called on literally millions of processes -- in which case one must wonder what on earth they are doing, and whether they should be using some other mechanism based around pgids or cgroups or something so they don't have to do something so ridiculously inefficient as calling *any* one syscall millions of times on millions of foreign processes.<br> </div> Mon, 03 Feb 2020 20:56:18 +0000 process_madvise(), pidfd capabilities, and the revenge of the PIDs https://lwn.net/Articles/810410/ https://lwn.net/Articles/810410/ NYKevin <p>It was mostly a tongue-in-cheek suggestion, and I'm pretty sure actually doing this would be a Bad Idea. But if you really wanted to do it, you could probably use the signals API to deal with those issues. That is: <ol> <li>Create a new SIGFOO value, and make all of the sigaction() et al. functions accept it. <li>Whenever someone calls process_syscall(), the target process receives a SIGFOO. <li>The default behavior of the SIGFOO is to call syscall(...) as if from a signal handler. <li>If the signal is masked, handled, or ignored, it behaves as you would expect (syscall() is not invoked). <li>(Optional) Masking, handling, or ignoring the signal requires a capability and/or UID=0, so that containers cannot veto the actions of their supervisors. Alternatively, it can't be masked, handled, or ignored at all, so that it behaves like SIGSTOP and SIGKILL. </ol> Thu, 23 Jan 2020 19:03:22 +0000 “which”? https://lwn.net/Articles/810305/ https://lwn.net/Articles/810305/ mirabilos <div class="FormattedComment"> No, why?<br> <p> It’s really common practice to do things this way (maybe you don’t know this as you seem to be a C++ programmer, but in the C/UNIX world, we do).<br> <p> Take, for example, mmap, when called with MAP_ANONYMOUS in flags, ignores the fd argument instead of checking it.<br> </div> Wed, 22 Jan 2020 17:19:50 +0000 “which”? https://lwn.net/Articles/810303/ https://lwn.net/Articles/810303/ james Perhaps the call should return an error if the pid is non-zero and pidfd isn't -1. Wed, 22 Jan 2020 16:59:01 +0000 “which”? https://lwn.net/Articles/810250/ https://lwn.net/Articles/810250/ mirabilos <div class="FormattedComment"> <font class="QuotedText">&gt; the pidfd variable</font><br> <p> No, there’s no extra variable, this is just a parameter.<br> <p> You’d either call it with…<br> <p> process_madvise(pidfd, /* ignored */ 0, …)<br> <p> … or with…<br> <p> process_madvise(-1, pid, …)<br> <p> … so this question never comes up.<br> <p> <p> <font class="QuotedText">&gt; bugs where both the pidfd and pid would be set</font><br> <p> This is a very common interface, and the answer is trivial, as I stated in the comment above: pid is used iff pidfd == -1 (meaning if it’s not -1, pid will be ignored). This is a basic standard technique.<br> </div> Wed, 22 Jan 2020 15:20:40 +0000 “which”? https://lwn.net/Articles/810243/ https://lwn.net/Articles/810243/ NAR <div class="FormattedComment"> That could be confusing - the pidfd variable would be used not only to store a pidfd, but to select which interface is called. Also, this interface would invite bugs where both the pidfd and pid would be set, maybe even to different processes. Documentation could make it explicit, however, programmers have the habit to not read the documentation and write code based on assumption created by reading the API.<br> <p> My idea was to use the flags argument to select between pid and pidfd - but I guess that flag should be the same as accepted by madvise. If only C had function overloading... But it doesn't so maybe bite the bullet and create two functions: madvise_by_pid and madvise_by_pidfd.<br> </div> Wed, 22 Jan 2020 12:37:43 +0000 process_madvise(), pidfd capabilities, and the revenge of the PIDs https://lwn.net/Articles/810234/ https://lwn.net/Articles/810234/ cyphar <div class="FormattedComment"> Sure, waitid(2) obviously wasn't written with pidfds in mind and adding them later was to avoid making a new syscall -- my point was that the resulting interface is identical to the one being proposed (even the proposed constants -- P_PID and P_PIDFD -- are the same):<br> <p> int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);<br> <p> vs<br> <p> int process_madvise(int which, pid_t pid, void *addr, size_t length, int advice, unsigned long flag);<br> <p> Where @which is equivalent to @idtype. Thus, it is arguably only as ugly as the waitid(2) interface. Also, they didn't re-use a flag argument -- waitid(2) explicitly had "type switching" from the outset (though it was intended to be used to differentiate between process groups and PIDs).<br> </div> Wed, 22 Jan 2020 06:46:52 +0000 process_madvise(), pidfd capabilities, and the revenge of the PIDs https://lwn.net/Articles/810233/ https://lwn.net/Articles/810233/ cyphar <div class="FormattedComment"> That already exists with the pidfd_open(2) syscall, the concern is that it's needless overhead (and a meaningless gesture) for userspace to have to create a pidfd if they are just going to use it as though it were a PID (with all of the issues related to it). That's what Kirill Tkhai was referring to when they wrote:<br> <p> <font class="QuotedText">&gt; In this moment the tracer knows everything about tracee state, and pidfd brackets pidfd_open() and close() around actual action look just stupid, and this is cpu time wasting.</font><br> </div> Wed, 22 Jan 2020 06:41:06 +0000 process_madvise(), pidfd capabilities, and the revenge of the PIDs https://lwn.net/Articles/810225/ https://lwn.net/Articles/810225/ roc <div class="FormattedComment"> The current ptrace code is designed around that relationship, and I assume that any significant changes to ptrace code are going to be hard. I'd love to be wrong!<br> </div> Wed, 22 Jan 2020 02:44:09 +0000 process_madvise(), pidfd capabilities, and the revenge of the PIDs https://lwn.net/Articles/810224/ https://lwn.net/Articles/810224/ roc <div class="FormattedComment"> There are many states that thread could be in that would be problematic. Most of the time the thread would be blocked in the kernel for some reason, in which case you'd want to queue the syscall for execution when it would next return to userspace, but that might never happen.<br> </div> Wed, 22 Jan 2020 02:42:51 +0000 process_madvise(), pidfd capabilities, and the revenge of the PIDs https://lwn.net/Articles/810216/ https://lwn.net/Articles/810216/ KaiRo <div class="FormattedComment"> I have no clue about kernel-level coding, but why not have a function like pidfd_from_pid(pid) that would create/take a pidfd for a given pid (with all the ambivalence a pid has) and which you then hand over to new calls that only support a pidfd? From the command line that should be fine and other code should see to convert to pidfd in the longer run anyhow.<br> </div> Wed, 22 Jan 2020 01:25:32 +0000 process_madvise(), pidfd capabilities, and the revenge of the PIDs https://lwn.net/Articles/810207/ https://lwn.net/Articles/810207/ Paf <div class="FormattedComment"> Why do you think breaking the ptrace parent relationship would be so hard?<br> <p> I’m not really familiar with that part of ptrace, but I have had to look at the signal handling dance and it is a *mess*. (Not incorrect in any way, just... messy)<br> </div> Tue, 21 Jan 2020 22:52:58 +0000 process_madvise(), pidfd capabilities, and the revenge of the PIDs https://lwn.net/Articles/810205/ https://lwn.net/Articles/810205/ Paf <div class="FormattedComment"> That’s an interesting point about the PID uncertainty for those programs, thanks. Though at the same time, the pidfd isn’t any *worse* than the questionable pid... hmm.<br> <p> This might be a situation where the kernel commitment to backwards compatibility implicitly pushes a less elegant interface. (I say implicitly because there is no explicit backwards compatibility issue here, but I think the philosophy arguably applies because not having both PIDs and pidfds implicitly pushes people to the new interface.)<br> <p> Hmm.<br> </div> Tue, 21 Jan 2020 22:49:50 +0000 process_madvise(), pidfd capabilities, and the revenge of the PIDs https://lwn.net/Articles/810196/ https://lwn.net/Articles/810196/ NYKevin <p>Well... you *could* have something like this: <pre> long process_syscall(int pidfd, long number, ...) </pre> <p>It would behave as-if <tt>process</tt> had invoked <tt>syscall(2)</tt> with the remaining arguments. Maybe you also whitelist <tt>number</tt> to syscalls that actually make sense to invoke remotely, and are unlikely to cause massive reentrancy or threading issues. Tue, 21 Jan 2020 21:17:51 +0000 “which”? https://lwn.net/Articles/810195/ https://lwn.net/Articles/810195/ mirabilos <div class="FormattedComment"> This breaks types, though.<br> <p> “which” is an int, sure, but the PID is of type pid_t, while pidfds as file descriptors are of type int.<br> <p> I’d rather have it…<br> <p> int process_madvise(int pidfd, pid_t pid, …<br> <p> … and use “pid” iff pidfd == -1 (which is the usual closed/invalid fd number).<br> </div> Tue, 21 Jan 2020 21:12:49 +0000 process_madvise(), pidfd capabilities, and the revenge of the PIDs https://lwn.net/Articles/810193/ https://lwn.net/Articles/810193/ roc <div class="FormattedComment"> I think pidfds for ptrace() would be good, but I don't think they immediately solve the major issues with ptrace.<br> <p> I would really like the ability to hand-off ptrace control to other processes by passing them a pidfd, but that would require lots more work. Something like:<br> * Make sure pidfd_wait or whatever can read the special ptrace status events.<br> * When pidfds are used, break the "ptrace parent" relationship in the kernel so *any* process with a pidfd for the tracee can ptrace() it or get the ptrace status events. (I bet this is *really* hard.)<br> But it would make much-requested rr features, like the ability to start debugging an in-progress rr recording without interrupting it, much more tractable.<br> </div> Tue, 21 Jan 2020 19:58:24 +0000 process_madvise(), pidfd capabilities, and the revenge of the PIDs https://lwn.net/Articles/810192/ https://lwn.net/Articles/810192/ roc <div class="FormattedComment"> Maybe hack pidfds into ptrace and other syscalls by passing "-pidfd" as the pid?<br> </div> Tue, 21 Jan 2020 19:52:10 +0000 process_madvise(), pidfd capabilities, and the revenge of the PIDs https://lwn.net/Articles/810190/ https://lwn.net/Articles/810190/ rvolgers <div class="FormattedComment"> If ever there was a good use case for pidfd's it's ptrace. That is one ugly interface, with all the signal magic and pseudo-reparenting.<br> <p> Of course, porting it would take quite a lot of effort probably, nevermind deprecating the old interface so all the cruft can be removed, but one can dream.<br> </div> Tue, 21 Jan 2020 19:32:55 +0000 process_madvise(), pidfd capabilities, and the revenge of the PIDs https://lwn.net/Articles/810176/ https://lwn.net/Articles/810176/ josh <div class="FormattedComment"> waitid has a flag to avoid having to create a new version of the syscall. It already accepted flags, so adding a flag to accept a pidfd in place of the existing pid argument made some sense.<br> </div> Tue, 21 Jan 2020 17:35:12 +0000 process_madvise(), pidfd capabilities, and the revenge of the PIDs https://lwn.net/Articles/810159/ https://lwn.net/Articles/810159/ cyphar <div class="FormattedComment"> <font class="QuotedText">&gt; In this moment the tracer knows everything about tracee state, and pidfd brackets pidfd_open() and close() around actual action look just stupid, and this is cpu time wasting. </font><br> <p> While I do understand wanting to maintain support for PIDs in newer syscalls (after all, in some cases you only get a PID from a user or other program), I don't think that a tracer program would be written in the way described. It's far more likely that the tracer would already have a pidfd open for each process it is tracing. But then again, since ptrace (and ptrace-related syscalls) doesn't use pidfds, it would also be fair to say that the interface mismatch would make the code ugly no matter what.<br> </div> Tue, 21 Jan 2020 15:50:15 +0000 process_madvise(), pidfd capabilities, and the revenge of the PIDs https://lwn.net/Articles/810127/ https://lwn.net/Articles/810127/ cyphar <div class="FormattedComment"> The counter-argument is waitid(2), which has basically the exact same interface.<br> <p> Additionally, doing the switching in user-space isn't all that fun. The syscall has to take pidfds, otherwise there's no point to permitting pidfds to be used with the interface (getting the pid of a pidfd is painful, but it also immediately becomes susceptible to pid recycling attacks -- the thing pidfds were meant to block). And that would annoy the people who are unhappy with requiring pidfds for new syscalls (they don't want to take up file handles, and it's likely that for their programs creating the pidfd is a meaningless gesture because they have no way of actually being sure the pid is correct).<br> </div> Tue, 21 Jan 2020 15:45:33 +0000 process_madvise(), pidfd capabilities, and the revenge of the PIDs https://lwn.net/Articles/810126/ https://lwn.net/Articles/810126/ dskoll <p>Hah! I have never programmed on Windows and know nothing about its API, and feel a little ashamed for having rediscovered that. :) <p>Thanks for the info. Tue, 21 Jan 2020 14:46:06 +0000 process_madvise(), pidfd capabilities, and the revenge of the PIDs https://lwn.net/Articles/810122/ https://lwn.net/Articles/810122/ Paf <div class="FormattedComment"> I am very curious to see how this gets worked out, my instinct is that the desire for the switchable interface implemented in the calls is deeply silly. Unless there are significant performance or other (security?) implications, this desire for an alternate interface should be solved with wrappers and/or macros, not have a switching argument baked in to the basic call.<br> <p> That is to say, there’s nothing silly about wanting both interfaces, but having a “what is this other argument” switch argument in the call, when not strictly necessary, seems... yuck? Perhaps opinions differ :)<br> </div> Tue, 21 Jan 2020 14:28:20 +0000 process_madvise(), pidfd capabilities, and the revenge of the PIDs https://lwn.net/Articles/810119/ https://lwn.net/Articles/810119/ rvolgers <div class="FormattedComment"> Or, as windows calls it, CreateRemoteThreadEx.<br> </div> Tue, 21 Jan 2020 13:26:26 +0000 process_madvise(), pidfd capabilities, and the revenge of the PIDs https://lwn.net/Articles/810117/ https://lwn.net/Articles/810117/ dskoll <p>Why not take this to its logical extreme? <P><TT>execute_as_process(int pidfd, void (*func)());</TT> <P>I am of course not completely serious and realize the difficulty of implementing this as well as the security implications, but it seems we are approaching this asymptotically. Tue, 21 Jan 2020 12:29:15 +0000