Skip to content

Commit 1790c0d

Browse files
authored
Merge pull request #30196 from vbotbuildovich/backport-pr-30191-v26.1.x-979
2 parents a5197ef + b60d498 commit 1790c0d

7 files changed

Lines changed: 50 additions & 14 deletions

File tree

src/v/kafka/client/transport.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ ss::future<> transport::read_loop() {
107107
_pending_requests.erase(it);
108108
std::optional<tagged_fields> reply_tags;
109109
if (entry->is_flexible) {
110-
auto [tags, bytes_read] = co_await parse_tags(in());
110+
auto [tags, bytes_read] = co_await parse_tags(
111+
in(), bytes_remaining);
111112
reply_tags = std::move(tags);
112113
bytes_remaining -= bytes_read;
113114
}

src/v/kafka/protocol/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ redpanda_cc_library(
7373
deps = [
7474
":messages",
7575
":protocol",
76+
"//src/v/base",
7677
"//src/v/net:types",
7778
"//src/v/utils:vint",
7879
"@seastar",

src/v/kafka/protocol/flex_versions.cc

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "kafka/protocol/flex_versions.h"
1111

12+
#include "base/units.h"
1213
#include "kafka/protocol/messages.h"
1314
#include "kafka/protocol/types.h"
1415
#include "kafka/protocol/wire.h"
@@ -17,8 +18,6 @@
1718

1819
#include <seastar/core/iostream.hh>
1920

20-
#include <stdexcept>
21-
2221
namespace kafka {
2322

2423
namespace {
@@ -49,6 +48,11 @@ get_flexible_request_min_versions_list(type_list<RequestTypes...> r) {
4948
constexpr auto g_flex_mapping = get_flexible_request_min_versions_list(
5049
request_types());
5150

51+
struct protocol_parse_exception : public net::parsing_exception {
52+
explicit protocol_parse_exception(const std::string& m)
53+
: net::parsing_exception(m) {}
54+
};
55+
5256
} // namespace
5357

5458
bool flex_versions::is_flexible_request(api_key key, api_version version) {
@@ -67,9 +71,20 @@ bool flex_versions::is_api_in_schema(api_key key) noexcept {
6771
return first_flex_version != invalid_api;
6872
}
6973

74+
namespace {
75+
// TODO(C++26): replace with std::sub_sat
76+
size_t sub_sat(size_t a, size_t b) {
77+
size_t c = 0;
78+
if (!__builtin_sub_overflow(a, b, &c)) {
79+
return c;
80+
}
81+
return 0;
82+
}
83+
} // namespace
84+
7085
ss::future<std::pair<std::optional<tagged_fields>, size_t>>
7186
// NOLINTNEXTLINE(cppcoreguidelines-avoid-reference-coroutine-parameters)
72-
parse_tags(ss::input_stream<char>& src) {
87+
parse_tags(ss::input_stream<char>& src, size_t max_bytes) {
7388
size_t total_bytes_read = 0;
7489
auto read_unsigned_vint =
7590
// NOLINTNEXTLINE(cppcoreguidelines-avoid-reference-coroutine-parameters)
@@ -94,26 +109,44 @@ parse_tags(ss::input_stream<char>& src) {
94109
while (num_tags-- > 0) {
95110
auto id = co_await read_unsigned_vint(total_bytes_read, src);
96111
auto next_len = co_await read_unsigned_vint(total_bytes_read, src);
112+
if (next_len > sub_sat(max_bytes, total_bytes_read)) {
113+
throw protocol_parse_exception(
114+
fmt::format(
115+
"tagged field {} length {} exceeds remaining message budget {}",
116+
id,
117+
next_len,
118+
max_bytes - total_bytes_read));
119+
}
97120
if (next_len > 128_KiB) {
98-
throw std::invalid_argument(
99-
fmt::format("Too large of a tagged field: {}", next_len));
121+
throw protocol_parse_exception(
122+
fmt::format(
123+
"tagged field {} length {} exceeds 128 KiB limit",
124+
id,
125+
next_len));
100126
}
101127
auto buf = co_await src.read_exactly(next_len);
128+
if (buf.size() != next_len) {
129+
throw protocol_parse_exception(
130+
fmt::format(
131+
"short read for tagged field {} length {} but got {}",
132+
id,
133+
next_len,
134+
buf.size()));
135+
}
102136
bytes data(bytes::initialized_later{}, buf.size());
103137
std::copy_n(buf.begin(), buf.size(), data.begin());
104138
total_bytes_read += next_len;
105139
auto [_, succeded] = tags.emplace(tag_id(id), std::move(data));
106140
if (!succeded) {
107-
throw std::logic_error(
108-
fmt::format("Protocol error, duplicate tag id detected, {}", id));
141+
throw protocol_parse_exception(
142+
fmt::format("duplicate tag id detected: {}", id));
109143
}
110144
}
111145
co_return std::make_pair(std::move(tags), total_bytes_read);
112146
}
113147

114148
namespace {
115149
struct invalid_buffer_size_exception : public net::parsing_exception {
116-
public:
117150
explicit invalid_buffer_size_exception(const std::string& m)
118151
: net::parsing_exception(m) {}
119152
};

src/v/kafka/protocol/flex_versions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,6 @@ class flex_versions {
4242
};
4343

4444
ss::future<std::pair<std::optional<tagged_fields>, size_t>>
45-
parse_tags(ss::input_stream<char>&);
45+
parse_tags(ss::input_stream<char>&, size_t max_bytes);
4646

4747
} // namespace kafka

src/v/kafka/server/connection_context.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ ss::future<> connection_context::process_one_request() {
480480
}
481481
}
482482

483-
auto h = co_await parse_header(conn->input());
483+
auto h = co_await parse_header(conn->input(), sz.value());
484484
_server.probe().add_bytes_received(sz.value());
485485
if (!h) {
486486
vlog(klog.debug, "could not parse header from client: {}", conn->addr);

src/v/kafka/server/protocol_utils.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ parse_v1_header(ss::input_stream<char>& src) {
9898
}
9999

100100
ss::future<std::optional<request_header>>
101-
parse_header(ss::input_stream<char>& src) {
101+
parse_header(ss::input_stream<char>& src, size_t request_size) {
102102
auto header = co_await parse_v1_header(src);
103103
if (header) {
104104
/// Conditionally handle v1 (flex) header
@@ -108,7 +108,7 @@ parse_header(ss::input_stream<char>& src) {
108108
/// reaches the request router
109109
} else if (
110110
flex_versions::is_flexible_request(header->key, header->version)) {
111-
auto [tags, bytes_read] = co_await parse_tags(src);
111+
auto [tags, bytes_read] = co_await parse_tags(src, request_size);
112112
header->tags = std::move(tags);
113113
header->tags_size_bytes = bytes_read;
114114
}

src/v/kafka/server/protocol_utils.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
namespace kafka {
2424

2525
// TODO: move to iobuf_parser
26-
ss::future<std::optional<request_header>> parse_header(ss::input_stream<char>&);
26+
ss::future<std::optional<request_header>>
27+
parse_header(ss::input_stream<char>&, size_t request_size);
2728

2829
ss::scattered_message<char> response_as_scattered(response_ptr response);
2930

0 commit comments

Comments
 (0)