websocket_deflate_stream_fuzzer.cc 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. // Copyright 2015 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include <stddef.h>
  5. #include <stdint.h>
  6. #include <fuzzer/FuzzedDataProvider.h>
  7. #include <string>
  8. #include <vector>
  9. #include "base/check.h"
  10. #include "base/memory/scoped_refptr.h"
  11. #include "base/strings/string_number_conversions.h"
  12. #include "base/strings/string_piece.h"
  13. #include "net/base/io_buffer.h"
  14. #include "net/base/net_errors.h"
  15. #include "net/log/net_log_with_source.h"
  16. #include "net/websockets/websocket_deflate_parameters.h"
  17. #include "net/websockets/websocket_deflate_predictor.h"
  18. #include "net/websockets/websocket_deflate_predictor_impl.h"
  19. #include "net/websockets/websocket_deflate_stream.h"
  20. #include "net/websockets/websocket_extension.h"
  21. #include "net/websockets/websocket_frame.h"
  22. #include "net/websockets/websocket_stream.h"
  23. namespace net {
  24. namespace {
  25. // If there are less random bytes left than MIN_BYTES_TO_CREATE_A_FRAME then
  26. // CreateFrame() will always create an empty frame. Since the fuzzer can create
  27. // the same empty frame with MIN_BYTES_TO_CREATE_A_FRAME bytes of input, save it
  28. // from exploring a large space of ways to do the same thing.
  29. constexpr size_t MIN_BYTES_TO_CREATE_A_FRAME = 3;
  30. constexpr size_t BYTES_CONSUMED_BY_PARAMS = 2;
  31. // If there are exactly BYTES_CONSUMED_BY_PARAMS + MIN_BYTES_TO_CREATE_A_FRAME
  32. // bytes of input, then the fuzzer will test a single frame. In order to also
  33. // test the case with zero frames, allow one less byte than this.
  34. constexpr size_t MIN_USEFUL_SIZE =
  35. BYTES_CONSUMED_BY_PARAMS + MIN_BYTES_TO_CREATE_A_FRAME - 1;
  36. class WebSocketFuzzedStream final : public WebSocketStream {
  37. public:
  38. explicit WebSocketFuzzedStream(FuzzedDataProvider* fuzzed_data_provider)
  39. : fuzzed_data_provider_(fuzzed_data_provider) {}
  40. int ReadFrames(std::vector<std::unique_ptr<WebSocketFrame>>* frames,
  41. CompletionOnceCallback callback) override {
  42. if (fuzzed_data_provider_->remaining_bytes() < MIN_BYTES_TO_CREATE_A_FRAME)
  43. return ERR_CONNECTION_CLOSED;
  44. while (fuzzed_data_provider_->remaining_bytes() > 0)
  45. frames->push_back(CreateFrame());
  46. return OK;
  47. }
  48. int WriteFrames(std::vector<std::unique_ptr<WebSocketFrame>>* frames,
  49. CompletionOnceCallback callback) override {
  50. return ERR_FILE_NOT_FOUND;
  51. }
  52. void Close() override {}
  53. std::string GetSubProtocol() const override { return std::string(); }
  54. std::string GetExtensions() const override { return std::string(); }
  55. const NetLogWithSource& GetNetLogWithSource() const override {
  56. return net_log_;
  57. }
  58. private:
  59. std::unique_ptr<WebSocketFrame> CreateFrame() {
  60. WebSocketFrameHeader::OpCode opcode =
  61. fuzzed_data_provider_
  62. ->ConsumeIntegralInRange<WebSocketFrameHeader::OpCode>(
  63. WebSocketFrameHeader::kOpCodeContinuation,
  64. WebSocketFrameHeader::kOpCodeControlUnused);
  65. auto frame = std::make_unique<WebSocketFrame>(opcode);
  66. // Bad news: ConsumeBool actually consumes a whole byte per call, so do
  67. // something hacky to conserve precious bits.
  68. uint8_t flags = fuzzed_data_provider_->ConsumeIntegral<uint8_t>();
  69. frame->header.final = flags & 0x1;
  70. frame->header.reserved1 = (flags >> 1) & 0x1;
  71. frame->header.reserved2 = (flags >> 2) & 0x1;
  72. frame->header.reserved3 = (flags >> 3) & 0x1;
  73. frame->header.masked = (flags >> 4) & 0x1;
  74. uint64_t payload_length =
  75. fuzzed_data_provider_->ConsumeIntegralInRange(0, 64);
  76. std::vector<char> payload =
  77. fuzzed_data_provider_->ConsumeBytes<char>(payload_length);
  78. auto buffer = base::MakeRefCounted<IOBufferWithSize>(payload.size());
  79. memcpy(buffer->data(), payload.data(), payload.size());
  80. buffers_.push_back(buffer);
  81. frame->payload = buffer->data();
  82. frame->header.payload_length = payload.size();
  83. return frame;
  84. }
  85. std::vector<scoped_refptr<IOBufferWithSize>> buffers_;
  86. FuzzedDataProvider* fuzzed_data_provider_;
  87. NetLogWithSource net_log_;
  88. };
  89. void WebSocketDeflateStreamFuzz(const uint8_t* data, size_t size) {
  90. FuzzedDataProvider fuzzed_data_provider(data, size);
  91. uint8_t flags = fuzzed_data_provider.ConsumeIntegral<uint8_t>();
  92. bool server_no_context_takeover = flags & 0x1;
  93. bool client_no_context_takeover = (flags >> 1) & 0x1;
  94. uint8_t window_bits = fuzzed_data_provider.ConsumeIntegral<uint8_t>();
  95. int server_max_window_bits = (window_bits & 0x7) + 8;
  96. int client_max_window_bits = ((window_bits >> 3) & 0x7) + 8;
  97. // WebSocketDeflateStream needs to be constructed on each call because it
  98. // has state.
  99. WebSocketExtension params("permessage-deflate");
  100. if (server_no_context_takeover)
  101. params.Add(WebSocketExtension::Parameter("server_no_context_takeover"));
  102. if (client_no_context_takeover)
  103. params.Add(WebSocketExtension::Parameter("client_no_context_takeover"));
  104. params.Add(WebSocketExtension::Parameter(
  105. "server_max_window_bits", base::NumberToString(server_max_window_bits)));
  106. params.Add(WebSocketExtension::Parameter(
  107. "client_max_window_bits", base::NumberToString(client_max_window_bits)));
  108. std::string failure_message;
  109. WebSocketDeflateParameters parameters;
  110. DCHECK(parameters.Initialize(params, &failure_message)) << failure_message;
  111. WebSocketDeflateStream deflate_stream(
  112. std::make_unique<WebSocketFuzzedStream>(&fuzzed_data_provider),
  113. parameters, std::make_unique<WebSocketDeflatePredictorImpl>());
  114. std::vector<std::unique_ptr<net::WebSocketFrame>> frames;
  115. deflate_stream.ReadFrames(&frames, CompletionOnceCallback());
  116. }
  117. } // namespace
  118. } // namespace net
  119. // Entry point for LibFuzzer.
  120. extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  121. if (size < net::MIN_USEFUL_SIZE)
  122. return 0;
  123. net::WebSocketDeflateStreamFuzz(data, size);
  124. return 0;
  125. }