system-proxy: Add connect_headers_parser_fuzzer

System-proxy workers expect that after connecting, clients
will first set an HTTP CONNECT request that needs to be
parsed to extract the target url.

This fuzzer tests against random data send from the clients.

BUG=chromium:1057190
TEST=in fuzzer shell:
/usr/libexec/fuzzers/system_proxy_connect_headers_parser_fuzzer

Change-Id: I947c5ecf0980b34c54ddcd709b7cacc3efbca424
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2165888
Tested-by: Andreea-Elena Costinas <acostinas@google.com>
Commit-Queue: Andreea-Elena Costinas <acostinas@google.com>
Reviewed-by: Pavol Marko <pmarko@chromium.org>
Reviewed-by: Hugo Benichi <hugobenichi@google.com>
diff --git a/system-proxy/BUILD.gn b/system-proxy/BUILD.gn
index de8e448..5be8c72 100644
--- a/system-proxy/BUILD.gn
+++ b/system-proxy/BUILD.gn
@@ -18,7 +18,10 @@
     deps += [ ":system-proxy_test" ]
   }
   if (use.fuzzer) {
-    deps += [ ":system_proxy_worker_config_fuzzer" ]
+    deps += [
+      ":system_proxy_connect_headers_parser_fuzzer",
+      ":system_proxy_worker_config_fuzzer",
+    ]
   }
 }
 
@@ -160,4 +163,18 @@
       ":libsystemproxyworker",
     ]
   }
+
+  executable("system_proxy_connect_headers_parser_fuzzer") {
+    all_dependent_pkg_deps = [ "libcurl" ]
+    configs += [
+      "//common-mk/common_fuzzer",
+      ":target_defaults",
+    ]
+    sources = [
+      "connect_headers_parser_fuzzer.cc",
+    ]
+    deps = [
+      ":libsystemproxyworker",
+    ]
+  }
 }
diff --git a/system-proxy/connect_headers_parser_fuzzer.cc b/system-proxy/connect_headers_parser_fuzzer.cc
new file mode 100644
index 0000000..db9ad98
--- /dev/null
+++ b/system-proxy/connect_headers_parser_fuzzer.cc
@@ -0,0 +1,69 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <base/bind.h>
+#include <base/files/file_util.h>
+#include <base/logging.h>
+#include <base/message_loop/message_loop.h>
+#include <base/run_loop.h>
+#include <brillo/message_loops/base_message_loop.h>
+#include <chromeos/patchpanel/socket.h>
+#include <chromeos/patchpanel/socket_forwarder.h>
+
+#include "system-proxy/proxy_connect_job.h"
+
+namespace {
+void NullProxyResolver(
+    const std::string&,
+    base::OnceCallback<void(const std::list<std::string>&)>) {}
+
+void OnConnectionSetupFinished(base::OnceClosure quit_task,
+                               std::unique_ptr<patchpanel::SocketForwarder>,
+                               system_proxy::ProxyConnectJob*) {
+  std::move(quit_task).Run();
+}
+}  // namespace
+
+struct Environment {
+  Environment() {
+    logging::SetMinLogLevel(logging::LOG_INFO);  // Disable logging.
+  }
+};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  static Environment env;
+
+  // Mock main task runner
+  base::MessageLoopForIO message_loop;
+  brillo::BaseMessageLoop brillo_loop(&message_loop);
+  brillo_loop.SetAsCurrent();
+
+  base::RunLoop run_loop;
+
+  int socket_pair[2];
+  socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, socket_pair);
+  base::ScopedFD reader_fd(socket_pair[0]);
+  base::ScopedFD writer_fd(socket_pair[1]);
+  int fds[2];
+
+  socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
+             0 /* protocol */, fds);
+  patchpanel::Socket cros_client_socket((base::ScopedFD(fds[1])));
+
+  auto connect_job = std::make_unique<system_proxy::ProxyConnectJob>(
+      std::make_unique<patchpanel::Socket>(base::ScopedFD(fds[0])), "",
+      base::BindOnce(&NullProxyResolver),
+      base::BindOnce(&OnConnectionSetupFinished, run_loop.QuitClosure()));
+  connect_job->Start();
+  cros_client_socket.SendTo(data, size);
+
+  run_loop.Run();
+  return 0;
+}