Re: Why can I waitpid() but can't EVFILT_PROC under pledge("proc")

2017-01-05 Thread Theo de Raadt
>You could possibly make a separate "event" or "wait" pledge to register new
>events or NOTE_EXIT calls, but I suspect that that would complicate things,
>making the large presumption that that could be desired.

Why would we do that?

We've not seen any source code which requires what you propose.

Please isn't support to adapt to odd-ball software; odd-ball software
should adapt to pledge.  Usually that suggests a move towards privsep.



Re: Why can I waitpid() but can't EVFILT_PROC under pledge("proc")

2017-01-05 Thread Luke Small
You could possibly make a separate "event" or "wait" pledge to register new
events or NOTE_EXIT calls, but I suspect that that would complicate things,
making the large presumption that that could be desired.

On Thu, Jan 5, 2017, 15:42 Theo de Raadt  wrote:

> > I imagine that the mitigation that is sought by pledge is to minimize
> > aberrent code reuse in whatever way a hacker can make code run again in a
> > way that it isn't supposed to. And maybe the programmer can choose what
> can
> > be problematic and what isn't if it runs again with their choice of the
> > calls. What problem could occur that EVFILT_PROC with NOTE_EXIT (as
> opposed
> > to EVFILT_PROC with maybe other fflags) could make that couldn't occur by
> > trying to put a kevent on a file descriptor. Is "abusively" monitoring a
> > process a security hole?
>
> You want to avoid using pledge "proc" in your own code; you want
> EVFILT_PROC to just work.  I guess you wish that EVFILT_PROC was
> always enabled, inside the pledge "stdio" environment, since you
> haven't described another proposal for what would toggle access.
>
> But that means you don't care about everyone else's code, in
> particular the whole base system.  1000+ code-chunks in the tree use
> "stdio" (or something else slightly more) for normal operation, but
> don't need or want EVFILT_PROC access as a matter of course.
>
> So you think those 1000+ code-chunks should gain EVFILT_PROC ability,
> because it is convenient for your code.  Result is if any of those
> code-chunks has a buffer overflow or means for code execution
> achievement, then it can observe all processes in the system.
>
> Basically, you desire that all pledge "stdio" processes can scan for
> the existance of all pid's by doing EVFILT_PROC attempts.  YES, that
> is exactly what you want, I am not mincing words!  Basically you want
> to undo the annotation/safety of pledge, because you haven't thought
> things through.
>
> Like, you'd be OK if a bug in the sshd pre-auth sandbox allowed such an
> operation?
>
> > If it is, shouldn't a task manager be run as root to see when a root
> > process dies?
>
> That has nothing to do with pledge.  If you want to ask an entirely
> seperate question, ask it in a seperate email.



Re: Why can I waitpid() but can't EVFILT_PROC under pledge("proc")

2017-01-05 Thread Theo de Raadt
> I should also clarify a bit. wait() only works for processes you've created
> with fork(), which requires "proc". There's good reason to allow you to watch
> for a child's exit much later, but without the ability to fork again.

that's right.

during development of pledge, we found many instances where a parent
creates a child, then both of them pledge narrowly.  Imagine the
parent goes to "stdio", but still wants to observe termination of the
child, and perform some very small action afterwards.  It is a common
pattern, so waitpid(2) is serviced normally in "stdio".

> Also, kevent allows exactly this setup with the same set of pledges. After
> calling fork() is when you attach the kevent for the child. Then you drop
> "proc" and can continue to receive notifications about child exits.
> 
> Using kevent() in the same way as wait() requires exactly the same pledge.

Only a subset of kqueue/kevent behaviours are allowed in "stdio" --
basically the poll/select equivelant behaviours exposed by libevent.
That kind of thing occurs in around 60 base programs (sometimes in
2-3x seperate event loops due to privsep, sometimes done by hand rather
than using libevent).

In the future if we encounter risky behaviours of kqueue/kevent which
are not critical for "stdio" programs, they may also get blocked.



Re: Why can I waitpid() but can't EVFILT_PROC under pledge("proc")

