Skip to content

PID reuse; confirmation screen confusion #126

@runxiyu

Description

@runxiyu
// peerChain
ucred, err = unix.GetsockoptUcred(int(fd), unix.SOL_SOCKET, unix.SO_PEERCRED)

// procStatus
b, err := os.ReadFile(fmt.Sprintf("/proc/%d/status", pid))

There's a TOCTOU window between GetsockoptUcred and ReadFile where the original process can exit and the PID can be reused.

I thought that pidfd would trivially solve this by holding on to the pidfd, doing a pidfd_getpid, and using /proc. However, holding the pidfd doesn't actually guarantee the does not get reused.

I believe that the race-free option is sort of like this past Linux 6.13, although these need further verification. In pseudo-C-ish (omitting sizeof(info) and such extensibility fields, not real C syntax, but hopefully illustrating the concepts):

  • ioctl(pidfd, PIDFD_GET_INFO, info = &pidfd_info{ .request_mask = PIDFD_INFO_PID })
    pid = info.pid (or replace this step with something like pidfd_getpid)
  • statx(pidfd, "", AT_EMPTY_PATH, STATX_INO, &sx0) /* pidfs inode is never reused */
  • procfs_dirfd = open("/proc/%d", O_PATH | O_DIRECTORY | O_CLOEXEC)
  • v = pidfd_open(pid, 0)
  • statx(v, "", AT_EMPTY_PATH, STATX_INO, &sx1)
  • if (sx0.stx_ino != sx1.stx_ino) error;
  • Then use the procfs_dirfd normally.
    Magic links might ESRCH if the process dies though.

See also https://www.corsix.org/content/what-is-a-pidfd.

Now, I think the more central issue is the framing of the UI/UX itself.

Allow use of key $name?
Key fingerprint $fp.
Requested by ssh (1234) ← gitzshkitty

This reads to a non-expert user as "we have authoritatively identified the application", in a way that any mechanism on the same UNIX user without using containers/namespaces/flatpak/etc, could not support: the comm field is settable by the process itself via prctl, or iirc by writing to /proc/self/comm. I think we need at least something like "Note: any program running as your user can present arbitrary information here."

Note that same-UID Linux has several ways to completely defeat any inter-process introspection scheme:

  • LD_PRELOAD, so checking proc_exe carefully won't work;
  • ptrace can inject arbitrary code
  • pidfd_getfd
  • Some other prctl schenanigans

cc @Foxboron @Mic92

Disclosed publicly with permission

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions