• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::unix::io::AsRawFd;
15 use std::os::unix::io::FromRawFd;
16 use std::os::unix::io::IntoRawFd;
17 use std::os::unix::io::RawFd;
18 use std::os::unix::net::UnixDatagram;
19 use std::os::unix::net::UnixListener;
20 use std::os::unix::net::UnixStream;
21 
22 use super::errno_result;
23 use super::Result;
24 use crate::descriptor::AsRawDescriptor;
25 use crate::descriptor::Descriptor;
26 use crate::descriptor::FromRawDescriptor;
27 use crate::descriptor::IntoRawDescriptor;
28 use crate::descriptor::SafeDescriptor;
29 
30 pub type RawDescriptor = RawFd;
31 
32 pub const INVALID_DESCRIPTOR: RawDescriptor = -1;
33 
34 /// Clones `descriptor`, returning a new `RawDescriptor` that refers to the same open file
35 /// description as `descriptor`. The cloned descriptor will have the `FD_CLOEXEC` flag set but will
36 /// not share any other file descriptor flags with `descriptor`.
clone_descriptor(descriptor: &dyn AsRawDescriptor) -> Result<RawDescriptor>37 pub fn clone_descriptor(descriptor: &dyn AsRawDescriptor) -> Result<RawDescriptor> {
38     clone_fd(&descriptor.as_raw_descriptor())
39 }
40 
41 /// Clones `fd`, returning a new file descriptor that refers to the same open file description as
42 /// `fd`. The cloned fd will have the `FD_CLOEXEC` flag set but will not share any other file
43 /// descriptor flags with `fd`.
clone_fd(fd: &dyn AsRawFd) -> Result<RawFd>44 fn clone_fd(fd: &dyn AsRawFd) -> Result<RawFd> {
45     // Safe because this doesn't modify any memory and we check the return value.
46     let ret = unsafe { libc::fcntl(fd.as_raw_fd(), libc::F_DUPFD_CLOEXEC, 0) };
47     if ret < 0 {
48         errno_result()
49     } else {
50         Ok(ret)
51     }
52 }
53 
54 /// Clears CLOEXEC flag on descriptor
clear_descriptor_cloexec<A: AsRawDescriptor>(fd_owner: &A) -> Result<()>55 pub fn clear_descriptor_cloexec<A: AsRawDescriptor>(fd_owner: &A) -> Result<()> {
56     clear_fd_cloexec(&fd_owner.as_raw_descriptor())
57 }
58 
59 /// Clears CLOEXEC flag on fd
clear_fd_cloexec<A: AsRawFd>(fd_owner: &A) -> Result<()>60 fn clear_fd_cloexec<A: AsRawFd>(fd_owner: &A) -> Result<()> {
61     let fd = fd_owner.as_raw_fd();
62     // Safe because fd is read only.
63     let flags = unsafe { libc::fcntl(fd, libc::F_GETFD) };
64     if flags == -1 {
65         return errno_result();
66     }
67 
68     let masked_flags = flags & !libc::FD_CLOEXEC;
69     // Safe because this has no side effect(s) on the current process.
70     if masked_flags != flags && unsafe { libc::fcntl(fd, libc::F_SETFD, masked_flags) } == -1 {
71         errno_result()
72     } else {
73         Ok(())
74     }
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 AsRawFd for SafeDescriptor {
as_raw_fd(&self) -> RawFd111     fn as_raw_fd(&self) -> RawFd {
112         self.as_raw_descriptor()
113     }
114 }
115 
116 impl TryFrom<&dyn AsRawFd> for SafeDescriptor {
117     type Error = std::io::Error;
118 
try_from(fd: &dyn AsRawFd) -> std::result::Result<Self, Self::Error>119     fn try_from(fd: &dyn AsRawFd) -> std::result::Result<Self, Self::Error> {
120         Ok(SafeDescriptor {
121             descriptor: clone_fd(fd)?,
122         })
123     }
124 }
125 
126 impl SafeDescriptor {
127     /// Clones this descriptor, internally creating a new descriptor. The new SafeDescriptor will
128     /// share the same underlying count within the kernel.
try_clone(&self) -> Result<SafeDescriptor>129     pub fn try_clone(&self) -> Result<SafeDescriptor> {
130         // Safe because this doesn't modify any memory and we check the return value.
131         let descriptor = unsafe { libc::fcntl(self.descriptor, libc::F_DUPFD_CLOEXEC, 0) };
132         if descriptor < 0 {
133             errno_result()
134         } else {
135             Ok(SafeDescriptor { descriptor })
136         }
137     }
138 }
139 
140 impl From<SafeDescriptor> for File {
from(s: SafeDescriptor) -> File141     fn from(s: SafeDescriptor) -> File {
142         // Safe because we own the SafeDescriptor at this point.
143         unsafe { File::from_raw_fd(s.into_raw_descriptor()) }
144     }
145 }
146 
147 impl From<SafeDescriptor> for TcpListener {
from(s: SafeDescriptor) -> Self148     fn from(s: SafeDescriptor) -> Self {
149         // Safe because we own the SafeDescriptor at this point.
150         unsafe { Self::from_raw_fd(s.into_raw_descriptor()) }
151     }
152 }
153 
154 impl From<SafeDescriptor> for TcpStream {
from(s: SafeDescriptor) -> Self155     fn from(s: SafeDescriptor) -> Self {
156         // Safe because we own the SafeDescriptor at this point.
157         unsafe { Self::from_raw_fd(s.into_raw_descriptor()) }
158     }
159 }
160 
161 impl From<SafeDescriptor> for UnixStream {
from(s: SafeDescriptor) -> Self162     fn from(s: SafeDescriptor) -> Self {
163         // Safe because we own the SafeDescriptor at this point.
164         unsafe { Self::from_raw_fd(s.into_raw_descriptor()) }
165     }
166 }
167 
168 // AsRawFd for interoperability with interfaces that require it. Within crosvm,
169 // always use AsRawDescriptor when possible.
170 impl AsRawFd for Descriptor {
as_raw_fd(&self) -> RawFd171     fn as_raw_fd(&self) -> RawFd {
172         self.0
173     }
174 }
175 
176 macro_rules! AsRawDescriptor {
177     ($name:ident) => {
178         impl AsRawDescriptor for $name {
179             fn as_raw_descriptor(&self) -> RawDescriptor {
180                 self.as_raw_fd()
181             }
182         }
183     };
184 }
185 
186 macro_rules! FromRawDescriptor {
187     ($name:ident) => {
188         impl FromRawDescriptor for $name {
189             unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
190                 $name::from_raw_fd(descriptor)
191             }
192         }
193     };
194 }
195 
196 macro_rules! IntoRawDescriptor {
197     ($name:ident) => {
198         impl IntoRawDescriptor for $name {
199             fn into_raw_descriptor(self) -> RawDescriptor {
200                 self.into_raw_fd()
201             }
202         }
203     };
204 }
205 
206 // Implementations for File. This enables the File-type to use
207 // RawDescriptor, but does not mean File should be used as a generic
208 // descriptor container. That should go to either SafeDescriptor or another more
209 // relevant container type.
210 AsRawDescriptor!(File);
211 AsRawDescriptor!(TcpListener);
212 AsRawDescriptor!(TcpStream);
213 AsRawDescriptor!(UdpSocket);
214 AsRawDescriptor!(UnixDatagram);
215 AsRawDescriptor!(UnixListener);
216 AsRawDescriptor!(UnixStream);
217 FromRawDescriptor!(File);
218 FromRawDescriptor!(UnixStream);
219 FromRawDescriptor!(UnixDatagram);
220 IntoRawDescriptor!(File);
221 IntoRawDescriptor!(UnixDatagram);
222 AsRawDescriptor!(Stdin);
223 AsRawDescriptor!(Stdout);
224 AsRawDescriptor!(Stderr);
225