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