1
0
mirror of https://github.com/projectatomic/bubblewrap.git synced 2026-02-06 00:45:49 +01:00

Allow loading more than one seccomp program

This will allow Flatpak to combine an allow-list (default-deny) of
known system calls with a deny-list (default-allow) of system calls
that are undesired.

Resolves: https://github.com/containers/bubblewrap/issues/453
Signed-off-by: Simon McVittie <smcv@collabora.com>
This commit is contained in:
Simon McVittie
2021-10-12 09:36:58 +01:00
parent c267db3295
commit d625fda8da
2 changed files with 94 additions and 23 deletions

View File

@@ -235,6 +235,50 @@ lock_file_new (const char *path)
return lock;
}
typedef struct _SeccompProgram SeccompProgram;
struct _SeccompProgram
{
struct sock_fprog program;
SeccompProgram *next;
};
DEFINE_LINKED_LIST (SeccompProgram, seccomp_program)
static SeccompProgram *
seccomp_program_new (int *fd)
{
SeccompProgram *self = _seccomp_program_append_new ();
cleanup_free char *data = NULL;
size_t len;
data = load_file_data (*fd, &len);
if (data == NULL)
die_with_error ("Can't read seccomp data");
close (*fd);
*fd = -1;
if (len % 8 != 0)
die ("Invalid seccomp data, must be multiple of 8");
self->program.len = len / 8;
self->program.filter = (struct sock_filter *) steal_pointer (&data);
return self;
}
static void
seccomp_programs_apply (void)
{
SeccompProgram *program;
for (program = seccomp_programs; program != NULL; program = program->next)
{
if (prctl (PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &program->program) != 0)
die_with_error ("prctl(PR_SET_SECCOMP)");
}
}
static void
usage (int ecode, FILE *out)
@@ -285,7 +329,8 @@ usage (int ecode, FILE *out)
" --bind-data FD DEST Copy from FD to file which is bind-mounted on DEST\n"
" --ro-bind-data FD DEST Copy from FD to file which is readonly bind-mounted on DEST\n"
" --symlink SRC DEST Create symlink at DEST with target SRC\n"
" --seccomp FD Load and use seccomp rules from FD\n"
" --seccomp FD Load and use seccomp rules from FD (not repeatable)\n"
" --add-seccomp FD Load and use seccomp rules from FD (repeatable)\n"
" --block-fd FD Block on FD until some data to read is available\n"
" --userns-block-fd FD Block on FD until the user namespace is ready\n"
" --info-fd FD Write information about the running container to FD\n"
@@ -519,7 +564,7 @@ monitor_child (int event_fd, pid_t child_pid, int setup_finished_fd)
* When there are no other processes in the sandbox the wait will return
* ECHILD, and we then exit pid 1 to clean up the sandbox. */
static int
do_init (int event_fd, pid_t initial_pid, struct sock_fprog *seccomp_prog)
do_init (int event_fd, pid_t initial_pid)
{
int initial_exit_status = 1;
LockFile *lock;
@@ -547,9 +592,7 @@ do_init (int event_fd, pid_t initial_pid, struct sock_fprog *seccomp_prog)
/* Optionally bind our lifecycle to that of the caller */
handle_die_with_parent ();
if (seccomp_prog != NULL &&
prctl (PR_SET_SECCOMP, SECCOMP_MODE_FILTER, seccomp_prog) != 0)
die_with_error ("prctl(PR_SET_SECCOMP)");
seccomp_programs_apply ();
while (TRUE)
{
@@ -2091,6 +2134,9 @@ parse_args_recurse (int *argcp,
if (argc < 2)
die ("--seccomp takes an argument");
if (seccomp_programs != NULL)
die ("--seccomp cannot be combined with --add-seccomp-fd");
if (opt_seccomp_fd != -1)
warn_only_last_option ("--seccomp");
@@ -2100,6 +2146,27 @@ parse_args_recurse (int *argcp,
opt_seccomp_fd = the_fd;
argv += 1;
argc -= 1;
}
else if (strcmp (arg, "--add-seccomp-fd") == 0)
{
int the_fd;
char *endptr;
if (argc < 2)
die ("--add-seccomp-fd takes an argument");
if (opt_seccomp_fd != -1)
die ("--add-seccomp-fd cannot be combined with --seccomp");
the_fd = strtol (argv[1], &endptr, 10);
if (argv[1][0] == 0 || endptr[0] != 0 || the_fd < 0)
die ("Invalid fd: %s", argv[1]);
/* takes ownership of fd */
seccomp_program_new (&the_fd);
argv += 1;
argc -= 1;
}
@@ -2485,9 +2552,6 @@ main (int argc,
struct stat sbuf;
uint64_t val;
int res UNUSED;
cleanup_free char *seccomp_data = NULL;
size_t seccomp_len;
struct sock_fprog seccomp_prog;
cleanup_free char *args_data = NULL;
int intermediate_pids_sockets[2] = {-1, -1};
@@ -3051,17 +3115,9 @@ main (int argc,
if (opt_seccomp_fd != -1)
{
seccomp_data = load_file_data (opt_seccomp_fd, &seccomp_len);
if (seccomp_data == NULL)
die_with_error ("Can't read seccomp data");
if (seccomp_len % 8 != 0)
die ("Invalid seccomp data, must be multiple of 8");
seccomp_prog.len = seccomp_len / 8;
seccomp_prog.filter = (struct sock_filter *) seccomp_data;
close (opt_seccomp_fd);
assert (seccomp_programs == NULL);
/* takes ownership of fd */
seccomp_program_new (&opt_seccomp_fd);
}
umask (old_umask);
@@ -3130,7 +3186,7 @@ main (int argc,
fdwalk (proc_fd, close_extra_fds, dont_close);
}
return do_init (event_fd, pid, seccomp_data != NULL ? &seccomp_prog : NULL);
return do_init (event_fd, pid);
}
}
@@ -3158,9 +3214,7 @@ main (int argc,
/* Should be the last thing before execve() so that filters don't
* need to handle anything above */
if (seccomp_data != NULL &&
prctl (PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &seccomp_prog) != 0)
die_with_error ("prctl(PR_SET_SECCOMP)");
seccomp_programs_apply ();
if (setup_finished_pipe[1] != -1)
{

View File

@@ -328,6 +328,23 @@
Load and use seccomp rules from <arg choice="plain">FD</arg>.
The rules need to be in the form of a compiled cBPF program,
as generated by seccomp_export_bpf.
If this option is given more than once, only the last one is used.
Use <option>--add-seccomp-fd</option> if multiple seccomp programs
are needed.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--add-seccomp-fd <arg choice="plain">FD</arg></option></term>
<listitem><para>
Load and use seccomp rules from <arg choice="plain">FD</arg>.
The rules need to be in the form of a compiled cBPF program,
as generated by seccomp_export_bpf.
This option can be repeated, in which case all the seccomp
programs will be loaded in the order given (note that the kernel
will evaluate them in reverse order, so the last program on the
bwrap command-line is evaluated first). All of them, except
possibly the last, must allow use of the PR_SET_SECCOMP prctl.
This option cannot be combined with <option>--seccomp</option>.
</para></listitem>
</varlistentry>
<varlistentry>