From 7ef86a08914427d6486734614d7d3bbed1f108fe Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Tue, 24 Sep 2019 17:46:16 +0800 Subject: [PATCH] libblkid: improve handling of ISO files with partition tables The ISO format specifically leaves the first 32kb blank so that it can be used for other purposes, such as adding a partition table. This is commonly used (e.g. by Endless and Fedora installation media) to have partition 0 starting at sector 0 as a mountable iso9660 filesystem, followed by more partitions (e.g. an EFI system partition). Such layouts can be easily created by tools such as xorriso. When plugging in a USB disk flashed with this type of ISO, blkid presents a somewhat confusing view of the block devices. Taking the example of a 'sda' disk with two partitions: 1. The "iso partition" 2. An unformatted partition In such a setup, before the changes here, blkid will currently report the ISO metadata attributes ID_FS_PUBLISHER_ID, ID_FS_UUID, ID_FS_LABEL, and ID_FS_TYPE=iso9660 on both sda *and* sda1. Since sda2 is unformatted, it won't have any ID_FS_ attributes of it's own. And due to the following standard udev rule: # for partitions import parent information ENV{DEVTYPE}=="partition", IMPORT{parent}="ID_*" sda2 will actually import all of the ID_FS_ stuff from the parent device sda. The result at this point is that three udev devices all have the same ID_FS_ attribute values, leading to strange results such as three devices all racing to own the link in /dev/disk/by-uuid, so you can't reliably do a mount-by-UUID. Clean up this situation by detecting such partitioned ISO disks in the superblock probing setup. If files of this kind are detected, we now only expose the ISO metadata attributes on the specific partition that points to the ISO data (and not the parent disk). Signed-off-by: Daniel Drake --- libblkid/src/superblocks/iso9660.c | 37 +++++++++ .../blkid/iso-partitions-no_partitions | 9 +++ .../expected/blkid/iso-partitions-partitions | 25 ++++++ tests/ts/blkid/iso-partitions | 71 ++++++++++++++++++ tests/ts/blkid/iso-partitions.img.xz | Bin 0 -> 1188 bytes 5 files changed, 142 insertions(+) create mode 100644 tests/expected/blkid/iso-partitions-no_partitions create mode 100644 tests/expected/blkid/iso-partitions-partitions create mode 100755 tests/ts/blkid/iso-partitions create mode 100644 tests/ts/blkid/iso-partitions.img.xz diff --git a/libblkid/src/superblocks/iso9660.c b/libblkid/src/superblocks/iso9660.c index 8dc2e5394..730939f70 100644 --- a/libblkid/src/superblocks/iso9660.c +++ b/libblkid/src/superblocks/iso9660.c @@ -13,6 +13,7 @@ */ #include #include +#include #include #include #include @@ -165,6 +166,37 @@ static int is_str_empty(const unsigned char *str, size_t len) return 1; } +/* + * The ISO format specifically avoids the first 32kb to allow for a + * partition table to be added, if desired. + * When an ISO contains a partition table, the usual thing to do is to + * have a partition that points at the iso filesystem. In such case, + * we want to only probe the iso metadata for the corresponding partition + * device, avoiding returning the metadata for the parent block device. + */ +static bool isofs_belongs_to_device(blkid_probe pr) +{ + dev_t devno; + blkid_partlist ls; + + /* Get device number, but if that fails, assume we aren't dealing + * with partitions, and continue probing. */ + devno = blkid_probe_get_devno(pr); + if (!devno) + return true; + + /* Get partition table, but if that fails, assume we aren't dealing + * with partitions, and continue probing. */ + ls = blkid_probe_get_partitions(pr); + if (!ls) + return true; + + /* Check that the device we're working with corresponds to an + * entry in the partition table. If so, this is the correct + * device to return the iso metadata on. */ + return blkid_partlist_devno_to_partition(ls, devno) != NULL; +} + /* iso9660 [+ Microsoft Joliet Extension] */ static int probe_iso9660(blkid_probe pr, const struct blkid_idmag *mag) { @@ -180,6 +212,11 @@ static int probe_iso9660(blkid_probe pr, const struct blkid_idmag *mag) if (!iso) return errno ? -errno : 1; + /* Check if the iso metadata should be returned on a different device + * instead of this one. */ + if (!isofs_belongs_to_device(pr)) + return 1; + memcpy(label, iso->volume_id, sizeof(label)); blkid_probe_set_block_size(pr, 2048); diff --git a/tests/expected/blkid/iso-partitions-no_partitions b/tests/expected/blkid/iso-partitions-no_partitions new file mode 100644 index 000000000..dbfd57a34 --- /dev/null +++ b/tests/expected/blkid/iso-partitions-no_partitions @@ -0,0 +1,9 @@ +ID_FS_BLOCK_SIZE=2048 +ID_FS_PUBLISHER_ID=UTIL-LINUX +ID_FS_UUID=2019-09-24-09-31-05-00 +ID_FS_UUID_ENC=2019-09-24-09-31-05-00 +ID_FS_VERSION=Joliet\x20Extension +ID_FS_LABEL=ISOIMAGE +ID_FS_LABEL_ENC=ISOIMAGE +ID_FS_TYPE=iso9660 +ID_FS_USAGE=filesystem diff --git a/tests/expected/blkid/iso-partitions-partitions b/tests/expected/blkid/iso-partitions-partitions new file mode 100644 index 000000000..e34ca39fc --- /dev/null +++ b/tests/expected/blkid/iso-partitions-partitions @@ -0,0 +1,25 @@ +ID_PART_TABLE_TYPE=dos +-- +ID_FS_BLOCK_SIZE=2048 +ID_FS_PUBLISHER_ID=UTIL-LINUX +ID_FS_UUID=2019-09-24-09-31-05-00 +ID_FS_UUID_ENC=2019-09-24-09-31-05-00 +ID_FS_VERSION=Joliet\x20Extension +ID_FS_LABEL=ISOIMAGE +ID_FS_LABEL_ENC=ISOIMAGE +ID_FS_TYPE=iso9660 +ID_FS_USAGE=filesystem +ID_PART_TABLE_TYPE=dos +ID_PART_ENTRY_SCHEME=dos +ID_PART_ENTRY_TYPE=0x83 +ID_PART_ENTRY_NUMBER=1 +ID_PART_ENTRY_OFFSET=0 +ID_PART_ENTRY_SIZE=136 +ID_PART_ENTRY_DISK=__ts_majorminor__ +-- +ID_PART_ENTRY_SCHEME=dos +ID_PART_ENTRY_TYPE=0xef +ID_PART_ENTRY_NUMBER=2 +ID_PART_ENTRY_OFFSET=136 +ID_PART_ENTRY_SIZE=4096 +ID_PART_ENTRY_DISK=__ts_majorminor__ diff --git a/tests/ts/blkid/iso-partitions b/tests/ts/blkid/iso-partitions new file mode 100755 index 000000000..02fdd4e50 --- /dev/null +++ b/tests/ts/blkid/iso-partitions @@ -0,0 +1,71 @@ +#!/bin/bash + +# +# Copyright (C) 2019 Endless Mobile, Inc. +# +# This file is part of util-linux. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This file is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +TS_TOPDIR="${0%/*}/../.." +TS_DESC="iso-partitions" + +. $TS_TOPDIR/functions.sh + +ts_init "$*" + +ts_check_test_command "$TS_CMD_BLKID" +ts_check_test_command "$TS_CMD_PARTX" + +ts_skip_nonroot + +# set global variable TS_DEVICE +ts_scsi_debug_init dev_size_mb=50 + +# This image (created by xorriso) has partition 1 pointing to the ISO +# area, followed by an unformatted second partition. +xz -dc ${TS_SELF}/iso-partitions.img.xz > ${TS_DEVICE} +udevadm settle + +ts_init_subtest "partitions" +$TS_CMD_PARTX -a ${TS_DEVICE} &>/dev/null +udevadm settle + +# Check that the ISO metadata is not shown on the main disk device +$TS_CMD_BLKID -p -o udev ${TS_DEVICE} >> $TS_OUTPUT +echo -- >> $TS_OUTPUT + +# Check that the ISO metadata is shown on the "ISO partition" +$TS_CMD_BLKID -p -o udev ${TS_DEVICE}1 >> $TS_OUTPUT +echo -- >> $TS_OUTPUT + +# Check that the ISO metadata is not shown on the other partition +$TS_CMD_BLKID -p -o udev ${TS_DEVICE}2 >> $TS_OUTPUT + +# substitute major/minor number before comparison +sed -i \ + -e 's/^\(ID_PART_ENTRY_DISK\)=.*/\1=__ts_majorminor__/' \ + $TS_OUTPUT + +ts_finalize_subtest + +# Remove the partition table and check that the ISO metadata is shown on the +# main disk device. +ts_init_subtest "no_partitions" +dd if=/dev/zero of=${TS_DEVICE} bs=512 count=1 &>/dev/null +udevadm settle +$TS_CMD_PARTX -d ${TS_DEVICE} &>/dev/null +udevadm settle +$TS_CMD_BLKID -p -o udev ${TS_DEVICE} >> $TS_OUTPUT +ts_finalize_subtest + +ts_finalize diff --git a/tests/ts/blkid/iso-partitions.img.xz b/tests/ts/blkid/iso-partitions.img.xz new file mode 100644 index 0000000000000000000000000000000000000000..4eb3dd17b788782d594261465ed3db22cef23b3b GIT binary patch literal 1188 zcmexsUKJ6=z`*kC+7>q^21Q0O1_p)_{ilon|KGr(63f7l|MyQ1%Y!)u&zg7ZKi62M zcxzwe?>A?1DjCgN{wLjMxyLr+@VnpMsSJNsxldj1;-xW*K{k+wFZbl%;Itbvg^Zgo z@q~zfDbVNZ)ypTj76le?-5Zr!zU0fh+dCkQ_rq`YvYa6+)A)7xlIu-e!8rBeg(HPciVo z;qpXR$%^G7dkv~CzX{@e_fqqon8o9)3A_J&w4ONegIea~^Ot|`Vzm4iHMM)ko^`eR z_f<8<&2oNj6#iRz%| z{@OuflgwZ0%)NAG!OhF-V_qL!$9nO44@Yjpe!WwkE0+lT)V*~* z|3&b*g-5Lqw!~bp5UzZjGuLq1rulgtFK6UVt`QWweS1UToheV&%Nrf#KDxxB*TM59 zUkv*mo{w{X3ZD8kN$lE^YpELV6>W|Kt{QQ8Zh26^xYOy|eBX{b+jgJXO-exy5*&X!` zn9aVz&6Y<|();jz3;w9d^Xq)eY@AwdHzgds)>wG$!4B4sS^q`y_f#rwU18jx)KVK2 zm^7)xGv-L{rb*8ioH)nM@^1dUrB0_i>|+@EFZiuj)0k2yZ`-f(uwdSD<@h%mr&}*h zozYdNHSv>r>37KkY%_dk{JpXM>ID8Hs=+_LPBb%QUAp02{=ouYcbktwSRsGX_uUpi&k*@c{kYhhh_?=b;D_`ocmj? zKOEVs7r%<%&O6O%f-v8IfyqA#D)2T zE=R|=9`IwZVt7*=y!`LJbv1@k^SAdJ<`L!H30Hq|Y_?`ty2dm1v_xnT17ibcL&J2& U7Ug+UHy%m<%>*oq7+4~s0PeF*O#lD@ literal 0 HcmV?d00001