2017-01-05 Thread Theo de Raadt
> I imagine that the mitigation that is sought by pledge is to minimize
> aberrent code reuse in whatever way a hacker can make code run again in a
> way that it isn't supposed to. And maybe the programmer can choose what can
> be problematic and what isn't if it runs again with their choice of the
> calls. What problem could occur that EVFILT_PROC with NOTE_EXIT (as opposed
> to EVFILT_PROC with maybe other fflags) could make that couldn't occur by
> trying to put a kevent on a file descriptor. Is "abusively" monitoring a
> process a security hole?

You want to avoid using pledge "proc" in your own code; you want
EVFILT_PROC to just work.  I guess you wish that EVFILT_PROC was
always enabled, inside the pledge "stdio" environment, since you
haven't described another proposal for what would toggle access.

But that means you don't care about everyone else's code, in
particular the whole base system.  1000+ code-chunks in the tree use
"stdio" (or something else slightly more) for normal operation, but
don't need or want EVFILT_PROC access as a matter of course.

So you think those 1000+ code-chunks should gain EVFILT_PROC ability,
because it is convenient for your code.  Result is if any of those
code-chunks has a buffer overflow or means for code execution
achievement, then it can observe all processes in the system.

Basically, you desire that all pledge "stdio" processes can scan for
the existance of all pid's by doing EVFILT_PROC attempts.  YES, that
is exactly what you want, I am not mincing words!  Basically you want
to undo the annotation/safety of pledge, because you haven't thought
things through.

Like, you'd be OK if a bug in the sshd pre-auth sandbox allowed such an
operation?

> If it is, shouldn't a task manager be run as root to see when a root
> process dies?

That has nothing to do with pledge.  If you want to ask an entirely
seperate question, ask it in a seperate email.



Re: Why can I waitpid() but can't EVFILT_PROC under pledge("proc")

2017-01-05 Thread Luke Small
Registering a EVFILT_PROC, NOTE_EXIT kevent requires proc

On Thu, Jan 5, 2017, 15:25 Ted Unangst  wrote:

> Theo de Raadt wrote:
> > > Luke Small wrote:
> > > > What if I want to prevent a process from forking while I want to
> create new
> > > > EVFILT_PROC events? Say, to accept the pid of a sibling fork from a
> pipe
> > > > and load it into a kqueue. Is there a reason why waitpid() isn't
> beholden
> > > > to this, or is there a reason that EVFILT_PROC is?
> > >
> > > wait() is a less powerful syscall than kevent().
> >
> > indeed, EVFILT_PROC lets you observe processes other than your own
> > children.
> >
> > that way far outside "stdio", you are reasoning about processes in
> general,
> > so of course you need pledge "proc".
>
> I should also clarify a bit. wait() only works for processes you've created
> with fork(), which requires "proc". There's good reason to allow you to
> watch
> for a child's exit much later, but without the ability to fork again.
>
> Also, kevent allows exactly this setup with the same set of pledges. After
> calling fork() is when you attach the kevent for the child. Then you drop
> "proc" and can continue to receive notifications about child exits.
>
> Using kevent() in the same way as wait() requires exactly the same pledge.



Re: Why can I waitpid() but can't EVFILT_PROC under pledge("proc")

2017-01-05 Thread Ted Unangst
Theo de Raadt wrote:
> > Luke Small wrote:
> > > What if I want to prevent a process from forking while I want to create 
> > > new
> > > EVFILT_PROC events? Say, to accept the pid of a sibling fork from a pipe
> > > and load it into a kqueue. Is there a reason why waitpid() isn't beholden
> > > to this, or is there a reason that EVFILT_PROC is?
> > 
> > wait() is a less powerful syscall than kevent().
> 
> indeed, EVFILT_PROC lets you observe processes other than your own
> children.
> 
> that way far outside "stdio", you are reasoning about processes in general,
> so of course you need pledge "proc".

I should also clarify a bit. wait() only works for processes you've created
with fork(), which requires "proc". There's good reason to allow you to watch
for a child's exit much later, but without the ability to fork again.

Also, kevent allows exactly this setup with the same set of pledges. After
calling fork() is when you attach the kevent for the child. Then you drop
"proc" and can continue to receive notifications about child exits.

Using kevent() in the same way as wait() requires exactly the same pledge.



Re: Why can I waitpid() but can't EVFILT_PROC under pledge("proc")

