@@ -1100,64 +1100,85 @@ int dissect_image(
11001100 m -> partitions [PARTITION_ROOT_SECONDARY_VERITY ].found = false;
11011101 m -> partitions [PARTITION_USR_SECONDARY ].found = false;
11021102 m -> partitions [PARTITION_USR_SECONDARY_VERITY ].found = false;
1103- } else {
1104- /* No root partition found? Then let's see if ther's one for the secondary architecture. And if not
1105- * either, then check if there's a single generic one, and use that. */
11061103
1107- if (m -> partitions [PARTITION_ROOT_VERITY ].found )
1108- return - EADDRNOTAVAIL ;
1104+ } else if (m -> partitions [PARTITION_ROOT_VERITY ].found )
1105+ return - EADDRNOTAVAIL ; /* Verity found but no matching rootfs? Something is off, refuse. */
11091106
1110- /* We didn't find a primary architecture root, but we found a primary architecture /usr? Refuse that for now. */
1111- if (m -> partitions [PARTITION_USR ].found || m -> partitions [PARTITION_USR_VERITY ].found )
1112- return - EADDRNOTAVAIL ;
1107+ else if (m -> partitions [PARTITION_ROOT_SECONDARY ].found ) {
11131108
1114- if (m -> partitions [PARTITION_ROOT_SECONDARY ].found ) {
1115- /* Upgrade secondary arch to first */
1116- m -> partitions [PARTITION_ROOT ] = m -> partitions [PARTITION_ROOT_SECONDARY ];
1117- zero (m -> partitions [PARTITION_ROOT_SECONDARY ]);
1118- m -> partitions [PARTITION_ROOT_VERITY ] = m -> partitions [PARTITION_ROOT_SECONDARY_VERITY ];
1119- zero (m -> partitions [PARTITION_ROOT_SECONDARY_VERITY ]);
1120-
1121- m -> partitions [PARTITION_USR ] = m -> partitions [PARTITION_USR_SECONDARY ];
1122- zero (m -> partitions [PARTITION_USR_SECONDARY ]);
1123- m -> partitions [PARTITION_USR_VERITY ] = m -> partitions [PARTITION_USR_SECONDARY_VERITY ];
1124- zero (m -> partitions [PARTITION_USR_SECONDARY_VERITY ]);
1125-
1126- } else if (flags & DISSECT_IMAGE_REQUIRE_ROOT ) {
1127- _cleanup_free_ char * o = NULL ;
1128- const char * options = NULL ;
1129-
1130- /* If the root hash was set, then we won't fall back to a generic node, because the
1131- * root hash decides. */
1132- if (verity && verity -> root_hash )
1133- return - EADDRNOTAVAIL ;
1109+ /* No root partition found but there's one for the secondary architecture? Then upgrade
1110+ * secondary arch to first */
11341111
1135- /* If we didn't find a generic node, then we can't fix this up either */
1136- if (!generic_node )
1137- return - ENXIO ;
1112+ m -> partitions [PARTITION_ROOT ] = m -> partitions [PARTITION_ROOT_SECONDARY ];
1113+ zero (m -> partitions [PARTITION_ROOT_SECONDARY ]);
1114+ m -> partitions [PARTITION_ROOT_VERITY ] = m -> partitions [PARTITION_ROOT_SECONDARY_VERITY ];
1115+ zero (m -> partitions [PARTITION_ROOT_SECONDARY_VERITY ]);
11381116
1139- /* If we didn't find a properly marked root partition, but we did find a single suitable
1140- * generic Linux partition, then use this as root partition, if the caller asked for it. */
1141- if ( multiple_generic )
1142- return - ENOTUNIQ ;
1117+ m -> partitions [ PARTITION_USR ] = m -> partitions [ PARTITION_USR_SECONDARY ];
1118+ zero ( m -> partitions [ PARTITION_USR_SECONDARY ]);
1119+ m -> partitions [ PARTITION_USR_VERITY ] = m -> partitions [ PARTITION_USR_SECONDARY_VERITY ];
1120+ zero ( m -> partitions [ PARTITION_USR_SECONDARY_VERITY ]) ;
11431121
1144- options = mount_options_from_designator (mount_options , PARTITION_ROOT );
1145- if (options ) {
1146- o = strdup (options );
1147- if (!o )
1148- return - ENOMEM ;
1149- }
1122+ } else if (m -> partitions [PARTITION_ROOT_SECONDARY_VERITY ].found )
1123+ return - EADDRNOTAVAIL ; /* as above */
11501124
1151- m -> partitions [PARTITION_ROOT ] = (DissectedPartition ) {
1152- .found = true,
1153- .rw = generic_rw ,
1154- .partno = generic_nr ,
1155- .architecture = _ARCHITECTURE_INVALID ,
1156- .node = TAKE_PTR (generic_node ),
1157- .uuid = generic_uuid ,
1158- .mount_options = TAKE_PTR (o ),
1159- };
1125+ else if (m -> partitions [PARTITION_USR ].found ) {
1126+
1127+ /* Invalidate secondary arch /usr/ if we found the primary arch */
1128+ m -> partitions [PARTITION_USR_SECONDARY ].found = false;
1129+ m -> partitions [PARTITION_USR_SECONDARY_VERITY ].found = false;
1130+
1131+ } else if (m -> partitions [PARTITION_USR_VERITY ].found )
1132+ return - EADDRNOTAVAIL ; /* as above */
1133+
1134+ else if (m -> partitions [PARTITION_USR_SECONDARY ].found ) {
1135+
1136+ /* Upgrade secondary arch to primary */
1137+ m -> partitions [PARTITION_USR ] = m -> partitions [PARTITION_USR_SECONDARY ];
1138+ zero (m -> partitions [PARTITION_USR_SECONDARY ]);
1139+ m -> partitions [PARTITION_USR_VERITY ] = m -> partitions [PARTITION_USR_SECONDARY_VERITY ];
1140+ zero (m -> partitions [PARTITION_USR_SECONDARY_VERITY ]);
1141+
1142+ } else if (m -> partitions [PARTITION_USR_SECONDARY_VERITY ].found )
1143+ return - EADDRNOTAVAIL ; /* as above */
1144+
1145+ else if (flags & DISSECT_IMAGE_REQUIRE_ROOT ) {
1146+ _cleanup_free_ char * o = NULL ;
1147+ const char * options = NULL ;
1148+
1149+ /* OK, we found nothing usable, then check if there's a single generic one distro, and use
1150+ * that. */
1151+
1152+ /* If the root hash was set, then we won't fall back to a generic node, because the root hash
1153+ * decides. */
1154+ if (verity && verity -> root_hash )
1155+ return - EADDRNOTAVAIL ;
1156+
1157+ /* If we didn't find a generic node, then we can't fix this up either */
1158+ if (!generic_node )
1159+ return - ENXIO ;
1160+
1161+ /* If we didn't find a properly marked root partition, but we did find a single suitable
1162+ * generic Linux partition, then use this as root partition, if the caller asked for it. */
1163+ if (multiple_generic )
1164+ return - ENOTUNIQ ;
1165+
1166+ options = mount_options_from_designator (mount_options , PARTITION_ROOT );
1167+ if (options ) {
1168+ o = strdup (options );
1169+ if (!o )
1170+ return - ENOMEM ;
11601171 }
1172+
1173+ m -> partitions [PARTITION_ROOT ] = (DissectedPartition ) {
1174+ .found = true,
1175+ .rw = generic_rw ,
1176+ .partno = generic_nr ,
1177+ .architecture = _ARCHITECTURE_INVALID ,
1178+ .node = TAKE_PTR (generic_node ),
1179+ .uuid = generic_uuid ,
1180+ .mount_options = TAKE_PTR (o ),
1181+ };
11611182 }
11621183
11631184 /* Refuse if we found a verity partition for /usr but no matching file system partition */
@@ -1397,6 +1418,32 @@ static int mount_partition(
13971418 return 1 ;
13981419}
13991420
1421+ static int mount_root_tmpfs (const char * where , uid_t uid_shift , DissectImageFlags flags ) {
1422+ _cleanup_free_ char * options = NULL ;
1423+ int r ;
1424+
1425+ assert (where );
1426+
1427+ /* For images that contain /usr/ but no rootfs, let's mount rootfs as tmpfs */
1428+
1429+ if (FLAGS_SET (flags , DISSECT_IMAGE_MKDIR )) {
1430+ r = mkdir_p (where , 0755 );
1431+ if (r < 0 )
1432+ return r ;
1433+ }
1434+
1435+ if (uid_is_valid (uid_shift )) {
1436+ if (asprintf (& options , "uid=" UID_FMT ",gid=" GID_FMT , uid_shift , (gid_t ) uid_shift ) < 0 )
1437+ return - ENOMEM ;
1438+ }
1439+
1440+ r = mount_nofollow_verbose (LOG_DEBUG , "rootfs" , where , "tmpfs" , MS_NODEV , options );
1441+ if (r < 0 )
1442+ return r ;
1443+
1444+ return 1 ;
1445+ }
1446+
14001447int dissected_image_mount (DissectedImage * m , const char * where , uid_t uid_shift , DissectImageFlags flags ) {
14011448 int r , xbootldr_mounted ;
14021449
@@ -1413,16 +1460,20 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift,
14131460 * -EAFNOSUPPORT → File system type not supported or not known
14141461 */
14151462
1416- if (!m -> partitions [PARTITION_ROOT ].found )
1417- return - ENXIO ;
1463+ if (!(m -> partitions [PARTITION_ROOT ].found ||
1464+ (m -> partitions [PARTITION_USR ].found && FLAGS_SET (flags , DISSECT_IMAGE_USR_NO_ROOT ))))
1465+ return - ENXIO ; /* Require a root fs or at least a /usr/ fs (the latter is subject to a flag of its own) */
14181466
14191467 if ((flags & DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY ) == 0 ) {
1420- r = mount_partition (m -> partitions + PARTITION_ROOT , where , NULL , uid_shift , flags );
1468+
1469+ /* First mount the root fs. If there's none we use a tmpfs. */
1470+ if (m -> partitions [PARTITION_ROOT ].found )
1471+ r = mount_partition (m -> partitions + PARTITION_ROOT , where , NULL , uid_shift , flags );
1472+ else
1473+ r = mount_root_tmpfs (where , uid_shift , flags );
14211474 if (r < 0 )
14221475 return r ;
1423- }
14241476
1425- if ((flags & DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY ) == 0 ) {
14261477 /* For us mounting root always means mounting /usr as well */
14271478 r = mount_partition (m -> partitions + PARTITION_USR , where , "/usr" , uid_shift , flags );
14281479 if (r < 0 )
@@ -2305,7 +2356,14 @@ int dissected_image_acquire_metadata(DissectedImage *m) {
23052356 if (r == 0 ) {
23062357 error_pipe [0 ] = safe_close (error_pipe [0 ]);
23072358
2308- r = dissected_image_mount (m , t , UID_INVALID , DISSECT_IMAGE_READ_ONLY |DISSECT_IMAGE_MOUNT_ROOT_ONLY |DISSECT_IMAGE_VALIDATE_OS );
2359+ r = dissected_image_mount (
2360+ m ,
2361+ t ,
2362+ UID_INVALID ,
2363+ DISSECT_IMAGE_READ_ONLY |
2364+ DISSECT_IMAGE_MOUNT_ROOT_ONLY |
2365+ DISSECT_IMAGE_VALIDATE_OS |
2366+ DISSECT_IMAGE_USR_NO_ROOT );
23092367 if (r < 0 ) {
23102368 /* Let parent know the error */
23112369 (void ) write (error_pipe [1 ], & r , sizeof (r ));
0 commit comments