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
0 commit comments