LKML Archive on
help / color / mirror / Atom feed
From: "Jason A. Donenfeld" <>
To: Kernel Hardening <>,
	Andy Lutomirski <>
Cc: LKML <>, Jann Horn <>,
	Christian Brauner <>
Subject: forkat(int pidfd), execveat(int pidfd), other awful things?
Date: Mon, 1 Feb 2021 18:47:17 +0100	[thread overview]
Message-ID: <> (raw)

Hi Andy & others,

I was reversing some NT stuff recently and marveling over how wild and
crazy things are over in Windows-land. A few things related to process
creation caught my interest:

- It's possible to create a new process with an *arbitrary parent
process*, which means it'll then inherit various things like handles
and security attributes and tokens from that new parent process.

- It's possible to create a new process with the memory space handle
of a different process. Consider this on Linux, and you have some
abomination like `forkat(int pidfd)`.

The big question is "why!?" At first I was just amused by its presence
in NT. Everything is an object and you can usually freely mix and
match things, and it's very flexible, which is cool. But this is NT,
not Linux.

Jann and I were discussing, though, that maybe some variant of these
features might be useful to get rid of setuid executables. Imagine
something like `systemd-sudod`, forked off of PID 1 very early.
Subsequently all new processes on the system run with
PR_SET_NO_NEW_PRIVS or similar policies to prevent non-root->root
transition. Then, if you want to transition, you ask systemd-sudod (or
polkitd, or whatever else you have in mind) to make you a new process,
and it then does the various policy checks, and executes a new process
for you as the parent of the requesting process.

So how would that work? Well, executing processes with arbitrary
parents would be part of it, as above. But we'd probably want to more
carefully control that new process. Which chroot is it in? How do
cgroups work? And so on. And ultimately this design leads to something
like ZwCreateProcess, where you have several arguments, each to a
handle to some part of the new process state, or null to be inherited
from its parent.

int execve_parent(int parent_pidfd, int root_dirfd, int cgroup_fd, int
namespace_fd, const char *pathname, char *const argv[], char *const

One could imagine this growing pretty unwieldy. There's also this
other design aspect of Linux that's worth considering. Namespaces and
other process-inherited resources are generally hierarchical, with
children getting the resource from their parent. This makes sense and
is simple to conceptualize. Everytime we add a new thing_fd as a
pointer to one of these resources, and allow it to be used outside of
that hierarchy, it introduces a kind of "escape hatch". That might be
considered "bad design" by some; it might not be by others. Seen this
way, NT is one massive escape hatch, with pretty much everything being
an object with a handle.

But! Maybe this is nonetheless an interesting design avenue to
explore. The introduction of pidfd is sort of just the "beginning" of
that kind of design.

Is any of this interesting to you as a future of privilege escalation
and management on Linux?


             reply	other threads:[~2021-02-01 17:55 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-02-01 17:47 Jason A. Donenfeld [this message]
2021-02-01 17:51 ` Jason A. Donenfeld
2021-02-01 18:20 ` Christian Brauner
2021-02-01 18:29 ` Andy Lutomirski
2021-02-02  9:23   ` David Laight
2021-07-28 16:37     ` Leveraging pidfs for process creation without fork John Cotton Ericson
2021-07-29 14:24       ` Christian Brauner
2021-07-29 14:54         ` John Ericson
2021-07-30  1:41         ` Al Viro
     [not found]           ` <>
2021-07-31 22:42             ` Al Viro
2021-08-02 12:19               ` Christian Brauner
2021-08-03  6:00                 ` John Cotton Ericson
2021-02-01 18:32 ` forkat(int pidfd), execveat(int pidfd), other awful things? Casey Schaufler

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='' \ \ \ \ \ \ \
    --subject='Re: forkat(int pidfd), execveat(int pidfd), other awful things?' \

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).