Merge pull request #14099 from keszybz/machine-ref-unref-fix

Fix for the issue when machine cannot be started second time, and better nspawn logging
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2019-11-22 14:33:27 +01:00 committed by GitHub
commit 58c0663b97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 196 additions and 192 deletions

View File

@ -754,7 +754,7 @@
container, with the exception of the loopback device and those
specified with <option>--network-interface=</option> and
configured with <option>--network-veth</option>. If this
option is specified, the CAP_NET_ADMIN capability will be
option is specified, the <constant>CAP_NET_ADMIN</constant> capability will be
added to the set of capabilities the container retains. The
latter may be disabled by using <option>--drop-capability=</option>.
If this option is not specified (or implied by one of the options
@ -943,17 +943,27 @@
<varlistentry>
<term><option>--capability=</option></term>
<listitem><para>List one or more additional capabilities to grant the container.
Takes a comma-separated list of capability names, see
<citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
<listitem><para>List one or more additional capabilities to grant the container. Takes a
comma-separated list of capability names, see <citerefentry
project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for more information. Note that the following capabilities will be granted in any way:
CAP_AUDIT_CONTROL, CAP_AUDIT_WRITE, CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH,
CAP_FOWNER, CAP_FSETID, CAP_IPC_OWNER, CAP_KILL, CAP_LEASE, CAP_LINUX_IMMUTABLE,
CAP_MKNOD, CAP_NET_BIND_SERVICE, CAP_NET_BROADCAST, CAP_NET_RAW, CAP_SETFCAP,
CAP_SETGID, CAP_SETPCAP, CAP_SETUID, CAP_SYS_ADMIN, CAP_SYS_BOOT, CAP_SYS_CHROOT,
CAP_SYS_NICE, CAP_SYS_PTRACE, CAP_SYS_RESOURCE, CAP_SYS_TTY_CONFIG. Also CAP_NET_ADMIN
is retained if <option>--private-network</option> is specified. If the special value
<literal>all</literal> is passed, all capabilities are retained.</para></listitem>
<constant>CAP_AUDIT_CONTROL</constant>, <constant>CAP_AUDIT_WRITE</constant>,
<constant>CAP_CHOWN</constant>, <constant>CAP_DAC_OVERRIDE</constant>,
<constant>CAP_DAC_READ_SEARCH</constant>, <constant>CAP_FOWNER</constant>,
<constant>CAP_FSETID</constant>, <constant>CAP_IPC_OWNER</constant>, <constant>CAP_KILL</constant>,
<constant>CAP_LEASE</constant>, <constant>CAP_LINUX_IMMUTABLE</constant>,
<constant>CAP_MKNOD</constant>, <constant>CAP_NET_BIND_SERVICE</constant>,
<constant>CAP_NET_BROADCAST</constant>, <constant>CAP_NET_RAW</constant>,
<constant>CAP_SETFCAP</constant>, <constant>CAP_SETGID</constant>, <constant>CAP_SETPCAP</constant>,
<constant>CAP_SETUID</constant>, <constant>CAP_SYS_ADMIN</constant>,
<constant>CAP_SYS_BOOT</constant>, <constant>CAP_SYS_CHROOT</constant>,
<constant>CAP_SYS_NICE</constant>, <constant>CAP_SYS_PTRACE</constant>,
<constant>CAP_SYS_RESOURCE</constant>, <constant>CAP_SYS_TTY_CONFIG</constant>. Also
<constant>CAP_NET_ADMIN</constant> is retained if <option>--private-network</option> is specified.
If the special value <literal>all</literal> is passed, all capabilities are retained.</para>
<para>If the special value of <literal>help</literal> is passed, the program will print known
capability names and exit.</para></listitem>
</varlistentry>
<varlistentry>
@ -962,7 +972,10 @@
<listitem><para>Specify one or more additional capabilities to
drop for the container. This allows running the container with
fewer capabilities than the default (see
above).</para></listitem>
above).</para>
<para>If the special value of <literal>help</literal> is passed, the program will print known
capability names and exit.</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -330,36 +330,107 @@ int machine_load(Machine *m) {
return r;
}
static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
static int machine_start_scope(
Machine *machine,
sd_bus_message *more_properties,
sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
_cleanup_free_ char *escaped = NULL, *unit = NULL;
const char *description;
int r;
assert(machine);
assert(machine->leader > 0);
assert(!machine->unit);
escaped = unit_name_escape(machine->name);
if (!escaped)
return log_oom();
unit = strjoin("machine-", escaped, ".scope");
if (!unit)
return log_oom();
r = sd_bus_message_new_method_call(
machine->manager->bus,
&m,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"StartTransientUnit");
if (r < 0)
return r;
r = sd_bus_message_append(m, "ss", unit, "fail");
if (r < 0)
return r;
r = sd_bus_message_open_container(m, 'a', "(sv)");
if (r < 0)
return r;
r = sd_bus_message_append(m, "(sv)", "Slice", "s", SPECIAL_MACHINE_SLICE);
if (r < 0)
return r;
description = strjoina(machine->class == MACHINE_VM ? "Virtual Machine " : "Container ", machine->name);
r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
if (r < 0)
return r;
r = sd_bus_message_append(m, "(sv)(sv)(sv)(sv)(sv)",
"PIDs", "au", 1, machine->leader,
"Delegate", "b", 1,
"CollectMode", "s", "inactive-or-failed",
"AddRef", "b", 1,
"TasksMax", "t", UINT64_C(16384));
if (r < 0)
return r;
if (more_properties) {
r = sd_bus_message_copy(m, more_properties, true);
if (r < 0)
return r;
}
r = sd_bus_message_close_container(m);
if (r < 0)
return r;
r = sd_bus_message_append(m, "a(sa(sv))", 0);
if (r < 0)
return r;
r = sd_bus_call(NULL, m, 0, error, &reply);
if (r < 0)
return r;
machine->unit = TAKE_PTR(unit);
machine->referenced = true;
const char *job;
r = sd_bus_message_read(reply, "o", &job);
if (r < 0)
return r;
return free_and_strdup(&machine->scope_job, job);
}
static int machine_ensure_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
int r;
assert(m);
assert(m->class != MACHINE_HOST);
if (!m->unit) {
_cleanup_free_ char *escaped = NULL, *scope = NULL;
char *description, *job = NULL;
int r;
escaped = unit_name_escape(m->name);
if (!escaped)
return log_oom();
scope = strjoin("machine-", escaped, ".scope");
if (!scope)
return log_oom();
description = strjoina(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
r = manager_start_scope(m->manager, scope, m->leader, SPECIAL_MACHINE_SLICE, description, properties, error, &job);
r = machine_start_scope(m, properties, error);
if (r < 0)
return log_error_errno(r, "Failed to start machine scope: %s", bus_error_message(error, r));
m->unit = TAKE_PTR(scope);
m->referenced = true;
free_and_replace(m->scope_job, job);
}
if (m->unit)
hashmap_put(m->manager->machine_units, m->unit, m);
assert(m->unit);
hashmap_put(m->manager->machine_units, m->unit, m);
return 0;
}
@ -380,7 +451,7 @@ int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
return r;
/* Create cgroup */
r = machine_start_scope(m, properties, error);
r = machine_ensure_scope(m, properties, error);
if (r < 0)
return r;
@ -404,49 +475,31 @@ int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
return 0;
}
static int machine_stop_scope(Machine *m) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
char *job = NULL;
int r, q;
assert(m);
assert(m->class != MACHINE_HOST);
if (!m->unit)
return 0;
r = manager_stop_unit(m->manager, m->unit, &error, &job);
if (r < 0) {
log_error_errno(r, "Failed to stop machine scope: %s", bus_error_message(&error, r));
sd_bus_error_free(&error);
} else
free_and_replace(m->scope_job, job);
if (m->referenced) {
q = manager_unref_unit(m->manager, m->unit, &error);
if (q < 0)
log_warning_errno(q, "Failed to drop reference to machine scope, ignoring: %s", bus_error_message(&error, r));
m->referenced = false;
}
return r;
}
int machine_stop(Machine *m) {
int r;
assert(m);
if (!IN_SET(m->class, MACHINE_CONTAINER, MACHINE_VM))
return -EOPNOTSUPP;
r = machine_stop_scope(m);
if (m->unit) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
char *job = NULL;
r = manager_stop_unit(m->manager, m->unit, &error, &job);
if (r < 0)
return log_error_errno(r, "Failed to stop machine scope: %s", bus_error_message(&error, r));
free_and_replace(m->scope_job, job);
}
m->stopping = true;
machine_save(m);
(void) manager_enqueue_nscd_cache_flush(m->manager);
return r;
return 0;
}
int machine_finalize(Machine *m) {
@ -583,6 +636,18 @@ void machine_release_unit(Machine *m) {
if (!m->unit)
return;
if (m->referenced) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
r = manager_unref_unit(m->manager, m->unit, &error);
if (r < 0)
log_warning_errno(r, "Failed to drop reference to machine scope, ignoring: %s",
bus_error_message(&error, r));
m->referenced = false;
}
(void) hashmap_remove(m->manager->machine_units, m->unit);
m->unit = mfree(m->unit);
}

