I have thought of a way pledge(2) can be made a little more
library-friendly.

This is not a patch, but just a thought.
There are 2 setups I have thought of:

=============== 1. Variable arguments ===============

int pledge(const char *promises, const char *paths[])
{
        return vpledge(1, promises, paths);
}

int vpledge(const size_t npledge, ...);

-----

In a program, this may be something like this:

#include <stdio.h>
#include <unistd.h>
#include <ultralib.h>
#include <extralib.h>
#include <superlib.h>
#include <mechalib.h>

int main(void) {
        if(vpledge(5, "stdio rpath wpath cpath", NULL,
                ultra_promises, ultra_pledgepaths,
                extra_promises, NULL, super_promises, NULL,
                mecha_promises, mecha_pledgepaths) == -1)
                errx("pledge");

        ... [other code] ...
};


 -------

In vpledge(), "npledge" refers to the number of pledge-pairs, which
consist of:

        const char *promises, const char *paths[]

These have the same semantics as the original pledge().

A library can export *_promises and *_pledgepaths symbols, pointing to
static text. This allows the library to change without the program
being affected because the new library changes call something outside
the original pledge() of a program.

============= 2. Using a struct ==================

-----

struct pledge {
        char *promises;
        char *paths[];
};

-----

int pledge(const char *promises, const char *paths[])
{
        struct pledge pl = {
                .promises, paths
        };

        return pledges(1, &pl);
}

int pledges(const size_t npledge, const struct pledge pledge_array[]);

-----

In a program, this may be something like this:

#include <stdio.h>
#include <unistd.h>
#include <ultralib.h>
#include <extralib.h>
#include <superlib.h>
#include <mechalib.h>

int main(void) {
        struct pledge pl[4];

        pl[0].promises = "stdio rpath wpath cpath";
        ultra_getpledge(&pl[1]);
        extra_getpledge(&pl[2]);
        super_getpledge(&pl[3]);
        mecha_getpledge(&pl[4]);

        if(pledges(5, pl) == -1)
                errx("pledge");

        ... [other code] ...

        
};


 -------


A library can tell the application what pledges are in use as follows:


static const char *pledge_promises = "stdio fattr sendfd recvfd"

void ultra_getpledge(struct pledge *const pl)
{
        pl->promises = pledge_promises;
        pl->paths = NULL;
}


==============

I think that #1 has the advantage of it being easier to code so a
program can ratchet down its abilities. #2 allows one to group the
pledge arguments into a single struct.

Thoughts?

Reply via email to