diff options
Diffstat (limited to 'src/portable')
-rw-r--r-- | src/portable/portable.c | 46 | ||||
-rw-r--r-- | src/portable/portable.h | 1 |
2 files changed, 42 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); diff --git a/src/portable/portable.h b/src/portable/portable.h index 94144287ae..077ab3333f 100644 --- a/src/portable/portable.h +++ b/src/portable/portable.h @@ -12,6 +12,7 @@ typedef struct PortableMetadata { int fd; char *source; char *image_path; + char *selinux_label; char name[]; } PortableMetadata; |