|
11 | 11 | #include "dbus-manager.h" |
12 | 12 | #include "dbus-service.h" |
13 | 13 | #include "dbus-util.h" |
| 14 | +#include "execute.h" |
14 | 15 | #include "exit-status.h" |
15 | 16 | #include "fd-util.h" |
16 | 17 | #include "fileio.h" |
| 18 | +#include "locale-util.h" |
| 19 | +#include "mount-util.h" |
17 | 20 | #include "parse-util.h" |
18 | 21 | #include "path-util.h" |
| 22 | +#include "selinux-access.h" |
19 | 23 | #include "service.h" |
20 | 24 | #include "signal-util.h" |
21 | 25 | #include "string-util.h" |
@@ -91,6 +95,79 @@ static int property_get_exit_status_set( |
91 | 95 | return sd_bus_message_close_container(reply); |
92 | 96 | } |
93 | 97 |
|
| 98 | +int bus_service_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
| 99 | + int read_only, make_file_or_directory; |
| 100 | + const char *dest, *src, *propagate_directory; |
| 101 | + Unit *u = userdata; |
| 102 | + ExecContext *c; |
| 103 | + pid_t unit_pid; |
| 104 | + int r; |
| 105 | + |
| 106 | + assert(message); |
| 107 | + assert(u); |
| 108 | + |
| 109 | + if (!MANAGER_IS_SYSTEM(u->manager)) |
| 110 | + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Adding bind mounts at runtime is only supported for system managers."); |
| 111 | + |
| 112 | + r = mac_selinux_unit_access_check(u, message, "start", error); |
| 113 | + if (r < 0) |
| 114 | + return r; |
| 115 | + |
| 116 | + r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_file_or_directory); |
| 117 | + if (r < 0) |
| 118 | + return r; |
| 119 | + |
| 120 | + if (!path_is_absolute(src) || !path_is_normalized(src)) |
| 121 | + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and normalized."); |
| 122 | + |
| 123 | + if (isempty(dest)) |
| 124 | + dest = src; |
| 125 | + else if (!path_is_absolute(dest) || !path_is_normalized(dest)) |
| 126 | + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and normalized."); |
| 127 | + |
| 128 | + r = bus_verify_manage_units_async_full( |
| 129 | + u, |
| 130 | + "bind-mount", |
| 131 | + CAP_SYS_ADMIN, |
| 132 | + N_("Authentication is required to bind mount on '$(unit)'."), |
| 133 | + true, |
| 134 | + message, |
| 135 | + error); |
| 136 | + if (r < 0) |
| 137 | + return r; |
| 138 | + if (r == 0) |
| 139 | + return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ |
| 140 | + |
| 141 | + if (u->type != UNIT_SERVICE) |
| 142 | + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit is not of type .service"); |
| 143 | + |
| 144 | + /* If it would be dropped at startup time, return an error. The context should always be available, but |
| 145 | + * there's an assert in exec_needs_mount_namespace, so double-check just in case. */ |
| 146 | + c = unit_get_exec_context(u); |
| 147 | + if (!c) |
| 148 | + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot access unit execution context"); |
| 149 | + if (path_startswith_strv(dest, c->inaccessible_paths)) |
| 150 | + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s is not accessible to this unit", dest); |
| 151 | + |
| 152 | + /* Ensure that the unit was started in a private mount namespace */ |
| 153 | + if (!exec_needs_mount_namespace(c, NULL, unit_get_exec_runtime(u))) |
| 154 | + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit not running in private mount namespace, cannot activate bind mount"); |
| 155 | + |
| 156 | + unit_pid = unit_main_pid(u); |
| 157 | + if (unit_pid == 0 || !UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) |
| 158 | + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit is not running"); |
| 159 | + |
| 160 | + propagate_directory = strjoina("/run/systemd/propagate/", u->id); |
| 161 | + r = bind_mount_in_namespace(unit_pid, |
| 162 | + propagate_directory, |
| 163 | + "/run/systemd/incoming/", |
| 164 | + src, dest, read_only, make_file_or_directory); |
| 165 | + if (r < 0) |
| 166 | + return sd_bus_error_set_errnof(error, r, "Failed to mount %s on %s in unit's namespace: %m", src, dest); |
| 167 | + |
| 168 | + return sd_bus_reply_method_return(message, NULL); |
| 169 | +} |
| 170 | + |
94 | 171 | const sd_bus_vtable bus_service_vtable[] = { |
95 | 172 | SD_BUS_VTABLE_START(0), |
96 | 173 | SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Service, type), SD_BUS_VTABLE_PROPERTY_CONST), |
@@ -146,6 +223,16 @@ const sd_bus_vtable bus_service_vtable[] = { |
146 | 223 | BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPost", offsetof(Service, exec_command[SERVICE_EXEC_STOP_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), |
147 | 224 | BUS_EXEC_EX_COMMAND_LIST_VTABLE("ExecStopPostEx", offsetof(Service, exec_command[SERVICE_EXEC_STOP_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), |
148 | 225 |
|
| 226 | + SD_BUS_METHOD_WITH_NAMES("BindMount", |
| 227 | + "ssbb", |
| 228 | + SD_BUS_PARAM(source) |
| 229 | + SD_BUS_PARAM(destination) |
| 230 | + SD_BUS_PARAM(read_only) |
| 231 | + SD_BUS_PARAM(mkdir), |
| 232 | + NULL,, |
| 233 | + bus_service_method_bind_mount, |
| 234 | + SD_BUS_VTABLE_UNPRIVILEGED), |
| 235 | + |
149 | 236 | /* The following four are obsolete, and thus marked hidden here. They moved into the Unit interface */ |
150 | 237 | SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_ratelimit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), |
151 | 238 | SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_ratelimit.burst), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), |
|
0 commit comments