Example program:

#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv) {
        char *const args[] = { "Z", NULL, };
        char *const env[] = { NULL, };

        if (argv[0][0] == 'Z') {
                printf("success\n");
                return (0);
        }

        unveil(argv[0], "x");
        pledge("exec", "stdio rpath");
        execve(argv[0], args, env);
}

Expected behavior: execve's itself then prints "success" and exits
Actual behavior: killed by SIGABRT when calling execve. It doesn't seem
to be pledge's usual SIGABRT because nothing gets logged to syslog like
pledge is supposed to do and core isn't dumped

What fixes it:
- execve-ing something other than argv[0]
- unveiling /usr/libexec/ld.so and /usr/lib with "r" permission
(along with the original unveil) before execve. Not unveiling /usr/lib
makes ld.so complain about not finding libc.so
- Removing the pledge or unveil or both
- Setting pledge execpromises to NULL

What doesn't fix it:
- Setting pledge promises to NULL
- Setting every single pledge promise (including "error") for both
of pledge's arguments
- Unveiling everything except /usr/libexec/ld.so with "rwxc" permissions
(Surprisingly ld.so works without /usr/lib this time...)
- execve-ing a symlink (killed with SIGABRT) or a hard link (execve
returns with ENOENT) to the same program
- Checking return codes. None of the functions return errors

Another interesting effect is that removing "rpath" from execpromises
also causes the SIGABRT when execve-ing any program, not just argv[0].
This should really be documented in the pledge manpage!

Reproduced on 6.6-stable and one day old -current on amd64

Reply via email to