mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-02-02 09:47:03 +03:00
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.
This commit is contained in:
parent
447d46879c
commit
409f4cf1f2
@ -2291,7 +2291,7 @@ if conf.get('ENABLE_PORTABLED') == 1
|
||||
systemd_portabled_sources,
|
||||
include_directories : includes,
|
||||
link_with : [libshared],
|
||||
dependencies : [threads],
|
||||
dependencies : [threads, libselinux],
|
||||
install_rpath : rootlibexecdir,
|
||||
install : true,
|
||||
install_dir : rootlibexecdir)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -12,6 +12,7 @@ typedef struct PortableMetadata {
|
||||
int fd;
|
||||
char *source;
|
||||
char *image_path;
|
||||
char *selinux_label;
|
||||
char name[];
|
||||
} PortableMetadata;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user