OpenBSD - short intro on “execpromises” in the pledge(2)
Hi there,
Today, we will be looking at the update for pledge(2) on OpenBSD and also about howto and usecase.
In the previous post about pledge(2), we understood the implementation and some internal working of pledge(2)
On 11 December 2017, **Theo de Raadt** said:
List: openbsd-tech
Subject: pledge execpromises
From: Theo de Raadt
Date: 2017-12-11 21:20:51
Message-ID: 6735.1513027251 () cvs ! openbsd ! org
This will probably be committed in the next day or so.
The 2nd argument of pledge() becomes execpromises, which is what
will gets activated after execve.
There is also a small new feature called “error”, which causes
violating system calls to return -1 with ENOSYS rather than killing
the process. This must be used with EXTREME CAUTION because libraries
and programs are full of unchecked system calls. If you carry on past
one of these failures, your program is in uncharted territory and
risks of exploitation become high.
“error” is being introduced for a different reason: The pre-exec
process’s expectation of what the post-exec process will do might
mismatch, so “error” allows things like starting an editor which has
no network access or maybe other restrictions in the future...
cvsweb.openbsd.org
OpenBSD 6.2-stable
pledge(2):
#include <unistd.h>
int pledge(const char *promises, const char *paths[]);
updated pledge(2):
#include <unistd.h>
int pledge(const char *promises, const char *execpromises);
the latest update introduces the second parameter for execpromises which are used to provide promises on child process which is invoked using the combination of execve(2) and fork(2)
execve(2):
#include <unistd.h>
int execve(const char *file, char *const argv[], char *const envp[]);
Description of exec-family syscalls:
Like all of the exec functions, execve replaces the calling process image with a new process image. This has the effect of running a new program with the process ID of the calling process. Note that a new process is not started; the new process image simply overlays the original process image. The execve function is most commonly used to overlay a process image that has been created by a call to the fork function.
Return value:
A successful call to execve does not have a return value because the new process image overlays the calling process image. However, a -1 is returned if the call to execve is unsuccessful. consider following example implementation
// cat test_parent1.c
#include <stdio.h>
#include <unistd.h>
int main (int argc, char **argv)
{
if(pledge("stdio exec","stdio rpath") == -1)
{
err(1,"parent pledge");
}
printf ("Parent: Hello, World!\n");
char *arg[] = { "./child", 0, 0, 0 };
execve(arg[0], &arg[0], NULL);
return 0;
}
// cat test_child1.c
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char **argv)
{
printf("child process\n");
while(1) {}
return 0;
}
# gcc -o parent test_parent1.c
# gcc -o child test_child1.c
# ./parent &
[1] 80962
# Parent: Hello, World!
# dmesg|grep 80962
process_name: child pid: 80962 ps_pledge: 9
process_name: child pid: 80962 ps_pledge: 9
As from above code, we have seen that pledge value of the new execve image is 9, that is;
#cat sys/pledge.h
#define PLEDGE_RPATH 0x0000000000000001ULL /* allow open for read */
#define PLEDGE_STDIO 0x0000000000000008ULL /* operate on own pid */
pledge for new execve image:
(RPATH) (STDIO) (NEW PLEDGE)
0x0000000000000001 | 0x0000000000000008 = 0x0000000000000009
So, better to use fork(2) with the combination of execve(2), so that, execve(2) will overlay forked process’s image, not parent’s image
This update on the pledge(2) is one step further towards improving OS security in OpenBSD
If something is missing or not correct, please feel free to update.