View File

@ -1294,98 +1294,6 @@ int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error
return 0;
}
int manager_start_scope(
Manager *manager,
const char *scope,
pid_t pid,
const char *slice,
const char *description,
sd_bus_message *more_properties,
sd_bus_error *error,
char **job) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
int r;
assert(manager);
assert(scope);
assert(pid > 1);
r = sd_bus_message_new_method_call(
manager->bus,
&m,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"StartTransientUnit");
if (r < 0)
return r;
r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
if (r < 0)
return r;
r = sd_bus_message_open_container(m, 'a', "(sv)");
if (r < 0)
return r;
if (!isempty(slice)) {
r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
if (r < 0)
return r;
}
if (!isempty(description)) {
r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
if (r < 0)
return r;
}
r = sd_bus_message_append(m, "(sv)(sv)(sv)(sv)(sv)",
"PIDs", "au", 1, pid,
"Delegate", "b", 1,
"CollectMode", "s", "inactive-or-failed",
"AddRef", "b", 1,
"TasksMax", "t", UINT64_C(16384));
if (r < 0)
return r;
if (more_properties) {
r = sd_bus_message_copy(m, more_properties, true);
if (r < 0)
return r;
}
r = sd_bus_message_close_container(m);
if (r < 0)
return r;
r = sd_bus_message_append(m, "a(sa(sv))", 0);
if (r < 0)
return r;
r = sd_bus_call(manager->bus, m, 0, error, &reply);
if (r < 0)
return r;
if (job) {
const char *j;
char *copy;
r = sd_bus_message_read(reply, "o", &j);
if (r < 0)
return r;
copy = strdup(j);
if (!copy)
return -ENOMEM;
*job = copy;
}
return 1;
}
int manager_unref_unit(
Manager *m,
const char *unit,

View File

@ -49,7 +49,6 @@ int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *er
int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error);
int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error);
int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, sd_bus_message *more_properties, sd_bus_error *error, char **job);
int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error);
int manager_unref_unit(Manager *m, const char *unit, sd_bus_error *error);

