mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-24 21:34:08 +03:00
Implement sets of system calls to help constructing system call filters. A set starts with '@' to distinguish from a system call. Closes: #3053, #3157
This commit is contained in:
parent
ce3eb7790c
commit
201c1cc22a
@ -1193,7 +1193,78 @@
|
|||||||
<function>read</function> and <function>write</function>, and
|
<function>read</function> and <function>write</function>, and
|
||||||
right after it add a blacklisting of
|
right after it add a blacklisting of
|
||||||
<function>write</function>, then <function>write</function>
|
<function>write</function>, then <function>write</function>
|
||||||
will be removed from the set.) </para></listitem>
|
will be removed from the set.)</para>
|
||||||
|
|
||||||
|
<para>As the number of possible system
|
||||||
|
calls is large, predefined sets of system calls are provided.
|
||||||
|
A set starts with <literal>@</literal> character, followed by
|
||||||
|
name of the set.
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<title>Currently predefined system call sets</title>
|
||||||
|
|
||||||
|
<tgroup cols='2'>
|
||||||
|
<colspec colname='set' />
|
||||||
|
<colspec colname='description' />
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Set</entry>
|
||||||
|
<entry>Description</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>@clock</entry>
|
||||||
|
<entry>System calls for changing the system clock (<function>adjtimex()</function>,
|
||||||
|
<function>settimeofday()</function>)</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>@io-event</entry>
|
||||||
|
<entry>Event loop use (<function>poll()</function>, <function>select()</function>,
|
||||||
|
<citerefentry project='man-pages'><refentrytitle>epoll</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||||
|
<function>eventfd()</function>...)</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>@ipc</entry>
|
||||||
|
<entry>SysV IPC, POSIX Message Queues or other IPC (<citerefentry project='man-pages'><refentrytitle>mq_overview</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||||
|
<citerefentry project='man-pages'><refentrytitle>svipc</refentrytitle><manvolnum>7</manvolnum></citerefentry>)</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>@module</entry>
|
||||||
|
<entry>Kernel module control (<function>create_module()</function>, <function>init_module()</function>...)</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>@mount</entry>
|
||||||
|
<entry>File system mounting and unmounting (<function>chroot()</function>, <function>mount()</function>...)</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>@network-io</entry>
|
||||||
|
<entry>Socket I/O (including local AF_UNIX):
|
||||||
|
<citerefentry project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||||
|
<citerefentry project='man-pages'><refentrytitle>unix</refentrytitle><manvolnum>7</manvolnum></citerefentry></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>@obsolete</entry>
|
||||||
|
<entry>Unusual, obsolete or unimplemented (<function>fattach()</function>, <function>gtty()</function>, <function>vm86()</function>...)</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>@privileged</entry>
|
||||||
|
<entry>All system calls which need superuser capabilities (<citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>)</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>@process</entry>
|
||||||
|
<entry>Process control, execution, namespaces (<function>execve()</function>, <function>kill()</function>, <citerefentry project='man-pages'><refentrytitle>namespaces</refentrytitle><manvolnum>7</manvolnum></citerefentry>...)</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>@raw-io</entry>
|
||||||
|
<entry>Raw I/O ports (<function>ioperm()</function>, <function>iopl()</function>, <function>pciconfig_read()</function>...)</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
Note, that as new system calls are added to the kernel, additional system calls might be added to the groups
|
||||||
|
above, so the contents of the sets may change between systemd versions.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
@ -2396,6 +2396,55 @@ int config_parse_documentation(const char *unit,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SECCOMP
|
#ifdef HAVE_SECCOMP
|
||||||
|
static int syscall_filter_parse_one(
|
||||||
|
const char *unit,
|
||||||
|
const char *filename,
|
||||||
|
unsigned line,
|
||||||
|
ExecContext *c,
|
||||||
|
bool invert,
|
||||||
|
const char *t,
|
||||||
|
bool warn) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (*t == '@') {
|
||||||
|
const SystemCallFilterSet *set;
|
||||||
|
|
||||||
|
for (set = syscall_filter_sets; set->set_name; set++)
|
||||||
|
if (streq(set->set_name, t)) {
|
||||||
|
const char *sys;
|
||||||
|
|
||||||
|
NULSTR_FOREACH(sys, set->value) {
|
||||||
|
r = syscall_filter_parse_one(unit, filename, line, c, invert, sys, false);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int id;
|
||||||
|
|
||||||
|
id = seccomp_syscall_resolve_name(t);
|
||||||
|
if (id < 0) {
|
||||||
|
if (warn)
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call, ignoring: %s", t);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we previously wanted to forbid a syscall and now
|
||||||
|
* we want to allow it, then remove it from the list
|
||||||
|
*/
|
||||||
|
if (!invert == c->syscall_whitelist) {
|
||||||
|
r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
|
||||||
|
if (r == 0)
|
||||||
|
return 0;
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom();
|
||||||
|
} else
|
||||||
|
set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int config_parse_syscall_filter(
|
int config_parse_syscall_filter(
|
||||||
const char *unit,
|
const char *unit,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
@ -2408,13 +2457,6 @@ int config_parse_syscall_filter(
|
|||||||
void *data,
|
void *data,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
static const char default_syscalls[] =
|
|
||||||
"execve\0"
|
|
||||||
"exit\0"
|
|
||||||
"exit_group\0"
|
|
||||||
"rt_sigreturn\0"
|
|
||||||
"sigreturn\0";
|
|
||||||
|
|
||||||
ExecContext *c = data;
|
ExecContext *c = data;
|
||||||
Unit *u = userdata;
|
Unit *u = userdata;
|
||||||
bool invert = false;
|
bool invert = false;
|
||||||
@ -2448,53 +2490,26 @@ int config_parse_syscall_filter(
|
|||||||
/* Allow everything but the ones listed */
|
/* Allow everything but the ones listed */
|
||||||
c->syscall_whitelist = false;
|
c->syscall_whitelist = false;
|
||||||
else {
|
else {
|
||||||
const char *i;
|
|
||||||
|
|
||||||
/* Allow nothing but the ones listed */
|
/* Allow nothing but the ones listed */
|
||||||
c->syscall_whitelist = true;
|
c->syscall_whitelist = true;
|
||||||
|
|
||||||
/* Accept default syscalls if we are on a whitelist */
|
/* Accept default syscalls if we are on a whitelist */
|
||||||
NULSTR_FOREACH(i, default_syscalls) {
|
r = syscall_filter_parse_one(unit, filename, line, c, false, "@default", false);
|
||||||
int id;
|
if (r < 0)
|
||||||
|
return r;
|
||||||
id = seccomp_syscall_resolve_name(i);
|
|
||||||
if (id < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
|
|
||||||
if (r == 0)
|
|
||||||
continue;
|
|
||||||
if (r < 0)
|
|
||||||
return log_oom();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FOREACH_WORD_QUOTED(word, l, rvalue, state) {
|
FOREACH_WORD_QUOTED(word, l, rvalue, state) {
|
||||||
_cleanup_free_ char *t = NULL;
|
_cleanup_free_ char *t = NULL;
|
||||||
int id;
|
|
||||||
|
|
||||||
t = strndup(word, l);
|
t = strndup(word, l);
|
||||||
if (!t)
|
if (!t)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
id = seccomp_syscall_resolve_name(t);
|
r = syscall_filter_parse_one(unit, filename, line, c, invert, t, true);
|
||||||
if (id < 0) {
|
if (r < 0)
|
||||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call, ignoring: %s", t);
|
return r;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we previously wanted to forbid a syscall and now
|
|
||||||
* we want to allow it, then remove it from the list
|
|
||||||
*/
|
|
||||||
if (!invert == c->syscall_whitelist) {
|
|
||||||
r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
|
|
||||||
if (r == 0)
|
|
||||||
continue;
|
|
||||||
if (r < 0)
|
|
||||||
return log_oom();
|
|
||||||
} else
|
|
||||||
set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
|
|
||||||
}
|
}
|
||||||
if (!isempty(state))
|
if (!isempty(state))
|
||||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
|
log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
|
||||||
|
@ -88,3 +88,219 @@ int seccomp_add_secondary_archs(scmp_filter_ctx *c) {
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SystemCallFilterSet syscall_filter_sets[] = {
|
||||||
|
{
|
||||||
|
/* Clock */
|
||||||
|
.set_name = "@clock",
|
||||||
|
.value =
|
||||||
|
"adjtimex\0"
|
||||||
|
"settimeofday\0"
|
||||||
|
}, {
|
||||||
|
/* Default list */
|
||||||
|
.set_name = "@default",
|
||||||
|
.value =
|
||||||
|
"execve\0"
|
||||||
|
"exit\0"
|
||||||
|
"exit_group\0"
|
||||||
|
"rt_sigreturn\0"
|
||||||
|
"sigreturn\0"
|
||||||
|
}, {
|
||||||
|
/* Event loop use */
|
||||||
|
.set_name = "@io-event",
|
||||||
|
.value =
|
||||||
|
"_newselect\0"
|
||||||
|
"epoll_create1\0"
|
||||||
|
"epoll_create\0"
|
||||||
|
"epoll_ctl\0"
|
||||||
|
"epoll_ctl_old\0"
|
||||||
|
"epoll_pwait\0"
|
||||||
|
"epoll_wait\0"
|
||||||
|
"epoll_wait_old\0"
|
||||||
|
"eventfd2\0"
|
||||||
|
"eventfd\0"
|
||||||
|
"poll\0"
|
||||||
|
"ppoll\0"
|
||||||
|
"pselect6\0"
|
||||||
|
"select\0"
|
||||||
|
}, {
|
||||||
|
/* Message queues, SYSV IPC or other IPC: unusual */
|
||||||
|
.set_name = "@ipc",
|
||||||
|
.value = "ipc\0"
|
||||||
|
"mq_getsetattr\0"
|
||||||
|
"mq_notify\0"
|
||||||
|
"mq_open\0"
|
||||||
|
"mq_timedreceive\0"
|
||||||
|
"mq_timedsend\0"
|
||||||
|
"mq_unlink\0"
|
||||||
|
"msgctl\0"
|
||||||
|
"msgget\0"
|
||||||
|
"msgrcv\0"
|
||||||
|
"msgsnd\0"
|
||||||
|
"process_vm_readv\0"
|
||||||
|
"process_vm_writev\0"
|
||||||
|
"semctl\0"
|
||||||
|
"semget\0"
|
||||||
|
"semop\0"
|
||||||
|
"semtimedop\0"
|
||||||
|
"shmat\0"
|
||||||
|
"shmctl\0"
|
||||||
|
"shmdt\0"
|
||||||
|
"shmget\0"
|
||||||
|
}, {
|
||||||
|
/* Kernel module control */
|
||||||
|
.set_name = "@module",
|
||||||
|
.value =
|
||||||
|
"create_module\0"
|
||||||
|
"delete_module\0"
|
||||||
|
"finit_module\0"
|
||||||
|
"init_module\0"
|
||||||
|
}, {
|
||||||
|
/* Mounting */
|
||||||
|
.set_name = "@mount",
|
||||||
|
.value =
|
||||||
|
"chroot\0"
|
||||||
|
"mount\0"
|
||||||
|
"oldumount\0"
|
||||||
|
"pivot_root\0"
|
||||||
|
"umount2\0"
|
||||||
|
"umount\0"
|
||||||
|
}, {
|
||||||
|
/* Network or Unix socket IO, should not be needed if not network facing */
|
||||||
|
.set_name = "@network-io",
|
||||||
|
.value =
|
||||||
|
"accept4\0"
|
||||||
|
"accept\0"
|
||||||
|
"bind\0"
|
||||||
|
"connect\0"
|
||||||
|
"getpeername\0"
|
||||||
|
"getsockname\0"
|
||||||
|
"getsockopt\0"
|
||||||
|
"listen\0"
|
||||||
|
"recv\0"
|
||||||
|
"recvfrom\0"
|
||||||
|
"recvmmsg\0"
|
||||||
|
"recvmsg\0"
|
||||||
|
"send\0"
|
||||||
|
"sendmmsg\0"
|
||||||
|
"sendmsg\0"
|
||||||
|
"sendto\0"
|
||||||
|
"setsockopt\0"
|
||||||
|
"shutdown\0"
|
||||||
|
"socket\0"
|
||||||
|
"socketcall\0"
|
||||||
|
"socketpair\0"
|
||||||
|
}, {
|
||||||
|
/* Unusual, obsolete or unimplemented, some unknown even to libseccomp */
|
||||||
|
.set_name = "@obsolete",
|
||||||
|
.value =
|
||||||
|
"_sysctl\0"
|
||||||
|
"afs_syscall\0"
|
||||||
|
"break\0"
|
||||||
|
"fattach\0"
|
||||||
|
"fdetach\0"
|
||||||
|
"ftime\0"
|
||||||
|
"get_kernel_syms\0"
|
||||||
|
"get_mempolicy\0"
|
||||||
|
"getmsg\0"
|
||||||
|
"getpmsg\0"
|
||||||
|
"gtty\0"
|
||||||
|
"isastream\0"
|
||||||
|
"lock\0"
|
||||||
|
"madvise1\0"
|
||||||
|
"modify_ldt\0"
|
||||||
|
"mpx\0"
|
||||||
|
"pciconfig_iobase\0"
|
||||||
|
"perf_event_open\0"
|
||||||
|
"prof\0"
|
||||||
|
"profil\0"
|
||||||
|
"putmsg\0"
|
||||||
|
"putpmsg\0"
|
||||||
|
"query_module\0"
|
||||||
|
"rtas\0"
|
||||||
|
"s390_runtime_instr\0"
|
||||||
|
"security\0"
|
||||||
|
"sgetmask\0"
|
||||||
|
"ssetmask\0"
|
||||||
|
"stty\0"
|
||||||
|
"subpage_prot\0"
|
||||||
|
"switch_endian\0"
|
||||||
|
"sys_debug_setcontext\0"
|
||||||
|
"tuxcall\0"
|
||||||
|
"ulimit\0"
|
||||||
|
"uselib\0"
|
||||||
|
"vm86\0"
|
||||||
|
"vm86old\0"
|
||||||
|
"vserver\0"
|
||||||
|
}, {
|
||||||
|
/* Nice grab-bag of all system calls which need superuser capabilities */
|
||||||
|
.set_name = "@privileged",
|
||||||
|
.value =
|
||||||
|
"@clock\0"
|
||||||
|
"@module\0"
|
||||||
|
"@raw-io\0"
|
||||||
|
"acct\0"
|
||||||
|
"bdflush\0"
|
||||||
|
"bpf\0"
|
||||||
|
"chown32\0"
|
||||||
|
"chown\0"
|
||||||
|
"chroot\0"
|
||||||
|
"fchown32\0"
|
||||||
|
"fchown\0"
|
||||||
|
"fchownat\0"
|
||||||
|
"kexec_file_load\0"
|
||||||
|
"kexec_load\0"
|
||||||
|
"lchown32\0"
|
||||||
|
"lchown\0"
|
||||||
|
"nfsservctl\0"
|
||||||
|
"pivot_root\0"
|
||||||
|
"quotactl\0"
|
||||||
|
"reboot\0"
|
||||||
|
"setdomainname\0"
|
||||||
|
"setfsuid32\0"
|
||||||
|
"setfsuid\0"
|
||||||
|
"setgroups32\0"
|
||||||
|
"setgroups\0"
|
||||||
|
"sethostname\0"
|
||||||
|
"setresuid32\0"
|
||||||
|
"setresuid\0"
|
||||||
|
"setreuid32\0"
|
||||||
|
"setreuid\0"
|
||||||
|
"setuid32\0"
|
||||||
|
"setuid\0"
|
||||||
|
"stime\0"
|
||||||
|
"swapoff\0"
|
||||||
|
"swapon\0"
|
||||||
|
"sysctl\0"
|
||||||
|
"vhangup\0"
|
||||||
|
}, {
|
||||||
|
/* Process control, execution, namespaces */
|
||||||
|
.set_name = "@process",
|
||||||
|
.value =
|
||||||
|
"arch_prctl\0"
|
||||||
|
"clone\0"
|
||||||
|
"execve\0"
|
||||||
|
"execveat\0"
|
||||||
|
"fork\0"
|
||||||
|
"kill\0"
|
||||||
|
"prctl\0"
|
||||||
|
"setns\0"
|
||||||
|
"tgkill\0"
|
||||||
|
"tkill\0"
|
||||||
|
"unshare\0"
|
||||||
|
"vfork\0"
|
||||||
|
}, {
|
||||||
|
/* Raw I/O ports */
|
||||||
|
.set_name = "@raw-io",
|
||||||
|
.value =
|
||||||
|
"ioperm\0"
|
||||||
|
"iopl\0"
|
||||||
|
"pciconfig_read\0"
|
||||||
|
"pciconfig_write\0"
|
||||||
|
"s390_pci_mmio_read\0"
|
||||||
|
"s390_pci_mmio_write\0"
|
||||||
|
}, {
|
||||||
|
.set_name = NULL,
|
||||||
|
.value = NULL
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -26,3 +26,10 @@ const char* seccomp_arch_to_string(uint32_t c);
|
|||||||
int seccomp_arch_from_string(const char *n, uint32_t *ret);
|
int seccomp_arch_from_string(const char *n, uint32_t *ret);
|
||||||
|
|
||||||
int seccomp_add_secondary_archs(scmp_filter_ctx *c);
|
int seccomp_add_secondary_archs(scmp_filter_ctx *c);
|
||||||
|
|
||||||
|
typedef struct SystemCallFilterSet {
|
||||||
|
const char *set_name;
|
||||||
|
const char *value;
|
||||||
|
} SystemCallFilterSet;
|
||||||
|
|
||||||
|
extern const SystemCallFilterSet syscall_filter_sets[];
|
||||||
|
Loading…
Reference in New Issue
Block a user