| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/socket/fuzzed_socket.h" | 5 #include "net/socket/fuzzed_socket.h" |
| 6 | 6 |
| 7 #include <algorithm> |
| 8 |
| 7 #include "base/bind.h" | 9 #include "base/bind.h" |
| 8 #include "base/location.h" | 10 #include "base/location.h" |
| 9 #include "base/logging.h" | 11 #include "base/logging.h" |
| 10 #include "base/thread_task_runner_handle.h" | 12 #include "base/thread_task_runner_handle.h" |
| 13 #include "net/base/fuzzed_data_provider.h" |
| 11 #include "net/base/io_buffer.h" | 14 #include "net/base/io_buffer.h" |
| 12 | 15 |
| 13 namespace net { | 16 namespace net { |
| 14 | 17 |
| 15 namespace { | 18 namespace { |
| 16 | 19 |
| 17 // Subset of the socket errors that can be returned by normal socket reads / | 20 // Some of the socket errors that can be returned by normal socket connection |
| 21 // attempts. |
| 22 const Error kConnectErrors[] = { |
| 23 ERR_CONNECTION_RESET, ERR_CONNECTION_CLOSED, ERR_FAILED, |
| 24 ERR_CONNECTION_TIMED_OUT, ERR_ACCESS_DENIED, ERR_CONNECTION_REFUSED, |
| 25 ERR_ADDRESS_UNREACHABLE}; |
| 26 |
| 27 // Some of the socket errors that can be returned by normal socket reads / |
| 18 // writes. The first one is returned when no more input data remains, so it's | 28 // writes. The first one is returned when no more input data remains, so it's |
| 19 // one of the most common ones. | 29 // one of the most common ones. |
| 20 const Error kReadWriteErrors[] = {ERR_CONNECTION_CLOSED, ERR_FAILED, | 30 const Error kReadWriteErrors[] = {ERR_CONNECTION_CLOSED, ERR_FAILED, |
| 21 ERR_TIMED_OUT, ERR_CONNECTION_RESET}; | 31 ERR_TIMED_OUT, ERR_CONNECTION_RESET}; |
| 22 | 32 |
| 23 } // namespace | 33 } // namespace |
| 24 | 34 |
| 25 FuzzedSocket::FuzzedSocket(const uint8_t* data, | 35 FuzzedSocket::FuzzedSocket(FuzzedDataProvider* data_provider, |
| 26 size_t data_size, | 36 net::NetLog* net_log) |
| 27 const BoundNetLog& bound_net_log) | 37 : data_provider_(data_provider), |
| 28 : data_(reinterpret_cast<const char*>(data), data_size), | 38 bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)), |
| 29 bound_net_log_(bound_net_log), | 39 remote_address_(IPEndPoint(IPAddress::IPv4Localhost(), 80)), |
| 30 weak_factory_(this) {} | 40 weak_factory_(this) {} |
| 31 | 41 |
| 32 FuzzedSocket::~FuzzedSocket() {} | 42 FuzzedSocket::~FuzzedSocket() {} |
| 33 | 43 |
| 34 int FuzzedSocket::Read(IOBuffer* buf, | 44 int FuzzedSocket::Read(IOBuffer* buf, |
| 35 int buf_len, | 45 int buf_len, |
| 36 const CompletionCallback& callback) { | 46 const CompletionCallback& callback) { |
| 47 DCHECK(!connect_pending_); |
| 37 DCHECK(!read_pending_); | 48 DCHECK(!read_pending_); |
| 38 | 49 |
| 39 bool sync; | 50 bool sync; |
| 40 int result; | 51 int result; |
| 41 | 52 |
| 42 if (net_error_ != OK) { | 53 if (net_error_ != OK) { |
| 43 // If an error has already been generated, use it to determine what to do. | 54 // If an error has already been generated, use it to determine what to do. |
| 44 result = net_error_; | 55 result = net_error_; |
| 45 sync = !error_pending_; | 56 sync = !error_pending_; |
| 46 } else { | 57 } else { |
| 47 // Otherwise, use |data_|. | 58 // Otherwise, use |data_provider_|. |
| 48 uint8_t random_val = ConsumeUint8FromData(); | 59 sync = data_provider_->ConsumeBool(); |
| 49 sync = !!(random_val & 0x01); | 60 // This allows for more consistent behavior across mutations of the fuzzed |
| 50 result = random_val >> 1; | 61 // data than ConsumeValueInRange(0,255). |
| 62 result = data_provider_->ConsumeBits(8); |
| 51 if (result > buf_len) | 63 if (result > buf_len) |
| 52 result = buf_len; | 64 result = buf_len; |
| 53 // Can't read more data than is available in |data_|. | 65 |
| 54 if (static_cast<size_t>(result) > data_.length()) | 66 if (result > 0) { |
| 55 result = data_.length(); | 67 base::StringPiece data = data_provider_->ConsumeBytes(result); |
| 68 result = data.length(); |
| 69 std::copy(data.data(), data.data() + result, buf->data()); |
| 70 } |
| 56 | 71 |
| 57 if (result == 0) { | 72 if (result == 0) { |
| 58 net_error_ = ConsumeReadWriteErrorFromData(); | 73 net_error_ = ConsumeReadWriteErrorFromData(); |
| 59 result = net_error_; | 74 result = net_error_; |
| 60 if (!sync) | 75 if (!sync) |
| 61 error_pending_ = true; | 76 error_pending_ = true; |
| 62 } else { | |
| 63 memcpy(buf->data(), data_.data(), result); | |
| 64 data_ = data_.substr(result); | |
| 65 } | 77 } |
| 66 } | 78 } |
| 67 | 79 |
| 68 // Graceful close of a socket returns OK, at least in theory. This doesn't | 80 // Graceful close of a socket returns OK, at least in theory. This doesn't |
| 69 // perfectly reflect real socket behavior, but close enough. | 81 // perfectly reflect real socket behavior, but close enough. |
| 70 if (result == ERR_CONNECTION_CLOSED) | 82 if (result == ERR_CONNECTION_CLOSED) |
| 71 result = 0; | 83 result = 0; |
| 72 | 84 |
| 73 if (sync) { | 85 if (sync) { |
| 74 if (result > 0) | 86 if (result > 0) |
| 75 total_bytes_read_ += result; | 87 total_bytes_read_ += result; |
| 76 return result; | 88 return result; |
| 77 } | 89 } |
| 78 | 90 |
| 79 read_pending_ = true; | 91 read_pending_ = true; |
| 80 base::ThreadTaskRunnerHandle::Get()->PostTask( | 92 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 81 FROM_HERE, base::Bind(&FuzzedSocket::OnReadComplete, | 93 FROM_HERE, base::Bind(&FuzzedSocket::OnReadComplete, |
| 82 weak_factory_.GetWeakPtr(), callback, result)); | 94 weak_factory_.GetWeakPtr(), callback, result)); |
| 83 return ERR_IO_PENDING; | 95 return ERR_IO_PENDING; |
| 84 } | 96 } |
| 85 | 97 |
| 86 int FuzzedSocket::Write(IOBuffer* buf, | 98 int FuzzedSocket::Write(IOBuffer* buf, |
| 87 int buf_len, | 99 int buf_len, |
| 88 const CompletionCallback& callback) { | 100 const CompletionCallback& callback) { |
| 101 DCHECK(!connect_pending_); |
| 89 DCHECK(!write_pending_); | 102 DCHECK(!write_pending_); |
| 90 | 103 |
| 91 bool sync; | 104 bool sync; |
| 92 int result; | 105 int result; |
| 93 | 106 |
| 94 if (net_error_ != OK) { | 107 if (net_error_ != OK) { |
| 95 // If an error has already been generated, use it to determine what to do. | 108 // If an error has already been generated, use it to determine what to do. |
| 96 result = net_error_; | 109 result = net_error_; |
| 97 sync = !error_pending_; | 110 sync = !error_pending_; |
| 98 } else { | 111 } else { |
| 99 // Otherwise, use |data_|. | 112 // Otherwise, use |data_|. |
| 100 uint8_t random_val = ConsumeUint8FromData(); | 113 sync = data_provider_->ConsumeBool(); |
| 101 sync = !!(random_val & 0x01); | 114 // This allows for more consistent behavior across mutations of the fuzzed |
| 102 result = random_val >> 1; | 115 // data than ConsumeValueInRange(0,255). |
| 116 result = data_provider_->ConsumeBits(8); |
| 103 if (result > buf_len) | 117 if (result > buf_len) |
| 104 result = buf_len; | 118 result = buf_len; |
| 105 if (result == 0) { | 119 if (result == 0) { |
| 106 net_error_ = ConsumeReadWriteErrorFromData(); | 120 net_error_ = ConsumeReadWriteErrorFromData(); |
| 107 result = net_error_; | 121 result = net_error_; |
| 108 if (!sync) | 122 if (!sync) |
| 109 error_pending_ = true; | 123 error_pending_ = true; |
| 110 } | 124 } |
| 111 } | 125 } |
| 112 | 126 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 127 return OK; | 141 return OK; |
| 128 } | 142 } |
| 129 | 143 |
| 130 int FuzzedSocket::SetSendBufferSize(int32_t size) { | 144 int FuzzedSocket::SetSendBufferSize(int32_t size) { |
| 131 return OK; | 145 return OK; |
| 132 } | 146 } |
| 133 | 147 |
| 134 int FuzzedSocket::Connect(const CompletionCallback& callback) { | 148 int FuzzedSocket::Connect(const CompletionCallback& callback) { |
| 135 // Sockets can normally be reused, but don't support it here. | 149 // Sockets can normally be reused, but don't support it here. |
| 136 DCHECK_NE(net_error_, OK); | 150 DCHECK_NE(net_error_, OK); |
| 151 DCHECK(!connect_pending_); |
| 137 DCHECK(!read_pending_); | 152 DCHECK(!read_pending_); |
| 138 DCHECK(!write_pending_); | 153 DCHECK(!write_pending_); |
| 139 DCHECK(!error_pending_); | 154 DCHECK(!error_pending_); |
| 140 DCHECK(!total_bytes_read_); | 155 DCHECK(!total_bytes_read_); |
| 141 DCHECK(!total_bytes_written_); | 156 DCHECK(!total_bytes_written_); |
| 142 | 157 |
| 143 net_error_ = OK; | 158 bool sync = true; |
| 144 return OK; | 159 Error result = OK; |
| 160 if (fuzz_connect_result_) { |
| 161 // Decide if sync or async. Use async, if no data is left. |
| 162 sync = data_provider_->ConsumeBool(); |
| 163 // Decide if the connect succeeds or not, and if so, pick an error code. |
| 164 if (data_provider_->ConsumeBool()) { |
| 165 result = kConnectErrors[data_provider_->ConsumeValueInRange( |
| 166 0, arraysize(kConnectErrors) - 1)]; |
| 167 } |
| 168 } |
| 169 |
| 170 if (sync) { |
| 171 net_error_ = result; |
| 172 return result; |
| 173 } |
| 174 |
| 175 connect_pending_ = true; |
| 176 if (result != OK) |
| 177 error_pending_ = true; |
| 178 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 179 FROM_HERE, base::Bind(&FuzzedSocket::OnConnectComplete, |
| 180 weak_factory_.GetWeakPtr(), callback, result)); |
| 181 return ERR_IO_PENDING; |
| 145 } | 182 } |
| 146 | 183 |
| 147 void FuzzedSocket::Disconnect() { | 184 void FuzzedSocket::Disconnect() { |
| 148 net_error_ = ERR_CONNECTION_CLOSED; | 185 net_error_ = ERR_CONNECTION_CLOSED; |
| 149 weak_factory_.InvalidateWeakPtrs(); | 186 weak_factory_.InvalidateWeakPtrs(); |
| 187 connect_pending_ = false; |
| 150 read_pending_ = false; | 188 read_pending_ = false; |
| 151 write_pending_ = false; | 189 write_pending_ = false; |
| 152 error_pending_ = false; | 190 error_pending_ = false; |
| 153 } | 191 } |
| 154 | 192 |
| 155 bool FuzzedSocket::IsConnected() const { | 193 bool FuzzedSocket::IsConnected() const { |
| 156 return net_error_ == OK && !error_pending_; | 194 return net_error_ == OK && !error_pending_; |
| 157 } | 195 } |
| 158 | 196 |
| 159 bool FuzzedSocket::IsConnectedAndIdle() const { | 197 bool FuzzedSocket::IsConnectedAndIdle() const { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 205 } | 243 } |
| 206 | 244 |
| 207 void FuzzedSocket::ClearConnectionAttempts() {} | 245 void FuzzedSocket::ClearConnectionAttempts() {} |
| 208 | 246 |
| 209 void FuzzedSocket::AddConnectionAttempts(const ConnectionAttempts& attempts) {} | 247 void FuzzedSocket::AddConnectionAttempts(const ConnectionAttempts& attempts) {} |
| 210 | 248 |
| 211 int64_t FuzzedSocket::GetTotalReceivedBytes() const { | 249 int64_t FuzzedSocket::GetTotalReceivedBytes() const { |
| 212 return total_bytes_read_; | 250 return total_bytes_read_; |
| 213 } | 251 } |
| 214 | 252 |
| 215 uint8_t FuzzedSocket::ConsumeUint8FromData() { | |
| 216 size_t length = data_.length(); | |
| 217 if (!length) | |
| 218 return 0; | |
| 219 uint8_t out = data_[length - 1]; | |
| 220 data_ = data_.substr(0, length - 1); | |
| 221 return out; | |
| 222 } | |
| 223 | |
| 224 Error FuzzedSocket::ConsumeReadWriteErrorFromData() { | 253 Error FuzzedSocket::ConsumeReadWriteErrorFromData() { |
| 225 return kReadWriteErrors[ConsumeUint8FromData() % arraysize(kReadWriteErrors)]; | 254 return kReadWriteErrors[data_provider_->ConsumeValueInRange( |
| 255 0, arraysize(kReadWriteErrors) - 1)]; |
| 226 } | 256 } |
| 227 | 257 |
| 228 void FuzzedSocket::OnReadComplete(const CompletionCallback& callback, | 258 void FuzzedSocket::OnReadComplete(const CompletionCallback& callback, |
| 229 int result) { | 259 int result) { |
| 230 CHECK(read_pending_); | 260 CHECK(read_pending_); |
| 231 read_pending_ = false; | 261 read_pending_ = false; |
| 232 if (result <= 0) { | 262 if (result <= 0) { |
| 233 error_pending_ = false; | 263 error_pending_ = false; |
| 234 } else { | 264 } else { |
| 235 total_bytes_read_ += result; | 265 total_bytes_read_ += result; |
| 236 } | 266 } |
| 237 callback.Run(result); | 267 callback.Run(result); |
| 238 } | 268 } |
| 239 | 269 |
| 240 void FuzzedSocket::OnWriteComplete(const CompletionCallback& callback, | 270 void FuzzedSocket::OnWriteComplete(const CompletionCallback& callback, |
| 241 int result) { | 271 int result) { |
| 242 CHECK(write_pending_); | 272 CHECK(write_pending_); |
| 243 write_pending_ = false; | 273 write_pending_ = false; |
| 244 if (result <= 0) { | 274 if (result <= 0) { |
| 245 error_pending_ = false; | 275 error_pending_ = false; |
| 246 } else { | 276 } else { |
| 247 total_bytes_written_ += result; | 277 total_bytes_written_ += result; |
| 248 } | 278 } |
| 249 callback.Run(result); | 279 callback.Run(result); |
| 250 } | 280 } |
| 251 | 281 |
| 282 void FuzzedSocket::OnConnectComplete(const CompletionCallback& callback, |
| 283 int result) { |
| 284 CHECK(connect_pending_); |
| 285 connect_pending_ = false; |
| 286 if (result < 0) |
| 287 error_pending_ = false; |
| 288 callback.Run(result); |
| 289 } |
| 290 |
| 252 } // namespace net | 291 } // namespace net |
| OLD | NEW |