mirror of
https://github.com/systemd/systemd
synced 2024-10-02 22:37:25 +00:00
Merge pull request #24408 from keszybz/execstart-escape
Properly escape ExecStart= commandlines in transient units
This commit is contained in:
commit
13be736d1f
|
@ -72,7 +72,7 @@
|
|||
processes of the command are managed by the service manager similarly to normal services, and will show
|
||||
up in the output of <command>systemctl list-units</command>. Execution in this case is synchronous, and
|
||||
will return only when the command finishes. This mode is enabled via the <option>--scope</option> switch
|
||||
(see below). </para>
|
||||
(see below).</para>
|
||||
|
||||
<para>If a command is run with path, socket, or timer options such as <option>--on-calendar=</option> (see below),
|
||||
a transient path, socket, or timer unit is created alongside the service unit for the specified command. Only the
|
||||
|
@ -82,15 +82,16 @@
|
|||
<filename>.path</filename>, <filename>.socket</filename>, or <filename>.timer</filename> unit that triggers the
|
||||
specified unit.</para>
|
||||
|
||||
<para>By default, services created with <command>systemd-run</command> default to the <option>simple</option> type,
|
||||
see the description of <varname>Type=</varname> in
|
||||
<para>By default, services created with <command>systemd-run</command> default to the
|
||||
<option>simple</option> type, see the description of <varname>Type=</varname> in
|
||||
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
|
||||
details. Note that when this type is used the service manager (and thus the <command>systemd-run</command> command)
|
||||
considers service start-up successful as soon as the <function>fork()</function> for the main service process
|
||||
succeeded, i.e. before the <function>execve()</function> is invoked, and thus even if the specified command cannot
|
||||
be started. Consider using the <option>exec</option> service type (i.e. <option>--property=Type=exec</option>) to
|
||||
ensure that <command>systemd-run</command> returns successfully only if the specified command line has been
|
||||
successfully started.</para>
|
||||
details. Note that when this type is used, the service manager (and thus the
|
||||
<command>systemd-run</command> command) considers service start-up successful as soon as the
|
||||
<function>fork()</function> for the main service process succeeded, i.e. before the
|
||||
<function>execve()</function> is invoked, and thus even if the specified command cannot be started.
|
||||
Consider using the <option>exec</option> service type (i.e. <option>--property=Type=exec</option>) to
|
||||
ensure that <command>systemd-run</command> returns successfully only if the specified command line has
|
||||
been successfully started.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
@ -411,10 +412,8 @@
|
|||
<xi:include href="standard-options.xml" xpointer="version" />
|
||||
</variablelist>
|
||||
|
||||
<para>All command line arguments after the first non-option
|
||||
argument become part of the command line of the launched
|
||||
process. If a command is run as service unit, the first argument
|
||||
needs to be an absolute program path.</para>
|
||||
<para>All command line arguments after the first non-option argument become part of the command line of
|
||||
the launched process.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
|
|
@ -1591,7 +1591,7 @@ int bus_set_transient_exec_command(
|
|||
if (!exec_chars)
|
||||
return -ENOMEM;
|
||||
|
||||
a = unit_concat_strv(c->argv, UNIT_ESCAPE_C|UNIT_ESCAPE_SPECIFIERS);
|
||||
a = unit_concat_strv(c->argv, UNIT_ESCAPE_SPECIFIERS|UNIT_ESCAPE_EXEC_SYNTAX);
|
||||
if (!a)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -1601,7 +1601,8 @@ int bus_set_transient_exec_command(
|
|||
_cleanup_free_ char *t = NULL;
|
||||
const char *p;
|
||||
|
||||
p = unit_escape_setting(c->path, UNIT_ESCAPE_C|UNIT_ESCAPE_SPECIFIERS, &t);
|
||||
p = unit_escape_setting(c->path,
|
||||
UNIT_ESCAPE_SPECIFIERS|UNIT_ESCAPE_EXEC_SYNTAX, &t);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
@ -4254,51 +4254,62 @@ static const char* unit_drop_in_dir(Unit *u, UnitWriteFlags flags) {
|
|||
}
|
||||
|
||||
char* unit_escape_setting(const char *s, UnitWriteFlags flags, char **buf) {
|
||||
char *ret = NULL;
|
||||
assert(!FLAGS_SET(flags, UNIT_ESCAPE_EXEC_SYNTAX | UNIT_ESCAPE_C));
|
||||
|
||||
_cleanup_free_ char *t = NULL;
|
||||
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
/* Escapes the input string as requested. Returns the escaped string. If 'buf' is specified then the allocated
|
||||
* return buffer pointer is also written to *buf, except if no escaping was necessary, in which case *buf is
|
||||
* set to NULL, and the input pointer is returned as-is. This means the return value always contains a properly
|
||||
* escaped version, but *buf when passed only contains a pointer if an allocation was necessary. If *buf is
|
||||
* not specified, then the return value always needs to be freed. Callers can use this to optimize memory
|
||||
* allocations. */
|
||||
/* Escapes the input string as requested. Returns the escaped string. If 'buf' is specified then the
|
||||
* allocated return buffer pointer is also written to *buf, except if no escaping was necessary, in
|
||||
* which case *buf is set to NULL, and the input pointer is returned as-is. This means the return
|
||||
* value always contains a properly escaped version, but *buf when passed only contains a pointer if
|
||||
* an allocation was necessary. If *buf is not specified, then the return value always needs to be
|
||||
* freed. Callers can use this to optimize memory allocations. */
|
||||
|
||||
if (flags & UNIT_ESCAPE_SPECIFIERS) {
|
||||
ret = specifier_escape(s);
|
||||
if (!ret)
|
||||
t = specifier_escape(s);
|
||||
if (!t)
|
||||
return NULL;
|
||||
|
||||
s = ret;
|
||||
s = t;
|
||||
}
|
||||
|
||||
if (flags & UNIT_ESCAPE_C) {
|
||||
char *a;
|
||||
/* We either do c-escaping or shell-escaping, to additionally escape characters that we parse for
|
||||
* ExecStart= and friend, i.e. '$' and ';' and quotes. */
|
||||
|
||||
a = cescape(s);
|
||||
free(ret);
|
||||
if (!a)
|
||||
if (flags & UNIT_ESCAPE_EXEC_SYNTAX) {
|
||||
char *t2 = shell_escape(s, "$;'\"");
|
||||
if (!t2)
|
||||
return NULL;
|
||||
free_and_replace(t, t2);
|
||||
|
||||
ret = a;
|
||||
s = t;
|
||||
|
||||
} else if (flags & UNIT_ESCAPE_C) {
|
||||
char *t2 = cescape(s);
|
||||
if (!t2)
|
||||
return NULL;
|
||||
free_and_replace(t, t2);
|
||||
|
||||
s = t;
|
||||
}
|
||||
|
||||
if (buf) {
|
||||
*buf = ret;
|
||||
return ret ?: (char*) s;
|
||||
*buf = TAKE_PTR(t);
|
||||
return (char*) s;
|
||||
}
|
||||
|
||||
return ret ?: strdup(s);
|
||||
return TAKE_PTR(t) ?: strdup(s);
|
||||
}
|
||||
|
||||
char* unit_concat_strv(char **l, UnitWriteFlags flags) {
|
||||
_cleanup_free_ char *result = NULL;
|
||||
size_t n = 0;
|
||||
|
||||
/* Takes a list of strings, escapes them, and concatenates them. This may be used to format command lines in a
|
||||
* way suitable for ExecStart= stanzas */
|
||||
/* Takes a list of strings, escapes them, and concatenates them. This may be used to format command
|
||||
* lines in a way suitable for ExecStart= stanzas. */
|
||||
|
||||
STRV_FOREACH(i, l) {
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
|
|
|
@ -531,19 +531,22 @@ typedef struct UnitStatusMessageFormats {
|
|||
/* Flags used when writing drop-in files or transient unit files */
|
||||
typedef enum UnitWriteFlags {
|
||||
/* Write a runtime unit file or drop-in (i.e. one below /run) */
|
||||
UNIT_RUNTIME = 1 << 0,
|
||||
UNIT_RUNTIME = 1 << 0,
|
||||
|
||||
/* Write a persistent drop-in (i.e. one below /etc) */
|
||||
UNIT_PERSISTENT = 1 << 1,
|
||||
UNIT_PERSISTENT = 1 << 1,
|
||||
|
||||
/* Place this item in the per-unit-type private section, instead of [Unit] */
|
||||
UNIT_PRIVATE = 1 << 2,
|
||||
UNIT_PRIVATE = 1 << 2,
|
||||
|
||||
/* Apply specifier escaping before writing */
|
||||
UNIT_ESCAPE_SPECIFIERS = 1 << 3,
|
||||
UNIT_ESCAPE_SPECIFIERS = 1 << 3,
|
||||
|
||||
/* Escape elements of ExecStart= syntax before writing */
|
||||
UNIT_ESCAPE_EXEC_SYNTAX = 1 << 4,
|
||||
|
||||
/* Apply C escaping before writing */
|
||||
UNIT_ESCAPE_C = 1 << 4,
|
||||
UNIT_ESCAPE_C = 1 << 5,
|
||||
} UnitWriteFlags;
|
||||
|
||||
/* Returns true if neither persistent, nor runtime storage is requested, i.e. this is a check invocation only */
|
||||
|
|
Loading…
Reference in a new issue