Skip to content
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

Implement VirtIO RNG device #70

Merged
merged 2 commits into from
Feb 1, 2025
Merged

Conversation

shengwen-tw
Copy link
Collaborator

@shengwen-tw shengwen-tw commented Jan 26, 2025

Overview

This commit introduces the VirtIO entropy device (also know as virtio-rng in QEMU and the Linux kernel) to resolve the blocking issue of arc4random_buf() [1] caused by insufficient entropy of /dev/random.

According to the man page (man 7 random):

The kernel random-number generator relies on entropy gathered from device drivers and other sources of environmental noise to seed a cryptographically secure pseudorandom number generator (CSPRNG).

Interface Pool: /dev/random
Pool: Blocking pool
Blocking behavior: If entropy too low, blocks until there is enough entropy
Behavior when pool is not yet ready: Blocks until enough entropy gathered

Quaoted from https://en.wikipedia.org/wiki//dev/random

With Linux kernel 3.16 and newer, the kernel itself mixes data from hardware random number generators into /dev/random on a sliding scale based on the definable entropy estimation quality of the HWRNG. This means that no userspace daemon, such as rngd from rng-tools, is needed to do that job. With Linux kernel 3.17+, the VirtIO RNG was modified to have a default quality defined above 0, and as such, is currently the only HWRNG mixed into /dev/random by default.

[1] https://elixir.bootlin.com/glibc/glibc-2.36/source/stdlib/arc4random.c

Close #68.

Prerequisites

  1. Enable CONFIG_OD in BusyBox
$ cd buildroot/output/build/busybox-1.36.1/
$ make menuconfig
  1. Rebuild buildroot
$ cd buildroot/
$ make busybox-rebuild
$ make -j$(nproc)
  1. Replace rootfs.cpio
$ cd semu
$ cp -f buildroot/output/images/rootfs.cpio ./

Test procedures

  1. Launch semu:
cd semu/
make check
  1. Check if virtio-rng is used
# cat /sys/class/misc/hw_random/rng_available
virtio_rng.0
# cat /sys/class/misc/hw_random/rng_current
virtio_rng.0
  1. Read /dev/random with od command
Welcome to Buildroot
buildroot login: root
# od /dev/random
0000000 126370 025274 055514 014745 051051 073714 156246 140301
0000020 157561 167176 122602 015767 107243 120045 136313 176061
0000040 115122 170566 107766 011777 057377 105023 152157 147260
0000060 130220 064322 160762 057245 153463 141757 046574 122202
0000100 174113 136630 120230 143307 073562 077302 017507 073016
0000120 062537 012454 100047 114555 140204 040440 172507 075066
0000140 040442 073115 161077 100450 037510 166327 163375 133510
0000160 176100 103667 010651 077154 077252 122605 046415 067073
0000200 042206 016216 101214 106563 161454 053741 016273 031322
0000220 166247 017356 066413 041563 124027 031751 054160 122432
...

Without virtio-rng, the od command will just hang due to the aforementioned issue.

@ChinYikMing
Copy link
Collaborator

Can you upload the newly built rootfs.cpio here for quick testing? Thanks!

@shengwen-tw
Copy link
Collaborator Author

Can you upload the newly built rootfs.cpio here for quick testing? Thanks!

You could try this: rootfs.cpio.zip

Copy link
Collaborator

@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.

Improve the descriptions in git commit messages by quoting the man page for entropy. Also, always use Close #68 instead of Closed #68 to emphasize the intention.

@ChinYikMing
Copy link
Collaborator

I try on machine x86-64, compiled with gcc 12.3.0.

Procedure:

  1. $ make check
  2. login with root
  3. # od /dev/random

Result:

...

[    3.884043] Run /init as init process
Starting syslogd: OK
Starting klogd: OK
Running sysctl: OK
Starting network: OK

Welcome to Buildroot
buildroot login: root 
# od /dev/random



Nothing is output (blocked), is it normal? I think the /dev/random should not be blocked?

@shengwen-tw
Copy link
Collaborator Author

shengwen-tw commented Jan 29, 2025

I try on machine x86-64, compiled with gcc 12.3.0.

Procedure:

  1. $ make check
  2. login with root
  3. # od /dev/random

Result:

...

[    3.884043] Run /init as init process
Starting syslogd: OK
Starting klogd: OK
Running sysctl: OK
Starting network: OK

Welcome to Buildroot
buildroot login: root 
# od /dev/random

Nothing is output (blocked), is it normal? I think the /dev/random should not be blocked?

It should not be blocked, could you check the following commands?

# cat /sys/class/misc/hw_random/rng_available
virtio_rng.0
# cat /sys/class/misc/hw_random/rng_current
virtio_rng.0

@shengwen-tw shengwen-tw force-pushed the virtio-rng branch 5 times, most recently from b5c6511 to c2f267d Compare January 29, 2025 08:12
virtio-rng.c Outdated

void virtio_rng_init(void)
{
rng_fd = open("/dev/urandom", O_RDONLY);
Copy link
Collaborator

Choose a reason for hiding this comment

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

/dev/random is probably going to be sufficient. What are the considerations to use /dev/urandom?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I used /dev/urandom because it does not block. However, this concern may not arise on the host, and adopting /dev/random is indeed more secure.

This commit introduces the VirtIO entropy device (also know as virtio-rng in
QEMU and the Linux kernel) to resolve the blocking issue of arc4random_buf()
[1] caused by insufficient entropy of /dev/random.

According to the man page (`man 7 random`):

The kernel random-number generator relies on entropy gathered from device
drivers and other sources of environmental noise to seed a cryptographically
secure pseudorandom number generator (CSPRNG).

Interface Pool: /dev/random
Pool: Blocking pool
Blocking behavior: If entropy too low, blocks until there is enough entropy
Behavior when pool is not yet ready: Blocks until enough entropy gathered

Quaoted from https://en.wikipedia.org/wiki//dev/random

With Linux kernel 3.16 and newer, the kernel itself mixes data from hardware
random number generators into /dev/random on a sliding scale based on the
definable entropy estimation quality of the HWRNG. This means that no userspace
daemon, such as rngd from rng-tools, is needed to do that job. With Linux
kernel 3.17+, the VirtIO RNG was modified to have a default quality defined
above 0, and as such, is currently the only HWRNG mixed into /dev/random by
default.

[1] https://elixir.bootlin.com/glibc/glibc-2.36/source/stdlib/arc4random.c

Close sysprog21#68.
@ChinYikMing
Copy link
Collaborator

I try on machine x86-64, compiled with gcc 12.3.0.
Procedure:

  1. $ make check
  2. login with root
  3. # od /dev/random

Result:

...

[    3.884043] Run /init as init process
Starting syslogd: OK
Starting klogd: OK
Running sysctl: OK
Starting network: OK

Welcome to Buildroot
buildroot login: root 
# od /dev/random

Nothing is output (blocked), is it normal? I think the /dev/random should not be blocked?

It should not be blocked, could you check the following commands?

# cat /sys/class/misc/hw_random/rng_available
virtio_rng.0
# cat /sys/class/misc/hw_random/rng_current
virtio_rng.0

I get the following output:

# cat /sys/class/misc/hw_random/rng_available
cat: can't open '/sys/class/misc/hw_random/rng_available': No such file or directory

I noticed that the Linux kernel needs to enable the virtio-rng driver to facilitate communication in this scenario (enabled in the proposed changes of Linux configuration). Could you also upload the virtio-rng enabled Linux kernel image along with the rootfs.cpio?

@shengwen-tw
Copy link
Collaborator Author

I noticed that the Linux kernel needs to enable the virtio-rng driver to facilitate communication in this scenario (enabled in the proposed changes of Linux configuration). Could you also upload the virtio-rng enabled Linux kernel image along with the rootfs.cpio?

Here you go: Image.zip

@ChinYikMing
Copy link
Collaborator

Using newly built Linux kernel, the od /dev/random has no more blocking.

@ChinYikMing
Copy link
Collaborator

BTW, I used the newly built rootfs.cpio within rv32emu which does not implement the VirtIO RNG device and it does not block the /dev/random by running od /dev/random. @shengwen-tw Do you have any idea with this?

/* Write entropy buffer */
void *entropy_buf =
(void *) ((uintptr_t) vrng->ram + (uintptr_t) vq_desc.addr);
ssize_t total = read(rng_fd, entropy_buf, vq_desc.len);
Copy link
Collaborator

Choose a reason for hiding this comment

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

read could fail. Please handle the return value.

Copy link
Collaborator Author

@shengwen-tw shengwen-tw Jan 31, 2025

Choose a reason for hiding this comment

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

According to man 4 random:

When the entropy pool is empty, reads from /dev/random will block until additional environmental noise is gathered.

Calling read() function on /dev/random can only return -1 (i.e., failed) if O_NONBLOCK flag is set when opening the device. Specifically:

If open(2) is called for /dev/random with the O_NONBLOCK flag, a subsequent read(2) will not block if the requested number of bytes is not available. Instead, the available bytes are returned. If no byte is available, read(2) will return -1 and errno will be set to EAGAIN.

@shengwen-tw
Copy link
Collaborator Author

BTW, I used the newly built rootfs.cpio within rv32emu which does not implement the VirtIO RNG device and it does not block the /dev/random by running od /dev/random. @shengwen-tw Do you have any idea with this?

Entropy collection can be influenced by the speed of the hardware or the emulated environment.
I believe that rv32emu is currently fast enough to prevent blocking. However, it is always nice to have entropy supplied by the host.

@jserv jserv merged commit 50fbf07 into sysprog21:master Feb 1, 2025
3 checks passed
@jserv
Copy link
Collaborator

jserv commented Feb 1, 2025

Thank @shengwen-tw for contributing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

VirtIO RNG and unexpected behavior of arc4random_buf() standard function of C
3 participants