• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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