1 // Copyright 2021 Code Intelligence GmbH
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <cstddef>
16 #include <cstdint>
17 #include <random>
18 #include <string>
19 #include <vector>
20
21 #include "gtest/gtest.h"
22 #include "launcher/jvm_tooling.h"
23 #include "tools/cpp/runfiles/runfiles.h"
24
25 namespace jazzer {
26
27 std::pair<std::string, jint> FixUpModifiedUtf8(const uint8_t* pos,
28 jint max_bytes, jint max_length,
29 bool ascii_only,
30 bool stop_on_backslash);
31
32 class FuzzedDataProviderTest : public ::testing::Test {
33 protected:
34 // After DestroyJavaVM() no new JVM instance can be created in the same
35 // process, so we set up a single JVM instance for this test binary which gets
36 // destroyed after all tests in this test suite have finished.
SetUpTestCase()37 static void SetUpTestCase() {
38 using ::bazel::tools::cpp::runfiles::Runfiles;
39 std::unique_ptr<Runfiles> runfiles(Runfiles::CreateForTest());
40 FLAGS_cp = runfiles->Rlocation(
41 "jazzer/launcher/testdata/fuzz_target_mocks_deploy.jar");
42
43 jvm_ = std::make_unique<JVM>();
44 }
45
TearDownTestCase()46 static void TearDownTestCase() { jvm_.reset(nullptr); }
47
48 static std::unique_ptr<JVM> jvm_;
49 };
50
51 std::unique_ptr<JVM> FuzzedDataProviderTest::jvm_ = nullptr;
52
53 constexpr std::size_t kValidModifiedUtf8NumRuns = 1000;
54 constexpr std::size_t kValidModifiedUtf8NumBytes = 100000;
55 constexpr uint32_t kValidModifiedUtf8Seed = 0x12345678;
56
TEST_F(FuzzedDataProviderTest,InvalidModifiedUtf8AfterFixup)57 TEST_F(FuzzedDataProviderTest, InvalidModifiedUtf8AfterFixup) {
58 auto& env = jvm_->GetEnv();
59 auto modified_utf8_validator = env.FindClass("test/ModifiedUtf8Encoder");
60 ASSERT_NE(nullptr, modified_utf8_validator);
61 auto string_to_modified_utf_bytes = env.GetStaticMethodID(
62 modified_utf8_validator, "encode", "(Ljava/lang/String;)[B");
63 ASSERT_NE(nullptr, string_to_modified_utf_bytes);
64 auto random_bytes = std::vector<uint8_t>(kValidModifiedUtf8NumBytes);
65 auto random = std::mt19937(kValidModifiedUtf8Seed);
66 for (bool ascii_only : {false, true}) {
67 for (bool stop_on_backslash : {false, true}) {
68 for (std::size_t i = 0; i < kValidModifiedUtf8NumRuns; ++i) {
69 std::generate(random_bytes.begin(), random_bytes.end(), random);
70 std::string fixed_string;
71 std::tie(fixed_string, std::ignore) = FixUpModifiedUtf8(
72 random_bytes.data(), random_bytes.size(),
73 std::numeric_limits<jint>::max(), ascii_only, stop_on_backslash);
74
75 jstring jni_fixed_string = env.NewStringUTF(fixed_string.c_str());
76 auto jni_roundtripped_bytes = (jbyteArray)env.CallStaticObjectMethod(
77 modified_utf8_validator, string_to_modified_utf_bytes,
78 jni_fixed_string);
79 ASSERT_FALSE(env.ExceptionCheck());
80 env.DeleteLocalRef(jni_fixed_string);
81 jint roundtripped_bytes_length =
82 env.GetArrayLength(jni_roundtripped_bytes);
83 jbyte* roundtripped_bytes =
84 env.GetByteArrayElements(jni_roundtripped_bytes, nullptr);
85 auto roundtripped_string =
86 std::string(reinterpret_cast<char*>(roundtripped_bytes),
87 roundtripped_bytes_length);
88 env.ReleaseByteArrayElements(jni_roundtripped_bytes, roundtripped_bytes,
89 JNI_ABORT);
90 env.DeleteLocalRef(jni_roundtripped_bytes);
91
92 // Verify that the bytes obtained from running our modified UTF-8 fix-up
93 // function remain unchanged when turned into a Java string and
94 // reencoded into modified UTF-8. This will only happen if the our
95 // fix-up function indeed returned valid modified UTF-8.
96 ASSERT_EQ(fixed_string, roundtripped_string);
97 }
98 }
99 }
100 }
101 } // namespace jazzer
102