/test/extensions/filters/listener/common/fuzz/listener_filter_fuzzer.cc

https://github.com/envoyproxy/envoy · C++ · 124 lines · 97 code · 25 blank · 2 comment · 15 complexity · dc662adb2402d77c4f575f5469a3b0b9 MD5 · raw file

  1. #include "test/extensions/filters/listener/common/fuzz/listener_filter_fuzzer.h"
  2. namespace Envoy {
  3. namespace Extensions {
  4. namespace ListenerFilters {
  5. void ListenerFilterFuzzer::fuzz(
  6. Network::ListenerFilter& filter,
  7. const test::extensions::filters::listener::FilterFuzzTestCase& input) {
  8. try {
  9. socket_.setLocalAddress(Network::Utility::resolveUrl(input.sock().local_address()));
  10. } catch (const EnvoyException& e) {
  11. socket_.setLocalAddress(Network::Utility::resolveUrl("tcp://0.0.0.0:0"));
  12. }
  13. try {
  14. socket_.setRemoteAddress(Network::Utility::resolveUrl(input.sock().remote_address()));
  15. } catch (const EnvoyException& e) {
  16. socket_.setRemoteAddress(Network::Utility::resolveUrl("tcp://0.0.0.0:0"));
  17. }
  18. FuzzedInputStream data(input);
  19. if (!data.empty()) {
  20. ON_CALL(os_sys_calls_, recv(kFakeSocketFd, _, _, _))
  21. .WillByDefault(testing::Return(Api::SysCallSizeResult{static_cast<ssize_t>(0), 0}));
  22. ON_CALL(dispatcher_, createFileEvent_(_, _, _, _))
  23. .WillByDefault(testing::DoAll(testing::SaveArg<1>(&file_event_callback_),
  24. testing::SaveArg<3>(&events_),
  25. testing::ReturnNew<NiceMock<Event::MockFileEvent>>()));
  26. }
  27. filter.onAccept(cb_);
  28. if (file_event_callback_ == nullptr) {
  29. // If filter does not call createFileEvent (i.e. original_dst and original_src)
  30. return;
  31. }
  32. if (!data.empty()) {
  33. ON_CALL(os_sys_calls_, ioctl(kFakeSocketFd, FIONREAD, _))
  34. .WillByDefault(
  35. Invoke([&data](os_fd_t, unsigned long int, void* argp) -> Api::SysCallIntResult {
  36. int bytes_avail = static_cast<int>(data.size());
  37. memcpy(argp, &bytes_avail, sizeof(int));
  38. return Api::SysCallIntResult{bytes_avail, 0};
  39. }));
  40. {
  41. testing::InSequence s;
  42. EXPECT_CALL(os_sys_calls_, recv(kFakeSocketFd, _, _, _))
  43. .Times(testing::AnyNumber())
  44. .WillRepeatedly(Invoke(
  45. [&data](os_fd_t, void* buffer, size_t length, int flags) -> Api::SysCallSizeResult {
  46. return data.read(buffer, length, flags == MSG_PEEK);
  47. }));
  48. }
  49. bool got_continue = false;
  50. ON_CALL(cb_, continueFilterChain(true))
  51. .WillByDefault(testing::InvokeWithoutArgs([&got_continue]() { got_continue = true; }));
  52. while (!got_continue) {
  53. if (data.done()) { // End of stream reached but not done
  54. if (events_ & Event::FileReadyType::Closed) {
  55. file_event_callback_(Event::FileReadyType::Closed);
  56. }
  57. return;
  58. } else {
  59. file_event_callback_(Event::FileReadyType::Read);
  60. }
  61. data.next();
  62. }
  63. }
  64. }
  65. FuzzedInputStream::FuzzedInputStream(
  66. const test::extensions::filters::listener::FilterFuzzTestCase& input)
  67. : nreads_(input.data_size()) {
  68. size_t len = 0;
  69. for (int i = 0; i < nreads_; i++) {
  70. len += input.data(i).size();
  71. }
  72. data_.reserve(len);
  73. for (int i = 0; i < nreads_; i++) {
  74. data_.insert(data_.end(), input.data(i).begin(), input.data(i).end());
  75. indices_.push_back(data_.size() - 1);
  76. }
  77. }
  78. FuzzedInputStream::FuzzedInputStream(std::vector<uint8_t> buffer, std::vector<size_t> indices)
  79. : nreads_(indices.size()), data_(std::move(buffer)), indices_(std::move(indices)) {}
  80. void FuzzedInputStream::next() {
  81. if (!done()) {
  82. nread_++;
  83. }
  84. }
  85. Api::SysCallSizeResult FuzzedInputStream::read(void* buffer, size_t length, bool peek) {
  86. const size_t len = std::min(size(), length); // Number of bytes to write
  87. memcpy(buffer, data_.data() + index_, len);
  88. if (!peek) {
  89. // If not peeking, written bytes will be marked as read
  90. index_ += len;
  91. }
  92. return Api::SysCallSizeResult{static_cast<ssize_t>(len), 0};
  93. }
  94. size_t FuzzedInputStream::size() const { return indices_[nread_] - index_ + 1; }
  95. bool FuzzedInputStream::done() { return nread_ >= nreads_ - 1; }
  96. bool FuzzedInputStream::empty() { return nreads_ == 0 || data_.empty(); }
  97. } // namespace ListenerFilters
  98. } // namespace Extensions
  99. } // namespace Envoy