Skip to content

net_tap / net_dio: RX write path does not check buffer capacity before writing #3120

@jstarks

Description

@jstarks

Problem

The TAP and DIO network backends call write_packet() on the BufferAccess pool without first checking capacity(). If a guest posts a small RX descriptor, the backend will attempt to write a full-size frame into it.

With the capacity() fix in #3119, write_header now asserts that metadata.len <= packet.cap. Since packet.cap is derived from the guest-provided descriptor size, a guest posting an undersized RX buffer will trigger this assert and crash the VMM when using TAP or DIO backends.

Affected code

net_tapvm/devices/net/net_tap/src/lib.rs around line 265:

self.inner.pool.write_packet(
    rx,
    &RxMetadata { offset: 0, len: frame_len, ..rx_meta },
    &self.buffer[frame_start..read_len],
);

net_diovm/devices/net/net_dio/src/lib.rs around line 144:

self.rx_pool.write_packet(
    id,
    &RxMetadata { offset: 0, len: buf.len(), ..Default::default() },
    buf,
);

Neither checks capacity(rx_id) before writing.

Fix

Both backends should check capacity() before calling write_packet(). If the frame exceeds the buffer capacity, either drop the packet (and return the RxId to the available pool) or truncate to the buffer size.

Consomme already does this correctly — its recv() implementation checks data.len() <= capacity(rx_id) and returns oversized buffers to rx_avail.

Impact

Guest-triggered VMM panic (DoS) when using TAP or DIO backends with a malicious or buggy guest driver that posts undersized RX descriptors.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions