mirror of
https://github.com/systemd/systemd
synced 2026-04-23 07:24:51 +02:00
Compare commits
27 Commits
ad337e55a3
...
af5ee76c56
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af5ee76c56 | ||
|
|
23484e1205 | ||
|
|
2cdd6bef9c | ||
|
|
46801e7647 | ||
|
|
09f5fc66f2 | ||
|
|
20afd9a184 | ||
|
|
4f5160698e | ||
|
|
f60b0813ea | ||
|
|
4f5c24857b | ||
|
|
d29cc4d6e1 | ||
|
|
d3e85c9c81 | ||
|
|
066931818d | ||
|
|
f1c70ed13d | ||
|
|
c3e7fba07c | ||
|
|
1219bd4306 | ||
|
|
4355c04fef | ||
|
|
827f865063 | ||
|
|
29e6f70b8d | ||
|
|
f79856d9e8 | ||
|
|
8d3e0d607e | ||
|
|
d16da79ec0 | ||
|
|
1c2b617703 | ||
|
|
acbb4d7ec4 | ||
|
|
d9ea4a210b | ||
|
|
55c8f9ecb0 | ||
|
|
43b9b2053c | ||
|
|
598a1d7633 |
16
man/system-or-user-ns.xml
Normal file
16
man/system-or-user-ns.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<!--
|
||||
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
-->
|
||||
|
||||
<refsect1>
|
||||
|
||||
<para id="singular">This option is only available for system services, or for services running in per-user
|
||||
instances of the service manager when unprivileged user namespaces are available.</para>
|
||||
|
||||
<para id="plural">These options are only available for system services, or for services running in per-user
|
||||
instances of the service manager when unprivileged user namespaces are available.</para>
|
||||
|
||||
</refsect1>
|
||||
@ -143,7 +143,9 @@
|
||||
<title>Mounting logging sockets into root environment</title>
|
||||
|
||||
<programlisting>BindReadOnlyPaths=/dev/log /run/systemd/journal/socket /run/systemd/journal/stdout</programlisting>
|
||||
</example></listitem>
|
||||
</example>
|
||||
|
||||
<xi:include href="system-or-user-ns.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -480,7 +482,9 @@
|
||||
<citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
||||
|
||||
<para>Note that usage from user units requires overlayfs support in unprivileged user namespaces,
|
||||
which was first introduced in kernel v5.11.</para></listitem>
|
||||
which was first introduced in kernel v5.11.</para>
|
||||
|
||||
<xi:include href="system-or-user-ns.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
@ -625,7 +629,7 @@
|
||||
<refsect1>
|
||||
<title>Capabilities</title>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="plural"/>
|
||||
<xi:include href="system-or-user-ns.xml" xpointer="plural"/>
|
||||
|
||||
<variablelist class='unit-directives'>
|
||||
|
||||
@ -1254,7 +1258,7 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
|
||||
<varname>DynamicUser=</varname> is set. This setting cannot ensure protection in all cases. In
|
||||
general it has the same limitations as <varname>ReadOnlyPaths=</varname>, see below.</para>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
<xi:include href="system-or-user-ns.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -1508,7 +1512,7 @@ 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-or-user-ns.xml" xpointer="plural"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -1533,7 +1537,7 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
|
||||
then the invoked processes by the unit cannot see any files or directories under <filename>/var/</filename> except for
|
||||
<filename>/var/lib/systemd</filename> or its contents.</para>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
<xi:include href="system-or-user-ns.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -1561,7 +1565,7 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
|
||||
available), and the unit should be written in a way that does not solely rely on this setting for
|
||||
security.</para>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
<xi:include href="system-or-user-ns.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -1595,7 +1599,7 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
|
||||
namespaces are not available), and the unit should be written in a way that does not solely rely on
|
||||
this setting for security.</para>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="singular"/>
|
||||
<xi:include href="system-or-user-ns.xml" xpointer="singular"/>
|
||||
|
||||
<para>When access to some but not all devices must be possible, the <varname>DeviceAllow=</varname>
|
||||
setting might be used instead. See
|
||||
@ -1629,7 +1633,7 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
|
||||
<varname>JoinsNamespaceOf=</varname> to listen on sockets inside of network namespaces of other
|
||||
services.</para>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
<xi:include href="system-or-user-ns.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -1648,7 +1652,7 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
|
||||
<para>When this option is used on a socket unit any sockets bound on behalf of this unit will be
|
||||
bound within the specified network namespace.</para>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
<xi:include href="system-or-user-ns.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -1679,7 +1683,7 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
|
||||
not available), and the unit should be written in a way that does not solely rely on this setting for
|
||||
security.</para>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
<xi:include href="system-or-user-ns.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -1695,7 +1699,7 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
|
||||
<varname>IPCNamespacePath=</varname> configured, as otherwise the network namespace of those
|
||||
units is reused.</para>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
<xi:include href="system-or-user-ns.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -1749,7 +1753,7 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
|
||||
capability (e.g. services for which <varname>User=</varname> is set),
|
||||
<varname>NoNewPrivileges=yes</varname> is implied.</para>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
<xi:include href="system-or-user-ns.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -1766,7 +1770,7 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
|
||||
doesn't have the <constant>CAP_SYS_ADMIN</constant> capability (e.g. services for which
|
||||
<varname>User=</varname> is set), <varname>NoNewPrivileges=yes</varname> is implied.</para>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
<xi:include href="system-or-user-ns.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -1790,7 +1794,7 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
|
||||
inaccessible. If <varname>ProtectKernelTunables=</varname> is set,
|
||||
<varname>MountAPIVFS=yes</varname> is implied.</para>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
<xi:include href="system-or-user-ns.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -1811,7 +1815,7 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
|
||||
but the unit doesn't have the <constant>CAP_SYS_ADMIN</constant> capability (e.g. services for
|
||||
which <varname>User=</varname> is set), <varname>NoNewPrivileges=yes</varname> is implied.</para>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
<xi:include href="system-or-user-ns.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -1830,7 +1834,7 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
|
||||
capability (e.g. services for which <varname>User=</varname> is set),
|
||||
<varname>NoNewPrivileges=yes</varname> is implied.</para>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
<xi:include href="system-or-user-ns.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -2134,7 +2138,7 @@ RestrictNamespaces=~cgroup net</programlisting>
|
||||
option. Hence it is primarily useful to explicitly request this behaviour if none of the other settings are
|
||||
used.</para>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
<xi:include href="system-or-user-ns.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -2164,7 +2168,7 @@ RestrictNamespaces=~cgroup net</programlisting>
|
||||
<para>Usually, it is best to leave this setting unmodified, and use higher level file system namespacing
|
||||
options instead, in particular <varname>PrivateMounts=</varname>, see above.</para>
|
||||
|
||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||
<xi:include href="system-or-user-ns.xml" xpointer="singular"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
@ -2714,8 +2718,8 @@ SystemCallErrorNumber=EPERM</programlisting>
|
||||
<varname>StandardInput=</varname>, see above. If <replaceable>path</replaceable> refers to a regular file
|
||||
on the filesystem, it is opened (created if it doesn't exist yet) for writing at the beginning of the file,
|
||||
but without truncating it.
|
||||
If standard input and output are directed to the same file path, it is opened only once, for reading as well
|
||||
as writing and duplicated. This is particularly useful when the specified path refers to an
|
||||
If standard input and output are directed to the same file path, it is opened only once — for reading as well
|
||||
as writing — and duplicated. This is particularly useful when the specified path refers to an
|
||||
<constant>AF_UNIX</constant> socket in the file system, as in that case only a
|
||||
single stream connection is created for both input and output.</para>
|
||||
|
||||
@ -2741,16 +2745,17 @@ SystemCallErrorNumber=EPERM</programlisting>
|
||||
<para><option>socket</option> connects standard output to a socket acquired via socket activation. The
|
||||
semantics are similar to the same option of <varname>StandardInput=</varname>, see above.</para>
|
||||
|
||||
<para>The <option>fd:<replaceable>name</replaceable></option> option connects standard output to a specific,
|
||||
named file descriptor provided by a socket unit. A name may be specified as part of this option, following a
|
||||
<literal>:</literal> character (e.g. <literal>fd:foobar</literal>). If no name is specified, the name
|
||||
<para>The <option>fd:<replaceable>name</replaceable></option> option connects standard output to a
|
||||
specific, named file descriptor provided by a socket unit. A name may be specified as part of this
|
||||
option, following a <literal>:</literal> character
|
||||
(e.g. <literal>fd:<replaceable>foobar</replaceable></literal>). If no name is specified, the name
|
||||
<literal>stdout</literal> is implied (i.e. <literal>fd</literal> is equivalent to
|
||||
<literal>fd:stdout</literal>). At least one socket unit defining the specified name must be provided via the
|
||||
<varname>Sockets=</varname> option, and the file descriptor name may differ from the name of its containing
|
||||
socket unit. If multiple matches are found, the first one will be used. See
|
||||
<literal>fd:stdout</literal>). At least one socket unit defining the specified name must be provided
|
||||
via the <varname>Sockets=</varname> option, and the file descriptor name may differ from the name of
|
||||
its containing socket unit. If multiple matches are found, the first one will be used. See
|
||||
<varname>FileDescriptorName=</varname> in
|
||||
<citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more
|
||||
details about named descriptors and their ordering.</para>
|
||||
<citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
for more details about named descriptors and their ordering.</para>
|
||||
|
||||
<para>If the standard output (or error output, see below) of a unit is connected to the journal or
|
||||
the kernel log buffer, the unit will implicitly gain a dependency of type <varname>After=</varname>
|
||||
|
||||
@ -1975,6 +1975,11 @@
|
||||
<entry>Cache directory root</entry>
|
||||
<entry>This is either <filename>/var/cache</filename> (for the system manager) or the path <literal>$XDG_CACHE_HOME</literal> resolves to (for user managers).</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>%d</literal></entry>
|
||||
<entry>Credentials directory</entry>
|
||||
<entry>This is the value of the <literal>$CREDENTIALS_DIRECTORY</literal> environment variable if available. See section "Credentials" in <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>%E</literal></entry>
|
||||
<entry>Configuration directory root</entry>
|
||||
|
||||
@ -32,7 +32,7 @@ _bootctl() {
|
||||
local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
local -A OPTS=(
|
||||
[STANDALONE]='-h --help -p --print-esp-path -x --print-boot-path --version --no-variables --no-pager --graceful'
|
||||
[ARG]='--esp-path --boot-path'
|
||||
[ARG]='--esp-path --boot-path --make-machine-id-directory'
|
||||
)
|
||||
|
||||
if __contains_word "$prev" ${OPTS[ARG]}; then
|
||||
@ -45,6 +45,9 @@ _bootctl() {
|
||||
fi
|
||||
compopt -o filenames
|
||||
;;
|
||||
--make-machine-id-directory)
|
||||
comps="yes no auto"
|
||||
;;
|
||||
esac
|
||||
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
||||
return 0
|
||||
|
||||
@ -69,6 +69,7 @@ _arguments \
|
||||
'--boot-path=[Path to the $BOOT partition]:path:_directories' \
|
||||
{-p,--print-esp-path}'[Print path to the EFI system partition]' \
|
||||
{-x,--print-boot-path}'[Print path to the $BOOT partition]' \
|
||||
'--make-machine-id-directory=[Control creation and deletion of the top-level machine ID directory.]:options:(yes no auto)' \
|
||||
'--no-variables[Do not touch EFI variables]' \
|
||||
'--no-pager[Do not pipe output into a pager]' \
|
||||
'--graceful[Do not fail when locating ESP or writing fails]' \
|
||||
|
||||
@ -23,7 +23,6 @@ static int parse_env_file_internal(
|
||||
size_t n_key = 0, n_value = 0, last_value_whitespace = SIZE_MAX, last_key_whitespace = SIZE_MAX;
|
||||
_cleanup_free_ char *contents = NULL, *key = NULL, *value = NULL;
|
||||
unsigned line = 1;
|
||||
char *p;
|
||||
int r;
|
||||
|
||||
enum {
|
||||
@ -46,7 +45,7 @@ static int parse_env_file_internal(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (p = contents; *p; p++) {
|
||||
for (char *p = contents; *p; p++) {
|
||||
char c = *p;
|
||||
|
||||
switch (state) {
|
||||
|
||||
@ -16,8 +16,8 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
|
||||
|
||||
#define typesafe_bsearch_r(k, b, n, func, userdata) \
|
||||
({ \
|
||||
const typeof(b[0]) *_k = k; \
|
||||
int (*_func_)(const typeof(b[0])*, const typeof(b[0])*, typeof(userdata)) = func; \
|
||||
const typeof((b)[0]) *_k = k; \
|
||||
int (*_func_)(const typeof((b)[0])*, const typeof((b)[0])*, typeof(userdata)) = func; \
|
||||
xbsearch_r((const void*) _k, (b), (n), sizeof((b)[0]), (comparison_userdata_fn_t) _func_, userdata); \
|
||||
})
|
||||
|
||||
@ -36,8 +36,8 @@ static inline void* bsearch_safe(const void *key, const void *base,
|
||||
|
||||
#define typesafe_bsearch(k, b, n, func) \
|
||||
({ \
|
||||
const typeof(b[0]) *_k = k; \
|
||||
int (*_func_)(const typeof(b[0])*, const typeof(b[0])*) = func; \
|
||||
const typeof((b)[0]) *_k = k; \
|
||||
int (*_func_)(const typeof((b)[0])*, const typeof((b)[0])*) = func; \
|
||||
bsearch_safe((const void*) _k, (b), (n), sizeof((b)[0]), (comparison_fn_t) _func_); \
|
||||
})
|
||||
|
||||
@ -57,7 +57,7 @@ static inline void _qsort_safe(void *base, size_t nmemb, size_t size, comparison
|
||||
* is the prototype for the comparison function */
|
||||
#define typesafe_qsort(p, n, func) \
|
||||
({ \
|
||||
int (*_func_)(const typeof(p[0])*, const typeof(p[0])*) = func; \
|
||||
int (*_func_)(const typeof((p)[0])*, const typeof((p)[0])*) = func; \
|
||||
_qsort_safe((p), (n), sizeof((p)[0]), (comparison_fn_t) _func_); \
|
||||
})
|
||||
|
||||
@ -71,7 +71,7 @@ static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, compariso
|
||||
|
||||
#define typesafe_qsort_r(p, n, func, userdata) \
|
||||
({ \
|
||||
int (*_func_)(const typeof(p[0])*, const typeof(p[0])*, typeof(userdata)) = func; \
|
||||
int (*_func_)(const typeof((p)[0])*, const typeof((p)[0])*, typeof(userdata)) = func; \
|
||||
qsort_r_safe((p), (n), sizeof((p)[0]), (comparison_userdata_fn_t) _func_, userdata); \
|
||||
})
|
||||
|
||||
|
||||
@ -610,7 +610,7 @@ bool strv_is_uniq(char * const *l) {
|
||||
char * const *i;
|
||||
|
||||
STRV_FOREACH(i, l)
|
||||
if (strv_find(i+1, *i))
|
||||
if (strv_contains(i+1, *i))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
@ -899,10 +899,10 @@ static int install_binaries(const char *esp_path, bool force) {
|
||||
|
||||
/* skip the .efi file, if there's a .signed version of it */
|
||||
if (endswith_no_case(de->d_name, ".efi")) {
|
||||
_cleanup_free_ const char *s = strjoin(BOOTLIBDIR, "/", de->d_name, ".signed");
|
||||
_cleanup_free_ const char *s = strjoin(de->d_name, ".signed");
|
||||
if (!s)
|
||||
return log_oom();
|
||||
if (access(s, F_OK) >= 0)
|
||||
if (faccessat(dirfd(d), s, F_OK, 0) >= 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1932,6 +1932,8 @@ static int verb_install(int argc, char *argv[], void *userdata) {
|
||||
bool install, graceful;
|
||||
int r;
|
||||
|
||||
/* Invoked for both "update" and "install" */
|
||||
|
||||
install = streq(argv[0], "install");
|
||||
graceful = !install && arg_graceful; /* support graceful mode for updates */
|
||||
|
||||
@ -2044,7 +2046,7 @@ static int verb_remove(int argc, char *argv[], void *userdata) {
|
||||
|
||||
q = remove_entry_directory(arg_esp_path);
|
||||
if (q < 0 && r >= 0)
|
||||
r = 1;
|
||||
r = q;
|
||||
|
||||
if (arg_xbootldr_path) {
|
||||
/* Remove the latter two also in the XBOOTLDR partition if it exists */
|
||||
|
||||
@ -3415,6 +3415,9 @@ static bool insist_on_sandboxing(
|
||||
if (context->dynamic_user)
|
||||
return true;
|
||||
|
||||
if (context->n_extension_images > 0 || !strv_isempty(context->extension_directories))
|
||||
return true;
|
||||
|
||||
/* If there are any bind mounts set that don't map back onto themselves, fs namespacing becomes
|
||||
* essential. */
|
||||
for (size_t i = 0; i < n_bind_mounts; i++)
|
||||
|
||||
@ -4251,7 +4251,7 @@ static void service_notify_message(
|
||||
/* Process FD store messages. Either FDSTOREREMOVE=1 for removal, or FDSTORE=1 for addition. In both cases,
|
||||
* process FDNAME= for picking the file descriptor name to use. Note that FDNAME= is required when removing
|
||||
* fds, but optional when pushing in new fds, for compatibility reasons. */
|
||||
if (strv_find(tags, "FDSTOREREMOVE=1")) {
|
||||
if (strv_contains(tags, "FDSTOREREMOVE=1")) {
|
||||
const char *name;
|
||||
|
||||
name = strv_find_startswith(tags, "FDNAME=");
|
||||
@ -4260,7 +4260,7 @@ static void service_notify_message(
|
||||
else
|
||||
service_remove_fd_store(s, name);
|
||||
|
||||
} else if (strv_find(tags, "FDSTORE=1")) {
|
||||
} else if (strv_contains(tags, "FDSTORE=1")) {
|
||||
const char *name;
|
||||
|
||||
name = strv_find_startswith(tags, "FDNAME=");
|
||||
|
||||
@ -138,7 +138,7 @@ 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);
|
||||
char *n = NULL;
|
||||
char *n;
|
||||
|
||||
n = strdup(u->manager->prefix[PTR_TO_UINT(data)]);
|
||||
if (!n)
|
||||
@ -148,6 +148,20 @@ static int specifier_special_directory(char specifier, const void *data, const c
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int specifier_credentials_dir(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
|
||||
const Unit *u = ASSERT_PTR(userdata);
|
||||
char *d;
|
||||
|
||||
assert(ret);
|
||||
|
||||
d = strjoin(u->manager->prefix[EXEC_DIRECTORY_RUNTIME], "/credentials/", u->id);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = d;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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
|
||||
@ -191,6 +205,7 @@ int unit_full_printf_full(const Unit *u, const char *format, size_t max_length,
|
||||
* %R: the root of this systemd's instance tree (deprecated)
|
||||
*
|
||||
* %C: the cache directory root (e.g. /var/cache or $XDG_CACHE_HOME)
|
||||
* %d: the credentials directory ($CREDENTIALS_DIRECTORY)
|
||||
* %E: the configuration directory root (e.g. /etc or $XDG_CONFIG_HOME)
|
||||
* %L: the log directory root (e.g. /var/log or $XDG_CONFIG_HOME/log)
|
||||
* %S: the state directory root (e.g. /var/lib or $XDG_CONFIG_HOME)
|
||||
@ -227,6 +242,7 @@ int unit_full_printf_full(const Unit *u, const char *format, size_t max_length,
|
||||
{ 'R', specifier_cgroup_root, NULL },
|
||||
|
||||
{ 'C', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_CACHE) },
|
||||
{ 'd', specifier_credentials_dir, NULL },
|
||||
{ 'E', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_CONFIGURATION) },
|
||||
{ 'L', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_LOGS) },
|
||||
{ 'S', specifier_special_directory, UINT_TO_PTR(EXEC_DIRECTORY_STATE) },
|
||||
|
||||
@ -114,7 +114,7 @@ int identity_add_token_pin(JsonVariant **v, const char *pin) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to convert PIN array: %m");
|
||||
|
||||
if (strv_find(pins, pin))
|
||||
if (strv_contains(pins, pin))
|
||||
return 0;
|
||||
|
||||
r = strv_extend(&pins, pin);
|
||||
|
||||
@ -85,6 +85,7 @@ else
|
||||
shift
|
||||
fi
|
||||
|
||||
# These two settings are settable in install.conf
|
||||
layout=
|
||||
initrd_generator=
|
||||
|
||||
@ -183,7 +184,6 @@ export KERNEL_INSTALL_STAGING_AREA
|
||||
[ "$layout" = "bls" ]
|
||||
MAKE_ENTRY_DIR_ABS=$?
|
||||
|
||||
|
||||
ret=0
|
||||
|
||||
PLUGINS="$(
|
||||
|
||||
@ -249,18 +249,15 @@ static int device_compare(sd_device * const *_a, sd_device * const *_b) {
|
||||
|
||||
prefix_len = sound_a - devpath_a;
|
||||
|
||||
if (strncmp(devpath_a, devpath_b, prefix_len) == 0) {
|
||||
if (strneq(devpath_a, devpath_b, prefix_len)) {
|
||||
const char *sound_b;
|
||||
|
||||
sound_b = devpath_b + prefix_len;
|
||||
|
||||
if (startswith(sound_a, "/controlC") &&
|
||||
!startswith(sound_b, "/contolC"))
|
||||
return 1;
|
||||
|
||||
if (!startswith(sound_a, "/controlC") &&
|
||||
startswith(sound_b, "/controlC"))
|
||||
return -1;
|
||||
r = CMP(!!startswith(sound_a, "/controlC"),
|
||||
!!startswith(sound_b, "/controlC"));
|
||||
if (r != 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1029,18 +1029,9 @@ int device_update_db(sd_device *device) {
|
||||
* set 'sticky' bit to indicate that we should not clean the
|
||||
* database when we transition from initramfs to the real root
|
||||
*/
|
||||
if (device->db_persist) {
|
||||
r = fchmod(fileno(f), 01644);
|
||||
if (r < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
r = fchmod(fileno(f), 0644);
|
||||
if (r < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
if (fchmod(fileno(f), device->db_persist ? 01644 : 0644) < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (has_info) {
|
||||
@ -1077,8 +1068,7 @@ int device_update_db(sd_device *device) {
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = rename(path_tmp, path);
|
||||
if (r < 0) {
|
||||
if (rename(path_tmp, path) < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -4239,7 +4239,7 @@ static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t r
|
||||
if (!tags)
|
||||
return log_oom();
|
||||
|
||||
if (strv_find(tags, "READY=1")) {
|
||||
if (strv_contains(tags, "READY=1")) {
|
||||
r = sd_notify(false, "READY=1\n");
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to send readiness notification, ignoring: %m");
|
||||
|
||||
@ -355,7 +355,7 @@ int bus_message_print_all_properties(
|
||||
if (!name_with_equal)
|
||||
return log_oom();
|
||||
|
||||
if (!filter || strv_find(filter, name) ||
|
||||
if (!filter || strv_contains(filter, name) ||
|
||||
(expected_value = strv_find_startswith(filter, name_with_equal))) {
|
||||
r = sd_bus_message_peek_type(m, NULL, &contents);
|
||||
if (r < 0)
|
||||
|
||||
@ -97,7 +97,7 @@ static int specifier_last_component(char specifier, const void *data, const char
|
||||
return 0;
|
||||
}
|
||||
|
||||
int install_full_printf_internal(const UnitFileInstallInfo *i, const char *format, size_t max_length, const char *root, char **ret) {
|
||||
int install_name_printf(const UnitFileInstallInfo *i, const char *format, const char *root, char **ret) {
|
||||
/* This is similar to unit_name_printf() */
|
||||
|
||||
const Specifier table[] = {
|
||||
@ -117,5 +117,5 @@ int install_full_printf_internal(const UnitFileInstallInfo *i, const char *forma
|
||||
assert(format);
|
||||
assert(ret);
|
||||
|
||||
return specifier_printf(format, max_length, table, root, i, ret);
|
||||
return specifier_printf(format, UNIT_NAME_MAX, table, root, i, ret);
|
||||
}
|
||||
|
||||
@ -4,11 +4,4 @@
|
||||
#include "install.h"
|
||||
#include "unit-name.h"
|
||||
|
||||
int install_full_printf_internal(const UnitFileInstallInfo *i, const char *format, size_t max_length, const char *root, char **ret);
|
||||
|
||||
static inline int install_name_printf(const UnitFileInstallInfo *i, const char *format, const char *root, char **ret) {
|
||||
return install_full_printf_internal(i, format, UNIT_NAME_MAX, root, ret);
|
||||
}
|
||||
static inline int install_path_printf(const UnitFileInstallInfo *i, const char *format, const char *root, char **ret) {
|
||||
return install_full_printf_internal(i, format, PATH_MAX-1, root, ret);
|
||||
}
|
||||
int install_name_printf(const UnitFileInstallInfo *i, const char *format, const char *root, char **ret);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -39,7 +39,7 @@ static int normalize_filenames(char **names) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int normalize_names(char **names, bool warn_if_path) {
|
||||
static int normalize_names(char **names) {
|
||||
char **u;
|
||||
bool was_path = false;
|
||||
|
||||
@ -56,7 +56,7 @@ static int normalize_names(char **names, bool warn_if_path) {
|
||||
was_path = true;
|
||||
}
|
||||
|
||||
if (warn_if_path && was_path)
|
||||
if (was_path)
|
||||
log_warning("Warning: Can't execute disable on the unit file path. Proceeding with the unit name.");
|
||||
|
||||
return 0;
|
||||
@ -92,7 +92,7 @@ int verb_enable(int argc, char *argv[], void *userdata) {
|
||||
}
|
||||
|
||||
if (streq(verb, "disable")) {
|
||||
r = normalize_names(names, true);
|
||||
r = normalize_names(names);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@ -117,9 +117,9 @@ int verb_enable(int argc, char *argv[], void *userdata) {
|
||||
carries_install_info = r;
|
||||
} else if (streq(verb, "link"))
|
||||
r = unit_file_link(arg_scope, flags, arg_root, names, &changes, &n_changes);
|
||||
else if (streq(verb, "preset")) {
|
||||
else if (streq(verb, "preset"))
|
||||
r = unit_file_preset(arg_scope, flags, arg_root, names, arg_preset_mode, &changes, &n_changes);
|
||||
} else if (streq(verb, "mask"))
|
||||
else if (streq(verb, "mask"))
|
||||
r = unit_file_mask(arg_scope, flags, arg_root, names, &changes, &n_changes);
|
||||
else if (streq(verb, "unmask"))
|
||||
r = unit_file_unmask(arg_scope, flags, arg_root, names, &changes, &n_changes);
|
||||
|
||||
@ -38,12 +38,12 @@ static bool output_show_unit_file(const UnitFileList *u, char **states, char **p
|
||||
if (!dot)
|
||||
return false;
|
||||
|
||||
if (!strv_find(arg_types, dot+1))
|
||||
if (!strv_contains(arg_types, dot+1))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!strv_isempty(states) &&
|
||||
!strv_find(states, unit_file_state_to_string(u->state)))
|
||||
!strv_contains(states, unit_file_state_to_string(u->state)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
@ -783,7 +783,7 @@ bool output_show_unit(const UnitInfo *u, char **patterns) {
|
||||
if (!strv_fnmatch_or_empty(patterns, u->id, FNM_NOESCAPE))
|
||||
return false;
|
||||
|
||||
if (arg_types && !strv_find(arg_types, unit_type_suffix(u->id)))
|
||||
if (arg_types && !strv_contains(arg_types, unit_type_suffix(u->id)))
|
||||
return false;
|
||||
|
||||
if (arg_all)
|
||||
@ -873,18 +873,15 @@ int mangle_names(const char *operation, char **original_names, char ***ret_mangl
|
||||
|
||||
/* When enabling units qualified path names are OK, too, hence allow them explicitly. */
|
||||
|
||||
if (is_path(*name)) {
|
||||
*i = strdup(*name);
|
||||
if (!*i)
|
||||
return log_oom();
|
||||
} else {
|
||||
if (is_path(*name))
|
||||
r = path_make_absolute_cwd(*name, i);
|
||||
else
|
||||
r = unit_name_mangle_with_suffix(*name, operation,
|
||||
arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
|
||||
".service", i);
|
||||
if (r < 0) {
|
||||
*i = NULL;
|
||||
return log_error_errno(r, "Failed to mangle unit name: %m");
|
||||
}
|
||||
if (r < 0) {
|
||||
*i = NULL;
|
||||
return log_error_errno(r, "Failed to mangle unit name or path '%s': %m", *name);
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
@ -319,7 +319,7 @@ static int putgrent_with_members(const struct group *gr, FILE *group) {
|
||||
return -ENOMEM;
|
||||
|
||||
STRV_FOREACH(i, a) {
|
||||
if (strv_find(l, *i))
|
||||
if (strv_contains(l, *i))
|
||||
continue;
|
||||
|
||||
if (strv_extend(&l, *i) < 0)
|
||||
@ -364,7 +364,7 @@ static int putsgent_with_members(const struct sgrp *sg, FILE *gshadow) {
|
||||
return -ENOMEM;
|
||||
|
||||
STRV_FOREACH(i, a) {
|
||||
if (strv_find(l, *i))
|
||||
if (strv_contains(l, *i))
|
||||
continue;
|
||||
|
||||
if (strv_extend(&l, *i) < 0)
|
||||
|
||||
@ -1086,6 +1086,7 @@ static void test_exec_specifier(Manager *m) {
|
||||
test(m, "exec-specifier.service", 0, CLD_EXITED);
|
||||
test(m, "exec-specifier@foo-bar.service", 0, CLD_EXITED);
|
||||
test(m, "exec-specifier-interpolation.service", 0, CLD_EXITED);
|
||||
test(m, "exec-specifier-credentials-dir.service", 0, CLD_EXITED);
|
||||
}
|
||||
|
||||
static void test_exec_standardinput(Manager *m) {
|
||||
|
||||
12
test/test-execute/exec-specifier-credentials-dir.service
Normal file
12
test/test-execute/exec-specifier-credentials-dir.service
Normal file
@ -0,0 +1,12 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
[Unit]
|
||||
Description=Test for specifiers
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
Environment=TOP_SECRET=%d/very_top_secret
|
||||
# Test if the specifier is resolved correctly both before and after LoadCredential=
|
||||
ExecStart=test %d/very_top_secret = "${CREDENTIALS_DIRECTORY}/very_top_secret"
|
||||
LoadCredential=very_top_secret
|
||||
ExecStart=test %d/very_top_secret = "${CREDENTIALS_DIRECTORY}/very_top_secret"
|
||||
ExecStart=sh -c 'test %d/very_top_secret = "$TOP_SECRET"'
|
||||
@ -20,6 +20,7 @@ ExecStart=test %L = /var/log
|
||||
ExecStart=test %E = /etc
|
||||
ExecStart=test %T = /tmp
|
||||
ExecStart=test %V = /var/tmp
|
||||
ExecStart=test %d = %t/credentials/%n
|
||||
ExecStart=sh -c 'test %u = $$(id -un)'
|
||||
ExecStart=sh -c 'test %U = $$(id -u)'
|
||||
ExecStart=sh -c 'test %g = $$(id -gn)'
|
||||
|
||||
@ -74,6 +74,53 @@ runas testuser systemd-run --wait --user --unit=test-bind-mount \
|
||||
-p PrivateUsers=yes -p BindPaths=/dev/null:/etc/os-release \
|
||||
test ! -s /etc/os-release
|
||||
|
||||
runas testuser systemd-run --wait --user --unit=test-read-write \
|
||||
-p PrivateUsers=yes -p ReadOnlyPaths=/ \
|
||||
-p ReadWritePaths="/var /run /tmp" \
|
||||
-p NoExecPaths=/ -p ExecPaths=/usr \
|
||||
test ! -w /etc/os-release
|
||||
|
||||
runas testuser systemd-run --wait --user --unit=test-caps \
|
||||
-p PrivateUsers=yes -p AmbientCapabilities=CAP_SYS_ADMIN \
|
||||
-p CapabilityBoundingSet=CAP_SYS_ADMIN \
|
||||
test -s /etc/os-release
|
||||
|
||||
runas testuser systemd-run --wait --user --unit=test-devices \
|
||||
-p PrivateUsers=yes -p PrivateDevices=yes -p PrivateIPC=yes \
|
||||
sh -c "ls -1 /dev/ | wc -l | grep -q -F 18"
|
||||
|
||||
# Same check as test/test-execute/exec-privatenetwork-yes.service
|
||||
runas testuser systemd-run --wait --user --unit=test-network \
|
||||
-p PrivateUsers=yes -p PrivateNetwork=yes \
|
||||
/bin/sh -x -c '! ip link | grep -E "^[0-9]+: " | grep -Ev ": (lo|(erspan|gre|gretap|ip_vti|ip6_vti|ip6gre|ip6tnl|sit|tunl)0@.*):"'
|
||||
|
||||
runas testuser systemd-run --wait --user --unit=test-hostname \
|
||||
-p PrivateUsers=yes -p ProtectHostname=yes \
|
||||
hostnamectl hostname foo \
|
||||
&& { echo 'unexpected success'; exit 1; }
|
||||
|
||||
runas testuser systemd-run --wait --user --unit=test-clock \
|
||||
-p PrivateUsers=yes -p ProtectClock=yes \
|
||||
timedatectl set-time "2012-10-30 18:17:16" \
|
||||
&& { echo 'unexpected success'; exit 1; }
|
||||
|
||||
runas testuser systemd-run --wait --user --unit=test-kernel-tunable \
|
||||
-p PrivateUsers=yes -p ProtectKernelTunables=yes \
|
||||
sh -c "echo 0 > /proc/sys/user/max_user_namespaces" \
|
||||
&& { echo 'unexpected success'; exit 1; }
|
||||
|
||||
runas testuser systemd-run --wait --user --unit=test-kernel-mod \
|
||||
-p PrivateUsers=yes -p ProtectKernelModules=yes \
|
||||
sh -c "modprobe -r overlay && modprobe overlay" \
|
||||
&& { echo 'unexpected success'; exit 1; }
|
||||
|
||||
if sysctl kernel.dmesg_restrict=0; then
|
||||
runas testuser systemd-run --wait --user --unit=test-kernel-log \
|
||||
-p PrivateUsers=yes -p ProtectKernelLogs=yes -p LogNamespace=yes \
|
||||
dmesg \
|
||||
&& { echo 'unexpected success'; exit 1; }
|
||||
fi
|
||||
|
||||
unsquashfs -no-xattrs -d /tmp/img /usr/share/minimal_0.raw
|
||||
runas testuser systemd-run --wait --user --unit=test-root-dir \
|
||||
-p PrivateUsers=yes -p RootDirectory=/tmp/img \
|
||||
@ -82,8 +129,9 @@ runas testuser systemd-run --wait --user --unit=test-root-dir \
|
||||
mkdir /tmp/img_bind
|
||||
mount --bind /tmp/img /tmp/img_bind
|
||||
runas testuser systemd-run --wait --user --unit=test-root-dir-bind \
|
||||
-p PrivateUsers=yes -p RootDirectory=/tmp/img_bind \
|
||||
-p PrivateUsers=yes -p RootDirectory=/tmp/img_bind -p MountFlags=private \
|
||||
grep MARKER=1 /etc/os-release
|
||||
umount /tmp/img_bind
|
||||
|
||||
# Unprivileged overlayfs was added to Linux 5.11, so try to detect it first
|
||||
mkdir -p /tmp/a /tmp/b /tmp/c
|
||||
@ -96,8 +144,6 @@ if unshare --mount --user --map-root-user mount -t overlay overlay /tmp/c -o low
|
||||
grep PORTABLE_PREFIXES=app1 /usr/lib/extension-release.d/extension-release.app2
|
||||
fi
|
||||
|
||||
umount /tmp/img_bind
|
||||
|
||||
systemd-analyze log-level info
|
||||
|
||||
echo OK >/testok
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user