This is an automated email from the ASF dual-hosted git repository.
piotr pushed a commit to branch iggy_header_reserved
in repository https://gitbox.apache.org/repos/asf/iggy.git
The following commit(s) were added to refs/heads/iggy_header_reserved by this
push:
new 1d71d98a0 Validate reserved field must be set to 0
1d71d98a0 is described below
commit 1d71d98a0f96c611d5f5a5649fc953ab4fd7dd57
Author: spetz <[email protected]>
AuthorDate: Tue Feb 3 10:33:51 2026 +0100
Validate reserved field must be set to 0
---
core/common/src/error/iggy_error.rs | 2 +
core/common/src/types/message/message_header.rs | 80 ++++++++++++++++++++++---
2 files changed, 75 insertions(+), 7 deletions(-)
diff --git a/core/common/src/error/iggy_error.rs
b/core/common/src/error/iggy_error.rs
index 0e5bd23e2..18d759c79 100644
--- a/core/common/src/error/iggy_error.rs
+++ b/core/common/src/error/iggy_error.rs
@@ -407,6 +407,8 @@ pub enum IggyError {
ProducerClosed = 4057,
#[error("Invalid offset: {0}")]
InvalidOffset(u64) = 4100,
+ #[error("Invalid reserved field value: {0}, expected: 0")]
+ InvalidReservedField(u64) = 4101,
#[error("Consumer group with ID: {0} for topic with ID: {1} was not
found.")]
ConsumerGroupIdNotFound(Identifier, Identifier) = 5000,
#[error("Invalid consumer group ID")]
diff --git a/core/common/src/types/message/message_header.rs
b/core/common/src/types/message/message_header.rs
index c2b788eba..1f14aa17d 100644
--- a/core/common/src/types/message/message_header.rs
+++ b/core/common/src/types/message/message_header.rs
@@ -94,11 +94,17 @@ impl IggyMessageHeader {
.try_into()
.map_err(|_| IggyError::InvalidNumberEncoding)?,
),
- reserved: u64::from_le_bytes(
- bytes[IGGY_MESSAGE_RESERVED_OFFSET_RANGE]
- .try_into()
- .map_err(|_| IggyError::InvalidNumberEncoding)?,
- ),
+ reserved: {
+ let reserved = u64::from_le_bytes(
+ bytes[IGGY_MESSAGE_RESERVED_OFFSET_RANGE]
+ .try_into()
+ .map_err(|_| IggyError::InvalidNumberEncoding)?,
+ );
+ if reserved != 0 {
+ return Err(IggyError::InvalidReservedField(reserved));
+ }
+ reserved
+ },
})
}
}
@@ -164,12 +170,16 @@ impl BytesSerializable for IggyMessageHeader {
.map_err(|_| IggyError::InvalidNumberEncoding)?,
);
- let _reserved = u64::from_le_bytes(
+ let reserved = u64::from_le_bytes(
bytes[IGGY_MESSAGE_RESERVED_OFFSET_RANGE]
.try_into()
.map_err(|_| IggyError::InvalidNumberEncoding)?,
);
+ if reserved != 0 {
+ return Err(IggyError::InvalidReservedField(reserved));
+ }
+
Ok(IggyMessageHeader {
checksum,
id,
@@ -178,7 +188,7 @@ impl BytesSerializable for IggyMessageHeader {
origin_timestamp,
user_headers_length: headers_length,
payload_length,
- reserved: _reserved,
+ reserved,
})
}
}
@@ -245,4 +255,60 @@ mod tests {
assert_eq!(header.user_headers_length,
deserialized.user_headers_length);
assert_eq!(header.payload_length, deserialized.payload_length);
}
+
+ #[test]
+ fn should_reject_non_zero_reserved_field_from_bytes() {
+ let header = IggyMessageHeader {
+ checksum: 123456789,
+ id: 987654321,
+ offset: 100,
+ timestamp: 1000000,
+ origin_timestamp: 999999,
+ user_headers_length: 50,
+ payload_length: 200,
+ reserved: 0,
+ };
+
+ // First serialize with reserved = 0
+ let mut bytes = header.to_bytes().to_vec();
+
+ // Manually set reserved field to non-zero value (last 8 bytes)
+ let non_zero_reserved: u64 = 42;
+
bytes[IGGY_MESSAGE_RESERVED_OFFSET_RANGE].copy_from_slice(&non_zero_reserved.to_le_bytes());
+
+ let result = IggyMessageHeader::from_bytes(Bytes::from(bytes));
+ assert!(result.is_err());
+ assert_eq!(
+ result.unwrap_err(),
+ IggyError::InvalidReservedField(non_zero_reserved)
+ );
+ }
+
+ #[test]
+ fn should_reject_non_zero_reserved_field_from_raw_bytes() {
+ let header = IggyMessageHeader {
+ checksum: 111,
+ id: 222,
+ offset: 333,
+ timestamp: 444,
+ origin_timestamp: 555,
+ user_headers_length: 66,
+ payload_length: 77,
+ reserved: 0,
+ };
+
+ // First serialize with reserved = 0
+ let mut bytes = header.to_bytes().to_vec();
+
+ // Manually set reserved field to non-zero value
+ let non_zero_reserved: u64 = 123456789;
+
bytes[IGGY_MESSAGE_RESERVED_OFFSET_RANGE].copy_from_slice(&non_zero_reserved.to_le_bytes());
+
+ let result = IggyMessageHeader::from_raw_bytes(&bytes);
+ assert!(result.is_err());
+ assert_eq!(
+ result.unwrap_err(),
+ IggyError::InvalidReservedField(non_zero_reserved)
+ );
+ }
}