diff options
author | Luca Boccassi <luca.boccassi@microsoft.com> | 2021-09-16 13:47:42 +0200 |
---|---|---|
committer | Luca Boccassi <luca.boccassi@microsoft.com> | 2021-09-20 15:23:55 +0200 |
commit | 409f4cf1f2bc797bb6a73eab310b707308a8352e (patch) | |
tree | 2a48a5abad0f602dce7d6da4696f518abb613a25 /src/portable/portable.c | |
parent | portable: use send_one_fd_iov/receive_one_fd_iov instead of custom helpers (diff) | |
download | systemd-409f4cf1f2bc797bb6a73eab310b707308a8352e.tar.xz systemd-409f4cf1f2bc797bb6a73eab310b707308a8352e.zip |
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.
Diffstat (limited to 'src/portable/portable.c')
-rw-r--r-- | src/portable/portable.c | 46 |
1 files changed, 41 insertions, 5 deletions
diff --git a/src/portable/portable.c b/src/portable/portable.c index 8af7fe2aef..4daafea3d3 100644 --- a/src/portable/portable.c +++ b/src/portable/portable.c @@ -28,6 +28,7 @@ #include "path-lookup.h" #include "portable.h" #include "process-util.h" +#include "selinux-util.h" #include "set.h" #include "signal-util.h" #include "socket-util.h" @@ -78,7 +79,7 @@ static bool unit_match(const char *unit, char **matches) { return false; } -static PortableMetadata *portable_metadata_new(const char *name, const char *path, int fd) { +static PortableMetadata *portable_metadata_new(const char *name, const char *path, const char *selinux_label, int fd) { PortableMetadata *m; m = malloc0(offsetof(PortableMetadata, name) + strlen(name) + 1); @@ -92,6 +93,15 @@ static PortableMetadata *portable_metadata_new(const char *name, const char *pat return mfree(m); } + /* The metadata file might have SELinux labels, we need to carry them and reapply them */ + if (!isempty(selinux_label)) { + m->selinux_label = strdup(selinux_label); + if (!m->selinux_label) { + free(m->image_path); + return mfree(m); + } + } + strcpy(m->name, name); m->fd = fd; @@ -105,6 +115,7 @@ PortableMetadata *portable_metadata_unref(PortableMetadata *i) { safe_close(i->fd); free(i->source); free(i->image_path); + free(i->selinux_label); return mfree(i); } @@ -201,6 +212,7 @@ static int extract_now( if (socket_fd >= 0) { struct iovec iov[] = { IOVEC_MAKE_STRING(os_release_id), + IOVEC_MAKE((char *)"\0", sizeof(char)), }; r = send_one_fd_iov_with_data_fd(socket_fd, iov, ELEMENTSOF(iov), os_release_fd); @@ -209,7 +221,7 @@ static int extract_now( } if (ret_os_release) { - os_release = portable_metadata_new(os_release_id, NULL, os_release_fd); + os_release = portable_metadata_new(os_release_id, NULL, NULL, os_release_fd); if (!os_release) return -ENOMEM; @@ -264,8 +276,19 @@ static int extract_now( } if (socket_fd >= 0) { + _cleanup_(mac_selinux_freep) char *con = NULL; +#if HAVE_SELINUX + /* The units will be copied on the host's filesystem, so if they had a SELinux label + * we have to preserve it. Copy it out so that it can be applied later. */ + + r = fgetfilecon_raw(fd, &con); + if (r < 0 && errno != ENODATA) + log_debug_errno(errno, "Failed to get SELinux file context from '%s', ignoring: %m", de->d_name); +#endif struct iovec iov[] = { IOVEC_MAKE_STRING(de->d_name), + IOVEC_MAKE((char *)"\0", sizeof(char)), + IOVEC_MAKE_STRING(strempty(con)), }; r = send_one_fd_iov_with_data_fd(socket_fd, iov, ELEMENTSOF(iov), fd); @@ -273,7 +296,7 @@ static int extract_now( return log_debug_errno(r, "Failed to send unit metadata to parent: %m"); } - m = portable_metadata_new(de->d_name, NULL, fd); + m = portable_metadata_new(de->d_name, NULL, NULL, fd); if (!m) return -ENOMEM; fd = -1; @@ -401,7 +424,11 @@ static int portable_extract_by_path( for (;;) { _cleanup_(portable_metadata_unrefp) PortableMetadata *add = NULL; _cleanup_close_ int fd = -1; - char iov_buffer[PATH_MAX + 2]; + /* We use NAME_MAX space for the SELinux label here. The kernel currently enforces no limit, but + * according to suggestions from the SELinux people this will change and it will probably be + * identical to NAME_MAX. For now we use that, but this should be updated one day when the final + * limit is known. */ + char iov_buffer[PATH_MAX + NAME_MAX + 2]; struct iovec iov = IOVEC_INIT(iov_buffer, sizeof(iov_buffer)); ssize_t n = receive_one_fd_iov(seq[0], &iov, 1, 0, &fd); @@ -420,7 +447,13 @@ static int portable_extract_by_path( return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid item sent from child."); - add = portable_metadata_new(iov_buffer, path, fd); + /* Given recvmsg cannot be used with multiple io vectors if you don't know the size in advance, + * use a marker to separate the name and the optional SELinux context. */ + char *selinux_label = memchr(iov_buffer, 0, n); + assert(selinux_label); + selinux_label++; + + add = portable_metadata_new(iov_buffer, path, selinux_label, fd); if (!add) return -ENOMEM; fd = -1; @@ -1065,7 +1098,10 @@ static int attach_unit_file( _cleanup_(unlink_and_freep) char *tmp = NULL; _cleanup_close_ int fd = -1; + (void) mac_selinux_create_file_prepare_label(path, m->selinux_label); + fd = open_tmpfile_linkable(path, O_WRONLY|O_CLOEXEC, &tmp); + mac_selinux_create_file_clear(); /* Clear immediately in case of errors */ if (fd < 0) return log_debug_errno(fd, "Failed to create unit file '%s': %m", path); |