xref: /aosp_15_r20/external/cronet/net/socket/fuzzed_socket.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2016 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/socket/fuzzed_socket.h"
6 
7 #include <fuzzer/FuzzedDataProvider.h>
8 
9 #include "base/check_op.h"
10 #include "base/functional/bind.h"
11 #include "base/location.h"
12 #include "base/notreached.h"
13 #include "base/ranges/algorithm.h"
14 #include "base/task/single_thread_task_runner.h"
15 #include "net/base/io_buffer.h"
16 #include "net/log/net_log_source_type.h"
17 #include "net/traffic_annotation/network_traffic_annotation.h"
18 
19 namespace net {
20 
21 namespace {
22 
23 const int kMaxAsyncReadsAndWrites = 1000;
24 
25 // Some of the socket errors that can be returned by normal socket connection
26 // attempts.
27 const Error kConnectErrors[] = {
28     ERR_CONNECTION_RESET,     ERR_CONNECTION_CLOSED, ERR_FAILED,
29     ERR_CONNECTION_TIMED_OUT, ERR_ACCESS_DENIED,     ERR_CONNECTION_REFUSED,
30     ERR_ADDRESS_UNREACHABLE};
31 
32 // Some of the socket errors that can be returned by normal socket reads /
33 // writes. The first one is returned when no more input data remains, so it's
34 // one of the most common ones.
35 const Error kReadWriteErrors[] = {ERR_CONNECTION_CLOSED, ERR_FAILED,
36                                   ERR_TIMED_OUT, ERR_CONNECTION_RESET};
37 
38 }  // namespace
39 
FuzzedSocket(FuzzedDataProvider * data_provider,net::NetLog * net_log)40 FuzzedSocket::FuzzedSocket(FuzzedDataProvider* data_provider,
41                            net::NetLog* net_log)
42     : data_provider_(data_provider),
43       net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::SOCKET)),
44       remote_address_(IPEndPoint(IPAddress::IPv4Localhost(), 80)) {}
45 
46 FuzzedSocket::~FuzzedSocket() = default;
47 
Read(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)48 int FuzzedSocket::Read(IOBuffer* buf,
49                        int buf_len,
50                        CompletionOnceCallback callback) {
51   DCHECK(!connect_pending_);
52   DCHECK(!read_pending_);
53 
54   bool sync;
55   int result;
56 
57   if (net_error_ != OK) {
58     // If an error has already been generated, use it to determine what to do.
59     result = net_error_;
60     sync = !error_pending_;
61   } else {
62     // Otherwise, use |data_provider_|. Always consume a bool, even when
63     // ForceSync() is true, to behave more consistently against input mutations.
64     sync = data_provider_->ConsumeBool() || ForceSync();
65 
66     num_async_reads_and_writes_ += static_cast<int>(!sync);
67 
68     std::string data = data_provider_->ConsumeRandomLengthString(buf_len);
69     result = data.size();
70 
71     if (!data.empty()) {
72       base::ranges::copy(data, buf->data());
73     } else {
74       result = ConsumeReadWriteErrorFromData();
75       net_error_ = result;
76       if (!sync)
77         error_pending_ = true;
78     }
79   }
80 
81   // Graceful close of a socket returns OK, at least in theory. This doesn't
82   // perfectly reflect real socket behavior, but close enough.
83   if (result == ERR_CONNECTION_CLOSED)
84     result = 0;
85 
86   if (sync) {
87     if (result > 0)
88       total_bytes_read_ += result;
89     return result;
90   }
91 
92   read_pending_ = true;
93   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
94       FROM_HERE,
95       base::BindOnce(&FuzzedSocket::OnReadComplete, weak_factory_.GetWeakPtr(),
96                      std::move(callback), result));
97   return ERR_IO_PENDING;
98 }
99 
Write(IOBuffer * buf,int buf_len,CompletionOnceCallback callback,const NetworkTrafficAnnotationTag &)100 int FuzzedSocket::Write(
101     IOBuffer* buf,
102     int buf_len,
103     CompletionOnceCallback callback,
104     const NetworkTrafficAnnotationTag& /* traffic_annotation */) {
105   DCHECK(!connect_pending_);
106   DCHECK(!write_pending_);
107 
108   bool sync;
109   int result;
110 
111   if (net_error_ != OK) {
112     // If an error has already been generated, use it to determine what to do.
113     result = net_error_;
114     sync = !error_pending_;
115   } else {
116     // Otherwise, use |data_provider_|. Always consume a bool, even when
117     // ForceSync() is true, to behave more consistently against input mutations.
118     sync = data_provider_->ConsumeBool() || ForceSync();
119 
120     num_async_reads_and_writes_ += static_cast<int>(!sync);
121 
122     // Intentionally using smaller |result| size here.
123     result = data_provider_->ConsumeIntegralInRange<int>(0, 0xFF);
124     if (result > buf_len)
125       result = buf_len;
126     if (result == 0) {
127       net_error_ = ConsumeReadWriteErrorFromData();
128       result = net_error_;
129       if (!sync)
130         error_pending_ = true;
131     }
132   }
133 
134   if (sync) {
135     if (result > 0)
136       total_bytes_written_ += result;
137     return result;
138   }
139 
140   write_pending_ = true;
141   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
142       FROM_HERE,
143       base::BindOnce(&FuzzedSocket::OnWriteComplete, weak_factory_.GetWeakPtr(),
144                      std::move(callback), result));
145   return ERR_IO_PENDING;
146 }
147 
SetReceiveBufferSize(int32_t size)148 int FuzzedSocket::SetReceiveBufferSize(int32_t size) {
149   return OK;
150 }
151 
SetSendBufferSize(int32_t size)152 int FuzzedSocket::SetSendBufferSize(int32_t size) {
153   return OK;
154 }
155 
Bind(const net::IPEndPoint & local_addr)156 int FuzzedSocket::Bind(const net::IPEndPoint& local_addr) {
157   NOTREACHED();
158   return ERR_NOT_IMPLEMENTED;
159 }
160 
Connect(CompletionOnceCallback callback)161 int FuzzedSocket::Connect(CompletionOnceCallback callback) {
162   // Sockets can normally be reused, but don't support it here.
163   DCHECK_NE(net_error_, OK);
164   DCHECK(!connect_pending_);
165   DCHECK(!read_pending_);
166   DCHECK(!write_pending_);
167   DCHECK(!error_pending_);
168   DCHECK(!total_bytes_read_);
169   DCHECK(!total_bytes_written_);
170 
171   bool sync = true;
172   Error result = OK;
173   if (fuzz_connect_result_) {
174     // Decide if sync or async. Use async, if no data is left.
175     sync = data_provider_->ConsumeBool();
176     // Decide if the connect succeeds or not, and if so, pick an error code.
177     if (data_provider_->ConsumeBool())
178       result = data_provider_->PickValueInArray(kConnectErrors);
179   }
180 
181   if (sync) {
182     net_error_ = result;
183     return result;
184   }
185 
186   connect_pending_ = true;
187   if (result != OK)
188     error_pending_ = true;
189   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
190       FROM_HERE,
191       base::BindOnce(&FuzzedSocket::OnConnectComplete,
192                      weak_factory_.GetWeakPtr(), std::move(callback), result));
193   return ERR_IO_PENDING;
194 }
195 
Disconnect()196 void FuzzedSocket::Disconnect() {
197   net_error_ = ERR_CONNECTION_CLOSED;
198   weak_factory_.InvalidateWeakPtrs();
199   connect_pending_ = false;
200   read_pending_ = false;
201   write_pending_ = false;
202   error_pending_ = false;
203 }
204 
IsConnected() const205 bool FuzzedSocket::IsConnected() const {
206   return net_error_ == OK && !error_pending_;
207 }
208 
IsConnectedAndIdle() const209 bool FuzzedSocket::IsConnectedAndIdle() const {
210   return IsConnected();
211 }
212 
GetPeerAddress(IPEndPoint * address) const213 int FuzzedSocket::GetPeerAddress(IPEndPoint* address) const {
214   if (!IsConnected())
215     return ERR_SOCKET_NOT_CONNECTED;
216   *address = remote_address_;
217   return OK;
218 }
219 
GetLocalAddress(IPEndPoint * address) const220 int FuzzedSocket::GetLocalAddress(IPEndPoint* address) const {
221   if (!IsConnected())
222     return ERR_SOCKET_NOT_CONNECTED;
223   *address = IPEndPoint(IPAddress(127, 0, 0, 1), 43434);
224   return OK;
225 }
226 
NetLog() const227 const NetLogWithSource& FuzzedSocket::NetLog() const {
228   return net_log_;
229 }
230 
WasEverUsed() const231 bool FuzzedSocket::WasEverUsed() const {
232   return total_bytes_written_ != 0 || total_bytes_read_ != 0;
233 }
234 
GetNegotiatedProtocol() const235 NextProto FuzzedSocket::GetNegotiatedProtocol() const {
236   return kProtoUnknown;
237 }
238 
GetSSLInfo(SSLInfo * ssl_info)239 bool FuzzedSocket::GetSSLInfo(SSLInfo* ssl_info) {
240   return false;
241 }
242 
GetTotalReceivedBytes() const243 int64_t FuzzedSocket::GetTotalReceivedBytes() const {
244   return total_bytes_read_;
245 }
246 
ApplySocketTag(const net::SocketTag & tag)247 void FuzzedSocket::ApplySocketTag(const net::SocketTag& tag) {}
248 
ConsumeReadWriteErrorFromData()249 Error FuzzedSocket::ConsumeReadWriteErrorFromData() {
250   return data_provider_->PickValueInArray(kReadWriteErrors);
251 }
252 
OnReadComplete(CompletionOnceCallback callback,int result)253 void FuzzedSocket::OnReadComplete(CompletionOnceCallback callback, int result) {
254   CHECK(read_pending_);
255   read_pending_ = false;
256   if (result <= 0) {
257     error_pending_ = false;
258   } else {
259     total_bytes_read_ += result;
260   }
261   std::move(callback).Run(result);
262 }
263 
OnWriteComplete(CompletionOnceCallback callback,int result)264 void FuzzedSocket::OnWriteComplete(CompletionOnceCallback callback,
265                                    int result) {
266   CHECK(write_pending_);
267   write_pending_ = false;
268   if (result <= 0) {
269     error_pending_ = false;
270   } else {
271     total_bytes_written_ += result;
272   }
273   std::move(callback).Run(result);
274 }
275 
OnConnectComplete(CompletionOnceCallback callback,int result)276 void FuzzedSocket::OnConnectComplete(CompletionOnceCallback callback,
277                                      int result) {
278   CHECK(connect_pending_);
279   connect_pending_ = false;
280   if (result < 0)
281     error_pending_ = false;
282   net_error_ = result;
283   std::move(callback).Run(result);
284 }
285 
ForceSync() const286 bool FuzzedSocket::ForceSync() const {
287   return (num_async_reads_and_writes_ >= kMaxAsyncReadsAndWrites);
288 }
289 
290 }  // namespace net
291