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.