Compare commits
16 Commits
e66d2eeeeb
...
a7ddeea15d
Author | SHA1 | Date |
---|---|---|
Zbigniew Jędrzejewski-Szmek | a7ddeea15d | |
Lennart Poettering | eb5e26112e | |
Topi Miettinen | f593965161 | |
Yu Watanabe | 6234712ec6 | |
Lennart Poettering | c796b91d2b | |
Zbigniew Jędrzejewski-Szmek | c882b71457 | |
Lennart Poettering | aa088f62d1 | |
Lennart Poettering | 569a0e42ec | |
Lennart Poettering | f5215bc8d3 | |
Zbigniew Jędrzejewski-Szmek | c2ee27a5e7 | |
Lennart Poettering | 80dd1125c8 | |
Zbigniew Jędrzejewski-Szmek | 452d2dfd52 | |
Zbigniew Jędrzejewski-Szmek | 7e5f1d4b3f | |
Zbigniew Jędrzejewski-Szmek | d0e5db44d9 | |
Topi Miettinen | 9df2cdd8ec | |
Topi Miettinen | 005bfaf118 |
3
TODO
3
TODO
|
@ -561,6 +561,9 @@ Features:
|
||||||
* sd-bus: add vtable flag, that may be used to request client creds implicitly
|
* sd-bus: add vtable flag, that may be used to request client creds implicitly
|
||||||
and asynchronously before dispatching the operation
|
and asynchronously before dispatching the operation
|
||||||
|
|
||||||
|
* sd-bus: parse addresses given in sd_bus_set_addresses immediately and not
|
||||||
|
only when used. Add unit tests.
|
||||||
|
|
||||||
* make use of ethtool veth peer info in machined, for automatically finding out
|
* make use of ethtool veth peer info in machined, for automatically finding out
|
||||||
host-side interface pointing to the container.
|
host-side interface pointing to the container.
|
||||||
|
|
||||||
|
|
|
@ -156,6 +156,7 @@ All execution-related settings are available for transient units.
|
||||||
✓ SystemCallFilter=
|
✓ SystemCallFilter=
|
||||||
✓ SystemCallArchitectures=
|
✓ SystemCallArchitectures=
|
||||||
✓ SystemCallErrorNumber=
|
✓ SystemCallErrorNumber=
|
||||||
|
✓ SystemCallLog=
|
||||||
✓ MemoryDenyWriteExecute=
|
✓ MemoryDenyWriteExecute=
|
||||||
✓ RestrictNamespaces=
|
✓ RestrictNamespaces=
|
||||||
✓ RestrictRealtime=
|
✓ RestrictRealtime=
|
||||||
|
|
|
@ -10,3 +10,4 @@
|
||||||
<!ENTITY MEMORY_ACCOUNTING_DEFAULT @MEMORY_ACCOUNTING_DEFAULT_YES_NO@>
|
<!ENTITY MEMORY_ACCOUNTING_DEFAULT @MEMORY_ACCOUNTING_DEFAULT_YES_NO@>
|
||||||
<!ENTITY KILL_USER_PROCESSES @KILL_USER_PROCESSES_YES_NO@>
|
<!ENTITY KILL_USER_PROCESSES @KILL_USER_PROCESSES_YES_NO@>
|
||||||
<!ENTITY DEBUGTTY @DEBUGTTY@>
|
<!ENTITY DEBUGTTY @DEBUGTTY@>
|
||||||
|
<!ENTITY RC_LOCAL_PATH @RC_LOCAL_PATH@>
|
||||||
|
|
|
@ -123,7 +123,7 @@ node /org/freedesktop/LogControl1 {
|
||||||
<citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
<citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||||
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||||
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||||
<citerefentry project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
<citerefentry project="man-pages"><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
</refentry>
|
</refentry>
|
||||||
|
|
|
@ -3904,6 +3904,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly b Accept = ...;
|
readonly b Accept = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly b FlushPending = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly b Writable = ...;
|
readonly b Writable = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly b KeepAlive = ...;
|
readonly b KeepAlive = ...;
|
||||||
|
@ -3976,8 +3978,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
readonly u NRefused = ...;
|
readonly u NRefused = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
readonly u FlushPending = ...;
|
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
|
||||||
readonly s FileDescriptorName = '...';
|
readonly s FileDescriptorName = '...';
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly i SocketProtocol = ...;
|
readonly i SocketProtocol = ...;
|
||||||
|
@ -4985,6 +4985,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="Accept"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="Accept"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="FlushPending"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="Writable"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="Writable"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="KeepAlive"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="KeepAlive"/>
|
||||||
|
@ -5059,8 +5061,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="NRefused"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="NRefused"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="FlushPending"/>
|
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="FileDescriptorName"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="FileDescriptorName"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="SocketProtocol"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="SocketProtocol"/>
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version='1.0'?>
|
||||||
<!--*-nxml-*-->
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
|
||||||
|
<!ENTITY % entities SYSTEM "custom-entities.ent" >
|
||||||
|
%entities;
|
||||||
|
]>
|
||||||
<!-- SPDX-License-Identifier: LGPL-2.1+ -->
|
<!-- SPDX-License-Identifier: LGPL-2.1+ -->
|
||||||
|
|
||||||
<refentry id="systemd-rc-local-generator" conditional='HAVE_SYSV_COMPAT'>
|
<refentry id="systemd-rc-local-generator" conditional='HAVE_SYSV_COMPAT'>
|
||||||
<refentryinfo>
|
<refentryinfo>
|
||||||
<title>systemd-rc-local-generator</title>
|
<title>systemd-rc-local-generator</title>
|
||||||
|
@ -16,7 +19,7 @@
|
||||||
|
|
||||||
<refnamediv>
|
<refnamediv>
|
||||||
<refname>systemd-rc-local-generator</refname>
|
<refname>systemd-rc-local-generator</refname>
|
||||||
<refpurpose>Compatibility generator for starting <filename>/etc/rc.local</filename> during boot</refpurpose>
|
<refpurpose>Compatibility generator for starting <filename>&RC_LOCAL_PATH;</filename> during boot</refpurpose>
|
||||||
</refnamediv>
|
</refnamediv>
|
||||||
|
|
||||||
<refsynopsisdiv>
|
<refsynopsisdiv>
|
||||||
|
@ -27,17 +30,17 @@
|
||||||
<title>Description</title>
|
<title>Description</title>
|
||||||
|
|
||||||
<para><filename>systemd-rc-local-generator</filename> is a generator that checks whether
|
<para><filename>systemd-rc-local-generator</filename> is a generator that checks whether
|
||||||
<filename>/etc/rc.local</filename> exists and is executable, and if it is pulls the
|
<filename>&RC_LOCAL_PATH;</filename> exists and is executable, and if it is pulls the
|
||||||
<filename>rc-local.service</filename> unit into the boot process. This unit is responsible for running this script
|
<filename>rc-local.service</filename> unit into the boot process. This unit is responsible for running
|
||||||
during late boot. Note that the script will be run with slightly different semantics than the original System V
|
this script during late boot. Note that the script will be run with slightly different semantics than the
|
||||||
version, which was run "last" in the boot process, which is a concept that does not translate to systemd. The
|
original System V version, which was run "last" in the boot process, which is a concept that does not
|
||||||
script is run after <filename>network.target</filename>, but in parallel with most other regular system
|
translate to systemd. The script is run after <filename>network.target</filename>, but in parallel with
|
||||||
services.</para>
|
most other regular system services.</para>
|
||||||
|
|
||||||
<para>Support for <filename>/etc/rc.local</filename> is provided
|
<para>Support for <filename>&RC_LOCAL_PATH;</filename> is provided for compatibility with specific System
|
||||||
for compatibility with specific System V systems only. However, it is strongly recommended to avoid making use of
|
V systems only. However, it is strongly recommended to avoid making use of this script today, and instead
|
||||||
this script today, and instead provide proper unit files with appropriate dependencies for any scripts to run
|
provide proper unit files with appropriate dependencies for any scripts to run during the boot process.
|
||||||
during the boot process.</para>
|
Note that the path to the script is set a compile time and varies between distributions.</para>
|
||||||
|
|
||||||
<para><filename>systemd-rc-local-generator</filename> implements
|
<para><filename>systemd-rc-local-generator</filename> implements
|
||||||
<citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
|
<citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
|
||||||
|
|
|
@ -1888,7 +1888,8 @@ RestrictNamespaces=~cgroup net</programlisting>
|
||||||
<constant>EACCES</constant> or <constant>EUCLEAN</constant> (see <citerefentry
|
<constant>EACCES</constant> or <constant>EUCLEAN</constant> (see <citerefentry
|
||||||
project='man-pages'><refentrytitle>errno</refentrytitle><manvolnum>3</manvolnum></citerefentry> for a
|
project='man-pages'><refentrytitle>errno</refentrytitle><manvolnum>3</manvolnum></citerefentry> for a
|
||||||
full list). This value will be returned when a deny-listed system call is triggered, instead of
|
full list). This value will be returned when a deny-listed system call is triggered, instead of
|
||||||
terminating the processes immediately. This value takes precedence over the one given in
|
terminating the processes immediately. Special setting <literal>kill</literal> can be used to
|
||||||
|
explicitly specify killing. This value takes precedence over the one given in
|
||||||
<varname>SystemCallErrorNumber=</varname>, see below. If running in user mode, or in system mode,
|
<varname>SystemCallErrorNumber=</varname>, see below. If running in user mode, or in system mode,
|
||||||
but without the <constant>CAP_SYS_ADMIN</constant> capability (e.g. setting
|
but without the <constant>CAP_SYS_ADMIN</constant> capability (e.g. setting
|
||||||
<varname>User=nobody</varname>), <varname>NoNewPrivileges=yes</varname> is implied. This feature
|
<varname>User=nobody</varname>), <varname>NoNewPrivileges=yes</varname> is implied. This feature
|
||||||
|
@ -2098,8 +2099,9 @@ SystemCallErrorNumber=EPERM</programlisting>
|
||||||
return when the system call filter configured with <varname>SystemCallFilter=</varname> is triggered,
|
return when the system call filter configured with <varname>SystemCallFilter=</varname> is triggered,
|
||||||
instead of terminating the process immediately. See <citerefentry
|
instead of terminating the process immediately. See <citerefentry
|
||||||
project='man-pages'><refentrytitle>errno</refentrytitle><manvolnum>3</manvolnum></citerefentry> for a
|
project='man-pages'><refentrytitle>errno</refentrytitle><manvolnum>3</manvolnum></citerefentry> for a
|
||||||
full list of error codes. When this setting is not used, or when the empty string is assigned, the
|
full list of error codes. When this setting is not used, or when the empty string or the special
|
||||||
process will be terminated immediately when the filter is triggered.</para></listitem>
|
setting <literal>kill</literal> is assigned, the process will be terminated immediately when the
|
||||||
|
filter is triggered.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
@ -2134,6 +2136,21 @@ SystemCallErrorNumber=EPERM</programlisting>
|
||||||
details.</para></listitem>
|
details.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>SystemCallLog=</varname></term>
|
||||||
|
|
||||||
|
<listitem><para>Takes a space-separated list of system call names. If this setting is used, all
|
||||||
|
system calls executed by the unit processes for the listed ones will be logged. If the first
|
||||||
|
character of the list is <literal>~</literal>, the effect is inverted: all system calls except the
|
||||||
|
listed system calls will be logged. If running in user mode, or in system mode, but without the
|
||||||
|
<constant>CAP_SYS_ADMIN</constant> capability (e.g. setting <varname>User=nobody</varname>),
|
||||||
|
<varname>NoNewPrivileges=yes</varname> is implied. This feature makes use of the Secure Computing
|
||||||
|
Mode 2 interfaces of the kernel ('seccomp filtering') and is useful for auditing or setting up a
|
||||||
|
minimal sandboxing environment. This option may be specified more than once, in which case the filter
|
||||||
|
masks are merged. If the empty string is assigned, the filter is reset, all prior assignments will
|
||||||
|
have no effect. This does not affect commands prefixed with <literal>+</literal>.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
|
|
@ -212,7 +212,7 @@ conf.set_quoted('SYSTEM_CONFIG_UNIT_DIR', join_paths(pkgsysc
|
||||||
conf.set_quoted('SYSTEM_DATA_UNIT_PATH', systemunitdir)
|
conf.set_quoted('SYSTEM_DATA_UNIT_PATH', systemunitdir)
|
||||||
conf.set_quoted('SYSTEM_SYSVINIT_PATH', sysvinit_path)
|
conf.set_quoted('SYSTEM_SYSVINIT_PATH', sysvinit_path)
|
||||||
conf.set_quoted('SYSTEM_SYSVRCND_PATH', sysvrcnd_path)
|
conf.set_quoted('SYSTEM_SYSVRCND_PATH', sysvrcnd_path)
|
||||||
conf.set_quoted('RC_LOCAL_SCRIPT_PATH_START', get_option('rc-local'))
|
conf.set_quoted('RC_LOCAL_PATH', get_option('rc-local'))
|
||||||
|
|
||||||
conf.set('ANSI_OK_COLOR', 'ANSI_' + get_option('ok-color').underscorify().to_upper())
|
conf.set('ANSI_OK_COLOR', 'ANSI_' + get_option('ok-color').underscorify().to_upper())
|
||||||
|
|
||||||
|
@ -299,7 +299,7 @@ substs.set('CERTIFICATEROOT', get_option('certif
|
||||||
substs.set('RANDOM_SEED', join_paths(randomseeddir, 'random-seed'))
|
substs.set('RANDOM_SEED', join_paths(randomseeddir, 'random-seed'))
|
||||||
substs.set('SYSTEM_SYSVINIT_PATH', sysvinit_path)
|
substs.set('SYSTEM_SYSVINIT_PATH', sysvinit_path)
|
||||||
substs.set('SYSTEM_SYSVRCND_PATH', sysvrcnd_path)
|
substs.set('SYSTEM_SYSVRCND_PATH', sysvrcnd_path)
|
||||||
substs.set('RC_LOCAL_SCRIPT_PATH_START', get_option('rc-local'))
|
substs.set('RC_LOCAL_PATH', get_option('rc-local'))
|
||||||
substs.set('MEMORY_ACCOUNTING_DEFAULT', memory_accounting_default ? 'yes' : 'no')
|
substs.set('MEMORY_ACCOUNTING_DEFAULT', memory_accounting_default ? 'yes' : 'no')
|
||||||
substs.set('STATUS_UNIT_FORMAT_DEFAULT', status_unit_format_default)
|
substs.set('STATUS_UNIT_FORMAT_DEFAULT', status_unit_format_default)
|
||||||
substs.set('HIGH_RLIMIT_NOFILE', conf.get('HIGH_RLIMIT_NOFILE'))
|
substs.set('HIGH_RLIMIT_NOFILE', conf.get('HIGH_RLIMIT_NOFILE'))
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
#include "missing_network.h"
|
#include "missing_network.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
|
#if HAVE_SECCOMP
|
||||||
|
#include "seccomp-util.h"
|
||||||
|
#endif
|
||||||
#include "stat-util.h"
|
#include "stat-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
|
@ -314,6 +317,7 @@ int parse_errno(const char *t) {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if HAVE_SECCOMP
|
||||||
int parse_syscall_and_errno(const char *in, char **name, int *error) {
|
int parse_syscall_and_errno(const char *in, char **name, int *error) {
|
||||||
_cleanup_free_ char *n = NULL;
|
_cleanup_free_ char *n = NULL;
|
||||||
char *p;
|
char *p;
|
||||||
|
@ -332,7 +336,7 @@ int parse_syscall_and_errno(const char *in, char **name, int *error) {
|
||||||
|
|
||||||
p = strchr(in, ':');
|
p = strchr(in, ':');
|
||||||
if (p) {
|
if (p) {
|
||||||
e = parse_errno(p + 1);
|
e = seccomp_parse_errno_or_action(p + 1);
|
||||||
if (e < 0)
|
if (e < 0)
|
||||||
return e;
|
return e;
|
||||||
|
|
||||||
|
@ -351,6 +355,7 @@ int parse_syscall_and_errno(const char *in, char **name, int *error) {
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static const char *mangle_base(const char *s, unsigned *base) {
|
static const char *mangle_base(const char *s, unsigned *base) {
|
||||||
const char *k;
|
const char *k;
|
||||||
|
|
|
@ -19,7 +19,9 @@ int parse_mtu(int family, const char *s, uint32_t *ret);
|
||||||
int parse_size(const char *t, uint64_t base, uint64_t *size);
|
int parse_size(const char *t, uint64_t base, uint64_t *size);
|
||||||
int parse_range(const char *t, unsigned *lower, unsigned *upper);
|
int parse_range(const char *t, unsigned *lower, unsigned *upper);
|
||||||
int parse_errno(const char *t);
|
int parse_errno(const char *t);
|
||||||
|
#if HAVE_SECCOMP
|
||||||
int parse_syscall_and_errno(const char *in, char **name, int *error);
|
int parse_syscall_and_errno(const char *in, char **name, int *error);
|
||||||
|
#endif
|
||||||
|
|
||||||
#define SAFE_ATO_REFUSE_PLUS_MINUS (1U << 30)
|
#define SAFE_ATO_REFUSE_PLUS_MINUS (1U << 30)
|
||||||
#define SAFE_ATO_REFUSE_LEADING_ZERO (1U << 29)
|
#define SAFE_ATO_REFUSE_LEADING_ZERO (1U << 29)
|
||||||
|
|
|
@ -387,7 +387,7 @@ static int property_get_syscall_filter(
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (num >= 0) {
|
if (num >= 0) {
|
||||||
e = errno_to_name(num);
|
e = seccomp_errno_or_action_to_string(num);
|
||||||
if (e) {
|
if (e) {
|
||||||
s = strjoin(name, ":", e);
|
s = strjoin(name, ":", e);
|
||||||
if (!s)
|
if (!s)
|
||||||
|
@ -415,6 +415,58 @@ static int property_get_syscall_filter(
|
||||||
return sd_bus_message_close_container(reply);
|
return sd_bus_message_close_container(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int property_get_syscall_log(
|
||||||
|
sd_bus *bus,
|
||||||
|
const char *path,
|
||||||
|
const char *interface,
|
||||||
|
const char *property,
|
||||||
|
sd_bus_message *reply,
|
||||||
|
void *userdata,
|
||||||
|
sd_bus_error *error) {
|
||||||
|
|
||||||
|
ExecContext *c = userdata;
|
||||||
|
_cleanup_strv_free_ char **l = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
#if HAVE_SECCOMP
|
||||||
|
void *id, *val;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert(bus);
|
||||||
|
assert(reply);
|
||||||
|
assert(c);
|
||||||
|
|
||||||
|
r = sd_bus_message_open_container(reply, 'r', "bas");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = sd_bus_message_append(reply, "b", c->syscall_log_allow_list);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
#if HAVE_SECCOMP
|
||||||
|
HASHMAP_FOREACH_KEY(val, id, c->syscall_log) {
|
||||||
|
char *name = NULL;
|
||||||
|
|
||||||
|
name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
|
||||||
|
if (!name)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
r = strv_consume(&l, name);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
strv_sort(l);
|
||||||
|
|
||||||
|
r = sd_bus_message_append_strv(reply, l);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return sd_bus_message_close_container(reply);
|
||||||
|
}
|
||||||
|
|
||||||
static int property_get_syscall_archs(
|
static int property_get_syscall_archs(
|
||||||
sd_bus *bus,
|
sd_bus *bus,
|
||||||
const char *path,
|
const char *path,
|
||||||
|
@ -1068,6 +1120,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
|
||||||
SD_BUS_PROPERTY("SystemCallFilter", "(bas)", property_get_syscall_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("SystemCallFilter", "(bas)", property_get_syscall_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("SystemCallArchitectures", "as", property_get_syscall_archs, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("SystemCallArchitectures", "as", property_get_syscall_archs, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("SystemCallErrorNumber", "i", bus_property_get_int, offsetof(ExecContext, syscall_errno), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("SystemCallErrorNumber", "i", bus_property_get_int, offsetof(ExecContext, syscall_errno), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
SD_BUS_PROPERTY("SystemCallLog", "(bas)", property_get_syscall_log, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("Personality", "s", property_get_personality, offsetof(ExecContext, personality), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("Personality", "s", property_get_personality, offsetof(ExecContext, personality), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("LockPersonality", "b", bus_property_get_bool, offsetof(ExecContext, lock_personality), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("LockPersonality", "b", bus_property_get_bool, offsetof(ExecContext, lock_personality), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("RestrictAddressFamilies", "(bas)", property_get_address_families, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("RestrictAddressFamilies", "(bas)", property_get_address_families, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
@ -1424,7 +1477,7 @@ static const char* mount_propagation_flags_to_string_with_check(unsigned long n)
|
||||||
static BUS_DEFINE_SET_TRANSIENT(nsec, "t", uint64_t, nsec_t, NSEC_FMT);
|
static BUS_DEFINE_SET_TRANSIENT(nsec, "t", uint64_t, nsec_t, NSEC_FMT);
|
||||||
static BUS_DEFINE_SET_TRANSIENT_IS_VALID(log_level, "i", int32_t, int, "%" PRIi32, log_level_is_valid);
|
static BUS_DEFINE_SET_TRANSIENT_IS_VALID(log_level, "i", int32_t, int, "%" PRIi32, log_level_is_valid);
|
||||||
#if HAVE_SECCOMP
|
#if HAVE_SECCOMP
|
||||||
static BUS_DEFINE_SET_TRANSIENT_IS_VALID(errno, "i", int32_t, int, "%" PRIi32, errno_is_valid);
|
static BUS_DEFINE_SET_TRANSIENT_IS_VALID(errno, "i", int32_t, int, "%" PRIi32, seccomp_errno_or_action_is_valid);
|
||||||
#endif
|
#endif
|
||||||
static BUS_DEFINE_SET_TRANSIENT_PARSE(std_input, ExecInput, exec_input_from_string);
|
static BUS_DEFINE_SET_TRANSIENT_PARSE(std_input, ExecInput, exec_input_from_string);
|
||||||
static BUS_DEFINE_SET_TRANSIENT_PARSE(std_output, ExecOutput, exec_output_from_string);
|
static BUS_DEFINE_SET_TRANSIENT_PARSE(std_output, ExecOutput, exec_output_from_string);
|
||||||
|
@ -1460,7 +1513,7 @@ static int read_mount_options(sd_bus_message *message, sd_bus_error *error, Moun
|
||||||
while ((r = sd_bus_message_read(message, "(ss)", &partition, &mount_options)) > 0) {
|
while ((r = sd_bus_message_read(message, "(ss)", &partition, &mount_options)) > 0) {
|
||||||
_cleanup_free_ char *previous = NULL, *escaped = NULL;
|
_cleanup_free_ char *previous = NULL, *escaped = NULL;
|
||||||
_cleanup_free_ MountOptions *o = NULL;
|
_cleanup_free_ MountOptions *o = NULL;
|
||||||
int partition_designator;
|
PartitionDesignator partition_designator;
|
||||||
|
|
||||||
if (chars_intersect(mount_options, WHITESPACE))
|
if (chars_intersect(mount_options, WHITESPACE))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||||
|
@ -2230,6 +2283,76 @@ int bus_exec_context_set_transient_property(
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
} else if (streq(name, "SystemCallLog")) {
|
||||||
|
int allow_list;
|
||||||
|
_cleanup_strv_free_ char **l = NULL;
|
||||||
|
|
||||||
|
r = sd_bus_message_enter_container(message, 'r', "bas");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = sd_bus_message_read(message, "b", &allow_list);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = sd_bus_message_read_strv(message, &l);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = sd_bus_message_exit_container(message);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||||
|
_cleanup_free_ char *joined = NULL;
|
||||||
|
SeccompParseFlags invert_flag = allow_list ? 0 : SECCOMP_PARSE_INVERT;
|
||||||
|
char **s;
|
||||||
|
|
||||||
|
if (strv_isempty(l)) {
|
||||||
|
c->syscall_log_allow_list = false;
|
||||||
|
c->syscall_log = hashmap_free(c->syscall_log);
|
||||||
|
|
||||||
|
unit_write_settingf(u, flags, name, "SystemCallLog=");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!c->syscall_log) {
|
||||||
|
c->syscall_log = hashmap_new(NULL);
|
||||||
|
if (!c->syscall_log)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
c->syscall_log_allow_list = allow_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
STRV_FOREACH(s, l) {
|
||||||
|
_cleanup_free_ char *n = NULL;
|
||||||
|
int e;
|
||||||
|
|
||||||
|
r = parse_syscall_and_errno(*s, &n, &e);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = seccomp_parse_syscall_filter(n,
|
||||||
|
0, /* errno not used */
|
||||||
|
c->syscall_log,
|
||||||
|
SECCOMP_PARSE_LOG | SECCOMP_PARSE_PERMISSIVE |
|
||||||
|
invert_flag |
|
||||||
|
(c->syscall_log_allow_list ? SECCOMP_PARSE_ALLOW_LIST : 0),
|
||||||
|
u->id,
|
||||||
|
NULL, 0);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
joined = strv_join(l, " ");
|
||||||
|
if (!joined)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
unit_write_settingf(u, flags, name, "SystemCallLog=%s%s", allow_list ? "" : "~", joined);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
} else if (streq(name, "SystemCallArchitectures")) {
|
} else if (streq(name, "SystemCallArchitectures")) {
|
||||||
_cleanup_strv_free_ char **l = NULL;
|
_cleanup_strv_free_ char **l = NULL;
|
||||||
|
|
||||||
|
|
|
@ -1407,6 +1407,13 @@ static bool context_has_syscall_filters(const ExecContext *c) {
|
||||||
!hashmap_isempty(c->syscall_filter);
|
!hashmap_isempty(c->syscall_filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool context_has_syscall_logs(const ExecContext *c) {
|
||||||
|
assert(c);
|
||||||
|
|
||||||
|
return c->syscall_log_allow_list ||
|
||||||
|
!hashmap_isempty(c->syscall_log);
|
||||||
|
}
|
||||||
|
|
||||||
static bool context_has_no_new_privileges(const ExecContext *c) {
|
static bool context_has_no_new_privileges(const ExecContext *c) {
|
||||||
assert(c);
|
assert(c);
|
||||||
|
|
||||||
|
@ -1428,6 +1435,7 @@ static bool context_has_no_new_privileges(const ExecContext *c) {
|
||||||
c->protect_kernel_logs ||
|
c->protect_kernel_logs ||
|
||||||
c->private_devices ||
|
c->private_devices ||
|
||||||
context_has_syscall_filters(c) ||
|
context_has_syscall_filters(c) ||
|
||||||
|
context_has_syscall_logs(c) ||
|
||||||
!set_isempty(c->syscall_archs) ||
|
!set_isempty(c->syscall_archs) ||
|
||||||
c->lock_personality ||
|
c->lock_personality ||
|
||||||
c->protect_hostname;
|
c->protect_hostname;
|
||||||
|
@ -1465,7 +1473,7 @@ static int apply_syscall_filter(const Unit* u, const ExecContext *c, bool needs_
|
||||||
if (skip_seccomp_unavailable(u, "SystemCallFilter="))
|
if (skip_seccomp_unavailable(u, "SystemCallFilter="))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
negative_action = c->syscall_errno == 0 ? scmp_act_kill_process() : SCMP_ACT_ERRNO(c->syscall_errno);
|
negative_action = c->syscall_errno == SECCOMP_ERROR_NUMBER_KILL ? scmp_act_kill_process() : SCMP_ACT_ERRNO(c->syscall_errno);
|
||||||
|
|
||||||
if (c->syscall_allow_list) {
|
if (c->syscall_allow_list) {
|
||||||
default_action = negative_action;
|
default_action = negative_action;
|
||||||
|
@ -1484,6 +1492,39 @@ static int apply_syscall_filter(const Unit* u, const ExecContext *c, bool needs_
|
||||||
return seccomp_load_syscall_filter_set_raw(default_action, c->syscall_filter, action, false);
|
return seccomp_load_syscall_filter_set_raw(default_action, c->syscall_filter, action, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int apply_syscall_log(const Unit* u, const ExecContext *c) {
|
||||||
|
#ifdef SCMP_ACT_LOG
|
||||||
|
uint32_t default_action, action;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert(u);
|
||||||
|
assert(c);
|
||||||
|
|
||||||
|
if (!context_has_syscall_logs(c))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#ifdef SCMP_ACT_LOG
|
||||||
|
if (skip_seccomp_unavailable(u, "SystemCallLog="))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (c->syscall_log_allow_list) {
|
||||||
|
/* Log nothing but the ones listed */
|
||||||
|
default_action = SCMP_ACT_ALLOW;
|
||||||
|
action = SCMP_ACT_LOG;
|
||||||
|
} else {
|
||||||
|
/* Log everything but the ones listed */
|
||||||
|
default_action = SCMP_ACT_LOG;
|
||||||
|
action = SCMP_ACT_ALLOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
return seccomp_load_syscall_filter_set_raw(default_action, c->syscall_log, action, false);
|
||||||
|
#else
|
||||||
|
/* old libseccomp */
|
||||||
|
log_unit_debug(u, "SECCOMP feature SCMP_ACT_LOG not available, skipping SystemCallLog=");
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static int apply_syscall_archs(const Unit *u, const ExecContext *c) {
|
static int apply_syscall_archs(const Unit *u, const ExecContext *c) {
|
||||||
assert(u);
|
assert(u);
|
||||||
assert(c);
|
assert(c);
|
||||||
|
@ -4438,6 +4479,12 @@ static int exec_child(
|
||||||
return log_unit_error_errno(unit, r, "Failed to lock personalities: %m");
|
return log_unit_error_errno(unit, r, "Failed to lock personalities: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = apply_syscall_log(unit, context);
|
||||||
|
if (r < 0) {
|
||||||
|
*exit_status = EXIT_SECCOMP;
|
||||||
|
return log_unit_error_errno(unit, r, "Failed to apply system call log filters: %m");
|
||||||
|
}
|
||||||
|
|
||||||
/* This really should remain the last step before the execve(), to make sure our own code is unaffected
|
/* This really should remain the last step before the execve(), to make sure our own code is unaffected
|
||||||
* by the filter as little as possible. */
|
* by the filter as little as possible. */
|
||||||
r = apply_syscall_filter(unit, context, needs_ambient_hack);
|
r = apply_syscall_filter(unit, context, needs_ambient_hack);
|
||||||
|
@ -4675,6 +4722,9 @@ void exec_context_init(ExecContext *c) {
|
||||||
assert_cc(NAMESPACE_FLAGS_INITIAL != NAMESPACE_FLAGS_ALL);
|
assert_cc(NAMESPACE_FLAGS_INITIAL != NAMESPACE_FLAGS_ALL);
|
||||||
c->restrict_namespaces = NAMESPACE_FLAGS_INITIAL;
|
c->restrict_namespaces = NAMESPACE_FLAGS_INITIAL;
|
||||||
c->log_level_max = -1;
|
c->log_level_max = -1;
|
||||||
|
#if HAVE_SECCOMP
|
||||||
|
c->syscall_errno = SECCOMP_ERROR_NUMBER_KILL;
|
||||||
|
#endif
|
||||||
numa_policy_reset(&c->numa_policy);
|
numa_policy_reset(&c->numa_policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5474,7 +5524,7 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
|
||||||
fputs(strna(name), f);
|
fputs(strna(name), f);
|
||||||
|
|
||||||
if (num >= 0) {
|
if (num >= 0) {
|
||||||
errno_name = errno_to_name(num);
|
errno_name = seccomp_errno_or_action_to_string(num);
|
||||||
if (errno_name)
|
if (errno_name)
|
||||||
fprintf(f, ":%s", errno_name);
|
fprintf(f, ":%s", errno_name);
|
||||||
else
|
else
|
||||||
|
@ -5517,15 +5567,20 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
|
||||||
prefix, c->network_namespace_path);
|
prefix, c->network_namespace_path);
|
||||||
|
|
||||||
if (c->syscall_errno > 0) {
|
if (c->syscall_errno > 0) {
|
||||||
|
#if HAVE_SECCOMP
|
||||||
const char *errno_name;
|
const char *errno_name;
|
||||||
|
#endif
|
||||||
|
|
||||||
fprintf(f, "%sSystemCallErrorNumber: ", prefix);
|
fprintf(f, "%sSystemCallErrorNumber: ", prefix);
|
||||||
|
|
||||||
errno_name = errno_to_name(c->syscall_errno);
|
#if HAVE_SECCOMP
|
||||||
|
errno_name = seccomp_errno_or_action_to_string(c->syscall_errno);
|
||||||
if (errno_name)
|
if (errno_name)
|
||||||
fprintf(f, "%s\n", errno_name);
|
fputs(errno_name, f);
|
||||||
else
|
else
|
||||||
fprintf(f, "%d\n", c->syscall_errno);
|
fprintf(f, "%d", c->syscall_errno);
|
||||||
|
#endif
|
||||||
|
fputc('\n', f);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < c->n_mount_images; i++) {
|
for (size_t i = 0; i < c->n_mount_images; i++) {
|
||||||
|
|
|
@ -302,6 +302,9 @@ struct ExecContext {
|
||||||
int syscall_errno;
|
int syscall_errno;
|
||||||
bool syscall_allow_list:1;
|
bool syscall_allow_list:1;
|
||||||
|
|
||||||
|
Hashmap *syscall_log;
|
||||||
|
bool syscall_log_allow_list:1; /* Log listed system calls */
|
||||||
|
|
||||||
bool address_families_allow_list:1;
|
bool address_families_allow_list:1;
|
||||||
Set *address_families;
|
Set *address_families;
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,7 @@ m4_ifdef(`HAVE_SECCOMP',
|
||||||
`$1.SystemCallFilter, config_parse_syscall_filter, 0, offsetof($1, exec_context)
|
`$1.SystemCallFilter, config_parse_syscall_filter, 0, offsetof($1, exec_context)
|
||||||
$1.SystemCallArchitectures, config_parse_syscall_archs, 0, offsetof($1, exec_context.syscall_archs)
|
$1.SystemCallArchitectures, config_parse_syscall_archs, 0, offsetof($1, exec_context.syscall_archs)
|
||||||
$1.SystemCallErrorNumber, config_parse_syscall_errno, 0, offsetof($1, exec_context)
|
$1.SystemCallErrorNumber, config_parse_syscall_errno, 0, offsetof($1, exec_context)
|
||||||
|
$1.SystemCallLog, config_parse_syscall_log, 0, offsetof($1, exec_context)
|
||||||
$1.MemoryDenyWriteExecute, config_parse_bool, 0, offsetof($1, exec_context.memory_deny_write_execute)
|
$1.MemoryDenyWriteExecute, config_parse_bool, 0, offsetof($1, exec_context.memory_deny_write_execute)
|
||||||
$1.RestrictNamespaces, config_parse_restrict_namespaces, 0, offsetof($1, exec_context)
|
$1.RestrictNamespaces, config_parse_restrict_namespaces, 0, offsetof($1, exec_context)
|
||||||
$1.RestrictRealtime, config_parse_bool, 0, offsetof($1, exec_context.restrict_realtime)
|
$1.RestrictRealtime, config_parse_bool, 0, offsetof($1, exec_context.restrict_realtime)
|
||||||
|
@ -88,6 +89,7 @@ $1.LockPersonality, config_parse_bool, 0,
|
||||||
`$1.SystemCallFilter, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
|
`$1.SystemCallFilter, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
|
||||||
$1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
|
$1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
|
||||||
$1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
|
$1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
|
||||||
|
$1.SystemCallLog, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
|
||||||
$1.MemoryDenyWriteExecute, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
|
$1.MemoryDenyWriteExecute, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
|
||||||
$1.RestrictNamespaces, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
|
$1.RestrictNamespaces, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
|
||||||
$1.RestrictRealtime, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
|
$1.RestrictRealtime, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
|
||||||
|
|
|
@ -1483,7 +1483,7 @@ int config_parse_root_image_options(
|
||||||
MountOptions *o = NULL;
|
MountOptions *o = NULL;
|
||||||
_cleanup_free_ char *mount_options_resolved = NULL;
|
_cleanup_free_ char *mount_options_resolved = NULL;
|
||||||
const char *mount_options = NULL, *partition = "root";
|
const char *mount_options = NULL, *partition = "root";
|
||||||
int partition_designator;
|
PartitionDesignator partition_designator;
|
||||||
|
|
||||||
/* Format is either 'root:foo' or 'foo' (root is implied) */
|
/* Format is either 'root:foo' or 'foo' (root is implied) */
|
||||||
if (!isempty(*second)) {
|
if (!isempty(*second)) {
|
||||||
|
@ -3197,6 +3197,86 @@ int config_parse_syscall_filter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int config_parse_syscall_log(
|
||||||
|
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) {
|
||||||
|
|
||||||
|
ExecContext *c = data;
|
||||||
|
_unused_ const Unit *u = userdata;
|
||||||
|
bool invert = false;
|
||||||
|
const char *p;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(filename);
|
||||||
|
assert(lvalue);
|
||||||
|
assert(rvalue);
|
||||||
|
assert(u);
|
||||||
|
|
||||||
|
if (isempty(rvalue)) {
|
||||||
|
/* Empty assignment resets the list */
|
||||||
|
c->syscall_log = hashmap_free(c->syscall_log);
|
||||||
|
c->syscall_log_allow_list = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rvalue[0] == '~') {
|
||||||
|
invert = true;
|
||||||
|
rvalue++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!c->syscall_log) {
|
||||||
|
c->syscall_log = hashmap_new(NULL);
|
||||||
|
if (!c->syscall_log)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
if (invert)
|
||||||
|
/* Log everything but the ones listed */
|
||||||
|
c->syscall_log_allow_list = false;
|
||||||
|
else
|
||||||
|
/* Log nothing but the ones listed */
|
||||||
|
c->syscall_log_allow_list = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = rvalue;
|
||||||
|
for (;;) {
|
||||||
|
_cleanup_free_ char *word = NULL, *name = NULL;
|
||||||
|
int num;
|
||||||
|
|
||||||
|
r = extract_first_word(&p, &word, NULL, 0);
|
||||||
|
if (r == 0)
|
||||||
|
return 0;
|
||||||
|
if (r == -ENOMEM)
|
||||||
|
return log_oom();
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = parse_syscall_and_errno(word, &name, &num);
|
||||||
|
if (r < 0 || num >= 0) { /* errno code not allowed */
|
||||||
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse syscall, ignoring: %s", word);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = seccomp_parse_syscall_filter(
|
||||||
|
name, 0, c->syscall_log,
|
||||||
|
SECCOMP_PARSE_LOG|SECCOMP_PARSE_PERMISSIVE|
|
||||||
|
(invert ? SECCOMP_PARSE_INVERT : 0)|
|
||||||
|
(c->syscall_log_allow_list ? SECCOMP_PARSE_ALLOW_LIST : 0),
|
||||||
|
unit, filename, line);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int config_parse_syscall_archs(
|
int config_parse_syscall_archs(
|
||||||
const char *unit,
|
const char *unit,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
|
@ -3264,9 +3344,9 @@ int config_parse_syscall_errno(
|
||||||
assert(lvalue);
|
assert(lvalue);
|
||||||
assert(rvalue);
|
assert(rvalue);
|
||||||
|
|
||||||
if (isempty(rvalue)) {
|
if (isempty(rvalue) || streq(rvalue, "kill")) {
|
||||||
/* Empty assignment resets to KILL */
|
/* Empty assignment resets to KILL */
|
||||||
c->syscall_errno = 0;
|
c->syscall_errno = SECCOMP_ERROR_NUMBER_KILL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4866,7 +4946,7 @@ int config_parse_mount_images(
|
||||||
for (;;) {
|
for (;;) {
|
||||||
_cleanup_free_ char *partition = NULL, *mount_options = NULL, *mount_options_resolved = NULL;
|
_cleanup_free_ char *partition = NULL, *mount_options = NULL, *mount_options_resolved = NULL;
|
||||||
MountOptions *o = NULL;
|
MountOptions *o = NULL;
|
||||||
int partition_designator;
|
PartitionDesignator partition_designator;
|
||||||
|
|
||||||
r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
|
r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
|
||||||
if (r == -ENOMEM)
|
if (r == -ENOMEM)
|
||||||
|
@ -5444,6 +5524,7 @@ void unit_dump_config_items(FILE *f) {
|
||||||
{ config_parse_syscall_filter, "SYSCALLS" },
|
{ config_parse_syscall_filter, "SYSCALLS" },
|
||||||
{ config_parse_syscall_archs, "ARCHS" },
|
{ config_parse_syscall_archs, "ARCHS" },
|
||||||
{ config_parse_syscall_errno, "ERRNO" },
|
{ config_parse_syscall_errno, "ERRNO" },
|
||||||
|
{ config_parse_syscall_log, "SYSCALLS" },
|
||||||
{ config_parse_address_families, "FAMILIES" },
|
{ config_parse_address_families, "FAMILIES" },
|
||||||
{ config_parse_restrict_namespaces, "NAMESPACES" },
|
{ config_parse_restrict_namespaces, "NAMESPACES" },
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -65,6 +65,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_unit_requires_mounts_for);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_syscall_filter);
|
CONFIG_PARSER_PROTOTYPE(config_parse_syscall_filter);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_syscall_archs);
|
CONFIG_PARSER_PROTOTYPE(config_parse_syscall_archs);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_syscall_errno);
|
CONFIG_PARSER_PROTOTYPE(config_parse_syscall_errno);
|
||||||
|
CONFIG_PARSER_PROTOTYPE(config_parse_syscall_log);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_environ);
|
CONFIG_PARSER_PROTOTYPE(config_parse_environ);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_pass_environ);
|
CONFIG_PARSER_PROTOTYPE(config_parse_pass_environ);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_unset_environ);
|
CONFIG_PARSER_PROTOTYPE(config_parse_unset_environ);
|
||||||
|
|
|
@ -456,7 +456,7 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) {
|
||||||
(void) table_set_empty_string(t, "-");
|
(void) table_set_empty_string(t, "-");
|
||||||
(void) table_set_align_percent(t, table_get_cell(t, 0, 7), 100);
|
(void) table_set_align_percent(t, table_get_cell(t, 0, 7), 100);
|
||||||
|
|
||||||
for (unsigned i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
|
for (PartitionDesignator i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
|
||||||
DissectedPartition *p = m->partitions + i;
|
DissectedPartition *p = m->partitions + i;
|
||||||
|
|
||||||
if (!p->found)
|
if (!p->found)
|
||||||
|
|
|
@ -782,7 +782,6 @@ static int parse_tcp_address(sd_bus *b, const char **p, char **guid) {
|
||||||
int r;
|
int r;
|
||||||
struct addrinfo *result, hints = {
|
struct addrinfo *result, hints = {
|
||||||
.ai_socktype = SOCK_STREAM,
|
.ai_socktype = SOCK_STREAM,
|
||||||
.ai_flags = AI_ADDRCONFIG,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
assert(b);
|
assert(b);
|
||||||
|
|
|
@ -59,7 +59,7 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
|
||||||
|
|
||||||
assert_se(arg_dest = dest);
|
assert_se(arg_dest = dest);
|
||||||
|
|
||||||
if (check_executable(RC_LOCAL_SCRIPT_PATH_START) >= 0) {
|
if (check_executable(RC_LOCAL_PATH) >= 0) {
|
||||||
log_debug("Automatically adding rc-local.service.");
|
log_debug("Automatically adding rc-local.service.");
|
||||||
|
|
||||||
r = add_symlink("rc-local.service", "multi-user.target");
|
r = add_symlink("rc-local.service", "multi-user.target");
|
||||||
|
|
|
@ -30,6 +30,9 @@
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
#include "rlimit-util.h"
|
#include "rlimit-util.h"
|
||||||
|
#if HAVE_SECCOMP
|
||||||
|
#include "seccomp-util.h"
|
||||||
|
#endif
|
||||||
#include "securebits-util.h"
|
#include "securebits-util.h"
|
||||||
#include "signal-util.h"
|
#include "signal-util.h"
|
||||||
#include "socket-util.h"
|
#include "socket-util.h"
|
||||||
|
@ -107,7 +110,10 @@ DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string);
|
||||||
DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string);
|
DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string);
|
||||||
DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string);
|
DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string);
|
||||||
DEFINE_BUS_APPEND_PARSE("i", log_level_from_string);
|
DEFINE_BUS_APPEND_PARSE("i", log_level_from_string);
|
||||||
DEFINE_BUS_APPEND_PARSE("i", parse_errno);
|
#if !HAVE_SECCOMP
|
||||||
|
static inline int seccomp_parse_errno_or_action(const char *eq) { return -EINVAL; }
|
||||||
|
#endif
|
||||||
|
DEFINE_BUS_APPEND_PARSE("i", seccomp_parse_errno_or_action);
|
||||||
DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string);
|
DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string);
|
||||||
DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string);
|
DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string);
|
||||||
DEFINE_BUS_APPEND_PARSE("i", signal_from_string);
|
DEFINE_BUS_APPEND_PARSE("i", signal_from_string);
|
||||||
|
@ -927,7 +933,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
||||||
return bus_append_parse_nice(m, field, eq);
|
return bus_append_parse_nice(m, field, eq);
|
||||||
|
|
||||||
if (streq(field, "SystemCallErrorNumber"))
|
if (streq(field, "SystemCallErrorNumber"))
|
||||||
return bus_append_parse_errno(m, field, eq);
|
return bus_append_seccomp_parse_errno_or_action(m, field, eq);
|
||||||
|
|
||||||
if (streq(field, "IOSchedulingClass"))
|
if (streq(field, "IOSchedulingClass"))
|
||||||
return bus_append_ioprio_class_from_string(m, field, eq);
|
return bus_append_ioprio_class_from_string(m, field, eq);
|
||||||
|
@ -1293,7 +1299,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
||||||
}
|
}
|
||||||
|
|
||||||
if (STR_IN_SET(field, "RestrictAddressFamilies",
|
if (STR_IN_SET(field, "RestrictAddressFamilies",
|
||||||
"SystemCallFilter")) {
|
"SystemCallFilter",
|
||||||
|
"SystemCallLog")) {
|
||||||
int allow_list = 1;
|
int allow_list = 1;
|
||||||
const char *p = eq;
|
const char *p = eq;
|
||||||
|
|
||||||
|
|
|
@ -325,7 +325,6 @@ int dissect_image(
|
||||||
int r, generic_nr;
|
int r, generic_nr;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
sd_device *q;
|
sd_device *q;
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
@ -420,7 +419,7 @@ int dissect_image(
|
||||||
m->verity = root_hash && verity_data;
|
m->verity = root_hash && verity_data;
|
||||||
m->can_verity = !!verity_data;
|
m->can_verity = !!verity_data;
|
||||||
|
|
||||||
options = mount_options_from_part(mount_options, PARTITION_ROOT);
|
options = mount_options_from_designator(mount_options, PARTITION_ROOT);
|
||||||
if (options) {
|
if (options) {
|
||||||
o = strdup(options);
|
o = strdup(options);
|
||||||
if (!o)
|
if (!o)
|
||||||
|
@ -504,7 +503,8 @@ int dissect_image(
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (is_gpt) {
|
if (is_gpt) {
|
||||||
int designator = _PARTITION_DESIGNATOR_INVALID, architecture = _ARCHITECTURE_INVALID;
|
PartitionDesignator designator = _PARTITION_DESIGNATOR_INVALID;
|
||||||
|
int architecture = _ARCHITECTURE_INVALID;
|
||||||
const char *stype, *sid, *fstype = NULL;
|
const char *stype, *sid, *fstype = NULL;
|
||||||
sd_id128_t type_id, id;
|
sd_id128_t type_id, id;
|
||||||
bool rw = true;
|
bool rw = true;
|
||||||
|
@ -716,7 +716,7 @@ int dissect_image(
|
||||||
if (!n)
|
if (!n)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
options = mount_options_from_part(mount_options, designator);
|
options = mount_options_from_designator(mount_options, designator);
|
||||||
if (options) {
|
if (options) {
|
||||||
o = strdup(options);
|
o = strdup(options);
|
||||||
if (!o)
|
if (!o)
|
||||||
|
@ -773,7 +773,7 @@ int dissect_image(
|
||||||
if (!n)
|
if (!n)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
options = mount_options_from_part(mount_options, PARTITION_XBOOTLDR);
|
options = mount_options_from_designator(mount_options, PARTITION_XBOOTLDR);
|
||||||
if (options) {
|
if (options) {
|
||||||
o = strdup(options);
|
o = strdup(options);
|
||||||
if (!o)
|
if (!o)
|
||||||
|
@ -827,7 +827,7 @@ int dissect_image(
|
||||||
if (multiple_generic)
|
if (multiple_generic)
|
||||||
return -ENOTUNIQ;
|
return -ENOTUNIQ;
|
||||||
|
|
||||||
options = mount_options_from_part(mount_options, PARTITION_ROOT);
|
options = mount_options_from_designator(mount_options, PARTITION_ROOT);
|
||||||
if (options) {
|
if (options) {
|
||||||
o = strdup(options);
|
o = strdup(options);
|
||||||
if (!o)
|
if (!o)
|
||||||
|
@ -866,7 +866,7 @@ int dissect_image(
|
||||||
b = NULL;
|
b = NULL;
|
||||||
|
|
||||||
/* Fill in file system types if we don't know them yet. */
|
/* Fill in file system types if we don't know them yet. */
|
||||||
for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
|
for (PartitionDesignator i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
|
||||||
DissectedPartition *p = m->partitions + i;
|
DissectedPartition *p = m->partitions + i;
|
||||||
|
|
||||||
if (!p->found)
|
if (!p->found)
|
||||||
|
@ -894,12 +894,10 @@ int dissect_image(
|
||||||
}
|
}
|
||||||
|
|
||||||
DissectedImage* dissected_image_unref(DissectedImage *m) {
|
DissectedImage* dissected_image_unref(DissectedImage *m) {
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
if (!m)
|
if (!m)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
|
for (PartitionDesignator i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
|
||||||
free(m->partitions[i].fstype);
|
free(m->partitions[i].fstype);
|
||||||
free(m->partitions[i].node);
|
free(m->partitions[i].node);
|
||||||
free(m->partitions[i].decrypted_fstype);
|
free(m->partitions[i].decrypted_fstype);
|
||||||
|
@ -1557,7 +1555,6 @@ int dissected_image_decrypt(
|
||||||
|
|
||||||
#if HAVE_LIBCRYPTSETUP
|
#if HAVE_LIBCRYPTSETUP
|
||||||
_cleanup_(decrypted_image_unrefp) DecryptedImage *d = NULL;
|
_cleanup_(decrypted_image_unrefp) DecryptedImage *d = NULL;
|
||||||
unsigned i;
|
|
||||||
int r;
|
int r;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1585,7 +1582,7 @@ int dissected_image_decrypt(
|
||||||
if (!d)
|
if (!d)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
|
for (PartitionDesignator i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
|
||||||
DissectedPartition *p = m->partitions + i;
|
DissectedPartition *p = m->partitions + i;
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
|
@ -2039,14 +2036,14 @@ int dissect_image_and_warn(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dissected_image_can_do_verity(const DissectedImage *image, unsigned partition_designator) {
|
bool dissected_image_can_do_verity(const DissectedImage *image, PartitionDesignator partition_designator) {
|
||||||
if (image->single_file_system)
|
if (image->single_file_system)
|
||||||
return partition_designator == PARTITION_ROOT && image->can_verity;
|
return partition_designator == PARTITION_ROOT && image->can_verity;
|
||||||
|
|
||||||
return PARTITION_VERITY_OF(partition_designator) >= 0;
|
return PARTITION_VERITY_OF(partition_designator) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dissected_image_has_verity(const DissectedImage *image, unsigned partition_designator) {
|
bool dissected_image_has_verity(const DissectedImage *image, PartitionDesignator partition_designator) {
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
if (image->single_file_system)
|
if (image->single_file_system)
|
||||||
|
@ -2068,10 +2065,10 @@ MountOptions* mount_options_free_all(MountOptions *options) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* mount_options_from_part(const MountOptions *options, int designator) {
|
const char* mount_options_from_designator(const MountOptions *options, PartitionDesignator designator) {
|
||||||
MountOptions *m;
|
const MountOptions *m;
|
||||||
|
|
||||||
LIST_FOREACH(mount_options, m, (MountOptions *)options)
|
LIST_FOREACH(mount_options, m, options)
|
||||||
if (designator == m->partition_designator && !isempty(m->options))
|
if (designator == m->partition_designator && !isempty(m->options))
|
||||||
return m->options;
|
return m->options;
|
||||||
|
|
||||||
|
@ -2164,4 +2161,4 @@ static const char *const partition_designator_table[] = {
|
||||||
[PARTITION_VAR] = "var",
|
[PARTITION_VAR] = "var",
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_STRING_TABLE_LOOKUP(partition_designator, int);
|
DEFINE_STRING_TABLE_LOOKUP(partition_designator, PartitionDesignator);
|
||||||
|
|
|
@ -27,7 +27,7 @@ struct DissectedPartition {
|
||||||
char *mount_options;
|
char *mount_options;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
typedef enum PartitionDesignator {
|
||||||
PARTITION_ROOT,
|
PARTITION_ROOT,
|
||||||
PARTITION_ROOT_SECONDARY, /* Secondary architecture */
|
PARTITION_ROOT_SECONDARY, /* Secondary architecture */
|
||||||
PARTITION_HOME,
|
PARTITION_HOME,
|
||||||
|
@ -41,9 +41,9 @@ enum {
|
||||||
PARTITION_VAR,
|
PARTITION_VAR,
|
||||||
_PARTITION_DESIGNATOR_MAX,
|
_PARTITION_DESIGNATOR_MAX,
|
||||||
_PARTITION_DESIGNATOR_INVALID = -1
|
_PARTITION_DESIGNATOR_INVALID = -1
|
||||||
};
|
} PartitionDesignator;
|
||||||
|
|
||||||
static inline int PARTITION_VERITY_OF(int p) {
|
static inline PartitionDesignator PARTITION_VERITY_OF(PartitionDesignator p) {
|
||||||
if (p == PARTITION_ROOT)
|
if (p == PARTITION_ROOT)
|
||||||
return PARTITION_ROOT_VERITY;
|
return PARTITION_ROOT_VERITY;
|
||||||
if (p == PARTITION_ROOT_SECONDARY)
|
if (p == PARTITION_ROOT_SECONDARY)
|
||||||
|
@ -87,14 +87,14 @@ struct DissectedImage {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MountOptions {
|
struct MountOptions {
|
||||||
int partition_designator;
|
PartitionDesignator partition_designator;
|
||||||
char *options;
|
char *options;
|
||||||
LIST_FIELDS(MountOptions, mount_options);
|
LIST_FIELDS(MountOptions, mount_options);
|
||||||
};
|
};
|
||||||
|
|
||||||
MountOptions* mount_options_free_all(MountOptions *options);
|
MountOptions* mount_options_free_all(MountOptions *options);
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(MountOptions*, mount_options_free_all);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(MountOptions*, mount_options_free_all);
|
||||||
const char* mount_options_from_part(const MountOptions *options, int designator);
|
const char* mount_options_from_designator(const MountOptions *options, PartitionDesignator designator);
|
||||||
|
|
||||||
int probe_filesystem(const char *node, char **ret_fstype);
|
int probe_filesystem(const char *node, char **ret_fstype);
|
||||||
int dissect_image(int fd, const void *root_hash, size_t root_hash_size, const char *verity_data, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret);
|
int dissect_image(int fd, const void *root_hash, size_t root_hash_size, const char *verity_data, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret);
|
||||||
|
@ -114,11 +114,11 @@ DecryptedImage* decrypted_image_unref(DecryptedImage *p);
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DecryptedImage*, decrypted_image_unref);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(DecryptedImage*, decrypted_image_unref);
|
||||||
int decrypted_image_relinquish(DecryptedImage *d);
|
int decrypted_image_relinquish(DecryptedImage *d);
|
||||||
|
|
||||||
const char* partition_designator_to_string(int i) _const_;
|
const char* partition_designator_to_string(PartitionDesignator d) _const_;
|
||||||
int partition_designator_from_string(const char *name) _pure_;
|
PartitionDesignator partition_designator_from_string(const char *name) _pure_;
|
||||||
|
|
||||||
int verity_metadata_load(const char *image, const char *root_hash_path, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data, char **ret_roothashsig);
|
int verity_metadata_load(const char *image, const char *root_hash_path, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data, char **ret_roothashsig);
|
||||||
bool dissected_image_can_do_verity(const DissectedImage *image, unsigned partition_designator);
|
bool dissected_image_can_do_verity(const DissectedImage *image, PartitionDesignator d);
|
||||||
bool dissected_image_has_verity(const DissectedImage *image, unsigned partition_designator);
|
bool dissected_image_has_verity(const DissectedImage *image, PartitionDesignator d);
|
||||||
|
|
||||||
int mount_image_privately_interactively(const char *path, DissectImageFlags flags, char **ret_directory, LoopDevice **ret_loop_device, DecryptedImage **ret_decrypted_image);
|
int mount_image_privately_interactively(const char *path, DissectImageFlags flags, char **ret_directory, LoopDevice **ret_loop_device, DecryptedImage **ret_decrypted_image);
|
||||||
|
|
|
@ -7,9 +7,8 @@
|
||||||
|
|
||||||
#include "id128-util.h"
|
#include "id128-util.h"
|
||||||
|
|
||||||
/* We only support root disk discovery for x86, x86-64, Itanium and ARM for
|
/* We only support root disk discovery for x86, x86-64, Itanium and ARM for now, since EFI for anything else
|
||||||
* now, since EFI for anything else doesn't really exist, and we only
|
* doesn't really exist, and we only care for root partitions on the same disk as the EFI ESP. */
|
||||||
* care for root partitions on the same disk as the EFI ESP. */
|
|
||||||
|
|
||||||
#define GPT_ROOT_X86 SD_ID128_MAKE(44,47,95,40,f2,97,41,b2,9a,f7,d1,31,d5,f0,45,8a)
|
#define GPT_ROOT_X86 SD_ID128_MAKE(44,47,95,40,f2,97,41,b2,9a,f7,d1,31,d5,f0,45,8a)
|
||||||
#define GPT_ROOT_X86_64 SD_ID128_MAKE(4f,68,bc,e3,e8,cd,4d,b1,96,e7,fb,ca,f9,84,b7,09)
|
#define GPT_ROOT_X86_64 SD_ID128_MAKE(4f,68,bc,e3,e8,cd,4d,b1,96,e7,fb,ca,f9,84,b7,09)
|
||||||
|
@ -24,9 +23,10 @@
|
||||||
#define GPT_VAR SD_ID128_MAKE(4d,21,b0,16,b5,34,45,c2,a9,fb,5c,16,e0,91,fd,2d)
|
#define GPT_VAR SD_ID128_MAKE(4d,21,b0,16,b5,34,45,c2,a9,fb,5c,16,e0,91,fd,2d)
|
||||||
#define GPT_TMP SD_ID128_MAKE(7e,c6,f5,57,3b,c5,4a,ca,b2,93,16,ef,5d,f6,39,d1)
|
#define GPT_TMP SD_ID128_MAKE(7e,c6,f5,57,3b,c5,4a,ca,b2,93,16,ef,5d,f6,39,d1)
|
||||||
#define GPT_USER_HOME SD_ID128_MAKE(77,3f,91,ef,66,d4,49,b5,bd,83,d6,83,bf,40,ad,16)
|
#define GPT_USER_HOME SD_ID128_MAKE(77,3f,91,ef,66,d4,49,b5,bd,83,d6,83,bf,40,ad,16)
|
||||||
|
#define GPT_LINUX_GENERIC SD_ID128_MAKE(0f,c6,3d,af,84,83,47,72,8e,79,3d,69,d8,47,7d,e4)
|
||||||
|
|
||||||
/* Verity partitions for the root partitions above (we only define them for the root partitions, because only they are
|
/* Verity partitions for the root partitions above (we only define them for the root partitions, because only
|
||||||
* are commonly read-only and hence suitable for verity). */
|
* they are are commonly read-only and hence suitable for verity). */
|
||||||
#define GPT_ROOT_X86_VERITY SD_ID128_MAKE(d1,3c,5d,3b,b5,d1,42,2a,b2,9f,94,54,fd,c8,9d,76)
|
#define GPT_ROOT_X86_VERITY SD_ID128_MAKE(d1,3c,5d,3b,b5,d1,42,2a,b2,9f,94,54,fd,c8,9d,76)
|
||||||
#define GPT_ROOT_X86_64_VERITY SD_ID128_MAKE(2c,73,57,ed,eb,d2,46,d9,ae,c1,23,d4,37,ec,2b,f5)
|
#define GPT_ROOT_X86_64_VERITY SD_ID128_MAKE(2c,73,57,ed,eb,d2,46,d9,ae,c1,23,d4,37,ec,2b,f5)
|
||||||
#define GPT_ROOT_ARM_VERITY SD_ID128_MAKE(73,86,cd,f2,20,3c,47,a9,a4,98,f2,ec,ce,45,a2,d6)
|
#define GPT_ROOT_ARM_VERITY SD_ID128_MAKE(73,86,cd,f2,20,3c,47,a9,a4,98,f2,ec,ce,45,a2,d6)
|
||||||
|
@ -62,15 +62,12 @@
|
||||||
#define GPT_FLAG_NO_BLOCK_IO_PROTOCOL (1ULL << 1)
|
#define GPT_FLAG_NO_BLOCK_IO_PROTOCOL (1ULL << 1)
|
||||||
#define GPT_FLAG_LEGACY_BIOS_BOOTABLE (1ULL << 2)
|
#define GPT_FLAG_LEGACY_BIOS_BOOTABLE (1ULL << 2)
|
||||||
|
|
||||||
/* Flags we recognize on the root, swap, home and srv partitions when
|
/* Flags we recognize on the root, swap, home and srv partitions when doing auto-discovery. These happen to
|
||||||
* doing auto-discovery. These happen to be identical to what
|
* be identical to what Microsoft defines for its own Basic Data Partitions, but that's just because we saw
|
||||||
* Microsoft defines for its own Basic Data Partitions, but that's
|
* no point in defining any other values here. */
|
||||||
* just because we saw no point in defining any other values here. */
|
|
||||||
#define GPT_FLAG_READ_ONLY (1ULL << 60)
|
#define GPT_FLAG_READ_ONLY (1ULL << 60)
|
||||||
#define GPT_FLAG_NO_AUTO (1ULL << 63)
|
#define GPT_FLAG_NO_AUTO (1ULL << 63)
|
||||||
|
|
||||||
#define GPT_LINUX_GENERIC SD_ID128_MAKE(0f,c6,3d,af,84,83,47,72,8e,79,3d,69,d8,47,7d,e4)
|
|
||||||
|
|
||||||
const char *gpt_partition_type_uuid_to_string(sd_id128_t id);
|
const char *gpt_partition_type_uuid_to_string(sd_id128_t id);
|
||||||
const char *gpt_partition_type_uuid_to_string_harder(
|
const char *gpt_partition_type_uuid_to_string_harder(
|
||||||
sd_id128_t id,
|
sd_id128_t id,
|
||||||
|
|
|
@ -1071,7 +1071,13 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* set, u
|
||||||
int id = PTR_TO_INT(syscall_id) - 1;
|
int id = PTR_TO_INT(syscall_id) - 1;
|
||||||
int error = PTR_TO_INT(val);
|
int error = PTR_TO_INT(val);
|
||||||
|
|
||||||
if (action != SCMP_ACT_ALLOW && error >= 0)
|
if (error == SECCOMP_ERROR_NUMBER_KILL)
|
||||||
|
a = scmp_act_kill_process();
|
||||||
|
#ifdef SCMP_ACT_LOG
|
||||||
|
else if (action == SCMP_ACT_LOG)
|
||||||
|
a = SCMP_ACT_LOG;
|
||||||
|
#endif
|
||||||
|
else if (action != SCMP_ACT_ALLOW && error >= 0)
|
||||||
a = SCMP_ACT_ERRNO(error);
|
a = SCMP_ACT_ERRNO(error);
|
||||||
|
|
||||||
r = seccomp_rule_add_exact(seccomp, a, id, 0);
|
r = seccomp_rule_add_exact(seccomp, a, id, 0);
|
||||||
|
|
|
@ -5,7 +5,10 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "errno-list.h"
|
||||||
|
#include "parse-util.h"
|
||||||
#include "set.h"
|
#include "set.h"
|
||||||
|
#include "string-util.h"
|
||||||
|
|
||||||
const char* seccomp_arch_to_string(uint32_t c);
|
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);
|
||||||
|
@ -115,3 +118,25 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(scmp_filter_ctx, seccomp_release);
|
||||||
int parse_syscall_archs(char **l, Set **ret_archs);
|
int parse_syscall_archs(char **l, Set **ret_archs);
|
||||||
|
|
||||||
uint32_t scmp_act_kill_process(void);
|
uint32_t scmp_act_kill_process(void);
|
||||||
|
|
||||||
|
/* This is a special value to be used where syscall filters otherwise expect errno numbers, will be
|
||||||
|
replaced with real seccomp action. */
|
||||||
|
enum {
|
||||||
|
SECCOMP_ERROR_NUMBER_KILL = INT_MAX - 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline bool seccomp_errno_or_action_is_valid(int n) {
|
||||||
|
return n == SECCOMP_ERROR_NUMBER_KILL || errno_is_valid(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int seccomp_parse_errno_or_action(const char *p) {
|
||||||
|
if (streq_ptr(p, "kill"))
|
||||||
|
return SECCOMP_ERROR_NUMBER_KILL;
|
||||||
|
return parse_errno(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const char *seccomp_errno_or_action_to_string(int num) {
|
||||||
|
if (num == SECCOMP_ERROR_NUMBER_KILL)
|
||||||
|
return "kill";
|
||||||
|
return errno_to_name(num);
|
||||||
|
}
|
||||||
|
|
|
@ -417,7 +417,6 @@ static int resolve_remote(Connection *c) {
|
||||||
static const struct addrinfo hints = {
|
static const struct addrinfo hints = {
|
||||||
.ai_family = AF_UNSPEC,
|
.ai_family = AF_UNSPEC,
|
||||||
.ai_socktype = SOCK_STREAM,
|
.ai_socktype = SOCK_STREAM,
|
||||||
.ai_flags = AI_ADDRCONFIG
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *node, *service;
|
const char *node, *service;
|
||||||
|
|
|
@ -4822,7 +4822,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
} else if (STR_IN_SET(name, "SystemCallFilter", "RestrictAddressFamilies")) {
|
} else if (STR_IN_SET(name, "SystemCallFilter", "SystemCallLog", "RestrictAddressFamilies")) {
|
||||||
_cleanup_strv_free_ char **l = NULL;
|
_cleanup_strv_free_ char **l = NULL;
|
||||||
int allow_list;
|
int allow_list;
|
||||||
|
|
||||||
|
|
|
@ -421,11 +421,6 @@ tests += [
|
||||||
[],
|
[],
|
||||||
'', 'manual'],
|
'', 'manual'],
|
||||||
|
|
||||||
[['src/test/test-dissect-image.c'],
|
|
||||||
[],
|
|
||||||
[libblkid],
|
|
||||||
'', 'manual'],
|
|
||||||
|
|
||||||
[['src/test/test-signal-util.c'],
|
[['src/test/test-signal-util.c'],
|
||||||
[],
|
[],
|
||||||
[]],
|
[]],
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <linux/loop.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "dissect-image.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "loop-util.h"
|
|
||||||
#include "string-util.h"
|
|
||||||
#include "tests.h"
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
_cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
|
|
||||||
_cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
|
|
||||||
int r, i;
|
|
||||||
|
|
||||||
test_setup_logging(LOG_DEBUG);
|
|
||||||
|
|
||||||
if (argc < 2) {
|
|
||||||
log_error("Requires one command line argument.");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = loop_device_make_by_path(argv[1], O_RDONLY, LO_FLAGS_PARTSCAN, &d);
|
|
||||||
if (r < 0) {
|
|
||||||
log_error_errno(r, "Failed to set up loopback device: %m");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = dissect_image(d->fd, NULL, 0, NULL, NULL, DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
|
|
||||||
if (r < 0) {
|
|
||||||
log_error_errno(r, "Failed to dissect image: %m");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
|
|
||||||
|
|
||||||
if (!m->partitions[i].found)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
printf("Found %s partition, %s of type %s at #%i (%s)\n",
|
|
||||||
partition_designator_to_string(i),
|
|
||||||
m->partitions[i].rw ? "writable" : "read-only",
|
|
||||||
strna(m->partitions[i].fstype),
|
|
||||||
m->partitions[i].partno,
|
|
||||||
strna(m->partitions[i].node));
|
|
||||||
}
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
|
@ -434,6 +434,8 @@ static void test_exec_systemcallfilter(Manager *m) {
|
||||||
test(__func__, m, "exec-systemcallfilter-with-errno-name.service", errno_from_name("EILSEQ"), CLD_EXITED);
|
test(__func__, m, "exec-systemcallfilter-with-errno-name.service", errno_from_name("EILSEQ"), CLD_EXITED);
|
||||||
test(__func__, m, "exec-systemcallfilter-with-errno-number.service", 255, CLD_EXITED);
|
test(__func__, m, "exec-systemcallfilter-with-errno-number.service", 255, CLD_EXITED);
|
||||||
test(__func__, m, "exec-systemcallfilter-with-errno-multi.service", errno_from_name("EILSEQ"), CLD_EXITED);
|
test(__func__, m, "exec-systemcallfilter-with-errno-multi.service", errno_from_name("EILSEQ"), CLD_EXITED);
|
||||||
|
test(__func__, m, "exec-systemcallfilter-override-error-action.service", SIGSYS, CLD_KILLED);
|
||||||
|
test(__func__, m, "exec-systemcallfilter-override-error-action2.service", errno_from_name("EILSEQ"), CLD_EXITED);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,10 +578,14 @@ static void test_exec_dynamicuser(Manager *m) {
|
||||||
test(__func__, m, "exec-dynamicuser-supplementarygroups.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
|
test(__func__, m, "exec-dynamicuser-supplementarygroups.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
|
||||||
test(__func__, m, "exec-dynamicuser-statedir.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
|
test(__func__, m, "exec-dynamicuser-statedir.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
|
||||||
|
|
||||||
|
(void) rm_rf("/var/lib/quux", REMOVE_ROOT|REMOVE_PHYSICAL);
|
||||||
(void) rm_rf("/var/lib/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
|
(void) rm_rf("/var/lib/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
|
||||||
(void) rm_rf("/var/lib/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
|
(void) rm_rf("/var/lib/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
|
||||||
|
(void) rm_rf("/var/lib/waldo", REMOVE_ROOT|REMOVE_PHYSICAL);
|
||||||
|
(void) rm_rf("/var/lib/private/quux", REMOVE_ROOT|REMOVE_PHYSICAL);
|
||||||
(void) rm_rf("/var/lib/private/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
|
(void) rm_rf("/var/lib/private/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
|
||||||
(void) rm_rf("/var/lib/private/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
|
(void) rm_rf("/var/lib/private/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
|
||||||
|
(void) rm_rf("/var/lib/private/waldo", REMOVE_ROOT|REMOVE_PHYSICAL);
|
||||||
|
|
||||||
test(__func__, m, "exec-dynamicuser-statedir-migrate-step1.service", 0, CLD_EXITED);
|
test(__func__, m, "exec-dynamicuser-statedir-migrate-step1.service", 0, CLD_EXITED);
|
||||||
test(__func__, m, "exec-dynamicuser-statedir-migrate-step2.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
|
test(__func__, m, "exec-dynamicuser-statedir-migrate-step2.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
|
#if HAVE_SECCOMP
|
||||||
|
#include "seccomp-util.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
static void test_parse_boolean(void) {
|
static void test_parse_boolean(void) {
|
||||||
assert_se(parse_boolean("1") == 1);
|
assert_se(parse_boolean("1") == 1);
|
||||||
|
@ -852,6 +855,7 @@ static void test_parse_errno(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_parse_syscall_and_errno(void) {
|
static void test_parse_syscall_and_errno(void) {
|
||||||
|
#if HAVE_SECCOMP
|
||||||
_cleanup_free_ char *n = NULL;
|
_cleanup_free_ char *n = NULL;
|
||||||
int e;
|
int e;
|
||||||
|
|
||||||
|
@ -882,11 +886,16 @@ static void test_parse_syscall_and_errno(void) {
|
||||||
assert_se(e == 255);
|
assert_se(e == 255);
|
||||||
n = mfree(n);
|
n = mfree(n);
|
||||||
|
|
||||||
|
assert_se(parse_syscall_and_errno("hoge:kill", &n, &e) >= 0);
|
||||||
|
assert_se(streq(n, "hoge"));
|
||||||
|
assert_se(e == SECCOMP_ERROR_NUMBER_KILL);
|
||||||
|
n = mfree(n);
|
||||||
|
|
||||||
/* The function checks the syscall name is empty or not. */
|
/* The function checks the syscall name is empty or not. */
|
||||||
assert_se(parse_syscall_and_errno("", &n, &e) == -EINVAL);
|
assert_se(parse_syscall_and_errno("", &n, &e) == -EINVAL);
|
||||||
assert_se(parse_syscall_and_errno(":255", &n, &e) == -EINVAL);
|
assert_se(parse_syscall_and_errno(":255", &n, &e) == -EINVAL);
|
||||||
|
|
||||||
/* errno must be a valid errno name or number between 0 and ERRNO_MAX == 4095 */
|
/* errno must be a valid errno name or number between 0 and ERRNO_MAX == 4095, or "kill" */
|
||||||
assert_se(parse_syscall_and_errno("hoge:4096", &n, &e) == -ERANGE);
|
assert_se(parse_syscall_and_errno("hoge:4096", &n, &e) == -ERANGE);
|
||||||
assert_se(parse_syscall_and_errno("hoge:-3", &n, &e) == -ERANGE);
|
assert_se(parse_syscall_and_errno("hoge:-3", &n, &e) == -ERANGE);
|
||||||
assert_se(parse_syscall_and_errno("hoge:12.3", &n, &e) == -EINVAL);
|
assert_se(parse_syscall_and_errno("hoge:12.3", &n, &e) == -EINVAL);
|
||||||
|
@ -896,6 +905,7 @@ static void test_parse_syscall_and_errno(void) {
|
||||||
assert_se(parse_syscall_and_errno("hoge:-EINVAL", &n, &e) == -EINVAL);
|
assert_se(parse_syscall_and_errno("hoge:-EINVAL", &n, &e) == -EINVAL);
|
||||||
assert_se(parse_syscall_and_errno("hoge:EINVALaaa", &n, &e) == -EINVAL);
|
assert_se(parse_syscall_and_errno("hoge:EINVALaaa", &n, &e) == -EINVAL);
|
||||||
assert_se(parse_syscall_and_errno("hoge:", &n, &e) == -EINVAL);
|
assert_se(parse_syscall_and_errno("hoge:", &n, &e) == -EINVAL);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_parse_mtu(void) {
|
static void test_parse_mtu(void) {
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Test for SystemCallFilter with specific kill action overriding default errno action
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/bin/python3 -c 'import os\ntry: os.uname()\nexcept Exception as e: exit(e.errno)'
|
||||||
|
Type=oneshot
|
||||||
|
SystemCallFilter=~uname:kill
|
||||||
|
SystemCallErrorNumber=EILSEQ
|
|
@ -0,0 +1,8 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Test for SystemCallFilter with specific errno action overriding default kill action
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/bin/python3 -c 'import os\ntry: os.uname()\nexcept Exception as e: exit(e.errno)'
|
||||||
|
Type=oneshot
|
||||||
|
SystemCallFilter=~uname:EILSEQ
|
||||||
|
SystemCallErrorNumber=kill
|
|
@ -8,16 +8,16 @@
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
|
|
||||||
# This unit gets pulled automatically into multi-user.target by
|
# This unit gets pulled automatically into multi-user.target by
|
||||||
# systemd-rc-local-generator if @RC_LOCAL_SCRIPT_PATH_START@ is executable.
|
# systemd-rc-local-generator if @RC_LOCAL_PATH@ is executable.
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=@RC_LOCAL_SCRIPT_PATH_START@ Compatibility
|
Description=@RC_LOCAL_PATH@ Compatibility
|
||||||
Documentation=man:systemd-rc-local-generator(8)
|
Documentation=man:systemd-rc-local-generator(8)
|
||||||
ConditionFileIsExecutable=@RC_LOCAL_SCRIPT_PATH_START@
|
ConditionFileIsExecutable=@RC_LOCAL_PATH@
|
||||||
After=network.target
|
After=network.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=forking
|
Type=forking
|
||||||
ExecStart=@RC_LOCAL_SCRIPT_PATH_START@ start
|
ExecStart=@RC_LOCAL_PATH@ start
|
||||||
TimeoutSec=0
|
TimeoutSec=0
|
||||||
RemainAfterExit=yes
|
RemainAfterExit=yes
|
||||||
GuessMainPID=no
|
GuessMainPID=no
|
||||||
|
|
Loading…
Reference in New Issue