1 // Copyright 2020 The Chromium OS Authors. All rights reserved.
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::{
6 convert::TryFrom,
7 fs::File,
8 io::{Stderr, Stdin, Stdout},
9 mem,
10 mem::ManuallyDrop,
11 net::UdpSocket,
12 ops::Drop,
13 os::unix::{
14 io::{AsRawFd, FromRawFd, IntoRawFd, RawFd},
15 net::{UnixDatagram, UnixListener, UnixStream},
16 },
17 };
18
19 use serde::{Deserialize, Serialize};
20
21 use super::{
22 errno_result,
23 net::{UnixSeqpacket, UnlinkUnixSeqpacketListener},
24 PollToken, Result,
25 };
26
27 pub type RawDescriptor = RawFd;
28
29 pub const INVALID_DESCRIPTOR: RawDescriptor = -1;
30
31 /// Trait for forfeiting ownership of the current raw descriptor, and returning the raw descriptor
32 pub trait IntoRawDescriptor {
into_raw_descriptor(self) -> RawDescriptor33 fn into_raw_descriptor(self) -> RawDescriptor;
34 }
35
36 /// Trait for returning the underlying raw descriptor, without giving up ownership of the
37 /// descriptor.
38 pub trait AsRawDescriptor {
as_raw_descriptor(&self) -> RawDescriptor39 fn as_raw_descriptor(&self) -> RawDescriptor;
40 }
41
42 pub trait FromRawDescriptor {
43 /// # Safety
44 /// Safe only if the caller ensures nothing has access to the descriptor after passing it to
45 /// `from_raw_descriptor`
from_raw_descriptor(descriptor: RawDescriptor) -> Self46 unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self;
47 }
48
49 /// Clones `descriptor`, returning a new `RawDescriptor` that refers to the same open file
50 /// description as `descriptor`. The cloned descriptor will have the `FD_CLOEXEC` flag set but will
51 /// not share any other file descriptor flags with `descriptor`.
clone_descriptor(descriptor: &dyn AsRawDescriptor) -> Result<RawDescriptor>52 pub fn clone_descriptor(descriptor: &dyn AsRawDescriptor) -> Result<RawDescriptor> {
53 clone_fd(&descriptor.as_raw_descriptor())
54 }
55
56 /// Clones `fd`, returning a new file descriptor that refers to the same open file description as
57 /// `fd`. The cloned fd will have the `FD_CLOEXEC` flag set but will not share any other file
58 /// descriptor flags with `fd`.
clone_fd(fd: &dyn AsRawFd) -> Result<RawFd>59 fn clone_fd(fd: &dyn AsRawFd) -> Result<RawFd> {
60 // Safe because this doesn't modify any memory and we check the return value.
61 let ret = unsafe { libc::fcntl(fd.as_raw_fd(), libc::F_DUPFD_CLOEXEC, 0) };
62 if ret < 0 {
63 errno_result()
64 } else {
65 Ok(ret)
66 }
67 }
68
69 /// Wraps a RawDescriptor and safely closes it when self falls out of scope.
70 #[derive(Serialize, Deserialize, Debug, Eq)]
71 #[serde(transparent)]
72 pub struct SafeDescriptor {
73 #[serde(with = "super::with_raw_descriptor")]
74 descriptor: RawDescriptor,
75 }
76
77 const KCMP_FILE: u32 = 0;
78
79 impl PartialEq for SafeDescriptor {
eq(&self, other: &Self) -> bool80 fn eq(&self, other: &Self) -> bool {
81 // If RawFd numbers match then we can return early without calling kcmp
82 if self.descriptor == other.descriptor {
83 return true;
84 }
85
86 // safe because we only use the return value and libc says it's always successful
87 let pid = unsafe { libc::getpid() };
88 // safe because we are passing everything by value and checking the return value
89 let ret = unsafe {
90 libc::syscall(
91 libc::SYS_kcmp,
92 pid,
93 pid,
94 KCMP_FILE,
95 self.descriptor,
96 other.descriptor,
97 )
98 };
99
100 ret == 0
101 }
102 }
103
104 impl Drop for SafeDescriptor {
drop(&mut self)105 fn drop(&mut self) {
106 let _ = unsafe { libc::close(self.descriptor) };
107 }
108 }
109
110 impl AsRawDescriptor for SafeDescriptor {
as_raw_descriptor(&self) -> RawDescriptor111 fn as_raw_descriptor(&self) -> RawDescriptor {
112 self.descriptor
113 }
114 }
115
116 impl IntoRawDescriptor for SafeDescriptor {
into_raw_descriptor(self) -> RawDescriptor117 fn into_raw_descriptor(self) -> RawDescriptor {
118 let descriptor = self.descriptor;
119 mem::forget(self);
120 descriptor
121 }
122 }
123
124 impl FromRawDescriptor for SafeDescriptor {
from_raw_descriptor(descriptor: RawDescriptor) -> Self125 unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
126 SafeDescriptor { descriptor }
127 }
128 }
129
130 impl AsRawFd for SafeDescriptor {
as_raw_fd(&self) -> RawFd131 fn as_raw_fd(&self) -> RawFd {
132 self.as_raw_descriptor()
133 }
134 }
135
136 impl TryFrom<&dyn AsRawFd> for SafeDescriptor {
137 type Error = std::io::Error;
138
try_from(fd: &dyn AsRawFd) -> std::result::Result<Self, Self::Error>139 fn try_from(fd: &dyn AsRawFd) -> std::result::Result<Self, Self::Error> {
140 Ok(SafeDescriptor {
141 descriptor: clone_fd(fd)?,
142 })
143 }
144 }
145
146 impl TryFrom<&dyn AsRawDescriptor> for SafeDescriptor {
147 type Error = std::io::Error;
148
149 /// Clones the underlying descriptor (handle), internally creating a new descriptor.
try_from(rd: &dyn AsRawDescriptor) -> std::result::Result<Self, Self::Error>150 fn try_from(rd: &dyn AsRawDescriptor) -> std::result::Result<Self, Self::Error> {
151 // Safe because the underlying raw descriptor is guaranteed valid by rd's existence.
152 //
153 // Note that we are cloning the underlying raw descriptor since we have no guarantee of
154 // its existence after this function returns.
155 let rd_as_safe_desc = ManuallyDrop::new(unsafe {
156 SafeDescriptor::from_raw_descriptor(rd.as_raw_descriptor())
157 });
158
159 // We have to clone rd because we have no guarantee ownership was transferred (rd is
160 // borrowed).
161 rd_as_safe_desc
162 .try_clone()
163 .map_err(|e| Self::Error::from_raw_os_error(e.errno()))
164 }
165 }
166
167 impl SafeDescriptor {
168 /// Clones this descriptor, internally creating a new descriptor. The new SafeDescriptor will
169 /// share the same underlying count within the kernel.
try_clone(&self) -> Result<SafeDescriptor>170 pub fn try_clone(&self) -> Result<SafeDescriptor> {
171 // Safe because this doesn't modify any memory and we check the return value.
172 let descriptor = unsafe { libc::fcntl(self.descriptor, libc::F_DUPFD_CLOEXEC, 0) };
173 if descriptor < 0 {
174 errno_result()
175 } else {
176 Ok(SafeDescriptor { descriptor })
177 }
178 }
179 }
180
181 impl From<SafeDescriptor> for File {
from(s: SafeDescriptor) -> File182 fn from(s: SafeDescriptor) -> File {
183 // Safe because we own the SafeDescriptor at this point.
184 unsafe { File::from_raw_fd(s.into_raw_descriptor()) }
185 }
186 }
187
188 impl From<File> for SafeDescriptor {
from(f: File) -> SafeDescriptor189 fn from(f: File) -> SafeDescriptor {
190 // Safe because we own the File at this point.
191 unsafe { SafeDescriptor::from_raw_descriptor(f.into_raw_descriptor()) }
192 }
193 }
194
195 impl From<SafeDescriptor> for UnixStream {
from(s: SafeDescriptor) -> Self196 fn from(s: SafeDescriptor) -> Self {
197 // Safe because we own the SafeDescriptor at this point.
198 unsafe { Self::from_raw_fd(s.into_raw_descriptor()) }
199 }
200 }
201
202 impl From<UnixSeqpacket> for SafeDescriptor {
from(s: UnixSeqpacket) -> Self203 fn from(s: UnixSeqpacket) -> Self {
204 // Safe because we own the UnixSeqpacket at this point.
205 unsafe { SafeDescriptor::from_raw_descriptor(s.into_raw_descriptor()) }
206 }
207 }
208
209 /// For use cases where a simple wrapper around a RawDescriptor is needed.
210 /// This is a simply a wrapper and does not manage the lifetime of the descriptor.
211 /// Most usages should prefer SafeDescriptor or using a RawDescriptor directly
212 #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
213 #[repr(transparent)]
214 pub struct Descriptor(pub RawDescriptor);
215 impl AsRawDescriptor for Descriptor {
as_raw_descriptor(&self) -> RawDescriptor216 fn as_raw_descriptor(&self) -> RawDescriptor {
217 self.0
218 }
219 }
220
221 // AsRawFd for interoperability with interfaces that require it. Within crosvm,
222 // always use AsRawDescriptor when possible.
223 impl AsRawFd for Descriptor {
as_raw_fd(&self) -> RawFd224 fn as_raw_fd(&self) -> RawFd {
225 self.0
226 }
227 }
228
229 /// Implement token for implementations that wish to use this struct as such
230 impl PollToken for Descriptor {
as_raw_token(&self) -> u64231 fn as_raw_token(&self) -> u64 {
232 self.0 as u64
233 }
234
from_raw_token(data: u64) -> Self235 fn from_raw_token(data: u64) -> Self {
236 Descriptor(data as RawDescriptor)
237 }
238 }
239
240 macro_rules! AsRawDescriptor {
241 ($name:ident) => {
242 impl AsRawDescriptor for $name {
243 fn as_raw_descriptor(&self) -> RawDescriptor {
244 self.as_raw_fd()
245 }
246 }
247 };
248 }
249
250 macro_rules! FromRawDescriptor {
251 ($name:ident) => {
252 impl FromRawDescriptor for $name {
253 unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
254 $name::from_raw_fd(descriptor)
255 }
256 }
257 };
258 }
259
260 macro_rules! IntoRawDescriptor {
261 ($name:ident) => {
262 impl IntoRawDescriptor for $name {
263 fn into_raw_descriptor(self) -> RawDescriptor {
264 self.into_raw_fd()
265 }
266 }
267 };
268 }
269
270 // Implementations for File. This enables the File-type to use
271 // RawDescriptor, but does not mean File should be used as a generic
272 // descriptor container. That should go to either SafeDescriptor or another more
273 // relevant container type.
274 AsRawDescriptor!(File);
275 AsRawDescriptor!(UnlinkUnixSeqpacketListener);
276 AsRawDescriptor!(UdpSocket);
277 AsRawDescriptor!(UnixDatagram);
278 AsRawDescriptor!(UnixListener);
279 AsRawDescriptor!(UnixStream);
280 FromRawDescriptor!(File);
281 FromRawDescriptor!(UnixStream);
282 FromRawDescriptor!(UnixDatagram);
283 IntoRawDescriptor!(File);
284 IntoRawDescriptor!(UnixDatagram);
285 AsRawDescriptor!(Stdin);
286 AsRawDescriptor!(Stdout);
287 AsRawDescriptor!(Stderr);
288
289 #[test]
290 #[allow(clippy::eq_op)]
clone_equality()291 fn clone_equality() {
292 let ret = unsafe { libc::eventfd(0, 0) };
293 if ret < 0 {
294 panic!("failed to create eventfd");
295 }
296 let descriptor = unsafe { SafeDescriptor::from_raw_descriptor(ret) };
297
298 assert_eq!(descriptor, descriptor);
299
300 assert_eq!(
301 descriptor,
302 descriptor.try_clone().expect("failed to clone eventfd")
303 );
304
305 let ret = unsafe { libc::eventfd(0, 0) };
306 if ret < 0 {
307 panic!("failed to create eventfd");
308 }
309 let another = unsafe { SafeDescriptor::from_raw_descriptor(ret) };
310
311 assert_ne!(descriptor, another);
312 }
313