Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tokio-util's LengthDelimitedCodec doesn't adjust decoded length before checking overflow #4815

Open
minghuaw opened this issue Jul 8, 2022 · 4 comments
Labels
A-tokio-util Area: The tokio-util crate C-bug Category: This is a bug. M-codec Module: tokio-util/codec S-blocked Status: marked as blocked ❌ on something else such as a PR or other implementation work.

Comments

@minghuaw
Copy link

minghuaw commented Jul 8, 2022

Version
tokio-util = { version = "0.7.3", features = ["codec"] }

Platform
Windows

Description

When .length_adjustment() is set to a negative value, a encoded max-sized frame cannot be decoded because overflow is checked before making length adjustment to the decoded length.
[short summary of the bug]

I tried this code:

use bytes::Bytes;
use futures_util::{SinkExt, StreamExt};
use tokio_util::codec::LengthDelimitedCodec;

#[tokio::main]
async fn main() {
    // All the configs
    const MAX_FRAME_LENGTH: usize = 10;
    const LENGTH_FIELD_LENGTH: usize = 4;
    const LENGTH_ADJUSTMENT: isize = -4;

    // test write
    let mut writer = vec![];
    let mut framed = LengthDelimitedCodec::builder()
        .big_endian()
        .length_field_length(LENGTH_FIELD_LENGTH)
        .max_frame_length(MAX_FRAME_LENGTH)
        .length_adjustment(LENGTH_ADJUSTMENT)
        .new_write(&mut writer);

    let payload = Bytes::from(vec![b'a'; MAX_FRAME_LENGTH]);
    framed.send(payload).await.unwrap();

    // test read
    let reader = &writer[..];
    let mut framed = LengthDelimitedCodec::builder()
        .big_endian()
        .length_field_length(LENGTH_FIELD_LENGTH)
        .max_frame_length(MAX_FRAME_LENGTH)
        .length_adjustment(LENGTH_ADJUSTMENT)
        .new_read(reader);
    let outcome = framed.next().await.unwrap().unwrap(); // This panics if `LENGTH_ADJUSTMENT` is negative
    assert_eq!(MAX_FRAME_LENGTH, outcome.len());
}

I expected to see this happen:

I expect that the codec is able to decode the bytes that are encoded by essentially the same codec.

Instead, this happened:

The decoding would fail when it checks for overflow

if n > self.builder.max_frame_len as u64 {

@minghuaw minghuaw added A-tokio Area: The main tokio crate C-bug Category: This is a bug. labels Jul 8, 2022
@minghuaw
Copy link
Author

minghuaw commented Jul 8, 2022

I believe this is caused by the decoder checking overflow

if n > self.builder.max_frame_len as u64 {

before making length adjustment

n.checked_sub(-self.builder.length_adjustment as usize)

@minghuaw
Copy link
Author

minghuaw commented Jul 8, 2022

A PR #4816 has been submitted to solve this issue. A new unit test covering this scenario is also added in the PR

@Darksonn Darksonn added A-tokio-util Area: The tokio-util crate M-codec Module: tokio-util/codec and removed A-tokio Area: The main tokio crate labels Jul 9, 2022
@Darksonn Darksonn added the S-blocked Status: marked as blocked ❌ on something else such as a PR or other implementation work. label Aug 10, 2022
@Darksonn
Copy link
Contributor

This is blocked because fixing it is a breaking change. We will release this change next time we make a breaking release of tokio-util. See #4816 for more details.

@rukmal
Copy link

rukmal commented Aug 23, 2024

+1 on this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-tokio-util Area: The tokio-util crate C-bug Category: This is a bug. M-codec Module: tokio-util/codec S-blocked Status: marked as blocked ❌ on something else such as a PR or other implementation work.
Projects
None yet
Development

No branches or pull requests

3 participants