2017-01-05 Thread Luke Small
I imagine that the mitigation that is sought by pledge is to minimize
aberrent code reuse in whatever way a hacker can make code run again in a
way that it isn't supposed to. And maybe the programmer can choose what can
be problematic and what isn't if it runs again with their choice of the
calls. What problem could occur that EVFILT_PROC with NOTE_EXIT (as opposed
to EVFILT_PROC with maybe other fflags) could make that couldn't occur by
trying to put a kevent on a file descriptor. Is "abusively" monitoring a
process a security hole? If it is, shouldn't a task manager be run as root
to see when a root process dies? It would be difficult enough to discover a
pid when you aren't supposed to since they probably wouldn't be stored
unless they are going to be used. waitpid(pid, &status, WNOHANG); in a loop
could do the same thing as that, but would be uglier to implement. I
suppose it may be difficult to turn back now after pledging so much in a
certain way.

On Thu, Jan 5, 2017, 14:41 Ted Unangst  wrote:

Luke Small wrote:
> What if I want to prevent a process from forking while I want to create
new
> EVFILT_PROC events? Say, to accept the pid of a sibling fork from a pipe
> and load it into a kqueue. Is there a reason why waitpid() isn't beholden
> to this, or is there a reason that EVFILT_PROC is?

wait() is a less powerful syscall than kevent().



Re: Why can I waitpid() but can't EVFILT_PROC under pledge("proc")

2017-01-05 Thread Theo de Raadt
> Luke Small wrote:
> > What if I want to prevent a process from forking while I want to create new
> > EVFILT_PROC events? Say, to accept the pid of a sibling fork from a pipe
> > and load it into a kqueue. Is there a reason why waitpid() isn't beholden
> > to this, or is there a reason that EVFILT_PROC is?
> 
> wait() is a less powerful syscall than kevent().

indeed, EVFILT_PROC lets you observe processes other than your own
children.

that way far outside "stdio", you are reasoning about processes in general,
so of course you need pledge "proc".



Re: Why can I waitpid() but can't EVFILT_PROC under pledge("proc")

2017-01-05 Thread Ted Unangst
Luke Small wrote:
> What if I want to prevent a process from forking while I want to create new
> EVFILT_PROC events? Say, to accept the pid of a sibling fork from a pipe
> and load it into a kqueue. Is there a reason why waitpid() isn't beholden
> to this, or is there a reason that EVFILT_PROC is?

wait() is a less powerful syscall than kevent().



Re: Why can I waitpid() but can't EVFILT_PROC under pledge("proc")

2017-01-05 Thread Theo de Raadt
> What if I want to prevent a process from forking while I want to create new
> EVFILT_PROC events? Say, to accept the pid of a sibling fork from a pipe
> and load it into a kqueue. Is there a reason why waitpid() isn't beholden
> to this, or is there a reason that EVFILT_PROC is?

Your usage case doesn't seem like boring normal code.

pledge is designed to serve two goals:

(1) encourage refactoring towards safer models

(2) reduce code exposure to the kernel

The pledge you are talking about is called "proc" rather than "fork"
for a reason -- it annotates code that attempts to reason about
process-trees as much as possible.  I can't specifically say what
reasoning about a process means, but a reasonable edge was chosen to
allow code to work.  Pledge contains a few cases where further
syscalls are allowed because too much existing code uses it;
similarily other syscalls contain narrow checks internally as you just
discovered because a feature wasn't found neccessary.  waitpid was
left in "stdio" because we found too much needing to be syncronously
aware of sub-process termination; we also found found which used
SIGCHLD and waitpid, but we found none using this non-POSIX kqueue
extension in this manner.

It is too complicated to explain all these details in the manual page.
Also strict explanation would be a trap for program developers and
kernel developers in the future.  The manual page is EXPLICITLY vague
as a result.  Actually, I forced the removal of information that was
too detailed.

If you can't make pledge work in a certain way, don't use it.  Or
refactor your program to not rely on the narrowest extensions you
find.

Oh and you want a final answer?  If we allow EVFILT_PROC to work in
"stdio", then around 200 programs suddenly can flow through that kernel
code path.  See point (2) above.



Why can I waitpid() but can't EVFILT_PROC under pledge("proc")

2017-01-05 Thread Luke Small
What if I want to prevent a process from forking while I want to create new
EVFILT_PROC events? Say, to accept the pid of a sibling fork from a pipe
and load it into a kqueue. Is there a reason why waitpid() isn't beholden
to this, or is there a reason that EVFILT_PROC is?