Skip to content

Commit c502e1f

Browse files
committed
Explicitly accept new incoming connections
1 parent 34d9d8f commit c502e1f

File tree

5 files changed

+167
-33
lines changed

5 files changed

+167
-33
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fortanix-vme/fortanix-vme-abi/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ compiler_builtins = { version = "0.1.0", optional = true }
1414
serde = { git = "https://github.com/fortanix/serde.git", branch = "master", default-features = false, features = ["derive", "alloc"] }
1515

1616
[features]
17+
std = []
1718
default = []
1819
docs = []
1920
rustc-dep-of-std = ["core", "alloc", "compiler_builtins/rustc-dep-of-std", "serde/rustc-dep-of-std"]

fortanix-vme/fortanix-vme-abi/src/lib.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
#![no_std]
22
extern crate alloc;
3+
#[cfg(feature="std")]
4+
extern crate std;
35

46
use alloc::string::String;
57
use serde::{Deserialize, Serialize};
8+
#[cfg(feature="std")]
9+
use std::net::SocketAddr;
610

711
pub const SERVER_PORT: u32 = 10000;
812

@@ -17,6 +21,45 @@ pub enum Request {
1721
/// The port the enclave is listening on to receive connections from the parent VM
1822
enclave_port: u32,
1923
},
24+
Accept {
25+
fd: i32,
26+
}
27+
}
28+
29+
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
30+
pub enum Addr {
31+
IPv4 {
32+
ip: [u8; 4],
33+
port: u16,
34+
},
35+
IPv6 {
36+
ip: [u8; 16],
37+
port: u16,
38+
flowinfo: u32,
39+
scope_id: u32,
40+
},
41+
}
42+
43+
#[cfg(feature="std")]
44+
impl From<SocketAddr> for Addr {
45+
fn from(addr: SocketAddr) -> Addr {
46+
match addr {
47+
SocketAddr::V4(addr) => {
48+
Addr::IPv4 {
49+
ip: addr.ip().octets(),
50+
port: addr.port(),
51+
}
52+
},
53+
SocketAddr::V6(addr) => {
54+
Addr::IPv6 {
55+
ip: addr.ip().octets(),
56+
port: addr.port(),
57+
flowinfo: addr.flowinfo(),
58+
scope_id: addr.scope_id(),
59+
}
60+
}
61+
}
62+
}
2063
}
2164

2265
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
@@ -27,5 +70,35 @@ pub enum Response {
2770
Bound {
2871
/// The TCP port the runner is listening on
2972
port: u16,
73+
/// The id used to identify the listener. It can be used for subsequent calls (e.g., to
74+
/// accept new incoming connections)
75+
fd: i32,
3076
},
77+
IncomingConnection {
78+
/// The address of the remote party
79+
peer: Addr,
80+
/// The vsock port number the runner will connect to the enclave in order to forward the
81+
/// incomming connection
82+
proxy_port: u32,
83+
}
84+
}
85+
86+
/*
87+
#[cfg(test)]
88+
mod test {
89+
use std::net::{IpAddr, SocketAddr};
90+
use std::str::FromStr;
91+
use crate::Addr;
92+
93+
#[test]
94+
fn test_addr() {
95+
let sock_addr = SocketAddr::from_str("10.11.12.13:4567").unwrap();
96+
if let Addr::IPv4 { port, ip } = sock_addr.into() {
97+
assert_eq!(IpAddr::from(ip), sock_addr.ip());
98+
assert_eq!(port, sock_addr.port());
99+
} else {
100+
panic!("Not IPv4")
101+
}
102+
}
31103
}
104+
*/

fortanix-vme/fortanix-vme-runner/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ edition = "2018"
55
authors = ["Fortanix, Inc."]
66

77
[dependencies]
8-
fortanix-vme-abi = { path = "../fortanix-vme-abi" }
8+
fnv = "1.0.7"
9+
fortanix-vme-abi = { path = "../fortanix-vme-abi", features = ["std"] }
910
nix = "0.22.1"
1011
serde = { version = "1.0", features = ["derive"] }
1112
serde_cbor = { version = "0.11" }

fortanix-vme/fortanix-vme-runner/src/lib.rs

Lines changed: 90 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use fnv::FnvHashMap;
12
use nix::sys::select::{select, FdSet};
23
use nix::sys::socket::SockAddr as NixSockAddr;
34
use serde_cbor;
@@ -7,8 +8,10 @@ use std::thread::{self, JoinHandle};
78
use std::io::{self, Error as IoError, ErrorKind as IoErrorKind, Read, Write};
89
use std::net::{Shutdown, TcpListener, TcpStream};
910
use std::os::unix::io::AsRawFd;
11+
use std::os::unix::prelude::RawFd;
12+
use std::sync::{Arc, Mutex};
1013
use fortanix_vme_abi::{self, Response, Request};
11-
use vsock::{self, Std, VsockListener, VsockStream};
14+
use vsock::{self, Std, Vsock, VsockListener, VsockStream};
1215

1316
const PROXY_BUFF_SIZE: usize = 4192;
1417

@@ -17,8 +20,6 @@ enum Direction {
1720
Right,
1821
}
1922

20-
pub struct Server;
21-
2223
pub trait StreamConnection: Read + Write {
2324
fn protocol() -> &'static str;
2425

@@ -79,6 +80,22 @@ impl StreamConnection for VsockStream {
7980
}
8081
}
8182

83+
struct ListenerInfo {
84+
listener: TcpListener,
85+
enclave_cid: u32,
86+
enclave_port: u32,
87+
}
88+
89+
pub struct Server {
90+
command_listener: Mutex<VsockListener>,
91+
/// Tracks information about TCP sockets that are currently listening for new connections. For
92+
/// every TCP listener socket in the runner, there is a vsock listener socket in the enclave.
93+
/// When the enclave instructs to accept a new connection, the runner accepts a new TCP
94+
/// connection. It then locates the ListenerInfo and finds the information it needs to set up a
95+
/// new vsock connection to the enclave
96+
listeners: Mutex<FnvHashMap<RawFd, Arc<Mutex<ListenerInfo>>>>,
97+
}
98+
8299
impl Server {
83100
fn log_communication(src: &str, src_port: u32, dst: &str, dst_port: u32, msg: &str, arrow: Direction, prot: &str) {
84101
let src = format!("{}:{}", src, src_port);
@@ -159,13 +176,14 @@ impl Server {
159176
* [2] remote
160177
* [3] proxy
161178
*/
162-
fn handle_request_connect(remote_addr: &String, enclave: &mut VsockStream) -> Result<(), IoError> {
179+
fn handle_request_connect(&self, remote_addr: &String, enclave: &mut VsockStream) -> Result<(), IoError> {
163180
// Connect to remote server
164181
let mut remote_socket = TcpStream::connect(remote_addr)?;
165182
let remote_name = remote_addr.split_terminator(":").next().unwrap_or(remote_addr);
166183

167184
// Create listening socket that the enclave can connect to
168-
let (proxy_server, _proxy_server_cid, proxy_server_port) = Self::bind(0)?;
185+
let proxy_server = VsockListener::<Std>::bind_with_cid_port(vsock::VMADDR_CID_ANY, 0)?;
186+
let proxy_server_port = proxy_server.local_addr()?.port();
169187

170188
// Notify the enclave on which port her proxy is listening on
171189
let response = Response::Connected {
@@ -190,12 +208,23 @@ impl Server {
190208
Ok(())
191209
}
192210

211+
fn add_listener_info(&self, info: ListenerInfo) -> RawFd {
212+
let fd = info.listener.as_raw_fd();
213+
self.listeners.lock().unwrap().insert(fd, Arc::new(Mutex::new(info)));
214+
fd
215+
}
216+
217+
fn listener_info(&self, fd: &RawFd) -> Option<Arc<Mutex<ListenerInfo>>> {
218+
self.listeners.lock().unwrap().get(&fd).map(|m| m.clone())
219+
}
220+
193221
/*
194222
* +-----------+
195223
* | remote |
196224
* +-----------+
197225
* ^
198226
* |
227+
* TCP
199228
* |
200229
* v
201230
* +----[2]-----+ +-------------+
@@ -207,12 +236,17 @@ impl Server {
207236
* [1] enclave
208237
* [2] remote
209238
* [3] proxy
239+
* `addr`: The address to bind the TCP connection on
240+
* `enclave_port`: The vsock port the enclave is listening on for new connections from the
241+
* runner
242+
* `enclave`: The runner-enclave vsock connection
210243
*/
211-
fn handle_request_bind(addr: &String, enclave_port: u32, enclave: &mut VsockStream) -> Result<(), IoError> {
212-
let cid: u32 = enclave.peer().unwrap().parse().unwrap_or(0);
244+
fn handle_request_bind(&self, addr: &String, enclave_port: u32, enclave: &mut VsockStream) -> Result<(), IoError> {
245+
let cid: u32 = enclave.peer().unwrap().parse().unwrap_or(vsock::VMADDR_CID_HYPERVISOR);
213246
let listener = TcpListener::bind(addr)?;
214247
let port = listener.local_addr().map(|addr| addr.port())?;
215-
let response = Response::Bound{ port };
248+
let fd = self.add_listener_info(ListenerInfo{ listener, enclave_cid: cid, enclave_port });
249+
let response = Response::Bound{ port, fd };
216250
Self::log_communication(
217251
"runner",
218252
enclave.local_port().unwrap_or_default(),
@@ -222,14 +256,37 @@ impl Server {
222256
Direction::Right,
223257
"vsock");
224258
enclave.write(&serde_cbor::ser::to_vec(&response).unwrap())?;
259+
Ok(())
260+
}
225261

226-
for incoming in listener.incoming() {
227-
let _ = thread::Builder::new().spawn(move || {
228-
let mut proxy = VsockStream::connect_with_cid_port(cid, enclave_port).unwrap();
229-
Self::proxy_connection((&mut incoming.unwrap(), "remote"), (&mut proxy, "proxy"));
230-
});
262+
fn handle_request_accept(&self, fd: RawFd, enclave: &mut VsockStream) -> Result<(), IoError> {
263+
let listener_info = self.listener_info(&fd).unwrap();
264+
let listener_info = listener_info.lock().unwrap();
265+
let (cid, port) = (listener_info.enclave_cid, listener_info.enclave_port);
266+
match listener_info.listener.accept() {
267+
Ok((mut conn, peer)) => {
268+
let vsock = Vsock::new::<Std>()?;
269+
let response = Response::IncomingConnection{
270+
peer: peer.into(),
271+
proxy_port: vsock.addr::<Std>()?.port(),
272+
};
273+
Self::log_communication(
274+
"runner",
275+
enclave.local_port().unwrap_or_default(),
276+
"enclave",
277+
enclave.peer_port().unwrap_or_default(),
278+
&format!("{:?}", &response),
279+
Direction::Right,
280+
"vsock");
281+
enclave.write(&serde_cbor::ser::to_vec(&response).unwrap())?;
282+
let _ = thread::Builder::new().spawn(move || {
283+
let mut proxy = vsock.connect_with_cid_port(cid, port).unwrap();
284+
Self::proxy_connection((&mut conn, "remote"), (&mut proxy, "proxy"));
285+
});
286+
Ok(())
287+
},
288+
Err(e) => Err(e),
231289
}
232-
Ok(())
233290
}
234291

235292
fn proxy_connection(remote: (&mut TcpStream, &str), proxy: (&mut VsockStream, &str)) {
@@ -255,39 +312,40 @@ impl Server {
255312
let _ = remote.0.shutdown(Shutdown::Both);
256313
}
257314

258-
fn handle_client(stream: &mut VsockStream) -> Result<(), IoError> {
315+
fn handle_client(&self, stream: &mut VsockStream) -> Result<(), IoError> {
259316
match Self::read_request(stream) {
260-
Ok(Request::Connect{ addr }) => Self::handle_request_connect(&addr, stream)?,
261-
Ok(Request::Bind{ addr, enclave_port }) => Self::handle_request_bind(&addr, enclave_port, stream)?,
317+
Ok(Request::Connect{ addr }) => self.handle_request_connect(&addr, stream)?,
318+
Ok(Request::Bind{ addr, enclave_port }) => self.handle_request_bind(&addr, enclave_port, stream)?,
319+
Ok(Request::Accept{ fd }) => self.handle_request_accept(fd, stream)?,
262320
Err(_e) => return Err(IoError::new(IoErrorKind::InvalidData, "Failed to read request")),
263321
};
264322
Ok(())
265323
}
266324

267-
fn bind(port: u32) -> io::Result<(VsockListener, u32, u32)> {
268-
let listener = VsockListener::<Std>::bind_with_cid_port(vsock::VMADDR_CID_ANY, port)?;
269-
let addr = listener.local_addr()?;
270-
271-
if let NixSockAddr::Vsock(addr) = addr.into() {
272-
Ok((listener, addr.cid(), addr.port()))
273-
} else {
274-
Err(IoError::new(IoErrorKind::InvalidInput, "Unexpected address type"))
275-
}
325+
fn bind(port: u32) -> io::Result<Server> {
326+
let command_listener = VsockListener::<Std>::bind_with_cid_port(vsock::VMADDR_CID_ANY, port)?;
327+
Ok(Server {
328+
command_listener: Mutex::new(command_listener),
329+
listeners: Mutex::new(FnvHashMap::default()),
330+
})
276331
}
277332

278333
pub fn run(port: u32) -> std::io::Result<(JoinHandle<()>, u32)> {
279334
println!("Starting enclave runner.");
280-
let (listener, _cid, port) = Self::bind(port)?;
335+
let server = Arc::new(Self::bind(port)?);
336+
let port = server.command_listener.lock().unwrap().local_addr()?.port();
281337
println!("Listening on vsock port {}...", port);
282338

283339
let handle = thread::Builder::new().spawn(move || {
284-
let listener = listener;
285-
loop {
286-
let (stream, _addr) = listener.accept().unwrap();
340+
let server = server;
341+
let server = server.clone();
342+
let command_listener = server.command_listener.lock().unwrap();
343+
for stream in command_listener.incoming() {
344+
let server = server.clone();
287345
let _ = thread::Builder::new()
288346
.spawn(move || {
289-
let mut stream = stream;
290-
if let Err(e) = Self::handle_client(&mut stream) {
347+
let mut stream = stream.unwrap();
348+
if let Err(e) = server.handle_client(&mut stream) {
291349
eprintln!("Error handling connection: {}, shutting connection down", e);
292350
let _ = stream.shutdown(Shutdown::Both);
293351
}

0 commit comments

Comments
 (0)