xref: /aosp_15_r20/external/cronet/net/socket/fuzzed_datagram_client_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_datagram_client_socket.h"
6 
7 #include <fuzzer/FuzzedDataProvider.h>
8 
9 #include <string>
10 
11 #include "base/check_op.h"
12 #include "base/functional/bind.h"
13 #include "base/location.h"
14 #include "base/ranges/algorithm.h"
15 #include "base/strings/string_piece.h"
16 #include "base/task/single_thread_task_runner.h"
17 #include "net/base/io_buffer.h"
18 #include "net/base/ip_address.h"
19 #include "net/base/net_errors.h"
20 #include "net/traffic_annotation/network_traffic_annotation.h"
21 
22 namespace net {
23 
24 // Subset of network errors that can occur on each operation. Less clear cut
25 // than TCP errors, so some of these may not actually be possible.
26 const Error kConnectErrors[] = {ERR_FAILED, ERR_ADDRESS_UNREACHABLE,
27                                 ERR_ACCESS_DENIED};
28 const Error kReadErrors[] = {ERR_FAILED, ERR_ADDRESS_UNREACHABLE};
29 const Error kWriteErrors[] = {ERR_FAILED, ERR_ADDRESS_UNREACHABLE,
30                               ERR_MSG_TOO_BIG};
31 
FuzzedDatagramClientSocket(FuzzedDataProvider * data_provider)32 FuzzedDatagramClientSocket::FuzzedDatagramClientSocket(
33     FuzzedDataProvider* data_provider)
34     : data_provider_(data_provider) {}
35 
36 FuzzedDatagramClientSocket::~FuzzedDatagramClientSocket() = default;
37 
Connect(const IPEndPoint & address)38 int FuzzedDatagramClientSocket::Connect(const IPEndPoint& address) {
39   CHECK(!connected_);
40 
41   // Decide if the connect attempt succeeds.
42   if (data_provider_->ConsumeBool()) {
43     connected_ = true;
44     remote_address_ = address;
45     return OK;
46   }
47 
48   // On failure, return a random connect error.
49   return data_provider_->PickValueInArray(kConnectErrors);
50 }
51 
ConnectUsingNetwork(handles::NetworkHandle network,const IPEndPoint & address)52 int FuzzedDatagramClientSocket::ConnectUsingNetwork(
53     handles::NetworkHandle network,
54     const IPEndPoint& address) {
55   CHECK(!connected_);
56   return ERR_NOT_IMPLEMENTED;
57 }
58 
59 int FuzzedDatagramClientSocket::FuzzedDatagramClientSocket::
ConnectUsingDefaultNetwork(const IPEndPoint & address)60     ConnectUsingDefaultNetwork(const IPEndPoint& address) {
61   CHECK(!connected_);
62   return ERR_NOT_IMPLEMENTED;
63 }
64 
ConnectAsync(const IPEndPoint & address,CompletionOnceCallback callback)65 int FuzzedDatagramClientSocket::ConnectAsync(const IPEndPoint& address,
66                                              CompletionOnceCallback callback) {
67   CHECK(!connected_);
68   int rv = Connect(address);
69   DCHECK_NE(rv, ERR_IO_PENDING);
70   if (data_provider_->ConsumeBool()) {
71     base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
72         FROM_HERE, base::BindOnce(std::move(callback), rv));
73     return ERR_IO_PENDING;
74   }
75   return rv;
76 }
77 
ConnectUsingNetworkAsync(handles::NetworkHandle network,const IPEndPoint & address,CompletionOnceCallback callback)78 int FuzzedDatagramClientSocket::ConnectUsingNetworkAsync(
79     handles::NetworkHandle network,
80     const IPEndPoint& address,
81     CompletionOnceCallback callback) {
82   CHECK(!connected_);
83   return ERR_NOT_IMPLEMENTED;
84 }
85 
ConnectUsingDefaultNetworkAsync(const IPEndPoint & address,CompletionOnceCallback callback)86 int FuzzedDatagramClientSocket::ConnectUsingDefaultNetworkAsync(
87     const IPEndPoint& address,
88     CompletionOnceCallback callback) {
89   CHECK(!connected_);
90   return ERR_NOT_IMPLEMENTED;
91 }
92 
GetBoundNetwork() const93 handles::NetworkHandle FuzzedDatagramClientSocket::GetBoundNetwork() const {
94   return handles::kInvalidNetworkHandle;
95 }
96 
ApplySocketTag(const SocketTag & tag)97 void FuzzedDatagramClientSocket::ApplySocketTag(const SocketTag& tag) {}
98 
Close()99 void FuzzedDatagramClientSocket::Close() {
100   connected_ = false;
101   read_pending_ = false;
102   write_pending_ = false;
103   remote_address_ = IPEndPoint();
104   weak_factory_.InvalidateWeakPtrs();
105 }
106 
GetPeerAddress(IPEndPoint * address) const107 int FuzzedDatagramClientSocket::GetPeerAddress(IPEndPoint* address) const {
108   if (!connected_)
109     return ERR_SOCKET_NOT_CONNECTED;
110   *address = remote_address_;
111   return OK;
112 }
113 
GetLocalAddress(IPEndPoint * address) const114 int FuzzedDatagramClientSocket::GetLocalAddress(IPEndPoint* address) const {
115   if (!connected_)
116     return ERR_SOCKET_NOT_CONNECTED;
117   *address = IPEndPoint(IPAddress(1, 2, 3, 4), 43210);
118   return OK;
119 }
120 
UseNonBlockingIO()121 void FuzzedDatagramClientSocket::UseNonBlockingIO() {}
122 
SetMulticastInterface(uint32_t interface_index)123 int FuzzedDatagramClientSocket::SetMulticastInterface(
124     uint32_t interface_index) {
125   return ERR_NOT_IMPLEMENTED;
126 }
127 
NetLog() const128 const NetLogWithSource& FuzzedDatagramClientSocket::NetLog() const {
129   return net_log_;
130 }
131 
Read(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)132 int FuzzedDatagramClientSocket::Read(IOBuffer* buf,
133                                      int buf_len,
134                                      CompletionOnceCallback callback) {
135   CHECK(!callback.is_null());
136   CHECK_GT(buf_len, 0);
137   CHECK(!read_pending_);
138 
139   // Normally calling this on disconnected sockets is allowed, but code really
140   // shouldn't be doing this.  If it is, it's best to figure out why, and fix
141   // it. Note that |connected_| is only set to false on calls to Close(), not on
142   // errors.
143   CHECK(connected_);
144 
145   // Get contents of response.
146   std::string data = data_provider_->ConsumeRandomLengthString(
147       data_provider_->ConsumeIntegralInRange(0, buf_len));
148 
149   int result;
150   if (!data.empty()) {
151     // If the response is not empty, consider it a successful read.
152     result = data.size();
153     base::ranges::copy(data, buf->data());
154   } else {
155     // If the response is empty, pick a random read error.
156     result = data_provider_->PickValueInArray(kReadErrors);
157   }
158 
159   // Decide if result should be returned synchronously.
160   if (data_provider_->ConsumeBool())
161     return result;
162 
163   read_pending_ = true;
164   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
165       FROM_HERE,
166       base::BindOnce(&FuzzedDatagramClientSocket::OnReadComplete,
167                      weak_factory_.GetWeakPtr(), std::move(callback), result));
168   return ERR_IO_PENDING;
169 }
170 
Write(IOBuffer * buf,int buf_len,CompletionOnceCallback callback,const NetworkTrafficAnnotationTag &)171 int FuzzedDatagramClientSocket::Write(
172     IOBuffer* buf,
173     int buf_len,
174     CompletionOnceCallback callback,
175     const NetworkTrafficAnnotationTag& /* traffic_annotation */) {
176   CHECK(!callback.is_null());
177   CHECK(!write_pending_);
178 
179   // Normally this is allowed, but code really shouldn't be doing this - if it
180   // is, it's best to figure out why, and fix it.
181   CHECK(connected_);
182 
183   int result;
184   // Decide if success or failure.
185   if (data_provider_->ConsumeBool()) {
186     // On success, everything is written.
187     result = buf_len;
188   } else {
189     // On failure, pick a random write error.
190     result = data_provider_->PickValueInArray(kWriteErrors);
191   }
192 
193   // Decide if result should be returned synchronously.
194   if (data_provider_->ConsumeBool())
195     return result;
196 
197   write_pending_ = true;
198   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
199       FROM_HERE,
200       base::BindOnce(&FuzzedDatagramClientSocket::OnWriteComplete,
201                      weak_factory_.GetWeakPtr(), std::move(callback), result));
202   return ERR_IO_PENDING;
203 }
204 
SetReceiveBufferSize(int32_t size)205 int FuzzedDatagramClientSocket::SetReceiveBufferSize(int32_t size) {
206   return OK;
207 }
208 
SetSendBufferSize(int32_t size)209 int FuzzedDatagramClientSocket::SetSendBufferSize(int32_t size) {
210   return OK;
211 }
212 
SetDoNotFragment()213 int FuzzedDatagramClientSocket::SetDoNotFragment() {
214   return OK;
215 }
216 
SetRecvTos()217 int FuzzedDatagramClientSocket::SetRecvTos() {
218   return OK;
219 }
220 
SetTos(DiffServCodePoint dscp,EcnCodePoint ecn)221 int FuzzedDatagramClientSocket::SetTos(DiffServCodePoint dscp,
222                                        EcnCodePoint ecn) {
223   return OK;
224 }
225 
OnReadComplete(net::CompletionOnceCallback callback,int result)226 void FuzzedDatagramClientSocket::OnReadComplete(
227     net::CompletionOnceCallback callback,
228     int result) {
229   CHECK(connected_);
230   CHECK(read_pending_);
231 
232   read_pending_ = false;
233   std::move(callback).Run(result);
234 }
235 
OnWriteComplete(net::CompletionOnceCallback callback,int result)236 void FuzzedDatagramClientSocket::OnWriteComplete(
237     net::CompletionOnceCallback callback,
238     int result) {
239   CHECK(connected_);
240   CHECK(write_pending_);
241 
242   write_pending_ = false;
243   std::move(callback).Run(result);
244 }
245 
GetLastTos() const246 DscpAndEcn FuzzedDatagramClientSocket::GetLastTos() const {
247   uint8_t tos;
248   data_provider_->ConsumeData(&tos, 1);
249   return TosToDscpAndEcn(tos);
250 }
251 
252 }  // namespace net
253