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/22 22:07:10
Or alternately IPAddress::IPv4Localhost()
mmenke
2016/04/27 19:53:25
Handy. Done.
| |
| 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_->ConsumeBits(1); |
|
eroman
2016/04/22 22:07:11
How about adding a wrapper method:
bool FuzzedDat
mmenke
2016/04/27 19:53:25
Hrm...We could make consume bits always round to t
| |
| 49 sync = !!(random_val & 0x01); | 58 result = data_provider_->ConsumeBits(7); |
|
eroman
2016/04/22 22:07:11
Could combine this with the next line:
result = s
mmenke
2016/04/27 19:53:25
You mean std::min(static_cast<uint32_t>(buf_len),
| |
| 50 result = random_val >> 1; | |
| 51 if (result > buf_len) | 59 if (result > buf_len) |
| 52 result = buf_len; | 60 result = buf_len; |
| 53 // Can't read more data than is available in |data_|. | 61 |
| 54 if (static_cast<size_t>(result) > data_.length()) | 62 if (result > 0) |
| 55 result = data_.length(); | 63 result = data_provider_->ConsumeBytes(buf->data(), result); |
| 56 | 64 |
| 57 if (result == 0) { | 65 if (result == 0) { |
| 58 net_error_ = ConsumeReadWriteErrorFromData(); | 66 net_error_ = ConsumeReadWriteErrorFromData(); |
| 59 result = net_error_; | 67 result = net_error_; |
| 60 if (!sync) | 68 if (!sync) |
| 61 error_pending_ = true; | 69 error_pending_ = true; |
| 62 } else { | |
| 63 memcpy(buf->data(), data_.data(), result); | |
| 64 data_ = data_.substr(result); | |
| 65 } | 70 } |
| 66 } | 71 } |
| 67 | 72 |
| 68 // Graceful close of a socket returns OK, at least in theory. This doesn't | 73 // Graceful close of a socket returns OK, at least in theory. This doesn't |
| 69 // perfectly reflect real socket behavior, but close enough. | 74 // perfectly reflect real socket behavior, but close enough. |
| 70 if (result == ERR_CONNECTION_CLOSED) | 75 if (result == ERR_CONNECTION_CLOSED) |
| 71 result = 0; | 76 result = 0; |
| 72 | 77 |
| 73 if (sync) { | 78 if (sync) { |
| 74 if (result > 0) | 79 if (result > 0) |
| 75 total_bytes_read_ += result; | 80 total_bytes_read_ += result; |
| 76 return result; | 81 return result; |
| 77 } | 82 } |
| 78 | 83 |
| 79 read_pending_ = true; | 84 read_pending_ = true; |
| 80 base::ThreadTaskRunnerHandle::Get()->PostTask( | 85 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 81 FROM_HERE, base::Bind(&FuzzedSocket::OnReadComplete, | 86 FROM_HERE, base::Bind(&FuzzedSocket::OnReadComplete, |
| 82 weak_factory_.GetWeakPtr(), callback, result)); | 87 weak_factory_.GetWeakPtr(), callback, result)); |
| 83 return ERR_IO_PENDING; | 88 return ERR_IO_PENDING; |
| 84 } | 89 } |
| 85 | 90 |
| 86 int FuzzedSocket::Write(IOBuffer* buf, | 91 int FuzzedSocket::Write(IOBuffer* buf, |
| 87 int buf_len, | 92 int buf_len, |
| 88 const CompletionCallback& callback) { | 93 const CompletionCallback& callback) { |
| 94 DCHECK(!connect_pending_); | |
| 89 DCHECK(!write_pending_); | 95 DCHECK(!write_pending_); |
| 90 | 96 |
| 91 bool sync; | 97 bool sync; |
| 92 int result; | 98 int result; |
| 93 | 99 |
| 94 if (net_error_ != OK) { | 100 if (net_error_ != OK) { |
| 95 // If an error has already been generated, use it to determine what to do. | 101 // If an error has already been generated, use it to determine what to do. |
| 96 result = net_error_; | 102 result = net_error_; |
| 97 sync = !error_pending_; | 103 sync = !error_pending_; |
| 98 } else { | 104 } else { |
| 99 // Otherwise, use |data_|. | 105 // Otherwise, use |data_|. |
| 100 uint8_t random_val = ConsumeUint8FromData(); | 106 sync = !!data_provider_->ConsumeBits(1); |
|
eroman
2016/04/22 22:07:11
Same suggestiong (ConsumeBool())
| |
| 101 sync = !!(random_val & 0x01); | 107 result = data_provider_->ConsumeBits(7); |
| 102 result = random_val >> 1; | |
| 103 if (result > buf_len) | 108 if (result > buf_len) |
| 104 result = buf_len; | 109 result = buf_len; |
| 105 if (result == 0) { | 110 if (result == 0) { |
| 106 net_error_ = ConsumeReadWriteErrorFromData(); | 111 net_error_ = ConsumeReadWriteErrorFromData(); |
| 107 result = net_error_; | 112 result = net_error_; |
| 108 if (!sync) | 113 if (!sync) |
| 109 error_pending_ = true; | 114 error_pending_ = true; |
| 110 } | 115 } |
| 111 } | 116 } |
| 112 | 117 |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 127 return OK; | 132 return OK; |
| 128 } | 133 } |
| 129 | 134 |
| 130 int FuzzedSocket::SetSendBufferSize(int32_t size) { | 135 int FuzzedSocket::SetSendBufferSize(int32_t size) { |
| 131 return OK; | 136 return OK; |
| 132 } | 137 } |
| 133 | 138 |
| 134 int FuzzedSocket::Connect(const CompletionCallback& callback) { | 139 int FuzzedSocket::Connect(const CompletionCallback& callback) { |
| 135 // Sockets can normally be reused, but don't support it here. | 140 // Sockets can normally be reused, but don't support it here. |
| 136 DCHECK_NE(net_error_, OK); | 141 DCHECK_NE(net_error_, OK); |
| 142 DCHECK(!connect_pending_); | |
| 137 DCHECK(!read_pending_); | 143 DCHECK(!read_pending_); |
| 138 DCHECK(!write_pending_); | 144 DCHECK(!write_pending_); |
| 139 DCHECK(!error_pending_); | 145 DCHECK(!error_pending_); |
| 140 DCHECK(!total_bytes_read_); | 146 DCHECK(!total_bytes_read_); |
| 141 DCHECK(!total_bytes_written_); | 147 DCHECK(!total_bytes_written_); |
| 142 | 148 |
| 143 net_error_ = OK; | 149 int sync = true; |
|
eroman
2016/04/22 22:07:10
Why not a bool?
| |
| 144 return OK; | 150 Error result = OK; |
| 151 if (fuzz_connect_result_) { | |
| 152 // Decide if sync or async. Use async, if no data is left. | |
| 153 sync = !!data_provider_->ConsumeBits(1); | |
| 154 // Decide if the connect succeeds or not. Fail, if no data is left. | |
| 155 bool is_error = !data_provider_->ConsumeBits(1); | |
| 156 | |
| 157 // Remove 6 bits, so a full byte as been consumed. If the connect is going | |
|
eroman
2016/04/22 22:07:11
as been --> has been.
Also note I don't think it
| |
| 158 // to fail, use them to decide the error code. Otherwise, throw them away. | |
| 159 uint32_t error_bits = data_provider_->ConsumeBits(6); | |
|
eroman
2016/04/22 22:07:11
Why not just Consume these 6 bits when |is_error|
mmenke
2016/04/25 15:09:19
See my other comments on how the fuzzer traverses
| |
| 160 if (is_error) | |
| 161 result = kConnectErrors[error_bits % arraysize(kConnectErrors)]; | |
|
eroman
2016/04/22 22:07:11
Note: would have been sufficient to consume 3 bits
| |
| 162 } | |
| 163 | |
| 164 if (sync) { | |
| 165 net_error_ = result; | |
| 166 return result; | |
| 167 } | |
| 168 | |
| 169 connect_pending_ = true; | |
| 170 if (result != OK) | |
| 171 error_pending_ = true; | |
| 172 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 173 FROM_HERE, base::Bind(&FuzzedSocket::OnConnectComplete, | |
| 174 weak_factory_.GetWeakPtr(), callback, result)); | |
| 175 return ERR_IO_PENDING; | |
| 145 } | 176 } |
| 146 | 177 |
| 147 void FuzzedSocket::Disconnect() { | 178 void FuzzedSocket::Disconnect() { |
| 148 net_error_ = ERR_CONNECTION_CLOSED; | 179 net_error_ = ERR_CONNECTION_CLOSED; |
| 149 weak_factory_.InvalidateWeakPtrs(); | 180 weak_factory_.InvalidateWeakPtrs(); |
| 181 connect_pending_ = false; | |
| 150 read_pending_ = false; | 182 read_pending_ = false; |
| 151 write_pending_ = false; | 183 write_pending_ = false; |
| 152 error_pending_ = false; | 184 error_pending_ = false; |
| 153 } | 185 } |
| 154 | 186 |
| 155 bool FuzzedSocket::IsConnected() const { | 187 bool FuzzedSocket::IsConnected() const { |
| 156 return net_error_ == OK && !error_pending_; | 188 return net_error_ == OK && !error_pending_; |
| 157 } | 189 } |
| 158 | 190 |
| 159 bool FuzzedSocket::IsConnectedAndIdle() const { | 191 bool FuzzedSocket::IsConnectedAndIdle() const { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 205 } | 237 } |
| 206 | 238 |
| 207 void FuzzedSocket::ClearConnectionAttempts() {} | 239 void FuzzedSocket::ClearConnectionAttempts() {} |
| 208 | 240 |
| 209 void FuzzedSocket::AddConnectionAttempts(const ConnectionAttempts& attempts) {} | 241 void FuzzedSocket::AddConnectionAttempts(const ConnectionAttempts& attempts) {} |
| 210 | 242 |
| 211 int64_t FuzzedSocket::GetTotalReceivedBytes() const { | 243 int64_t FuzzedSocket::GetTotalReceivedBytes() const { |
| 212 return total_bytes_read_; | 244 return total_bytes_read_; |
| 213 } | 245 } |
| 214 | 246 |
| 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() { | 247 Error FuzzedSocket::ConsumeReadWriteErrorFromData() { |
| 225 return kReadWriteErrors[ConsumeUint8FromData() % arraysize(kReadWriteErrors)]; | 248 return kReadWriteErrors[data_provider_->ConsumeBits(8) % |
|
eroman
2016/04/22 22:07:11
Ditto here -- 8 bits is more than we need. Not a p
| |
| 249 arraysize(kReadWriteErrors)]; | |
| 226 } | 250 } |
| 227 | 251 |
| 228 void FuzzedSocket::OnReadComplete(const CompletionCallback& callback, | 252 void FuzzedSocket::OnReadComplete(const CompletionCallback& callback, |
| 229 int result) { | 253 int result) { |
| 230 CHECK(read_pending_); | 254 CHECK(read_pending_); |
| 231 read_pending_ = false; | 255 read_pending_ = false; |
| 232 if (result <= 0) { | 256 if (result <= 0) { |
| 233 error_pending_ = false; | 257 error_pending_ = false; |
| 234 } else { | 258 } else { |
| 235 total_bytes_read_ += result; | 259 total_bytes_read_ += result; |
| 236 } | 260 } |
| 237 callback.Run(result); | 261 callback.Run(result); |
| 238 } | 262 } |
| 239 | 263 |
| 240 void FuzzedSocket::OnWriteComplete(const CompletionCallback& callback, | 264 void FuzzedSocket::OnWriteComplete(const CompletionCallback& callback, |
| 241 int result) { | 265 int result) { |
| 242 CHECK(write_pending_); | 266 CHECK(write_pending_); |
| 243 write_pending_ = false; | 267 write_pending_ = false; |
| 244 if (result <= 0) { | 268 if (result <= 0) { |
| 245 error_pending_ = false; | 269 error_pending_ = false; |
| 246 } else { | 270 } else { |
| 247 total_bytes_written_ += result; | 271 total_bytes_written_ += result; |
| 248 } | 272 } |
| 249 callback.Run(result); | 273 callback.Run(result); |
| 250 } | 274 } |
| 251 | 275 |
| 276 void FuzzedSocket::OnConnectComplete(const CompletionCallback& callback, | |
| 277 int result) { | |
| 278 CHECK(connect_pending_); | |
| 279 connect_pending_ = false; | |
| 280 if (result < 0) | |
| 281 error_pending_ = false; | |
| 282 callback.Run(result); | |
| 283 } | |
| 284 | |
| 252 } // namespace net | 285 } // namespace net |
| OLD | NEW |