]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/nspawn/nspawn-register.c
66962d7ba958f37edc5646bec95543c711fff10e
[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 static int can_set_coredump_receive(sd_bus *bus) {
112 _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL;
113 _cleanup_free_ char *path = NULL;
114 int b, r;
115
116 assert(bus);
117
118 path = unit_dbus_path_from_name(SPECIAL_INIT_SCOPE);
119 if (!path)
120 return log_oom();
121
122 r = sd_bus_get_property_trivial(
123 bus,
124 "org.freedesktop.systemd1",
125 path,
126 "org.freedesktop.systemd1.Scope",
127 "CoredumpReceive",
128 &e,
129 'b', &b);
130 if (r < 0 && !sd_bus_error_has_names(&e, SD_BUS_ERROR_UNKNOWN_PROPERTY, SD_BUS_ERROR_PROPERTY_READ_ONLY))
131 log_warning_errno(r, "Failed to determine if CoredumpReceive= can be set, assuming it cannot be: %s",
132 bus_error_message(&e, r));
133
134 return r >= 0;
135 }
136
137 int register_machine(
138 sd_bus *bus,
139 const char *machine_name,
140 pid_t pid,
141 const char *directory,
142 sd_id128_t uuid,
143 int local_ifindex,
144 const char *slice,
145 CustomMount *mounts,
146 unsigned n_mounts,
147 int kill_signal,
148 char **properties,
149 sd_bus_message *properties_message,
150 bool keep_unit,
151 const char *service,
152 StartMode start_mode) {
153
154 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
155 int r;
156
157 assert(bus);
158
159 if (keep_unit) {
160 r = bus_call_method(
161 bus,
162 bus_machine_mgr,
163 "RegisterMachineWithNetwork",
164 &error,
165 NULL,
166 "sayssusai",
167 machine_name,
168 SD_BUS_MESSAGE_APPEND_ID128(uuid),
169 service,
170 "container",
171 (uint32_t) pid,
172 strempty(directory),
173 local_ifindex > 0 ? 1 : 0, local_ifindex);
174 } else {
175 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
176
177 r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "CreateMachineWithNetwork");
178 if (r < 0)
179 return bus_log_create_error(r);
180
181 r = sd_bus_message_append(
182 m,
183 "sayssusai",
184 machine_name,
185 SD_BUS_MESSAGE_APPEND_ID128(uuid),
186 service,
187 "container",
188 (uint32_t) pid,
189 strempty(directory),
190 local_ifindex > 0 ? 1 : 0, local_ifindex);
191 if (r < 0)
192 return bus_log_create_error(r);
193
194 r = sd_bus_message_open_container(m, 'a', "(sv)");
195 if (r < 0)
196 return bus_log_create_error(r);
197
198 if (!isempty(slice)) {
199 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
200 if (r < 0)
201 return bus_log_create_error(r);
202 }
203
204 r = append_controller_property(bus, m);
205 if (r < 0)
206 return r;
207
208 r = append_machine_properties(
209 m,
210 mounts,
211 n_mounts,
212 kill_signal,
213 start_mode == START_BOOT && can_set_coredump_receive(bus) > 0);
214 if (r < 0)
215 return r;
216
217 if (properties_message) {
218 r = sd_bus_message_copy(m, properties_message, true);
219 if (r < 0)
220 return bus_log_create_error(r);
221 }
222
223 r = bus_append_unit_property_assignment_many(m, UNIT_SERVICE, properties);
224 if (r < 0)
225 return r;
226
227 r = sd_bus_message_close_container(m);
228 if (r < 0)
229 return bus_log_create_error(r);
230
231 r = sd_bus_call(bus, m, 0, &error, NULL);
232 }
233 if (r < 0)
234 return log_error_errno(r, "Failed to register machine: %s", bus_error_message(&error, r));
235
236 return 0;
237 }
238
239 int unregister_machine(
240 sd_bus *bus,
241 const char *machine_name) {
242
243 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
244 int r;
245
246 assert(bus);
247
248 r = bus_call_method(bus, bus_machine_mgr, "UnregisterMachine", &error, NULL, "s", machine_name);
249 if (r < 0)
250 log_debug("Failed to unregister machine: %s", bus_error_message(&error, r));
251
252 return 0;
253 }
254
255 int allocate_scope(
256 sd_bus *bus,
257 const char *machine_name,
258 pid_t pid,
259 const char *slice,
260 CustomMount *mounts,
261 unsigned n_mounts,
262 int kill_signal,
263 char **properties,
264 sd_bus_message *properties_message,
265 bool allow_pidfd,
266 StartMode start_mode) {
267
268 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
269 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
270 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
271 _cleanup_free_ char *scope = NULL;
272 const char *description, *object;
273 int r;
274
275 assert(bus);
276
277 r = bus_wait_for_jobs_new(bus, &w);
278 if (r < 0)
279 return log_error_errno(r, "Could not watch job: %m");
280
281 r = unit_name_mangle_with_suffix(machine_name, "as machine name", 0, ".scope", &scope);
282 if (r < 0)
283 return log_error_errno(r, "Failed to mangle scope name: %m");
284
285 r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
286 if (r < 0)
287 return bus_log_create_error(r);
288
289 r = sd_bus_message_append(m, "ss", scope, "fail");
290 if (r < 0)
291 return bus_log_create_error(r);
292
293 /* Properties */
294 r = sd_bus_message_open_container(m, 'a', "(sv)");
295 if (r < 0)
296 return bus_log_create_error(r);
297
298 description = strjoina("Container ", machine_name);
299
300 if (allow_pidfd) {
301 _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
302 r = pidref_set_pid(&pidref, pid);
303 if (r < 0)
304 return log_error_errno(r, "Failed to allocate PID reference: %m");
305
306 r = bus_append_scope_pidref(m, &pidref);
307 } else
308 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
309 if (r < 0)
310 return bus_log_create_error(r);
311
312 r = sd_bus_message_append(m, "(sv)(sv)(sv)(sv)(sv)",
313 "Description", "s", description,
314 "Delegate", "b", 1,
315 "CollectMode", "s", "inactive-or-failed",
316 "AddRef", "b", 1,
317 "Slice", "s", isempty(slice) ? SPECIAL_MACHINE_SLICE : slice);
318 if (r < 0)
319 return bus_log_create_error(r);
320
321 r = append_controller_property(bus, m);
322 if (r < 0)
323 return r;
324
325 if (properties_message) {
326 r = sd_bus_message_copy(m, properties_message, true);
327 if (r < 0)
328 return bus_log_create_error(r);
329 }
330
331 r = append_machine_properties(
332 m,
333 mounts,
334 n_mounts,
335 kill_signal,
336 start_mode == START_BOOT && can_set_coredump_receive(bus) > 0);
337 if (r < 0)
338 return r;
339
340 r = bus_append_unit_property_assignment_many(m, UNIT_SCOPE, properties);
341 if (r < 0)
342 return r;
343
344 r = sd_bus_message_close_container(m);
345 if (r < 0)
346 return bus_log_create_error(r);
347
348 /* No auxiliary units */
349 r = sd_bus_message_append(
350 m,
351 "a(sa(sv))",
352 0);
353 if (r < 0)
354 return bus_log_create_error(r);
355
356 r = sd_bus_call(bus, m, 0, &error, &reply);
357 if (r < 0) {
358 /* If this failed with a property we couldn't write, this is quite likely because the server
359 * doesn't support PIDFDs yet, let's try without. */
360 if (allow_pidfd &&
361 sd_bus_error_has_names(&error, SD_BUS_ERROR_UNKNOWN_PROPERTY, SD_BUS_ERROR_PROPERTY_READ_ONLY))
362 return allocate_scope(bus, machine_name, pid, slice, mounts, n_mounts, kill_signal, properties, properties_message, /* allow_pidfd= */ false, start_mode);
363
364 return log_error_errno(r, "Failed to allocate scope: %s", bus_error_message(&error, r));
365 }
366
367 r = sd_bus_message_read(reply, "o", &object);
368 if (r < 0)
369 return bus_log_parse_error(r);
370
371 r = bus_wait_for_jobs_one(w, object, false, NULL);
372 if (r < 0)
373 return r;
374
375 return 0;
376 }
377
378 int terminate_scope(
379 sd_bus *bus,
380 const char *machine_name) {
381
382 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
383 _cleanup_free_ char *scope = NULL;
384 int r;
385
386 r = unit_name_mangle_with_suffix(machine_name, "to terminate", 0, ".scope", &scope);
387 if (r < 0)
388 return log_error_errno(r, "Failed to mangle scope name: %m");
389
390 r = bus_call_method(bus, bus_systemd_mgr, "AbandonScope", &error, NULL, "s", scope);
391 if (r < 0) {
392 log_debug_errno(r, "Failed to abandon scope '%s', ignoring: %s", scope, bus_error_message(&error, r));
393 sd_bus_error_free(&error);
394 }
395
396 r = bus_call_method(
397 bus,
398 bus_systemd_mgr,
399 "KillUnit",
400 &error,
401 NULL,
402 "ssi",
403 scope,
404 "all",
405 (int32_t) SIGKILL);
406 if (r < 0) {
407 log_debug_errno(r, "Failed to SIGKILL scope '%s', ignoring: %s", scope, bus_error_message(&error, r));
408 sd_bus_error_free(&error);
409 }
410
411 r = bus_call_method(bus, bus_systemd_mgr, "UnrefUnit", &error, NULL, "s", scope);
412 if (r < 0)
413 log_debug_errno(r, "Failed to drop reference to scope '%s', ignoring: %s", scope, bus_error_message(&error, r));
414
415 return 0;
416 }