Commit d96acf38 authored by Li Lingfeng's avatar Li Lingfeng
Browse files

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: default avatarLi Lingfeng <lilingfeng3@huawei.com>
parent bf779220
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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
+40 −8
Original line number Diff line number Diff line
@@ -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;
		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)