]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/nspawn/nspawn-register.c
nspawn: set CoredumpReceive=yes on container's scope when --boot is set
[thirdparty/systemd.git] / src / nspawn / nspawn-register.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "sd-bus.h"
4
5 #include "bus-error.h"
6 #include "bus-locator.h"
7 #include "bus-unit-util.h"
8 #include "bus-util.h"
9 #include "bus-wait-for-jobs.h"
10 #include "nspawn-register.h"
11 #include "nspawn-settings.h"
12 #include "special.h"
13 #include "stat-util.h"
14 #include "strv.h"
15
16 static int append_machine_properties(
17 sd_bus_message *m,
18 CustomMount *mounts,
19 unsigned n_mounts,
20 int kill_signal,
21 bool coredump_receive) {
22
23 unsigned j;
24 int r;
25
26 assert(m);
27
28 r = sd_bus_message_append(m, "(sv)", "DevicePolicy", "s", "closed");
29 if (r < 0)
30 return bus_log_create_error(r);
31
32 /* If you make changes here, also make sure to update systemd-nspawn@.service, to keep the device policies in
33 * sync regardless if we are run with or without the --keep-unit switch. */
34 r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 2,
35 /* Allow the container to
36 * access and create the API
37 * device nodes, so that
38 * PrivateDevices= in the
39 * container can work
40 * fine */
41 "/dev/net/tun", "rwm",
42 /* Allow the container
43 * access to ptys. However,
44 * do not permit the
45 * container to ever create
46 * these device nodes. */
47 "char-pts", "rw");
48 if (r < 0)
49 return bus_log_create_error(r);
50
51 for (j = 0; j < n_mounts; j++) {
52 CustomMount *cm = mounts + j;
53
54 if (cm->type != CUSTOM_MOUNT_BIND)
55 continue;
56
57 r = is_device_node(cm->source);
58 if (r == -ENOENT) {
59 /* The bind source might only appear as the image is put together, hence don't complain */
60 log_debug_errno(r, "Bind mount source %s not found, ignoring: %m", cm->source);
61 continue;
62 }
63 if (r < 0)
64 return log_error_errno(r, "Failed to stat %s: %m", cm->source);
65
66 if (r) {
67 r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 1,
68 cm->source, cm->read_only ? "r" : "rw");
69 if (r < 0)
70 return log_error_errno(r, "Failed to append message arguments: %m");
71 }
72 }
73
74 if (kill_signal != 0) {
75 r = sd_bus_message_append(m, "(sv)", "KillSignal", "i", kill_signal);
76 if (r < 0)
77 return bus_log_create_error(r);
78
79 r = sd_bus_message_append(m, "(sv)", "KillMode", "s", "mixed");
80 if (r < 0)
81 return bus_log_create_error(r);
82 }
83
84 if (coredump_receive) {
85 r = sd_bus_message_append(m, "(sv)", "CoredumpReceive", "b", true);
86 if (r < 0)
87 return bus_log_create_error(r);
88 }
89
90 return 0;
91 }
92
93 static int append_controller_property(sd_bus *bus, sd_bus_message *m) {
94 const char *unique;
95 int r;
96
97 assert(bus);
98 assert(m);
99
100 r = sd_bus_get_unique_name(bus, &unique);
101 if (r < 0)
102 return log_error_errno(r, "Failed to get unique name: %m");
103
104 r = sd_bus_message_append(m, "(sv)", "Controller", "s", unique);
105 if (r < 0)
106 return bus_log_create_error(r);
107
108 return 0;
109 }
110
111 int register_machine(
112 sd_bus *bus,
113 const char *machine_name,
114 pid_t pid,
115 const char *directory,
116 sd_id128_t uuid,
117 int local_ifindex,
118 const char *slice,
119 CustomMount *mounts,
120 unsigned n_mounts,
121 int kill_signal,
122 char **properties,
123 sd_bus_message *properties_message,
124 bool keep_unit,
125 const char *service,
126 StartMode start_mode) {
127
128 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
129 int r;
130
131 assert(bus);
132
133 if (keep_unit) {
134 r = bus_call_method(
135 bus,
136 bus_machine_mgr,
137 "RegisterMachineWithNetwork",
138 &error,
139 NULL,
140 "sayssusai",
141 machine_name,
142 SD_BUS_MESSAGE_APPEND_ID128(uuid),
143 service,
144 "container",
145 (uint32_t) pid,
146 strempty(directory),
147 local_ifindex > 0 ? 1 : 0, local_ifindex);
148 } else {
149 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
150
151 r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "CreateMachineWithNetwork");
152 if (r < 0)
153 return bus_log_create_error(r);
154
155 r = sd_bus_message_append(
156 m,
157 "sayssusai",
158 machine_name,
159 SD_BUS_MESSAGE_APPEND_ID128(uuid),
160 service,
161 "container",
162 (uint32_t) pid,
163 strempty(directory),
164 local_ifindex > 0 ? 1 : 0, local_ifindex);
165 if (r < 0)
166 return bus_log_create_error(r);
167
168 r = sd_bus_message_open_container(m, 'a', "(sv)");
169 if (r < 0)
170 return bus_log_create_error(r);
171
172 if (!isempty(slice)) {
173 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
174 if (r < 0)
175 return bus_log_create_error(r);
176 }
177
178 r = append_controller_property(bus, m);
179 if (r < 0)
180 return r;
181
182 r = append_machine_properties(
183 m,
184 mounts,
185 n_mounts,
186 kill_signal,
187 start_mode == START_BOOT);
188 if (r < 0)
189 return r;
190
191 if (properties_message) {
192 r = sd_bus_message_copy(m, properties_message, true);
193 if (r < 0)
194 return bus_log_create_error(r);
195 }
196
197 r = bus_append_unit_property_assignment_many(m, UNIT_SERVICE, properties);
198 if (r < 0)
199 return r;
200
201 r = sd_bus_message_close_container(m);
202 if (r < 0)
203 return bus_log_create_error(r);
204
205 r = sd_bus_call(bus, m, 0, &error, NULL);
206 }
207 if (r < 0)
208 return log_error_errno(r, "Failed to register machine: %s", bus_error_message(&error, r));
209
210 return 0;
211 }
212
213 int unregister_machine(
214 sd_bus *bus,
215 const char *machine_name) {
216
217 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
218 int r;
219
220 assert(bus);
221
222 r = bus_call_method(bus, bus_machine_mgr, "UnregisterMachine", &error, NULL, "s", machine_name);
223 if (r < 0)
224 log_debug("Failed to unregister machine: %s", bus_error_message(&error, r));
225
226 return 0;
227 }
228
229 int allocate_scope(
230 sd_bus *bus,
231 const char *machine_name,
232 pid_t pid,
233 const char *slice,
234 CustomMount *mounts,
235 unsigned n_mounts,
236 int kill_signal,
237 char **properties,
238 sd_bus_message *properties_message,
239 bool allow_pidfd,
240 StartMode start_mode) {
241
242 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
243 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
244 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
245 _cleanup_free_ char *scope = NULL;
246 const char *description, *object;
247 int r;
248
249 assert(bus);
250
251 r = bus_wait_for_jobs_new(bus, &w);
252 if (r < 0)
253 return log_error_errno(r, "Could not watch job: %m");
254
255 r = unit_name_mangle_with_suffix(machine_name, "as machine name", 0, ".scope", &scope);
256 if (r < 0)
257 return log_error_errno(r, "Failed to mangle scope name: %m");
258
259 r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
260 if (r < 0)
261 return bus_log_create_error(r);
262
263 r = sd_bus_message_append(m, "ss", scope, "fail");
264 if (r < 0)
265 return bus_log_create_error(r);
266
267 /* Properties */
268 r = sd_bus_message_open_container(m, 'a', "(sv)");
269 if (r < 0)
270 return bus_log_create_error(r);
271
272 description = strjoina("Container ", machine_name);
273
274 if (allow_pidfd) {
275 _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
276 r = pidref_set_pid(&pidref, pid);
277 if (r < 0)
278 return log_error_errno(r, "Failed to allocate PID reference: %m");
279
280 r = bus_append_scope_pidref(m, &pidref);
281 } else
282 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
283 if (r < 0)
284 return bus_log_create_error(r);
285
286 r = sd_bus_message_append(m, "(sv)(sv)(sv)(sv)(sv)",
287 "Description", "s", description,
288 "Delegate", "b", 1,
289 "CollectMode", "s", "inactive-or-failed",
290 "AddRef", "b", 1,
291 "Slice", "s", isempty(slice) ? SPECIAL_MACHINE_SLICE : slice);
292 if (r < 0)
293 return bus_log_create_error(r);
294
295 r = append_controller_property(bus, m);
296 if (r < 0)
297 return r;
298
299 if (properties_message) {
300 r = sd_bus_message_copy(m, properties_message, true);
301 if (r < 0)
302 return bus_log_create_error(r);
303 }
304
305 r = append_machine_properties(
306 m,
307 mounts,
308 n_mounts,
309 kill_signal,
310 start_mode == START_BOOT);
311 if (r < 0)
312 return r;
313
314 r = bus_append_unit_property_assignment_many(m, UNIT_SCOPE, properties);
315 if (r < 0)
316 return r;
317
318 r = sd_bus_message_close_container(m);
319 if (r < 0)
320 return bus_log_create_error(r);
321
322 /* No auxiliary units */
323 r = sd_bus_message_append(
324 m,
325 "a(sa(sv))",
326 0);
327 if (r < 0)
328 return bus_log_create_error(r);
329
330 r = sd_bus_call(bus, m, 0, &error, &reply);
331 if (r < 0) {
332 /* If this failed with a property we couldn't write, this is quite likely because the server
333 * doesn't support PIDFDs yet, let's try without. */
334 if (allow_pidfd &&
335 sd_bus_error_has_names(&error, SD_BUS_ERROR_UNKNOWN_PROPERTY, SD_BUS_ERROR_PROPERTY_READ_ONLY))
336 return allocate_scope(bus, machine_name, pid, slice, mounts, n_mounts, kill_signal, properties, properties_message, /* allow_pidfd= */ false, start_mode);
337
338 return log_error_errno(r, "Failed to allocate scope: %s", bus_error_message(&error, r));
339 }
340
341 r = sd_bus_message_read(reply, "o", &object);
342 if (r < 0)
343 return bus_log_parse_error(r);
344
345 r = bus_wait_for_jobs_one(w, object, false, NULL);
346 if (r < 0)
347 return r;
348
349 return 0;
350 }
351
352 int terminate_scope(
353 sd_bus *bus,
354 const char *machine_name) {
355
356 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
357 _cleanup_free_ char *scope = NULL;
358 int r;
359
360 r = unit_name_mangle_with_suffix(machine_name, "to terminate", 0, ".scope", &scope);
361 if (r < 0)
362 return log_error_errno(r, "Failed to mangle scope name: %m");
363
364 r = bus_call_method(bus, bus_systemd_mgr, "AbandonScope", &error, NULL, "s", scope);
365 if (r < 0) {
366 log_debug_errno(r, "Failed to abandon scope '%s', ignoring: %s", scope, bus_error_message(&error, r));
367 sd_bus_error_free(&error);
368 }
369
370 r = bus_call_method(
371 bus,
372 bus_systemd_mgr,
373 "KillUnit",
374 &error,
375 NULL,
376 "ssi",
377 scope,
378 "all",
379 (int32_t) SIGKILL);
380 if (r < 0) {
381 log_debug_errno(r, "Failed to SIGKILL scope '%s', ignoring: %s", scope, bus_error_message(&error, r));
382 sd_bus_error_free(&error);
383 }
384
385 r = bus_call_method(bus, bus_systemd_mgr, "UnrefUnit", &error, NULL, "s", scope);
386 if (r < 0)
387 log_debug_errno(r, "Failed to drop reference to scope '%s', ignoring: %s", scope, bus_error_message(&error, r));
388
389 return 0;
390 }