1
0
mirror of https://github.com/systemd/systemd synced 2026-04-15 11:34:50 +02:00

Compare commits

..

No commits in common. "ac16a593cf4ecf8dd04b8be78fd2e8fd2fe55991" and "0d63af09773512f7853d9e9ff186cd2cfc0cea04" have entirely different histories.

24 changed files with 101 additions and 398 deletions

View File

@ -2682,8 +2682,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s RootVerity = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as ExtensionDirectories = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(sba(ss)) ExtensionImages = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(ssba(ss)) MountImages = [...];
@ -3829,8 +3827,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<variablelist class="dbus-property" generated="True" extra-ref="RootVerity"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExtensionDirectories"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExtensionImages"/>
<variablelist class="dbus-property" generated="True" extra-ref="MountImages"/>
@ -4189,7 +4185,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<varname>RootHashSignature</varname>
<varname>MountImages</varname>
<varname>ExtensionImages</varname>
<varname>ExtensionDirectories</varname>
see systemd.exec(5) for their meaning.</para>
<para><varname>MemoryAvailable</varname> indicates how much unused memory is available to the unit before
@ -4564,8 +4559,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s RootVerity = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as ExtensionDirectories = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(sba(ss)) ExtensionImages = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(ssba(ss)) MountImages = [...];
@ -5729,8 +5722,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
<variablelist class="dbus-property" generated="True" extra-ref="RootVerity"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExtensionDirectories"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExtensionImages"/>
<variablelist class="dbus-property" generated="True" extra-ref="MountImages"/>
@ -6353,8 +6344,6 @@ node /org/freedesktop/systemd1/unit/home_2emount {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s RootVerity = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as ExtensionDirectories = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(sba(ss)) ExtensionImages = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(ssba(ss)) MountImages = [...];
@ -7364,8 +7353,6 @@ node /org/freedesktop/systemd1/unit/home_2emount {
<variablelist class="dbus-property" generated="True" extra-ref="RootVerity"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExtensionDirectories"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExtensionImages"/>
<variablelist class="dbus-property" generated="True" extra-ref="MountImages"/>
@ -8115,8 +8102,6 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s RootVerity = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly as ExtensionDirectories = ['...', ...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(sba(ss)) ExtensionImages = [...];
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly a(ssba(ss)) MountImages = [...];
@ -9098,8 +9083,6 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
<variablelist class="dbus-property" generated="True" extra-ref="RootVerity"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExtensionDirectories"/>
<variablelist class="dbus-property" generated="True" extra-ref="ExtensionImages"/>
<variablelist class="dbus-property" generated="True" extra-ref="MountImages"/>

View File

@ -459,34 +459,6 @@
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>ExtensionDirectories=</varname></term>
<listitem><para>This setting is similar to <varname>BindReadOnlyPaths=</varname> in that it mounts a file
system hierarchy from a directory, but instead of providing a destination path, an overlay will be set
up. This option expects a whitespace separated list of source directories.</para>
<para>A read-only OverlayFS will be set up on top of <filename>/usr/</filename> and
<filename>/opt/</filename> hierarchies. The order in which the directories are listed will determine
the order in which the overlay is laid down: directories specified first to last will result in overlayfs
layers bottom to top.</para>
<para>Each directory listed in <varname>ExtensionDirectories=</varname> may be prefixed with <literal>-</literal>,
in which case it will be ignored when its source path does not exist. Any mounts created with this option are
specific to the unit, and are not visible in the host's mount table.</para>
<para>These settings may be used more than once, each usage appends to the unit's list of directories
paths. If the empty string is assigned, the entire list of mount paths defined prior to this is
reset.</para>
<para>Each directory must contain a <filename>/usr/lib/extension-release.d/extension-release.IMAGE</filename>
file, with the appropriate metadata which matches <varname>RootImage=</varname>/<varname>RootDirectory=</varname>
or the host. See:
<citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@ -2098,16 +2098,6 @@ Note that this setting is <emphasis>not</emphasis> influenced by the <varname>Us
<xi:include href="standard-specifiers.xml" xpointer="V"/>
<xi:include href="standard-specifiers.xml" xpointer="w"/>
<xi:include href="standard-specifiers.xml" xpointer="W"/>
<row>
<entry><literal>%y</literal></entry>
<entry>The path to the fragment</entry>
<entry>This is the path where the main part of the unit file is located. For linked unit files, the real path outside of the unit search directories is used. For units that don't have a fragment file, this specifier will raise an error.</entry>
</row>
<row>
<entry><literal>%Y</literal></entry>
<entry>The directory of the fragment</entry>
<entry>This is the directory part of <literal>%y</literal>.</entry>
</row>
<xi:include href="standard-specifiers.xml" xpointer="percent"/>
</tbody>
</tgroup>

View File

@ -1204,7 +1204,6 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("RootHashSignature", "ay", property_get_root_hash_sig, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RootHashSignaturePath", "s", NULL, offsetof(ExecContext, root_hash_sig_path), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RootVerity", "s", NULL, offsetof(ExecContext, root_verity), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ExtensionDirectories", "as", NULL, offsetof(ExecContext, extension_directories), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ExtensionImages", "a(sba(ss))", property_get_extension_images, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MountImages", "a(ssba(ss))", property_get_mount_images, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@ -3262,8 +3261,7 @@ int bus_exec_context_set_transient_property(
return 1;
} else if (STR_IN_SET(name, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
"ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths", "ExecPaths", "NoExecPaths",
"ExtensionDirectories")) {
"ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths", "ExecPaths", "NoExecPaths")) {
_cleanup_strv_free_ char **l = NULL;
char ***dirs;
char **p;
@ -3293,8 +3291,6 @@ int bus_exec_context_set_transient_property(
dirs = &c->exec_paths;
else if (streq(name, "NoExecPaths"))
dirs = &c->no_exec_paths;
else if (streq(name, "ExtensionDirectories"))
dirs = &c->extension_directories;
else /* "InaccessiblePaths" */
dirs = &c->inaccessible_paths;

View File

@ -2065,9 +2065,6 @@ bool exec_needs_mount_namespace(
if (context->n_extension_images > 0)
return true;
if (!strv_isempty(context->extension_directories))
return true;
if (!IN_SET(context->mount_flags, 0, MS_SHARED))
return true;
@ -3569,7 +3566,6 @@ static int apply_mount_namespace(
context->root_verity,
context->extension_images,
context->n_extension_images,
context->extension_directories,
propagate_dir,
incoming_dir,
root_dir || root_image ? params->notify_socket : NULL,
@ -5248,7 +5244,6 @@ void exec_context_done(ExecContext *c) {
c->root_hash_sig_path = mfree(c->root_hash_sig_path);
c->root_verity = mfree(c->root_verity);
c->extension_images = mount_image_free_many(c->extension_images, &c->n_extension_images);
c->extension_directories = strv_free(c->extension_directories);
c->tty_path = mfree(c->tty_path);
c->syslog_identifier = mfree(c->syslog_identifier);
c->user = mfree(c->user);
@ -6125,8 +6120,6 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
strempty(o->options));
fprintf(f, "\n");
}
strv_dump(f, prefix, "ExtensionDirectories", c->extension_directories);
}
bool exec_context_maintains_privileges(const ExecContext *c) {

View File

@ -273,7 +273,6 @@ struct ExecContext {
size_t n_mount_images;
MountImage *extension_images;
size_t n_extension_images;
char **extension_directories;
uint64_t capability_bounding_set;
uint64_t capability_ambient_set;

View File

@ -9,7 +9,6 @@
{{type}}.RootHash, config_parse_exec_root_hash, 0, offsetof({{type}}, exec_context)
{{type}}.RootHashSignature, config_parse_exec_root_hash_sig, 0, offsetof({{type}}, exec_context)
{{type}}.RootVerity, config_parse_unit_path_printf, true, offsetof({{type}}, exec_context.root_verity)
{{type}}.ExtensionDirectories, config_parse_namespace_path_strv, 0, offsetof({{type}}, exec_context.extension_directories)
{{type}}.ExtensionImages, config_parse_extension_images, 0, offsetof({{type}}, exec_context)
{{type}}.MountImages, config_parse_mount_images, 0, offsetof({{type}}, exec_context)
{{type}}.User, config_parse_user_group_compat, 0, offsetof({{type}}, exec_context.user)

View File

@ -63,7 +63,6 @@ typedef enum MountMode {
EXEC,
TMPFS,
RUN,
EXTENSION_DIRECTORIES, /* Bind-mounted outside the root directory, and used by subsequent mounts */
EXTENSION_IMAGES, /* Mounted outside the root directory, and used by subsequent mounts */
MQUEUEFS,
READWRITE_IMPLICIT, /* Should have the lowest priority. */
@ -409,23 +408,22 @@ static int append_mount_images(MountEntry **p, const MountImage *mount_images, s
return 0;
}
static int append_extensions(
static int append_extension_images(
MountEntry **p,
const char *root,
const char *extension_dir,
char **hierarchies,
const MountImage *mount_images,
size_t n,
char **extension_directories) {
size_t n) {
_cleanup_strv_free_ char **overlays = NULL;
char **hierarchy, **extension_directory;
char **hierarchy;
int r;
assert(p);
assert(extension_dir);
if (n == 0 && strv_isempty(extension_directories))
if (n == 0)
return 0;
/* Prepare a list of overlays, that will have as each element a string suitable for being
@ -484,62 +482,6 @@ static int append_extensions(
};
}
/* Secondly, extend the lowerdir= parameters with each ExtensionDirectory.
* Bind mount them in the same location as the ExtensionImages, so that we
* can check that they are valid trees (extension-release.d). */
STRV_FOREACH(extension_directory, extension_directories) {
_cleanup_free_ char *mount_point = NULL, *source = NULL;
const char *e = *extension_directory;
bool ignore_enoent = false;
/* Pick up the counter where the ExtensionImages left it. */
r = asprintf(&mount_point, "%s/%zu", extension_dir, n++);
if (r < 0)
return -ENOMEM;
/* Look for any prefixes */
if (startswith(e, "-")) {
e++;
ignore_enoent = true;
}
/* Ignore this for now */
if (startswith(e, "+"))
e++;
source = strdup(e);
if (!source)
return -ENOMEM;
for (size_t j = 0; hierarchies && hierarchies[j]; ++j) {
_cleanup_free_ char *prefixed_hierarchy = NULL, *escaped = NULL, *lowerdir = NULL;
prefixed_hierarchy = path_join(mount_point, hierarchies[j]);
if (!prefixed_hierarchy)
return -ENOMEM;
escaped = shell_escape(prefixed_hierarchy, ",:");
if (!escaped)
return -ENOMEM;
/* Note that lowerdir= parameters are in 'reverse' order, so the
* top-most directory in the overlay comes first in the list. */
lowerdir = strjoin(escaped, ":", overlays[j]);
if (!lowerdir)
return -ENOMEM;
free_and_replace(overlays[j], lowerdir);
}
*((*p)++) = (MountEntry) {
.path_malloc = TAKE_PTR(mount_point),
.source_const = TAKE_PTR(source),
.mode = EXTENSION_DIRECTORIES,
.ignore = ignore_enoent,
.has_prefix = true,
.read_only = true,
};
}
/* Then, for each hierarchy, prepare an overlay with the list of lowerdir= strings
* set up earlier. */
for (size_t i = 0; hierarchies && hierarchies[i]; ++i) {
@ -663,12 +605,9 @@ static int append_protect_system(MountEntry **p, ProtectSystem protect_system, b
static int mount_path_compare(const MountEntry *a, const MountEntry *b) {
int d;
/* ExtensionImages/Directories will be used by other mounts as a base, so sort them first
/* EXTENSION_IMAGES will be used by other mounts as a base, so sort them first
* regardless of the prefix - they are set up in the propagate directory anyway */
d = -CMP(a->mode == EXTENSION_IMAGES, b->mode == EXTENSION_IMAGES);
if (d != 0)
return d;
d = -CMP(a->mode == EXTENSION_DIRECTORIES, b->mode == EXTENSION_DIRECTORIES);
if (d != 0)
return d;
@ -818,8 +757,8 @@ static void drop_outside_root(const char *root_directory, MountEntry *m, size_t
for (f = m, t = m; f < m + *n; f++) {
/* ExtensionImages/Directories bases are opened in /run/systemd/unit-extensions on the host */
if (!IN_SET(f->mode, EXTENSION_IMAGES, EXTENSION_DIRECTORIES) && !path_startswith(mount_entry_path(f), root_directory)) {
/* ExtensionImages bases are opened in /run/systemd/unit-extensions on the host */
if (f->mode != EXTENSION_IMAGES && !path_startswith(mount_entry_path(f), root_directory)) {
log_debug("%s is outside of root directory.", mount_entry_path(f));
mount_entry_done(f);
continue;
@ -1357,47 +1296,6 @@ static int apply_one_mount(
what = mount_entry_path(m);
break;
case EXTENSION_DIRECTORIES: {
_cleanup_free_ char *host_os_release_id = NULL, *host_os_release_version_id = NULL,
*host_os_release_sysext_level = NULL, *extension_name = NULL;
_cleanup_strv_free_ char **extension_release = NULL;
r = path_extract_filename(mount_entry_source(m), &extension_name);
if (r < 0)
return log_debug_errno(r, "Failed to extract extension name from %s: %m", mount_entry_source(m));
r = parse_os_release(
empty_to_root(root_directory),
"ID", &host_os_release_id,
"VERSION_ID", &host_os_release_version_id,
"SYSEXT_LEVEL", &host_os_release_sysext_level,
NULL);
if (r < 0)
return log_debug_errno(r, "Failed to acquire 'os-release' data of OS tree '%s': %m", empty_to_root(root_directory));
if (isempty(host_os_release_id))
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "'ID' field not found or empty in 'os-release' data of OS tree '%s': %m", empty_to_root(root_directory));
r = load_extension_release_pairs(mount_entry_source(m), extension_name, &extension_release);
if (r == -ENOENT && m->ignore)
return 0;
if (r < 0)
return log_debug_errno(r, "Failed to parse directory %s extension-release metadata: %m", extension_name);
r = extension_release_validate(
extension_name,
host_os_release_id,
host_os_release_version_id,
host_os_release_sysext_level,
/* host_sysext_scope */ NULL, /* Leave empty, we need to accept both system and portable */
extension_release);
if (r == 0)
return log_debug_errno(SYNTHETIC_ERRNO(ESTALE), "Directory %s extension-release metadata does not match the root's", extension_name);
if (r < 0)
return log_debug_errno(r, "Failed to compare directory %s extension-release metadata with the root's os-release: %m", extension_name);
_fallthrough_;
}
case BIND_MOUNT:
rbind = false;
@ -1627,7 +1525,6 @@ static size_t namespace_calculate_mounts(
size_t n_temporary_filesystems,
size_t n_mount_images,
size_t n_extension_images,
size_t n_extension_directories,
size_t n_hierarchies,
const char* tmp_dir,
const char* var_tmp_dir,
@ -1662,8 +1559,7 @@ static size_t namespace_calculate_mounts(
strv_length(empty_directories) +
n_bind_mounts +
n_mount_images +
(n_extension_images > 0 || n_extension_directories > 0 ? /* Mount each image and directory plus an overlay per hierarchy */
n_hierarchies + n_extension_images + n_extension_directories: 0) +
(n_extension_images > 0 ? n_hierarchies + n_extension_images : 0) + /* Mount each image plus an overlay per hierarchy */
n_temporary_filesystems +
ns_info->private_dev +
(ns_info->protect_kernel_tunables ?
@ -1759,8 +1655,8 @@ static int apply_mounts(
if (m->applied)
continue;
/* ExtensionImages/Directories are first opened in the propagate directory, not in the root_directory */
r = follow_symlink(!IN_SET(m->mode, EXTENSION_IMAGES, EXTENSION_DIRECTORIES) ? root : NULL, m);
/* ExtensionImages are first opened in the propagate directory, not in the root_directory */
r = follow_symlink(m->mode != EXTENSION_IMAGES ? root : NULL, m);
if (r < 0) {
if (error_path && mount_entry_path(m))
*error_path = strdup(mount_entry_path(m));
@ -1983,7 +1879,6 @@ int setup_namespace(
const char *verity_data_path,
const MountImage *extension_images,
size_t n_extension_images,
char **extension_directories,
const char *propagate_dir,
const char *incoming_dir,
const char *notify_socket,
@ -2097,7 +1992,7 @@ int setup_namespace(
require_prefix = true;
}
if (n_extension_images > 0 || !strv_isempty(extension_directories)) {
if (n_extension_images > 0) {
r = parse_env_extension_hierarchies(&hierarchies);
if (r < 0)
return r;
@ -2115,7 +2010,6 @@ int setup_namespace(
n_temporary_filesystems,
n_mount_images,
n_extension_images,
strv_length(extension_directories),
strv_length(hierarchies),
tmp_dir, var_tmp_dir,
creds_path,
@ -2184,7 +2078,7 @@ int setup_namespace(
if (r < 0)
goto finish;
r = append_extensions(&m, root, extension_dir, hierarchies, extension_images, n_extension_images, extension_directories);
r = append_extension_images(&m, root, extension_dir, hierarchies, extension_images, n_extension_images);
if (r < 0)
goto finish;

View File

@ -142,7 +142,6 @@ int setup_namespace(
const char *root_verity,
const MountImage *extension_images,
size_t n_extension_images,
char **extension_directories,
const char *propagate_dir,
const char *incoming_dir,
const char *notify_socket,

View File

@ -13,22 +13,28 @@
#include "user-util.h"
static int specifier_prefix_and_instance(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const Unit *u = ASSERT_PTR(userdata);
const Unit *u = userdata;
assert(u);
return unit_name_to_prefix_and_instance(u->id, ret);
}
static int specifier_prefix(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const Unit *u = ASSERT_PTR(userdata);
const Unit *u = userdata;
assert(u);
return unit_name_to_prefix(u->id, ret);
}
static int specifier_prefix_unescaped(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
_cleanup_free_ char *p = NULL;
const Unit *u = ASSERT_PTR(userdata);
const Unit *u = userdata;
int r;
assert(u);
r = unit_name_to_prefix(u->id, &p);
if (r < 0)
return r;
@ -37,17 +43,21 @@ static int specifier_prefix_unescaped(char specifier, const void *data, const ch
}
static int specifier_instance_unescaped(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const Unit *u = ASSERT_PTR(userdata);
const Unit *u = userdata;
assert(u);
return unit_name_unescape(strempty(u->instance), ret);
}
static int specifier_last_component(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const Unit *u = ASSERT_PTR(userdata);
const Unit *u = userdata;
_cleanup_free_ char *prefix = NULL;
char *dash;
int r;
assert(u);
r = unit_name_to_prefix(u->id, &prefix);
if (r < 0)
return r;
@ -72,7 +82,9 @@ static int specifier_last_component_unescaped(char specifier, const void *data,
}
static int specifier_filename(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const Unit *u = ASSERT_PTR(userdata);
const Unit *u = userdata;
assert(u);
if (u->instance)
return unit_name_path_unescape(u->instance, ret);
@ -85,9 +97,11 @@ static void bad_specifier(const Unit *u, char specifier) {
}
static int specifier_cgroup(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const Unit *u = ASSERT_PTR(userdata);
const Unit *u = userdata;
char *n;
assert(u);
bad_specifier(u, specifier);
if (u->cgroup_path)
@ -102,9 +116,11 @@ static int specifier_cgroup(char specifier, const void *data, const char *root,
}
static int specifier_cgroup_root(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const Unit *u = ASSERT_PTR(userdata);
const Unit *u = userdata;
char *n;
assert(u);
bad_specifier(u, specifier);
n = strdup(u->manager->cgroup_root);
@ -116,9 +132,11 @@ static int specifier_cgroup_root(char specifier, const void *data, const char *r
}
static int specifier_cgroup_slice(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const Unit *u = ASSERT_PTR(userdata), *slice;
const Unit *u = userdata, *slice;
char *n;
assert(u);
bad_specifier(u, specifier);
slice = UNIT_GET_SLICE(u);
@ -137,9 +155,11 @@ static int specifier_cgroup_slice(char specifier, const void *data, const char *
}
static int specifier_special_directory(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const Unit *u = ASSERT_PTR(userdata);
const Unit *u = userdata;
char *n = NULL;
assert(u);
n = strdup(u->manager->prefix[PTR_TO_UINT(data)]);
if (!n)
return -ENOMEM;
@ -149,6 +169,7 @@ static int specifier_special_directory(char specifier, const void *data, const c
}
int unit_name_printf(const Unit *u, const char* format, char **ret) {
/*
* This will use the passed string as format string and replace the following specifiers (which should all be
* safe for inclusion in unit names):
@ -219,8 +240,6 @@ int unit_full_printf_full(const Unit *u, const char *format, size_t max_length,
{ 'P', specifier_prefix_unescaped, NULL },
{ 'f', specifier_filename, NULL },
{ 'y', specifier_real_path, u->fragment_path },
{ 'Y', specifier_real_directory, u->fragment_path },
{ 'c', specifier_cgroup, NULL },
{ 'r', specifier_cgroup_slice, NULL },

View File

@ -973,7 +973,6 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
"ExecPaths",
"NoExecPaths",
"ExecSearchPath",
"ExtensionDirectories",
"ConfigurationDirectory",
"SupplementaryGroups",
"SystemCallArchitectures"))

View File

@ -14,10 +14,12 @@
#include "user-util.h"
static int specifier_prefix_and_instance(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const UnitFileInstallInfo *i = ASSERT_PTR(userdata);
const UnitFileInstallInfo *i = userdata;
_cleanup_free_ char *prefix = NULL;
int r;
assert(i);
r = unit_name_to_prefix_and_instance(i->name, &prefix);
if (r < 0)
return r;
@ -36,9 +38,11 @@ static int specifier_prefix_and_instance(char specifier, const void *data, const
}
static int specifier_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const UnitFileInstallInfo *i = ASSERT_PTR(userdata);
const UnitFileInstallInfo *i = userdata;
char *ans;
assert(i);
if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE) && i->default_instance)
return unit_name_replace_instance(i->name, i->default_instance, ret);
@ -50,16 +54,20 @@ static int specifier_name(char specifier, const void *data, const char *root, co
}
static int specifier_prefix(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const UnitFileInstallInfo *i = ASSERT_PTR(userdata);
const UnitFileInstallInfo *i = userdata;
assert(i);
return unit_name_to_prefix(i->name, ret);
}
static int specifier_instance(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const UnitFileInstallInfo *i = ASSERT_PTR(userdata);
const UnitFileInstallInfo *i = userdata;
char *instance;
int r;
assert(i);
r = unit_name_to_instance(i->name, &instance);
if (r < 0)
return r;
@ -79,8 +87,6 @@ static int specifier_last_component(char specifier, const void *data, const char
char *dash;
int r;
assert(ret);
r = specifier_prefix(specifier, data, root, userdata, &prefix);
if (r < 0)
return r;

View File

@ -18,7 +18,6 @@
#include "id128-util.h"
#include "macro.h"
#include "os-util.h"
#include "path-util.h"
#include "specifier.h"
#include "string-util.h"
#include "strv.h"
@ -36,6 +35,7 @@
int specifier_printf(const char *text, size_t max_length, const Specifier table[], const char *root, const void *userdata, char **ret) {
_cleanup_free_ char *result = NULL;
bool percent = false;
const char *f;
size_t l;
char *t;
int r;
@ -48,10 +48,8 @@ int specifier_printf(const char *text, size_t max_length, const Specifier table[
return -ENOMEM;
t = result;
for (const char *f = text; *f != '\0'; f++, l--) {
for (f = text; *f != '\0'; f++, l--) {
if (percent) {
percent = false;
if (*f == '%')
*(t++) = '%';
else {
@ -68,8 +66,6 @@ int specifier_printf(const char *text, size_t max_length, const Specifier table[
r = i->lookup(i->specifier, i->data, root, userdata, &w);
if (r < 0)
return r;
if (isempty(w))
continue;
j = t - result;
k = strlen(w);
@ -86,6 +82,8 @@ int specifier_printf(const char *text, size_t max_length, const Specifier table[
*(t++) = *f;
}
}
percent = false;
} else if (*f == '%')
percent = true;
else
@ -110,39 +108,16 @@ int specifier_printf(const char *text, size_t max_length, const Specifier table[
/* Generic handler for simple string replacements */
int specifier_string(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
char *n = NULL;
char *n;
if (!isempty(data)) {
n = strdup(data);
if (!n)
return -ENOMEM;
}
n = strdup(strempty(data));
if (!n)
return -ENOMEM;
*ret = n;
return 0;
}
int specifier_real_path(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const char *path = data;
if (!path)
return -ENOENT;
return chase_symlinks(path, root, 0, ret, NULL);
}
int specifier_real_directory(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
_cleanup_free_ char *path = NULL;
int r;
r = specifier_real_path(specifier, data, root, userdata, &path);
if (r < 0)
return r;
assert(path);
return path_extract_directory(path, ret);
}
int specifier_machine_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
sd_id128_t id;
char *n;
@ -211,8 +186,10 @@ int specifier_short_host_name(char specifier, const void *data, const char *root
int specifier_kernel_release(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
struct utsname uts;
char *n;
int r;
if (uname(&uts) < 0)
r = uname(&uts);
if (r < 0)
return -errno;
n = strdup(uts.release);
@ -234,31 +211,47 @@ int specifier_architecture(char specifier, const void *data, const char *root, c
return 0;
}
/* Note: fields in /etc/os-release might quite possibly be missing, even if everything is entirely valid
* otherwise. We'll return an empty value or NULL in that case from the functions below. */
static int specifier_os_release_common(const char *field, const char *root, char **ret) {
char *t = NULL;
int r;
r = parse_os_release(root, field, &t);
if (r < 0)
return r;
if (!t) {
/* fields in /etc/os-release might quite possibly be missing, even if everything is entirely
* valid otherwise. Let's hence return "" in that case. */
t = strdup("");
if (!t)
return -ENOMEM;
}
*ret = t;
return 0;
}
int specifier_os_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
return parse_os_release(root, "ID", ret);
return specifier_os_release_common("ID", root, ret);
}
int specifier_os_version_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
return parse_os_release(root, "VERSION_ID", ret);
return specifier_os_release_common("VERSION_ID", root, ret);
}
int specifier_os_build_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
return parse_os_release(root, "BUILD_ID", ret);
return specifier_os_release_common("BUILD_ID", root, ret);
}
int specifier_os_variant_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
return parse_os_release(root, "VARIANT_ID", ret);
return specifier_os_release_common("VARIANT_ID", root, ret);
}
int specifier_os_image_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
return parse_os_release(root, "IMAGE_ID", ret);
return specifier_os_release_common("IMAGE_ID", root, ret);
}
int specifier_os_image_version(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
return parse_os_release(root, "IMAGE_VERSION", ret);
return specifier_os_release_common("IMAGE_VERSION", root, ret);
}
int specifier_group_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
@ -298,6 +291,7 @@ int specifier_user_name(char specifier, const void *data, const char *root, cons
}
int specifier_user_id(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
if (asprintf(ret, UID_FMT, getuid()) < 0)
return -ENOMEM;

View File

@ -14,8 +14,6 @@ typedef struct Specifier {
int specifier_printf(const char *text, size_t max_length, const Specifier table[], const char *root, const void *userdata, char **ret);
int specifier_string(char specifier, const void *data, const char *root, const void *userdata, char **ret);
int specifier_real_path(char specifier, const void *data, const char *root, const void *userdata, char **ret);
int specifier_real_directory(char specifier, const void *data, const char *root, const void *userdata, char **ret);
int specifier_machine_id(char specifier, const void *data, const char *root, const void *userdata, char **ret);
int specifier_boot_id(char specifier, const void *data, const char *root, const void *userdata, char **ret);

View File

@ -207,7 +207,6 @@ TEST(protect_kernel_logs) {
NULL,
NULL,
NULL,
NULL,
NULL);
assert_se(r == 0);

View File

@ -108,7 +108,6 @@ int main(int argc, char *argv[]) {
NULL,
NULL,
NULL,
NULL,
NULL);
if (r < 0) {
log_error_errno(r, "Failed to set up namespace: %m");

View File

@ -3,7 +3,6 @@
#include "alloc-util.h"
#include "log.h"
#include "specifier.h"
#include "stat-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
@ -57,7 +56,6 @@ TEST(specifier_printf) {
static const Specifier table[] = {
{ 'X', specifier_string, (char*) "AAAA" },
{ 'Y', specifier_string, (char*) "BBBB" },
{ 'e', specifier_string, NULL },
COMMON_SYSTEM_SPECIFIERS,
{}
};
@ -65,66 +63,25 @@ TEST(specifier_printf) {
_cleanup_free_ char *w = NULL;
int r;
r = specifier_printf("xxx a=%X b=%Y e=%e yyy", SIZE_MAX, table, NULL, NULL, &w);
r = specifier_printf("xxx a=%X b=%Y yyy", SIZE_MAX, table, NULL, NULL, &w);
assert_se(r >= 0);
assert_se(w);
puts(w);
assert_se(streq(w, "xxx a=AAAA b=BBBB e= yyy"));
assert_se(streq(w, "xxx a=AAAA b=BBBB yyy"));
free(w);
r = specifier_printf("machine=%m, boot=%b, host=%H, version=%v, arch=%a, empty=%e", SIZE_MAX, table, NULL, NULL, &w);
r = specifier_printf("machine=%m, boot=%b, host=%H, version=%v, arch=%a", SIZE_MAX, table, NULL, NULL, &w);
assert_se(r >= 0);
assert_se(w);
puts(w);
w = mfree(w);
specifier_printf("os=%o, os-version=%w, build=%B, variant=%W, empty=%e%e%e", SIZE_MAX, table, NULL, NULL, &w);
specifier_printf("os=%o, os-version=%w, build=%B, variant=%W", SIZE_MAX, table, NULL, NULL, &w);
if (w)
puts(w);
}
TEST(specifier_real_path) {
static const Specifier table[] = {
{ 'p', specifier_string, "/dev/initctl" },
{ 'y', specifier_real_path, "/dev/initctl" },
{ 'Y', specifier_real_directory, "/dev/initctl" },
{ 'w', specifier_real_path, "/dev/tty" },
{ 'W', specifier_real_directory, "/dev/tty" },
{}
};
_cleanup_free_ char *w = NULL;
int r;
r = specifier_printf("p=%p y=%y Y=%Y w=%w W=%W", SIZE_MAX, table, NULL, NULL, &w);
assert_se(r >= 0 || r == -ENOENT);
assert_se(w || r == -ENOENT);
puts(strnull(w));
/* /dev/initctl should normally be a symlink to /run/initctl */
if (files_same("/dev/initctl", "/run/initctl", 0) > 0)
assert_se(streq(w, "p=/dev/initctl y=/run/initctl Y=/run w=/dev/tty W=/dev"));
}
TEST(specifier_real_path_missing_file) {
static const Specifier table[] = {
{ 'p', specifier_string, "/dev/-no-such-file--" },
{ 'y', specifier_real_path, "/dev/-no-such-file--" },
{ 'Y', specifier_real_directory, "/dev/-no-such-file--" },
{}
};
_cleanup_free_ char *w = NULL;
int r;
r = specifier_printf("p=%p y=%y", SIZE_MAX, table, NULL, NULL, &w);
assert_se(r == -ENOENT);
r = specifier_printf("p=%p Y=%Y", SIZE_MAX, table, NULL, NULL, &w);
assert_se(r == -ENOENT);
}
TEST(specifiers) {
for (const Specifier *s = specifier_table; s->specifier; s++) {
char spec[3];

View File

@ -232,14 +232,12 @@ static void cleanup_dir(DIR *dir, mode_t mask, int depth) {
if (depth <= 0)
return;
assert(dir);
FOREACH_DIRENT_ALL(dent, dir, break) {
struct stat stats;
if (dot_or_dot_dot(dent->d_name))
if (dent->d_name[0] == '.')
continue;
if (fstatat(dirfd(dir), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) < 0)
if (fstatat(dirfd(dir), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0)
continue;
if ((stats.st_mode & mask) != 0)
continue;
@ -256,62 +254,6 @@ static void cleanup_dir(DIR *dir, mode_t mask, int depth) {
}
}
/*
* Assume that dir is a directory with file names matching udev data base
* entries for devices in /run/udev/data (such as "b8:16"), and removes
* all files except those that haven't been deleted in /run/udev/data
* (i.e. they were skipped during db cleanup because of the db_persist flag).
* Returns true if the directory is empty after cleanup.
*/
static bool cleanup_dir_after_db_cleanup(DIR *dir, DIR *datadir) {
unsigned int kept = 0;
assert(dir && datadir);
FOREACH_DIRENT_ALL(dent, dir, break) {
struct stat data_stats, link_stats;
if (dot_or_dot_dot(dent->d_name))
continue;
if (fstatat(dirfd(dir), dent->d_name, &link_stats, AT_SYMLINK_NOFOLLOW) < 0) {
if (errno != ENOENT)
kept++;
continue;
}
if (fstatat(dirfd(datadir), dent->d_name, &data_stats, 0) < 0)
(void) unlinkat(dirfd(dir), dent->d_name,
S_ISDIR(link_stats.st_mode) ? AT_REMOVEDIR : 0);
else
/* The entry still exists under /run/udev/data */
kept++;
}
return kept == 0;
}
static void cleanup_dirs_after_db_cleanup(DIR *dir, DIR *datadir) {
assert(dir && datadir);
FOREACH_DIRENT_ALL(dent, dir, break) {
struct stat stats;
if (dot_or_dot_dot(dent->d_name))
continue;
if (fstatat(dirfd(dir), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) < 0)
continue;
if (S_ISDIR(stats.st_mode)) {
_cleanup_closedir_ DIR *dir2 = NULL;
dir2 = fdopendir(openat(dirfd(dir), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
if (dir2 && cleanup_dir_after_db_cleanup(dir2, datadir))
(void) unlinkat(dirfd(dir), dent->d_name, AT_REMOVEDIR);
} else
(void) unlinkat(dirfd(dir), dent->d_name, 0);
}
}
static void cleanup_db(void) {
_cleanup_closedir_ DIR *dir1 = NULL, *dir2 = NULL, *dir3 = NULL, *dir4 = NULL, *dir5 = NULL;
@ -321,11 +263,11 @@ static void cleanup_db(void) {
dir2 = opendir("/run/udev/links");
if (dir2)
cleanup_dirs_after_db_cleanup(dir2, dir1);
cleanup_dir(dir2, 0, 2);
dir3 = opendir("/run/udev/tags");
if (dir3)
cleanup_dirs_after_db_cleanup(dir3, dir1);
cleanup_dir(dir3, 0, 2);
dir4 = opendir("/run/udev/static_node-tags");
if (dir4)
@ -333,7 +275,7 @@ static void cleanup_db(void) {
dir5 = opendir("/run/udev/watch");
if (dir5)
cleanup_dir_after_db_cleanup(dir5, dir1);
cleanup_dir(dir5, 0, 1);
}
static int query_device(QueryType query, sd_device* device) {

View File

@ -217,7 +217,6 @@ RootImage=
RootHash=
RootHashSignature=
RootVerity=
ExtensionDirectories=
ExtensionImages=
RuntimeMaxSec=
SELinuxContextFromNet=

View File

@ -40,7 +40,6 @@ DynamicUser=
Environment=
EnvironmentFile=
ExecPaths=
ExtensionDirectories=
ExtensionImages=
FinalKillSignal=
ForceUnmount=

View File

@ -168,7 +168,6 @@ ExecStartPre=
ExecStop=
ExecStopPost=
ExitType=
ExtensionDirectories=
ExtensionImages=
FailureAction=
FileDescriptorStoreMax=

View File

@ -50,7 +50,6 @@ ExecStartPost=
ExecStartPre=
ExecStopPost=
ExecStopPre=
ExtensionDirectories=
ExtensionImages=
FileDescriptorName=
FinalKillSignal=

View File

@ -39,7 +39,6 @@ DynamicUser=
Environment=
EnvironmentFile=
ExecPaths=
ExtensionDirectories=
ExtensionImages=
FinalKillSignal=
Group=

View File

@ -321,36 +321,6 @@ EOF
systemctl start testservice-50e.service
systemctl is-active testservice-50e.service
# ExtensionDirectories will set up an overlay
mkdir -p "${image_dir}/app0" "${image_dir}/app1"
systemd-run -P --property ExtensionDirectories="${image_dir}/nonexistant" --property RootImage="${image}.raw" cat /opt/script0.sh && { echo 'unexpected success'; exit 1; }
systemd-run -P --property ExtensionDirectories="${image_dir}/app0" --property RootImage="${image}.raw" cat /opt/script0.sh && { echo 'unexpected success'; exit 1; }
systemd-dissect --mount /usr/share/app0.raw "${image_dir}/app0"
systemd-dissect --mount /usr/share/app1.raw "${image_dir}/app1"
systemd-run -P --property ExtensionDirectories="${image_dir}/app0" --property RootImage="${image}.raw" cat /opt/script0.sh | grep -q -F "extension-release.app0"
systemd-run -P --property ExtensionDirectories="${image_dir}/app0" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
systemd-run -P --property ExtensionDirectories="${image_dir}/app0 ${image_dir}/app1" --property RootImage="${image}.raw" cat /opt/script0.sh | grep -q -F "extension-release.app0"
systemd-run -P --property ExtensionDirectories="${image_dir}/app0 ${image_dir}/app1" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
systemd-run -P --property ExtensionDirectories="${image_dir}/app0 ${image_dir}/app1" --property RootImage="${image}.raw" cat /opt/script1.sh | grep -q -F "extension-release.app2"
systemd-run -P --property ExtensionDirectories="${image_dir}/app0 ${image_dir}/app1" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/other_file | grep -q -F "MARKER=1"
cat >/run/systemd/system/testservice-50f.service <<EOF
[Service]
MountAPIVFS=yes
TemporaryFileSystem=/run
RootImage=${image}.raw
ExtensionDirectories=${image_dir}/app0 ${image_dir}/app1
# Relevant only for sanitizer runs
UnsetEnvironment=LD_PRELOAD
ExecStart=/bin/bash -c '/opt/script0.sh | grep ID'
ExecStart=/bin/bash -c '/opt/script1.sh | grep ID'
Type=oneshot
RemainAfterExit=yes
EOF
systemctl start testservice-50f.service
systemctl is-active testservice-50f.service
umount "${image_dir}/app0"
umount "${image_dir}/app1"
echo OK >/testok
exit 0