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