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