Snap for 12335440 from 5101a2d9bdab8bfec251891c2f4aef8b2d814bee to 24Q4-release
Change-Id: I6442a47e8ab58c1c2c058e67e3c047b69df07e5e
diff --git a/android/fd_server/Android.bp b/android/fd_server/Android.bp
index 32a8fec..b02c104 100644
--- a/android/fd_server/Android.bp
+++ b/android/fd_server/Android.bp
@@ -18,7 +18,6 @@
"liblog_rust",
"libnix",
"librpcbinder_rs",
- "libsafe_ownedfd",
],
prefer_rlib: true,
apex_available: ["com.android.virt"],
@@ -40,7 +39,6 @@
"liblog_rust",
"libnix",
"librpcbinder_rs",
- "libsafe_ownedfd",
],
prefer_rlib: true,
test_suites: ["general-tests"],
diff --git a/android/fd_server/src/aidl.rs b/android/fd_server/src/aidl.rs
index 2f3697c..5f91987 100644
--- a/android/fd_server/src/aidl.rs
+++ b/android/fd_server/src/aidl.rs
@@ -14,21 +14,20 @@
* limitations under the License.
*/
-use anyhow::{Context, Result};
+use anyhow::Result;
use log::error;
use nix::{
errno::Errno, fcntl::openat, fcntl::OFlag, sys::stat::fchmod, sys::stat::mkdirat,
sys::stat::mode_t, sys::stat::Mode, sys::statvfs::statvfs, sys::statvfs::Statvfs,
unistd::unlinkat, unistd::UnlinkatFlags,
};
-use safe_ownedfd::take_fd_ownership;
use std::cmp::min;
use std::collections::{btree_map, BTreeMap};
use std::convert::TryInto;
use std::fs::File;
use std::io;
use std::os::unix::fs::FileExt;
-use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, OwnedFd};
+use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd};
use std::path::{Component, Path, PathBuf, MAIN_SEPARATOR};
use std::sync::{Arc, RwLock};
@@ -39,8 +38,7 @@
get_fsverity_metadata_path, parse_fsverity_metadata, FSVerityMetadata,
};
use binder::{
- BinderFeatures, ExceptionCode, Interface, IntoBinderResult, Result as BinderResult, Status,
- StatusCode, Strong,
+ BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Status, StatusCode, Strong,
};
/// Bitflags of forbidden file mode, e.g. setuid, setgid and sticky bit.
@@ -301,11 +299,9 @@
mode,
)
.map_err(new_errno_error)?;
- let new_fd = take_fd_ownership(new_fd)
- .context("Failed to take ownership of fd for file")
- .or_service_specific_exception(-1)?;
- let new_file = File::from(new_fd);
- Ok((new_file.as_raw_fd(), FdConfig::ReadWrite(new_file)))
+ // SAFETY: new_fd is just created and not an error.
+ let new_file = unsafe { File::from_raw_fd(new_fd) };
+ Ok((new_fd, FdConfig::ReadWrite(new_file)))
}
_ => Err(new_errno_error(Errno::ENOTDIR)),
})
@@ -331,10 +327,9 @@
Mode::empty(),
)
.map_err(new_errno_error)?;
- let fd_owner = take_fd_ownership(new_dir_fd)
- .context("Failed to take ownership of the fd for directory")
- .or_service_specific_exception(-1)?;
- Ok((fd_owner.as_raw_fd(), FdConfig::OutputDir(fd_owner)))
+ // SAFETY: new_dir_fd is just created and not an error.
+ let fd_owner = unsafe { OwnedFd::from_raw_fd(new_dir_fd) };
+ Ok((new_dir_fd, FdConfig::OutputDir(fd_owner)))
}
_ => Err(new_errno_error(Errno::ENOTDIR)),
})
@@ -413,11 +408,9 @@
fn open_readonly_at(dir_fd: BorrowedFd, path: &Path) -> nix::Result<File> {
let new_fd = openat(Some(dir_fd.as_raw_fd()), path, OFlag::O_RDONLY, Mode::empty())?;
- let new_fd = take_fd_ownership(new_fd).map_err(|e| match e {
- safe_ownedfd::Error::Errno(e) => e,
- _ => Errno::UnknownErrno,
- })?;
- Ok(File::from(new_fd))
+ // SAFETY: new_fd is just created successfully and not owned.
+ let new_file = unsafe { File::from_raw_fd(new_fd) };
+ Ok(new_file)
}
fn validate_and_cast_offset(offset: i64) -> Result<u64, Status> {
diff --git a/android/virtmgr/Android.bp b/android/virtmgr/Android.bp
index cbb7b38..f0b6881 100644
--- a/android/virtmgr/Android.bp
+++ b/android/virtmgr/Android.bp
@@ -54,7 +54,6 @@
"libregex",
"librpcbinder_rs",
"librustutils",
- "libsafe_ownedfd",
"libsemver",
"libselinux_bindgen",
"libserde",
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index dab78c3..87fb611 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -73,7 +73,6 @@
use nix::unistd::pipe;
use rpcbinder::RpcServer;
use rustutils::system_properties;
-use safe_ownedfd::take_fd_ownership;
use semver::VersionReq;
use serde::Deserialize;
use std::collections::HashSet;
@@ -85,7 +84,7 @@
use std::iter;
use std::num::{NonZeroU16, NonZeroU32};
use std::ops::Range;
-use std::os::unix::io::{AsRawFd, IntoRawFd};
+use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
use std::os::unix::raw::pid_t;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex, Weak, LazyLock};
@@ -1405,7 +1404,7 @@
let stream = VsockStream::connect_with_cid_port(self.instance.cid, port)
.context("Failed to connect")
.or_service_specific_exception(-1)?;
- vsock_stream_to_pfd(stream)
+ Ok(vsock_stream_to_pfd(stream))
}
fn setHostConsoleName(&self, ptsname: &str) -> binder::Result<()> {
@@ -1564,12 +1563,10 @@
}
/// Converts a `VsockStream` to a `ParcelFileDescriptor`.
-fn vsock_stream_to_pfd(stream: VsockStream) -> binder::Result<ParcelFileDescriptor> {
- let owned_fd = take_fd_ownership(stream.into_raw_fd())
- .context("Failed to take ownership of the vsock stream")
- .with_log()
- .or_service_specific_exception(-1)?;
- Ok(ParcelFileDescriptor::new(owned_fd))
+fn vsock_stream_to_pfd(stream: VsockStream) -> ParcelFileDescriptor {
+ // SAFETY: ownership is transferred from stream to f
+ let f = unsafe { File::from_raw_fd(stream.into_raw_fd()) };
+ ParcelFileDescriptor::new(f)
}
/// Parses the platform version requirement string.
diff --git a/android/virtmgr/src/main.rs b/android/virtmgr/src/main.rs
index e4a96ac..67e7282 100644
--- a/android/virtmgr/src/main.rs
+++ b/android/virtmgr/src/main.rs
@@ -25,16 +25,16 @@
use crate::aidl::{GLOBAL_SERVICE, VirtualizationService};
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualizationService::BnVirtualizationService;
-use anyhow::{bail, Result};
+use anyhow::{bail, Context, Result};
use binder::{BinderFeatures, ProcessState};
use log::{info, LevelFilter};
use rpcbinder::{FileDescriptorTransportMode, RpcServer};
-use std::os::unix::io::{AsFd, RawFd};
+use std::os::unix::io::{AsFd, FromRawFd, OwnedFd, RawFd};
use std::sync::LazyLock;
use clap::Parser;
+use nix::fcntl::{fcntl, F_GETFD, F_SETFD, FdFlag};
use nix::unistd::{write, Pid, Uid};
use std::os::unix::raw::{pid_t, uid_t};
-use safe_ownedfd::take_fd_ownership;
const LOG_TAG: &str = "virtmgr";
@@ -71,6 +71,32 @@
ready_fd: RawFd,
}
+fn take_fd_ownership(raw_fd: RawFd, owned_fds: &mut Vec<RawFd>) -> Result<OwnedFd, anyhow::Error> {
+ // Basic check that the integer value does correspond to a file descriptor.
+ fcntl(raw_fd, F_GETFD).with_context(|| format!("Invalid file descriptor {raw_fd}"))?;
+
+ // The file descriptor had CLOEXEC disabled to be inherited from the parent.
+ // Re-enable it to make sure it is not accidentally inherited further.
+ fcntl(raw_fd, F_SETFD(FdFlag::FD_CLOEXEC))
+ .with_context(|| format!("Could not set CLOEXEC on file descriptor {raw_fd}"))?;
+
+ // Creating OwnedFd for stdio FDs is not safe.
+ if [libc::STDIN_FILENO, libc::STDOUT_FILENO, libc::STDERR_FILENO].contains(&raw_fd) {
+ bail!("File descriptor {raw_fd} is standard I/O descriptor");
+ }
+
+ // Reject RawFds that already have a corresponding OwnedFd.
+ if owned_fds.contains(&raw_fd) {
+ bail!("File descriptor {raw_fd} already owned");
+ }
+ owned_fds.push(raw_fd);
+
+ // SAFETY: Initializing OwnedFd for a RawFd provided in cmdline arguments.
+ // We checked that the integer value corresponds to a valid FD and that this
+ // is the first argument to claim its ownership.
+ Ok(unsafe { OwnedFd::from_raw_fd(raw_fd) })
+}
+
fn check_vm_support() -> Result<()> {
if hypervisor_props::is_any_vm_supported()? {
Ok(())
@@ -94,9 +120,11 @@
let args = Args::parse();
- let rpc_server_fd =
- take_fd_ownership(args.rpc_server_fd).expect("Failed to take ownership of rpc_server_fd");
- let ready_fd = take_fd_ownership(args.ready_fd).expect("Failed to take ownership of ready_fd");
+ let mut owned_fds = vec![];
+ let rpc_server_fd = take_fd_ownership(args.rpc_server_fd, &mut owned_fds)
+ .expect("Failed to take ownership of rpc_server_fd");
+ let ready_fd = take_fd_ownership(args.ready_fd, &mut owned_fds)
+ .expect("Failed to take ownership of ready_fd");
// Start thread pool for kernel Binder connection to VirtualizationServiceInternal.
ProcessState::start_thread_pool();
diff --git a/docs/img/pvm-dice.png b/docs/img/pvm-dice.png
new file mode 100644
index 0000000..5b26038
--- /dev/null
+++ b/docs/img/pvm-dice.png
Binary files differ
diff --git a/docs/pvm_dice_chain.md b/docs/pvm_dice_chain.md
new file mode 100644
index 0000000..11cdb6f
--- /dev/null
+++ b/docs/pvm_dice_chain.md
@@ -0,0 +1,52 @@
+# pVM DICE Chain
+
+Unlike KeyMint, which only needs a vendor DICE chain, the pVM DICE
+chain combines the vendor's DICE chain with additional pVM DICE nodes
+describing the protected VM's environment.
+
+![][pvm-dice-chain-img]
+
+The full RKP VM DICE chain, starting from `UDS_Pub` rooted in ROM, is
+sent to the RKP server during [pVM remote attestation][vm-attestation].
+
+[vm-attestation]: vm_remote_attestation.md
+[pvm-dice-chain-img]: img/pvm-dice.png
+
+## Key derivation
+
+Key derivation is a critical step in the DICE handover process within
+[pvmfw][pvmfw]. Vendors need to ensure that both pvmfw and their final DICE
+node use the same method to derive a key pair from `CDI_Attest` in order to
+maintain a valid certificate chain. Pvmfw use [open-dice][open-dice] with the
+following formula:
+
+```
+CDI_Attest_pub, CDI_Attest_priv = KDF_ASYM(KDF(CDI_Attest))
+```
+
+Where KDF = HKDF-SHA-512 (RFC 5869).
+
+Currently, KDF_ASYM = Ed25519, but EC p-384 and p-256 (RFC 6979) support is
+coming soon.
+
+Vendors must use a supported algorithm for the last DICE node to ensure
+compatibility and chain integrity.
+
+[pvmfw]: ../guest/pvmfw
+[open-dice]: https://cs.android.com/android/platform/superproject/main/+/main:external/open-dice/
+
+## Testing
+
+To verify that the DICE handover is successful in pvmfw and eventually the pVM
+has a valid DICE chain, you can run the VSR test
+`MicrodroidTests#protectedVmHasValidDiceChain`. The test retrieves the DICE
+chain from within a Microdroid VM in protected mode and checks the following
+properties using the [hwtrust][hwtrust] library:
+
+1. All the fields in the DICE chain conform to
+ [Android Profile for DICE][android-open-dice].
+2. The DICE chain is a valid certificate chain, where the subject public key in
+ each certificate can be used to verify the signature of the next certificate.
+
+[hwtrust]: https://cs.android.com/android/platform/superproject/main/+/main:tools/security/remote_provisioning/hwtrust/
+[android-open-dice]: https://android.googlesource.com/platform/external/open-dice/+/refs/heads/main/docs/android.md
diff --git a/guest/authfs_service/Android.bp b/guest/authfs_service/Android.bp
index e508c17..2101a36 100644
--- a/guest/authfs_service/Android.bp
+++ b/guest/authfs_service/Android.bp
@@ -18,7 +18,6 @@
"libnix",
"librpcbinder_rs",
"librustutils",
- "libsafe_ownedfd",
"libshared_child",
],
prefer_rlib: true,
diff --git a/guest/authfs_service/src/authfs.rs b/guest/authfs_service/src/authfs.rs
index cfd5766..f2638c2 100644
--- a/guest/authfs_service/src/authfs.rs
+++ b/guest/authfs_service/src/authfs.rs
@@ -89,12 +89,9 @@
&config.outputDirFdAnnotations,
debuggable,
)?;
- wait_until_authfs_ready(&child, &mountpoint).map_err(|e| {
- match child.wait() {
- Ok(status) => debug!("Wait for authfs: {}", status),
- Err(e) => warn!("Failed to wait for child: {}", e),
- }
- e
+ wait_until_authfs_ready(&child, &mountpoint).inspect_err(|_| match child.wait() {
+ Ok(status) => debug!("Wait for authfs: {}", status),
+ Err(e) => warn!("Failed to wait for child: {}", e),
})?;
let authfs = AuthFs { mountpoint, process: child };
diff --git a/guest/authfs_service/src/main.rs b/guest/authfs_service/src/main.rs
index ff2f770..97e684d 100644
--- a/guest/authfs_service/src/main.rs
+++ b/guest/authfs_service/src/main.rs
@@ -26,10 +26,9 @@
use log::*;
use rpcbinder::RpcServer;
use rustutils::sockets::android_get_control_socket;
-use safe_ownedfd::take_fd_ownership;
use std::ffi::OsString;
use std::fs::{create_dir, read_dir, remove_dir_all, remove_file};
-use std::os::unix::io::OwnedFd;
+use std::os::unix::io::{FromRawFd, OwnedFd};
use std::sync::atomic::{AtomicUsize, Ordering};
use authfs_aidl_interface::aidl::com::android::virt::fs::AuthFsConfig::AuthFsConfig;
@@ -110,9 +109,22 @@
}
/// Prepares a socket file descriptor for the authfs service.
-fn prepare_authfs_service_socket() -> Result<OwnedFd> {
+///
+/// # Safety requirement
+///
+/// The caller must ensure that this function is the only place that claims ownership
+/// of the file descriptor and it is called only once.
+unsafe fn prepare_authfs_service_socket() -> Result<OwnedFd> {
let raw_fd = android_get_control_socket(AUTHFS_SERVICE_SOCKET_NAME)?;
- Ok(take_fd_ownership(raw_fd)?)
+
+ // Creating OwnedFd for stdio FDs is not safe.
+ if [libc::STDIN_FILENO, libc::STDOUT_FILENO, libc::STDERR_FILENO].contains(&raw_fd) {
+ bail!("File descriptor {raw_fd} is standard I/O descriptor");
+ }
+ // SAFETY: Initializing OwnedFd for a RawFd created by the init.
+ // We checked that the integer value corresponds to a valid FD and that the caller
+ // ensures that this is the only place to claim its ownership.
+ Ok(unsafe { OwnedFd::from_raw_fd(raw_fd) })
}
#[allow(clippy::eq_op)]
@@ -125,7 +137,8 @@
clean_up_working_directory()?;
- let socket_fd = prepare_authfs_service_socket()?;
+ // SAFETY: This is the only place we take the ownership of the fd of the authfs service.
+ let socket_fd = unsafe { prepare_authfs_service_socket()? };
let service = AuthFsService::new_binder(debuggable).as_binder();
debug!("{} is starting as a rpc service.", AUTHFS_SERVICE_SOCKET_NAME);
let server = RpcServer::new_bound_socket(service, socket_fd)?;
diff --git a/guest/microdroid_manager/Android.bp b/guest/microdroid_manager/Android.bp
index 82e26b7..9c9a3d0 100644
--- a/guest/microdroid_manager/Android.bp
+++ b/guest/microdroid_manager/Android.bp
@@ -48,7 +48,6 @@
"libprotobuf",
"librpcbinder_rs",
"librustutils",
- "libsafe_ownedfd",
"libsecretkeeper_client",
"libsecretkeeper_comm_nostd",
"libscopeguard",
@@ -60,7 +59,6 @@
"libvsock",
"librand",
"libzeroize",
- "libsafe_ownedfd",
],
init_rc: ["microdroid_manager.rc"],
multilib: {
diff --git a/guest/microdroid_manager/src/main.rs b/guest/microdroid_manager/src/main.rs
index d12bfd3..7352a2c 100644
--- a/guest/microdroid_manager/src/main.rs
+++ b/guest/microdroid_manager/src/main.rs
@@ -50,14 +50,13 @@
use rustutils::sockets::android_get_control_socket;
use rustutils::system_properties;
use rustutils::system_properties::PropertyWatcher;
-use safe_ownedfd::take_fd_ownership;
use secretkeeper_comm::data_types::ID_SIZE;
use std::borrow::Cow::{Borrowed, Owned};
use std::env;
use std::ffi::CString;
use std::fs::{self, create_dir, File, OpenOptions};
use std::io::{Read, Write};
-use std::os::unix::io::OwnedFd;
+use std::os::unix::io::{FromRawFd, OwnedFd};
use std::os::unix::process::CommandExt;
use std::os::unix::process::ExitStatusExt;
use std::path::Path;
@@ -200,7 +199,13 @@
);
info!("started.");
- let vm_payload_service_fd = prepare_vm_payload_service_socket()?;
+ // SAFETY: This is the only place we take the ownership of the fd of the vm payload service.
+ //
+ // To ensure that the CLOEXEC flag is set on the file descriptor as early as possible,
+ // it is necessary to fetch the socket corresponding to vm_payload_service at the
+ // very beginning, as android_get_control_socket() sets the CLOEXEC flag on the file
+ // descriptor.
+ let vm_payload_service_fd = unsafe { prepare_vm_payload_service_socket()? };
load_crashkernel_if_supported().context("Failed to load crashkernel")?;
@@ -482,9 +487,22 @@
}
/// Prepares a socket file descriptor for the vm payload service.
-fn prepare_vm_payload_service_socket() -> Result<OwnedFd> {
+///
+/// # Safety
+///
+/// The caller must ensure that this function is the only place that claims ownership
+/// of the file descriptor and it is called only once.
+unsafe fn prepare_vm_payload_service_socket() -> Result<OwnedFd> {
let raw_fd = android_get_control_socket(VM_PAYLOAD_SERVICE_SOCKET_NAME)?;
- Ok(take_fd_ownership(raw_fd)?)
+
+ // Creating OwnedFd for stdio FDs is not safe.
+ if [libc::STDIN_FILENO, libc::STDOUT_FILENO, libc::STDERR_FILENO].contains(&raw_fd) {
+ bail!("File descriptor {raw_fd} is standard I/O descriptor");
+ }
+ // SAFETY: Initializing OwnedFd for a RawFd created by the init.
+ // We checked that the integer value corresponds to a valid FD and that the caller
+ // ensures that this is the only place to claim its ownership.
+ Ok(unsafe { OwnedFd::from_raw_fd(raw_fd) })
}
fn is_strict_boot() -> bool {
diff --git a/guest/pvmfw/README.md b/guest/pvmfw/README.md
index 4712d77..58ba10c 100644
--- a/guest/pvmfw/README.md
+++ b/guest/pvmfw/README.md
@@ -251,10 +251,13 @@
}
```
-and contains the _Compound Device Identifiers_ ("CDIs"), used to derive the
-next-stage secret, and a certificate chain, intended for pVM attestation. Note
-that it differs from the `AndroidDiceHandover` defined by the specification in
-that its `DiceCertChain` field is mandatory (while optional in the original).
+It contains the _Compound Device Identifiers_ (CDIs), used for deriving the
+next-stage secret, and a certificate chain, necessary for building the full
+[pVM DICE chain][pvm-dice-chain] required by features like
+[pVM remote attestation][vm-attestation].
+
+Note that it differs from the `AndroidDiceHandover` defined by the specification
+in that its `DiceCertChain` field is mandatory (while optional in the original).
Devices that fully implement DICE should provide a certificate rooted at the
Unique Device Secret (UDS) in a boot stage preceding the pvmfw loader (typically
@@ -262,16 +265,6 @@
can be passed to [`DiceAndroidHandoverMainFlow`][DiceAndroidHandoverMainFlow] along with
the inputs described below.
-Otherwise, as an intermediate step towards supporting DICE throughout the
-software stack of the device, incomplete implementations may root the DICE chain
-at the pvmfw loader, using an arbitrary constant as initial CDI. The pvmfw
-loader can easily do so by:
-
-1. Building an "empty" `AndroidDiceHandover` using CBOR operations only
- containing constant CDIs ([example][Trusty-BCC])
-1. Passing the resulting `AndroidDiceHandover` to `DiceAndroidHandoverMainFlow`
- as described above
-
The recommended DICE inputs at this stage are:
- **Code**: hash of the pvmfw image, hypervisor (`boot.img`), and other target
@@ -291,19 +284,6 @@
`/reserved-memory` device tree node marked as
[`compatible=”google,open-dice”`][dice-dt].
-#### Testing
-
-To verify that the DICE handover is successful in pvmfw and eventually the pVM
-has a valid DICE chain, you can run the VSR test
-`MicrodroidTests#protectedVmHasValidDiceChain`. The test retrieves the DICE
-chain from within a Microdroid VM in protected mode and checks the following
-properties using the [hwtrust][hwtrust] library:
-
-1. All the fields in the DICE chain conform to
- [Android Profile for DICE][android-open-dice].
-2. The DICE chain is a valid certificate chain, where the subject public key in
- each certificate can be used to verify the signature of the next certificate.
-
[AVB]: https://source.android.com/docs/security/features/verifiedboot/boot-flow
[AndroidDiceHandover]: https://pigweed.googlesource.com/open-dice/+/42ae7760023/src/android.c#212
[DiceAndroidHandoverMainFlow]: https://pigweed.googlesource.com/open-dice/+/42ae7760023/src/android.c#221
@@ -311,9 +291,8 @@
[dice-mode]: https://pigweed.googlesource.com/open-dice/+/refs/heads/main/docs/specification.md#Mode-Value-Details
[dice-dt]: https://www.kernel.org/doc/Documentation/devicetree/bindings/reserved-memory/google%2Copen-dice.yaml
[Layering]: https://pigweed.googlesource.com/open-dice/+/refs/heads/main/docs/specification.md#layering-details
-[Trusty-BCC]: https://android.googlesource.com/trusty/lib/+/1696be0a8f3a7103/lib/hwbcc/common/swbcc.c#554
-[hwtrust]: https://cs.android.com/android/platform/superproject/main/+/main:tools/security/remote_provisioning/hwtrust/
-[android-open-dice]: https://android.googlesource.com/platform/external/open-dice/+/refs/heads/main/docs/android.md
+[pvm-dice-chain]: ../../docs/pvm_dice_chain.md
+[vm-attestation]: ../../docs/vm_remote_attestation.md
### Platform Requirements
diff --git a/guest/rialto/src/main.rs b/guest/rialto/src/main.rs
index a98ec25..7de8718 100644
--- a/guest/rialto/src/main.rs
+++ b/guest/rialto/src/main.rs
@@ -109,31 +109,27 @@
let fdt = libfdt::Fdt::from_slice(fdt)?;
let memory_range = fdt.first_memory_range()?;
- MEMORY.lock().as_mut().unwrap().shrink(&memory_range).map_err(|e| {
+ MEMORY.lock().as_mut().unwrap().shrink(&memory_range).inspect_err(|_| {
error!("Failed to use memory range value from DT: {memory_range:#x?}");
- e
})?;
if let Some(mem_sharer) = get_mem_sharer() {
let granule = mem_sharer.granule()?;
- MEMORY.lock().as_mut().unwrap().init_dynamic_shared_pool(granule).map_err(|e| {
+ MEMORY.lock().as_mut().unwrap().init_dynamic_shared_pool(granule).inspect_err(|_| {
error!("Failed to initialize dynamically shared pool.");
- e
})?;
} else if let Ok(swiotlb_info) = SwiotlbInfo::new_from_fdt(fdt) {
let range = swiotlb_info.fixed_range().ok_or_else(|| {
error!("Pre-shared pool range not specified in swiotlb node");
Error::from(FdtError::BadValue)
})?;
- MEMORY.lock().as_mut().unwrap().init_static_shared_pool(range).map_err(|e| {
+ MEMORY.lock().as_mut().unwrap().init_static_shared_pool(range).inspect_err(|_| {
error!("Failed to initialize pre-shared pool.");
- e
})?;
} else {
info!("No MEM_SHARE capability detected or swiotlb found: allocating buffers from heap.");
- MEMORY.lock().as_mut().unwrap().init_heap_shared_pool().map_err(|e| {
+ MEMORY.lock().as_mut().unwrap().init_heap_shared_pool().inspect_err(|_| {
error!("Failed to initialize heap-based pseudo-shared pool.");
- e
})?;
}
@@ -153,9 +149,8 @@
let res = unsafe {
MEMORY.lock().as_mut().unwrap().alloc_range_outside_main_memory(&dice_range)
};
- res.map_err(|e| {
+ res.inspect_err(|_| {
error!("Failed to use DICE range from DT: {dice_range:#x?}");
- e
})?;
let dice_start = dice_range.start as *const u8;
// SAFETY: There's no memory overlap and the region is mapped as read-only data.
diff --git a/libs/libfdt/src/libfdt.rs b/libs/libfdt/src/libfdt.rs
index b2250f5..6869af6 100644
--- a/libs/libfdt/src/libfdt.rs
+++ b/libs/libfdt/src/libfdt.rs
@@ -292,7 +292,7 @@
// SAFETY: Accesses (read-only) are constrained to the DT totalsize.
let ret = unsafe { libfdt_bindgen::fdt_find_max_phandle(fdt, &mut phandle) };
- FdtRawResult::from(ret).try_into()?;
+ () = FdtRawResult::from(ret).try_into()?;
phandle.try_into()
}
@@ -390,7 +390,7 @@
// SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
unsafe { libfdt_bindgen::fdt_setprop_placeholder(fdt, node, name, len, &mut data) };
- FdtRawResult::from(ret).try_into()?;
+ () = FdtRawResult::from(ret).try_into()?;
get_mut_slice_at_ptr(self.as_fdt_slice_mut(), data.cast(), size).ok_or(FdtError::Internal)
}
diff --git a/libs/libsafe_ownedfd/Android.bp b/libs/libsafe_ownedfd/Android.bp
deleted file mode 100644
index 53e14dc..0000000
--- a/libs/libsafe_ownedfd/Android.bp
+++ /dev/null
@@ -1,38 +0,0 @@
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-rust_defaults {
- name: "libsafe_ownedfd.defaults",
- crate_name: "safe_ownedfd",
- srcs: ["src/lib.rs"],
- edition: "2021",
- rustlibs: [
- "libnix",
- "libthiserror",
- ],
-}
-
-rust_library {
- name: "libsafe_ownedfd",
- defaults: ["libsafe_ownedfd.defaults"],
- apex_available: [
- "com.android.compos",
- "com.android.microfuchsia",
- "com.android.virt",
- ],
-}
-
-rust_test {
- name: "libsafe_ownedfd.test",
- defaults: ["libsafe_ownedfd.defaults"],
- rustlibs: [
- "libanyhow",
- "libtempfile",
- ],
- host_supported: true,
- test_suites: ["general-tests"],
- test_options: {
- unit_test: true,
- },
-}
diff --git a/libs/libsafe_ownedfd/src/lib.rs b/libs/libsafe_ownedfd/src/lib.rs
deleted file mode 100644
index 52ae180..0000000
--- a/libs/libsafe_ownedfd/src/lib.rs
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2024, The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! Library for a safer conversion from `RawFd` to `OwnedFd`
-
-use nix::fcntl::{fcntl, FdFlag, F_DUPFD, F_GETFD, F_SETFD};
-use nix::libc;
-use nix::unistd::close;
-use std::os::fd::FromRawFd;
-use std::os::fd::OwnedFd;
-use std::os::fd::RawFd;
-use std::sync::Mutex;
-use thiserror::Error;
-
-/// Errors that can occur while taking an ownership of `RawFd`
-#[derive(Debug, PartialEq, Error)]
-pub enum Error {
- /// RawFd is not a valid file descriptor
- #[error("{0} is not a file descriptor")]
- Invalid(RawFd),
-
- /// RawFd is either stdio, stdout, or stderr
- #[error("standard IO descriptors cannot be owned")]
- StdioNotAllowed,
-
- /// Generic UNIX error
- #[error("UNIX error")]
- Errno(#[from] nix::errno::Errno),
-}
-
-static LOCK: Mutex<()> = Mutex::new(());
-
-/// Takes the ownership of `RawFd` and converts it to `OwnedFd`. It is important to know that
-/// `RawFd` is closed when this function successfully returns. The raw file descriptor of the
-/// returned `OwnedFd` is different from `RawFd`. The returned file descriptor is CLOEXEC set.
-pub fn take_fd_ownership(raw_fd: RawFd) -> Result<OwnedFd, Error> {
- fcntl(raw_fd, F_GETFD).map_err(|_| Error::Invalid(raw_fd))?;
-
- if [libc::STDIN_FILENO, libc::STDOUT_FILENO, libc::STDERR_FILENO].contains(&raw_fd) {
- return Err(Error::StdioNotAllowed);
- }
-
- // sync is needed otherwise we can create multiple OwnedFds out of the same RawFd
- let lock = LOCK.lock().unwrap();
- let new_fd = fcntl(raw_fd, F_DUPFD(raw_fd))?;
- close(raw_fd)?;
- drop(lock);
-
- // This is not essential, but let's follow the common practice in the Rust ecosystem
- fcntl(new_fd, F_SETFD(FdFlag::FD_CLOEXEC)).map_err(Error::Errno)?;
-
- // SAFETY: In this function, we have checked that RawFd is actually an open file descriptor and
- // this is the first time to claim its ownership because we just created it by duping.
- Ok(unsafe { OwnedFd::from_raw_fd(new_fd) })
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use anyhow::Result;
- use nix::fcntl::{fcntl, FdFlag, F_GETFD, F_SETFD};
- use std::os::fd::AsRawFd;
- use std::os::fd::IntoRawFd;
- use tempfile::tempfile;
-
- #[test]
- fn good_fd() -> Result<()> {
- let raw_fd = tempfile()?.into_raw_fd();
- assert!(take_fd_ownership(raw_fd).is_ok());
- Ok(())
- }
-
- #[test]
- fn invalid_fd() -> Result<()> {
- let raw_fd = 12345; // randomly chosen
- assert_eq!(take_fd_ownership(raw_fd).unwrap_err(), Error::Invalid(raw_fd));
- Ok(())
- }
-
- #[test]
- fn original_fd_closed() -> Result<()> {
- let raw_fd = tempfile()?.into_raw_fd();
- let owned_fd = take_fd_ownership(raw_fd)?;
- assert_ne!(raw_fd, owned_fd.as_raw_fd());
- assert!(fcntl(raw_fd, F_GETFD).is_err());
- Ok(())
- }
-
- #[test]
- fn cannot_use_same_rawfd_multiple_times() -> Result<()> {
- let raw_fd = tempfile()?.into_raw_fd();
-
- let owned_fd = take_fd_ownership(raw_fd); // once
- let owned_fd2 = take_fd_ownership(raw_fd); // twice
-
- assert!(owned_fd.is_ok());
- assert!(owned_fd2.is_err());
- Ok(())
- }
-
- #[test]
- fn cloexec() -> Result<()> {
- let raw_fd = tempfile()?.into_raw_fd();
-
- // intentionally clear cloexec to see if it is set by take_fd_ownership
- fcntl(raw_fd, F_SETFD(FdFlag::empty()))?;
- let flags = fcntl(raw_fd, F_GETFD)?;
- assert_eq!(flags, FdFlag::empty().bits());
-
- let owned_fd = take_fd_ownership(raw_fd)?;
- let flags = fcntl(owned_fd.as_raw_fd(), F_GETFD)?;
- assert_eq!(flags, FdFlag::FD_CLOEXEC.bits());
- drop(owned_fd);
- Ok(())
- }
-}
diff --git a/microfuchsia/microfuchsiad/Android.bp b/microfuchsia/microfuchsiad/Android.bp
index ab3f865..ddf360d 100644
--- a/microfuchsia/microfuchsiad/Android.bp
+++ b/microfuchsia/microfuchsiad/Android.bp
@@ -15,9 +15,8 @@
"libandroid_logger",
"libanyhow",
"libbinder_rs",
- "liblibc",
"liblog_rust",
- "libsafe_ownedfd",
+ "liblibc",
"libvmclient",
],
apex_available: [
diff --git a/microfuchsia/microfuchsiad/src/instance_starter.rs b/microfuchsia/microfuchsiad/src/instance_starter.rs
index 6688447..15fcc06 100644
--- a/microfuchsia/microfuchsiad/src/instance_starter.rs
+++ b/microfuchsia/microfuchsiad/src/instance_starter.rs
@@ -23,10 +23,9 @@
use anyhow::{ensure, Context, Result};
use binder::{LazyServiceGuard, ParcelFileDescriptor};
use log::info;
-use safe_ownedfd::take_fd_ownership;
use std::ffi::CStr;
use std::fs::File;
-use std::os::fd::AsRawFd;
+use std::os::fd::FromRawFd;
use vmclient::VmInstance;
pub struct MicrofuchsiaInstance {
@@ -134,7 +133,6 @@
"failed to openpty"
);
}
- let leader = take_fd_ownership(leader)?;
// SAFETY: calling these libc functions with valid+initialized variables is safe.
unsafe {
@@ -147,25 +145,24 @@
c_line: 0,
c_cc: [0u8; 19],
};
- ensure!(
- libc::tcgetattr(leader.as_raw_fd(), &mut attr) == 0,
- "failed to get termios attributes"
- );
+ ensure!(libc::tcgetattr(leader, &mut attr) == 0, "failed to get termios attributes");
// Force it to be a raw pty and re-set it.
libc::cfmakeraw(&mut attr);
ensure!(
- libc::tcsetattr(leader.as_raw_fd(), libc::TCSANOW, &attr) == 0,
+ libc::tcsetattr(leader, libc::TCSANOW, &attr) == 0,
"failed to set termios attributes"
);
}
// Construct the return value.
+ // SAFETY: The file descriptors are valid because openpty returned without error (above).
+ let leader = unsafe { File::from_raw_fd(leader) };
let follower_name: Vec<u8> = follower_name.iter_mut().map(|x| *x as _).collect();
let follower_name = CStr::from_bytes_until_nul(&follower_name)
.context("pty filename missing NUL")?
.to_str()
.context("pty filename invalid utf8")?
.to_string();
- Ok(Pty { leader: File::from(leader), follower_name })
+ Ok(Pty { leader, follower_name })
}