Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions crates/engineioxide/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# engineioxide 0.17.7
* chore(deps): bump `tokio_tungstenite` to v0.30
*
* feat(security): add `ws_max_message_size`/`ws_max_frame_size` config options to bound the size of incoming
websocket messages and frames, preventing memory exhaustion by malicious clients. Defaults to 64 MiB/16 MiB.
See [Github Advisory](https://github.com/Totodore/socketioxide/security/advisories/GHSA-55mf-67qm-4wpg).

# engineioxide 0.17.6
* feat: add `emit_{binary,many}_volatile` methods to `Socket` to emit volatile packets.

Expand Down
2 changes: 1 addition & 1 deletion crates/engineioxide/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "engineioxide"
description = "Engine IO server implementation as a Tower Service."
version = "0.17.6"
version = "0.17.7"
edition.workspace = true
rust-version.workspace = true
authors.workspace = true
Expand Down
34 changes: 34 additions & 0 deletions crates/engineioxide/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,19 @@ pub struct EngineIoConfig {
/// but will consume more memory.
pub ws_read_buffer_size: usize,

/// The maximum size of an incoming message
///
/// The default value is 64 MiB which should be reasonably big for all normal use-cases but small enough
/// to prevent memory eating by a malicious user.
pub ws_max_message_size: usize,

/// The maximum size of a single incoming message frame.
/// The limit is for frame payload NOT including the frame header.
///
/// The default value is 16 MiB which should be reasonably big for all normal use-cases but small enough
/// to prevent memory eating by a malicious user.
pub ws_max_frame_size: usize,

/// Allowed transports on this server
/// It is represented as a bitfield to allow to combine any number of transports easily
pub transports: u8,
Expand All @@ -86,6 +99,8 @@ impl Default for EngineIoConfig {
max_buffer_size: 128,
max_payload: 1e5 as u64, // 100kb
ws_read_buffer_size: 4096,
ws_max_message_size: 64 << 20,
ws_max_frame_size: 16 << 20,
transports: TransportType::Polling as u8 | TransportType::Websocket as u8,
}
}
Expand Down Expand Up @@ -205,6 +220,25 @@ impl EngineIoConfigBuilder {
self
}

/// The maximum size of an incoming message
///
/// The default value is 64 MiB which should be reasonably big for all normal use-cases but small enough
/// to prevent memory eating by a malicious user.
pub fn ws_max_message_size(mut self, ws_max_message_size: usize) -> Self {
self.config.ws_max_message_size = ws_max_message_size;
self
}

/// The maximum size of a single incoming message frame.
/// The limit is for frame payload NOT including the frame header.
///
/// The default value is 16 MiB which should be reasonably big for all normal use-cases but small enough
/// to prevent memory eating by a malicious user.
pub fn ws_max_frame_size(mut self, ws_max_frame_size: usize) -> Self {
self.config.ws_max_frame_size = ws_max_frame_size;
self
}

/// Allowed transports on this server
///
/// The `transports` array should have a size of 1 or 2
Expand Down
6 changes: 5 additions & 1 deletion crates/engineioxide/src/transport/ws.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,11 @@ pub async fn on_init<H: EngineIoHandler, S>(
where
S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
{
let ws_config = WebSocketConfig::default().read_buffer_size(engine.config.ws_read_buffer_size);
let ws_config = WebSocketConfig::default()
.read_buffer_size(engine.config.ws_read_buffer_size)
.max_message_size(Some(engine.config.ws_max_message_size))
.max_frame_size(Some(engine.config.ws_max_frame_size));

let ws_init = move || WebSocketStream::from_raw_socket(conn, Role::Server, Some(ws_config));
let (socket, ws) = if let Some(sid) = sid {
match engine.get_socket(sid) {
Expand Down
6 changes: 6 additions & 0 deletions crates/parser-common/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# socketioxide-parser-common 0.17.2
* fix(security): implement `ParseConfig` rules to fix unlimited binary data attachments which could lead
to denial of service. See [Github Advisory](https://github.com/Totodore/socketioxide/security/advisories/GHSA-55mf-67qm-4wpg).
* deps: bump `socketioxide-core` to 0.19

# socketioxide-parser-common 0.17.1
* deps: bump `socketioxide-core` to 0.18

# socketioxide-parser-common 0.17
* deps: bump `socketioxide-core` to 0.17
* MSRV: rust-version is now 1.86 with edition 2024
Expand Down
4 changes: 2 additions & 2 deletions crates/parser-common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "socketioxide-parser-common"
description = "Common parser for the socketioxide protocol"
version = "0.17.1"
version = "0.17.2"
edition.workspace = true
rust-version.workspace = true
authors.workspace = true
Expand All @@ -17,7 +17,7 @@ bytes.workspace = true
itoa.workspace = true
serde.workspace = true
serde_json.workspace = true
socketioxide-core = { version = "0.18", path = "../socketioxide-core" }
socketioxide-core = { version = "0.19", path = "../socketioxide-core" }

[dev-dependencies]
criterion.workspace = true
Expand Down
8 changes: 6 additions & 2 deletions crates/parser-common/benches/packet_decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use criterion::{BatchSize, Criterion, black_box, criterion_group, criterion_main
use socketioxide_core::{
Sid, Value,
packet::{ConnectPacket, Packet, PacketData},
parser::Parse,
parser::{Parse, ParseConfig, ParserState},
};
use socketioxide_parser_common::CommonParser;

Expand All @@ -15,7 +15,11 @@ fn encode(packet: Packet) -> String {
}
fn decode(value: String) -> Option<Packet> {
CommonParser
.decode_str(&Default::default(), black_box(value.into()))
.decode_str(
&ParseConfig::default(),
&ParserState::default(),
black_box(value.into()),
)
.ok()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ use socketioxide_core::parser::Parse;
use socketioxide_parser_common::CommonParser;
fuzz_target!(|data: &[u8]| {
CommonParser
.decode_bin(&Default::default(), Bytes::copy_from_slice(data))
.decode_bin(&Default::default(), &Default::default(), Bytes::copy_from_slice(data))
.ok();
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ use socketioxide_parser_common::CommonParser;

fuzz_target!(|data: &[u8]| {
let data = unsafe { Str::from_bytes_unchecked(Bytes::copy_from_slice(data)) };
CommonParser.decode_str(&Default::default(), data).ok();
CommonParser.decode_str(&Default::default(), &Default::default(), data).ok();
});
Loading