BUG/MEDIUM: quic: do not split STREAM frames if no space

When building STREAM frames in a packet buffer, if a frame is too large
it will be splitted in two. A shorten version will be used and the
original frame will be modified to represent the remaining space.

To ensure there is enough space to store the frame data length encoded
as a QUIC integer, we use the function max_available_room(). This
function can return 0 if there not only a small space left which is
insufficient for the frame header and the shorten data. Prior to this
patch, this wasn't check and an empty unneeded STREAM frame was built
and sent for nothing.

Change this by checking the value return by max_available_room(). If 0,
do not try to split this frame and continue to the next ones in the
packet.

On 2.6, this patch serves as an optimization which will prevent the building
of unneeded empty STREAM frames.

On 2.7, this behavior has the side-effect of triggering a BUG_ON()
statement on quic_build_stream_frame(). This BUG_ON() ensures that we do
not use quic_frame with OFF bit set if its offset is 0. This can happens
if the condition defined above is reproduced for a STREAM frame at
offset 0. An empty unneeded frame is built as descibed. The problem is
that the original frame is modified with its OFF bit set even if the
offset is still 0.

This must be backported up to 2.6.
This commit is contained in:
Amaury Denoyelle 2023-02-03 18:39:06 +01:00
parent 50440457e3
commit f2f08f88ef
1 changed files with 14 additions and 4 deletions

View File

@ -6819,11 +6819,13 @@ static inline int qc_build_frms(struct list *outlist, struct list *inlist,
TRACE_DEVEL(" New STREAM frame build (room, len)", TRACE_DEVEL(" New STREAM frame build (room, len)",
QUIC_EV_CONN_BCFRMS, qc, &room, len); QUIC_EV_CONN_BCFRMS, qc, &room, len);
/* hlen contains STREAM id and offset. Ensure there is
* enough room for length field.
*/
if (cf->type & QUIC_STREAM_FRAME_TYPE_LEN_BIT) { if (cf->type & QUIC_STREAM_FRAME_TYPE_LEN_BIT) {
dlen = max_available_room(avail_room, &dlen_sz); dlen = QUIC_MIN((uint64_t)max_available_room(avail_room, &dlen_sz),
if (dlen > cf->stream.len) { cf->stream.len);
dlen = cf->stream.len;
}
dlen_sz = quic_int_getsize(dlen); dlen_sz = quic_int_getsize(dlen);
flen = hlen + dlen_sz + dlen; flen = hlen + dlen_sz + dlen;
} }
@ -6831,6 +6833,14 @@ static inline int qc_build_frms(struct list *outlist, struct list *inlist,
dlen = QUIC_MIN((uint64_t)avail_room, cf->stream.len); dlen = QUIC_MIN((uint64_t)avail_room, cf->stream.len);
flen = hlen + dlen; flen = hlen + dlen;
} }
if (cf->stream.len && !dlen) {
/* Only a small gap is left on buffer, not
* enough to encode the STREAM data length.
*/
continue;
}
TRACE_DEVEL(" STREAM data length (hlen, stream.len, dlen)", TRACE_DEVEL(" STREAM data length (hlen, stream.len, dlen)",
QUIC_EV_CONN_BCFRMS, qc, &hlen, &cf->stream.len, &dlen); QUIC_EV_CONN_BCFRMS, qc, &hlen, &cf->stream.len, &dlen);
TRACE_DEVEL(" STREAM frame length (flen)", TRACE_DEVEL(" STREAM frame length (flen)",