commit 68564ebb50f8afab5a9527c534417e247cca0b27 Author: Filipe Manana Date: Thu Aug 17 10:20:13 2023 +0100 libmount: Fix regression when mounting with atime A regression was introduced in v2.39 that causes mounting with the atime option to fail: $ mkfs.ext4 -F /dev/sdi $ mount -o atime /dev/sdi /mnt/sdi mount: /mnt/sdi: not mount point or bad option. dmesg(1) may have more information after failed mount system call. The failure comes from the mount_setattr(2) call returning -EINVAL. This is because we pass an invalid value for the attr_clr argument. From a strace capture we have: mount_setattr(4, "", AT_EMPTY_PATH, {attr_set=0, attr_clr=MOUNT_ATTR_NOATIME, propagation=0 /* MS_??? */, userns_fd=0}, 32) = -1 EINVAL (Invalid argument) We can't pass MOUNT_ATTR_NOATIME to mount_setattr(2) through the attr_clr argument because all atime options are exclusive, so in order to set atime one has to pass MOUNT_ATTR__ATIME to attr_clr and leave attr_set as MOUNT_ATTR_RELATIME (which is defined as a value of 0). This can be read from the man page for mount_setattr(2) and also from the kernel source: $ cat fs/namespace.c static int build_mount_kattr(const struct mount_attr *attr, size_t usize, struct mount_kattr *kattr, unsigned int flags) { (...) /* * Since the MOUNT_ATTR_ values are an enum, not a bitmap, * users wanting to transition to a different atime setting cannot * simply specify the atime setting in @attr_set, but must also * specify MOUNT_ATTR__ATIME in the @attr_clr field. * So ensure that MOUNT_ATTR__ATIME can't be partially set in * @attr_clr and that @attr_set can't have any atime bits set if * MOUNT_ATTR__ATIME isn't set in @attr_clr. */ if (attr->attr_clr & MOUNT_ATTR__ATIME) { if ((attr->attr_clr & MOUNT_ATTR__ATIME) != MOUNT_ATTR__ATIME) return -EINVAL; /* * Clear all previous time settings as they are mutually * exclusive. */ kattr->attr_clr |= MNT_RELATIME | MNT_NOATIME; switch (attr->attr_set & MOUNT_ATTR__ATIME) { case MOUNT_ATTR_RELATIME: kattr->attr_set |= MNT_RELATIME; break; case MOUNT_ATTR_NOATIME: kattr->attr_set |= MNT_NOATIME; break; case MOUNT_ATTR_STRICTATIME: break; default: return -EINVAL; } (...) So fix this by setting attr_clr MOUNT_ATTR__ATIME if we want to clear any atime related option. Signed-off-by: Filipe Manana diff --git a/libmount/src/optlist.c b/libmount/src/optlist.c index 1e962ec6d..0702adae7 100644 --- a/libmount/src/optlist.c +++ b/libmount/src/optlist.c @@ -875,7 +875,18 @@ int mnt_optlist_get_attrs(struct libmnt_optlist *ls, uint64_t *set, uint64_t *cl if (opt->ent->mask & MNT_INVERT) { DBG(OPTLIST, ul_debugobj(ls, " clr: %s", opt->ent->name)); - *clr |= x; + /* + * All atime settings are mutually exclusive so *clr must + * have MOUNT_ATTR__ATIME set. + * + * See the function fs/namespace.c:build_mount_kattr() + * in the linux kernel source. + */ + if (x == MOUNT_ATTR_RELATIME || x == MOUNT_ATTR_NOATIME || + x == MOUNT_ATTR_STRICTATIME) + *clr |= MOUNT_ATTR__ATIME; + else + *clr |= x; } else { DBG(OPTLIST, ul_debugobj(ls, " set: %s", opt->ent->name)); *set |= x; diff --git a/tests/expected/libmount/context-mount-flags b/tests/expected/libmount/context-mount-flags index 960641863..eb71323dd 100644 --- a/tests/expected/libmount/context-mount-flags +++ b/tests/expected/libmount/context-mount-flags @@ -3,3 +3,6 @@ ro,nosuid,noexec successfully mounted rw,nosuid,noexec successfully umounted +successfully mounted +rw,relatime +successfully umounted diff --git a/tests/ts/libmount/context b/tests/ts/libmount/context index f5b47185e..a5d2e81a3 100755 --- a/tests/ts/libmount/context +++ b/tests/ts/libmount/context @@ -116,8 +116,15 @@ $TS_CMD_FINDMNT --kernel --mountpoint $MOUNTPOINT -o VFS-OPTIONS -n >> $TS_OUTPU ts_run $TESTPROG --umount $MOUNTPOINT >> $TS_OUTPUT 2>> $TS_ERRLOG is_mounted $DEVICE && echo "$DEVICE still mounted" >> $TS_OUTPUT 2>> $TS_ERRLOG -ts_finalize_subtest +# Test that the atime option works after the migration to use the new kernel mount APIs. +ts_run $TESTPROG --mount -o atime $DEVICE $MOUNTPOINT >> $TS_OUTPUT 2>> $TS_ERRLOG +$TS_CMD_FINDMNT --kernel --mountpoint $MOUNTPOINT -o VFS-OPTIONS -n >> $TS_OUTPUT 2>> $TS_ERRLOG +is_mounted $DEVICE || echo "$DEVICE not mounted" >> $TS_OUTPUT 2>> $TS_ERRLOG +ts_run $TESTPROG --umount $MOUNTPOINT >> $TS_OUTPUT 2>> $TS_ERRLOG +is_mounted $DEVICE && echo "$DEVICE still mounted" >> $TS_OUTPUT 2>> $TS_ERRLOG + +ts_finalize_subtest ts_init_subtest "mount-loopdev" mkdir -p $MOUNTPOINT &> /dev/null commit 1ec71634aa4ef5ddca23d65c8a296f3614231e8a Author: Colin Gillespie Date: Wed Aug 9 18:28:07 2023 +1000 libblkid: (bcachefs) fix not detecting large superblocks Probing does not detect bcachefs filesystems with a superblock larger than 4KiB. Bcachefs superblocks grow in size and can become much larger than this. Increase the superblock maximum size limit to 1MiB. Validate the superblock isn't larger than the maximum size defined in the superblocks layout section. (cherry picked from commit 48d573797797650d96456979797c0155d58f61cb) diff --git a/libblkid/src/superblocks/bcache.c b/libblkid/src/superblocks/bcache.c index 40e702d75..236877042 100644 --- a/libblkid/src/superblocks/bcache.c +++ b/libblkid/src/superblocks/bcache.c @@ -102,6 +102,15 @@ union bcachefs_sb_csum { uint8_t raw[16]; } __attribute__((packed)); +struct bcachefs_sb_layout { + uint8_t magic[16]; + uint8_t layout_type; + uint8_t sb_max_size_bits; + uint8_t nr_superblocks; + uint8_t pad[5]; + uint64_t sb_offset[61]; +} __attribute__((packed)); + struct bcachefs_super_block { union bcachefs_sb_csum csum; uint16_t version; @@ -123,7 +132,7 @@ struct bcachefs_super_block { uint64_t flags[8]; uint64_t features[2]; uint64_t compat[2]; - uint8_t layout[512]; + struct bcachefs_sb_layout layout; struct bcachefs_sb_field _start[]; } __attribute__((packed)); @@ -143,7 +152,7 @@ struct bcachefs_super_block { /* granularity of offset and length fields within superblock */ #define BCACHEFS_SECTOR_SIZE 512 /* maximum superblock size */ -#define BCACHEFS_SB_MAX_SIZE 4096 +#define BCACHEFS_SB_MAX_SIZE 0x100000 /* fields offset within super block */ #define BCACHEFS_SB_FIELDS_OFF offsetof(struct bcachefs_super_block, _start) /* tag value for members field */ @@ -302,6 +311,9 @@ static int probe_bcachefs(blkid_probe pr, const struct blkid_idmag *mag) return BLKID_PROBE_NONE; sb_size = BCACHEFS_SB_FIELDS_OFF + BYTES(bcs); + if (sb_size > BCACHEFS_SECTOR_SIZE << bcs->layout.sb_max_size_bits) + return BLKID_PROBE_NONE; + if (sb_size > BCACHEFS_SB_MAX_SIZE) return BLKID_PROBE_NONE; commit acbf17ae8f8ee0f941fe98ed12f115f2b349bba8 Author: Karel Zak Date: Wed Aug 23 11:53:45 2023 +0200 libblkid: (bcachefs) fix compiler warning [-Werror=sign-compare] Addresses: https://github.com/util-linux/util-linux/pull/2427 Signed-off-by: Karel Zak (cherry picked from commit 17873d38fc97913c0a31d4bd08cfbfe45c4de5be) diff --git a/libblkid/src/superblocks/bcache.c b/libblkid/src/superblocks/bcache.c index 236877042..6ab3fe9d4 100644 --- a/libblkid/src/superblocks/bcache.c +++ b/libblkid/src/superblocks/bcache.c @@ -311,7 +311,7 @@ static int probe_bcachefs(blkid_probe pr, const struct blkid_idmag *mag) return BLKID_PROBE_NONE; sb_size = BCACHEFS_SB_FIELDS_OFF + BYTES(bcs); - if (sb_size > BCACHEFS_SECTOR_SIZE << bcs->layout.sb_max_size_bits) + if (sb_size > ((uint64_t) BCACHEFS_SECTOR_SIZE << bcs->layout.sb_max_size_bits)) return BLKID_PROBE_NONE; if (sb_size > BCACHEFS_SB_MAX_SIZE) commit 6b9fda87c4e5d0c6f945d7565197f157b9fa3d5f Author: Thomas Weißschuh Date: Wed Aug 23 11:58:33 2023 +0200 libblkid: (bcachefs) fix size validation Avoid signed shift out-of-bounds. Also mark the constants explitly as unsigned instead of casting. Signed-off-by: Thomas Weißschuh (cherry picked from commit befe455f59de8c7bc66b85ed52aae8cbc95325fa) diff --git a/libblkid/src/superblocks/bcache.c b/libblkid/src/superblocks/bcache.c index 6ab3fe9d4..28ac4b52b 100644 --- a/libblkid/src/superblocks/bcache.c +++ b/libblkid/src/superblocks/bcache.c @@ -142,17 +142,19 @@ struct bcachefs_super_block { /* magic string len */ #define BCACHE_SB_MAGIC_LEN (sizeof(BCACHE_SB_MAGIC) - 1) /* super block offset */ -#define BCACHE_SB_OFF 0x1000 +#define BCACHE_SB_OFF 0x1000U /* supper block offset in kB */ #define BCACHE_SB_KBOFF (BCACHE_SB_OFF >> 10) /* magic string offset within super block */ #define BCACHE_SB_MAGIC_OFF offsetof(struct bcache_super_block, magic) /* start of checksummed data within superblock */ -#define BCACHE_SB_CSUMMED_START 8 +#define BCACHE_SB_CSUMMED_START 8U /* granularity of offset and length fields within superblock */ -#define BCACHEFS_SECTOR_SIZE 512 +#define BCACHEFS_SECTOR_SIZE 512U +/* maximum superblock size shift */ +#define BCACHEFS_SB_MAX_SIZE_SHIFT 0x10U /* maximum superblock size */ -#define BCACHEFS_SB_MAX_SIZE 0x100000 +#define BCACHEFS_SB_MAX_SIZE (1U << BCACHEFS_SB_MAX_SIZE_SHIFT) /* fields offset within super block */ #define BCACHEFS_SB_FIELDS_OFF offsetof(struct bcachefs_super_block, _start) /* tag value for members field */ @@ -311,12 +313,16 @@ static int probe_bcachefs(blkid_probe pr, const struct blkid_idmag *mag) return BLKID_PROBE_NONE; sb_size = BCACHEFS_SB_FIELDS_OFF + BYTES(bcs); - if (sb_size > ((uint64_t) BCACHEFS_SECTOR_SIZE << bcs->layout.sb_max_size_bits)) - return BLKID_PROBE_NONE; if (sb_size > BCACHEFS_SB_MAX_SIZE) return BLKID_PROBE_NONE; + if (bcs->layout.sb_max_size_bits > BCACHEFS_SB_MAX_SIZE_SHIFT) + return BLKID_PROBE_NONE; + + if (sb_size > (BCACHEFS_SECTOR_SIZE << bcs->layout.sb_max_size_bits)) + return BLKID_PROBE_NONE; + sb = blkid_probe_get_sb_buffer(pr, mag, sb_size); if (!sb) return BLKID_PROBE_NONE;