From a646c1280d77de2d2c4f6734ecee5aa2013e3cfa Mon Sep 17 00:00:00 2001
From: Mihai Maruseac <mihaimaruseac@google.com>
Date: Sun, 7 Jun 2020 14:33:07 -0700
Subject: [PATCH] Create tensorflow/security/fuzzing.

This should enable us to create fuzzers that can be used in open source, both in OSSFuzz (in the end, this is part of stabilizing the OSSFuzz integration) and by themselves alone (by passing the corresponding flags).

PiperOrigin-RevId: 315182751
Change-Id: I3b6c38b0bd0613fcfe12d0d61726a5a4bab9c09c
---
 tensorflow/opensource_only.files           |  1 +
 tensorflow/security/fuzzing/BUILD          | 17 +++++
 tensorflow/security/fuzzing/demo_fuzz.cc   | 32 +++++++++
 tensorflow/security/fuzzing/tf_fuzzing.bzl | 80 ++++++++++++++++++++++
 4 files changed, 130 insertions(+)
 create mode 100644 tensorflow/security/fuzzing/BUILD
 create mode 100644 tensorflow/security/fuzzing/demo_fuzz.cc
 create mode 100644 tensorflow/security/fuzzing/tf_fuzzing.bzl

diff --git a/tensorflow/opensource_only.files b/tensorflow/opensource_only.files
index be0396dd113..d49b1c1e381 100644
--- a/tensorflow/opensource_only.files
+++ b/tensorflow/opensource_only.files
@@ -13,6 +13,7 @@ tensorflow/python/tpu/profiler/pip_package/README
 tensorflow/python/tpu/profiler/pip_package/build_pip_package.sh
 tensorflow/python/tpu/profiler/pip_package/setup.py
 tensorflow/python/tpu/tpu.bzl
+tensorflow/security/fuzzing/tf_fuzzing.bzl
 tensorflow/stream_executor/build_defs.bzl
 tensorflow/third_party/BUILD
 tensorflow/third_party/__init__.py
diff --git a/tensorflow/security/fuzzing/BUILD b/tensorflow/security/fuzzing/BUILD
new file mode 100644
index 00000000000..887e1a23cdf
--- /dev/null
+++ b/tensorflow/security/fuzzing/BUILD
@@ -0,0 +1,17 @@
+# Fuzzing TensorFlow.
+# Since we use OSSFuzz, gather all fuzzers into a single place.
+# This way, we can use tooling to determine the status of the fuzzing efforts.
+
+load(
+    "//tensorflow/security/fuzzing:tf_fuzzing.bzl",
+    "tf_fuzz_target",
+)
+
+package(
+    licenses = ["notice"],  # Apache 2.0
+)
+
+tf_fuzz_target(
+    name = "demo_fuzz",
+    srcs = ["demo_fuzz.cc"],
+)
diff --git a/tensorflow/security/fuzzing/demo_fuzz.cc b/tensorflow/security/fuzzing/demo_fuzz.cc
new file mode 100644
index 00000000000..71777591694
--- /dev/null
+++ b/tensorflow/security/fuzzing/demo_fuzz.cc
@@ -0,0 +1,32 @@
+/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+#include <cstdint>
+#include <cstdlib>
+
+// This is a demo fuzzer to test that the entire framework functions correctly.
+// Once we start moving the existing fuzzers to this framework we will delete
+// this.
+// TODO(mihaimaruseac): Delete this when no longer needed
+void DemoFuzzer(const uint8_t* data, size_t size) {
+  // Trigger a small bug that should be found by the fuzzer quite quickly
+  if (size > 10 && size % 3 == 2)
+    if (data[0] > data[1])
+      if (data[5] % data[2] == data[3]) abort();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  DemoFuzzer(data, size);
+  return 0;
+}
diff --git a/tensorflow/security/fuzzing/tf_fuzzing.bzl b/tensorflow/security/fuzzing/tf_fuzzing.bzl
new file mode 100644
index 00000000000..63a8cbac704
--- /dev/null
+++ b/tensorflow/security/fuzzing/tf_fuzzing.bzl
@@ -0,0 +1,80 @@
+"""Definitions for rules to fuzz TensorFlow."""
+
+# TensorFlow fuzzing can be done in open source too.
+#
+# For a fuzzer ${FUZZ} we have the following setup:
+#   - ${FUZZ}_fuzz.cc           : the implementation of the fuzzer
+#   - corpus/${FUZZ}/...        : public corpus for the fuzzer
+#   - dictionaries/${FUZZ}.dict : fuzzing dictionary for the fuzzer
+#   - ${FUZZ}_internal/...      : internal data for the fuzzer
+#
+# If a fuzzer needs some framework to build, we can use the ${FUZZ}_internal/
+# directory to hold the harness. Or, if the infrastructure needs to be shared
+# across multiple fuzzers (for example fuzzing ops), we can store it in other
+# places in TF or move it to a different folder here. We will decide on these
+# on a case by case basis, for now the ops fuzzing harness resides under
+# tensorflow/core/kernels/fuzzing.
+#
+# The internal folder can also contain proto definitions (if using proto-based
+# mutators to do structure aware fuzzing) or any other type of content that is
+# not classified elsewhere.
+
+# tf_cc_fuzz_target is a cc_test modified to include fuzzing support.
+def tf_fuzz_target(
+        name,
+        # Fuzzing specific arguments
+        fuzzing_dict = [],
+        corpus = [],
+        parsers = [],
+        # Reporting bugs arguments, not used in open source
+        componentid = None,
+        hotlists = [],
+        # Additional cc_test control
+        data = [],
+        deps = [],
+        tags = [],
+        # Remaining cc_test arguments
+        **kwargs):
+    """Specify how to build a TensorFlow fuzz target.
+
+    Args:
+      name: Mandatory name of the fuzzer target.
+
+      fuzzing_dict: An optional a set of dictionary files following
+        the AFL/libFuzzer dictionary syntax.
+
+      corpus: An optional set of files used as the initial test corpus
+        for the target. When doing "bazel test" in the default null-fuzzer
+        (unittest) mode, these files are automatically passed to the target
+        function.
+
+      parsers: An optional list of file extensions that the target supports.
+        Used by tools like autofuzz to reuse corpus sets across targets.
+
+      componentid: Used internally for reporting fuzz discovered bugs.
+
+      hotlists: Used internally for reporting fuzz discovered bugs.
+
+      data: Additional data dependencies passed to the underlying cc_test rule.
+
+      deps: An optional list of dependencies for the code you're fuzzing.
+
+      tags: Additional tags passed to the underlying cc_test rule.
+
+      **kwargs: Collects all remaining arguments and passes them to the
+        underlying cc_test rule generated by the macro.
+    """
+    componentid = None
+    hotlists = None
+
+    # Fuzzers in open source must be run manually
+    tags = tags + ["manual"]
+
+    # Now, redirect to cc_test
+    native.cc_test(
+        name = name,
+        deps = deps,  # TODO(mihaimaruseac): fuzzing lib?
+        data = data,  # TODO(mihaimaruseac): dict, corpus, parsers??
+        tags = tags,  # TODO(mihaimaruseac): fuzzing tags?
+        **kwargs
+    )