@@ -527,14 +527,18 @@ static int portable_extract_by_path(
527527 return 0 ;
528528}
529529
530- int portable_extract (
530+ static int extract_image_and_extensions (
531531 const char * name_or_path ,
532532 char * * matches ,
533533 char * * extension_image_paths ,
534+ bool validate_sysext ,
535+ Image * * ret_image ,
536+ OrderedHashmap * * ret_extension_images ,
534537 PortableMetadata * * ret_os_release ,
535538 Hashmap * * ret_unit_files ,
536539 sd_bus_error * error ) {
537540
541+ _cleanup_free_ char * id = NULL , * version_id = NULL , * sysext_level = NULL ;
538542 _cleanup_ (portable_metadata_unrefp ) PortableMetadata * os_release = NULL ;
539543 _cleanup_ordered_hashmap_free_ OrderedHashmap * extension_images = NULL ;
540544 _cleanup_hashmap_free_ Hashmap * unit_files = NULL ;
@@ -543,6 +547,9 @@ int portable_extract(
543547 int r ;
544548
545549 assert (name_or_path );
550+ assert (matches );
551+ assert (ret_image );
552+ assert (ret_extension_images );
546553
547554 r = image_find_harder (IMAGE_PORTABLE , name_or_path , NULL , & image );
548555 if (r < 0 )
@@ -573,17 +580,91 @@ int portable_extract(
573580 if (r < 0 )
574581 return r ;
575582
583+ /* If we are layering extension images on top of a runtime image, check that the os-release and extension-release metadata
584+ * match, otherwise reject it immediately as invalid, or it will fail when the units are started. */
585+ if (validate_sysext ) {
586+ _cleanup_fclose_ FILE * f = NULL ;
587+
588+ r = take_fdopen_unlocked (& os_release -> fd , "r" , & f );
589+ if (r < 0 )
590+ return r ;
591+
592+ r = parse_env_file (f , os_release -> name ,
593+ "ID" , & id ,
594+ "VERSION_ID" , & version_id ,
595+ "SYSEXT_LEVEL" , & sysext_level );
596+ if (r < 0 )
597+ return r ;
598+ }
599+
576600 ORDERED_HASHMAP_FOREACH (ext , extension_images ) {
601+ _cleanup_ (portable_metadata_unrefp ) PortableMetadata * extension_release_meta = NULL ;
577602 _cleanup_hashmap_free_ Hashmap * extra_unit_files = NULL ;
603+ _cleanup_strv_free_ char * * extension_release = NULL ;
604+ _cleanup_fclose_ FILE * f = NULL ;
578605
579- r = portable_extract_by_path (ext -> path , /* path_is_extension= */ true, matches , NULL , & extra_unit_files , error );
606+ r = portable_extract_by_path (ext -> path , /* path_is_extension= */ true, matches , & extension_release_meta , & extra_unit_files , error );
580607 if (r < 0 )
581608 return r ;
609+
582610 r = hashmap_move (unit_files , extra_unit_files );
583611 if (r < 0 )
584612 return r ;
613+
614+ if (!validate_sysext )
615+ continue ;
616+
617+ r = take_fdopen_unlocked (& extension_release_meta -> fd , "r" , & f );
618+ if (r < 0 )
619+ return r ;
620+
621+ r = load_env_file_pairs (f , extension_release_meta -> name , & extension_release );
622+ if (r < 0 )
623+ return r ;
624+
625+ r = extension_release_validate (ext -> path , id , version_id , sysext_level , extension_release );
626+ if (r == 0 )
627+ return sd_bus_error_set_errnof (error , SYNTHETIC_ERRNO (ESTALE ), "Image %s extension-release metadata does not match the root's" , ext -> path );
628+ if (r < 0 )
629+ return sd_bus_error_set_errnof (error , r , "Failed to compare image %s extension-release metadata with the root's os-release: %m" , ext -> path );
585630 }
586631
632+ * ret_image = TAKE_PTR (image );
633+ * ret_extension_images = TAKE_PTR (extension_images );
634+ if (ret_os_release )
635+ * ret_os_release = TAKE_PTR (os_release );
636+ if (ret_unit_files )
637+ * ret_unit_files = TAKE_PTR (unit_files );
638+
639+ return 0 ;
640+ }
641+
642+ int portable_extract (
643+ const char * name_or_path ,
644+ char * * matches ,
645+ char * * extension_image_paths ,
646+ PortableMetadata * * ret_os_release ,
647+ Hashmap * * ret_unit_files ,
648+ sd_bus_error * error ) {
649+
650+ _cleanup_ (portable_metadata_unrefp ) PortableMetadata * os_release = NULL ;
651+ _cleanup_ordered_hashmap_free_ OrderedHashmap * extension_images = NULL ;
652+ _cleanup_hashmap_free_ Hashmap * unit_files = NULL ;
653+ _cleanup_ (image_unrefp ) Image * image = NULL ;
654+ int r ;
655+
656+ r = extract_image_and_extensions (name_or_path ,
657+ matches ,
658+ extension_image_paths ,
659+ /* validate_sysext= */ false,
660+ & image ,
661+ & extension_images ,
662+ & os_release ,
663+ & unit_files ,
664+ error );
665+ if (r < 0 )
666+ return r ;
667+
587668 if (hashmap_isempty (unit_files )) {
588669 _cleanup_free_ char * extensions = strv_join (extension_image_paths , ", " );
589670 if (!extensions )
@@ -1165,91 +1246,25 @@ int portable_attach(
11651246 size_t * n_changes ,
11661247 sd_bus_error * error ) {
11671248
1168- _cleanup_free_ char * id = NULL , * version_id = NULL , * sysext_level = NULL ;
1169- _cleanup_ (portable_metadata_unrefp ) PortableMetadata * os_release = NULL ;
11701249 _cleanup_ordered_hashmap_free_ OrderedHashmap * extension_images = NULL ;
11711250 _cleanup_hashmap_free_ Hashmap * unit_files = NULL ;
11721251 _cleanup_ (lookup_paths_free ) LookupPaths paths = {};
11731252 _cleanup_ (image_unrefp ) Image * image = NULL ;
11741253 PortableMetadata * item ;
1175- Image * ext ;
1176- char * * p ;
11771254 int r ;
11781255
1179- assert (name_or_path );
1180-
1181- r = image_find_harder (IMAGE_PORTABLE , name_or_path , NULL , & image );
1182- if (r < 0 )
1183- return r ;
1184- if (!strv_isempty (extension_image_paths )) {
1185- extension_images = ordered_hashmap_new (& image_hash_ops );
1186- if (!extension_images )
1187- return - ENOMEM ;
1188-
1189- STRV_FOREACH (p , extension_image_paths ) {
1190- _cleanup_ (image_unrefp ) Image * new = NULL ;
1191-
1192- r = image_find_harder (IMAGE_PORTABLE , * p , NULL , & new );
1193- if (r < 0 )
1194- return r ;
1195-
1196- r = ordered_hashmap_put (extension_images , new -> name , new );
1197- if (r < 0 )
1198- return r ;
1199- TAKE_PTR (new );
1200- }
1201- }
1202-
1203- r = portable_extract_by_path (image -> path , /* path_is_extension= */ false, matches , & os_release , & unit_files , error );
1256+ r = extract_image_and_extensions (name_or_path ,
1257+ matches ,
1258+ extension_image_paths ,
1259+ /* validate_sysext= */ true,
1260+ & image ,
1261+ & extension_images ,
1262+ /* os_release= */ NULL ,
1263+ & unit_files ,
1264+ error );
12041265 if (r < 0 )
12051266 return r ;
12061267
1207- /* If we are layering extension images on top of a runtime image, check that the os-release and extension-release metadata
1208- * match, otherwise reject it immediately as invalid, or it will fail when the units are started. */
1209- if (os_release ) {
1210- _cleanup_fclose_ FILE * f = NULL ;
1211-
1212- r = take_fdopen_unlocked (& os_release -> fd , "r" , & f );
1213- if (r < 0 )
1214- return r ;
1215-
1216- r = parse_env_file (f , os_release -> name ,
1217- "ID" , & id ,
1218- "VERSION_ID" , & version_id ,
1219- "SYSEXT_LEVEL" , & sysext_level );
1220- if (r < 0 )
1221- return r ;
1222- }
1223-
1224- ORDERED_HASHMAP_FOREACH (ext , extension_images ) {
1225- _cleanup_ (portable_metadata_unrefp ) PortableMetadata * extension_release_meta = NULL ;
1226- _cleanup_hashmap_free_ Hashmap * extra_unit_files = NULL ;
1227- _cleanup_strv_free_ char * * extension_release = NULL ;
1228- _cleanup_fclose_ FILE * f = NULL ;
1229-
1230- r = portable_extract_by_path (ext -> path , /* path_is_extension= */ true, matches , & extension_release_meta , & extra_unit_files , error );
1231- if (r < 0 )
1232- return r ;
1233-
1234- r = take_fdopen_unlocked (& extension_release_meta -> fd , "r" , & f );
1235- if (r < 0 )
1236- return r ;
1237-
1238- r = load_env_file_pairs (f , extension_release_meta -> name , & extension_release );
1239- if (r < 0 )
1240- return r ;
1241-
1242- r = extension_release_validate (ext -> path , id , version_id , sysext_level , extension_release );
1243- if (r == 0 )
1244- return sd_bus_error_set_errnof (error , SYNTHETIC_ERRNO (ESTALE ), "Image %s extension-release metadata does not match the root's" , ext -> path );
1245- if (r < 0 )
1246- return sd_bus_error_set_errnof (error , r , "Failed to compare image %s extension-release metadata with the root's os-release: %m" , ext -> path );
1247-
1248- r = hashmap_move (unit_files , extra_unit_files );
1249- if (r < 0 )
1250- return r ;
1251- }
1252-
12531268 if (hashmap_isempty (unit_files )) {
12541269 _cleanup_free_ char * extensions = strv_join (extension_image_paths , ", " );
12551270 if (!extensions )
0 commit comments