Hacker News new | ask | show | jobs
by sdkmvx 3723 days ago
That won't work because exec resets pledge.

A very important part of pledge's design is that a parent can be more restricted than its child. This isn't a sandboxing mechanism. It's intended to mitigate the dangers of some other vulnerability leading to remote code execution. With pledge, even if you get into the system you may not be able to make all the syscalls you need.

2 comments

> A very important part of pledge's design is that a parent can be more restricted than its child. This isn't a sandboxing mechanism. It's intended to mitigate the dangers of some other vulnerability leading to remote code execution. With pledge, even if you get into the system you may not be able to make all the syscalls you need.

ISTM this will just slightly raise the bar so that attackers who get code execution have to force a call to execve.

On the other hand, it avoids needing to worry about all the setuid issues that Linux's seccomp avoids using PR_SET_NO_NEW_PRIVS.

> ISTM this will just slightly raise the bar so that attackers who get code execution have to force a call to execve.

If the program did not pledge 'exec', then calling execve() will cause the program to be killed. Lots of programs don't need exec, so don't pledge it.

It is indeed another security mitigation, any potential attack payload will need to do more work and hence require more code.

In fact, most programs will not need the exec promise in which case any attempt to call execv(3)..

Abort trap (core dumped)

If you think about the semantics of execv(3), it needs a path to an existing executable. So an attacker will need to know of one in advance, or write one out to disk beforehand.. oh but--

Abort trap (core dumped)

The exploited process pledged "stdio rpath proc exec" and cannot write to arbitrary files. Hmm. Bummer.

> If you think about the semantics of execv(3), it needs a path to an existing executable. So an attacker will need to know of one in advance, or write one out to disk beforehand.. oh but--

/bin/sh, perhaps? It's harder to pass in machine code, but I bet there's a way. /bin/sh -c "echo -e shellcode_here >/tmp/foo; chmod 700 /tmp/foo; /tmp/foo" seems plausible to me.

Well, binary shellcode often has the sole purpose of providing shell access, so if you can just exec /bin/sh then that job is already done...
You're right, of course. If you promise exec, you should certainly expect someone will find a way to use it.
> this will just slightly raise the bar so that attackers who get code execution have to force a call to execve

In most cases your program doesn't need execve, so it can call pledge without "exec" promise.

Sometimes you will still be able to open some shell script and add your commands there or something like this, but without "wpath" promise it is impossible.

> exec resets pledge

Source? I didn't see that in the man page.

From the manpage:

> exec: Allows a process to call execve(2). Coupled with the proc promise, this allows a process to fork and execute another program. The new program starts running without pledge active and hopefully makes a new pledge().

That's not clear, though. "The new program" it talks about is after running fork and exec, not just exec. It doesn't specify which call resets the pledge.
From the quoted text I'd understand it's the `exec` that resets the pledge.
I installed OpenBSD so I could check this out. tl;dr, you were right.

    $ cat testpledge.c
    #include <unistd.h>
    #include <stdio.h>
    int main()
    {
      pledge("proc exec", NULL);
      execl("/bin/echo", "echo", "asdf", NULL);
      _exit(0);
    }
    $ cc testpledge.c
    $ ./a.out
    asdf
After fork, the original program is still running. The text specifically refers to the proc promise, which allows fork. It may be tersely formulated, but I really don't see how you could interpret this text otherwise.