1 // Copyright 2020 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 use std::convert::TryFrom;
6 use std::fs::File;
7 use std::io::Stderr;
8 use std::io::Stdin;
9 use std::io::Stdout;
10 use std::net::TcpListener;
11 use std::net::TcpStream;
12 use std::net::UdpSocket;
13 use std::ops::Drop;
14 use std::os::fd::OwnedFd;
15 use std::os::unix::io::AsRawFd;
16 use std::os::unix::io::FromRawFd;
17 use std::os::unix::io::IntoRawFd;
18 use std::os::unix::io::RawFd;
19 use std::os::unix::net::UnixDatagram;
20 use std::os::unix::net::UnixListener;
21 use std::os::unix::net::UnixStream;
22
23 use crate::descriptor::AsRawDescriptor;
24 use crate::descriptor::Descriptor;
25 use crate::descriptor::FromRawDescriptor;
26 use crate::descriptor::IntoRawDescriptor;
27 use crate::descriptor::SafeDescriptor;
28 use crate::errno::errno_result;
29 use crate::errno::Result;
30
31 pub type RawDescriptor = RawFd;
32
33 pub const INVALID_DESCRIPTOR: RawDescriptor = -1;
34
35 /// Clones `descriptor`, returning a new `SafeDescriptor` that refers to the same file
36 /// `descriptor`. The cloned descriptor will have the `FD_CLOEXEC` flag set but will not share any
37 /// other file descriptor flags with `descriptor`.
clone_descriptor(descriptor: &(impl AsRawDescriptor + ?Sized)) -> Result<SafeDescriptor>38 pub fn clone_descriptor(descriptor: &(impl AsRawDescriptor + ?Sized)) -> Result<SafeDescriptor> {
39 clone_fd(descriptor.as_raw_descriptor())
40 }
41
42 /// Clones `fd`, returning a new file descriptor that refers to the same open file as `fd`. The
43 /// cloned fd will have the `FD_CLOEXEC` flag set but will not share any other file descriptor
44 /// flags with `fd`.
clone_fd(fd: RawFd) -> Result<SafeDescriptor>45 fn clone_fd(fd: RawFd) -> Result<SafeDescriptor> {
46 // SAFETY:
47 // Safe because this doesn't modify any memory and we check the return value.
48 let ret = unsafe { libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, 0) };
49 if ret < 0 {
50 errno_result()
51 } else {
52 // SAFETY: We just dup'd the FD and so have exclusive access.
53 Ok(unsafe { SafeDescriptor::from_raw_descriptor(ret) })
54 }
55 }
56
57 /// Adds CLOEXEC flag on descriptor
set_descriptor_cloexec<A: AsRawDescriptor>(fd_owner: &A) -> Result<()>58 pub fn set_descriptor_cloexec<A: AsRawDescriptor>(fd_owner: &A) -> Result<()> {
59 modify_descriptor_flags(fd_owner.as_raw_descriptor(), |flags| {
60 flags | libc::FD_CLOEXEC
61 })
62 }
63
64 /// Clears CLOEXEC flag on descriptor
clear_descriptor_cloexec<A: AsRawDescriptor>(fd_owner: &A) -> Result<()>65 pub fn clear_descriptor_cloexec<A: AsRawDescriptor>(fd_owner: &A) -> Result<()> {
66 modify_descriptor_flags(fd_owner.as_raw_descriptor(), |flags| {
67 flags & !libc::FD_CLOEXEC
68 })
69 }
70
71 /// Apply the specified modification to the file descriptor's flags.
modify_descriptor_flags( desc: RawDescriptor, modify_flags: impl FnOnce(libc::c_int) -> libc::c_int, ) -> Result<()>72 fn modify_descriptor_flags(
73 desc: RawDescriptor,
74 modify_flags: impl FnOnce(libc::c_int) -> libc::c_int,
75 ) -> Result<()> {
76 // SAFETY:
77 // Safe because fd is read only.
78 let flags = unsafe { libc::fcntl(desc, libc::F_GETFD) };
79 if flags == -1 {
80 return errno_result();
81 }
82
83 let new_flags = modify_flags(flags);
84
85 // SAFETY:
86 // Safe because this has no side effect(s) on the current process.
87 if new_flags != flags && unsafe { libc::fcntl(desc, libc::F_SETFD, new_flags) } == -1 {
88 errno_result()
89 } else {
90 Ok(())
91 }
92 }
93
94 impl Drop for SafeDescriptor {
drop(&mut self)95 fn drop(&mut self) {
96 // SAFETY:
97 // Safe because descriptor is valid.
98 let _ = unsafe { libc::close(self.descriptor) };
99 }
100 }
101
102 impl AsRawFd for SafeDescriptor {
as_raw_fd(&self) -> RawFd103 fn as_raw_fd(&self) -> RawFd {
104 self.as_raw_descriptor()
105 }
106 }
107
108 impl TryFrom<&dyn AsRawFd> for SafeDescriptor {
109 type Error = std::io::Error;
110
try_from(fd: &dyn AsRawFd) -> std::result::Result<Self, Self::Error>111 fn try_from(fd: &dyn AsRawFd) -> std::result::Result<Self, Self::Error> {
112 Ok(clone_fd(fd.as_raw_fd())?)
113 }
114 }
115
116 impl SafeDescriptor {
117 /// Clones this descriptor, internally creating a new descriptor. The new SafeDescriptor will
118 /// share the same underlying count within the kernel.
try_clone(&self) -> Result<SafeDescriptor>119 pub fn try_clone(&self) -> Result<SafeDescriptor> {
120 // SAFETY:
121 // Safe because this doesn't modify any memory and we check the return value.
122 let descriptor = unsafe { libc::fcntl(self.descriptor, libc::F_DUPFD_CLOEXEC, 0) };
123 if descriptor < 0 {
124 errno_result()
125 } else {
126 Ok(SafeDescriptor { descriptor })
127 }
128 }
129 }
130
131 impl From<SafeDescriptor> for File {
from(s: SafeDescriptor) -> File132 fn from(s: SafeDescriptor) -> File {
133 // SAFETY:
134 // Safe because we own the SafeDescriptor at this point.
135 unsafe { File::from_raw_fd(s.into_raw_descriptor()) }
136 }
137 }
138
139 impl From<SafeDescriptor> for TcpListener {
from(s: SafeDescriptor) -> Self140 fn from(s: SafeDescriptor) -> Self {
141 // SAFETY:
142 // Safe because we own the SafeDescriptor at this point.
143 unsafe { Self::from_raw_fd(s.into_raw_descriptor()) }
144 }
145 }
146
147 impl From<SafeDescriptor> for TcpStream {
from(s: SafeDescriptor) -> Self148 fn from(s: SafeDescriptor) -> Self {
149 // SAFETY:
150 // Safe because we own the SafeDescriptor at this point.
151 unsafe { Self::from_raw_fd(s.into_raw_descriptor()) }
152 }
153 }
154
155 impl From<SafeDescriptor> for UnixStream {
from(s: SafeDescriptor) -> Self156 fn from(s: SafeDescriptor) -> Self {
157 // SAFETY:
158 // Safe because we own the SafeDescriptor at this point.
159 unsafe { Self::from_raw_fd(s.into_raw_descriptor()) }
160 }
161 }
162
163 impl From<SafeDescriptor> for OwnedFd {
from(s: SafeDescriptor) -> Self164 fn from(s: SafeDescriptor) -> Self {
165 // SAFETY:
166 // Safe because we own the SafeDescriptor at this point.
167 unsafe { OwnedFd::from_raw_descriptor(s.into_raw_descriptor()) }
168 }
169 }
170
171 impl From<OwnedFd> for SafeDescriptor {
from(fd: OwnedFd) -> Self172 fn from(fd: OwnedFd) -> Self {
173 // SAFETY:
174 // Safe because we own the OwnedFd at this point.
175 unsafe { SafeDescriptor::from_raw_descriptor(fd.into_raw_descriptor()) }
176 }
177 }
178
179 // AsRawFd for interoperability with interfaces that require it. Within crosvm,
180 // always use AsRawDescriptor when possible.
181 impl AsRawFd for Descriptor {
as_raw_fd(&self) -> RawFd182 fn as_raw_fd(&self) -> RawFd {
183 self.0
184 }
185 }
186
187 macro_rules! AsRawDescriptor {
188 ($name:ident) => {
189 impl AsRawDescriptor for $name {
190 fn as_raw_descriptor(&self) -> RawDescriptor {
191 self.as_raw_fd()
192 }
193 }
194 };
195 }
196
197 macro_rules! FromRawDescriptor {
198 ($name:ident) => {
199 impl FromRawDescriptor for $name {
200 unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
201 $name::from_raw_fd(descriptor)
202 }
203 }
204 };
205 }
206
207 macro_rules! IntoRawDescriptor {
208 ($name:ident) => {
209 impl IntoRawDescriptor for $name {
210 fn into_raw_descriptor(self) -> RawDescriptor {
211 self.into_raw_fd()
212 }
213 }
214 };
215 }
216
217 // Implementations for File. This enables the File-type to use
218 // RawDescriptor, but does not mean File should be used as a generic
219 // descriptor container. That should go to either SafeDescriptor or another more
220 // relevant container type.
221 AsRawDescriptor!(File);
222 AsRawDescriptor!(OwnedFd);
223 AsRawDescriptor!(TcpListener);
224 AsRawDescriptor!(TcpStream);
225 AsRawDescriptor!(UdpSocket);
226 AsRawDescriptor!(UnixDatagram);
227 AsRawDescriptor!(UnixListener);
228 AsRawDescriptor!(UnixStream);
229 FromRawDescriptor!(File);
230 FromRawDescriptor!(OwnedFd);
231 FromRawDescriptor!(UnixStream);
232 FromRawDescriptor!(UnixDatagram);
233 IntoRawDescriptor!(File);
234 IntoRawDescriptor!(OwnedFd);
235 IntoRawDescriptor!(UnixDatagram);
236 IntoRawDescriptor!(UnixStream);
237 AsRawDescriptor!(Stdin);
238 AsRawDescriptor!(Stdout);
239 AsRawDescriptor!(Stderr);
240