Skip to content

Support readonly feature of VirtIO block device #584

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 17, 2025

Conversation

ChinYikMing
Copy link
Collaborator

@ChinYikMing ChinYikMing commented Mar 12, 2025

Why?

Enhances the security of the VirtIO block device by preventing unintended data corruption in the guest OS when accessing critical data.

Test

  1. Clone the repo:
$ git clone https://github.com/ChinYikMing/rv32emu.git -b virtio-blk-readonly --depth 1 && cd rv32emu
  1. Get the prebuilt images and build:
$ make ENABLE_SYSTEM=1 INITRD_SIZE=32 -j100 && make ENABLE_SYSTEM=1 artifact
  1. Prepare disk image:

macOS:

# Might need to install file system utility
$ brew install e2fsprogs

# Create a disk image
$ dd if=/dev/zero of=disk.img bs=4M count=32
$ $(brew --prefix e2fsprogs)/sbin/mkfs.ext4 disk.img

Linux

# Create a disk image
$ dd if=/dev/zero of=disk.img bs=4M count=32
$ mkfs.ext4 disk.img
  1. Check the kernel boot log which should have something as the following:
$ build/rv32emu -k build/linux-image/Image -i build/linux-image/rootfs.cpio -x vblk:disk.img,readonly

Might see something similar:

...
...
[    0.583109] virtio_blk virtio0: 1/0/0 default/read/poll queues
[    0.584873] virtio_blk virtio0: [vda] 262144 512-byte logical blocks (134 MB/128 MiB)
...
...
  1. Mount the virtio block device:
# mkdir mnt
# mount /dev/vda mnt

Might see something similar:

[   37.134323] /dev/vda: Can't open blockdev
[   37.135211] /dev/vda: Can't open blockdev
[   37.136593] EXT4-fs (vda): INFO: recovery required on readonly filesystem
[   37.136804] EXT4-fs (vda): write access unavailable, cannot proceed (try mounting with noload)
mount: mounting /dev/vda on mnt failed: Read-only file system

