Skip to content

Commit b6d3a3d

Browse files
alvestrandmibrunin
authored andcommitted
[Backport] CVE-2025-7657: Use after free in WebRTC
Manual cherry-pick of patch originally reviewed on https://chromium-review.googlesource.com/c/chromium/src/+/6694889: Harden P2PSocketTcpBase::SendBatch against errors This change ensures that even if errors occur that cause the socket to be deleted during packet processing, SendBatch will terminate correctly. Bug: 427681143 Change-Id: I41da6789c8aab44b31c00c6a7844cd86b918561c Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6694889 Reviewed-by: Sergey Ulanov <[email protected]> Commit-Queue: Harald Alvestrand <[email protected]> Cr-Commit-Position: refs/heads/main@{#1481925} Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/665025 Reviewed-by: Allan Sandfeld Jensen <[email protected]>
1 parent 2e9beb5 commit b6d3a3d

File tree

2 files changed

+74
-48
lines changed

2 files changed

+74
-48
lines changed

chromium/services/network/p2p/socket_tcp.cc

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,13 @@ P2PSocketTcpBase::P2PSocketTcpBase(
6868

6969
P2PSocketTcpBase::~P2PSocketTcpBase() = default;
7070

71-
void P2PSocketTcpBase::InitAccepted(const net::IPEndPoint& remote_address,
71+
bool P2PSocketTcpBase::InitAccepted(const net::IPEndPoint& remote_address,
7272
std::unique_ptr<net::StreamSocket> socket) {
7373
DCHECK(socket);
7474
remote_address_.ip_address = remote_address;
7575
// TODO(ronghuawu): Add FakeSSLServerSocket.
7676
socket_ = std::move(socket);
77-
DoRead();
77+
return DoRead();
7878
}
7979

8080
void P2PSocketTcpBase::Init(
@@ -123,15 +123,18 @@ void P2PSocketTcpBase::OnConnected(int result) {
123123
DCHECK_NE(result, net::ERR_IO_PENDING);
124124

125125
if (result != net::OK) {
126-
LOG(WARNING) << "Error from connecting socket, result=" << result;
126+
LOG(WARNING) << "Error from connecting socket, result=" << result
127+
<< ", destroying socket";
127128
OnError();
128129
return;
129130
}
130131

131-
OnOpen();
132+
if (!OnOpen()) {
133+
LOG(ERROR) << "Socket destroyed in OnConnected/OnOpen";
134+
}
132135
}
133136

134-
void P2PSocketTcpBase::OnOpen() {
137+
bool P2PSocketTcpBase::OnOpen() {
135138
// Setting socket send and receive buffer size.
136139
if (net::OK != socket_->SetReceiveBufferSize(kTcpRecvSocketBufferSize)) {
137140
LOG(WARNING) << "Failed to set socket receive buffer size to "
@@ -144,9 +147,9 @@ void P2PSocketTcpBase::OnOpen() {
144147
}
145148

146149
if (!DoSendSocketCreateMsg())
147-
return;
150+
return false;
148151

149-
DoRead();
152+
return DoRead();
150153
}
151154

152155
bool P2PSocketTcpBase::DoSendSocketCreateMsg() {
@@ -193,7 +196,7 @@ bool P2PSocketTcpBase::DoSendSocketCreateMsg() {
193196
return true;
194197
}
195198

196-
void P2PSocketTcpBase::DoRead() {
199+
bool P2PSocketTcpBase::DoRead() {
197200
while (true) {
198201
if (!read_buffer_.get()) {
199202
read_buffer_ = base::MakeRefCounted<net::GrowableIOBuffer>();
@@ -209,14 +212,23 @@ void P2PSocketTcpBase::DoRead() {
209212
const int result = socket_->Read(
210213
read_buffer_.get(), read_buffer_->RemainingCapacity(),
211214
base::BindOnce(&P2PSocketTcp::OnRead, base::Unretained(this)));
212-
if (result == net::ERR_IO_PENDING || !HandleReadResult(result))
213-
return;
215+
if (result == net::ERR_IO_PENDING) {
216+
return true; // not finished, but blocked
217+
}
218+
if (!HandleReadResult(result)) {
219+
return false; // error, socket deleted
220+
}
214221
}
215222
}
216223

217224
void P2PSocketTcpBase::OnRead(int result) {
218-
if (HandleReadResult(result))
219-
DoRead();
225+
if (!HandleReadResult(result)) {
226+
LOG(ERROR) << "OnRead/HandleReadResult reports socket destroyed";
227+
return;
228+
}
229+
if (!DoRead()) {
230+
LOG(ERROR) << "OnRead/DoRead reports socket destroyed";
231+
}
220232
}
221233

222234
bool P2PSocketTcpBase::OnPacket(base::span<const uint8_t> data) {
@@ -256,17 +268,17 @@ bool P2PSocketTcpBase::OnPacket(base::span<const uint8_t> data) {
256268
return true;
257269
}
258270

259-
void P2PSocketTcpBase::WriteOrQueue(SendBuffer& send_buffer) {
271+
bool P2PSocketTcpBase::WriteOrQueue(SendBuffer& send_buffer) {
260272
if (write_buffer_.buffer.get()) {
261273
write_queue_.push(send_buffer);
262-
return;
274+
return true;
263275
}
264276

265277
write_buffer_ = send_buffer;
266-
DoWrite();
278+
return DoWrite();
267279
}
268280

269-
void P2PSocketTcpBase::DoWrite() {
281+
bool P2PSocketTcpBase::DoWrite() {
270282
while (!write_pending_ && write_buffer_.buffer.get()) {
271283
int result = socket_->Write(
272284
write_buffer_.buffer.get(), write_buffer_.buffer->BytesRemaining(),
@@ -276,9 +288,10 @@ void P2PSocketTcpBase::DoWrite() {
276288
if (result == net::ERR_IO_PENDING) {
277289
write_pending_ = true;
278290
} else if (!HandleWriteResult(result)) {
279-
break;
291+
return false; // Error, socket is destroyed.
280292
}
281293
}
294+
return true;
282295
}
283296

284297
void P2PSocketTcpBase::OnWritten(int result) {
@@ -287,8 +300,13 @@ void P2PSocketTcpBase::OnWritten(int result) {
287300

288301
write_pending_ = false;
289302

290-
if (HandleWriteResult(result))
291-
DoWrite();
303+
if (!HandleWriteResult(result)) {
304+
LOG(ERROR) << "Socket destroyed in OnWritten/HandleWriteResult";
305+
return;
306+
}
307+
if (!DoWrite()) {
308+
LOG(ERROR) << "Socket destroyed in OnWritten/DoWrite";
309+
}
292310
}
293311

294312
bool P2PSocketTcpBase::HandleWriteResult(int result) {
@@ -376,13 +394,14 @@ bool P2PSocketTcpBase::SendPacket(base::span<const uint8_t> data,
376394
}
377395
}
378396

379-
DoSend(packet_info.destination, data, packet_info.packet_options);
380-
return true;
397+
return DoSend(packet_info.destination, data, packet_info.packet_options);
381398
}
382399

383400
void P2PSocketTcpBase::Send(base::span<const uint8_t> data,
384401
const P2PPacketInfo& packet_info) {
385-
SendPacket(data, packet_info);
402+
if (!SendPacket(data, packet_info)) {
403+
LOG(ERROR) << "Socket destroyed while sending";
404+
}
386405
}
387406

388407
void P2PSocketTcpBase::SendBatch(
@@ -448,7 +467,7 @@ bool P2PSocketTcp::ProcessInput(base::span<const uint8_t> input,
448467
return OnPacket(input.subspan(kPacketHeaderSize, packet_size));
449468
}
450469

451-
void P2PSocketTcp::DoSend(const net::IPEndPoint& to,
470+
bool P2PSocketTcp::DoSend(const net::IPEndPoint& to,
452471
base::span<const uint8_t> data,
453472
const rtc::PacketOptions& options) {
454473
int buffer_size = kPacketHeaderSize + data.size();
@@ -467,7 +486,7 @@ void P2PSocketTcp::DoSend(const net::IPEndPoint& to,
467486
send_buffer.buffer->BytesRemaining() - kPacketHeaderSize,
468487
options.packet_time_params, rtc::TimeMicros());
469488

470-
WriteOrQueue(send_buffer);
489+
return WriteOrQueue(send_buffer);
471490
}
472491

473492
// P2PSocketStunTcp
@@ -508,15 +527,15 @@ bool P2PSocketStunTcp::ProcessInput(base::span<const uint8_t> input,
508527
return OnPacket(input.subspan(0, packet_size));
509528
}
510529

511-
void P2PSocketStunTcp::DoSend(const net::IPEndPoint& to,
530+
bool P2PSocketStunTcp::DoSend(const net::IPEndPoint& to,
512531
base::span<const uint8_t> data,
513532
const rtc::PacketOptions& options) {
514533
// Each packet is expected to have header (STUN/TURN ChannelData), where
515534
// header contains message type and and length of message.
516535
if (data.size() < kPacketHeaderSize + kPacketLengthOffset) {
517536
NOTREACHED();
518537
OnError();
519-
return;
538+
return false;
520539
}
521540

522541
int pad_bytes;
@@ -526,7 +545,7 @@ void P2PSocketStunTcp::DoSend(const net::IPEndPoint& to,
526545
if (data.size() != expected_len) {
527546
NOTREACHED();
528547
OnError();
529-
return;
548+
return false;
530549
}
531550

532551
// Add any pad bytes to the total size.
@@ -554,7 +573,7 @@ void P2PSocketStunTcp::DoSend(const net::IPEndPoint& to,
554573
data.size()),
555574
false);
556575

557-
WriteOrQueue(send_buffer);
576+
return WriteOrQueue(send_buffer);
558577
}
559578

560579
int P2PSocketStunTcp::GetExpectedPacketSize(base::span<const uint8_t> data,

chromium/services/network/p2p/socket_tcp.h

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) P2PSocketTcpBase : public P2PSocket {
4545

4646
~P2PSocketTcpBase() override;
4747

48-
void InitAccepted(const net::IPEndPoint& remote_address,
49-
std::unique_ptr<net::StreamSocket> socket);
48+
// The TCP socket is deleted on errors; in this case, false is returned.
49+
[[nodiscard]] bool InitAccepted(const net::IPEndPoint& remote_address,
50+
std::unique_ptr<net::StreamSocket> socket);
5051

5152
// P2PSocket overrides.
5253
void Init(
@@ -76,36 +77,40 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) P2PSocketTcpBase : public P2PSocket {
7677
// Derived classes will provide the implementation.
7778
virtual bool ProcessInput(base::span<const uint8_t> input,
7879
size_t* bytes_consumed) = 0;
79-
virtual void DoSend(const net::IPEndPoint& to,
80-
base::span<const uint8_t> data,
81-
const rtc::PacketOptions& options) = 0;
80+
[[nodiscard]] virtual bool DoSend(
81+
const net::IPEndPoint& to,
82+
base::span<const uint8_t> data,
83+
const rtc::PacketOptions& options) = 0;
8284

83-
void WriteOrQueue(SendBuffer& send_buffer);
85+
[[nodiscard]] bool WriteOrQueue(SendBuffer& send_buffer);
8486
[[nodiscard]] bool OnPacket(base::span<const uint8_t> data);
8587

86-
bool SendPacket(base::span<const uint8_t> data,
87-
const P2PPacketInfo& packet_info);
88+
[[nodiscard]] bool SendPacket(base::span<const uint8_t> data,
89+
const P2PPacketInfo& packet_info);
8890

8991
private:
9092
friend class P2PSocketTcpTestBase;
9193
friend class P2PSocketTcpServerTest;
9294

93-
void DoRead();
94-
void DoWrite();
95+
// These functions return |false| in case of an error.
96+
// The socket is destroyed in that case, so the caller should not use |this|.
97+
[[nodiscard]] bool DoRead();
98+
[[nodiscard]] bool DoWrite();
9599

96-
// Return |false| in case of an error. The socket is destroyed in that case,
97-
// so the caller should not use |this|.
98100
[[nodiscard]] bool HandleReadResult(int result);
99101
[[nodiscard]] bool HandleWriteResult(int result);
100102

101103
// Callbacks for Connect(), Read() and Write().
104+
// Socket destruction may happen in these functions, but they are
105+
// invoked asynchronously, on the same thread, so we assume that
106+
// socket destruction doesn't happen while a function is active.
102107
void OnConnected(int result);
103108
void OnRead(int result);
104109
void OnWritten(int result);
105110

106111
// Helper method to send socket create message and start read.
107-
void OnOpen();
108-
bool DoSendSocketCreateMsg();
112+
[[nodiscard]] bool OnOpen();
113+
[[nodiscard]] bool DoSendSocketCreateMsg();
109114

110115
P2PHostAndIPEndPoint remote_address_;
111116

@@ -140,9 +145,10 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) P2PSocketTcp : public P2PSocketTcpBase {
140145
protected:
141146
bool ProcessInput(base::span<const uint8_t> input,
142147
size_t* bytes_consumed) override;
143-
void DoSend(const net::IPEndPoint& to,
144-
base::span<const uint8_t> data,
145-
const rtc::PacketOptions& options) override;
148+
[[nodiscard]] bool DoSend(
149+
const net::IPEndPoint& to,
150+
base::span<const uint8_t> data,
151+
const rtc::PacketOptions& options) override;
146152
};
147153

148154
// P2PSocketStunTcp class provides the framing of STUN messages when used
@@ -168,9 +174,10 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) P2PSocketStunTcp
168174
protected:
169175
bool ProcessInput(base::span<const uint8_t> input,
170176
size_t* bytes_consumed) override;
171-
void DoSend(const net::IPEndPoint& to,
172-
base::span<const uint8_t> data,
173-
const rtc::PacketOptions& options) override;
177+
[[nodiscard]] bool DoSend(
178+
const net::IPEndPoint& to,
179+
base::span<const uint8_t> data,
180+
const rtc::PacketOptions& options) override;
174181

175182
private:
176183
int GetExpectedPacketSize(base::span<const uint8_t> data, int* pad_bytes);

0 commit comments

Comments
 (0)