View File

@ -139,11 +139,10 @@ static int seccomp_add_default_syscall_filter(
*/
};
int r;
size_t i;
char **p;
int r;
for (i = 0; i < ELEMENTSOF(whitelist); i++) {
for (size_t i = 0; i < ELEMENTSOF(whitelist); i++) {
if (whitelist[i].capability != 0 && (cap_list_retain & (1ULL << whitelist[i].capability)) == 0)
continue;
@ -153,7 +152,7 @@ static int seccomp_add_default_syscall_filter(
}
STRV_FOREACH(p, syscall_whitelist) {
r = seccomp_add_syscall_filter_item(ctx, *p, SCMP_ACT_ALLOW, syscall_blacklist, false);
r = seccomp_add_syscall_filter_item(ctx, *p, SCMP_ACT_ALLOW, syscall_blacklist, true);
if (r < 0)
log_warning_errno(r, "Failed to add rule for system call %s on %s, ignoring: %m",
*p, seccomp_arch_to_string(arch));

View File

@ -492,6 +492,46 @@ static int detect_unified_cgroup_hierarchy_from_image(const char *directory) {
return 0;
}
static int parse_capability_spec(const char *spec, uint64_t *ret_mask) {
uint64_t mask = 0;
int r;
for (;;) {
_cleanup_free_ char *t = NULL;
r = extract_first_word(&spec, &t, ",", 0);
if (r < 0)
return log_error_errno(r, "Failed to parse capability %s.", t);
if (r == 0)
break;
if (streq(t, "help")) {
for (int i = 0; i < capability_list_length(); i++) {
const char *name;
name = capability_to_name(i);
if (name)
puts(name);
}
return 0; /* quit */
}
if (streq(t, "all"))
mask = (uint64_t) -1;
else {
r = capability_from_name(t);
if (r < 0)
return log_error_errno(r, "Failed to parse capability %s.", t);
mask |= 1ULL << r;
}
}
*ret_mask = mask;
return 1; /* continue */
}
static int parse_share_ns_env(const char *name, unsigned long ns_flag) {
int r;
@ -695,7 +735,6 @@ static int parse_argv(int argc, char *argv[]) {
};
int c, r;
const char *p;
uint64_t plus = 0, minus = 0;
bool mask_all_settings = false, mask_no_settings = false;
@ -937,37 +976,18 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_CAPABILITY:
case ARG_DROP_CAPABILITY: {
p = optarg;
for (;;) {
_cleanup_free_ char *t = NULL;
r = extract_first_word(&p, &t, ",", 0);
if (r < 0)
return log_error_errno(r, "Failed to parse capability %s.", t);
if (r == 0)
break;
if (streq(t, "all")) {
if (c == ARG_CAPABILITY)
plus = (uint64_t) -1;
else
minus = (uint64_t) -1;
} else {
r = capability_from_name(t);
if (r < 0)
return log_error_errno(r, "Failed to parse capability %s.", t);
if (c == ARG_CAPABILITY)
plus |= 1ULL << r;
else
minus |= 1ULL << r;
}
}
uint64_t m;
r = parse_capability_spec(optarg, &m);
if (r <= 0)
return r;
if (c == ARG_CAPABILITY)
plus |= m;
else
minus |= m;
arg_settings_mask |= SETTING_CAPABILITY;
break;
}
case ARG_NO_NEW_PRIVILEGES:
r = parse_boolean(optarg);
if (r < 0)

View File

@ -9,7 +9,7 @@
#include "resolved-dns-stream.h"
#include "resolved-dnstls.h"
#define PRIORTY_STRING "NORMAL:-VERS-ALL:+VERS-TLS1.3:+VERS-TLS1.2"
#define TLS_PROTOCOL_PRIORITY "NORMAL:-VERS-ALL:+VERS-TLS1.3:+VERS-TLS1.2"
DEFINE_TRIVIAL_CLEANUP_FUNC(gnutls_session_t, gnutls_deinit);
static ssize_t dnstls_stream_writev(gnutls_transport_ptr_t p, const giovec_t *iov, int iovcnt) {
@ -38,7 +38,7 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
return r;
/* As DNS-over-TLS is a recent protocol, older TLS versions can be disabled */
r = gnutls_priority_set_direct(gs, PRIORTY_STRING, NULL);
r = gnutls_priority_set_direct(gs, TLS_PROTOCOL_PRIORITY, NULL);
if (r < 0)
return r;