From 06d779b822628e450dd4b2360617c3dda595c47b Mon Sep 17 00:00:00 2001 From: Li Lingfeng Date: Fri, 12 Jan 2024 14:32:05 +0800 Subject: [PATCH 1/6] block: Record writing and mounting regardless of whether bdev_allow_write_mounted is set hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8S3GW CVE: NA --------------------------- Introduce bd_mounted to record the state of mount. The count of bd_writers and bd_mounted can have other uses and they doesn't block writes when bdev_allow_write_mounted is not set, so remove the restriction for recording them. Signed-off-by: Li Lingfeng --- block/bdev.c | 19 +++++++++---------- include/linux/blk_types.h | 3 +++ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/block/bdev.c b/block/bdev.c index dd39c26c44ad..b031c91efa0d 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -735,17 +735,22 @@ void blkdev_put_no_open(struct block_device *bdev) static bool bdev_writes_blocked(struct block_device *bdev) { - return bdev->bd_writers == -1; + return bdev->bd_mounted; } static void bdev_block_writes(struct block_device *bdev) { - bdev->bd_writers = -1; + bdev->bd_mounted = true; } static void bdev_unblock_writes(struct block_device *bdev) { - bdev->bd_writers = 0; + bdev->bd_mounted = false; +} + +static bool bdev_mount_blocked(struct block_device *bdev) +{ + return bdev->bd_writers > 0; } static bool bdev_may_open(struct block_device *bdev, blk_mode_t mode) @@ -755,16 +760,13 @@ static bool bdev_may_open(struct block_device *bdev, blk_mode_t mode) /* Writes blocked? */ if (mode & BLK_OPEN_WRITE && bdev_writes_blocked(bdev)) return false; - if (mode & BLK_OPEN_RESTRICT_WRITES && bdev->bd_writers > 0) + if (mode & BLK_OPEN_RESTRICT_WRITES && bdev_mount_blocked(bdev)) return false; return true; } static void bdev_claim_write_access(struct block_device *bdev, blk_mode_t mode) { - if (bdev_allow_write_mounted) - return; - /* Claim exclusive or shared write access. */ if (mode & BLK_OPEN_RESTRICT_WRITES) bdev_block_writes(bdev); @@ -774,9 +776,6 @@ static void bdev_claim_write_access(struct block_device *bdev, blk_mode_t mode) static void bdev_yield_write_access(struct block_device *bdev, blk_mode_t mode) { - if (bdev_allow_write_mounted) - return; - /* Yield exclusive or shared write access. */ if (mode & BLK_OPEN_RESTRICT_WRITES) bdev_unblock_writes(bdev); diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 262ae789726b..f571b45eba19 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -69,6 +69,9 @@ struct block_device { #ifdef CONFIG_FAIL_MAKE_REQUEST bool bd_make_it_fail; #endif + /* State of mounting */ + bool bd_mounted; + /* The counter of write opened */ int bd_writers; /* * keep this out-of-line as it's both big and not needed in the fast -- Gitee From 108aa35d481d1367a4d1817f5266da55c49662e3 Mon Sep 17 00:00:00 2001 From: Li Lingfeng Date: Fri, 12 Jan 2024 14:32:06 +0800 Subject: [PATCH 2/6] block: Expand the meaning of bdev_allow_write_mounted hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8S3GW CVE: NA --------------------------- For bdev_allow_write_mounted, there will be more subdivided scenarios and different bits of it will be used to indicate different scenarios, so expand it now. Signed-off-by: Li Lingfeng --- block/bdev.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/block/bdev.c b/block/bdev.c index b031c91efa0d..a63f79901cc4 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -30,8 +30,12 @@ #include "../fs/internal.h" #include "blk.h" +#define bdev_write_mounted_opt(opt) (bdev_allow_write_mounted & (1 << BLKDEV_##opt)) /* Should we allow writing to mounted block devices? */ -static bool bdev_allow_write_mounted = IS_ENABLED(CONFIG_BLK_DEV_WRITE_MOUNTED); +#define BLKDEV_ALLOW_WRITE_MOUNTED 0 + +static u8 bdev_allow_write_mounted = + IS_ENABLED(CONFIG_BLK_DEV_WRITE_MOUNTED) << BLKDEV_ALLOW_WRITE_MOUNTED; struct bdev_inode { struct block_device bdev; @@ -755,7 +759,7 @@ static bool bdev_mount_blocked(struct block_device *bdev) static bool bdev_may_open(struct block_device *bdev, blk_mode_t mode) { - if (bdev_allow_write_mounted) + if (bdev_write_mounted_opt(ALLOW_WRITE_MOUNTED)) return true; /* Writes blocked? */ if (mode & BLK_OPEN_WRITE && bdev_writes_blocked(bdev)) @@ -1134,7 +1138,7 @@ void bdev_statx_dioalign(struct inode *inode, struct kstat *stat) static int __init setup_bdev_allow_write_mounted(char *str) { - if (kstrtobool(str, &bdev_allow_write_mounted)) + if (kstrtou8(str, 0, &bdev_allow_write_mounted)) pr_warn("Invalid option string for bdev_allow_write_mounted:" " '%s'\n", str); return 1; -- Gitee From bf7792202c890cf87ad1b79ecf165ed4a10bd19e Mon Sep 17 00:00:00 2001 From: Li Lingfeng Date: Fri, 12 Jan 2024 14:32:07 +0800 Subject: [PATCH 3/6] block: Add config option to detect writing to part0 while partitions mounted hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8S3GW CVE: NA --------------------------- When a partition of a block device is mounted, opening the entire block device for write operations may also damage the file system. Identify this situation. Signed-off-by: Li Lingfeng --- block/Kconfig | 10 ++++++++++ block/bdev.c | 43 +++++++++++++++++++++++++++++++++++++----- include/linux/blkdev.h | 2 ++ 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/block/Kconfig b/block/Kconfig index 7c7187366450..42d9e8f7eb54 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -249,6 +249,16 @@ config BLK_INLINE_ENCRYPTION_FALLBACK by falling back to the kernel crypto API when inline encryption hardware is not present. +config BLK_DEV_DETECT_WRITING_PART0 + bool "Detect writing to part0 when partitions mounted" + default n + help + When partitions of a block device are mounted, writing to part0's + buffer cache is likely going to cause filesystem corruption on + each partition. + As a supplement to BLK_DEV_WRITE_MOUNTED, enabling this + to detect the scenario above. + source "block/partitions/Kconfig" config BLK_MQ_PCI diff --git a/block/bdev.c b/block/bdev.c index a63f79901cc4..bc3ed0014f55 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -33,9 +33,12 @@ #define bdev_write_mounted_opt(opt) (bdev_allow_write_mounted & (1 << BLKDEV_##opt)) /* Should we allow writing to mounted block devices? */ #define BLKDEV_ALLOW_WRITE_MOUNTED 0 +/* Should we detect writing to part0 when partitions mounted */ +#define BLKDEV_DETECT_WRITING_PART0 1 static u8 bdev_allow_write_mounted = - IS_ENABLED(CONFIG_BLK_DEV_WRITE_MOUNTED) << BLKDEV_ALLOW_WRITE_MOUNTED; + IS_ENABLED(CONFIG_BLK_DEV_WRITE_MOUNTED) << BLKDEV_ALLOW_WRITE_MOUNTED | + IS_ENABLED(CONFIG_BLK_DEV_DETECT_WRITING_PART0) << BLKDEV_DETECT_WRITING_PART0; struct bdev_inode { struct block_device bdev; @@ -739,22 +742,52 @@ void blkdev_put_no_open(struct block_device *bdev) static bool bdev_writes_blocked(struct block_device *bdev) { - return bdev->bd_mounted; + if (bdev->bd_mounted) + return true; + if (bdev_opt(DETECT_WRITING_PART0)) + return bdev_is_partition(bdev) ? bdev_whole(bdev)->bd_mounted : + bdev->bd_disk->mount_partitions; + + return false; } static void bdev_block_writes(struct block_device *bdev) { bdev->bd_mounted = true; + if (bdev_is_partition(bdev)) + bdev->bd_disk->mount_partitions++; } static void bdev_unblock_writes(struct block_device *bdev) { bdev->bd_mounted = false; + if (bdev_is_partition(bdev)) + bdev->bd_disk->mount_partitions--; } static bool bdev_mount_blocked(struct block_device *bdev) { - return bdev->bd_writers > 0; + if (bdev->bd_writers) + return true; + if (bdev_opt(DETECT_WRITING_PART0)) + return bdev_is_partition(bdev) ? bdev_whole(bdev)->bd_writers : + bdev->bd_disk->write_open_partitions; + + return false; +} + +static void bdev_block_mount(struct block_device *bdev) +{ + bdev->bd_writers++; + if (bdev_is_partition(bdev)) + bdev->bd_disk->write_open_partitions++; +} + +static void bdev_unblock_mount(struct block_device *bdev) +{ + bdev->bd_writers--; + if (bdev_is_partition(bdev)) + bdev->bd_disk->write_open_partitions--; } static bool bdev_may_open(struct block_device *bdev, blk_mode_t mode) @@ -775,7 +808,7 @@ static void bdev_claim_write_access(struct block_device *bdev, blk_mode_t mode) if (mode & BLK_OPEN_RESTRICT_WRITES) bdev_block_writes(bdev); else if (mode & BLK_OPEN_WRITE) - bdev->bd_writers++; + bdev_block_mount(bdev); } static void bdev_yield_write_access(struct block_device *bdev, blk_mode_t mode) @@ -784,7 +817,7 @@ static void bdev_yield_write_access(struct block_device *bdev, blk_mode_t mode) if (mode & BLK_OPEN_RESTRICT_WRITES) bdev_unblock_writes(bdev); else if (mode & BLK_OPEN_WRITE) - bdev->bd_writers--; + bdev_unblock_mount(bdev); } /** diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index bea0b5fdac74..d8a0ee46ba37 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -162,6 +162,8 @@ struct gendisk { struct mutex open_mutex; /* open/close mutex */ unsigned open_partitions; /* number of open partitions */ + unsigned write_open_partitions; /* number of write open partitions */ + unsigned mount_partitions; /* number of mount partitions */ struct backing_dev_info *bdi; struct kobject queue_kobj; /* the queue/ directory */ -- Gitee From d96acf3852faa62d4d7550669d5e3af4bb8d810c Mon Sep 17 00:00:00 2001 From: Li Lingfeng Date: Fri, 12 Jan 2024 14:32:08 +0800 Subject: [PATCH 4/6] block: Add config option to show info about opening a mounted device for write hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8S3GW CVE: NA --------------------------- When writing to a mounted block device is allowed, we need to identify which processes may write to the block device to prevent the file system from being damaged in silence. Signed-off-by: Li Lingfeng --- block/Kconfig | 7 +++++++ block/bdev.c | 48 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/block/Kconfig b/block/Kconfig index 42d9e8f7eb54..2e70a431d417 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -259,6 +259,13 @@ config BLK_DEV_DETECT_WRITING_PART0 As a supplement to BLK_DEV_WRITE_MOUNTED, enabling this to detect the scenario above. +config BLK_DEV_WRITE_MOUNTED_DUMP + bool "Dump info when detecting conflict of opening block device" + default n + help + Enabling this to dump info when opening mounted block devices + for write or trying to mount write opened block devices. + source "block/partitions/Kconfig" config BLK_MQ_PCI diff --git a/block/bdev.c b/block/bdev.c index bc3ed0014f55..050a5cc5d4c2 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -30,15 +30,20 @@ #include "../fs/internal.h" #include "blk.h" +#define OPEN_EXCLUSIVE "VFS: Open an exclusive opened block device for write" +#define OPEN_FOR_EXCLUSIVE "VFS: Open a write opened block device exclusively" #define bdev_write_mounted_opt(opt) (bdev_allow_write_mounted & (1 << BLKDEV_##opt)) /* Should we allow writing to mounted block devices? */ #define BLKDEV_ALLOW_WRITE_MOUNTED 0 /* Should we detect writing to part0 when partitions mounted */ #define BLKDEV_DETECT_WRITING_PART0 1 +/* Should we dump info when opening mounted block devices for write? */ +#define BLKDEV_WRITE_MOUNTED_DUMP 2 static u8 bdev_allow_write_mounted = IS_ENABLED(CONFIG_BLK_DEV_WRITE_MOUNTED) << BLKDEV_ALLOW_WRITE_MOUNTED | - IS_ENABLED(CONFIG_BLK_DEV_DETECT_WRITING_PART0) << BLKDEV_DETECT_WRITING_PART0; + IS_ENABLED(CONFIG_BLK_DEV_DETECT_WRITING_PART0) << BLKDEV_DETECT_WRITING_PART0 | + IS_ENABLED(CONFIG_BLK_DEV_WRITE_MOUNTED_DUMP) << BLKDEV_WRITE_MOUNTED_DUMP; struct bdev_inode { struct block_device bdev; @@ -740,11 +745,34 @@ void blkdev_put_no_open(struct block_device *bdev) put_device(&bdev->bd_device); } +static void blkdev_dump_conflict_opener(struct block_device *bdev, char *msg) +{ + char name[BDEVNAME_SIZE]; + struct task_struct *p = NULL; + char comm_buf[TASK_COMM_LEN]; + pid_t p_pid; + + if (!bdev_write_mounted_opt(WRITE_MOUNTED_DUMP)) + return; + rcu_read_lock(); + p = rcu_dereference(current->real_parent); + task_lock(p); + strncpy(comm_buf, p->comm, TASK_COMM_LEN); + p_pid = p->pid; + task_unlock(p); + rcu_read_unlock(); + + snprintf(name, sizeof(name), "%pg", bdev); + pr_info_ratelimited("%s [%s]. current [%d %s]. parent [%d %s]\n", + msg, name, + current->pid, current->comm, p_pid, comm_buf); +} + static bool bdev_writes_blocked(struct block_device *bdev) { if (bdev->bd_mounted) return true; - if (bdev_opt(DETECT_WRITING_PART0)) + if (bdev_write_mounted_opt(DETECT_WRITING_PART0)) return bdev_is_partition(bdev) ? bdev_whole(bdev)->bd_mounted : bdev->bd_disk->mount_partitions; @@ -769,7 +797,7 @@ static bool bdev_mount_blocked(struct block_device *bdev) { if (bdev->bd_writers) return true; - if (bdev_opt(DETECT_WRITING_PART0)) + if (bdev_write_mounted_opt(DETECT_WRITING_PART0)) return bdev_is_partition(bdev) ? bdev_whole(bdev)->bd_writers : bdev->bd_disk->write_open_partitions; @@ -792,14 +820,18 @@ static void bdev_unblock_mount(struct block_device *bdev) static bool bdev_may_open(struct block_device *bdev, blk_mode_t mode) { - if (bdev_write_mounted_opt(ALLOW_WRITE_MOUNTED)) + if (bdev_write_mounted_opt(ALLOW_WRITE_MOUNTED) && + !bdev_write_mounted_opt(WRITE_MOUNTED_DUMP)) return true; /* Writes blocked? */ if (mode & BLK_OPEN_WRITE && bdev_writes_blocked(bdev)) - return false; - if (mode & BLK_OPEN_RESTRICT_WRITES && bdev_mount_blocked(bdev)) - return false; - return true; + blkdev_dump_conflict_opener(bdev, OPEN_EXCLUSIVE); + else if (mode & BLK_OPEN_RESTRICT_WRITES && bdev_mount_blocked(bdev)) + blkdev_dump_conflict_opener(bdev, OPEN_FOR_EXCLUSIVE); + else + return true; + + return bdev_write_mounted_opt(ALLOW_WRITE_MOUNTED); } static void bdev_claim_write_access(struct block_device *bdev, blk_mode_t mode) -- Gitee From 092b90d27efe66a1d20823ce85ca481a68a323d0 Mon Sep 17 00:00:00 2001 From: Li Lingfeng Date: Fri, 12 Jan 2024 14:32:09 +0800 Subject: [PATCH 5/6] block: Show info about opening a lower device for write while upper-layers mounted hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8S3GW CVE: NA --------------------------- Filesystem on logic devices may be corrupted when writing to a block device which is used to create logic devices, so show info to indicate this risk behavior. Signed-off-by: Li Lingfeng --- block/bdev.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/block/bdev.c b/block/bdev.c index 050a5cc5d4c2..b555deef0d76 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -818,6 +818,22 @@ static void bdev_unblock_mount(struct block_device *bdev) bdev->bd_disk->write_open_partitions--; } +static void bdev_write_exclusive_dump(struct block_device *bdev, void *holder, + const struct blk_holder_ops *hops) +{ + bool may_claim; + + if (!bdev_write_mounted_opt(WRITE_MOUNTED_DUMP)) + return; + + mutex_lock(&bdev_lock); + may_claim = bd_may_claim(bdev, holder, hops); + mutex_unlock(&bdev_lock); + + if (!may_claim) + blkdev_dump_conflict_opener(bdev, OPEN_EXCLUSIVE); +} + static bool bdev_may_open(struct block_device *bdev, blk_mode_t mode) { if (bdev_write_mounted_opt(ALLOW_WRITE_MOUNTED) && @@ -919,6 +935,9 @@ struct bdev_handle *bdev_open_by_dev(dev_t dev, blk_mode_t mode, void *holder, disk_block_events(disk); + if (mode & BLK_OPEN_WRITE) + bdev_write_exclusive_dump(bdev, holder, hops); + mutex_lock(&disk->open_mutex); ret = -ENXIO; if (!disk_live(disk)) -- Gitee From 904ff472ef09413c73cf478d36d3e8aa30d0924b Mon Sep 17 00:00:00 2001 From: Li Lingfeng Date: Fri, 12 Jan 2024 14:32:10 +0800 Subject: [PATCH 6/6] add config about writing mounted devices in openeuler_defconfig hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8S3GW CVE: NA --------------------------- OpenEuler need detect conflict of opening block device, so enable it as default. Signed-off-by: Li Lingfeng --- arch/arm64/configs/openeuler_defconfig | 3 +++ arch/x86/configs/openeuler_defconfig | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig index 703fe5bc2535..fb66e3e9c47a 100644 --- a/arch/arm64/configs/openeuler_defconfig +++ b/arch/arm64/configs/openeuler_defconfig @@ -901,6 +901,9 @@ CONFIG_BLK_DEBUG_FS=y CONFIG_BLK_DEBUG_FS_ZONED=y # CONFIG_BLK_SED_OPAL is not set # CONFIG_BLK_INLINE_ENCRYPTION is not set +CONFIG_BLK_DEV_WRITE_MOUNTED=y +CONFIG_BLK_DEV_DETECT_WRITING_PART0=y +CONFIG_BLK_DEV_WRITE_MOUNTED_DUMP=y # # Partition Types diff --git a/arch/x86/configs/openeuler_defconfig b/arch/x86/configs/openeuler_defconfig index c9e816e54003..54f0d478f614 100644 --- a/arch/x86/configs/openeuler_defconfig +++ b/arch/x86/configs/openeuler_defconfig @@ -965,6 +965,9 @@ CONFIG_BLK_DEBUG_FS=y CONFIG_BLK_DEBUG_FS_ZONED=y # CONFIG_BLK_SED_OPAL is not set # CONFIG_BLK_INLINE_ENCRYPTION is not set +CONFIG_BLK_DEV_WRITE_MOUNTED=y +CONFIG_BLK_DEV_DETECT_WRITING_PART0=y +CONFIG_BLK_DEV_WRITE_MOUNTED_DUMP=y # # Partition Types -- Gitee