mirror of
https://github.com/systemd/systemd
synced 2025-09-29 16:54:46 +02:00
Compare commits
5 Commits
78dff3f3d7
...
9fc168cd1e
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9fc168cd1e | ||
![]() |
0c3c9a4096 | ||
![]() |
ddc155b2fd | ||
![]() |
21be71eefb | ||
![]() |
668b3a42fe |
@ -246,10 +246,19 @@ def check_one_keycode(prop, value):
|
|||||||
'KBD_LCD_MENU' in key):
|
'KBD_LCD_MENU' in key):
|
||||||
error('Keycode {} unknown', key)
|
error('Keycode {} unknown', key)
|
||||||
|
|
||||||
|
def check_wheel_clicks(properties):
|
||||||
|
pairs = (('MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL', 'MOUSE_WHEEL_CLICK_COUNT'),
|
||||||
|
('MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL', 'MOUSE_WHEEL_CLICK_ANGLE'),
|
||||||
|
('MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL', 'MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL'),
|
||||||
|
('MOUSE_WHEEL_CLICK_COUNT', 'MOUSE_WHEEL_CLICK_ANGLE'))
|
||||||
|
for pair in pairs:
|
||||||
|
if pair[0] in properties and pair[1] not in properties:
|
||||||
|
error('{} requires {} to be specified', *pair)
|
||||||
|
|
||||||
def check_properties(groups):
|
def check_properties(groups):
|
||||||
grammar = property_grammar()
|
grammar = property_grammar()
|
||||||
for matches, props in groups:
|
for matches, props in groups:
|
||||||
prop_names = set()
|
seen_props = {}
|
||||||
for prop in props:
|
for prop in props:
|
||||||
# print('--', prop)
|
# print('--', prop)
|
||||||
prop = prop.partition('#')[0].rstrip()
|
prop = prop.partition('#')[0].rstrip()
|
||||||
@ -259,9 +268,9 @@ def check_properties(groups):
|
|||||||
error('Failed to parse: {!r}', prop)
|
error('Failed to parse: {!r}', prop)
|
||||||
continue
|
continue
|
||||||
# print('{!r}'.format(parsed))
|
# print('{!r}'.format(parsed))
|
||||||
if parsed.NAME in prop_names:
|
if parsed.NAME in seen_props:
|
||||||
error('Property {} is duplicated', parsed.NAME)
|
error('Property {} is duplicated', parsed.NAME)
|
||||||
prop_names.add(parsed.NAME)
|
seen_props[parsed.NAME] = parsed.VALUE
|
||||||
if parsed.NAME == 'MOUSE_DPI':
|
if parsed.NAME == 'MOUSE_DPI':
|
||||||
check_one_default(prop, parsed.VALUE.SETTINGS)
|
check_one_default(prop, parsed.VALUE.SETTINGS)
|
||||||
elif parsed.NAME == 'ACCEL_MOUNT_MATRIX':
|
elif parsed.NAME == 'ACCEL_MOUNT_MATRIX':
|
||||||
@ -270,6 +279,8 @@ def check_properties(groups):
|
|||||||
val = parsed.VALUE if isinstance(parsed.VALUE, str) else parsed.VALUE[0]
|
val = parsed.VALUE if isinstance(parsed.VALUE, str) else parsed.VALUE[0]
|
||||||
check_one_keycode(prop, val)
|
check_one_keycode(prop, val)
|
||||||
|
|
||||||
|
check_wheel_clicks(seen_props)
|
||||||
|
|
||||||
def print_summary(fname, groups):
|
def print_summary(fname, groups):
|
||||||
n_matches = sum(len(matches) for matches, props in groups)
|
n_matches = sum(len(matches) for matches, props in groups)
|
||||||
n_props = sum(len(props) for matches, props in groups)
|
n_props = sum(len(props) for matches, props in groups)
|
||||||
|
@ -2643,6 +2643,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly as InaccessiblePaths = ['...', ...];
|
readonly as InaccessiblePaths = ['...', ...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly as ExecPaths = ['...', ...];
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly as NoExecPaths = ['...', ...];
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly t MountFlags = ...;
|
readonly t MountFlags = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly b PrivateTmp = ...;
|
readonly b PrivateTmp = ...;
|
||||||
@ -3154,6 +3158,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
|
|
||||||
<!--property InaccessiblePaths is not documented!-->
|
<!--property InaccessiblePaths is not documented!-->
|
||||||
|
|
||||||
|
<!--property ExecPaths is not documented!-->
|
||||||
|
|
||||||
|
<!--property NoExecPaths is not documented!-->
|
||||||
|
|
||||||
<!--property PrivateTmp is not documented!-->
|
<!--property PrivateTmp is not documented!-->
|
||||||
|
|
||||||
<!--property PrivateDevices is not documented!-->
|
<!--property PrivateDevices is not documented!-->
|
||||||
@ -3722,6 +3730,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="InaccessiblePaths"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="InaccessiblePaths"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="ExecPaths"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="NoExecPaths"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MountFlags"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MountFlags"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="PrivateTmp"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="PrivateTmp"/>
|
||||||
@ -4385,6 +4397,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
|||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly as InaccessiblePaths = ['...', ...];
|
readonly as InaccessiblePaths = ['...', ...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly as ExecPaths = ['...', ...];
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly as NoExecPaths = ['...', ...];
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly t MountFlags = ...;
|
readonly t MountFlags = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly b PrivateTmp = ...;
|
readonly b PrivateTmp = ...;
|
||||||
@ -4924,6 +4940,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
|||||||
|
|
||||||
<!--property InaccessiblePaths is not documented!-->
|
<!--property InaccessiblePaths is not documented!-->
|
||||||
|
|
||||||
|
<!--property ExecPaths is not documented!-->
|
||||||
|
|
||||||
|
<!--property NoExecPaths is not documented!-->
|
||||||
|
|
||||||
<!--property PrivateTmp is not documented!-->
|
<!--property PrivateTmp is not documented!-->
|
||||||
|
|
||||||
<!--property PrivateDevices is not documented!-->
|
<!--property PrivateDevices is not documented!-->
|
||||||
@ -5490,6 +5510,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="InaccessiblePaths"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="InaccessiblePaths"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="ExecPaths"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="NoExecPaths"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MountFlags"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MountFlags"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="PrivateTmp"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="PrivateTmp"/>
|
||||||
@ -6066,6 +6090,10 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
|||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly as InaccessiblePaths = ['...', ...];
|
readonly as InaccessiblePaths = ['...', ...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly as ExecPaths = ['...', ...];
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly as NoExecPaths = ['...', ...];
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly t MountFlags = ...;
|
readonly t MountFlags = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly b PrivateTmp = ...;
|
readonly b PrivateTmp = ...;
|
||||||
@ -6533,6 +6561,10 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
|||||||
|
|
||||||
<!--property InaccessiblePaths is not documented!-->
|
<!--property InaccessiblePaths is not documented!-->
|
||||||
|
|
||||||
|
<!--property ExecPaths is not documented!-->
|
||||||
|
|
||||||
|
<!--property NoExecPaths is not documented!-->
|
||||||
|
|
||||||
<!--property PrivateTmp is not documented!-->
|
<!--property PrivateTmp is not documented!-->
|
||||||
|
|
||||||
<!--property PrivateDevices is not documented!-->
|
<!--property PrivateDevices is not documented!-->
|
||||||
@ -7017,6 +7049,10 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="InaccessiblePaths"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="InaccessiblePaths"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="ExecPaths"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="NoExecPaths"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MountFlags"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MountFlags"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="PrivateTmp"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="PrivateTmp"/>
|
||||||
@ -7714,6 +7750,10 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
|||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly as InaccessiblePaths = ['...', ...];
|
readonly as InaccessiblePaths = ['...', ...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly as ExecPaths = ['...', ...];
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly as NoExecPaths = ['...', ...];
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly t MountFlags = ...;
|
readonly t MountFlags = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly b PrivateTmp = ...;
|
readonly b PrivateTmp = ...;
|
||||||
@ -8167,6 +8207,10 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
|||||||
|
|
||||||
<!--property InaccessiblePaths is not documented!-->
|
<!--property InaccessiblePaths is not documented!-->
|
||||||
|
|
||||||
|
<!--property ExecPaths is not documented!-->
|
||||||
|
|
||||||
|
<!--property NoExecPaths is not documented!-->
|
||||||
|
|
||||||
<!--property PrivateTmp is not documented!-->
|
<!--property PrivateTmp is not documented!-->
|
||||||
|
|
||||||
<!--property PrivateDevices is not documented!-->
|
<!--property PrivateDevices is not documented!-->
|
||||||
@ -8637,6 +8681,10 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="InaccessiblePaths"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="InaccessiblePaths"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="ExecPaths"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="NoExecPaths"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MountFlags"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MountFlags"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="PrivateTmp"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="PrivateTmp"/>
|
||||||
|
@ -1359,6 +1359,8 @@ StateDirectory=aaa/bbb ccc</programlisting>
|
|||||||
<term><varname>ReadWritePaths=</varname></term>
|
<term><varname>ReadWritePaths=</varname></term>
|
||||||
<term><varname>ReadOnlyPaths=</varname></term>
|
<term><varname>ReadOnlyPaths=</varname></term>
|
||||||
<term><varname>InaccessiblePaths=</varname></term>
|
<term><varname>InaccessiblePaths=</varname></term>
|
||||||
|
<term><varname>ExecPaths=</varname></term>
|
||||||
|
<term><varname>NoExecPaths=</varname></term>
|
||||||
|
|
||||||
<listitem><para>Sets up a new file system namespace for executed processes. These options may be used
|
<listitem><para>Sets up a new file system namespace for executed processes. These options may be used
|
||||||
to limit access a process has to the file system. Each setting takes a space-separated list of paths
|
to limit access a process has to the file system. Each setting takes a space-separated list of paths
|
||||||
@ -1380,12 +1382,18 @@ StateDirectory=aaa/bbb ccc</programlisting>
|
|||||||
<varname>BindPaths=</varname>, or <varname>BindReadOnlyPaths=</varname> inside it. For a more flexible option,
|
<varname>BindPaths=</varname>, or <varname>BindReadOnlyPaths=</varname> inside it. For a more flexible option,
|
||||||
see <varname>TemporaryFileSystem=</varname>.</para>
|
see <varname>TemporaryFileSystem=</varname>.</para>
|
||||||
|
|
||||||
|
<para>Content in paths listed in <varname>NoExecPaths=</varname> are not executable even if the usual
|
||||||
|
file access controls would permit this. Nest <varname>ExecPaths=</varname> inside of
|
||||||
|
<varname>NoExecPaths=</varname> in order to provide executable content within non-executable
|
||||||
|
directories.</para>
|
||||||
|
|
||||||
<para>Non-directory paths may be specified as well. These options may be specified more than once,
|
<para>Non-directory paths may be specified as well. These options may be specified more than once,
|
||||||
in which case all paths listed will have limited access from within the namespace. If the empty string is
|
in which case all paths listed will have limited access from within the namespace. If the empty string is
|
||||||
assigned to this option, the specific list is reset, and all prior assignments have no effect.</para>
|
assigned to this option, the specific list is reset, and all prior assignments have no effect.</para>
|
||||||
|
|
||||||
<para>Paths in <varname>ReadWritePaths=</varname>, <varname>ReadOnlyPaths=</varname> and
|
<para>Paths in <varname>ReadWritePaths=</varname>, <varname>ReadOnlyPaths=</varname>,
|
||||||
<varname>InaccessiblePaths=</varname> may be prefixed with <literal>-</literal>, in which case they will be
|
<varname>InaccessiblePaths=</varname>, <varname>ExecPaths=</varname> and
|
||||||
|
<varname>NoExecPaths=</varname> may be prefixed with <literal>-</literal>, in which case they will be
|
||||||
ignored when they do not exist. If prefixed with <literal>+</literal> the paths are taken relative to the root
|
ignored when they do not exist. If prefixed with <literal>+</literal> the paths are taken relative to the root
|
||||||
directory of the unit, as configured with <varname>RootDirectory=</varname>/<varname>RootImage=</varname>,
|
directory of the unit, as configured with <varname>RootDirectory=</varname>/<varname>RootImage=</varname>,
|
||||||
instead of relative to the root directory of the host (see above). When combining <literal>-</literal> and
|
instead of relative to the root directory of the host (see above). When combining <literal>-</literal> and
|
||||||
@ -1408,6 +1416,15 @@ StateDirectory=aaa/bbb ccc</programlisting>
|
|||||||
<varname>CapabilityBoundingSet=~CAP_SYS_ADMIN</varname> or
|
<varname>CapabilityBoundingSet=~CAP_SYS_ADMIN</varname> or
|
||||||
<varname>SystemCallFilter=~@mount</varname>.</para>
|
<varname>SystemCallFilter=~@mount</varname>.</para>
|
||||||
|
|
||||||
|
<para>Simple allow-list example using these directives:
|
||||||
|
<programlisting>[Service]
|
||||||
|
ReadOnlyPaths=/
|
||||||
|
ReadWritePaths=/var /run
|
||||||
|
InaccessiblePaths=-/lost+found
|
||||||
|
NoExecPaths=/
|
||||||
|
ExecPaths=/usr/sbin/my_daemon /usr/lib /usr/lib64
|
||||||
|
</programlisting></para>
|
||||||
|
|
||||||
<xi:include href="system-only.xml" xpointer="plural"/></listitem>
|
<xi:include href="system-only.xml" xpointer="plural"/></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
@ -1094,6 +1094,8 @@ const sd_bus_vtable bus_exec_vtable[] = {
|
|||||||
SD_BUS_PROPERTY("ReadWritePaths", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("ReadWritePaths", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("ReadOnlyPaths", "as", NULL, offsetof(ExecContext, read_only_paths), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("ReadOnlyPaths", "as", NULL, offsetof(ExecContext, read_only_paths), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("InaccessiblePaths", "as", NULL, offsetof(ExecContext, inaccessible_paths), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("InaccessiblePaths", "as", NULL, offsetof(ExecContext, inaccessible_paths), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
SD_BUS_PROPERTY("ExecPaths", "as", NULL, offsetof(ExecContext, exec_paths), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
SD_BUS_PROPERTY("NoExecPaths", "as", NULL, offsetof(ExecContext, no_exec_paths), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("PrivateDevices", "b", bus_property_get_bool, offsetof(ExecContext, private_devices), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("PrivateDevices", "b", bus_property_get_bool, offsetof(ExecContext, private_devices), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
@ -2981,7 +2983,7 @@ int bus_exec_context_set_transient_property(
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
} else if (STR_IN_SET(name, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
|
} else if (STR_IN_SET(name, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
|
||||||
"ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths")) {
|
"ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths", "ExecPaths", "NoExecPaths")) {
|
||||||
_cleanup_strv_free_ char **l = NULL;
|
_cleanup_strv_free_ char **l = NULL;
|
||||||
char ***dirs;
|
char ***dirs;
|
||||||
char **p;
|
char **p;
|
||||||
@ -3007,6 +3009,10 @@ int bus_exec_context_set_transient_property(
|
|||||||
dirs = &c->read_write_paths;
|
dirs = &c->read_write_paths;
|
||||||
else if (STR_IN_SET(name, "ReadOnlyDirectories", "ReadOnlyPaths"))
|
else if (STR_IN_SET(name, "ReadOnlyDirectories", "ReadOnlyPaths"))
|
||||||
dirs = &c->read_only_paths;
|
dirs = &c->read_only_paths;
|
||||||
|
else if (streq(name, "ExecPaths"))
|
||||||
|
dirs = &c->exec_paths;
|
||||||
|
else if (streq(name, "NoExecPaths"))
|
||||||
|
dirs = &c->no_exec_paths;
|
||||||
else /* "InaccessiblePaths" */
|
else /* "InaccessiblePaths" */
|
||||||
dirs = &c->inaccessible_paths;
|
dirs = &c->inaccessible_paths;
|
||||||
|
|
||||||
|
@ -1999,7 +1999,9 @@ bool exec_needs_mount_namespace(
|
|||||||
|
|
||||||
if (!strv_isempty(context->read_write_paths) ||
|
if (!strv_isempty(context->read_write_paths) ||
|
||||||
!strv_isempty(context->read_only_paths) ||
|
!strv_isempty(context->read_only_paths) ||
|
||||||
!strv_isempty(context->inaccessible_paths))
|
!strv_isempty(context->inaccessible_paths) ||
|
||||||
|
!strv_isempty(context->exec_paths) ||
|
||||||
|
!strv_isempty(context->no_exec_paths))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (context->n_bind_mounts > 0)
|
if (context->n_bind_mounts > 0)
|
||||||
@ -3206,6 +3208,8 @@ static int apply_mount_namespace(
|
|||||||
&ns_info, context->read_write_paths,
|
&ns_info, context->read_write_paths,
|
||||||
needs_sandboxing ? context->read_only_paths : NULL,
|
needs_sandboxing ? context->read_only_paths : NULL,
|
||||||
needs_sandboxing ? context->inaccessible_paths : NULL,
|
needs_sandboxing ? context->inaccessible_paths : NULL,
|
||||||
|
needs_sandboxing ? context->exec_paths : NULL,
|
||||||
|
needs_sandboxing ? context->no_exec_paths : NULL,
|
||||||
empty_directories,
|
empty_directories,
|
||||||
bind_mounts,
|
bind_mounts,
|
||||||
n_bind_mounts,
|
n_bind_mounts,
|
||||||
@ -4815,6 +4819,8 @@ void exec_context_done(ExecContext *c) {
|
|||||||
c->read_only_paths = strv_free(c->read_only_paths);
|
c->read_only_paths = strv_free(c->read_only_paths);
|
||||||
c->read_write_paths = strv_free(c->read_write_paths);
|
c->read_write_paths = strv_free(c->read_write_paths);
|
||||||
c->inaccessible_paths = strv_free(c->inaccessible_paths);
|
c->inaccessible_paths = strv_free(c->inaccessible_paths);
|
||||||
|
c->exec_paths = strv_free(c->exec_paths);
|
||||||
|
c->no_exec_paths = strv_free(c->no_exec_paths);
|
||||||
|
|
||||||
bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
|
bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
|
||||||
c->bind_mounts = NULL;
|
c->bind_mounts = NULL;
|
||||||
@ -5162,6 +5168,18 @@ static void strv_fprintf(FILE *f, char **l) {
|
|||||||
fprintf(f, " %s", *g);
|
fprintf(f, " %s", *g);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void strv_dump(FILE* f, const char *prefix, const char *name, char **strv) {
|
||||||
|
assert(f);
|
||||||
|
assert(prefix);
|
||||||
|
assert(name);
|
||||||
|
|
||||||
|
if (!strv_isempty(strv)) {
|
||||||
|
fprintf(f, "%s%s:", name, prefix);
|
||||||
|
strv_fprintf(f, strv);
|
||||||
|
fputs("\n", f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
|
void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
|
||||||
char **e, **d, buf_clean[FORMAT_TIMESPAN_MAX];
|
char **e, **d, buf_clean[FORMAT_TIMESPAN_MAX];
|
||||||
int r;
|
int r;
|
||||||
@ -5474,32 +5492,16 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
|
|||||||
|
|
||||||
fprintf(f, "%sDynamicUser: %s\n", prefix, yes_no(c->dynamic_user));
|
fprintf(f, "%sDynamicUser: %s\n", prefix, yes_no(c->dynamic_user));
|
||||||
|
|
||||||
if (!strv_isempty(c->supplementary_groups)) {
|
strv_dump(f, prefix, "SupplementaryGroups", c->supplementary_groups);
|
||||||
fprintf(f, "%sSupplementaryGroups:", prefix);
|
|
||||||
strv_fprintf(f, c->supplementary_groups);
|
|
||||||
fputs("\n", f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c->pam_name)
|
if (c->pam_name)
|
||||||
fprintf(f, "%sPAMName: %s\n", prefix, c->pam_name);
|
fprintf(f, "%sPAMName: %s\n", prefix, c->pam_name);
|
||||||
|
|
||||||
if (!strv_isempty(c->read_write_paths)) {
|
strv_dump(f, prefix, "ReadWritePaths", c->read_write_paths);
|
||||||
fprintf(f, "%sReadWritePaths:", prefix);
|
strv_dump(f, prefix, "ReadOnlyPaths", c->read_only_paths);
|
||||||
strv_fprintf(f, c->read_write_paths);
|
strv_dump(f, prefix, "InaccessiblePaths", c->inaccessible_paths);
|
||||||
fputs("\n", f);
|
strv_dump(f, prefix, "ExecPaths", c->exec_paths);
|
||||||
}
|
strv_dump(f, prefix, "NoExecPaths", c->no_exec_paths);
|
||||||
|
|
||||||
if (!strv_isempty(c->read_only_paths)) {
|
|
||||||
fprintf(f, "%sReadOnlyPaths:", prefix);
|
|
||||||
strv_fprintf(f, c->read_only_paths);
|
|
||||||
fputs("\n", f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strv_isempty(c->inaccessible_paths)) {
|
|
||||||
fprintf(f, "%sInaccessiblePaths:", prefix);
|
|
||||||
strv_fprintf(f, c->inaccessible_paths);
|
|
||||||
fputs("\n", f);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < c->n_bind_mounts; i++)
|
for (size_t i = 0; i < c->n_bind_mounts; i++)
|
||||||
fprintf(f, "%s%s: %s%s:%s:%s\n", prefix,
|
fprintf(f, "%s%s: %s%s:%s:%s\n", prefix,
|
||||||
|
@ -243,7 +243,7 @@ struct ExecContext {
|
|||||||
char *apparmor_profile;
|
char *apparmor_profile;
|
||||||
char *smack_process_label;
|
char *smack_process_label;
|
||||||
|
|
||||||
char **read_write_paths, **read_only_paths, **inaccessible_paths;
|
char **read_write_paths, **read_only_paths, **inaccessible_paths, **exec_paths, **no_exec_paths;
|
||||||
unsigned long mount_flags;
|
unsigned long mount_flags;
|
||||||
BindMount *bind_mounts;
|
BindMount *bind_mounts;
|
||||||
size_t n_bind_mounts;
|
size_t n_bind_mounts;
|
||||||
|
@ -119,6 +119,8 @@ $1.InaccessibleDirectories, config_parse_namespace_path_strv,
|
|||||||
$1.ReadWritePaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_paths)
|
$1.ReadWritePaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_paths)
|
||||||
$1.ReadOnlyPaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_paths)
|
$1.ReadOnlyPaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_paths)
|
||||||
$1.InaccessiblePaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_paths)
|
$1.InaccessiblePaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_paths)
|
||||||
|
$1.ExecPaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.exec_paths)
|
||||||
|
$1.NoExecPaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.no_exec_paths)
|
||||||
$1.BindPaths, config_parse_bind_paths, 0, offsetof($1, exec_context)
|
$1.BindPaths, config_parse_bind_paths, 0, offsetof($1, exec_context)
|
||||||
$1.BindReadOnlyPaths, config_parse_bind_paths, 0, offsetof($1, exec_context)
|
$1.BindReadOnlyPaths, config_parse_bind_paths, 0, offsetof($1, exec_context)
|
||||||
$1.TemporaryFileSystem, config_parse_temporary_filesystems, 0, offsetof($1, exec_context)
|
$1.TemporaryFileSystem, config_parse_temporary_filesystems, 0, offsetof($1, exec_context)
|
||||||
|
@ -54,6 +54,8 @@ typedef enum MountMode {
|
|||||||
RUN,
|
RUN,
|
||||||
READONLY,
|
READONLY,
|
||||||
READWRITE,
|
READWRITE,
|
||||||
|
NOEXEC,
|
||||||
|
EXEC,
|
||||||
TMPFS,
|
TMPFS,
|
||||||
READWRITE_IMPLICIT, /* Should have the lowest priority. */
|
READWRITE_IMPLICIT, /* Should have the lowest priority. */
|
||||||
_MOUNT_MODE_MAX,
|
_MOUNT_MODE_MAX,
|
||||||
@ -66,6 +68,8 @@ typedef struct MountEntry {
|
|||||||
bool has_prefix:1; /* Already is prefixed by the root dir? */
|
bool has_prefix:1; /* Already is prefixed by the root dir? */
|
||||||
bool read_only:1; /* Shall this mount point be read-only? */
|
bool read_only:1; /* Shall this mount point be read-only? */
|
||||||
bool nosuid:1; /* Shall set MS_NOSUID on the mount itself */
|
bool nosuid:1; /* Shall set MS_NOSUID on the mount itself */
|
||||||
|
bool noexec:1; /* Shall set MS_NOEXEC on the mount itself */
|
||||||
|
bool exec:1; /* Shall clear MS_NOEXEC on the mount itself */
|
||||||
bool applied:1; /* Already applied */
|
bool applied:1; /* Already applied */
|
||||||
char *path_malloc; /* Use this instead of 'path_const' if we had to allocate memory */
|
char *path_malloc; /* Use this instead of 'path_const' if we had to allocate memory */
|
||||||
const char *source_const; /* The source path, for bind mounts or images */
|
const char *source_const; /* The source path, for bind mounts or images */
|
||||||
@ -212,6 +216,8 @@ static const char * const mount_mode_table[_MOUNT_MODE_MAX] = {
|
|||||||
[TMPFS] = "tmpfs",
|
[TMPFS] = "tmpfs",
|
||||||
[MOUNT_IMAGES] = "mount-images",
|
[MOUNT_IMAGES] = "mount-images",
|
||||||
[READWRITE_IMPLICIT] = "rw-implicit",
|
[READWRITE_IMPLICIT] = "rw-implicit",
|
||||||
|
[EXEC] = "exec",
|
||||||
|
[NOEXEC] = "noexec",
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(mount_mode, MountMode);
|
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(mount_mode, MountMode);
|
||||||
@ -231,6 +237,18 @@ static bool mount_entry_read_only(const MountEntry *p) {
|
|||||||
return p->read_only || IN_SET(p->mode, READONLY, INACCESSIBLE, PRIVATE_TMP_READONLY);
|
return p->read_only || IN_SET(p->mode, READONLY, INACCESSIBLE, PRIVATE_TMP_READONLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool mount_entry_noexec(const MountEntry *p) {
|
||||||
|
assert(p);
|
||||||
|
|
||||||
|
return p->noexec || IN_SET(p->mode, NOEXEC, INACCESSIBLE, SYSFS, PROCFS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mount_entry_exec(const MountEntry *p) {
|
||||||
|
assert(p);
|
||||||
|
|
||||||
|
return p->exec || p->mode == EXEC;
|
||||||
|
}
|
||||||
|
|
||||||
static const char *mount_entry_source(const MountEntry *p) {
|
static const char *mount_entry_source(const MountEntry *p) {
|
||||||
assert(p);
|
assert(p);
|
||||||
|
|
||||||
@ -497,7 +515,10 @@ static void drop_duplicates(MountEntry *m, size_t *n) {
|
|||||||
path_equal(mount_entry_path(f), mount_entry_path(previous)) &&
|
path_equal(mount_entry_path(f), mount_entry_path(previous)) &&
|
||||||
!f->applied && !previous->applied) {
|
!f->applied && !previous->applied) {
|
||||||
log_debug("%s (%s) is duplicate.", mount_entry_path(f), mount_mode_to_string(f->mode));
|
log_debug("%s (%s) is duplicate.", mount_entry_path(f), mount_mode_to_string(f->mode));
|
||||||
previous->read_only = previous->read_only || mount_entry_read_only(f); /* Propagate the read-only flag to the remaining entry */
|
/* Propagate the flags to the remaining entry */
|
||||||
|
previous->read_only = previous->read_only || mount_entry_read_only(f);
|
||||||
|
previous->noexec = previous->noexec || mount_entry_noexec(f);
|
||||||
|
previous->exec = previous->exec || mount_entry_exec(f);
|
||||||
mount_entry_done(f);
|
mount_entry_done(f);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1057,6 +1078,8 @@ static int apply_mount(
|
|||||||
case READONLY:
|
case READONLY:
|
||||||
case READWRITE:
|
case READWRITE:
|
||||||
case READWRITE_IMPLICIT:
|
case READWRITE_IMPLICIT:
|
||||||
|
case EXEC:
|
||||||
|
case NOEXEC:
|
||||||
r = path_is_mount_point(mount_entry_path(m), root_directory, 0);
|
r = path_is_mount_point(mount_entry_path(m), root_directory, 0);
|
||||||
if (r == -ENOENT && m->ignore)
|
if (r == -ENOENT && m->ignore)
|
||||||
return 0;
|
return 0;
|
||||||
@ -1064,7 +1087,7 @@ static int apply_mount(
|
|||||||
return log_debug_errno(r, "Failed to determine whether %s is already a mount point: %m",
|
return log_debug_errno(r, "Failed to determine whether %s is already a mount point: %m",
|
||||||
mount_entry_path(m));
|
mount_entry_path(m));
|
||||||
if (r > 0) /* Nothing to do here, it is already a mount. We just later toggle the MS_RDONLY
|
if (r > 0) /* Nothing to do here, it is already a mount. We just later toggle the MS_RDONLY
|
||||||
* bit for the mount point if needed. */
|
* and MS_NOEXEC bits for the mount point if needed. */
|
||||||
return 0;
|
return 0;
|
||||||
/* This isn't a mount point yet, let's make it one. */
|
/* This isn't a mount point yet, let's make it one. */
|
||||||
what = mount_entry_path(m);
|
what = mount_entry_path(m);
|
||||||
@ -1195,7 +1218,7 @@ static int make_read_only(const MountEntry *m, char **deny_list, FILE *proc_self
|
|||||||
else
|
else
|
||||||
r = bind_remount_one_with_mountinfo(mount_entry_path(m), new_flags, flags_mask, proc_self_mountinfo);
|
r = bind_remount_one_with_mountinfo(mount_entry_path(m), new_flags, flags_mask, proc_self_mountinfo);
|
||||||
|
|
||||||
/* Not that we only turn on the MS_RDONLY flag here, we never turn it off. Something that was marked
|
/* Note that we only turn on the MS_RDONLY flag here, we never turn it off. Something that was marked
|
||||||
* read-only already stays this way. This improves compatibility with container managers, where we
|
* read-only already stays this way. This improves compatibility with container managers, where we
|
||||||
* won't attempt to undo read-only mounts already applied. */
|
* won't attempt to undo read-only mounts already applied. */
|
||||||
|
|
||||||
@ -1207,6 +1230,40 @@ static int make_read_only(const MountEntry *m, char **deny_list, FILE *proc_self
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int make_noexec(const MountEntry *m, char **deny_list, FILE *proc_self_mountinfo) {
|
||||||
|
unsigned long new_flags = 0, flags_mask = 0;
|
||||||
|
bool submounts = false;
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
assert(m);
|
||||||
|
assert(proc_self_mountinfo);
|
||||||
|
|
||||||
|
if (mount_entry_noexec(m)) {
|
||||||
|
new_flags |= MS_NOEXEC;
|
||||||
|
flags_mask |= MS_NOEXEC;
|
||||||
|
} else if (mount_entry_exec(m)) {
|
||||||
|
new_flags &= ~MS_NOEXEC;
|
||||||
|
flags_mask |= MS_NOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags_mask == 0) /* No Change? */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
submounts = !IN_SET(m->mode, EMPTY_DIR, TMPFS);
|
||||||
|
|
||||||
|
if (submounts)
|
||||||
|
r = bind_remount_recursive_with_mountinfo(mount_entry_path(m), new_flags, flags_mask, deny_list, proc_self_mountinfo);
|
||||||
|
else
|
||||||
|
r = bind_remount_one_with_mountinfo(mount_entry_path(m), new_flags, flags_mask, proc_self_mountinfo);
|
||||||
|
|
||||||
|
if (r == -ENOENT && m->ignore)
|
||||||
|
return 0;
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to re-mount '%s'%s: %m", mount_entry_path(m),
|
||||||
|
submounts ? " and its submounts" : "");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static bool namespace_info_mount_apivfs(const NamespaceInfo *ns_info) {
|
static bool namespace_info_mount_apivfs(const NamespaceInfo *ns_info) {
|
||||||
assert(ns_info);
|
assert(ns_info);
|
||||||
|
|
||||||
@ -1228,6 +1285,8 @@ static size_t namespace_calculate_mounts(
|
|||||||
char** read_write_paths,
|
char** read_write_paths,
|
||||||
char** read_only_paths,
|
char** read_only_paths,
|
||||||
char** inaccessible_paths,
|
char** inaccessible_paths,
|
||||||
|
char** exec_paths,
|
||||||
|
char** no_exec_paths,
|
||||||
char** empty_directories,
|
char** empty_directories,
|
||||||
size_t n_bind_mounts,
|
size_t n_bind_mounts,
|
||||||
size_t n_temporary_filesystems,
|
size_t n_temporary_filesystems,
|
||||||
@ -1260,6 +1319,8 @@ static size_t namespace_calculate_mounts(
|
|||||||
strv_length(read_write_paths) +
|
strv_length(read_write_paths) +
|
||||||
strv_length(read_only_paths) +
|
strv_length(read_only_paths) +
|
||||||
strv_length(inaccessible_paths) +
|
strv_length(inaccessible_paths) +
|
||||||
|
strv_length(exec_paths) +
|
||||||
|
strv_length(no_exec_paths) +
|
||||||
strv_length(empty_directories) +
|
strv_length(empty_directories) +
|
||||||
n_bind_mounts +
|
n_bind_mounts +
|
||||||
n_mount_images +
|
n_mount_images +
|
||||||
@ -1406,6 +1467,8 @@ int setup_namespace(
|
|||||||
char** read_write_paths,
|
char** read_write_paths,
|
||||||
char** read_only_paths,
|
char** read_only_paths,
|
||||||
char** inaccessible_paths,
|
char** inaccessible_paths,
|
||||||
|
char** exec_paths,
|
||||||
|
char** no_exec_paths,
|
||||||
char** empty_directories,
|
char** empty_directories,
|
||||||
const BindMount *bind_mounts,
|
const BindMount *bind_mounts,
|
||||||
size_t n_bind_mounts,
|
size_t n_bind_mounts,
|
||||||
@ -1523,6 +1586,8 @@ int setup_namespace(
|
|||||||
read_write_paths,
|
read_write_paths,
|
||||||
read_only_paths,
|
read_only_paths,
|
||||||
inaccessible_paths,
|
inaccessible_paths,
|
||||||
|
exec_paths,
|
||||||
|
no_exec_paths,
|
||||||
empty_directories,
|
empty_directories,
|
||||||
n_bind_mounts,
|
n_bind_mounts,
|
||||||
n_temporary_filesystems,
|
n_temporary_filesystems,
|
||||||
@ -1550,6 +1615,14 @@ int setup_namespace(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
|
r = append_access_mounts(&m, exec_paths, EXEC, require_prefix);
|
||||||
|
if (r < 0)
|
||||||
|
goto finish;
|
||||||
|
|
||||||
|
r = append_access_mounts(&m, no_exec_paths, NOEXEC, require_prefix);
|
||||||
|
if (r < 0)
|
||||||
|
goto finish;
|
||||||
|
|
||||||
r = append_empty_dir_mounts(&m, empty_directories);
|
r = append_empty_dir_mounts(&m, empty_directories);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
@ -1869,6 +1942,21 @@ int setup_namespace(
|
|||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Third round, flip the noexec bits with a simplified deny list. */
|
||||||
|
for (m = mounts, j = 0; m < mounts + n_mounts; ++m)
|
||||||
|
if (IN_SET(m->mode, EXEC, NOEXEC))
|
||||||
|
deny_list[j++] = (char*) mount_entry_path(m);
|
||||||
|
deny_list[j] = NULL;
|
||||||
|
|
||||||
|
for (m = mounts; m < mounts + n_mounts; ++m) {
|
||||||
|
r = make_noexec(m, deny_list, proc_self_mountinfo);
|
||||||
|
if (r < 0) {
|
||||||
|
if (error_path && mount_entry_path(m))
|
||||||
|
*error_path = strdup(mount_entry_path(m));
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MS_MOVE does not work on MS_SHARED so the remount MS_SHARED will be done later */
|
/* MS_MOVE does not work on MS_SHARED so the remount MS_SHARED will be done later */
|
||||||
|
@ -108,6 +108,8 @@ int setup_namespace(
|
|||||||
char **read_write_paths,
|
char **read_write_paths,
|
||||||
char **read_only_paths,
|
char **read_only_paths,
|
||||||
char **inaccessible_paths,
|
char **inaccessible_paths,
|
||||||
|
char **exec_paths,
|
||||||
|
char **no_exec_paths,
|
||||||
char **empty_directories,
|
char **empty_directories,
|
||||||
const BindMount *bind_mounts,
|
const BindMount *bind_mounts,
|
||||||
size_t n_bind_mounts,
|
size_t n_bind_mounts,
|
||||||
|
@ -904,6 +904,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
|||||||
"ReadWritePaths",
|
"ReadWritePaths",
|
||||||
"ReadOnlyPaths",
|
"ReadOnlyPaths",
|
||||||
"InaccessiblePaths",
|
"InaccessiblePaths",
|
||||||
|
"ExecPaths",
|
||||||
|
"NoExecPaths",
|
||||||
"RuntimeDirectory",
|
"RuntimeDirectory",
|
||||||
"StateDirectory",
|
"StateDirectory",
|
||||||
"CacheDirectory",
|
"CacheDirectory",
|
||||||
|
@ -210,13 +210,14 @@ int bind_remount_recursive_with_mountinfo(
|
|||||||
assert(prefix);
|
assert(prefix);
|
||||||
assert(proc_self_mountinfo);
|
assert(proc_self_mountinfo);
|
||||||
|
|
||||||
/* Recursively remount a directory (and all its submounts) read-only or read-write. If the directory is already
|
/* Recursively remount a directory (and all its submounts) with desired flags (MS_READONLY,
|
||||||
* mounted, we reuse the mount and simply mark it MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write
|
* MS_NOSUID, MS_NOEXEC). If the directory is already mounted, we reuse the mount and simply mark it
|
||||||
* operation). If it isn't we first make it one. Afterwards we apply MS_BIND|MS_RDONLY (or remove MS_RDONLY) to
|
* MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write operation), ditto for other flags. If it
|
||||||
* all submounts we can access, too. When mounts are stacked on the same mount point we only care for each
|
* isn't we first make it one. Afterwards we apply (or remove) the flags to all submounts we can
|
||||||
* individual "top-level" mount on each point, as we cannot influence/access the underlying mounts anyway. We
|
* access, too. When mounts are stacked on the same mount point we only care for each individual
|
||||||
* do not have any effect on future submounts that might get propagated, they might be writable. This includes
|
* "top-level" mount on each point, as we cannot influence/access the underlying mounts anyway. We do
|
||||||
* future submounts that have been triggered via autofs.
|
* not have any effect on future submounts that might get propagated, they might be writable
|
||||||
|
* etc. This includes future submounts that have been triggered via autofs.
|
||||||
*
|
*
|
||||||
* If the "deny_list" parameter is specified it may contain a list of subtrees to exclude from the
|
* If the "deny_list" parameter is specified it may contain a list of subtrees to exclude from the
|
||||||
* remount operation. Note that we'll ignore the deny list for the top-level path. */
|
* remount operation. Note that we'll ignore the deny list for the top-level path. */
|
||||||
|
@ -408,6 +408,11 @@ static void test_exec_inaccessiblepaths(Manager *m) {
|
|||||||
test(m, "exec-inaccessiblepaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
|
test(m, "exec-inaccessiblepaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_exec_noexecpaths(Manager *m) {
|
||||||
|
|
||||||
|
test(m, "exec-noexecpaths-simple.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_exec_temporaryfilesystem(Manager *m) {
|
static void test_exec_temporaryfilesystem(Manager *m) {
|
||||||
|
|
||||||
test(m, "exec-temporaryfilesystem-options.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
|
test(m, "exec-temporaryfilesystem-options.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
|
||||||
@ -865,6 +870,7 @@ int main(int argc, char *argv[]) {
|
|||||||
entry(test_exec_ignoresigpipe),
|
entry(test_exec_ignoresigpipe),
|
||||||
entry(test_exec_inaccessiblepaths),
|
entry(test_exec_inaccessiblepaths),
|
||||||
entry(test_exec_ioschedulingclass),
|
entry(test_exec_ioschedulingclass),
|
||||||
|
entry(test_exec_noexecpaths),
|
||||||
entry(test_exec_oomscoreadjust),
|
entry(test_exec_oomscoreadjust),
|
||||||
entry(test_exec_passenvironment),
|
entry(test_exec_passenvironment),
|
||||||
entry(test_exec_personality),
|
entry(test_exec_personality),
|
||||||
|
@ -157,6 +157,8 @@ static void test_protect_kernel_logs(void) {
|
|||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
NULL, 0,
|
NULL, 0,
|
||||||
NULL, 0,
|
NULL, 0,
|
||||||
NULL, 0,
|
NULL, 0,
|
||||||
|
@ -26,6 +26,19 @@ int main(int argc, char *argv[]) {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char * const exec[] = {
|
||||||
|
"/lib",
|
||||||
|
"/usr",
|
||||||
|
"-/lib64",
|
||||||
|
"-/usr/lib64",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
const char * const no_exec[] = {
|
||||||
|
"/var",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
const char *inaccessible[] = {
|
const char *inaccessible[] = {
|
||||||
"/home/lennart/projects",
|
"/home/lennart/projects",
|
||||||
NULL
|
NULL
|
||||||
@ -70,6 +83,8 @@ int main(int argc, char *argv[]) {
|
|||||||
(char **) writable,
|
(char **) writable,
|
||||||
(char **) readonly,
|
(char **) readonly,
|
||||||
(char **) inaccessible,
|
(char **) inaccessible,
|
||||||
|
(char **) exec,
|
||||||
|
(char **) no_exec,
|
||||||
NULL,
|
NULL,
|
||||||
&(BindMount) { .source = (char*) "/usr/bin", .destination = (char*) "/etc/systemd", .read_only = true }, 1,
|
&(BindMount) { .source = (char*) "/usr/bin", .destination = (char*) "/etc/systemd", .read_only = true }, 1,
|
||||||
&(TemporaryFileSystem) { .path = (char*) "/var", .options = (char*) "ro" }, 1,
|
&(TemporaryFileSystem) { .path = (char*) "/var", .options = (char*) "ro" }, 1,
|
||||||
|
@ -85,6 +85,7 @@ DirectoryMode=
|
|||||||
DirectoryNotEmpty=
|
DirectoryNotEmpty=
|
||||||
Documentation=
|
Documentation=
|
||||||
DynamicUser=
|
DynamicUser=
|
||||||
|
ExecPaths=
|
||||||
ExecReload=
|
ExecReload=
|
||||||
ExecCondition=
|
ExecCondition=
|
||||||
ExecStart=
|
ExecStart=
|
||||||
@ -147,6 +148,7 @@ MessageQueueMaxMessages=
|
|||||||
MessageQueueMessageSize=
|
MessageQueueMessageSize=
|
||||||
MountAPIVFS=
|
MountAPIVFS=
|
||||||
NoDelay=
|
NoDelay=
|
||||||
|
NoExecPaths=
|
||||||
NoNewPrivileges=
|
NoNewPrivileges=
|
||||||
NonBlocking=
|
NonBlocking=
|
||||||
NotifyAccess=
|
NotifyAccess=
|
||||||
|
10
test/test-execute/exec-noexecpaths-simple.service
Normal file
10
test/test-execute/exec-noexecpaths-simple.service
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Test for NoExecPaths=
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
# This should work, as we explicitly disable the effect of NoExecPaths=
|
||||||
|
ExecStart=+/bin/sh -c '/bin/cat /dev/null'
|
||||||
|
# This should also work, as we do not disable the effect of NoExecPaths= but invert the exit code
|
||||||
|
ExecStart=/bin/sh -x -c '! /bin/cat /dev/null'
|
||||||
|
NoExecPaths=/bin/cat
|
@ -2088,6 +2088,10 @@ _test_cleanup() {
|
|||||||
set +e
|
set +e
|
||||||
_umount_dir $initdir
|
_umount_dir $initdir
|
||||||
rm -vf "$IMAGE_PUBLIC"
|
rm -vf "$IMAGE_PUBLIC"
|
||||||
|
# If multiple setups/cleans are ran in parallel, this can cause a race
|
||||||
|
if [ ${TEST_PARALLELIZE} -ne 1 ]; then
|
||||||
|
rm -vf "${IMAGESTATEDIR}/default.img"
|
||||||
|
fi
|
||||||
rm -vfr "$TESTDIR"
|
rm -vfr "$TESTDIR"
|
||||||
rm -vf "$STATEFILE"
|
rm -vf "$STATEFILE"
|
||||||
) || :
|
) || :
|
||||||
|
@ -18,6 +18,11 @@ try:
|
|||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
shlex_join = e
|
shlex_join = e
|
||||||
|
|
||||||
|
try:
|
||||||
|
from shlex import quote as shlex_quote
|
||||||
|
except ImportError as e:
|
||||||
|
shlex_quote = e
|
||||||
|
|
||||||
class NoCommand(Exception):
|
class NoCommand(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -186,6 +191,9 @@ def subst_output(document, programlisting, stats):
|
|||||||
interface = programlisting.get('interface')
|
interface = programlisting.get('interface')
|
||||||
|
|
||||||
argv = [f'{opts.build_dir}/{executable}', f'--bus-introspect={interface}']
|
argv = [f'{opts.build_dir}/{executable}', f'--bus-introspect={interface}']
|
||||||
|
if isinstance(shlex_join, Exception):
|
||||||
|
print(f'COMMAND: {" ".join(shlex_quote(arg) for arg in argv)}')
|
||||||
|
else:
|
||||||
print(f'COMMAND: {shlex_join(argv)}')
|
print(f'COMMAND: {shlex_join(argv)}')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -296,7 +304,7 @@ def parse_args():
|
|||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
opts = parse_args()
|
opts = parse_args()
|
||||||
|
|
||||||
for item in (etree, shlex_join):
|
for item in (etree, shlex_quote):
|
||||||
if isinstance(item, Exception):
|
if isinstance(item, Exception):
|
||||||
print(item, file=sys.stderr)
|
print(item, file=sys.stderr)
|
||||||
exit(77 if opts.test else 1)
|
exit(77 if opts.test else 1)
|
||||||
@ -308,7 +316,7 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
# Let's print all statistics at the end
|
# Let's print all statistics at the end
|
||||||
mlen = max(len(page) for page in stats)
|
mlen = max(len(page) for page in stats)
|
||||||
total = sum((item['stats'] for item in stats.values()), start=collections.Counter())
|
total = sum((item['stats'] for item in stats.values()), collections.Counter())
|
||||||
total = 'total', dict(stats=total, outdated=False)
|
total = 'total', dict(stats=total, outdated=False)
|
||||||
outdated = []
|
outdated = []
|
||||||
for page, info in sorted(stats.items()) + [total]:
|
for page, info in sorted(stats.items()) + [total]:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user