| From 7e212ddab9682e39c383baa643250c6fd45afc05 Mon Sep 17 00:00:00 2001 |
| From: Daniil Lunev <dlunev@chromium.org> |
| Date: Wed, 23 Mar 2022 16:55:36 +1100 |
| Subject: [PATCH] CHROMIUM: loop: Selective prohibit open after fdclear |
| |
| Security model for CrOS swap requires exclusion of userspace |
| access to integrity information. Since integrity information |
| is stored as a dm-integrity metadevice, that means a need |
| for access exclusion to loop device and underlying file. |
| While underlying file can be unlinked from userspace, the loop |
| device is constantly present and requires other mechanisms to |
| block its userspace "open". A proposed "flag"-based solution for |
| device mapper part of the story (needed for excluding access to |
| plain text content of memory) was rejected upstream[1] and there |
| is no reason to think the stance on loop device would be different. |
| While switching behaviour on filename pattern is a hack, this is |
| a minimal diff from upstream to introduce needed behaviour. |
| |
| More details: http://shortn/_CcsfmxSjSQ |
| |
| [1] https://lkml.org/lkml/2022/1/24/633 |
| |
| BUG=b:226288069 |
| TEST=http://crrev/c/3544851 |
| |
| Signed-off-by: Daniil Lunev <dlunev@chromium.org> |
| |
| Change-Id: I80359fe90dd5d5396d7f330e79b51248dba3b85c |
| Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/3544412 |
| Reviewed-by: Allen Webb <allenwebb@google.com> |
| Tested-by: Daniil Lunev <dlunev@chromium.org> |
| Reviewed-by: Brian Geffon <bgeffon@chromium.org> |
| Commit-Queue: Daniil Lunev <dlunev@chromium.org> |
| --- |
| drivers/block/loop.c | 16 ++++++++++++++++ |
| 1 file changed, 16 insertions(+) |
| |
| diff --git a/drivers/block/loop.c b/drivers/block/loop.c |
| index 084f9b8a0ba3..8e831e3f199c 100644 |
| --- a/drivers/block/loop.c |
| +++ b/drivers/block/loop.c |
| @@ -52,6 +52,7 @@ struct loop_device { |
| loff_t lo_offset; |
| loff_t lo_sizelimit; |
| int lo_flags; |
| + bool block_open_on_autoclear; |
| char lo_file_name[LO_NAME_SIZE]; |
| |
| struct file * lo_backing_file; |
| @@ -92,10 +93,20 @@ struct loop_cmd { |
| #define LOOP_IDLE_WORKER_TIMEOUT (60 * HZ) |
| #define LOOP_DEFAULT_HW_Q_DEPTH (128) |
| |
| +static const char kBlockOpenOnAutoclearPrefix[] = "__block_open_on_autoclear__"; |
| + |
| static DEFINE_IDR(loop_index_idr); |
| static DEFINE_MUTEX(loop_ctl_mutex); |
| static DEFINE_MUTEX(loop_validate_mutex); |
| |
| +static bool should_block_open_on_autoclear(struct file *file) |
| +{ |
| + const size_t prefix_len = strlen(kBlockOpenOnAutoclearPrefix); |
| + const char *fname = file->f_path.dentry->d_name.name; |
| + |
| + return !strncmp(fname, kBlockOpenOnAutoclearPrefix, prefix_len); |
| +} |
| + |
| /** |
| * loop_global_lock_killable() - take locks for safe loop_validate_file() test |
| * |
| @@ -607,6 +618,8 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, |
| blk_mq_freeze_queue(lo->lo_queue); |
| mapping_set_gfp_mask(old_file->f_mapping, lo->old_gfp_mask); |
| lo->lo_backing_file = file; |
| + if (should_block_open_on_autoclear(file)) |
| + lo->block_open_on_autoclear = true; |
| lo->old_gfp_mask = mapping_gfp_mask(file->f_mapping); |
| mapping_set_gfp_mask(file->f_mapping, |
| lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); |
| @@ -1068,6 +1081,8 @@ static int loop_configure(struct loop_device *lo, fmode_t mode, |
| lo->use_dio = lo->lo_flags & LO_FLAGS_DIRECT_IO; |
| lo->lo_device = bdev; |
| lo->lo_backing_file = file; |
| + if (should_block_open_on_autoclear(file)) |
| + lo->block_open_on_autoclear = true; |
| lo->old_gfp_mask = mapping_gfp_mask(mapping); |
| mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); |
| |
| @@ -1147,6 +1162,7 @@ static void __loop_clr_fd(struct loop_device *lo, bool release) |
| spin_lock_irq(&lo->lo_lock); |
| filp = lo->lo_backing_file; |
| lo->lo_backing_file = NULL; |
| + lo->block_open_on_autoclear = false; |
| spin_unlock_irq(&lo->lo_lock); |
| |
| lo->lo_device = NULL; |
| -- |
| 2.36.1.255.ge46751e96f-goog |
| |