Revert changes about libsafe_ownedfd

It actually was an unsafe abstraction over OwnedFd::from_raw_fd.

This change reverts following changes:

Revert "Remove the use of from_raw_fd from fd_server/aidl.rs"

This reverts commit 105153e486d7d2dfded4d0c41b22fb2bc493a5ee.

Revert "Remove yet another use of from_raw_fd"

This reverts commit abdbd756f696a1c0d0035d1a80b3d6e827c635f0.

Revert "Don't use unsafe raw_from_fd"

This reverts commit 2867dd3e838fb4deb71f335a15e0c9dc2d617240.

Revert "Remove one more use of from_raw_fd"

This reverts commit 9ef2732fb3d55ee6b085e4a02cfbb1078b041ef8.

Revert "Use take_fd_ownership instead of the unsafe from_raw_fd"

This reverts commit ba3099ec10003d6bb2c84138bbb422997142466d.

Revert "Add libsafe_ownedfd crate"

This reverts commit 1743878cd20564e42fe41e4fbaefcb964bf83e02.

Bug: 243500154
Test: N/A
Change-Id: I4e12876518a337f1f14dc1301de909b8ace28282
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/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/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/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 })
 }