[Pkg-rust-maintainers] Bug#1109421: unblock: rust-virtiofsd/1.13.2-1
Michael Tokarev
mjt at tls.msk.ru
Thu Jul 17 11:00:26 BST 2025
Package: release.debian.org
Severity: normal
X-Debbugs-Cc: rust-virtiofsd at packages.debian.org, pkg-qemu-devel at lists.alioth.debian.org
Control: affects -1 + src:rust-virtiofsd
User: release.debian.org at packages.debian.org
Usertags: unblock
Please unblock package rust-virtiofsd
[ Reason ]
There's a new upstream minor/bugfix release of virtiofsd,
fixing a number of bugs/omissions in previous releases and
adding some docs.
In particular, it adds some docs about how to use virtiofsd
as non-privileged user, which is a confusing topic for some
users.
[ Tests ]
This release passes all debian automatic tests (there are
quite some now), and my internal usage testing too, showing
no regressions.
[ Risks ]
The changes in this (upstream) version are rather small and
focused. I don't expect much risk in this case.
[ Checklist ]
[?] all changes are documented in the d/changelog
[x] I reviewed all changes and I approve them
[x] attach debdiff against the package in testing
[ Other info ]
Maybe I should've add this info to d/changelog directly (our
rust tooling in debian fills d/changelog automatically). Here's
the actual set of upstream changes:
* v1.13.2:
- https://gitlab.com/virtio-fs/virtiofsd/-/merge_requests/286
Call setgroups syscall directly
- https://gitlab.com/virtio-fs/virtiofsd/-/merge_requests/285
README.md: expand section on non-privileged running
- https://gitlab.com/virtio-fs/virtiofsd/-/merge_requests/282
Fix/silence new clippy warnings
- https://gitlab.com/virtio-fs/virtiofsd/-/merge_requests/278
Fix new clippy warning(s)/CI
- https://gitlab.com/virtio-fs/virtiofsd/-/merge_requests/277
Document root-less usage using util-linux's unshare
- https://gitlab.com/virtio-fs/virtiofsd/-/merge_requests/262
Limit guest FD allocation
* v1.13.1:
- https://gitlab.com/virtio-fs/virtiofsd/-/merge_requests/275
Enable --xattr when --security-label is used
- https://gitlab.com/virtio-fs/virtiofsd/-/merge_requests/274
seccomp: Allow tkill syscall
- https://gitlab.com/virtio-fs/virtiofsd/-/merge_requests/273
CI: Disable clippy::manual-c-str-literals warning
Unfortunately this is just in upstream commit messages, not
in any README/NEWS files, and sort of difficult to find.
Either way, the changes do look fine (each of them).
If this package isn't unblocked before trixie release, I'll
be filing a s-p-u bug request with this package (maybe after
adding the missing d/changelog info from the above).
unblock rust-virtiofsd/1.13.2-1
The debdiff follows.
Thanks,
/mjt
diff -Nru rust-virtiofsd-1.13.0/.cargo_vcs_info.json rust-virtiofsd-1.13.2/.cargo_vcs_info.json
--- rust-virtiofsd-1.13.0/.cargo_vcs_info.json 1970-01-01 03:00:01.000000000 +0300
+++ rust-virtiofsd-1.13.2/.cargo_vcs_info.json 1970-01-01 03:00:01.000000000 +0300
@@ -1,6 +1,6 @@
{
"git": {
- "sha1": "3bf77b7cfa42b23935968c757a4f22ed31bc35d6"
+ "sha1": "720245d0857e9837484488ff69c2f8c577466851"
},
"path_in_vcs": ""
}
\ No newline at end of file
diff -Nru rust-virtiofsd-1.13.0/Cargo.lock rust-virtiofsd-1.13.2/Cargo.lock
--- rust-virtiofsd-1.13.0/Cargo.lock 1970-01-01 03:00:01.000000000 +0300
+++ rust-virtiofsd-1.13.2/Cargo.lock 1970-01-01 03:00:01.000000000 +0300
@@ -875,7 +875,7 @@
[[package]]
name = "virtiofsd"
-version = "1.13.0"
+version = "1.13.2"
dependencies = [
"bitflags 1.3.2",
"btree-range-map",
diff -Nru rust-virtiofsd-1.13.0/Cargo.toml rust-virtiofsd-1.13.2/Cargo.toml
--- rust-virtiofsd-1.13.0/Cargo.toml 1970-01-01 03:00:01.000000000 +0300
+++ rust-virtiofsd-1.13.2/Cargo.toml 1970-01-01 03:00:01.000000000 +0300
@@ -12,10 +12,11 @@
[package]
edition = "2018"
name = "virtiofsd"
-version = "1.13.0"
+version = "1.13.2"
authors = ["The Virtiofs Project Developers"]
build = false
exclude = [".gitlab-ci.yml"]
+autolib = false
autobins = false
autoexamples = false
autotests = false
@@ -26,8 +27,14 @@
license = "Apache-2.0 AND BSD-3-Clause"
repository = "https://gitlab.com/virtio-fs/virtiofsd"
-[profile.release]
-lto = true
+[features]
+default = ["seccomp"]
+seccomp = ["dep:libseccomp-sys"]
+xen = [
+ "vhost-user-backend/xen",
+ "vhost/xen",
+ "vm-memory/xen",
+]
[lib]
name = "virtiofsd"
@@ -101,11 +108,5 @@
[dependencies.vmm-sys-util]
version = "0.12.1"
-[features]
-default = ["seccomp"]
-seccomp = ["dep:libseccomp-sys"]
-xen = [
- "vhost-user-backend/xen",
- "vhost/xen",
- "vm-memory/xen",
-]
+[profile.release]
+lto = true
diff -Nru rust-virtiofsd-1.13.0/Cargo.toml.orig rust-virtiofsd-1.13.2/Cargo.toml.orig
--- rust-virtiofsd-1.13.0/Cargo.toml.orig 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/Cargo.toml.orig 2006-07-24 05:21:28.000000000 +0400
@@ -1,7 +1,7 @@
[package]
name = "virtiofsd"
description = "A virtio-fs vhost-user device daemon"
-version = "1.13.0"
+version = "1.13.2"
authors = ["The Virtiofs Project Developers"]
edition = "2018"
homepage = "https://virtio-fs.gitlab.io/"
diff -Nru rust-virtiofsd-1.13.0/README.md rust-virtiofsd-1.13.2/README.md
--- rust-virtiofsd-1.13.0/README.md 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/README.md 2006-07-24 05:21:28.000000000 +0400
@@ -145,7 +145,7 @@
```shell
--security-label
```
-Enable support for security label (SELinux).
+Enable support for security label (SELinux). Implies --xattr.
```shell
--preserve-noatime
@@ -512,12 +512,27 @@
See [FAQ](#faq) for adding virtiofs config to an existing qemu command-line.
### Running as non-privileged user
-When run without root, virtiofsd requires a user namespace (see `user_namespaces(7)`)
-to be able to switch between arbitrary user/group IDs within the guest.
-virtiofsd will fail in a user namespace where UIDs/GIDs have not been mapped
-(i.e., `uid_map` and `gid_map` files have not been written).
-There are many options to run virtiofsd inside a user namespace.
-For instance:
+
+virtiofsd can be run as a non-privileged user without a sandbox. If
+you take care to ensure the UID/GID used in the guest matches the
+effective UID of virtiofsd on the host you will be able to mount your
+host $HOME into the guest and use it transparently.
+
+If the UID/GID on the guest is different from the host but you only
+expect a single user to be accessing files you can use
+`--translate-uid` to map it to the host UID:
+
+```shell
+--translate-uid=map:<guest UID>:<host UID>:1
+```
+
+with a similar mapping for `--translate-gid`.
+
+If you want to support multiple user/group IDs within the guest, you
+can use subordinate UIDs/GIDs (subuids/subgids) that virtiofsd can
+then use despite not running as root. There are many options to employ
+a user namespace to map those subuids/subgids for virtiofsd to use for
+the guest, for instance:
Let's assume the invoking UID and GID is 1000 and the content of both `/etc/subuid`
and `/etc/subgid` are:
@@ -534,6 +549,13 @@
host$ podman unshare -- virtiofsd --socket-path=/tmp/vfsd.sock --shared-dir /mnt \
--announce-submounts --sandbox chroot &
```
+Alternatively we can also achieve the same effect without Podman by relying on `unshare(1)` included in
+`util-linux` which has the benefit that it should already be installed for most users. Use it like so:
+
+```shell
+host$ unshare -r --map-auto -- virtiofsd --socket-path=/tmp/vfsd.sock --shared-dir /mnt \
+ --announce-submounts --sandbox chroot &
+```
Using `lxc-usernsexec(1)`, we could leave the invoking user outside the mapping, having
the root user inside the user namespace mapped to the user and group 100000:
diff -Nru rust-virtiofsd-1.13.0/debian/changelog rust-virtiofsd-1.13.2/debian/changelog
--- rust-virtiofsd-1.13.0/debian/changelog 2025-01-31 14:10:04.000000000 +0300
+++ rust-virtiofsd-1.13.2/debian/changelog 2025-07-10 20:02:47.000000000 +0300
@@ -1,3 +1,9 @@
+rust-virtiofsd (1.13.2-1) unstable; urgency=medium
+
+ * Package virtiofsd 1.13.2 from crates.io using debcargo 2.7.8
+
+ -- Michael Tokarev <mjt at tls.msk.ru> Thu, 10 Jul 2025 20:02:47 +0300
+
rust-virtiofsd (1.13.0-5) unstable; urgency=medium
[ Luca Boccassi ]
diff -Nru rust-virtiofsd-1.13.0/debian/control rust-virtiofsd-1.13.2/debian/control
--- rust-virtiofsd-1.13.0/debian/control 2025-01-31 14:10:04.000000000 +0300
+++ rust-virtiofsd-1.13.2/debian/control 2025-07-10 20:02:47.000000000 +0300
@@ -3,7 +3,8 @@
Priority: optional
Build-Depends: debhelper-compat (= 13),
dh-sequence-cargo,
- cargo:native,
+ architecture-is-64-bit
+Build-Depends-Arch: cargo:native,
rustc:native,
libstd-rust-dev,
librust-bitflags-1+default-dev (>= 1.2-~~),
@@ -30,8 +31,7 @@
librust-vm-memory-0.16+backend-atomic-dev,
librust-vm-memory-0.16+backend-mmap-dev,
librust-vm-memory-0.16+default-dev,
- librust-vmm-sys-util-0.12+default-dev (>= 0.12.1-~~),
- architecture-is-64-bit
+ librust-vmm-sys-util-0.12+default-dev (>= 0.12.1-~~)
Maintainer: Debian Rust Maintainers <pkg-rust-maintainers at alioth-lists.debian.net>
Uploaders:
Fabian Grünbichler <debian at fabian.gruenbichler.email>,
@@ -88,16 +88,15 @@
librust-virtiofsd-1.13+default-dev (= ${binary:Version}),
librust-virtiofsd-1.13+seccomp-dev (= ${binary:Version}),
librust-virtiofsd-1.13+xen-dev (= ${binary:Version}),
- librust-virtiofsd-1.13.0-dev (= ${binary:Version}),
- librust-virtiofsd-1.13.0+default-dev (= ${binary:Version}),
- librust-virtiofsd-1.13.0+seccomp-dev (= ${binary:Version}),
- librust-virtiofsd-1.13.0+xen-dev (= ${binary:Version})
+ librust-virtiofsd-1.13.2-dev (= ${binary:Version}),
+ librust-virtiofsd-1.13.2+default-dev (= ${binary:Version}),
+ librust-virtiofsd-1.13.2+seccomp-dev (= ${binary:Version}),
+ librust-virtiofsd-1.13.2+xen-dev (= ${binary:Version})
Description: Virtio-fs vhost-user device daemon - Rust source code
Source code for Debianized Rust crate "virtiofsd"
Package: virtiofsd
Architecture: any
-Multi-Arch: allowed
Section: otherosfs
Depends:
${misc:Depends},
diff -Nru rust-virtiofsd-1.13.0/debian/copyright rust-virtiofsd-1.13.2/debian/copyright
--- rust-virtiofsd-1.13.0/debian/copyright 2025-01-31 14:10:04.000000000 +0300
+++ rust-virtiofsd-1.13.2/debian/copyright 2025-07-10 20:02:47.000000000 +0300
@@ -37,6 +37,7 @@
src/passthrough/device_state/serialization.rs
src/passthrough/device_state/serialized.rs
src/passthrough/file_handle.rs
+ src/passthrough/guest_fd_limit.rs
src/passthrough/read_only.rs
src/passthrough/stat.rs
src/sandbox.rs
diff -Nru rust-virtiofsd-1.13.0/debian/copyright.debcargo.hint rust-virtiofsd-1.13.2/debian/copyright.debcargo.hint
--- rust-virtiofsd-1.13.0/debian/copyright.debcargo.hint 2025-01-31 14:10:04.000000000 +0300
+++ rust-virtiofsd-1.13.2/debian/copyright.debcargo.hint 2025-07-10 20:02:47.000000000 +0300
@@ -131,6 +131,13 @@
FIXME (overlay): These notices are extracted from files. Please review them
before uploading to the archive.
+Files: src/passthrough/guest_fd_limit.rs
+Copyright: 2024 Red Hat, Inc. All rights reserved.
+License: UNKNOWN-LICENSE; FIXME (overlay)
+Comment:
+ FIXME (overlay): These notices are extracted from files. Please review them
+ before uploading to the archive.
+
Files: src/passthrough/mod.rs
Copyright: 2019 The Chromium OS Authors. All rights reserved.
License: UNKNOWN-LICENSE; FIXME (overlay)
diff -Nru rust-virtiofsd-1.13.0/debian/tests/control rust-virtiofsd-1.13.2/debian/tests/control
--- rust-virtiofsd-1.13.0/debian/tests/control 2025-01-31 14:10:04.000000000 +0300
+++ rust-virtiofsd-1.13.2/debian/tests/control 2025-07-10 20:02:47.000000000 +0300
@@ -1,24 +1,24 @@
-Test-Command: /usr/share/cargo/bin/cargo-auto-test virtiofsd 1.13.0 --all-targets --all-features
+Test-Command: /usr/share/cargo/bin/cargo-auto-test virtiofsd 1.13.2 --all-targets --all-features
Features: test-name=rust-virtiofsd:@
Depends: dh-cargo (>= 31), rustc, @
Restrictions: allow-stderr, skip-not-installable
-Test-Command: /usr/share/cargo/bin/cargo-auto-test virtiofsd 1.13.0 --all-targets
+Test-Command: /usr/share/cargo/bin/cargo-auto-test virtiofsd 1.13.2 --all-targets
Features: test-name=librust-virtiofsd-dev:default
Depends: dh-cargo (>= 31), rustc, @
Restrictions: allow-stderr, skip-not-installable
-Test-Command: /usr/share/cargo/bin/cargo-auto-test virtiofsd 1.13.0 --all-targets --no-default-features --features seccomp
+Test-Command: /usr/share/cargo/bin/cargo-auto-test virtiofsd 1.13.2 --all-targets --no-default-features --features seccomp
Features: test-name=librust-virtiofsd-dev:seccomp
Depends: dh-cargo (>= 31), rustc, @
Restrictions: allow-stderr, skip-not-installable
-Test-Command: /usr/share/cargo/bin/cargo-auto-test virtiofsd 1.13.0 --all-targets --no-default-features --features xen
+Test-Command: /usr/share/cargo/bin/cargo-auto-test virtiofsd 1.13.2 --all-targets --no-default-features --features xen
Features: test-name=librust-virtiofsd-dev:xen
Depends: dh-cargo (>= 31), rustc, @
Restrictions: allow-stderr, skip-not-installable
-Test-Command: /usr/share/cargo/bin/cargo-auto-test virtiofsd 1.13.0 --all-targets --no-default-features
+Test-Command: /usr/share/cargo/bin/cargo-auto-test virtiofsd 1.13.2 --all-targets --no-default-features
Features: test-name=librust-virtiofsd-dev:
Depends: dh-cargo (>= 31), rustc, @
Restrictions: allow-stderr, skip-not-installable
diff -Nru rust-virtiofsd-1.13.0/debian/tests/control.debcargo.hint rust-virtiofsd-1.13.2/debian/tests/control.debcargo.hint
--- rust-virtiofsd-1.13.0/debian/tests/control.debcargo.hint 2025-01-31 14:10:04.000000000 +0300
+++ rust-virtiofsd-1.13.2/debian/tests/control.debcargo.hint 2025-07-10 20:02:47.000000000 +0300
@@ -1,24 +1,24 @@
-Test-Command: /usr/share/cargo/bin/cargo-auto-test virtiofsd 1.13.0 --all-targets --all-features
+Test-Command: /usr/share/cargo/bin/cargo-auto-test virtiofsd 1.13.2 --all-targets --all-features
Features: test-name=rust-virtiofsd:@
Depends: dh-cargo (>= 31), rustc, @
Restrictions: allow-stderr, skip-not-installable
-Test-Command: /usr/share/cargo/bin/cargo-auto-test virtiofsd 1.13.0 --all-targets
+Test-Command: /usr/share/cargo/bin/cargo-auto-test virtiofsd 1.13.2 --all-targets
Features: test-name=librust-virtiofsd-dev:default
Depends: dh-cargo (>= 31), rustc, @
Restrictions: allow-stderr, skip-not-installable
-Test-Command: /usr/share/cargo/bin/cargo-auto-test virtiofsd 1.13.0 --all-targets --no-default-features --features seccomp
+Test-Command: /usr/share/cargo/bin/cargo-auto-test virtiofsd 1.13.2 --all-targets --no-default-features --features seccomp
Features: test-name=librust-virtiofsd-dev:seccomp
Depends: dh-cargo (>= 31), rustc, @
Restrictions: allow-stderr, skip-not-installable
-Test-Command: /usr/share/cargo/bin/cargo-auto-test virtiofsd 1.13.0 --all-targets --no-default-features --features xen
+Test-Command: /usr/share/cargo/bin/cargo-auto-test virtiofsd 1.13.2 --all-targets --no-default-features --features xen
Features: test-name=librust-virtiofsd-dev:xen
Depends: dh-cargo (>= 31), rustc, @
Restrictions: allow-stderr, skip-not-installable
-Test-Command: /usr/share/cargo/bin/cargo-auto-test virtiofsd 1.13.0 --all-targets --no-default-features
+Test-Command: /usr/share/cargo/bin/cargo-auto-test virtiofsd 1.13.2 --all-targets --no-default-features
Features: test-name=librust-virtiofsd-dev:
Depends: dh-cargo (>= 31), rustc, @
Restrictions: allow-stderr, skip-not-installable
diff -Nru rust-virtiofsd-1.13.0/src/idmap.rs rust-virtiofsd-1.13.2/src/idmap.rs
--- rust-virtiofsd-1.13.0/src/idmap.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/idmap.rs 2006-07-24 05:21:28.000000000 +0400
@@ -26,7 +26,7 @@
f,
"The map is empty or incorrect number of values are provided"
),
- IdMapError::InvalidValue(err) => write!(f, "{}", err),
+ IdMapError::InvalidValue(err) => write!(f, "{err}"),
}
}
}
diff -Nru rust-virtiofsd-1.13.0/src/limits.rs rust-virtiofsd-1.13.2/src/limits.rs
--- rust-virtiofsd-1.13.0/src/limits.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/limits.rs 2006-07-24 05:21:28.000000000 +0400
@@ -46,18 +46,19 @@
}
}
-pub fn setup_rlimit_nofile(nofile: Option<u64>) -> Result<(), String> {
+/// Set the limit of open files to the given value, returning the actual limit.
+pub fn setup_rlimit_nofile(nofile: Option<u64>) -> Result<u64, String> {
let max_nofile = get_max_nofile()?;
let rlimit { rlim_cur, rlim_max } = get_nofile_limits()?;
let target_limit = if let Some(nofile) = nofile {
if nofile == 0 {
- return Ok(()); // '--rlimit-nofile=0' leaves the resource limit unchanged
+ return Ok(rlim_cur); // '--rlimit-nofile=0' leaves the resource limit unchanged
}
nofile
} else {
if DEFAULT_NOFILE <= rlim_cur {
- return Ok(()); // the user has already setup the soft limit higher than the target
+ return Ok(rlim_cur); // the user has already setup the soft limit higher than the target
}
cmp::min(DEFAULT_NOFILE, max_nofile)
};
@@ -66,21 +67,23 @@
return Err(format!("It cannot be increased above {max_nofile}"));
}
- if let Err(error) = setup_rlimit_nofile_to(target_limit) {
+ let new_limit = if let Err(error) = setup_rlimit_nofile_to(target_limit) {
if nofile.is_some() {
// Error attempting to setup user-supplied value
return Err(error);
} else {
warn!(
- "Failure when trying to set the limit to {}, \
- the hard limit ({}) of open file descriptors is used instead.",
- target_limit, rlim_max
+ "Failure when trying to set the limit to {target_limit}, \
+ the hard limit ({rlim_max}) of open file descriptors is used instead."
);
setup_rlimit_nofile_to(rlim_max).map_err(|error| {
format!("Cannot increase the soft limit to the hard limit: {error}")
- })?
+ })?;
+ rlim_max
}
- }
+ } else {
+ target_limit
+ };
- Ok(())
+ Ok(new_limit)
}
diff -Nru rust-virtiofsd-1.13.0/src/main.rs rust-virtiofsd-1.13.2/src/main.rs
--- rust-virtiofsd-1.13.0/src/main.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/main.rs 2006-07-24 05:21:28.000000000 +0400
@@ -12,7 +12,7 @@
use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration;
-use std::{env, process};
+use std::{cmp, env, process};
use virtiofsd::idmap::{GidMap, UidMap};
use clap::{CommandFactory, Parser};
@@ -33,6 +33,23 @@
use virtiofsd::{limits, oslib, soft_idmap};
use vm_memory::{GuestMemoryAtomic, GuestMemoryMmap};
+/// Maximum number of memory areas (slots) supported by the vhost-user-backend crate.
+///
+/// The constant has the same name there, but is not exported.
+const MAX_MEM_SLOTS: u64 = 509;
+
+/// How many file descriptors to reserve for internal use.
+///
+/// The exact value has been chosen mostly arbitrarily, but we know we need one FD per shared
+/// memory area, which is where the `MAX_MEM_SLOTS` comes from.
+///
+/// Given how allocating FD towards the guest quota works, we also need to add one FD per thread in
+/// our pool: FDs are created first, and only then accounted for. All threads must be able to
+/// simultaneously create an FD and then have it be accounted for, so we need to make room for as
+/// many additional FDs as there are threads in the pool. The thread pool size is set at runtime,
+/// though, so cannot be taken into account here, but instead where this constant is used.
+const INTERNAL_FD_RESERVE: u64 = MAX_MEM_SLOTS + 100;
+
type Result<T> = std::result::Result<T, Error>;
fn parse_seccomp(src: &str) -> std::result::Result<SeccompAction, &'static str> {
@@ -254,7 +271,7 @@
#[arg(short = 'f')]
compat_foreground: bool,
- /// Enable security label support. Expects SELinux xattr on file creation
+ /// Enable security label support (implies --xattr). Expects SELinux xattr on file creation
/// from client and stores it in the newly created file.
#[arg(long = "security-label")]
security_label: bool,
@@ -349,10 +366,10 @@
/// different ways:
///
/// - abort: Whenever any error occurs, return a hard error to the vhost-user front-end (e.g.
- /// QEMU), aborting migration.
+ /// QEMU), aborting migration.
///
/// - guest-error: Let migration finish, but the guest will be unable to access any of the
- /// affected inodes, receiving only errors.
+ /// affected inodes, receiving only errors.
///
/// This parameter is ignored on the source side.
#[arg(long = "migration-on-error", default_value = "abort")]
@@ -514,7 +531,7 @@
if opt.syslog {
if let Err(e) = syslog::init(syslog::Facility::LOG_USER, log_level, None) {
set_default_logger(log_level);
- warn!("can't enable syslog: {}", e);
+ warn!("can't enable syslog: {e}");
}
} else {
set_default_logger(log_level);
@@ -530,7 +547,7 @@
let signals = vec![libc::SIGHUP, libc::SIGTERM];
for s in signals {
if let Err(e) = signal::register_signal_handler(s, handle_signal) {
- error!("Setting signal handlers: {}", e);
+ error!("Setting signal handlers: {e}");
process::exit(1);
}
}
@@ -552,14 +569,11 @@
let (action, cap_name) = modcap.split_at(1);
let cap_name = cap_name.to_uppercase();
if !matches!(action, "+" | "-") {
- error!(
- "invalid modcap action: expecting '+'|'-' but found '{}'",
- action
- );
+ error!("invalid modcap action: expecting '+'|'-' but found '{action}'");
process::exit(1);
}
if let Err(error) = capng::name_to_capability(&cap_name) {
- error!("invalid capability '{}': {}", &cap_name, error);
+ error!("invalid capability '{cap_name}': {error}");
process::exit(1);
}
@@ -595,10 +609,7 @@
if inode_file_handles != InodeFileHandlesMode::Never {
let required_cap = "DAC_READ_SEARCH".to_owned();
if disabled_caps.contains(&required_cap) {
- error!(
- "can't disable {} when using --inode-file-handles={:?}",
- &required_cap, inode_file_handles
- );
+ error!("can't disable {required_cap} when using --inode-file-handles={inode_file_handles:?}");
process::exit(1);
}
required_caps.insert(required_cap);
@@ -612,11 +623,11 @@
capng::Type::PERMITTED | capng::Type::EFFECTIVE,
required_caps.iter().map(String::as_str).collect(),
) {
- error!("can't set up the child capabilities: {}", e);
+ error!("can't set up the child capabilities: {e}");
process::exit(1);
}
if let Err(e) = capng::apply(capng::Set::BOTH) {
- error!("can't apply the child capabilities: {}", e);
+ error!("can't apply the child capabilities: {e}");
process::exit(1);
}
}
@@ -684,7 +695,7 @@
}
let xattrmap = opt.xattrmap.clone();
- let xattr = xattrmap.is_some() || opt.posix_acl || opt.xattr;
+ let xattr = xattrmap.is_some() || opt.posix_acl || opt.security_label || opt.xattr;
let thread_pool_size = opt.thread_pool_size;
let readdirplus = match opt.cache {
CachePolicy::Never => false,
@@ -738,12 +749,12 @@
let pid_file_name = socket.to_owned() + ".pid";
let pid_file_path = Path::new(pid_file_name.as_str());
let pid_file = write_pid_file(pid_file_path).unwrap_or_else(|error| {
- error!("Error creating pid file '{}': {}", pid_file_name, error);
+ error!("Error creating pid file '{pid_file_name}': {error}");
process::exit(1);
});
let listener = Listener::new(socket, true).unwrap_or_else(|error| {
- error!("Error creating listener: {}", error);
+ error!("Error creating listener: {error}");
process::exit(1);
});
@@ -771,11 +782,25 @@
}
}
- limits::setup_rlimit_nofile(opt.rlimit_nofile).unwrap_or_else(|error| {
- error!("Error increasing number of open files: {}", error);
+ let fd_count_limit = limits::setup_rlimit_nofile(opt.rlimit_nofile).unwrap_or_else(|error| {
+ error!("Error increasing number of open files: {error}");
process::exit(1)
});
+ // Account for guest FDs that are created first and only accounted for then (see doc comment on
+ // `INTERNAL_FD_RESERVE`
+ let internal_fd_reserve = INTERNAL_FD_RESERVE + cmp::max(opt.thread_pool_size as u64, 1);
+ let guest_fd_limit = fd_count_limit.checked_sub(internal_fd_reserve).unwrap_or_else(|| {
+ error!("Maximum number of file descriptors too small: Limit is {fd_count_limit}, must be at least {internal_fd_reserve}");
+ process::exit(1)
+ });
+
+ // Warn the user if there is a suspiciously low limit on the guest FD count that will make it
+ // hard to actually do something; the number of `128` is completely arbitrary.
+ if guest_fd_limit < 128 {
+ warn!("File descriptor count limit is very small, leaving only {guest_fd_limit} file descriptors for the guest");
+ }
+
let mut sandbox = Sandbox::new(
shared_dir.to_string(),
opt.sandbox,
@@ -783,14 +808,14 @@
opt.gid_map,
)
.unwrap_or_else(|error| {
- error!("Error creating sandbox: {}", error);
+ error!("Error creating sandbox: {error}");
process::exit(1)
});
// Enter the sandbox, from this point the process will be isolated (or not)
// as chosen in '--sandbox'.
let listener = sandbox.enter(listener).unwrap_or_else(|error| {
- error!("Error entering sandbox: {}", error);
+ error!("Error entering sandbox: {error}");
process::exit(1)
});
@@ -820,6 +845,7 @@
migration_mode: opt.migration_mode,
uid_map: Some(opt.translate_uid),
gid_map: Some(opt.translate_gid),
+ guest_fd_limit,
..Default::default()
};
@@ -864,7 +890,7 @@
.set_tag(tag)
.build(fs)
.unwrap_or_else(|error| {
- error!("Error creating vhost-user backend: {}", error);
+ error!("Error creating vhost-user backend: {error}");
process::exit(1)
}),
);
@@ -879,7 +905,7 @@
info!("Waiting for vhost-user socket connection...");
if let Err(e) = daemon.start(listener) {
- error!("Failed to start daemon: {:?}", e);
+ error!("Failed to start daemon: {e:?}");
process::exit(1);
}
@@ -888,7 +914,7 @@
if let Err(e) = daemon.wait() {
match e {
HandleRequest(Disconnected) => info!("Client disconnected, shutting down"),
- _ => error!("Waiting for daemon failed: {:?}", e),
+ _ => error!("Waiting for daemon failed: {e:?}"),
}
}
}
diff -Nru rust-virtiofsd-1.13.0/src/oslib.rs rust-virtiofsd-1.13.2/src/oslib.rs
--- rust-virtiofsd-1.13.0/src/oslib.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/oslib.rs 2006-07-24 05:21:28.000000000 +0400
@@ -286,17 +286,15 @@
Ok(CFileHandle {
handle_bytes: sfh_bytes.len().try_into().map_err(|err| {
other_io_error(format!(
- "Handle size ({} bytes) too big: {}",
+ "Handle size ({} bytes) too big: {err}",
sfh_bytes.len(),
- err
))
})?,
#[allow(clippy::useless_conversion)]
handle_type: sfh.handle_type().try_into().map_err(|err| {
other_io_error(format!(
- "Handle type (0x{:x}) too large: {}",
+ "Handle type (0x{:x}) too large: {err}",
sfh.handle_type(),
- err
))
})?,
f_handle,
@@ -533,12 +531,14 @@
/// Set supplementary group
pub fn setsupgroup(gid: HostGid) -> io::Result<()> {
let gid_raw = gid.into_inner();
- check_retval(unsafe { libc::setgroups(1, &gid_raw) })?;
+ check_retval(unsafe { libc::syscall(libc::SYS_setgroups, 1, &gid_raw) })?;
Ok(())
}
/// Drop all supplementary groups
pub fn dropsupgroups() -> io::Result<()> {
- check_retval(unsafe { libc::setgroups(0, std::ptr::null()) })?;
+ check_retval(unsafe {
+ libc::syscall(libc::SYS_setgroups, 0, std::ptr::null::<libc::gid_t>())
+ })?;
Ok(())
}
diff -Nru rust-virtiofsd-1.13.0/src/passthrough/credentials.rs rust-virtiofsd-1.13.2/src/passthrough/credentials.rs
--- rust-virtiofsd-1.13.0/src/passthrough/credentials.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/passthrough/credentials.rs 2006-07-24 05:21:28.000000000 +0400
@@ -123,10 +123,7 @@
let cap = capng::name_to_capability(cap_name).map_err(|_| {
let err = io::Error::last_os_error();
- error!(
- "couldn't get the capability id for name {}: {:?}",
- cap_name, err
- );
+ error!("couldn't get the capability id for name {cap_name}: {err:?}");
err
})?;
@@ -137,14 +134,11 @@
capability: cap,
}];
capng::update(req).map_err(|e| {
- error!("couldn't drop {} capability: {:?}", cap, e);
+ error!("couldn't drop {cap} capability: {e:?}");
einval()
})?;
capng::apply(Set::CAPS).map_err(|e| {
- error!(
- "couldn't apply capabilities after dropping {}: {:?}",
- cap, e
- );
+ error!("couldn't apply capabilities after dropping {cap}: {e:?}");
einval()
})?;
Ok(Some(Self { cap }))
diff -Nru rust-virtiofsd-1.13.0/src/passthrough/device_state/deserialization.rs rust-virtiofsd-1.13.2/src/passthrough/device_state/deserialization.rs
--- rust-virtiofsd-1.13.0/src/passthrough/device_state/deserialization.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/passthrough/device_state/deserialization.rs 2006-07-24 05:21:28.000000000 +0400
@@ -25,7 +25,7 @@
use std::convert::{TryFrom, TryInto};
use std::io;
use std::sync::atomic::{AtomicU64, Ordering};
-use std::sync::{Arc, Mutex, RwLock};
+use std::sync::{Arc, Mutex};
impl TryFrom<Vec<u8>> for serialized::PassthroughFs {
type Error = io::Error;
@@ -360,11 +360,8 @@
io::Error::new(
err.kind(),
format!(
- "Opening {}{}{}: {}",
- pfd,
+ "Opening {pfd}{}{filename}: {err}",
if pfd.ends_with('/') { "" } else { "/" },
- filename,
- err
),
)
})?;
@@ -375,7 +372,7 @@
let file_or_handle = if let Some(h) = handle.as_ref() {
FileOrHandle::Handle(fs.make_file_handle_openable(h)?)
} else {
- FileOrHandle::File(fd)
+ FileOrHandle::File(fs.guest_fds.allocate(fd)?)
};
Ok(InodeData {
@@ -404,7 +401,7 @@
match fs.cfg.migration_on_error {
MigrationOnError::Abort => Err(err.context(format!("Inode {}", self.id))),
MigrationOnError::GuestError => {
- warn!("Invalid inode {} indexed: {}", self.id, err);
+ warn!("Invalid inode {} indexed: {err}", self.id);
Ok(InodeData {
inode: self.id,
file_or_handle: FileOrHandle::Invalid(Arc::new(err)),
@@ -427,8 +424,8 @@
// Disregard the mount ID, this may be a different host, so the mount ID may differ
is_fh.require_equal_without_mount_id(ref_fh).map_err(|err| {
other_io_error(format!(
- "Inode {} is not the same inode as in the migration source: {}",
- self.id, err
+ "Inode {} is not the same inode as in the migration source: {err}",
+ self.id
))
})
}
@@ -458,7 +455,7 @@
let st = statx(&fd, None).err_context(|| "stat")?;
let file_or_handle = match fs.cfg.inode_file_handles {
- InodeFileHandlesMode::Never => FileOrHandle::File(fd),
+ InodeFileHandlesMode::Never => FileOrHandle::File(fs.guest_fds.allocate(fd)?),
InodeFileHandlesMode::Mandatory | InodeFileHandlesMode::Prefer => {
FileOrHandle::Handle(ofh)
}
@@ -493,30 +490,32 @@
.open_file(flags, &fs.proc_self_fd)
.and_then(|f| f.into_file())
{
- Ok(f) => HandleDataFile::File(RwLock::new(f)),
+ Ok(f) => fs.guest_fds.allocate(f).map(Into::into),
Err(err) => {
let error_msg = if let Ok(path) = inode.get_path(&fs.proc_self_fd) {
let p = path.as_c_str().to_string_lossy();
format!(
- "Opening inode {} ({}) as handle {}: {}",
- self.inode, p, self.id, err
+ "Opening inode {} ({p}) as handle {}: {err}",
+ self.inode, self.id
)
} else {
- format!(
- "Opening inode {} as handle {}: {}",
- self.inode, self.id, err
- )
+ format!("Opening inode {} as handle {}: {err}", self.inode, self.id)
};
- let err = io::Error::new(err.kind(), error_msg);
- match fs.cfg.migration_on_error {
- MigrationOnError::Abort => return Err(err),
- MigrationOnError::GuestError => {
- warn!("Invalid handle {} is open in guest: {}", self.id, err);
- HandleDataFile::Invalid(Arc::new(err))
- }
- }
+ Err(io::Error::new(err.kind(), error_msg))
}
};
+
+ let handle_data_file = match handle_data_file {
+ Ok(hdf) => hdf,
+ Err(err) => match fs.cfg.migration_on_error {
+ MigrationOnError::Abort => return Err(err),
+ MigrationOnError::GuestError => {
+ warn!("Invalid handle {} is open in guest: {err}", self.id);
+ HandleDataFile::Invalid(Arc::new(err))
+ }
+ },
+ };
+
let migration_info = HandleMigrationInfo::OpenInode { flags };
(handle_data_file, migration_info)
}
diff -Nru rust-virtiofsd-1.13.0/src/passthrough/device_state/mod.rs rust-virtiofsd-1.13.2/src/passthrough/device_state/mod.rs
--- rust-virtiofsd-1.13.0/src/passthrough/device_state/mod.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/passthrough/device_state/mod.rs 2006-07-24 05:21:28.000000000 +0400
@@ -7,9 +7,8 @@
* following submodules:
* - serialized: Serialized data structures
* - preserialization: Structures and functionality for preparing for migration (serialization),
- * i.e. define and construct the precursors to the eventually serialized
- * information that are stored alongside the associated inodes and handles they
- * describe
+ * i.e. define and construct the precursors to the eventually serialized information that are
+ * stored alongside the associated inodes and handles they describe
* - serialization: Functionality for serializing
* - deserialization: Functionality for deserializing
*/
diff -Nru rust-virtiofsd-1.13.0/src/passthrough/device_state/preserialization/file_handles.rs rust-virtiofsd-1.13.2/src/passthrough/device_state/preserialization/file_handles.rs
--- rust-virtiofsd-1.13.0/src/passthrough/device_state/preserialization/file_handles.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/passthrough/device_state/preserialization/file_handles.rs 2006-07-24 05:21:28.000000000 +0400
@@ -69,10 +69,9 @@
if let Err(err) = self.set_migration_info(&inode_data) {
error!(
- "Inode {} ({}): {}",
+ "Inode {} ({}): {err}",
inode_data.inode,
inode_data.identify(&self.fs.proc_self_fd),
- err
);
}
}
diff -Nru rust-virtiofsd-1.13.0/src/passthrough/device_state/preserialization/find_paths.rs rust-virtiofsd-1.13.2/src/passthrough/device_state/preserialization/find_paths.rs
--- rust-virtiofsd-1.13.0/src/passthrough/device_state/preserialization/find_paths.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/passthrough/device_state/preserialization/find_paths.rs 2006-07-24 05:21:28.000000000 +0400
@@ -286,7 +286,7 @@
let file_or_handle = if let Some(h) = handle.as_ref() {
FileOrHandle::Handle(self.fs.make_file_handle_openable(h)?)
} else {
- FileOrHandle::File(path_fd)
+ FileOrHandle::File(self.fs.guest_fds.allocate(path_fd)?)
};
let mig_info = InodeMigrationInfo::new_internal(
diff -Nru rust-virtiofsd-1.13.0/src/passthrough/device_state/preserialization/mod.rs rust-virtiofsd-1.13.2/src/passthrough/device_state/preserialization/mod.rs
--- rust-virtiofsd-1.13.0/src/passthrough/device_state/preserialization/mod.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/passthrough/device_state/preserialization/mod.rs 2006-07-24 05:21:28.000000000 +0400
@@ -67,9 +67,8 @@
MigrationMode::FileHandles => {
let handle = file_or_handle.try_into().err_context(|| {
format!(
- "(inode {})/{:?}: Failed to generate file handle",
+ "(inode {})/{filename:?}: Failed to generate file handle",
parent_ref.get().inode,
- filename,
)
})?;
file_handles::FileHandle::new(handle).into()
diff -Nru rust-virtiofsd-1.13.0/src/passthrough/device_state/preserialization/proc_paths.rs rust-virtiofsd-1.13.2/src/passthrough/device_state/preserialization/proc_paths.rs
--- rust-virtiofsd-1.13.0/src/passthrough/device_state/preserialization/proc_paths.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/passthrough/device_state/preserialization/proc_paths.rs 2006-07-24 05:21:28.000000000 +0400
@@ -224,11 +224,10 @@
*
* In case of error, differentiate between:
* - `Fallback(err)`: We failed to construct inode migration info for some number of inodes.
- * However, we expect a different, more exhaustive method to find inodes’
- * paths (e.g. DFS through the shared directory) can succeed. In case of
- * `Mode::Constructor`, the caller must fall back to such a different
- * preserialization module (i.e. [`super::find_paths`]). In other modes,
- * this should be treated the same as `Unrecoverable`.
+ * However, we expect a different, more exhaustive method to find inodes’ paths (e.g. DFS
+ * through the shared directory) can succeed. In case of `Mode::Constructor`, the caller
+ * must fall back to such a different preserialization module (i.e. [`super::find_paths`]).
+ * In other modes, this should be treated the same as `Unrecoverable`.
* - `Unrecoverable(err)`: Hard error, falling back to a different method is not advised.
*/
fn run(self) -> Result<(), WrappedError> {
diff -Nru rust-virtiofsd-1.13.0/src/passthrough/device_state/serialization.rs rust-virtiofsd-1.13.2/src/passthrough/device_state/serialization.rs
--- rust-virtiofsd-1.13.0/src/passthrough/device_state/serialization.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/passthrough/device_state/serialization.rs 2006-07-24 05:21:28.000000000 +0400
@@ -58,8 +58,8 @@
.as_serialized(fs)
.unwrap_or_else(|err| {
warn!(
- "Failed to serialize inode {} (st_dev={}, mnt_id={}, st_ino={}): {}; marking as invalid",
- inode.inode, inode.ids.dev, inode.ids.mnt_id, inode.ids.ino, err
+ "Failed to serialize inode {} (st_dev={}, mnt_id={}, st_ino={}): {err}; marking as invalid",
+ inode.inode, inode.ids.dev, inode.ids.mnt_id, inode.ids.ino
);
serialized::Inode {
id: inode.inode,
diff -Nru rust-virtiofsd-1.13.0/src/passthrough/file_handle.rs rust-virtiofsd-1.13.2/src/passthrough/file_handle.rs
--- rust-virtiofsd-1.13.0/src/passthrough/file_handle.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/passthrough/file_handle.rs 2006-07-24 05:21:28.000000000 +0400
@@ -3,6 +3,7 @@
// found in the LICENSE file.
use crate::oslib;
+use crate::passthrough::guest_fd_limit::GuestFile;
use crate::passthrough::mount_fd::{MPRResult, MountFd, MountFds};
use crate::passthrough::stat::MountId;
use serde::{Deserialize, Serialize};
@@ -35,7 +36,7 @@
}
pub enum FileOrHandle {
- File(File),
+ File(GuestFile),
Handle(OpenableFileHandle),
// `io::Error` does not implement `Clone`, so without wrapping it in `Arc`, returning the error
// anywhere would be impossible without consuming it
diff -Nru rust-virtiofsd-1.13.0/src/passthrough/guest_fd_limit.rs rust-virtiofsd-1.13.2/src/passthrough/guest_fd_limit.rs
--- rust-virtiofsd-1.13.0/src/passthrough/guest_fd_limit.rs 1970-01-01 03:00:00.000000000 +0300
+++ rust-virtiofsd-1.13.2/src/passthrough/guest_fd_limit.rs 2006-07-24 05:21:28.000000000 +0400
@@ -0,0 +1,111 @@
+// Copyright 2024 Red Hat, Inc. All rights reserved.
+//
+// SPDX-License-Identifier: (Apache-2.0 AND BSD-3-Clause)
+
+//! Allow limiting the number of file descriptors we allocate for the guest.
+//!
+//! Any process only has a limited number of file descriptor slots available for use, and besides
+//! allocating FDs for the guest, virtiofsd also needs to be able to create file descriptors for
+//! internal use. By limiting the number we will allocate for the guest, we can ensure there are
+//! always free slots open for such internal use.
+
+use std::fs::File;
+use std::io;
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
+use std::sync::Arc;
+
+/// Basically just a semaphore, but specifically for limiting guest FD use.
+///
+/// Wraps plain `File`s to create `GuestFile`s that count against the guest FD limit until dropped.
+pub(crate) struct GuestFdSemaphore {
+ /// Initial (overall) limit.
+ initial: u64,
+
+ /// How many allocations are still available before exhausting the limit.
+ available: AtomicU64,
+
+ /// Whether an error about no remaining FD slots has been logged.
+ ///
+ /// Further errors will then be suppressed.
+ error_logged: AtomicBool,
+}
+
+/// Returned by `GuestFdSemaphore::allocate()`, will release the slot when dropped.
+pub struct GuestFile {
+ /// Contained FD.
+ file: File,
+
+ /// Semaphore reference.
+ sem: Arc<GuestFdSemaphore>,
+}
+
+impl GuestFdSemaphore {
+ /// Create a new instance with the given `limit`.
+ pub fn new(limit: u64) -> Self {
+ GuestFdSemaphore {
+ initial: limit,
+ available: limit.into(),
+ error_logged: false.into(),
+ }
+ }
+
+ /// Put the given file into a free slot.
+ ///
+ /// The slot is released by dropping the returned `GuestFile`.
+ pub fn allocate(self: &Arc<Self>, file: File) -> io::Result<GuestFile> {
+ self.available.fetch_update(
+ Ordering::Relaxed,
+ Ordering::Relaxed,
+ |previous| previous.checked_sub(1),
+ ).map_err(|_| {
+ if !self.error_logged.fetch_or(true, Ordering::Relaxed) {
+ error!(
+ "No more file descriptors available to the guest (0 available out of {} initially), \
+ consider increasing the --rlimit-nofile value",
+ self.initial,
+ );
+ }
+
+ // Since this error is likely returned to the guest (and not logged), prefer an
+ // error with a reasonable errno number over a useful error message.
+ io::Error::from_raw_os_error(libc::ENFILE)
+ })?;
+
+ Ok(GuestFile {
+ file,
+ sem: Arc::clone(self),
+ })
+ }
+
+ /// Release one slot.
+ ///
+ /// Do not use directly, just drop [`GuestFile`].
+ fn release(&self) {
+ let increased_to = self
+ .available
+ .fetch_add(1, Ordering::Relaxed)
+ .checked_add(1)
+ .unwrap_or_else(|| panic!("FD semaphore overflow"));
+ debug_assert!(increased_to <= self.initial);
+ }
+}
+
+impl GuestFile {
+ /// Get the inner file.
+ pub fn get_file(&self) -> &File {
+ &self.file
+ }
+}
+
+impl AsRawFd for GuestFile {
+ fn as_raw_fd(&self) -> RawFd {
+ self.file.as_raw_fd()
+ }
+}
+
+impl Drop for GuestFile {
+ fn drop(&mut self) {
+ self.sem.release();
+ }
+}
diff -Nru rust-virtiofsd-1.13.0/src/passthrough/inode_store.rs rust-virtiofsd-1.13.2/src/passthrough/inode_store.rs
--- rust-virtiofsd-1.13.0/src/passthrough/inode_store.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/passthrough/inode_store.rs 2006-07-24 05:21:28.000000000 +0400
@@ -132,7 +132,7 @@
/// Get an `O_PATH` file for this inode
pub fn get_file(&'a self) -> io::Result<InodeFile<'a>> {
match &self.file_or_handle {
- FileOrHandle::File(f) => Ok(InodeFile::Ref(f)),
+ FileOrHandle::File(f) => Ok(InodeFile::Ref(f.get_file())),
FileOrHandle::Handle(h) => {
let file = h.open(libc::O_PATH)?;
Ok(InodeFile::Owned(file))
@@ -206,8 +206,8 @@
_ => "unknown inode type",
};
format!(
- "[{}; mount_id={} device_id={} inode_id={}]",
- mode, self.ids.mnt_id, self.ids.dev, self.ids.ino,
+ "[{mode}; mount_id={} device_id={} inode_id={}]",
+ self.ids.mnt_id, self.ids.dev, self.ids.ino,
)
}
}
diff -Nru rust-virtiofsd-1.13.0/src/passthrough/mod.rs rust-virtiofsd-1.13.2/src/passthrough/mod.rs
--- rust-virtiofsd-1.13.0/src/passthrough/mod.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/passthrough/mod.rs 2006-07-24 05:21:28.000000000 +0400
@@ -5,6 +5,7 @@
pub mod credentials;
pub mod device_state;
pub mod file_handle;
+mod guest_fd_limit;
pub mod inode_store;
pub mod mount_fd;
pub mod read_only;
@@ -31,6 +32,7 @@
use crate::util::{other_io_error, ResultErrorContext};
use crate::{fuse, oslib};
use file_handle::{FileHandle, FileOrHandle, OpenableFileHandle};
+use guest_fd_limit::{GuestFdSemaphore, GuestFile};
use mount_fd::{MPRError, MountFds};
use stat::{statx, StatExt};
use std::borrow::Cow;
@@ -53,7 +55,7 @@
type Handle = u64;
enum HandleDataFile {
- File(RwLock<File>),
+ File(RwLock<GuestFile>),
// `io::Error` does not implement `Clone`, so without wrapping it in `Arc`, returning the error
// anywhere would be impossible without consuming it
Invalid(Arc<io::Error>),
@@ -386,6 +388,12 @@
* Is `take()`n when `PassthroughFs` is created, i.e. `None` during runtime.
*/
pub gid_map: Option<Vec<soft_idmap::cmdline::IdMap>>,
+
+ /// Number of file descriptors we can allocate for guest use. Limiting this ensures there is
+ /// always some room for file descriptors used and needed by virtiofsd internally.
+ ///
+ /// The default is `u64::MAX`.
+ pub guest_fd_limit: u64,
}
impl Default for Config {
@@ -417,6 +425,7 @@
migration_mode: MigrationMode::FindPaths,
uid_map: None,
gid_map: None,
+ guest_fd_limit: u64::MAX,
}
}
}
@@ -439,6 +448,11 @@
handles: RwLock<BTreeMap<Handle, Arc<HandleData>>>,
next_handle: AtomicU64,
+ // Represents a limit for the number of file descriptors we allow allocating for the guest.
+ // Having such a limit that is below the actual maximum number of file descriptors virtiofsd is
+ // allowed to use ensures that virtiofsd can always create file descriptors for internal use.
+ guest_fds: Arc<GuestFdSemaphore>,
+
// Maps mount IDs to an open FD on the respective ID for the purpose of open_by_handle_at().
// This is set when inode_file_handles is not never, since in the 'never' case,
// open_by_handle_at() is not called.
@@ -535,6 +549,7 @@
next_inode: AtomicU64::new(fuse::ROOT_ID + 1),
handles: RwLock::new(BTreeMap::new()),
next_handle: AtomicU64::new(0),
+ guest_fds: Arc::new(GuestFdSemaphore::new(cfg.guest_fd_limit)),
mount_fds,
proc_self_fd,
root_fd,
@@ -634,16 +649,16 @@
/// These are the possible return values:
/// - `Ok(Some(_))`: Success, caller should use this file handle.
/// - `Ok(None)`: No error, but no file handle is available. The caller should fall back to
- /// using an `O_PATH` FD.
+ /// using an `O_PATH` FD.
/// - `Err(_)`: An error occurred, the caller should return this to the guest.
///
/// This function takes the chosen `self.cfg.inode_file_handles` mode into account:
/// - `Never`: Always return `Ok(None)`.
/// - `Prefer`: Return `Ok(None)` when file handles are not supported by this filesystem.
- /// Otherwise, return either `Ok(Some(_))` or `Err(_)`, depending on whether a file
- /// handle could be generated or not.
+ /// Otherwise, return either `Ok(Some(_))` or `Err(_)`, depending on whether a file handle
+ /// could be generated or not.
/// - `Mandatory`: Never return `Ok(None)`. When the filesystem does not support file handles,
- /// return an `Err(_)`.
+ /// return an `Err(_)`.
///
/// When the filesystem does not support file handles, this is logged (as a warning in
/// `Prefer` mode, and as an error in `Mandatory` mode) one time per filesystem.
@@ -700,12 +715,12 @@
InodeFileHandlesMode::Never => unreachable!(),
InodeFileHandlesMode::Prefer => {
if !err.silent() {
- warn!("{}", err);
+ warn!("{err}");
}
}
InodeFileHandlesMode::Mandatory => {
if !err.silent() {
- error!("{}", err);
+ error!("{err}");
}
return Err(err.into_inner());
}
@@ -722,7 +737,7 @@
})
.map_err(|e| {
if !e.silent() {
- error!("{}", e);
+ error!("{e}");
}
e.into_inner()
})
@@ -753,12 +768,12 @@
Err(e) => match self.cfg.inode_file_handles {
InodeFileHandlesMode::Never => unreachable!(),
InodeFileHandlesMode::Prefer => {
- warn!("Failed to open file handle for the root node: {}", e);
+ warn!("Failed to open file handle for the root node: {e}");
warn!("File handles do not appear safe to use, disabling file handles altogether");
self.cfg.inode_file_handles = InodeFileHandlesMode::Never;
}
InodeFileHandlesMode::Mandatory => {
- error!("Failed to open file handle for the root node: {}", e);
+ error!("Failed to open file handle for the root node: {e}");
error!("Refusing to use (mandatory) file handles, as they do not appear safe to use");
return Err(e);
}
@@ -862,7 +877,7 @@
let file_or_handle = if let Some(h) = handle.as_ref() {
FileOrHandle::Handle(self.make_file_handle_openable(h)?)
} else {
- FileOrHandle::File(path_fd)
+ FileOrHandle::File(self.guest_fds.allocate(path_fd)?)
};
let mig_info = if self.track_migration_info.load(Ordering::Relaxed) {
@@ -943,7 +958,7 @@
let handle = self.next_handle.fetch_add(1, Ordering::Relaxed);
let data = HandleData {
inode,
- file: file.into(),
+ file: self.guest_fds.allocate(file)?.into(),
migration_info: HandleMigrationInfo::new(flags as i32),
};
@@ -1263,7 +1278,7 @@
let file_or_handle = if let Some(h) = handle.as_ref() {
FileOrHandle::Handle(self.make_file_handle_openable(h)?)
} else {
- FileOrHandle::File(path_fd)
+ FileOrHandle::File(self.guest_fds.allocate(path_fd)?)
};
// Always keep the root node's migration info set (`InodeStore::clear_migration_info()`
@@ -1764,7 +1779,7 @@
let handle = self.next_handle.fetch_add(1, Ordering::Relaxed);
let data = HandleData {
inode: entry.inode,
- file: file.into(),
+ file: self.guest_fds.allocate(file)?.into(),
migration_info: HandleMigrationInfo::new(flags as i32),
};
@@ -1805,7 +1820,7 @@
// This is safe because read_from_file_at uses preadv64, so the underlying file descriptor
// offset is not affected by this operation.
let f = data.file.get()?.read().unwrap();
- w.read_from_file_at(&f, size as usize, offset)
+ w.read_from_file_at(f.get_file(), size as usize, offset)
}
fn write<R: ZeroCopyReader>(
@@ -1847,7 +1862,7 @@
// write on the underlying file is performed in append mode.
let is_append = flags & libc::O_APPEND as u32 != 0;
let flags = (!delayed_write && is_append).then_some(oslib::WritevFlags::RWF_APPEND);
- r.write_to_file_at(&f, size as usize, offset, flags)
+ r.write_to_file_at(f.get_file(), size as usize, offset, flags)
}
}
@@ -2650,7 +2665,7 @@
let file = self.open_inode(inode, libc::O_RDONLY | libc::O_NOFOLLOW)?;
let raw_fd = file.as_raw_fd();
- debug!("syncfs: inode={}, mount_fd={}", inode, raw_fd);
+ debug!("syncfs: inode={inode}, mount_fd={raw_fd}");
let ret = unsafe { libc::syncfs(raw_fd) };
if ret != 0 {
// Thread-safe, because errno is stored in thread-local storage.
@@ -2662,7 +2677,7 @@
}
impl HandleDataFile {
- fn get(&self) -> io::Result<&'_ RwLock<File>> {
+ fn get(&self) -> io::Result<&'_ RwLock<GuestFile>> {
match self {
HandleDataFile::File(file) => Ok(file),
HandleDataFile::Invalid(err) => Err(io::Error::new(
@@ -2673,8 +2688,8 @@
}
}
-impl From<File> for HandleDataFile {
- fn from(file: File) -> Self {
+impl From<GuestFile> for HandleDataFile {
+ fn from(file: GuestFile) -> Self {
HandleDataFile::File(RwLock::new(file))
}
}
diff -Nru rust-virtiofsd-1.13.0/src/passthrough/mount_fd.rs rust-virtiofsd-1.13.2/src/passthrough/mount_fd.rs
--- rust-virtiofsd-1.13.0/src/passthrough/mount_fd.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/passthrough/mount_fd.rs 2006-07-24 05:21:28.000000000 +0400
@@ -191,7 +191,7 @@
/// Add a prefix to the description
#[must_use]
pub fn prefix(self, s: String) -> Self {
- let new_desc = format!("{}: {}", s, self.description);
+ let new_desc = format!("{s}: {}", self.description);
self.set_desc(new_desc)
}
@@ -234,18 +234,16 @@
match (self.fs_mount_id, &self.fs_mount_root) {
(None, None) => write!(f, "{}", self.description),
- (Some(id), None) => write!(f, "Filesystem with mount ID {}: {}", id, self.description),
+ (Some(id), None) => write!(f, "Filesystem with mount ID {id}: {}", self.description),
- (None, Some(root)) => write!(
- f,
- "Filesystem mounted on \"{}\": {}",
- root, self.description
- ),
+ (None, Some(root)) => {
+ write!(f, "Filesystem mounted on \"{root}\": {}", self.description)
+ }
(Some(id), Some(root)) => write!(
f,
- "Filesystem mounted on \"{}\" (mount ID: {}): {}",
- root, id, self.description
+ "Filesystem mounted on \"{root}\" (mount ID: {id}): {}",
+ self.description
),
}
}
@@ -319,8 +317,8 @@
return Err(self
.error_for(mount_id, io::Error::from_raw_os_error(libc::EIO))
.set_desc(format!(
- "Mount point's ({}) mount ID ({}) does not match expected value ({})",
- mount_point, stx.mnt_id, mount_id
+ "Mount point's ({mount_point}) mount ID ({}) does not match expected value ({mount_id})",
+ stx.mnt_id
)));
}
@@ -357,8 +355,7 @@
mount_fd
} else {
debug!(
- "Creating MountFd: mount_id={}, mount_fd={}",
- mount_id,
+ "Creating MountFd: mount_id={mount_id}, mount_fd={}",
file.as_raw_fd(),
);
let mount_fd = Arc::new(MountFd {
diff -Nru rust-virtiofsd-1.13.0/src/sandbox.rs rust-virtiofsd-1.13.2/src/sandbox.rs
--- rust-virtiofsd-1.13.0/src/sandbox.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/sandbox.rs 2006-07-24 05:21:28.000000000 +0400
@@ -447,7 +447,7 @@
// other end of the pipe.
drop(x_reader);
drop(y_writer);
- error!("sandbox: couldn't setup id mappings: {}", error);
+ error!("sandbox: couldn't setup id mappings: {error}");
process::exit(1);
};
}
@@ -489,11 +489,11 @@
// Set the process inside the user namespace as root
let mut ret = unsafe { libc::setresuid(0, 0, 0) };
if ret != 0 {
- warn!("Couldn't set the process uid as root: {}", ret);
+ warn!("Couldn't set the process uid as root: {ret}");
}
ret = unsafe { libc::setresgid(0, 0, 0) };
if ret != 0 {
- warn!("Couldn't set the process gid as root: {}", ret);
+ warn!("Couldn't set the process gid as root: {ret}");
}
let child = util::sfork().map_err(Error::Fork)?;
diff -Nru rust-virtiofsd-1.13.0/src/seccomp.rs rust-virtiofsd-1.13.2/src/seccomp.rs
--- rust-virtiofsd-1.13.0/src/seccomp.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/seccomp.rs 2006-07-24 05:21:28.000000000 +0400
@@ -186,6 +186,9 @@
allow_syscall!(ctx, libc::SYS_syncfs);
#[cfg(target_arch = "x86_64")]
allow_syscall!(ctx, libc::SYS_time); // Rarely needed, except on static builds
+ allow_syscall!(ctx, libc::SYS_tkill); // Deprecated in favour of tgkill, but older OSes may
+ // still be using it, and we should avoid crashing on
+ // those cases.
allow_syscall!(ctx, libc::SYS_tgkill);
allow_syscall!(ctx, libc::SYS_umask);
#[cfg(any(
diff -Nru rust-virtiofsd-1.13.0/src/server.rs rust-virtiofsd-1.13.2/src/server.rs
--- rust-virtiofsd-1.13.0/src/server.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/server.rs 2006-07-24 05:21:28.000000000 +0400
@@ -112,8 +112,8 @@
if let Ok(opcode) = Opcode::try_from(in_header.opcode) {
debug!(
- "Received request: opcode={:?} ({}), inode={}, unique={}, pid={}",
- opcode, in_header.opcode, in_header.nodeid, in_header.unique, in_header.pid
+ "Received request: opcode={opcode:?} ({}), inode={}, unique={}, pid={}",
+ in_header.opcode, in_header.nodeid, in_header.unique, in_header.pid
);
match opcode {
Opcode::Lookup => self.lookup(in_header, r, w),
@@ -598,7 +598,7 @@
unique: in_header.unique,
};
- debug!("Replying OK, header: {:?}", out);
+ debug!("Replying OK, header: {out:?}");
w.write_all(out.as_slice()).map_err(Error::EncodeMessage)?;
Ok(out.len as usize)
}
@@ -889,7 +889,7 @@
};
if major < KERNEL_VERSION {
- error!("Unsupported fuse protocol version: {}.{}", major, minor);
+ error!("Unsupported fuse protocol version: {major}.{minor}");
return reply_error(
io::Error::from_raw_os_error(libc::EPROTO),
in_header.unique,
@@ -909,10 +909,7 @@
}
if minor < MIN_KERNEL_MINOR_VERSION {
- error!(
- "Unsupported fuse protocol minor version: {}.{}",
- major, minor
- );
+ error!("Unsupported fuse protocol minor version: {major}.{minor}");
return reply_error(
io::Error::from_raw_os_error(libc::EPROTO),
in_header.unique,
@@ -1491,7 +1488,7 @@
unique,
};
- debug!("Replying OK, header: {:?}", out);
+ debug!("Replying OK, header: {out:?}");
w.write_all(out.as_slice()).map_err(Error::EncodeMessage)?;
w.flush().map_err(Error::FlushMessage)?;
Ok(out.len as usize)
@@ -1519,7 +1516,7 @@
unique,
};
- debug!("Replying OK, header: {:?}", header);
+ debug!("Replying OK, header: {header:?}");
w.write_all(header.as_slice())
.map_err(Error::EncodeMessage)?;
@@ -1743,7 +1740,7 @@
secctx_received = true;
extensions.secctx = parse_security_context(nr_secctx, current_extension_bytes)?;
- debug!("Extension received: {} SecCtx", nr_secctx);
+ debug!("Extension received: {nr_secctx} SecCtx");
}
ExtType::SupGroups => {
if !options.contains(FsOptions::CREATE_SUPP_GROUP) || extensions.sup_gid.is_some() {
diff -Nru rust-virtiofsd-1.13.0/src/soft_idmap/mod.rs rust-virtiofsd-1.13.2/src/soft_idmap/mod.rs
--- rust-virtiofsd-1.13.0/src/soft_idmap/mod.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/soft_idmap/mod.rs 2006-07-24 05:21:28.000000000 +0400
@@ -218,15 +218,14 @@
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
MapEntry::Squash { from, to } => {
- write!(f, "squash [{}, {}) to {}", from.start, from.end, to)
+ write!(f, "squash [{}, {}) to {to}", from.start, from.end)
}
MapEntry::Range { from, to_base } => {
write!(
f,
- "map [{}, {}) to [{}, {})",
+ "map [{}, {}) to [{to_base}, {})",
from.start,
from.end,
- to_base,
*to_base + (from.end - from.start)
)
}
diff -Nru rust-virtiofsd-1.13.0/src/util.rs rust-virtiofsd-1.13.2/src/util.rs
--- rust-virtiofsd-1.13.0/src/util.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/util.rs 2006-07-24 05:21:28.000000000 +0400
@@ -110,7 +110,7 @@
capng::clear(capng::Set::BOTH);
if let Err(e) = capng::apply(capng::Set::BOTH) {
// Don't exit the process here since we already have a child.
- error!("warning: can't apply the parent capabilities: {}", e);
+ error!("warning: can't apply the parent capabilities: {e}");
}
let mut status = 0;
@@ -124,10 +124,10 @@
libc::WEXITSTATUS(status)
} else if libc::WIFSIGNALED(status) {
let signal = libc::WTERMSIG(status);
- error!("Child process terminated by signal {}", signal);
+ error!("Child process terminated by signal {signal}");
-signal
} else {
- error!("Unexpected waitpid status: {:#X}", status);
+ error!("Unexpected waitpid status: {status:#X}");
libc::EXIT_FAILURE
};
@@ -163,6 +163,8 @@
/// Same as `io::Error::other()`, but the respective io_error_other feature has only been
/// stabilized in Rust 1.74.0, which is too new for our intended targets.
pub fn other_io_error<E: Into<Box<dyn std::error::Error + Send + Sync>>>(err: E) -> io::Error {
+ #[allow(unknown_lints)]
+ #[allow(clippy::io_other_error)]
io::Error::new(io::ErrorKind::Other, err)
}
diff -Nru rust-virtiofsd-1.13.0/src/vhost_user.rs rust-virtiofsd-1.13.2/src/vhost_user.rs
--- rust-virtiofsd-1.13.0/src/vhost_user.rs 2006-07-24 05:21:28.000000000 +0400
+++ rust-virtiofsd-1.13.2/src/vhost_user.rs 2006-07-24 05:21:28.000000000 +0400
@@ -459,9 +459,9 @@
}
fn features(&self) -> u64 {
- 1 << VIRTIO_F_VERSION_1
- | 1 << VIRTIO_RING_F_INDIRECT_DESC
- | 1 << VIRTIO_RING_F_EVENT_IDX
+ (1 << VIRTIO_F_VERSION_1)
+ | (1 << VIRTIO_RING_F_INDIRECT_DESC)
+ | (1 << VIRTIO_RING_F_EVENT_IDX)
| VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits()
| VhostUserVirtioFeatures::LOG_ALL.bits()
}
@@ -623,7 +623,7 @@
if phase != VhostTransferStatePhase::STOPPED {
return Err(io::Error::new(
io::ErrorKind::Unsupported,
- format!("Transfer in phase {:?} is not supported", phase),
+ format!("Transfer in phase {phase:?} is not supported"),
));
}
@@ -658,9 +658,9 @@
server.prepare_serialization(Arc::new(AtomicBool::new(false)));
}
- server.serialize(file).map_err(|e| {
- io::Error::new(e.kind(), format!("Failed to save state: {}", e))
- })
+ server
+ .serialize(file)
+ .map_err(|e| io::Error::new(e.kind(), format!("Failed to save state: {e}")))
})
}
@@ -673,9 +673,9 @@
}
thread::spawn(move || {
- server.deserialize_and_apply(file).map_err(|e| {
- io::Error::new(e.kind(), format!("Failed to load state: {}", e))
- })
+ server
+ .deserialize_and_apply(file)
+ .map_err(|e| io::Error::new(e.kind(), format!("Failed to load state: {e}")))
})
}
};
@@ -712,7 +712,7 @@
.kill_evt
.write(1);
if let Err(e) = result {
- error!("Error shutting down worker thread: {:?}", e)
+ error!("Error shutting down worker thread: {e:?}")
}
}
}
More information about the Pkg-rust-maintainers
mailing list