Skip to content

Commit 3bd3b98

Browse files
mtjhrcslp
authored andcommitted
vsock: Fix TCP connection bug - add ConnectedUnconfirmed proxy state
Add another state to the Proxy trait called ConnectedUnconfirmed. This is used when when the socket is connected (on the host), but confirm_connect hasn't been called yet. Make the TCP implementation use this new transitional state fixing the described bug: `libkrun` connects to the TCP socket on the host (this action is done upon the TSI_CONNECT request), but the guest is not yet connected to stream vsock socket corresponding to the actual transport for that connection. (We have not called `confirm_connect`). The problem is that since we assume the guest is already connected we attempt to recv in process_event. Which can cause the VSOCK_OP_CREDIT_REQUEST to be sent the guest, but the guest is expecting a VSOCK_OP_RESPONSE as a response to a connection request. This makes the guest kernel return EPROTO from the connect syscall. (specifically EPROTO is returned from the `virtio_transport_recv_connecting` in `net/vmw_vsock/virtio_transport_common.c`) Signed-off-by: Matej Hrica <[email protected]>
1 parent 91a0ce0 commit 3bd3b98

File tree

2 files changed

+18
-8
lines changed

2 files changed

+18
-8
lines changed

src/devices/src/virtio/vsock/proxy.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub enum ProxyError {
2525
pub enum ProxyStatus {
2626
Idle,
2727
Connecting,
28+
ConnectedUnconfirmed,
2829
Connected,
2930
Listening,
3031
Closed,

src/devices/src/virtio/vsock/tcp.rs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -340,8 +340,7 @@ impl TcpProxy {
340340
push_packet(self.cid, rx, &self.rxq, &self.queue, &self.mem);
341341
}
342342

343-
fn switch_to_connected(&mut self) {
344-
self.status = ProxyStatus::Connected;
343+
fn switch_to_blocking(&mut self) {
345344
match fcntl(self.fd, FcntlArg::F_GETFL) {
346345
Ok(flags) => match OFlag::from_bits(flags) {
347346
Some(flags) => {
@@ -374,7 +373,8 @@ impl Proxy for TcpProxy {
374373
) {
375374
Ok(()) => {
376375
debug!("vsock: connect: Connected");
377-
self.switch_to_connected();
376+
self.switch_to_blocking();
377+
self.status = ProxyStatus::ConnectedUnconfirmed;
378378
0
379379
}
380380
Err(nix::errno::Errno::EINPROGRESS) => {
@@ -395,7 +395,7 @@ impl Proxy for TcpProxy {
395395
if self.status == ProxyStatus::Connecting {
396396
update.polling = Some((self.id, self.fd, EventSet::IN | EventSet::OUT));
397397
} else {
398-
if self.status == ProxyStatus::Connected {
398+
if self.status == ProxyStatus::ConnectedUnconfirmed {
399399
update.polling = Some((self.id, self.fd, EventSet::IN));
400400
}
401401
self.push_connect_rsp(result);
@@ -413,6 +413,15 @@ impl Proxy for TcpProxy {
413413
self.peer_port,
414414
);
415415

416+
if self.status != ProxyStatus::ConnectedUnconfirmed {
417+
warn!(
418+
"tcp: confirm_connect: Expected state to be {:?}, but it is {:?}",
419+
ProxyStatus::ConnectedUnconfirmed,
420+
self.status
421+
);
422+
}
423+
self.status = ProxyStatus::Connected;
424+
416425
self.peer_buf_alloc = pkt.buf_alloc();
417426
self.peer_fwd_cnt = Wrapping(pkt.fwd_cnt());
418427

@@ -574,8 +583,6 @@ impl Proxy for TcpProxy {
574583
self.peer_buf_alloc = pkt.buf_alloc();
575584
self.peer_fwd_cnt = Wrapping(pkt.fwd_cnt());
576585

577-
self.status = ProxyStatus::Connected;
578-
579586
ProxyUpdate {
580587
polling: Some((self.id, self.fd, EventSet::IN)),
581588
..Default::default()
@@ -607,7 +614,8 @@ impl Proxy for TcpProxy {
607614
self.peer_buf_alloc = pkt.buf_alloc();
608615
self.peer_fwd_cnt = Wrapping(pkt.fwd_cnt());
609616

610-
self.switch_to_connected();
617+
self.switch_to_blocking();
618+
self.status = ProxyStatus::Connected;
611619

612620
ProxyUpdate {
613621
polling: Some((self.id, self.fd, EventSet::IN)),
@@ -748,7 +756,8 @@ impl Proxy for TcpProxy {
748756
if evset.contains(EventSet::OUT) {
749757
debug!("process_event: OUT");
750758
if self.status == ProxyStatus::Connecting {
751-
self.switch_to_connected();
759+
self.switch_to_blocking();
760+
self.status = ProxyStatus::ConnectedUnconfirmed;
752761
self.push_connect_rsp(0);
753762
update.signal_queue = true;
754763
update.polling = Some((self.id(), self.fd, EventSet::IN));

0 commit comments

Comments
 (0)