IshKebab 8 hours ago

The standard Linux process management API is a total mess IMO. It doesn't even offer a way to avoid TOCTOU. They've made some improvements recently (https://lwn.net/Articles/794707/) but as far as I know you still can't implement something like pstree without just reading files from `/proc` which is shit.

  • ijustlovemath an hour ago

    With TOCTOU, the solution is often just to try to use the resource and handle errors, not to assume that since you checked it, it's available.

    • loeg 36 minutes ago

      PID reuse is the classic example here. There is no neat solution other than process handles, which Unix/Linux does not historically have.

  • josephcsible an hour ago

    > It doesn't even offer a way to avoid TOCTOU.

    What do you mean? I admit there are cases where it's hard to avoid TOCTOU, but I can't think of any where it's impossible.

    • IshKebab an hour ago

      For example to kill all of the children of a process you first have to read all of the files in `/proc` to build a process tree, and then send your signals, by which time the process tree may have changed.

  • pjmlp 7 hours ago

    UNIX/POSIX process management.

  • formerly_proven 7 hours ago

    Who needs handles for processes when you can have reusable IDs instead? /s

    For a while the limit has been around 4 million or something like that, instead of the traditional 32k. Which of course broke a bunch of stuff that assumed "char pid[5];" is good enough. Fun stuff.

    The kernel offers up this (here abbreviated) example which you could use for all accesses to /proc/<pid> when you have an open pidfd to ensure that the two refer to the same process:

        static int pidfd_metadata_fd(pid_t pid, int pidfd) {
                char path[100];
                snprintf(path, sizeof(path), "/proc/%d", pid);
                int procfd = open(path, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
                if (sys_pidfd_send_signal(pidfd, 0, NULL, 0) < 0 && errno != EPERM) {
                   close(procfd);
                   procfd = -1;
                }
                return procfd;
        }
    
    And these days you even can poll for pidfds (readable = exited) and you can even use P_PIDFD with waitid. So the very basic process management cycle can be done through pidfds nowadays.

    > as far as I know you still can't implement something like pstree without just reading files from `/proc` which is shit.

    It's also slow! Tools like top/htop/ps -aux etc. use a surprising amount of CPU because they have to do a trillion trips to the kernel and back. Compare this to the win32 equivalent where, iirc, there is just one or two trips to the kernel to acquire a snapshot and you walk that in user-space instead.

    • alexvitkov 6 hours ago

        char path[100];
        snprintf(path, sizeof(path), "/proc/%d", pid);
      
      You're assuming the pid will fit in 93 bytes! The exact same mistake as `char pid[5];`

      Jokes aside, sometimes userspace deserves to be broken, and `char pid[5]` is IMO one of those cases. The fact that we treat integers as a scarce reusable resource is bad, and the fact that we now have a second-order process identifier to cover that up is worse.

      • formerly_proven 44 minutes ago

        Fun fact that broken code was in the runtime used by a major Fortran compiler

usr1106 7 hours ago

Excellent writeup!

Some observations unrelated to the bug.

1. Nice to see some details about the Debian build server implementation. I have always found it rather obscure. Compared to that OpenSUSE's OBS is refreshingly open. Not only can you just use their cloud service for free, but you can also rather easily set up your own instance.

2. Nice to see that the Debian build infra gets updated. I am a bit suprised that Perl code gets introduced in 2024. Isn't that a bit out of fashion for a reason: It's typically very hard to read code written by others. (As said unrelated. It did not cause the bug in TFA.)

rurban 8 hours ago

I had a similar murder mystery investigation the last months, and to rewrite the whole murder concept. But in the end, getting rid of signals (I hate signals ) and replacing it with messages didn't work, so I embraced arranging a proper group and killing them at once. With some exceptions.