For ext4 image, to maintain the consistency of the file system, the ext4 does the journal replay (which is failed by this error log: "recovery required on readonly filesystem) and mount command default use read and write permission. Thus, it has to mount with noload option.

  1. Remount the virtio block device and manipulate the device:
# mount -o noload /dev/vda mnt

Try to create a file which should fail on readonly mounted device:

# touch mnt/apple
touch: mnt/apple: Read-only file system

Summary by Bito

This pull request introduces a readonly feature for the VirtIO block device, enhancing security by preventing unintended data corruption. Key changes include a readonly flag during initialization, updated function signatures, and improved command line options for usability.

Unit tests added: False

Estimated effort to review (1-5, lower is better): 2

Copy link
Contributor

@jserv jserv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmarks

Benchmark suite Current: c9e2b5f Previous: b26e7fc Ratio
Dhrystone 1274 Average DMIPS over 10 runs 1311 Average DMIPS over 10 runs 1.03
Coremark 913.979 Average iterations/sec over 10 runs 920.165 Average iterations/sec over 10 runs 1.01

This comment was automatically generated by workflow using github-action-benchmark.

@ChinYikMing ChinYikMing force-pushed the virtio-blk-readonly branch 2 times, most recently from 7beced0 to d34087d Compare March 13, 2025 05:46
@ChinYikMing ChinYikMing requested a review from jserv March 15, 2025 05:45
@jserv
Copy link
Contributor

jserv commented Mar 15, 2025

I would like to ask @otteryc for reviewing.

@jserv jserv requested a review from vacantron March 15, 2025 05:59
src/riscv.c Outdated
/* Currently, only used for block image path and permission */
#define MAX_OPTS 2
char *vblk_opts[MAX_OPTS];
memset(vblk_opts, 0, sizeof(char *[MAX_OPTS]));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace sizeof(char *[MAX_OPTS]) with ARRAY_SIZE.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace sizeof(char *[MAX_OPTS]) with ARRAY_SIZE.

ARRAY_SIZE gets the element count in an array but it does not know the size of each element. To use it, it should be used like this: ARRAY_SIZE(vblk_opts) * sizeof(vblk_opts[0]).

Thus, for more shorter, I would go with "partial Initialization" which would initialize the rest of the element to 0 by declaring the vblk_opts as char *vblk_opts[MAX_OPTS] = {NULL}.

@ChinYikMing ChinYikMing force-pushed the virtio-blk-readonly branch from d34087d to b26e7fc Compare March 16, 2025 08:53
Copy link
Contributor

@otteryc otteryc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!
Please consider:

  1. Refine the corresponding statements in README.md for clarity.
  2. Fix the device_features_sel error also in semu as well.

Add support for comma-separated options for VirtIO devices. For the
readonly option, if the string readonly is specified, subsequent VirtIO
block device access will be read-only; otherwise, the default behavior
is read and write. To implement this, a device_features field is
introduced to store device features during initialization.
VIRTIO_BLK_F_RO is the feature bit to enable readonly.

This feature enhances the security of the VirtIO block device by
preventing unintended data corruption in the guest OS when accessing
critical data.

Additionally, after implementing the VirtIO block device in sysprog21#539, some
register access errors were shown and they are fixed in this commit:
- reading from the VirtIO DeviceFeatures register now correctly checks
  the device_features_sel instead of driver_features_sel.
- writing to the VirtIO DeviceFeaturesSel register now correctly updates
  device_features_sel instead of driver_features_sel.
@ChinYikMing ChinYikMing force-pushed the virtio-blk-readonly branch from b26e7fc to c9e2b5f Compare March 16, 2025 09:10
@jserv jserv merged commit 885c378 into sysprog21:master Mar 17, 2025
10 checks passed
@jserv
Copy link
Contributor

jserv commented Mar 17, 2025

Thank @ChinYikMing for contributing!

@ChinYikMing ChinYikMing deleted the virtio-blk-readonly branch March 17, 2025 02:01
ChinYikMing added a commit to ChinYikMing/rv32emu that referenced this pull request Mar 18, 2025
PR sysprog21#584 initializes the vblk only when the vblk CLI option is provided.
This leads to a segmentation fault when vblk is not specified, as the
capacity of the vblk device is left uninitialized (not set to 0).
Previously, the code would always initialize vblk but set its capacity
to 0, preventing the VirtIO block driver from interacting with it and
avoiding the segmentation fault. However, this original approach was
functionally redundant.

A better solution is to dynamically load or unload the VirtIO node in
the SoC node of the Device Tree based on configuration. To support
future others VirtIO devices, the interface of load_dtb() has been
refined, it now can parse all options stored in the attribute.
ChinYikMing added a commit to ChinYikMing/rv32emu that referenced this pull request Mar 18, 2025
PR sysprog21#584 initializes the vblk only when the vblk CLI option is provided.
This leads to a segmentation fault when vblk is not specified, as the
capacity of the vblk device is left uninitialized (not set to 0).
Previously, the code would always initialize vblk but set its capacity
to 0, preventing the VirtIO block driver from interacting with it and
avoiding the segmentation fault. However, this original approach was
functionally redundant.

A better solution is to dynamically load or unload the VirtIO node in
the SoC node of the Device Tree based on configuration. To support
future others VirtIO devices, the interface of load_dtb() has been
refined, it now can parse all options stored in the attribute.
@jserv jserv added this to the release-2025.1 milestone Mar 19, 2025
ChinYikMing added a commit to ChinYikMing/rv32emu that referenced this pull request Mar 20, 2025
PR sysprog21#584 initializes the vblk only when the vblk CLI option is provided.
This leads to a segmentation fault when vblk is not specified, as the
capacity of the vblk device is left uninitialized (not set to 0).
Previously, the code would always initialize vblk but set its capacity
to 0, preventing the VirtIO block driver from interacting with it and
avoiding the segmentation fault. However, this original approach was
functionally redundant.

A better solution is to dynamically load or unload the VirtIO node in
the SoC node of the Device Tree based on configuration. To support
future others VirtIO devices, the interface of load_dtb() has been
refined, it now can parse all options stored in the attribute.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants