Skip to content

vsock TX path: BufDescTooSmall with Linux ≥ 6.x guest kernels (multi-descriptor TX chain not handled) #674

@val4oss

Description

@val4oss

Describe the bug

When running a container with krun as the OCI runtime and a guest kernel ≥ 6.2, any application sending sufficiently large data over TCP causes the vsock device to log:

ERROR krun_devices::virtio::vsock::device] error reading TX packet: BufDescTooSmall

The connection is silently dropped and retried indefinitely. The application never completes its request.

Root cause

The guest kernel splits large TX packets across multiple chained descriptors. Specifically, a 64KB packet (pkt.len = 65536, which is MAX_PKT_BUF_SIZE) is split into two 32KB descriptors (buf_desc.len = 32768).

The current from_tx_virtq_head() in src/devices/src/virtio/vsock/packet.rs only reads the first data descriptor and checks its length against pkt.len():

if buf_desc.len < pkt.len() {
    return Err(VsockError::BufDescTooSmall);  // always fails for 64KB packets
}

Since 32768 < 65536, it always fails. The code never traverses the rest of the descriptor chain.

Note: a related single-descriptor TX fix (mirroring the Linux ≥ 6.2 RX fix) was already applied and does not address this case — the error now comes specifically from the two-descriptor split path (head.has_next=true).

Debug log confirming the values

ERROR krun_devices::virtio::vsock::packet] BufDescTooSmall: buf_desc.len=32768 pkt.len=65536 head.has_next=true

Steps to reproduce

  1. Run a container with --runtime krun with a Linux ≥ 6.x guest kernel
  2. Inside the container, make any large HTTPS request with a body ≥ 64KB (e.g. GitHub Copilot CLI gh copilot, which sends large JSON payloads containing tool definitions)
  3. Observe repeated BufDescTooSmall errors

Environment

  • libkrun: 1.18.0 (with single-descriptor TX patch applied)
  • Guest kernel: 6.12.68
  • Host OS: Linux (openSUSE)
  • Reproducible with: gh copilot -p "..." — sends 64KB HTTP request bodies. Applications with smaller payloads are not affected.

Expected behavior

from_tx_virtq_head() should traverse the full descriptor chain and accumulate the total available buffer length, mirroring how the RX path handles chained descriptors.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions