mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-23 17:34:00 +03:00
Merge pull request #6798 from poettering/nspawn-seccomp
nspawn seccomp improvements
This commit is contained in:
commit
44a51139b9
@ -713,6 +713,23 @@
|
|||||||
above).</para></listitem>
|
above).</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--system-call-filter=</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Alter the system call filter applied to containers. Takes a space-separated list of system call
|
||||||
|
names or group names (the latter prefixed with <literal>@</literal>, as listed by the
|
||||||
|
<command>syscall-filter</command> command of <citerefentry
|
||||||
|
project='man-pages'><refentrytitle>systemd-analyze</refentrytitle><manvolnum>1</manvolnum></citerefentry>). Passed
|
||||||
|
system calls will be permitted. The list may optionally be prefixed by <literal>~</literal>, in which case all
|
||||||
|
listed system calls are prohibited. If this command line option is used multiple times the configured lists are
|
||||||
|
combined. If both a positive and a negative list (that is one system call list without and one with the
|
||||||
|
<literal>~</literal> prefix) are configured, the positive list takes precedence over the negative list. Note
|
||||||
|
that <command>systemd-nspawn</command> always implements a system call blacklist (as opposed to a whitelist),
|
||||||
|
and this command line option hence adds or removes entries from the default blacklist, depending on the
|
||||||
|
<literal>~</literal> prefix. Note that the applied system call filter is also altered implicitly if additional
|
||||||
|
capabilities are passed using the <command>--capabilities=</command>.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--kill-signal=</option></term>
|
<term><option>--kill-signal=</option></term>
|
||||||
|
|
||||||
|
@ -274,11 +274,21 @@
|
|||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>NotifyReady=</varname></term>
|
<term><varname>NotifyReady=</varname></term>
|
||||||
|
|
||||||
<listitem><para>Configures support for notifications from the container's init process.
|
<listitem><para>Configures support for notifications from the container's init process. This is equivalent to
|
||||||
This is equivalent to use <option>--notify-ready=</option> command line switch,
|
the <option>--notify-ready=</option> command line switch, and takes the same paramaters. See
|
||||||
and takes the same options. See <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> for details
|
||||||
for details about the specific options supported.</para></listitem>
|
about the specific options supported.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>SystemCallFilter=</varname></term>
|
||||||
|
|
||||||
|
<listitem><para>Configures the system call filter applied to containers. This is equivalent to the
|
||||||
|
<option>--system-call-filter=</option> command line switch, and takes the same list parameter. See
|
||||||
|
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
|
||||||
|
details.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ Exec.WorkingDirectory, config_parse_path, 0, offsetof(Settings,
|
|||||||
Exec.PivotRoot, config_parse_pivot_root, 0, 0
|
Exec.PivotRoot, config_parse_pivot_root, 0, 0
|
||||||
Exec.PrivateUsers, config_parse_private_users, 0, 0
|
Exec.PrivateUsers, config_parse_private_users, 0, 0
|
||||||
Exec.NotifyReady, config_parse_bool, 0, offsetof(Settings, notify_ready)
|
Exec.NotifyReady, config_parse_bool, 0, offsetof(Settings, notify_ready)
|
||||||
|
Exec.SystemCallFilter, config_parse_syscall_filter,0, 0,
|
||||||
Files.ReadOnly, config_parse_tristate, 0, offsetof(Settings, read_only)
|
Files.ReadOnly, config_parse_tristate, 0, offsetof(Settings, read_only)
|
||||||
Files.Volatile, config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode)
|
Files.Volatile, config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode)
|
||||||
Files.Bind, config_parse_bind, 0, 0
|
Files.Bind, config_parse_bind, 0, 0
|
||||||
|
@ -33,112 +33,74 @@
|
|||||||
#include "seccomp-util.h"
|
#include "seccomp-util.h"
|
||||||
#endif
|
#endif
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
|
#include "strv.h"
|
||||||
|
|
||||||
#ifdef HAVE_SECCOMP
|
#ifdef HAVE_SECCOMP
|
||||||
|
|
||||||
static int seccomp_add_default_syscall_filter(
|
static int seccomp_add_default_syscall_filter(
|
||||||
scmp_filter_ctx ctx,
|
scmp_filter_ctx ctx,
|
||||||
uint32_t arch,
|
uint32_t arch,
|
||||||
uint64_t cap_list_retain) {
|
uint64_t cap_list_retain,
|
||||||
|
char **syscall_whitelist,
|
||||||
|
char **syscall_blacklist) {
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
uint64_t capability;
|
uint64_t capability;
|
||||||
int syscall_num;
|
const char* name;
|
||||||
} blacklist[] = {
|
} blacklist[] = {
|
||||||
{ 0, SCMP_SYS(_sysctl) }, /* obsolete syscall */
|
{ 0, "@obsolete" },
|
||||||
{ 0, SCMP_SYS(add_key) }, /* keyring is not namespaced */
|
{ 0, "@keyring" }, /* keyring is not namespaced */
|
||||||
{ 0, SCMP_SYS(afs_syscall) }, /* obsolete syscall */
|
{ 0, "bpf" },
|
||||||
{ 0, SCMP_SYS(bdflush) },
|
{ 0, "kexec_file_load" },
|
||||||
#ifdef __NR_bpf
|
{ 0, "kexec_load" },
|
||||||
{ 0, SCMP_SYS(bpf) },
|
{ 0, "lookup_dcookie" },
|
||||||
#endif
|
{ 0, "open_by_handle_at" },
|
||||||
{ 0, SCMP_SYS(break) }, /* obsolete syscall */
|
{ 0, "perf_event_open" },
|
||||||
{ 0, SCMP_SYS(create_module) }, /* obsolete syscall */
|
{ 0, "quotactl" },
|
||||||
{ 0, SCMP_SYS(ftime) }, /* obsolete syscall */
|
{ 0, "@swap" },
|
||||||
{ 0, SCMP_SYS(get_kernel_syms) }, /* obsolete syscall */
|
{ CAP_SYSLOG, "syslog" },
|
||||||
{ 0, SCMP_SYS(getpmsg) }, /* obsolete syscall */
|
{ CAP_SYS_MODULE, "@module" },
|
||||||
{ 0, SCMP_SYS(gtty) }, /* obsolete syscall */
|
{ CAP_SYS_PACCT, "acct" },
|
||||||
#ifdef __NR_kexec_file_load
|
{ CAP_SYS_PTRACE, "process_vm_readv" },
|
||||||
{ 0, SCMP_SYS(kexec_file_load) },
|
{ CAP_SYS_PTRACE, "process_vm_writev" },
|
||||||
#endif
|
{ CAP_SYS_PTRACE, "ptrace" },
|
||||||
{ 0, SCMP_SYS(kexec_load) },
|
{ CAP_SYS_RAWIO, "@raw-io" },
|
||||||
{ 0, SCMP_SYS(keyctl) }, /* keyring is not namespaced */
|
{ CAP_SYS_TIME, "@clock" },
|
||||||
{ 0, SCMP_SYS(lock) }, /* obsolete syscall */
|
|
||||||
{ 0, SCMP_SYS(lookup_dcookie) },
|
|
||||||
{ 0, SCMP_SYS(mpx) }, /* obsolete syscall */
|
|
||||||
{ 0, SCMP_SYS(nfsservctl) }, /* obsolete syscall */
|
|
||||||
{ 0, SCMP_SYS(open_by_handle_at) },
|
|
||||||
{ 0, SCMP_SYS(perf_event_open) },
|
|
||||||
{ 0, SCMP_SYS(prof) }, /* obsolete syscall */
|
|
||||||
{ 0, SCMP_SYS(profil) }, /* obsolete syscall */
|
|
||||||
{ 0, SCMP_SYS(putpmsg) }, /* obsolete syscall */
|
|
||||||
{ 0, SCMP_SYS(query_module) }, /* obsolete syscall */
|
|
||||||
{ 0, SCMP_SYS(quotactl) },
|
|
||||||
{ 0, SCMP_SYS(request_key) }, /* keyring is not namespaced */
|
|
||||||
{ 0, SCMP_SYS(security) }, /* obsolete syscall */
|
|
||||||
{ 0, SCMP_SYS(sgetmask) }, /* obsolete syscall */
|
|
||||||
{ 0, SCMP_SYS(ssetmask) }, /* obsolete syscall */
|
|
||||||
{ 0, SCMP_SYS(stty) }, /* obsolete syscall */
|
|
||||||
{ 0, SCMP_SYS(swapoff) },
|
|
||||||
{ 0, SCMP_SYS(swapon) },
|
|
||||||
{ 0, SCMP_SYS(sysfs) }, /* obsolete syscall */
|
|
||||||
{ 0, SCMP_SYS(tuxcall) }, /* obsolete syscall */
|
|
||||||
{ 0, SCMP_SYS(ulimit) }, /* obsolete syscall */
|
|
||||||
{ 0, SCMP_SYS(uselib) }, /* obsolete syscall */
|
|
||||||
{ 0, SCMP_SYS(ustat) }, /* obsolete syscall */
|
|
||||||
{ 0, SCMP_SYS(vserver) }, /* obsolete syscall */
|
|
||||||
{ CAP_SYSLOG, SCMP_SYS(syslog) },
|
|
||||||
{ CAP_SYS_MODULE, SCMP_SYS(delete_module) },
|
|
||||||
{ CAP_SYS_MODULE, SCMP_SYS(finit_module) },
|
|
||||||
{ CAP_SYS_MODULE, SCMP_SYS(init_module) },
|
|
||||||
{ CAP_SYS_PACCT, SCMP_SYS(acct) },
|
|
||||||
{ CAP_SYS_PTRACE, SCMP_SYS(process_vm_readv) },
|
|
||||||
{ CAP_SYS_PTRACE, SCMP_SYS(process_vm_writev) },
|
|
||||||
{ CAP_SYS_PTRACE, SCMP_SYS(ptrace) },
|
|
||||||
{ CAP_SYS_RAWIO, SCMP_SYS(ioperm) },
|
|
||||||
{ CAP_SYS_RAWIO, SCMP_SYS(iopl) },
|
|
||||||
{ CAP_SYS_RAWIO, SCMP_SYS(pciconfig_iobase) },
|
|
||||||
{ CAP_SYS_RAWIO, SCMP_SYS(pciconfig_read) },
|
|
||||||
{ CAP_SYS_RAWIO, SCMP_SYS(pciconfig_write) },
|
|
||||||
#ifdef __NR_s390_pci_mmio_read
|
|
||||||
{ CAP_SYS_RAWIO, SCMP_SYS(s390_pci_mmio_read) },
|
|
||||||
#endif
|
|
||||||
#ifdef __NR_s390_pci_mmio_write
|
|
||||||
{ CAP_SYS_RAWIO, SCMP_SYS(s390_pci_mmio_write) },
|
|
||||||
#endif
|
|
||||||
{ CAP_SYS_TIME, SCMP_SYS(adjtimex) },
|
|
||||||
{ CAP_SYS_TIME, SCMP_SYS(clock_adjtime) },
|
|
||||||
{ CAP_SYS_TIME, SCMP_SYS(clock_settime) },
|
|
||||||
{ CAP_SYS_TIME, SCMP_SYS(settimeofday) },
|
|
||||||
{ CAP_SYS_TIME, SCMP_SYS(stime) },
|
|
||||||
};
|
};
|
||||||
unsigned i;
|
|
||||||
int r, c = 0;
|
int r, c = 0;
|
||||||
|
size_t i;
|
||||||
|
char **p;
|
||||||
|
|
||||||
for (i = 0; i < ELEMENTSOF(blacklist); i++) {
|
for (i = 0; i < ELEMENTSOF(blacklist); i++) {
|
||||||
if (blacklist[i].capability != 0 && (cap_list_retain & (1ULL << blacklist[i].capability)))
|
if (blacklist[i].capability != 0 && (cap_list_retain & (1ULL << blacklist[i].capability)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
r = seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EPERM), blacklist[i].syscall_num, 0);
|
r = seccomp_add_syscall_filter_item(ctx, blacklist[i].name, SCMP_ACT_ERRNO(EPERM), syscall_whitelist);
|
||||||
if (r < 0) {
|
if (r < 0)
|
||||||
/* If the system call is not known on this architecture, then that's fine, let's ignore it */
|
/* If the system call is not known on this architecture, then that's fine, let's ignore it */
|
||||||
_cleanup_free_ char *n = NULL;
|
log_debug_errno(r, "Failed to add rule for system call %s, ignoring: %m", blacklist[i].name);
|
||||||
|
else
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
|
||||||
n = seccomp_syscall_resolve_num_arch(arch, blacklist[i].syscall_num);
|
STRV_FOREACH(p, syscall_blacklist) {
|
||||||
log_debug_errno(r, "Failed to add rule for system call %s, ignoring: %m", strna(n));
|
r = seccomp_add_syscall_filter_item(ctx, *p, SCMP_ACT_ERRNO(EPERM), syscall_whitelist);
|
||||||
} else
|
if (r < 0)
|
||||||
|
log_debug_errno(r, "Failed to add rule for system call %s, ignoring: %m", *p);
|
||||||
|
else
|
||||||
c++;
|
c++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
int setup_seccomp(uint64_t cap_list_retain) {
|
int setup_seccomp(uint64_t cap_list_retain, char **syscall_whitelist, char **syscall_blacklist) {
|
||||||
uint32_t arch;
|
uint32_t arch;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!is_seccomp_available()) {
|
if (!is_seccomp_available()) {
|
||||||
log_debug("SECCOMP features not detected in the kernel, disabling SECCOMP audit filter");
|
log_debug("SECCOMP features not detected in the kernel, disabling SECCOMP filterering");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,7 +114,7 @@ int setup_seccomp(uint64_t cap_list_retain) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to allocate seccomp object: %m");
|
return log_error_errno(r, "Failed to allocate seccomp object: %m");
|
||||||
|
|
||||||
n = seccomp_add_default_syscall_filter(seccomp, arch, cap_list_retain);
|
n = seccomp_add_default_syscall_filter(seccomp, arch, cap_list_retain, syscall_whitelist, syscall_blacklist);
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
return n;
|
return n;
|
||||||
|
|
||||||
@ -191,7 +153,7 @@ int setup_seccomp(uint64_t cap_list_retain) {
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
int setup_seccomp(uint64_t cap_list_retain) {
|
int setup_seccomp(uint64_t cap_list_retain, char **syscall_whitelist, char **syscall_blacklist) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,4 +21,4 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
int setup_seccomp(uint64_t cap_list_retain);
|
int setup_seccomp(uint64_t cap_list_retain, char **syscall_whitelist, char **syscall_blacklist);
|
||||||
|
@ -93,6 +93,8 @@ Settings* settings_free(Settings *s) {
|
|||||||
free(s->pivot_root_new);
|
free(s->pivot_root_new);
|
||||||
free(s->pivot_root_old);
|
free(s->pivot_root_old);
|
||||||
free(s->working_directory);
|
free(s->working_directory);
|
||||||
|
strv_free(s->syscall_whitelist);
|
||||||
|
strv_free(s->syscall_blacklist);
|
||||||
|
|
||||||
strv_free(s->network_interfaces);
|
strv_free(s->network_interfaces);
|
||||||
strv_free(s->network_macvlan);
|
strv_free(s->network_macvlan);
|
||||||
@ -568,3 +570,51 @@ int config_parse_private_users(
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int config_parse_syscall_filter(
|
||||||
|
const char *unit,
|
||||||
|
const char *filename,
|
||||||
|
unsigned line,
|
||||||
|
const char *section,
|
||||||
|
unsigned section_line,
|
||||||
|
const char *lvalue,
|
||||||
|
int ltype,
|
||||||
|
const char *rvalue,
|
||||||
|
void *data,
|
||||||
|
void *userdata) {
|
||||||
|
|
||||||
|
Settings *settings = data;
|
||||||
|
bool negative;
|
||||||
|
const char *items;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(filename);
|
||||||
|
assert(lvalue);
|
||||||
|
assert(rvalue);
|
||||||
|
|
||||||
|
negative = rvalue[0] == '~';
|
||||||
|
items = negative ? rvalue + 1 : rvalue;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
_cleanup_free_ char *word = NULL;
|
||||||
|
|
||||||
|
r = extract_first_word(&items, &word, NULL, 0);
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
if (r == -ENOMEM)
|
||||||
|
return log_oom();
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse SystemCallFilter= parameter %s, ignoring: %m", rvalue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (negative)
|
||||||
|
r = strv_extend(&settings->syscall_blacklist, word);
|
||||||
|
else
|
||||||
|
r = strv_extend(&settings->syscall_whitelist, word);
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -58,7 +58,8 @@ typedef enum SettingsMask {
|
|||||||
SETTING_USERNS = 1 << 13,
|
SETTING_USERNS = 1 << 13,
|
||||||
SETTING_NOTIFY_READY = 1 << 14,
|
SETTING_NOTIFY_READY = 1 << 14,
|
||||||
SETTING_PIVOT_ROOT = 1 << 15,
|
SETTING_PIVOT_ROOT = 1 << 15,
|
||||||
_SETTINGS_MASK_ALL = (1 << 16) -1
|
SETTING_SYSCALL_FILTER = 1 << 16,
|
||||||
|
_SETTINGS_MASK_ALL = (1 << 17) -1
|
||||||
} SettingsMask;
|
} SettingsMask;
|
||||||
|
|
||||||
typedef struct Settings {
|
typedef struct Settings {
|
||||||
@ -78,6 +79,8 @@ typedef struct Settings {
|
|||||||
UserNamespaceMode userns_mode;
|
UserNamespaceMode userns_mode;
|
||||||
uid_t uid_shift, uid_range;
|
uid_t uid_shift, uid_range;
|
||||||
bool notify_ready;
|
bool notify_ready;
|
||||||
|
char **syscall_whitelist;
|
||||||
|
char **syscall_blacklist;
|
||||||
|
|
||||||
/* [Image] */
|
/* [Image] */
|
||||||
int read_only;
|
int read_only;
|
||||||
@ -121,3 +124,4 @@ int config_parse_network_zone(const char *unit, const char *filename, unsigned l
|
|||||||
int config_parse_boot(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
int config_parse_boot(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||||
int config_parse_pid2(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
int config_parse_pid2(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||||
int config_parse_private_users(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
int config_parse_private_users(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||||
|
int config_parse_syscall_filter(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||||
|
@ -208,6 +208,8 @@ static unsigned long arg_clone_ns_flags = CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS
|
|||||||
static MountSettingsMask arg_mount_settings = MOUNT_APPLY_APIVFS_RO;
|
static MountSettingsMask arg_mount_settings = MOUNT_APPLY_APIVFS_RO;
|
||||||
static void *arg_root_hash = NULL;
|
static void *arg_root_hash = NULL;
|
||||||
static size_t arg_root_hash_size = 0;
|
static size_t arg_root_hash_size = 0;
|
||||||
|
static char **arg_syscall_whitelist = NULL;
|
||||||
|
static char **arg_syscall_blacklist = NULL;
|
||||||
|
|
||||||
static void help(void) {
|
static void help(void) {
|
||||||
printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
|
printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
|
||||||
@ -267,6 +269,8 @@ static void help(void) {
|
|||||||
" --capability=CAP In addition to the default, retain specified\n"
|
" --capability=CAP In addition to the default, retain specified\n"
|
||||||
" capability\n"
|
" capability\n"
|
||||||
" --drop-capability=CAP Drop the specified capability from the default set\n"
|
" --drop-capability=CAP Drop the specified capability from the default set\n"
|
||||||
|
" --system-call-filter=LIST|~LIST\n"
|
||||||
|
" Permit/prohibit specific system calls\n"
|
||||||
" --kill-signal=SIGNAL Select signal to use for shutting down PID 1\n"
|
" --kill-signal=SIGNAL Select signal to use for shutting down PID 1\n"
|
||||||
" --link-journal=MODE Link up guest journal, one of no, auto, guest, \n"
|
" --link-journal=MODE Link up guest journal, one of no, auto, guest, \n"
|
||||||
" host, try-guest, try-host\n"
|
" host, try-guest, try-host\n"
|
||||||
@ -431,6 +435,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
ARG_PRIVATE_USERS_CHOWN,
|
ARG_PRIVATE_USERS_CHOWN,
|
||||||
ARG_NOTIFY_READY,
|
ARG_NOTIFY_READY,
|
||||||
ARG_ROOT_HASH,
|
ARG_ROOT_HASH,
|
||||||
|
ARG_SYSTEM_CALL_FILTER,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
@ -482,6 +487,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
{ "pivot-root", required_argument, NULL, ARG_PIVOT_ROOT },
|
{ "pivot-root", required_argument, NULL, ARG_PIVOT_ROOT },
|
||||||
{ "notify-ready", required_argument, NULL, ARG_NOTIFY_READY },
|
{ "notify-ready", required_argument, NULL, ARG_NOTIFY_READY },
|
||||||
{ "root-hash", required_argument, NULL, ARG_ROOT_HASH },
|
{ "root-hash", required_argument, NULL, ARG_ROOT_HASH },
|
||||||
|
{ "system-call-filter", required_argument, NULL, ARG_SYSTEM_CALL_FILTER },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1051,6 +1057,36 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ARG_SYSTEM_CALL_FILTER: {
|
||||||
|
bool negative;
|
||||||
|
const char *items;
|
||||||
|
|
||||||
|
negative = optarg[0] == '~';
|
||||||
|
items = negative ? optarg + 1 : optarg;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
_cleanup_free_ char *word = NULL;
|
||||||
|
|
||||||
|
r = extract_first_word(&items, &word, NULL, 0);
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
if (r == -ENOMEM)
|
||||||
|
return log_oom();
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse system call filter: %m");
|
||||||
|
|
||||||
|
if (negative)
|
||||||
|
r = strv_extend(&arg_syscall_blacklist, word);
|
||||||
|
else
|
||||||
|
r = strv_extend(&arg_syscall_whitelist, word);
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
|
||||||
|
arg_settings_mask |= SETTING_SYSCALL_FILTER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@ -2606,7 +2642,7 @@ static int outer_child(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = setup_seccomp(arg_caps_retain);
|
r = setup_seccomp(arg_caps_retain, arg_syscall_whitelist, arg_syscall_blacklist);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -3111,6 +3147,21 @@ static int load_settings(void) {
|
|||||||
if ((arg_settings_mask & SETTING_NOTIFY_READY) == 0)
|
if ((arg_settings_mask & SETTING_NOTIFY_READY) == 0)
|
||||||
arg_notify_ready = settings->notify_ready;
|
arg_notify_ready = settings->notify_ready;
|
||||||
|
|
||||||
|
if ((arg_settings_mask & SETTING_SYSCALL_FILTER) == 0) {
|
||||||
|
|
||||||
|
if (!arg_settings_trusted && !strv_isempty(arg_syscall_whitelist))
|
||||||
|
log_warning("Ignoring SystemCallFilter= settings, file %s is not trusted.", p);
|
||||||
|
else {
|
||||||
|
strv_free(arg_syscall_whitelist);
|
||||||
|
strv_free(arg_syscall_blacklist);
|
||||||
|
|
||||||
|
arg_syscall_whitelist = settings->syscall_whitelist;
|
||||||
|
arg_syscall_blacklist = settings->syscall_blacklist;
|
||||||
|
|
||||||
|
settings->syscall_whitelist = settings->syscall_blacklist = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -682,11 +682,48 @@ const SyscallFilterSet *syscall_filter_set_find(const char *name) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int seccomp_add_syscall_filter_set(scmp_filter_ctx seccomp, const SyscallFilterSet *set, uint32_t action, char **exclude);
|
||||||
|
|
||||||
|
int seccomp_add_syscall_filter_item(scmp_filter_ctx *seccomp, const char *name, uint32_t action, char **exclude) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(seccomp);
|
||||||
|
assert(name);
|
||||||
|
|
||||||
|
if (strv_contains(exclude, name))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (name[0] == '@') {
|
||||||
|
const SyscallFilterSet *other;
|
||||||
|
|
||||||
|
other = syscall_filter_set_find(name);
|
||||||
|
if (!other)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
r = seccomp_add_syscall_filter_set(seccomp, other, action, exclude);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
} else {
|
||||||
|
int id;
|
||||||
|
|
||||||
|
id = seccomp_syscall_resolve_name(name);
|
||||||
|
if (id == __NR_SCMP_ERROR)
|
||||||
|
return -EINVAL; /* Not known at all? Then that's a real error */
|
||||||
|
|
||||||
|
r = seccomp_rule_add_exact(seccomp, action, id, 0);
|
||||||
|
if (r < 0)
|
||||||
|
/* If the system call is not known on this architecture, then that's fine, let's ignore it */
|
||||||
|
log_debug_errno(r, "Failed to add rule for system call %s() / %d, ignoring: %m", name, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int seccomp_add_syscall_filter_set(
|
static int seccomp_add_syscall_filter_set(
|
||||||
scmp_filter_ctx seccomp,
|
scmp_filter_ctx seccomp,
|
||||||
uint32_t default_action,
|
|
||||||
const SyscallFilterSet *set,
|
const SyscallFilterSet *set,
|
||||||
uint32_t action) {
|
uint32_t action,
|
||||||
|
char **exclude) {
|
||||||
|
|
||||||
const char *sys;
|
const char *sys;
|
||||||
int r;
|
int r;
|
||||||
@ -695,28 +732,9 @@ static int seccomp_add_syscall_filter_set(
|
|||||||
assert(set);
|
assert(set);
|
||||||
|
|
||||||
NULSTR_FOREACH(sys, set->value) {
|
NULSTR_FOREACH(sys, set->value) {
|
||||||
int id;
|
r = seccomp_add_syscall_filter_item(seccomp, sys, action, exclude);
|
||||||
|
if (r < 0)
|
||||||
if (sys[0] == '@') {
|
return r;
|
||||||
const SyscallFilterSet *other;
|
|
||||||
|
|
||||||
other = syscall_filter_set_find(sys);
|
|
||||||
if (!other)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
r = seccomp_add_syscall_filter_set(seccomp, default_action, other, action);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
} else {
|
|
||||||
id = seccomp_syscall_resolve_name(sys);
|
|
||||||
if (id == __NR_SCMP_ERROR)
|
|
||||||
return -EINVAL; /* Not known at all? Then that's a real error */
|
|
||||||
|
|
||||||
r = seccomp_rule_add_exact(seccomp, action, id, 0);
|
|
||||||
if (r < 0)
|
|
||||||
/* If the system call is not known on this architecture, then that's fine, let's ignore it */
|
|
||||||
log_debug_errno(r, "Failed to add rule for system call %s() / %d, ignoring: %m", sys, id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -740,7 +758,7 @@ int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilter
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = seccomp_add_syscall_filter_set(seccomp, default_action, set, action);
|
r = seccomp_add_syscall_filter_set(seccomp, set, action, NULL);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_debug_errno(r, "Failed to add filter set, ignoring: %m");
|
log_debug_errno(r, "Failed to add filter set, ignoring: %m");
|
||||||
continue;
|
continue;
|
||||||
|
@ -69,6 +69,8 @@ const SyscallFilterSet *syscall_filter_set_find(const char *name);
|
|||||||
|
|
||||||
int seccomp_filter_set_add(Set *s, bool b, const SyscallFilterSet *set);
|
int seccomp_filter_set_add(Set *s, bool b, const SyscallFilterSet *set);
|
||||||
|
|
||||||
|
int seccomp_add_syscall_filter_item(scmp_filter_ctx *ctx, const char *name, uint32_t action, char **exclude);
|
||||||
|
|
||||||
int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilterSet *set, uint32_t action);
|
int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilterSet *set, uint32_t action);
|
||||||
int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Set* set, uint32_t action);
|
int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Set* set, uint32_t action);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user