X Tutup
Skip to content

Commit 409f4cf

Browse files
committed
portable: copy SELinux label when extracting units from images
Units are copied out via sendmsg datafd from images, but that means the SELinux labels get lost in transit. Extract them and copy them over. Given recvmsg cannot use multiple IOV transparently when the sizes are variable, use a '\0' as a separator between the filename and the label.
1 parent 447d468 commit 409f4cf

File tree

3 files changed

+43
-6
lines changed

3 files changed

+43
-6
lines changed

meson.build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2291,7 +2291,7 @@ if conf.get('ENABLE_PORTABLED') == 1
22912291
systemd_portabled_sources,
22922292
include_directories : includes,
22932293
link_with : [libshared],
2294-
dependencies : [threads],
2294+
dependencies : [threads, libselinux],
22952295
install_rpath : rootlibexecdir,
22962296
install : true,
22972297
install_dir : rootlibexecdir)

src/portable/portable.c

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "path-lookup.h"
2929
#include "portable.h"
3030
#include "process-util.h"
31+
#include "selinux-util.h"
3132
#include "set.h"
3233
#include "signal-util.h"
3334
#include "socket-util.h"
@@ -78,7 +79,7 @@ static bool unit_match(const char *unit, char **matches) {
7879
return false;
7980
}
8081

81-
static PortableMetadata *portable_metadata_new(const char *name, const char *path, int fd) {
82+
static PortableMetadata *portable_metadata_new(const char *name, const char *path, const char *selinux_label, int fd) {
8283
PortableMetadata *m;
8384

8485
m = malloc0(offsetof(PortableMetadata, name) + strlen(name) + 1);
@@ -92,6 +93,15 @@ static PortableMetadata *portable_metadata_new(const char *name, const char *pat
9293
return mfree(m);
9394
}
9495

96+
/* The metadata file might have SELinux labels, we need to carry them and reapply them */
97+
if (!isempty(selinux_label)) {
98+
m->selinux_label = strdup(selinux_label);
99+
if (!m->selinux_label) {
100+
free(m->image_path);
101+
return mfree(m);
102+
}
103+
}
104+
95105
strcpy(m->name, name);
96106
m->fd = fd;
97107

@@ -105,6 +115,7 @@ PortableMetadata *portable_metadata_unref(PortableMetadata *i) {
105115
safe_close(i->fd);
106116
free(i->source);
107117
free(i->image_path);
118+
free(i->selinux_label);
108119

109120
return mfree(i);
110121
}
@@ -201,6 +212,7 @@ static int extract_now(
201212
if (socket_fd >= 0) {
202213
struct iovec iov[] = {
203214
IOVEC_MAKE_STRING(os_release_id),
215+
IOVEC_MAKE((char *)"\0", sizeof(char)),
204216
};
205217

206218
r = send_one_fd_iov_with_data_fd(socket_fd, iov, ELEMENTSOF(iov), os_release_fd);
@@ -209,7 +221,7 @@ static int extract_now(
209221
}
210222

211223
if (ret_os_release) {
212-
os_release = portable_metadata_new(os_release_id, NULL, os_release_fd);
224+
os_release = portable_metadata_new(os_release_id, NULL, NULL, os_release_fd);
213225
if (!os_release)
214226
return -ENOMEM;
215227

@@ -264,16 +276,27 @@ static int extract_now(
264276
}
265277

266278
if (socket_fd >= 0) {
279+
_cleanup_(mac_selinux_freep) char *con = NULL;
280+
#if HAVE_SELINUX
281+
/* The units will be copied on the host's filesystem, so if they had a SELinux label
282+
* we have to preserve it. Copy it out so that it can be applied later. */
283+
284+
r = fgetfilecon_raw(fd, &con);
285+
if (r < 0 && errno != ENODATA)
286+
log_debug_errno(errno, "Failed to get SELinux file context from '%s', ignoring: %m", de->d_name);
287+
#endif
267288
struct iovec iov[] = {
268289
IOVEC_MAKE_STRING(de->d_name),
290+
IOVEC_MAKE((char *)"\0", sizeof(char)),
291+
IOVEC_MAKE_STRING(strempty(con)),
269292
};
270293

271294
r = send_one_fd_iov_with_data_fd(socket_fd, iov, ELEMENTSOF(iov), fd);
272295
if (r < 0)
273296
return log_debug_errno(r, "Failed to send unit metadata to parent: %m");
274297
}
275298

276-
m = portable_metadata_new(de->d_name, NULL, fd);
299+
m = portable_metadata_new(de->d_name, NULL, NULL, fd);
277300
if (!m)
278301
return -ENOMEM;
279302
fd = -1;
@@ -401,7 +424,11 @@ static int portable_extract_by_path(
401424
for (;;) {
402425
_cleanup_(portable_metadata_unrefp) PortableMetadata *add = NULL;
403426
_cleanup_close_ int fd = -1;
404-
char iov_buffer[PATH_MAX + 2];
427+
/* We use NAME_MAX space for the SELinux label here. The kernel currently enforces no limit, but
428+
* according to suggestions from the SELinux people this will change and it will probably be
429+
* identical to NAME_MAX. For now we use that, but this should be updated one day when the final
430+
* limit is known. */
431+
char iov_buffer[PATH_MAX + NAME_MAX + 2];
405432
struct iovec iov = IOVEC_INIT(iov_buffer, sizeof(iov_buffer));
406433

407434
ssize_t n = receive_one_fd_iov(seq[0], &iov, 1, 0, &fd);
@@ -420,7 +447,13 @@ static int portable_extract_by_path(
420447
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
421448
"Invalid item sent from child.");
422449

423-
add = portable_metadata_new(iov_buffer, path, fd);
450+
/* Given recvmsg cannot be used with multiple io vectors if you don't know the size in advance,
451+
* use a marker to separate the name and the optional SELinux context. */
452+
char *selinux_label = memchr(iov_buffer, 0, n);
453+
assert(selinux_label);
454+
selinux_label++;
455+
456+
add = portable_metadata_new(iov_buffer, path, selinux_label, fd);
424457
if (!add)
425458
return -ENOMEM;
426459
fd = -1;
@@ -1065,7 +1098,10 @@ static int attach_unit_file(
10651098
_cleanup_(unlink_and_freep) char *tmp = NULL;
10661099
_cleanup_close_ int fd = -1;
10671100

1101+
(void) mac_selinux_create_file_prepare_label(path, m->selinux_label);
1102+
10681103
fd = open_tmpfile_linkable(path, O_WRONLY|O_CLOEXEC, &tmp);
1104+
mac_selinux_create_file_clear(); /* Clear immediately in case of errors */
10691105
if (fd < 0)
10701106
return log_debug_errno(fd, "Failed to create unit file '%s': %m", path);
10711107

src/portable/portable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ typedef struct PortableMetadata {
1212
int fd;
1313
char *source;
1414
char *image_path;
15+
char *selinux_label;
1516
char name[];
1617
} PortableMetadata;
1718

0 commit comments

Comments
 (0)
X Tutup