├── llvm_gcov.sh ├── generate_proto.sh ├── tools ├── harness_t2t_detect.h ├── harness.h ├── t2t_detect_fuzzer.cc ├── t2t_detect_dbg.cc ├── coverage_t2t_detect.cc ├── harness_common.h ├── port │ ├── gtest.h │ └── protobuf.h ├── src │ ├── random.h │ ├── utf8_fix.h │ ├── libfuzzer │ │ ├── libfuzzer_test.cc │ │ ├── CMakeLists.txt │ │ ├── libfuzzer_mutator.h │ │ ├── libfuzzer_mutator.cc │ │ ├── libfuzzer_macro.h │ │ └── libfuzzer_macro.cc │ ├── text_format.h │ ├── binary_format.h │ ├── binary_format.cc │ ├── text_format.cc │ ├── weighted_reservoir_sampler.h │ ├── utf8_fix_test.cc │ ├── CMakeLists.txt │ ├── weighted_reservoir_sampler_test.cc │ ├── utf8_fix.cc │ ├── mutator_test_proto3.proto │ ├── mutator_test_proto2.proto │ ├── mutator.h │ ├── field_instance.h │ ├── mutator_test.cc │ └── mutator.cc ├── t2t_detect.proto ├── Android.bp ├── harness_t2t_detect.cc ├── harness_common.cc └── harness.cc ├── patch.sh ├── protobuf.patch ├── get_coverage.sh ├── docs ├── extending.md ├── coverage_debug.md └── proxmark.md ├── README.md └── nfc.patch /llvm_gcov.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | exec llvm-cov gcov "$@" 3 | -------------------------------------------------------------------------------- /generate_proto.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | $1/out/host/linux-x86/bin/aprotoc --proto_path=$1/system/nfc/tools --cpp_out=$1/system/nfc/tools $1/system/nfc/tools/t2t_detect.proto 4 | 5 | 6 | -------------------------------------------------------------------------------- /tools/harness_t2t_detect.h: -------------------------------------------------------------------------------- 1 | #ifndef HARNESS_T2T_DETECT_H 2 | #define HARNESS_T2T_DETECT_H 3 | #include "t2t_detect.pb.h" 4 | void TestDetect(const nfc::DetectSession& session); 5 | #endif 6 | -------------------------------------------------------------------------------- /tools/harness.h: -------------------------------------------------------------------------------- 1 | #ifndef HARNESS_H 2 | #define HARNESS_H 3 | #include "nfc_event.pb.h" 4 | int initialize(); 5 | void cleanup(); 6 | void TestRW(const nfc::Session& session, uint8_t protocol); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /tools/t2t_detect_fuzzer.cc: -------------------------------------------------------------------------------- 1 | #include "src/libfuzzer/libfuzzer_macro.h" 2 | #include 3 | #include "harness_t2t_detect.h" 4 | #include 5 | #include 6 | #include 7 | 8 | DEFINE_BINARY_PROTO_FUZZER(const nfc::DetectSession& session) { 9 | TestDetect(session); 10 | } 11 | -------------------------------------------------------------------------------- /patch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$#" -ne 1 ]; then 4 | echo "AOSP root directory not supplied: Usage: ./patch.sh " 5 | exit 6 | fi 7 | 8 | echo "Patching nfc" 9 | 10 | patch -p1 -d $1/system/nfc < nfc.patch 11 | 12 | echo "Patching protobuf to enable rtti for libprotobuf-mutator" 13 | 14 | patch -p1 -d $1/external/protobuf < protobuf.patch 15 | 16 | echo "Copying fuzzers to nfc" 17 | 18 | cp -r tools $1/system/nfc 19 | -------------------------------------------------------------------------------- /protobuf.patch: -------------------------------------------------------------------------------- 1 | diff --git a/Android.bp b/Android.bp 2 | index a0f57524b..a99c25f01 100644 3 | --- a/Android.bp 4 | +++ b/Android.bp 5 | @@ -206,6 +206,7 @@ cc_library { 6 | defaults: ["libprotobuf-cpp-full-defaults"], 7 | host_supported: true, 8 | vendor_available: true, 9 | + rtti: true, 10 | target: { 11 | android: { 12 | static: { 13 | @@ -216,6 +217,9 @@ cc_library { 14 | enabled: true, 15 | }, 16 | }, 17 | + sanitize: { 18 | + never: true, 19 | + }, 20 | } 21 | 22 | // Compiler library for the host 23 | -------------------------------------------------------------------------------- /tools/t2t_detect_dbg.cc: -------------------------------------------------------------------------------- 1 | #include "harness_common.h" 2 | #include "harness_t2t_detect.h" 3 | #include 4 | #include 5 | 6 | int main(int argc, char* argv[]) { 7 | nfc::DetectSession session; 8 | if (argc == 2) { 9 | std::fstream input(argv[1], std::ios::in | std::ios::binary); 10 | if (!session.ParseFromIstream(&input)) { 11 | std::cerr << "Failed to parse input." << std::endl; 12 | return -1; 13 | } 14 | } else { 15 | return -1; 16 | } 17 | initialize(); 18 | TestDetect(session); 19 | cleanup(); 20 | return 0; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /tools/coverage_t2t_detect.cc: -------------------------------------------------------------------------------- 1 | #include "harness_common.h" 2 | #include "harness_t2t_detect.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char* argv[]) { 9 | std::string dir_name = argv[1]; 10 | DIR* dirp = opendir(argv[1]); 11 | struct dirent* dp = NULL; 12 | while ((dp = readdir(dirp)) != NULL) { 13 | nfc::DetectSession session; 14 | std::fstream input(dir_name + "/" + dp->d_name, std::ios::in | std::ios::binary); 15 | if (session.ParseFromIstream(&input)) { 16 | initialize(); 17 | TestDetect(session); 18 | cleanup(); 19 | } 20 | } 21 | closedir(dirp); 22 | return 0; 23 | } 24 | 25 | -------------------------------------------------------------------------------- /tools/harness_common.h: -------------------------------------------------------------------------------- 1 | #ifndef HARNESS_COMMON_H 2 | #define HARNESS_COMMON_H 3 | 4 | #include "NfcAdaptation.h" 5 | #include "nfc_int.h" 6 | #include "nfa_sys.h" 7 | #include "nfc_api.h" 8 | #include "rw_api.h" 9 | #include "nfa_api.h" 10 | #include "nfa_rw_int.h" 11 | #include "nfc_config.h" 12 | #include "gki_int.h" 13 | #include "nfc_target.h" 14 | 15 | int initialize(); 16 | void cleanup(); 17 | void deactivate(); 18 | void setup(uint8_t protocol); 19 | void set_message_len(NFC_HDR* p_msg); 20 | NFC_HDR* create_data_msg_meta(uint16_t data_len, const char* p_data); 21 | uint16_t cap_data_len(size_t data_len); 22 | void initialize_rf_conn(); 23 | //True if prob % 255 exceeded threshold. 24 | bool get_prob(uint32_t prob, uint8_t thresh); 25 | NFC_HDR* copy_msg(NFC_HDR* p_msg); 26 | #endif 27 | -------------------------------------------------------------------------------- /tools/port/gtest.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. All rights reserved. 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 | #ifndef PORT_GTEST_H_ 16 | #define PORT_GTEST_H_ 17 | 18 | #include "gtest/gtest.h" 19 | 20 | #endif // PORT_GTEST_H_ 21 | -------------------------------------------------------------------------------- /tools/src/random.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. All rights reserved. 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 | #ifndef SRC_RANDOM_H_ 16 | #define SRC_RANDOM_H_ 17 | 18 | #include 19 | 20 | namespace protobuf_mutator { 21 | 22 | using RandomEngine = std::minstd_rand; 23 | 24 | } // namespace protobuf_mutator 25 | 26 | #endif // SRC_RANDOM_H_ 27 | -------------------------------------------------------------------------------- /tools/t2t_detect.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | package nfc; 3 | 4 | message DetectSession { 5 | repeated WaitSelectSector wait_select = 1; 6 | repeated DefaultResponse dr = 2; 7 | repeated WaitCc wait_cc = 3; 8 | } 9 | 10 | //response to WAIT_READ_CC state 11 | message WaitCc { 12 | required int64 hdr_0 = 1; 13 | required int64 hdr_1 = 2; 14 | required uint32 ack = 3; 15 | required Cc3 cc3 = 4; //0x0f index 16 | required Cc1 cc1 = 5; //0x0d index 17 | } 18 | 19 | enum Cc3 { 20 | RW = 0x00; 21 | R0 = 0x01; 22 | } 23 | 24 | enum Cc1 { 25 | LEGACY = 0x10; 26 | VNO = 0x11; 27 | NEW_VNO = 0x12; 28 | } 29 | 30 | //Generic response of fixed length 31 | message DefaultResponse { 32 | required int64 hdr_0 = 1; 33 | required int64 hdr_1 = 2; 34 | required uint32 ack = 3; 35 | } 36 | 37 | //response for wait select sector can be any length 38 | message WaitSelectSector { 39 | required bytes data = 1; 40 | } 41 | -------------------------------------------------------------------------------- /tools/src/utf8_fix.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. All rights reserved. 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 | #ifndef SRC_UTF8_FIX_H_ 16 | #define SRC_UTF8_FIX_H_ 17 | 18 | #include 19 | 20 | #include "src/random.h" 21 | 22 | namespace protobuf_mutator { 23 | 24 | void FixUtf8String(std::string* str, RandomEngine* random); 25 | 26 | } // namespace protobuf_mutator 27 | 28 | #endif // SRC_UTF8_FIX_H_ 29 | -------------------------------------------------------------------------------- /tools/src/libfuzzer/libfuzzer_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google Inc. All rights reserved. 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 "port/gtest.h" 16 | #include "src/libfuzzer/libfuzzer_macro.h" 17 | #include "src/mutator_test_proto2.pb.h" 18 | 19 | static bool reached = false; 20 | 21 | DEFINE_PROTO_FUZZER(const protobuf_mutator::Msg::EmptyMessage& message) { 22 | reached = true; 23 | } 24 | 25 | TEST(LibFuzzerTest, Basic) { 26 | LLVMFuzzerTestOneInput((const uint8_t*)"", 0); 27 | EXPECT_TRUE(reached); 28 | } 29 | -------------------------------------------------------------------------------- /tools/port/protobuf.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. All rights reserved. 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 | #ifndef PORT_PROTOBUF_H_ 16 | #define PORT_PROTOBUF_H_ 17 | 18 | #include 19 | 20 | #include "google/protobuf/any.pb.h" 21 | #include "google/protobuf/descriptor.pb.h" 22 | #include "google/protobuf/message.h" 23 | #include "google/protobuf/text_format.h" 24 | #include "google/protobuf/util/message_differencer.h" 25 | #include "google/protobuf/wire_format.h" 26 | 27 | namespace protobuf_mutator { 28 | 29 | namespace protobuf = google::protobuf; 30 | 31 | // String type used by google::protobuf. 32 | using String = std::string; 33 | 34 | } // namespace protobuf_mutator 35 | 36 | #endif // PORT_PROTOBUF_H_ 37 | -------------------------------------------------------------------------------- /tools/src/text_format.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. All rights reserved. 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 | #ifndef SRC_TEXT_FORMAT_H_ 16 | #define SRC_TEXT_FORMAT_H_ 17 | 18 | #include 19 | 20 | #include "port/protobuf.h" 21 | 22 | namespace protobuf_mutator { 23 | 24 | // Text serialization of protos. 25 | bool ParseTextMessage(const uint8_t* data, size_t size, 26 | protobuf::Message* output); 27 | bool ParseTextMessage(const std::string& data, protobuf::Message* output); 28 | size_t SaveMessageAsText(const protobuf::Message& message, uint8_t* data, 29 | size_t max_size); 30 | std::string SaveMessageAsText(const protobuf::Message& message); 31 | 32 | } // namespace protobuf_mutator 33 | 34 | #endif // SRC_TEXT_FORMAT_H_ 35 | -------------------------------------------------------------------------------- /tools/src/binary_format.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. All rights reserved. 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 | #ifndef SRC_BINARY_FORMAT_H_ 16 | #define SRC_BINARY_FORMAT_H_ 17 | 18 | #include 19 | 20 | #include "port/protobuf.h" 21 | 22 | namespace protobuf_mutator { 23 | 24 | // Binary serialization of protos. 25 | bool ParseBinaryMessage(const uint8_t* data, size_t size, 26 | protobuf::Message* output); 27 | bool ParseBinaryMessage(const std::string& data, protobuf::Message* output); 28 | size_t SaveMessageAsBinary(const protobuf::Message& message, uint8_t* data, 29 | size_t max_size); 30 | std::string SaveMessageAsBinary(const protobuf::Message& message); 31 | 32 | } // namespace protobuf_mutator 33 | 34 | #endif // SRC_BINARY_FORMAT_H_ 35 | -------------------------------------------------------------------------------- /tools/src/binary_format.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. All rights reserved. 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 "src/binary_format.h" 16 | 17 | namespace protobuf_mutator { 18 | 19 | using protobuf::Message; 20 | 21 | bool ParseBinaryMessage(const uint8_t* data, size_t size, Message* output) { 22 | return ParseBinaryMessage({data, data + size}, output); 23 | } 24 | 25 | bool ParseBinaryMessage(const std::string& data, protobuf::Message* output) { 26 | output->Clear(); 27 | if (!output->ParsePartialFromString(data)) { 28 | output->Clear(); 29 | return false; 30 | } 31 | return true; 32 | } 33 | 34 | size_t SaveMessageAsBinary(const Message& message, uint8_t* data, 35 | size_t max_size) { 36 | std::string result = SaveMessageAsBinary(message); 37 | if (result.size() <= max_size) { 38 | memcpy(data, result.data(), result.size()); 39 | return result.size(); 40 | } 41 | return 0; 42 | } 43 | 44 | std::string SaveMessageAsBinary(const protobuf::Message& message) { 45 | String tmp; 46 | if (!message.SerializePartialToString(&tmp)) return {}; 47 | return tmp; 48 | } 49 | 50 | } // namespace protobuf_mutator 51 | -------------------------------------------------------------------------------- /tools/src/libfuzzer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. All rights reserved. 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 | add_library(protobuf-mutator-libfuzzer 16 | libfuzzer_mutator.cc 17 | libfuzzer_macro.cc) 18 | target_link_libraries(protobuf-mutator-libfuzzer 19 | protobuf-mutator 20 | ${PROTOBUF_LIBRARIES}) 21 | set_target_properties(protobuf-mutator-libfuzzer PROPERTIES 22 | COMPILE_FLAGS "${NO_FUZZING_FLAGS}" 23 | SOVERSION 0) 24 | 25 | install(TARGETS protobuf-mutator-libfuzzer 26 | ARCHIVE DESTINATION ${LIB_DIR} 27 | LIBRARY DESTINATION ${LIB_DIR}) 28 | 29 | if (LIB_PROTO_MUTATOR_TESTING) 30 | add_executable(libfuzzer_test 31 | libfuzzer_test.cc) 32 | target_link_libraries(libfuzzer_test 33 | protobuf-mutator 34 | protobuf-mutator-libfuzzer 35 | mutator-test-proto 36 | ${GTEST_BOTH_LIBRARIES} 37 | ${CMAKE_THREAD_LIBS_INIT}) 38 | add_test(test.protobuf_libfuzzer_test libfuzzer_test --gtest_color=yes AUTO) 39 | add_dependencies(check libfuzzer_test) 40 | endif() 41 | -------------------------------------------------------------------------------- /tools/src/libfuzzer/libfuzzer_mutator.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. All rights reserved. 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 | #ifndef SRC_LIBFUZZER_LIBFUZZER_MUTATOR_H_ 16 | #define SRC_LIBFUZZER_LIBFUZZER_MUTATOR_H_ 17 | 18 | #include 19 | 20 | #include "src/mutator.h" 21 | 22 | namespace protobuf_mutator { 23 | namespace libfuzzer { 24 | 25 | // Overrides protobuf_mutator::Mutator::Mutate* methods with implementation 26 | // which uses libFuzzer library. protobuf_mutator::Mutator has very basic 27 | // implementation of this methods. 28 | class Mutator : public protobuf_mutator::Mutator { 29 | public: 30 | using protobuf_mutator::Mutator::Mutator; 31 | 32 | protected: 33 | int32_t MutateInt32(int32_t value) override; 34 | int64_t MutateInt64(int64_t value) override; 35 | uint32_t MutateUInt32(uint32_t value) override; 36 | uint64_t MutateUInt64(uint64_t value) override; 37 | float MutateFloat(float value) override; 38 | double MutateDouble(double value) override; 39 | std::string MutateString(const std::string& value, 40 | size_t size_increase_hint) override; 41 | }; 42 | 43 | } // namespace libfuzzer 44 | } // namespace protobuf_mutator 45 | 46 | #endif // SRC_LIBFUZZER_LIBFUZZER_MUTATOR_H_ 47 | -------------------------------------------------------------------------------- /get_coverage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$#" -ne 4 ]; then 4 | echo "Usage: ./get_coverage.sh , all directories should be absolute path" 5 | exit 6 | fi 7 | 8 | ANDROID_BUILD_TOP=$1 9 | ADB=adb 10 | AOSP_PRODUCT=${ANDROID_BUILD_TOP}/out/target/product/$2 11 | NFC_COVERAGE=/data/fuzz/arm64/nfc_coverage_t2t 12 | CORPUS_DIR=/data/fuzz/arm64/t2t_detect_fuzzer/minimized 13 | TMP_DATA_DIR=/data/local/tmp 14 | COVERAGE_DIR=${AOSP_PRODUCT}/coverage 15 | OUT_DIR=$4/coverage 16 | LLVM_GCOV=$3/llvm_gcov.sh 17 | 18 | echo ${LLVM_GCOV} 19 | 20 | #clean up 21 | rm -rf $OUT_DIR 22 | mkdir -p $OUT_DIR 23 | 24 | #copy .gcnodir across 25 | 26 | cp ${COVERAGE_DIR}/system/lib64/libprotobuf-cpp-full.zip ${OUT_DIR} 27 | cp ${COVERAGE_DIR}/system/lib64/libnfc-nci-coverage.zip ${OUT_DIR} 28 | cp ${COVERAGE_DIR}/system/bin/nfc_coverage_t2t.zip ${OUT_DIR} 29 | 30 | #extract .gcnodir to .gcno 31 | 32 | cd ${OUT_DIR} 33 | 34 | unzip ${OUT_DIR}/libprotobuf-cpp-full.zip 35 | unzip ${OUT_DIR}/libnfc-nci-coverage.zip 36 | unzip ${OUT_DIR}/nfc_coverage_t2t.zip 37 | 38 | #clean up .gcda files 39 | echo "Clean up" 40 | $ADB shell rm -rf $TMP_DATA_DIR 41 | $ADB shell mkdir -p $TMP_DATA_DIR 42 | $ADB shell find $TMP_DATA_DIR -iname "*.gcda" -exec rm -rf "{}" "\;" 43 | 44 | # get coverage 45 | $ADB shell \ 46 | GCOV_PREFIX=$TMP_DATA_DIR \ 47 | GCOV_PREFIX_STRIP=`echo $ANDROID_BUILD_TOP | grep -o / | wc -l` \ 48 | ${NFC_COVERAGE} ${CORPUS_DIR} 49 | 50 | $ADB pull ${TMP_DATA_DIR} ${OUT_DIR} 51 | 52 | find . -iname "*.gcda" -exec mv "{}" . \; 53 | find . -iname "*.gcno" -exec mv "{}" . \; 54 | 55 | llvm-cov gcov -f -b *.gcda 56 | 57 | lcov --directory . --base-directory ${ANDROID_BUILD_TOP} --no-external --gcov-tool ${LLVM_GCOV} --capture -o cov.info 58 | 59 | genhtml cov.info -o report 60 | 61 | rm -rf *.gcov cov.info *.gcno *.gcda 62 | 63 | set +x 64 | -------------------------------------------------------------------------------- /tools/src/text_format.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. All rights reserved. 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 "src/text_format.h" 16 | 17 | #include "port/protobuf.h" 18 | 19 | namespace protobuf_mutator { 20 | 21 | using protobuf::Message; 22 | using protobuf::TextFormat; 23 | 24 | bool ParseTextMessage(const uint8_t* data, size_t size, Message* output) { 25 | return ParseTextMessage({data, data + size}, output); 26 | } 27 | 28 | bool ParseTextMessage(const std::string& data, protobuf::Message* output) { 29 | output->Clear(); 30 | TextFormat::Parser parser; 31 | parser.SetRecursionLimit(100); 32 | parser.AllowPartialMessage(true); 33 | if (!parser.ParseFromString(data, output)) { 34 | output->Clear(); 35 | return false; 36 | } 37 | return true; 38 | } 39 | 40 | size_t SaveMessageAsText(const Message& message, uint8_t* data, 41 | size_t max_size) { 42 | std::string result = SaveMessageAsText(message); 43 | if (result.size() <= max_size) { 44 | memcpy(data, result.data(), result.size()); 45 | return result.size(); 46 | } 47 | return 0; 48 | } 49 | 50 | std::string SaveMessageAsText(const protobuf::Message& message) { 51 | String tmp; 52 | if (!protobuf::TextFormat::PrintToString(message, &tmp)) return {}; 53 | return tmp; 54 | } 55 | 56 | } // namespace protobuf_mutator 57 | -------------------------------------------------------------------------------- /docs/extending.md: -------------------------------------------------------------------------------- 1 | # Extending the fuzzer 2 | 3 | The fuzzer can be extended to other types of NFC tags. The `TestDetect` function used in the harness sets up the envoirnment that is suitable for fuzzing other types of tag read/write under `system/nfc/src/nfc/tags` in the aosp source tree: 4 | 5 | ```cpp 6 | void TestDetect(const nfc::DetectSession& session) { 7 | setup(NFC_PROTOCOL_T2T); 8 | nfa_rw_start_ndef_detection(); 9 | nfa_rw_cb.cur_op = NFA_RW_OP_READ_NDEF; 10 | handleT2T(session); 11 | deactivate(); 12 | } 13 | ``` 14 | 15 | To set up for other protocol, just replace `NFC_PROTOCOL_T2T` by a macro appropriate for that protocol. To test other operations other than tag read, (e.g. format, set read only, write), remove the `nfa_rw_cb.cur_op = NFA_RW_OP_READ_NDEF` line. 16 | 17 | After that, the crucial point is to replace the processing logic by ones that are appropriate for the corresponding protocol (i.e. `create_t2t_wait_cc`, `create_t2t_wait_select_sector`, `create_t2t_default_response`) For experiment, You can try to just use the `create_t2t_wait_select_sector` function: 18 | 19 | ```cpp 20 | void create_t2t_wait_select_sector(const nfc::WaitSelectSector& df, NFC_HDR** p_msgs) { 21 | size_t data_len = cap_data_len(df.data().length()); 22 | NFC_HDR* p_msg = create_data_msg_meta(data_len, df.data().c_str()); 23 | if (p_msg == NULL) return; 24 | p_msg->len = (uint16_t)(data_len); 25 | //copy the rest of the data 26 | if (data_len > 3) 27 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + 3, df.data().c_str() + 3, data_len - 3); 28 | p_msgs[0] = p_msg; 29 | return; 30 | } 31 | ``` 32 | 33 | As this will just fuzz with data of any length generated by the fuzzer and take care of the necessary meta data (first 3 bytes in the payload) that is necessary for the payload to be accepted. Using this is probably not optimal and may take longer for fuzzing. To be better results, more effort may be needed to create custom protobuf messages and custom processors. 34 | -------------------------------------------------------------------------------- /tools/src/weighted_reservoir_sampler.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 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 | #ifndef SRC_WEIGHTED_RESERVOIR_SAMPLER_H_ 16 | #define SRC_WEIGHTED_RESERVOIR_SAMPLER_H_ 17 | 18 | #include 19 | #include 20 | 21 | namespace protobuf_mutator { 22 | 23 | // Algorithm pick one item from the sequence of weighted items. 24 | // https://en.wikipedia.org/wiki/Reservoir_sampling#Algorithm_A-Chao 25 | // 26 | // Example: 27 | // WeightedReservoirSampler sampler; 28 | // for(int i = 0; i < size; ++i) 29 | // sampler.Pick(weight[i], i); 30 | // return sampler.GetSelected(); 31 | template 32 | class WeightedReservoirSampler { 33 | public: 34 | explicit WeightedReservoirSampler(RandomEngine* random) : random_(random) {} 35 | 36 | void Try(uint64_t weight, const T& item) { 37 | if (Pick(weight)) selected_ = item; 38 | } 39 | 40 | const T& selected() const { return selected_; } 41 | 42 | bool IsEmpty() const { return total_weight_ == 0; } 43 | 44 | private: 45 | bool Pick(uint64_t weight) { 46 | if (weight == 0) return false; 47 | total_weight_ += weight; 48 | return weight == total_weight_ || std::uniform_int_distribution( 49 | 1, total_weight_)(*random_) <= weight; 50 | } 51 | 52 | T selected_ = {}; 53 | uint64_t total_weight_ = 0; 54 | RandomEngine* random_; 55 | }; 56 | 57 | } // namespace protobuf_mutator 58 | 59 | #endif // SRC_WEIGHTED_RESERVOIR_SAMPLER_H_ 60 | -------------------------------------------------------------------------------- /tools/src/utf8_fix_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. All rights reserved. 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 "src/utf8_fix.h" 16 | 17 | #include "port/gtest.h" 18 | #include "port/protobuf.h" 19 | 20 | namespace protobuf_mutator { 21 | 22 | protobuf::LogSilencer log_silincer; 23 | 24 | class FixUtf8StringTest : public ::testing::TestWithParam { 25 | public: 26 | bool IsStructurallyValid(const std::string& s) { 27 | using protobuf::internal::WireFormatLite; 28 | return WireFormatLite::VerifyUtf8String(s.data(), s.length(), 29 | WireFormatLite::PARSE, ""); 30 | } 31 | }; 32 | 33 | TEST_F(FixUtf8StringTest, IsStructurallyValid) { 34 | EXPECT_TRUE(IsStructurallyValid("")); 35 | EXPECT_TRUE(IsStructurallyValid("abc")); 36 | EXPECT_TRUE(IsStructurallyValid("\xC2\xA2")); 37 | EXPECT_TRUE(IsStructurallyValid("\xE2\x82\xAC")); 38 | EXPECT_TRUE(IsStructurallyValid("\xF0\x90\x8D\x88")); 39 | EXPECT_FALSE(IsStructurallyValid("\xFF\xFF\xFF\xFF")); 40 | EXPECT_FALSE(IsStructurallyValid("\xFF\x8F")); 41 | EXPECT_FALSE(IsStructurallyValid("\x3F\xBF")); 42 | } 43 | 44 | INSTANTIATE_TEST_SUITE_P(Size, FixUtf8StringTest, ::testing::Range(0, 10)); 45 | 46 | TEST_P(FixUtf8StringTest, FixUtf8String) { 47 | RandomEngine random(GetParam()); 48 | std::uniform_int_distribution<> random8(0, 0xFF); 49 | 50 | std::string str(random8(random), 0); 51 | for (uint32_t run = 0; run < 10000; ++run) { 52 | for (size_t i = 0; i < str.size(); ++i) str[i] = random8(random); 53 | std::string fixed = str; 54 | FixUtf8String(&fixed, &random); 55 | if (IsStructurallyValid(str)) { 56 | EXPECT_EQ(str, fixed); 57 | } else { 58 | EXPECT_TRUE(IsStructurallyValid(fixed)); 59 | } 60 | } 61 | } 62 | 63 | } // namespace protobuf_mutator 64 | -------------------------------------------------------------------------------- /tools/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2017 Google Inc. All rights reserved. 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 | add_subdirectory(libfuzzer) 16 | 17 | add_library(protobuf-mutator 18 | binary_format.cc 19 | mutator.cc 20 | text_format.cc 21 | utf8_fix.cc) 22 | target_link_libraries(protobuf-mutator 23 | ${PROTOBUF_LIBRARIES}) 24 | set_target_properties(protobuf-mutator PROPERTIES 25 | COMPILE_FLAGS "${NO_FUZZING_FLAGS}" 26 | SOVERSION 0) 27 | 28 | if (LIB_PROTO_MUTATOR_TESTING) 29 | protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS 30 | mutator_test_proto2.proto 31 | mutator_test_proto3.proto) 32 | 33 | add_library(mutator-test-proto 34 | ${PROTO_SRCS}) 35 | 36 | add_executable(mutator_test 37 | mutator_test.cc 38 | utf8_fix_test.cc 39 | weighted_reservoir_sampler_test.cc) 40 | target_link_libraries(mutator_test 41 | protobuf-mutator 42 | mutator-test-proto 43 | ${ZLIB_LIBRARIES} 44 | ${GTEST_BOTH_LIBRARIES} 45 | ${CMAKE_THREAD_LIBS_INIT}) 46 | 47 | ProcessorCount(CPU_COUNT) 48 | math(EXPR TEST_SHARDS_COUNT 2*${CPU_COUNT}) 49 | math(EXPR TEST_SHARDS_MAX ${TEST_SHARDS_COUNT}-1) 50 | foreach(SHARD RANGE ${TEST_SHARDS_MAX}) 51 | add_test(test.protobuf_mutator_test_${SHARD} mutator_test --gtest_color=yes AUTO) 52 | set_property( 53 | TEST test.protobuf_mutator_test_${SHARD} 54 | APPEND PROPERTY ENVIRONMENT 55 | GTEST_SHARD_INDEX=${SHARD} 56 | GTEST_TOTAL_SHARDS=${TEST_SHARDS_COUNT}) 57 | endforeach(SHARD) 58 | 59 | add_dependencies(check mutator_test) 60 | endif() 61 | 62 | install(TARGETS protobuf-mutator 63 | ARCHIVE DESTINATION ${LIB_DIR} 64 | LIBRARY DESTINATION ${LIB_DIR}) 65 | -------------------------------------------------------------------------------- /tools/src/weighted_reservoir_sampler_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 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 "src/weighted_reservoir_sampler.h" 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "port/gtest.h" 22 | 23 | using testing::Combine; 24 | using testing::Range; 25 | using testing::TestWithParam; 26 | using testing::ValuesIn; 27 | 28 | namespace protobuf_mutator { 29 | 30 | class WeightedReservoirSamplerTest 31 | : public TestWithParam>> {}; 32 | 33 | const int kRuns = 1000000; 34 | 35 | const std::vector kTests[] = { 36 | {1}, 37 | {1, 1, 1}, 38 | {1, 1, 0}, 39 | {1, 10, 100}, 40 | {100, 1, 10}, 41 | {1, 10000, 10000}, 42 | {1, 3, 7, 100, 105}, 43 | {93519, 52999, 354, 37837, 55285, 31787, 89096, 55695, 1587, 44 | 18233, 77557, 67632, 59348, 51250, 17417, 96856, 78568, 44296, 45 | 70170, 41328, 9206, 90187, 54086, 35602, 53167, 33791, 60118, 46 | 52962, 10327, 80513, 49526, 18326, 83662, 49644, 70903, 4910, 47 | 36309, 19196, 42982, 53316, 14773, 86607, 60835}}; 48 | 49 | INSTANTIATE_TEST_SUITE_P(AllTest, WeightedReservoirSamplerTest, 50 | Combine(Range(1, 10, 3), ValuesIn(kTests))); 51 | 52 | TEST_P(WeightedReservoirSamplerTest, Test) { 53 | std::vector weights = std::get<1>(GetParam()); 54 | std::vector counts(weights.size(), 0); 55 | 56 | using RandomEngine = std::minstd_rand; 57 | RandomEngine rand(std::get<0>(GetParam())); 58 | for (int i = 0; i < kRuns; ++i) { 59 | WeightedReservoirSampler sampler(&rand); 60 | for (size_t j = 0; j < weights.size(); ++j) sampler.Try(weights[j], j); 61 | ++counts[sampler.selected()]; 62 | } 63 | 64 | int sum = std::accumulate(weights.begin(), weights.end(), 0); 65 | for (size_t j = 0; j < weights.size(); ++j) { 66 | float expected = weights[j]; 67 | expected /= sum; 68 | 69 | float actual = counts[j]; 70 | actual /= kRuns; 71 | 72 | EXPECT_NEAR(expected, actual, 0.01); 73 | } 74 | } 75 | 76 | } // namespace protobuf_mutator 77 | -------------------------------------------------------------------------------- /tools/src/utf8_fix.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. All rights reserved. 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 "src/utf8_fix.h" 16 | 17 | #include 18 | #include 19 | 20 | namespace protobuf_mutator { 21 | 22 | namespace { 23 | 24 | void StoreCode(char* e, char32_t code, uint8_t size, uint8_t prefix) { 25 | while (--size) { 26 | *(--e) = 0x80 | (code & 0x3F); 27 | code >>= 6; 28 | } 29 | *(--e) = prefix | code; 30 | } 31 | 32 | char* FixCode(char* b, const char* e, RandomEngine* random) { 33 | const char* start = b; 34 | assert(b < e); 35 | 36 | e = std::min(e, b + 4); 37 | char32_t c = *b++; 38 | for (; b < e && (*b & 0xC0) == 0x80; ++b) { 39 | c = (c << 6) + (*b & 0x3F); 40 | } 41 | uint8_t size = b - start; 42 | switch (size) { 43 | case 1: 44 | c &= 0x7F; 45 | StoreCode(b, c, size, 0); 46 | break; 47 | case 2: 48 | c &= 0x7FF; 49 | if (c < 0x80) { 50 | // Use uint32_t because uniform_int_distribution does not support 51 | // char32_t on Windows. 52 | c = std::uniform_int_distribution(0x80, 0x7FF)(*random); 53 | } 54 | StoreCode(b, c, size, 0xC0); 55 | break; 56 | case 3: 57 | c &= 0xFFFF; 58 | 59 | // [0xD800, 0xE000) are reserved for UTF-16 surrogate halves. 60 | if (c < 0x800 || (c >= 0xD800 && c < 0xE000)) { 61 | uint32_t halves = 0xE000 - 0xD800; 62 | c = std::uniform_int_distribution(0x800, 63 | 0xFFFF - halves)(*random); 64 | if (c >= 0xD800) c += halves; 65 | } 66 | StoreCode(b, c, size, 0xE0); 67 | break; 68 | case 4: 69 | c &= 0x1FFFFF; 70 | if (c < 0x10000 || c > 0x10FFFF) { 71 | c = std::uniform_int_distribution(0x10000, 0x10FFFF)(*random); 72 | } 73 | StoreCode(b, c, size, 0xF0); 74 | break; 75 | default: 76 | assert(false && "Unexpected size of UTF-8 sequence"); 77 | } 78 | return b; 79 | } 80 | 81 | } // namespace 82 | 83 | void FixUtf8String(std::string* str, RandomEngine* random) { 84 | if (str->empty()) return; 85 | char* b = &(*str)[0]; 86 | const char* e = b + str->size(); 87 | while (b < e) { 88 | b = FixCode(b, e, random); 89 | } 90 | } 91 | 92 | } // namespace protobuf_mutator 93 | -------------------------------------------------------------------------------- /tools/src/mutator_test_proto3.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package protobuf_mutator; 3 | 4 | message Msg3 { 5 | enum Enum { 6 | ENUM_0 = 0; 7 | ENUM_1 = 1; 8 | ENUM_2 = 2; 9 | ENUM_3 = 3; 10 | ENUM_4 = 4; 11 | ENUM_5 = 5; 12 | ENUM_6 = 6; 13 | ENUM_7 = 7; 14 | ENUM_8 = 8; 15 | ENUM_9 = 9; 16 | } 17 | 18 | message SubMsg { 19 | int64 optional_int64 = 1; 20 | } 21 | 22 | double optional_double = 18; 23 | float optional_float = 19; 24 | int32 optional_int32 = 20; 25 | int64 optional_int64 = 21; 26 | uint32 optional_uint32 = 22; 27 | uint64 optional_uint64 = 23; 28 | sint32 optional_sint32 = 24; 29 | sint64 optional_sint64 = 25; 30 | fixed32 optional_fixed32 = 26; 31 | fixed64 optional_fixed64 = 27; 32 | sfixed32 optional_sfixed32 = 28; 33 | sfixed64 optional_sfixed64 = 29; 34 | bool optional_bool = 30; 35 | string optional_string = 31; 36 | bytes optional_bytes = 32; 37 | Enum optional_enum = 33; 38 | Msg3 optional_msg = 34; 39 | 40 | repeated double repeated_double = 35; 41 | repeated float repeated_float = 36; 42 | repeated int32 repeated_int32 = 37; 43 | repeated int64 repeated_int64 = 38; 44 | repeated uint32 repeated_uint32 = 39; 45 | repeated uint64 repeated_uint64 = 40; 46 | repeated sint32 repeated_sint32 = 41; 47 | repeated sint64 repeated_sint64 = 42; 48 | repeated fixed32 repeated_fixed32 = 43; 49 | repeated fixed64 repeated_fixed64 = 44; 50 | repeated sfixed32 repeated_sfixed32 = 45; 51 | repeated sfixed64 repeated_sfixed64 = 46; 52 | repeated bool repeated_bool = 47; 53 | repeated string repeated_string = 48; 54 | repeated bytes repeated_bytes = 49; 55 | repeated Enum repeated_enum = 50; 56 | repeated Msg3 repeated_msg = 51; 57 | 58 | oneof OneOf { 59 | double oneof_double = 52; 60 | float oneof_float = 53; 61 | int32 oneof_int32 = 54; 62 | int64 oneof_int64 = 55; 63 | uint32 oneof_uint32 = 56; 64 | uint64 oneof_uint64 = 57; 65 | sint32 oneof_sint32 = 58; 66 | sint64 oneof_sint64 = 59; 67 | fixed32 oneof_fixed32 = 60; 68 | fixed64 oneof_fixed64 = 61; 69 | sfixed32 oneof_sfixed32 = 62; 70 | sfixed64 oneof_sfixed64 = 63; 71 | bool oneof_bool = 64; 72 | string oneof_string = 65; 73 | bytes oneof_bytes = 66; 74 | Enum oneof_enum = 67; 75 | Msg3 oneof_msg = 68; 76 | } 77 | 78 | SubMsg sub_message = 69; 79 | 80 | message EmptyMessage {} 81 | 82 | message RegressionMessage { 83 | enum SingleValueEnum { ENUM_0 = 0; } 84 | SingleValueEnum enum = 2; 85 | } 86 | 87 | message SmallMessage { 88 | enum Enum { 89 | ENUM_0 = 0; 90 | ENUM_1 = 1; 91 | ENUM_2 = 2; 92 | ENUM_3 = 3; 93 | } 94 | 95 | bool opt_bool = 1; 96 | Enum opt_enum = 2; 97 | } 98 | 99 | message MapMessage { 100 | map map1 = 1; 101 | map map2 = 2; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /tools/Android.bp: -------------------------------------------------------------------------------- 1 | cc_defaults { 2 | name: "coverage_defaults", 3 | native_coverage : true, 4 | rtti: true, 5 | srcs: [ 6 | "harness_common.cc", 7 | "src/binary_format.cc", 8 | "src/text_format.cc", 9 | "src/utf8_fix.cc", 10 | ], 11 | cflags: [ 12 | "-Wno-multichar", 13 | "-Wno-unused-parameter", 14 | "-DBUILDCFG=1", 15 | "-DDCHECK_ALWAYS_ON", 16 | "-DGKI_ENABLE_BUF_CORRUPTION_CHECK", 17 | "-fprofile-arcs", 18 | "-ftest-coverage", 19 | "-DFUZZ", 20 | ], 21 | include_dirs: [ 22 | "system/nfc/src/include", 23 | "system/nfc/src/gki/ulinux", 24 | "system/nfc/src/gki/common", 25 | "system/nfc/src/nfa/include", 26 | "system/nfc/src/nfc/include", 27 | ], 28 | static_libs: [ 29 | "libnfcutils", 30 | ], 31 | shared_libs: [ 32 | "libnfc-nci-coverage", 33 | "libprotobuf-cpp-full", 34 | ], 35 | ldflags: [ 36 | "-fprofile-arcs", 37 | "-ftest-coverage", 38 | ], 39 | } 40 | 41 | cc_binary { 42 | name: "nfc_coverage_t2t", 43 | defaults: ["coverage_defaults"], 44 | srcs: [ 45 | "coverage_t2t_detect.cc", 46 | "harness_t2t_detect.cc", 47 | "t2t_detect.pb.cc", 48 | ], 49 | } 50 | 51 | cc_defaults { 52 | name: "nfc_harness_defaults", 53 | srcs: [ 54 | "harness_common.cc", 55 | "src/binary_format.cc", 56 | "src/libfuzzer/libfuzzer_macro.cc", 57 | "src/libfuzzer/libfuzzer_mutator.cc", 58 | "src/mutator.cc", 59 | "src/text_format.cc", 60 | "src/utf8_fix.cc", 61 | ], 62 | 63 | cflags: [ 64 | "-Wno-multichar", 65 | "-Wno-unused-parameter", 66 | "-DBUILDCFG=1", 67 | "-DDCHECK_ALWAYS_ON", 68 | "-DGKI_ENABLE_BUF_CORRUPTION_CHECK", 69 | "-DFUZZ", 70 | ], 71 | 72 | rtti: true, 73 | 74 | include_dirs: [ 75 | "system/nfc/src/include", 76 | "system/nfc/src/gki/ulinux", 77 | "system/nfc/src/gki/common", 78 | "system/nfc/src/nfa/include", 79 | "system/nfc/src/nfc/include", 80 | ], 81 | static_libs: [ 82 | "libnfcutils", 83 | ], 84 | shared_libs: [ 85 | "libprotobuf-cpp-full", 86 | ], 87 | 88 | sanitize : { 89 | misc_undefined: [ 90 | "bounds", 91 | ], 92 | integer_overflow: true, 93 | }, 94 | } 95 | 96 | cc_fuzz { 97 | name: "t2t_detect_fuzzer", 98 | defaults: ["nfc_harness_defaults"], 99 | srcs: [ 100 | "t2t_detect_fuzzer.cc", 101 | "harness_t2t_detect.cc", 102 | "t2t_detect.pb.cc", 103 | ], 104 | 105 | shared_libs: [ 106 | "libnfc-nci-fuzz", 107 | ], 108 | } 109 | 110 | cc_binary { 111 | name: "t2t_detect_dbg", 112 | defaults: ["nfc_harness_defaults"], 113 | 114 | srcs: [ 115 | "t2t_detect_dbg.cc", 116 | "harness_t2t_detect.cc", 117 | "t2t_detect.pb.cc", 118 | ], 119 | 120 | cflags: [ 121 | "-g", 122 | "-O0", 123 | ], 124 | 125 | shared_libs: [ 126 | "libnfc-nci-dbg", 127 | ], 128 | } 129 | -------------------------------------------------------------------------------- /docs/coverage_debug.md: -------------------------------------------------------------------------------- 1 | ## Getting coverage information 2 | 3 | To get coverage information, first create a directory called `minimized` and minimize the corpus: 4 | 5 | ``` 6 | sargo:/data/fuzz/arm64/t2t_detect_fuzzer # mkdir minimized 7 | sargo:/data/fuzz/arm64/t2t_detect_fuzzer # ASAN_OPTIONS=detect_container_overflow=0 ./t2t_detect_fuzzer -merge=1 minimized corpus 8 | ``` 9 | 10 | On the host machine, change into the aosp root directory and compile the `nfc_coverage_t2t` target: 11 | 12 | ``` 13 | NATIVE_COVERAGE=true COVERAGE_PATHS="*" make -j($nproc) nfc_coverage_t2t 14 | ``` 15 | 16 | then push this and some other libraries to the device, which requires remounting as it is pushing into `system/bin` (If verity is not disabled, then the first time `adb remount -R` is run, the device will reboot and disable verity. In this case, `adb root` and `adb remount -R` will need to be done again after the reboot): 17 | 18 | ``` 19 | adb root 20 | adb remount -R 21 | adb push /out/target/product//system/bin/nfc_coverage_t2t /system/bin 22 | adb push /out/target/product//system/lib64/libnfc-nci-coverage.so /system/lib64 23 | adb push /out/target/product//system/bin/libprotobuf-cpp-full.so /system/lib64 24 | ``` 25 | 26 | Then create an output directory for the coverage data and run the `get_coverage.sh` script on the root directory of this repo: 27 | 28 | ``` 29 | mkdir OUT_DIR 30 | ./get_coverage.sh 31 | ``` 32 | 33 | where `` is the name of the built for the device, e.g. `sargo` for Pixel3a and all directories should be absolute path. This will create a directory `/coverage` directory with a `report` directory under it that contains coverage information. 34 | 35 | ## Debugging crash samples 36 | 37 | To debug crash samples, build the target `t2t_detect_dbg`: 38 | 39 | ``` 40 | make -j($nproc) t2t_detect_dbg 41 | ``` 42 | 43 | Then copy the relevant binary and libraries to the device, again, this requires a remount: 44 | 45 | ``` 46 | adb root 47 | adb remount -R 48 | adb push /out/target/product//system/bin/t2t_detect_dbg /system/bin 49 | adb push /out/target/product//system/lib64/libnfc-nci-dbg.so /system/lib64 50 | adb push /out/target/product//system/bin/libprotobuf-cpp-full.so /system/lib64 51 | ``` 52 | 53 | To debug, use `gdb` for remote debugging. First forward the port `5039` for debug (other port can also be used): 54 | 55 | ``` 56 | adb forward tcp:5039 tcp:5039 57 | ``` 58 | 59 | Then in the device, start a debugging session with `gdbserver64`: 60 | 61 | ``` 62 | sargo:/data/fuzz/arm64/t2t_detect_fuzzer # gdbserver64 :5039 t2t_detect_fuzzer crash-ID 63 | Process t2t_detect_dbg created; pid = 15700 64 | Listening on port 5039 65 | ``` 66 | 67 | This should start listening on port 5039 for a remote debugging session. 68 | 69 | Now on host, change directory to the aosp root, and start a debugging session with `gdb`(this has to be done on aosp root, and `gdb` under `prebuilts/gdb/linux-x86/bin` is to be used) 70 | 71 | ``` 72 | prebuilts/gdb/linux-x86/bin/gdb out/target/product/sargo/symbols/system/bin/t2t_detect_dbg 73 | ``` 74 | 75 | Once inside `gdb`, set the search path for the shared-library symbols (with `` set according to your setup) and set target to be remote. I suggest adding a `.gdbinit` file that include these lines in ``: 76 | 77 | ``` 78 | set sysroot /out/target/product/sargo/symbols 79 | set solib-search-path /out/target/product/sargo/symbols/system/lib64 80 | target remote :5039 81 | ``` 82 | -------------------------------------------------------------------------------- /tools/src/libfuzzer/libfuzzer_mutator.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. All rights reserved. 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 "src/libfuzzer/libfuzzer_mutator.h" 16 | 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "port/protobuf.h" 24 | #include "src/mutator.h" 25 | 26 | // see compiler-rt/lib/sanitizer-common/sanitizer_internal_defs.h; usage same as 27 | // SANITIZER_INTERFACE_WEAK_DEF with some functionality removed 28 | #ifdef _MSC_VER 29 | #if defined(_M_IX86) || defined(__i386__) 30 | #define WIN_SYM_PREFIX "_" 31 | #else 32 | #define WIN_SYM_PREFIX 33 | #endif 34 | 35 | #define STRINGIFY_(A) #A 36 | #define STRINGIFY(A) STRINGIFY_(A) 37 | 38 | #define WEAK_DEFAULT_NAME(Name) Name##__def 39 | 40 | // clang-format off 41 | #define LIB_PROTO_MUTATOR_WEAK_DEF(ReturnType, Name, ...) \ 42 | __pragma(comment(linker, "/alternatename:" \ 43 | WIN_SYM_PREFIX STRINGIFY(Name) "=" \ 44 | WIN_SYM_PREFIX STRINGIFY(WEAK_DEFAULT_NAME(Name))))\ 45 | extern "C" ReturnType Name(__VA_ARGS__); \ 46 | extern "C" ReturnType WEAK_DEFAULT_NAME(Name)(__VA_ARGS__) 47 | // clang-format on 48 | #else 49 | #define LIB_PROTO_MUTATOR_WEAK_DEF(ReturnType, Name, ...) \ 50 | extern "C" __attribute__((weak)) ReturnType Name(__VA_ARGS__) 51 | #endif 52 | 53 | LIB_PROTO_MUTATOR_WEAK_DEF(size_t, LLVMFuzzerMutate, uint8_t*, size_t, size_t) { 54 | return 0; 55 | } 56 | 57 | namespace protobuf_mutator { 58 | namespace libfuzzer { 59 | 60 | namespace { 61 | 62 | template 63 | T MutateValue(T v) { 64 | size_t size = 65 | LLVMFuzzerMutate(reinterpret_cast(&v), sizeof(v), sizeof(v)); 66 | memset(reinterpret_cast(&v) + size, 0, sizeof(v) - size); 67 | return v; 68 | } 69 | 70 | } // namespace 71 | 72 | int32_t Mutator::MutateInt32(int32_t value) { return MutateValue(value); } 73 | 74 | int64_t Mutator::MutateInt64(int64_t value) { return MutateValue(value); } 75 | 76 | uint32_t Mutator::MutateUInt32(uint32_t value) { return MutateValue(value); } 77 | 78 | uint64_t Mutator::MutateUInt64(uint64_t value) { return MutateValue(value); } 79 | 80 | float Mutator::MutateFloat(float value) { return MutateValue(value); } 81 | 82 | double Mutator::MutateDouble(double value) { return MutateValue(value); } 83 | 84 | std::string Mutator::MutateString(const std::string& value, 85 | size_t size_increase_hint) { 86 | // Randomly return empty strings as LLVMFuzzerMutate does not produce them. 87 | // Use uint16_t because on Windows, uniform_int_distribution does not support 88 | // any 8 bit types. 89 | if (!std::uniform_int_distribution(0, 20)(*random())) return {}; 90 | std::string result = value; 91 | result.resize(value.size() + size_increase_hint); 92 | if (result.empty()) result.push_back(0); 93 | result.resize(LLVMFuzzerMutate(reinterpret_cast(&result[0]), 94 | value.size(), result.size())); 95 | return result; 96 | } 97 | 98 | } // namespace libfuzzer 99 | } // namespace protobuf_mutator 100 | -------------------------------------------------------------------------------- /tools/src/mutator_test_proto2.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | package protobuf_mutator; 3 | 4 | message Msg { 5 | enum Enum { 6 | ENUM_0 = 0; 7 | ENUM_1 = 1; 8 | ENUM_2 = 2; 9 | ENUM_3 = 3; 10 | ENUM_4 = 4; 11 | ENUM_5 = 5; 12 | ENUM_6 = 6; 13 | ENUM_7 = 7; 14 | ENUM_8 = 8; 15 | ENUM_9 = 9; 16 | } 17 | 18 | message SubMsg { 19 | optional int64 optional_int64 = 1; 20 | } 21 | 22 | required double required_double = 1; 23 | required float required_float = 2; 24 | required int32 required_int32 = 3; 25 | required int64 required_int64 = 4; 26 | required uint32 required_uint32 = 5; 27 | required uint64 required_uint64 = 6; 28 | required sint32 required_sint32 = 7; 29 | required sint64 required_sint64 = 8; 30 | required fixed32 required_fixed32 = 9; 31 | required fixed64 required_fixed64 = 10; 32 | required sfixed32 required_sfixed32 = 11; 33 | required sfixed64 required_sfixed64 = 12; 34 | required bool required_bool = 13; 35 | required string required_string = 14; 36 | required bytes required_bytes = 15; 37 | required Enum required_enum = 16; 38 | required SubMsg required_msg = 17; 39 | 40 | optional double optional_double = 18; 41 | optional float optional_float = 19; 42 | optional int32 optional_int32 = 20; 43 | optional int64 optional_int64 = 21; 44 | optional uint32 optional_uint32 = 22; 45 | optional uint64 optional_uint64 = 23; 46 | optional sint32 optional_sint32 = 24; 47 | optional sint64 optional_sint64 = 25; 48 | optional fixed32 optional_fixed32 = 26; 49 | optional fixed64 optional_fixed64 = 27; 50 | optional sfixed32 optional_sfixed32 = 28; 51 | optional sfixed64 optional_sfixed64 = 29; 52 | optional bool optional_bool = 30; 53 | optional string optional_string = 31; 54 | optional bytes optional_bytes = 32; 55 | optional Enum optional_enum = 33; 56 | optional Msg optional_msg = 34; 57 | 58 | repeated double repeated_double = 35; 59 | repeated float repeated_float = 36; 60 | repeated int32 repeated_int32 = 37; 61 | repeated int64 repeated_int64 = 38; 62 | repeated uint32 repeated_uint32 = 39; 63 | repeated uint64 repeated_uint64 = 40; 64 | repeated sint32 repeated_sint32 = 41; 65 | repeated sint64 repeated_sint64 = 42; 66 | repeated fixed32 repeated_fixed32 = 43; 67 | repeated fixed64 repeated_fixed64 = 44; 68 | repeated sfixed32 repeated_sfixed32 = 45; 69 | repeated sfixed64 repeated_sfixed64 = 46; 70 | repeated bool repeated_bool = 47; 71 | repeated string repeated_string = 48; 72 | repeated bytes repeated_bytes = 49; 73 | repeated Enum repeated_enum = 50; 74 | repeated Msg repeated_msg = 51; 75 | 76 | oneof OneOf { 77 | double oneof_double = 52; 78 | float oneof_float = 53; 79 | int32 oneof_int32 = 54; 80 | int64 oneof_int64 = 55; 81 | uint32 oneof_uint32 = 56; 82 | uint64 oneof_uint64 = 57; 83 | sint32 oneof_sint32 = 58; 84 | sint64 oneof_sint64 = 59; 85 | fixed32 oneof_fixed32 = 60; 86 | fixed64 oneof_fixed64 = 61; 87 | sfixed32 oneof_sfixed32 = 62; 88 | sfixed64 oneof_sfixed64 = 63; 89 | bool oneof_bool = 64; 90 | string oneof_string = 65; 91 | bytes oneof_bytes = 66; 92 | Enum oneof_enum = 67; 93 | Msg oneof_msg = 68; 94 | } 95 | 96 | optional SubMsg sub_message = 69; 97 | 98 | required group Group = 70 { 99 | required bool required_bool = 1; 100 | optional bool optional_bool = 2; 101 | repeated bool repeated_bool = 3; 102 | } 103 | 104 | message EmptyMessage {} 105 | 106 | message RegressionMessage { 107 | enum SingleValueEnum { ENUM_0 = 0; } 108 | optional SingleValueEnum enum = 2; 109 | } 110 | 111 | message SmallMessage { 112 | enum Enum { 113 | ENUM_0 = 0; 114 | ENUM_1 = 1; 115 | ENUM_2 = 2; 116 | ENUM_3 = 3; 117 | } 118 | 119 | optional bool opt_bool = 1; 120 | optional Enum opt_enum = 2; 121 | } 122 | 123 | message MapMessage { 124 | map map1 = 1; 125 | map map2 = 2; 126 | } 127 | } 128 | 129 | 130 | -------------------------------------------------------------------------------- /tools/src/mutator.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 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 | #ifndef SRC_MUTATOR_H_ 16 | #define SRC_MUTATOR_H_ 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "port/protobuf.h" 29 | #include "src/random.h" 30 | 31 | namespace protobuf_mutator { 32 | 33 | // Randomly makes incremental change in the given protobuf. 34 | // Usage example: 35 | // protobuf_mutator::Mutator mutator(1); 36 | // MyMessage message; 37 | // message.ParseFromString(encoded_message); 38 | // mutator.Mutate(&message, 10000); 39 | // 40 | // Class implements very basic mutations of fields. E.g. it just flips bits for 41 | // integers, floats and strings. Also it increases, decreases size of 42 | // strings only by one. For better results users should override 43 | // protobuf_mutator::Mutator::Mutate* methods with more useful logic, e.g. using 44 | // library like libFuzzer. 45 | class Mutator { 46 | public: 47 | // seed: value to initialize random number generator. 48 | Mutator() = default; 49 | virtual ~Mutator() = default; 50 | 51 | // Initialized internal random number generator. 52 | void Seed(uint32_t value); 53 | 54 | // message: message to mutate. 55 | // size_increase_hint: approximate number of bytes which can be added to the 56 | // message. Method does not guarantee that real result size increase will be 57 | // less than the value. It only changes probabilities of mutations which can 58 | // cause size increase. Caller could repeat mutation if result was larger than 59 | // requested. 60 | void Mutate(protobuf::Message* message, size_t size_increase_hint); 61 | 62 | void CrossOver(const protobuf::Message& message1, 63 | protobuf::Message* message2); 64 | 65 | // Callback to postprocess mutations. 66 | // Implementation should use seed to initialize random number generators. 67 | using PostProcess = 68 | std::function; 69 | 70 | // Register callback which will be called after every message mutation. 71 | // In this callback fuzzer may adjust content of the message or mutate some 72 | // fields in some fuzzer specific way. 73 | void RegisterPostProcessor(const protobuf::Descriptor* desc, 74 | PostProcess callback); 75 | 76 | protected: 77 | // TODO(vitalybuka): Consider to replace with single mutate (uint8_t*, size). 78 | virtual int32_t MutateInt32(int32_t value); 79 | virtual int64_t MutateInt64(int64_t value); 80 | virtual uint32_t MutateUInt32(uint32_t value); 81 | virtual uint64_t MutateUInt64(uint64_t value); 82 | virtual float MutateFloat(float value); 83 | virtual double MutateDouble(double value); 84 | virtual bool MutateBool(bool value); 85 | virtual size_t MutateEnum(size_t index, size_t item_count); 86 | virtual std::string MutateString(const std::string& value, 87 | size_t size_increase_hint); 88 | 89 | std::unordered_multimap 90 | post_processors_; 91 | 92 | RandomEngine* random() { return &random_; } 93 | 94 | private: 95 | friend class FieldMutator; 96 | friend class TestMutator; 97 | void InitializeAndTrim(protobuf::Message* message, int max_depth); 98 | void MutateImpl(protobuf::Message* message, size_t size_increase_hint); 99 | void CrossOverImpl(const protobuf::Message& message1, 100 | protobuf::Message* message2); 101 | std::string MutateUtf8String(const std::string& value, 102 | size_t size_increase_hint); 103 | void ApplyPostProcessing(protobuf::Message* message); 104 | bool IsInitialized(const protobuf::Message& message) const; 105 | bool keep_initialized_ = true; 106 | size_t random_to_default_ratio_ = 100; 107 | RandomEngine random_; 108 | }; 109 | 110 | } // namespace protobuf_mutator 111 | 112 | #endif // SRC_MUTATOR_H_ 113 | -------------------------------------------------------------------------------- /tools/harness_t2t_detect.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "harness_common.h" 6 | #include "harness_t2t_detect.h" 7 | #include "NfcAdaptation.h" 8 | #include "nfc_int.h" 9 | #include "nfa_sys.h" 10 | #include "nfc_api.h" 11 | #include "rw_api.h" 12 | #include "nfa_api.h" 13 | #include "nfa_rw_int.h" 14 | #include "nfc_config.h" 15 | #include "gki_int.h" 16 | #include "nfc_target.h" 17 | #include "rw_int.h" 18 | 19 | extern tNFC_STATUS nfa_rw_start_ndef_detection(void); 20 | 21 | static char buffer[3] = {0}; 22 | 23 | static int max_op = 50; 24 | 25 | void create_t2t_wait_select_sector(const nfc::WaitSelectSector& df, NFC_HDR** p_msgs) { 26 | size_t data_len = cap_data_len(df.data().length()); 27 | NFC_HDR* p_msg = create_data_msg_meta(data_len, df.data().c_str()); 28 | if (p_msg == NULL) return; 29 | p_msg->len = (uint16_t)(data_len); 30 | //copy the rest of the data 31 | if (data_len > 3) 32 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + 3, df.data().c_str() + 3, data_len - 3); 33 | p_msgs[0] = p_msg; 34 | return; 35 | } 36 | 37 | void create_t2t_wait_cc(const nfc::WaitCc& wait_cc, NFC_HDR** p_msgs) { 38 | uint32_t offset = 3; 39 | size_t data_len = 19; 40 | NFC_HDR* p_msg = create_data_msg_meta(data_len, buffer); 41 | int64_t hdr_0 = wait_cc.hdr_0(); 42 | int64_t hdr_1 = wait_cc.hdr_1(); 43 | uint8_t* hdr_0_ptr = (uint8_t*)(&hdr_0); 44 | uint8_t* hdr_1_ptr = (uint8_t*)(&hdr_1); 45 | if (p_msg == NULL) return; 46 | //set data 47 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + offset, hdr_0_ptr, 8); 48 | offset += 8; 49 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + offset, hdr_1_ptr, 8); 50 | offset += 8; 51 | //set cc0, cc1 and cc3. 52 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + 3 + 0x0F, wait_cc.cc3(), 1); 53 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + 3 + 0x0D, wait_cc.cc1(), 1); 54 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + 3 + 0x0C, T2T_CC0_NMN, 1); 55 | if (get_prob(wait_cc.ack(), 230)) { 56 | p_msg->len = 4; 57 | } else { 58 | p_msg->len = 19; 59 | } 60 | p_msgs[0] = p_msg; 61 | return; 62 | } 63 | 64 | void create_t2t_default_response(const nfc::DefaultResponse& df, NFC_HDR** p_msgs) { 65 | uint32_t offset = 3; 66 | size_t data_len = 19; 67 | NFC_HDR* p_msg = create_data_msg_meta(data_len, buffer); 68 | int64_t hdr_0 = df.hdr_0(); 69 | int64_t hdr_1 = df.hdr_1(); 70 | uint8_t* hdr_0_ptr = (uint8_t*)(&hdr_0); 71 | uint8_t* hdr_1_ptr = (uint8_t*)(&hdr_1); 72 | if (p_msg == NULL) return; 73 | //set data 74 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + offset, hdr_0_ptr, 8); 75 | offset += 8; 76 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + offset, hdr_1_ptr, 8); 77 | offset += 8; 78 | if (get_prob(df.ack(), 230)) { 79 | p_msg->len = 4; 80 | } else { 81 | p_msg->len = 19; 82 | } 83 | p_msgs[0] = p_msg; 84 | return; 85 | } 86 | 87 | 88 | void handleT2T(const nfc::DetectSession& session) { 89 | bool free_buf; 90 | tRW_T2T_CB* p_t2t = &rw_cb.tcb.t2t; 91 | int wait_cc_counter = 0; 92 | /* 93 | int x = 17; 94 | p_t2t->attr[x] = 1; 95 | */ 96 | int default_message_counter = 0; 97 | int wait_select_counter = 0; 98 | for (int i = 0; i < max_op; i++) { 99 | NFC_HDR* p_msgs[1] = {0}; 100 | switch (p_t2t->substate) { 101 | case RW_T2T_SUBSTATE_WAIT_READ_CC: 102 | if (wait_cc_counter >= session.wait_cc_size()) return; 103 | create_t2t_wait_cc(session.wait_cc(wait_cc_counter++), p_msgs); 104 | break; 105 | case RW_T2T_SUBSTATE_WAIT_SELECT_SECTOR: 106 | if (wait_select_counter >= session.wait_select_size()) return; 107 | create_t2t_wait_select_sector(session.wait_select(wait_select_counter++), p_msgs); 108 | break; 109 | default: 110 | if (default_message_counter >= session.dr_size()) return; 111 | create_t2t_default_response(session.dr(default_message_counter++), p_msgs); 112 | break; 113 | } 114 | if (*p_msgs) { 115 | set_message_len(*p_msgs); 116 | NFC_HDR* msg = copy_msg(*p_msgs); 117 | free_buf = nfc_ncif_process_event(msg); 118 | if (free_buf) { 119 | GKI_freebuf(*p_msgs); 120 | } 121 | //Short circuit once it's idle, as anything after that is more or less wasted. 122 | if (p_t2t->state == RW_T2T_STATE_IDLE) { 123 | return; 124 | } 125 | } 126 | } 127 | } 128 | 129 | void TestDetect(const nfc::DetectSession& session) { 130 | setup(NFC_PROTOCOL_T2T); 131 | nfa_rw_start_ndef_detection(); 132 | nfa_rw_cb.cur_op = NFA_RW_OP_READ_NDEF; 133 | handleT2T(session); 134 | deactivate(); 135 | } 136 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android NFC fuzzer 2 | 3 | ## Introduction 4 | 5 | This is a fuzzer that uses libprotobuf-mutator to fuzz the NFC module on an Android device. This can be used on supported Google phones such as Pixel3 and Pixel4. It has been tested on Pixel3a. Currently the NFC forum type 2 tag is implemented. 6 | 7 | DISCLAIMER: As using the fuzzer requires OEM unlocking of the device and flashing custom OS. There is a chance of data loss or bricking the device (which may require factory restore). It is recommended that a dedicated research device is used for the purpose and any consequences is at the user's own risk. The author is not liable for any data loss, damage to devices or compromised in security when following these steps. Fuzzing corpus is also considered as trusted input and the author is not liable for any security compromise resulting from using untrusted corpus and would not consider memory corruption bugs in corpus parsing code security bugs. The fuzzer is offer on an AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON- INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. 8 | 9 | ## Set up instructions 10 | 11 | The idea is to modify nfc system library, libnfc-nci.so to create fuzz harnesses and feed it with inputs generated by libprotobuf-mutator. As I do not seem to be able to fuzz with libprotobuf-mutator as a standalone library, the fuzzer needs to include a local copy of the source code of libprotobuf-mutator and compile it together. The directories `src` and `port` under `tools` are the same directories from libprotobuf-mutator. These correspond to commit `9eaf063` of libprotobuf-mutator in the aosp source tree. The reason for using a cached version is that newer versions seem to have introduced some changes which causes the following failure when fuzzing: 12 | 13 | ``` 14 | /usr/local/google/buildbot/src/android/llvm-toolchain/out/llvm-project/compiler-rt/lib/fuzzer/FuzzerMutate.cpp:510: size_t fuzzer::MutationDispatcher::MutateImpl(uint8_t *, size_t, size_t, Vector &): assertion "MaxSize > 0" failed 15 | ``` 16 | 17 | First follow the instructions [here](https://source.android.com/setup/build/downloading) to obtain a copy of the aosp and initialize it with the master branch. 18 | 19 | ``` 20 | mkdir AOSP_ROOT 21 | cd AOSP_ROOT 22 | repo init -u https://android.googlesource.com/platform/manifest 23 | repo sync -qc -j$(nproc) 24 | ``` 25 | 26 | Then obtain the proprietary binaries for your device following instructions [here](https://source.android.com/setup/build/downloading), under the "Obtain proprietary binary" section. 27 | 28 | ## Build and run the fuzzer 29 | 30 | ### Building the fuzzer 31 | 32 | Next set up the build environment and select the product and variant (See instructions [here](https://source.android.com/setup/build/building)): 33 | 34 | ``` 35 | cd AOSP_ROOT 36 | source build/envsetup.sh 37 | lunch - 38 | ``` 39 | 40 | For example, environment for a Pixel3a will be 41 | 42 | ``` 43 | cd AOSP_ROOT 44 | source build/envsetup.sh 45 | lunch aosp_sargo-userdebug 46 | ``` 47 | 48 | For fuzzing, it is not necessary to build the entire aosp, which will save time and disk space. 49 | 50 | In order to compile the protobuf for fuzzing, `aprotoc` needs to be built: 51 | 52 | ``` 53 | make -j($nproc) aprotoc 54 | ``` 55 | 56 | After that, run the `patch.sh` script in this repository's root directory with the aosp root directory as argument, to patch the nfc library code, and to include the fuzzers in the `system/nfc` directory (The patch should merges cleanly with commit `@cfccaaf` for `system/nfc` and commit `@6645f5c` for `external/protobuf` in the aosp source tree): 57 | 58 | ``` 59 | ./patch.sh AOSP_ROOT 60 | ``` 61 | 62 | at this point, a directory called `tools` will be copied to the `system/nfc` directory in the AOSP checkout. This directory contains the fuzzers, as well as tools for generating coverage and debugging. 63 | 64 | Then compile the protobuf definitions for fuzzing: 65 | 66 | ``` 67 | ./generate_proto.sh AOSP_ROOT 68 | ``` 69 | 70 | Following the build instructions from [here](https://source.android.com/devices/tech/debug/libfuzzer) to build the fuzzer. The available targets can be found in the `tools/Android.bp`, with targets of type `cc_fuzz`. For example, to build the `t2t_detect_fuzzer`, run: 71 | 72 | ``` 73 | SANITIZE_TARGET=address make -j$(nproc) t2t_detect_fuzzer 74 | ``` 75 | 76 | ### Running it on device 77 | 78 | To run the fuzzer on device, the [Android flash tool](https://source.android.com/setup/contribute/flash) can be used. This is a very convenient web service that flashes the latest master build on a device. This avoids the need to build the entire aosp locally. Note that to use the service, OEM needs to be unlock and may also wipe all the user data, so it is recommended to use a dedicated research device for such purpose. These are tested on Android master branch with build number 6331282. 79 | 80 | To use the Android flash tool, `adb` and `fastboot` needs to be installed. These can either be built from the aosp checkout, or install via apt: 81 | 82 | ``` 83 | make -j($nproc) adb 84 | make -j($nproc) fastboot 85 | ``` 86 | 87 | Note also that `fastboot` also requires extra configurations, see [here](https://stackoverflow.com/questions/27017453/fastboot-and-adb-not-working-with-sudo/28127944#28127944) for some details. 88 | 89 | After that, the fuzzer can be copied to the device for fuzzing: 90 | 91 | ``` 92 | adb root 93 | adb sync data 94 | ``` 95 | 96 | If `adb sync data` failed, the same can be achieved by just copying the `data/fuzz` directory in the `out/target/product/` directory: 97 | 98 | ``` 99 | adb push AOSP_ROOT/out/target/product//data/fuzz /data 100 | ``` 101 | 102 | This is now ready for fuzzing on the device: 103 | 104 | ``` 105 | adb shell 106 | sargo:/ # ASAN_OPTIONS=detect_container_overflow=0 /data/fuzz/arm64/t2t_detect_fuzzer/t2t_detect_fuzzer /data/fuzz/arm64/t2t_detect_fuzzer/corpus 107 | ``` 108 | The `detect_container_overflow` option may be required as protobuf is not compiled with asan and will cause `container_overflow` FP when fuzzing. 109 | -------------------------------------------------------------------------------- /tools/src/libfuzzer/libfuzzer_macro.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. All rights reserved. 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 | #ifndef SRC_LIBFUZZER_LIBFUZZER_MACRO_H_ 16 | #define SRC_LIBFUZZER_LIBFUZZER_MACRO_H_ 17 | 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "port/protobuf.h" 25 | 26 | // Defines custom mutator, crossover and test functions using default 27 | // serialization format. Default is text. 28 | #define DEFINE_PROTO_FUZZER(arg) DEFINE_TEXT_PROTO_FUZZER(arg) 29 | // Defines custom mutator, crossover and test functions using text 30 | // serialization. This format is more convenient to read. 31 | #define DEFINE_TEXT_PROTO_FUZZER(arg) DEFINE_PROTO_FUZZER_IMPL(false, arg) 32 | // Defines custom mutator, crossover and test functions using binary 33 | // serialization. This makes mutations faster. However often test function is 34 | // significantly slower than mutator, so fuzzing rate may stay unchanged. 35 | #define DEFINE_BINARY_PROTO_FUZZER(arg) DEFINE_PROTO_FUZZER_IMPL(true, arg) 36 | 37 | // Registers the callback as a potential mutation performed on the parent 38 | // message of a field. This must be called inside an initialization code block. 39 | // libFuzzer suggests putting one-time-initialization in a function used to 40 | // initialize a static variable inside the fuzzer target. For example: 41 | // 42 | // static bool Modify( 43 | // SomeMessage* message /* Fix or additionally modify the message */, 44 | // unsigned int seed /* If random generator is needed use this seed */) { 45 | // ... 46 | // } 47 | // 48 | // DEFINE_PROTO_FUZZER(const SomeMessage& msg) { 49 | // static PostProcessorRegistration reg(&Modify); 50 | // } 51 | 52 | // Implementation of macros above. 53 | #define DEFINE_CUSTOM_PROTO_MUTATOR_IMPL(use_binary, Proto) \ 54 | extern "C" size_t LLVMFuzzerCustomMutator( \ 55 | uint8_t* data, size_t size, size_t max_size, unsigned int seed) { \ 56 | using protobuf_mutator::libfuzzer::CustomProtoMutator; \ 57 | Proto input; \ 58 | return CustomProtoMutator(use_binary, data, size, max_size, seed, &input); \ 59 | } 60 | 61 | #define DEFINE_CUSTOM_PROTO_CROSSOVER_IMPL(use_binary, Proto) \ 62 | extern "C" size_t LLVMFuzzerCustomCrossOver( \ 63 | const uint8_t* data1, size_t size1, const uint8_t* data2, size_t size2, \ 64 | uint8_t* out, size_t max_out_size, unsigned int seed) { \ 65 | using protobuf_mutator::libfuzzer::CustomProtoCrossOver; \ 66 | Proto input1; \ 67 | Proto input2; \ 68 | return CustomProtoCrossOver(use_binary, data1, size1, data2, size2, out, \ 69 | max_out_size, seed, &input1, &input2); \ 70 | } 71 | 72 | #define DEFINE_TEST_ONE_PROTO_INPUT_IMPL(use_binary, Proto) \ 73 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { \ 74 | using protobuf_mutator::libfuzzer::LoadProtoInput; \ 75 | Proto input; \ 76 | if (LoadProtoInput(use_binary, data, size, &input)) \ 77 | TestOneProtoInput(input); \ 78 | return 0; \ 79 | } 80 | 81 | #define DEFINE_POST_PROCESS_PROTO_MUTATION_IMPL(Proto) \ 82 | using PostProcessorRegistration = \ 83 | protobuf_mutator::libfuzzer::PostProcessorRegistration; 84 | 85 | #define DEFINE_PROTO_FUZZER_IMPL(use_binary, arg) \ 86 | static void TestOneProtoInput(arg); \ 87 | using FuzzerProtoType = std::remove_const::argument_type>::type>::type; \ 89 | DEFINE_CUSTOM_PROTO_MUTATOR_IMPL(use_binary, FuzzerProtoType) \ 90 | DEFINE_CUSTOM_PROTO_CROSSOVER_IMPL(use_binary, FuzzerProtoType) \ 91 | DEFINE_TEST_ONE_PROTO_INPUT_IMPL(use_binary, FuzzerProtoType) \ 92 | DEFINE_POST_PROCESS_PROTO_MUTATION_IMPL(FuzzerProtoType) \ 93 | static void TestOneProtoInput(arg) 94 | 95 | namespace protobuf_mutator { 96 | namespace libfuzzer { 97 | 98 | size_t CustomProtoMutator(bool binary, uint8_t* data, size_t size, 99 | size_t max_size, unsigned int seed, 100 | protobuf::Message* input); 101 | size_t CustomProtoCrossOver(bool binary, const uint8_t* data1, size_t size1, 102 | const uint8_t* data2, size_t size2, uint8_t* out, 103 | size_t max_out_size, unsigned int seed, 104 | protobuf::Message* input1, 105 | protobuf::Message* input2); 106 | bool LoadProtoInput(bool binary, const uint8_t* data, size_t size, 107 | protobuf::Message* input); 108 | 109 | void RegisterPostProcessor( 110 | const protobuf::Descriptor* desc, 111 | std::function 112 | callback); 113 | 114 | template 115 | struct PostProcessorRegistration { 116 | PostProcessorRegistration( 117 | const std::function& callback) { 118 | RegisterPostProcessor( 119 | Proto::descriptor(), 120 | [callback](protobuf::Message* message, unsigned int seed) { 121 | callback(static_cast(message), seed); 122 | }); 123 | } 124 | }; 125 | 126 | } // namespace libfuzzer 127 | } // namespace protobuf_mutator 128 | 129 | #endif // SRC_LIBFUZZER_LIBFUZZER_MACRO_H_ 130 | -------------------------------------------------------------------------------- /tools/harness_common.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "harness_common.h" 6 | 7 | extern void nfa_rw_handle_i93_evt(tRW_EVENT event, tRW_DATA* p_rw_data); 8 | extern void nfa_rw_handle_t4t_evt(tRW_EVENT event, tRW_DATA* p_rw_data); 9 | extern void nfa_rw_handle_t3t_evt(tRW_EVENT event, tRW_DATA* p_rw_data); 10 | extern void nfa_rw_handle_t2t_evt(tRW_EVENT event, tRW_DATA* p_rw_data); 11 | extern void nfa_rw_handle_t1t_evt(tRW_EVENT event, tRW_DATA* p_rw_data); 12 | extern tNFC_STATUS nfa_rw_start_ndef_detection(void); 13 | extern void GKI_shutdown(); 14 | extern void gki_buffer_init(); 15 | extern void gki_timers_init(); 16 | extern void NFC_Init_RW(tHAL_NFC_ENTRY* p_hal_entry_tbl); 17 | extern void gki_buffers_cleanup(void); 18 | extern void gki_reset(); 19 | extern void allocate_all_pools(); 20 | extern void reset_task(); 21 | 22 | static NfcAdaptation* adaptation; 23 | 24 | #define T5T_PROTOCOL 0x06 //Need to fix it for some reason. 25 | 26 | static uint8_t* fine_memory_pool[256]; 27 | 28 | void init_fine_memory_pool() { 29 | for (int i = 0; i < 256; i++) { 30 | fine_memory_pool[i] = (uint8_t*)malloc(NCI_MSG_HDR_SIZE + i + sizeof(NFC_HDR) + NFC_RECEIVE_MSGS_OFFSET + BUFFER_HDR_SIZE); 31 | } 32 | } 33 | 34 | void cleanup_fine_memory_pool() { 35 | for (int i = 0; i < 256; i++) { 36 | free(fine_memory_pool[i]); 37 | fine_memory_pool[i] = NULL; 38 | } 39 | } 40 | 41 | void initialize_rf_conn() { 42 | tNFC_CONN_CB* p_cb = &nfc_cb.conn_cb[NFC_RF_CONN_ID]; 43 | p_cb->init_credits = p_cb->num_buff = 0; 44 | nfc_set_conn_id(p_cb, NFC_RF_CONN_ID); 45 | } 46 | 47 | uint16_t cap_data_len(size_t data_len) { 48 | if (data_len < 3) return data_len; 49 | if (data_len - NCI_MSG_HDR_SIZE > 255) return 255 + NCI_MSG_HDR_SIZE; //Some hack to prevent buffer too large. Looks like message length cannot be longer than max of 8bit. 50 | return data_len; 51 | } 52 | 53 | NFC_HDR* create_data_msg_meta(uint16_t data_len, const char* p_data) { 54 | NFC_HDR* p_msg; 55 | /* ignore all data while shutting down NFCC */ 56 | if (nfc_cb.nfc_state == NFC_STATE_W4_HAL_CLOSE) { 57 | return NULL; 58 | } 59 | 60 | if (data_len < 3) return NULL; 61 | p_msg = (NFC_HDR*)GKI_getpoolbuf(NFC_NCI_POOL_ID); 62 | if (p_msg != NULL) { 63 | /* Initialize NFC_HDR */ 64 | p_msg->event = BT_EVT_TO_NFC_NCI; 65 | p_msg->offset = NFC_RECEIVE_MSGS_OFFSET; 66 | //First write the 3 byte header 67 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset, p_data, 3); 68 | memset((uint8_t*)(p_msg + 1) + p_msg->offset, 0, 1); //set everything to zero (mt -> data event and cid -> NFC_RF_CONN_ID) pbf to zero to avoid overflow. 69 | // memset((uint8_t*)(p_msg + 1) + p_msg->offset, p_data[0] & NCI_PBF_MASK, 1); //set everything other than pbf to zero (mt -> data event and cid -> NFC_RF_CONN_ID). 70 | return p_msg; 71 | } 72 | return NULL; 73 | } 74 | 75 | void set_message_len(NFC_HDR* p_msg) { 76 | //Cap message len at 255 77 | if (p_msg->len > 258) { 78 | p_msg->len = 258; 79 | } 80 | uint8_t len = (uint8_t)(p_msg->len - NCI_MSG_HDR_SIZE); 81 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + 2, len, 1); //set len to match message length. 82 | } 83 | 84 | NFC_HDR* copy_msg(NFC_HDR* p_msg) { 85 | uint16_t len = p_msg->len; 86 | if (len < 3) return NULL; 87 | uint8_t* mem = fine_memory_pool[len - 3]; 88 | memcpy(mem, (uint8_t*)p_msg - BUFFER_HDR_SIZE, BUFFER_HDR_SIZE + NCI_MSG_HDR_SIZE + sizeof(NFC_HDR) + NFC_RECEIVE_MSGS_OFFSET + len - 3); 89 | return (NFC_HDR*)((uint8_t*)mem + BUFFER_HDR_SIZE); 90 | } 91 | 92 | void selectProtocol(uint8_t protocol) { 93 | tNFC_ACTIVATE_DEVT* p_activate_params = new tNFC_ACTIVATE_DEVT; 94 | /* not a tag NFC_PROTOCOL_NFCIP1: NFCDEP/LLCP - NFC-A or NFC-F */ 95 | if (NFC_PROTOCOL_T1T == protocol) { 96 | /* Type1Tag - NFC-A */ 97 | p_activate_params->protocol = NFC_PROTOCOL_T1T; 98 | p_activate_params->rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_A; 99 | //Initialize uid 100 | p_activate_params->rf_tech_param.param.pa.nfcid1_len = 4; 101 | for (int i = 0; i < NCI_NFCID1_MAX_LEN; i++) { 102 | p_activate_params->rf_tech_param.param.pa.nfcid1[i] = 0; 103 | } 104 | //Initialize hr 105 | for (int i = 0; i < NCI_T1T_HR_LEN; i++) { 106 | p_activate_params->rf_tech_param.param.pa.hr[i] = 0; 107 | p_activate_params->intf_param.intf_param.frame.param[i] = 0; 108 | } 109 | p_activate_params->intf_param.intf_param.frame.param_len = 0; 110 | } else if (NFC_PROTOCOL_T2T == protocol) { 111 | /* Type2Tag - NFC-A */ 112 | p_activate_params->protocol = NFC_PROTOCOL_T2T; 113 | p_activate_params->rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_A; 114 | p_activate_params->rf_tech_param.param.pa.sel_rsp = NFC_SEL_RES_NFC_FORUM_T2T; 115 | nfa_rw_cb.pa_sel_res = NFC_SEL_RES_NFC_FORUM_T2T; 116 | //Initialize uid 117 | p_activate_params->rf_tech_param.param.pa.nfcid1_len = 4; 118 | for (int i = 0; i < NCI_NFCID1_MAX_LEN; i++) { 119 | p_activate_params->rf_tech_param.param.pa.nfcid1[i] = 0; 120 | } 121 | } else if (false) { 122 | /* Type3Tag - NFC-F */ 123 | p_activate_params->protocol = NFC_PROTOCOL_T3T; 124 | p_activate_params->rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_F; 125 | } else if (NFC_PROTOCOL_ISO_DEP == protocol) { 126 | /* ISODEP/4A,4B- NFC-A or NFC-B */ 127 | p_activate_params->protocol = NFC_PROTOCOL_ISO_DEP; 128 | //p_activate_params->rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_B; 129 | p_activate_params->rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_A; 130 | } else if (NFC_PROTOCOL_T5T == protocol) { 131 | /* T5T */ 132 | p_activate_params->protocol = NFC_PROTOCOL_T5T; 133 | p_activate_params->rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_V; 134 | } 135 | tNFA_RW_MSG* p_data = new tNFA_RW_MSG; 136 | p_data->activate_ntf.p_activate_params = p_activate_params; 137 | nfa_rw_activate_ntf(p_data); 138 | delete p_data; 139 | delete p_activate_params; 140 | } 141 | 142 | extern "C" int LLVMFuzzerInitialize(int *argc, char*** argv) { 143 | return initialize(); 144 | } 145 | 146 | int initialize() { 147 | adaptation = &NfcAdaptation::GetInstance(); 148 | // NFC_Init(NULL); 149 | adaptation->InitializeFuzzer(); 150 | init_fine_memory_pool(); 151 | return 0; 152 | } 153 | 154 | void cleanup() { 155 | GKI_shutdown(); 156 | NfcConfig::clear(); 157 | } 158 | 159 | void deactivate() { 160 | nfa_rw_deactivate_ntf(NULL); 161 | } 162 | 163 | void setup(uint8_t protocol) { 164 | NFC_Init_RW(NULL); 165 | gki_reset(); 166 | reset_task(); 167 | initialize_rf_conn(); 168 | selectProtocol(protocol); 169 | } 170 | 171 | bool get_prob(uint32_t prob, uint8_t thresh) { 172 | uint8_t remainder = prob % 256; 173 | return remainder > thresh; 174 | } 175 | -------------------------------------------------------------------------------- /tools/src/libfuzzer/libfuzzer_macro.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Google Inc. All rights reserved. 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 "src/libfuzzer/libfuzzer_macro.h" 16 | 17 | #include "src/binary_format.h" 18 | #include "src/libfuzzer/libfuzzer_mutator.h" 19 | #include "src/text_format.h" 20 | 21 | namespace protobuf_mutator { 22 | namespace libfuzzer { 23 | 24 | namespace { 25 | 26 | class InputReader { 27 | public: 28 | InputReader(const uint8_t* data, size_t size) : data_(data), size_(size) {} 29 | virtual ~InputReader() = default; 30 | 31 | virtual bool Read(protobuf::Message* message) const = 0; 32 | 33 | const uint8_t* data() const { return data_; } 34 | size_t size() const { return size_; } 35 | 36 | private: 37 | const uint8_t* data_; 38 | size_t size_; 39 | }; 40 | 41 | class OutputWriter { 42 | public: 43 | OutputWriter(uint8_t* data, size_t size) : data_(data), size_(size) {} 44 | virtual ~OutputWriter() = default; 45 | 46 | virtual size_t Write(const protobuf::Message& message) = 0; 47 | 48 | uint8_t* data() const { return data_; } 49 | size_t size() const { return size_; } 50 | 51 | private: 52 | uint8_t* data_; 53 | size_t size_; 54 | }; 55 | 56 | class TextInputReader : public InputReader { 57 | public: 58 | using InputReader::InputReader; 59 | 60 | bool Read(protobuf::Message* message) const override { 61 | return ParseTextMessage(data(), size(), message); 62 | } 63 | }; 64 | 65 | class TextOutputWriter : public OutputWriter { 66 | public: 67 | using OutputWriter::OutputWriter; 68 | 69 | size_t Write(const protobuf::Message& message) override { 70 | return SaveMessageAsText(message, data(), size()); 71 | } 72 | }; 73 | 74 | class BinaryInputReader : public InputReader { 75 | public: 76 | using InputReader::InputReader; 77 | 78 | bool Read(protobuf::Message* message) const override { 79 | return ParseBinaryMessage(data(), size(), message); 80 | } 81 | }; 82 | 83 | class BinaryOutputWriter : public OutputWriter { 84 | public: 85 | using OutputWriter::OutputWriter; 86 | 87 | size_t Write(const protobuf::Message& message) override { 88 | return SaveMessageAsBinary(message, data(), size()); 89 | } 90 | }; 91 | 92 | Mutator* GetMutator() { 93 | static Mutator mutator; 94 | return &mutator; 95 | } 96 | 97 | size_t MutateMessage(unsigned int seed, const InputReader& input, 98 | OutputWriter* output, protobuf::Message* message) { 99 | GetMutator()->Seed(seed); 100 | input.Read(message); 101 | GetMutator()->Mutate(message, output->size() > input.size() 102 | ? (output->size() - input.size()) 103 | : 0); 104 | if (size_t new_size = output->Write(*message)) { 105 | assert(new_size <= output->size()); 106 | return new_size; 107 | } 108 | return 0; 109 | } 110 | 111 | size_t CrossOverMessages(unsigned int seed, const InputReader& input1, 112 | const InputReader& input2, OutputWriter* output, 113 | protobuf::Message* message1, 114 | protobuf::Message* message2) { 115 | GetMutator()->Seed(seed); 116 | input1.Read(message1); 117 | input2.Read(message2); 118 | GetMutator()->CrossOver(*message2, message1); 119 | if (size_t new_size = output->Write(*message1)) { 120 | assert(new_size <= output->size()); 121 | return new_size; 122 | } 123 | return 0; 124 | } 125 | 126 | size_t MutateTextMessage(uint8_t* data, size_t size, size_t max_size, 127 | unsigned int seed, protobuf::Message* message) { 128 | TextInputReader input(data, size); 129 | TextOutputWriter output(data, max_size); 130 | return MutateMessage(seed, input, &output, message); 131 | } 132 | 133 | size_t CrossOverTextMessages(const uint8_t* data1, size_t size1, 134 | const uint8_t* data2, size_t size2, uint8_t* out, 135 | size_t max_out_size, unsigned int seed, 136 | protobuf::Message* message1, 137 | protobuf::Message* message2) { 138 | TextInputReader input1(data1, size1); 139 | TextInputReader input2(data2, size2); 140 | TextOutputWriter output(out, max_out_size); 141 | return CrossOverMessages(seed, input1, input2, &output, message1, message2); 142 | } 143 | 144 | size_t MutateBinaryMessage(uint8_t* data, size_t size, size_t max_size, 145 | unsigned int seed, protobuf::Message* message) { 146 | BinaryInputReader input(data, size); 147 | BinaryOutputWriter output(data, max_size); 148 | return MutateMessage(seed, input, &output, message); 149 | } 150 | 151 | size_t CrossOverBinaryMessages(const uint8_t* data1, size_t size1, 152 | const uint8_t* data2, size_t size2, uint8_t* out, 153 | size_t max_out_size, unsigned int seed, 154 | protobuf::Message* message1, 155 | protobuf::Message* message2) { 156 | BinaryInputReader input1(data1, size1); 157 | BinaryInputReader input2(data2, size2); 158 | BinaryOutputWriter output(out, max_out_size); 159 | return CrossOverMessages(seed, input1, input2, &output, message1, message2); 160 | } 161 | 162 | } // namespace 163 | 164 | size_t CustomProtoMutator(bool binary, uint8_t* data, size_t size, 165 | size_t max_size, unsigned int seed, 166 | protobuf::Message* input) { 167 | auto mutate = binary ? &MutateBinaryMessage : &MutateTextMessage; 168 | return mutate(data, size, max_size, seed, input); 169 | } 170 | 171 | size_t CustomProtoCrossOver(bool binary, const uint8_t* data1, size_t size1, 172 | const uint8_t* data2, size_t size2, uint8_t* out, 173 | size_t max_out_size, unsigned int seed, 174 | protobuf::Message* input1, 175 | protobuf::Message* input2) { 176 | auto cross = binary ? &CrossOverBinaryMessages : &CrossOverTextMessages; 177 | return cross(data1, size1, data2, size2, out, max_out_size, seed, input1, 178 | input2); 179 | } 180 | 181 | bool LoadProtoInput(bool binary, const uint8_t* data, size_t size, 182 | protobuf::Message* input) { 183 | return binary ? ParseBinaryMessage(data, size, input) 184 | : ParseTextMessage(data, size, input); 185 | } 186 | 187 | void RegisterPostProcessor( 188 | const protobuf::Descriptor* desc, 189 | std::function 190 | callback) { 191 | GetMutator()->RegisterPostProcessor(desc, callback); 192 | } 193 | 194 | } // namespace libfuzzer 195 | } // namespace protobuf_mutator 196 | -------------------------------------------------------------------------------- /docs/proxmark.md: -------------------------------------------------------------------------------- 1 | # Testing with Proxmark3 2 | 3 | [Proxmark3](https://lab401.com/products/proxmark-3-rdv4) is used to create the test cases. This is great tool without which the current research would not have been possible. 4 | 5 | ## Setting up Proxmark3 6 | 7 | In order to use Proxmark3 to reproduce the issues, it is necessary to modify the firmware and flash the firmware. The are 2 different versions of the firmware, the [official](https://github.com/Proxmark/proxmark3) firmware that will work on most versions of Proxmark3 and the [RfidResearchGroup](https://github.com/RfidResearchGroup/proxmark3) one that is mostly customized for the rdv4 version. (Although see [this](https://github.com/RfidResearchGroup/proxmark3#build-for-non-rdv4-proxmark3-platforms) for non rdv4). All testing here is done with rdv4 and I do not know if it'll work for non rdv4. For NFC type 2 tags, the RfidResearchGroup version works for both Pixel3a and Pixel4, while the official version only works for Pixel3a. 8 | 9 | The documentation on both repositories are fairly informative and easy to follow. There are, however, a couple of things that are worth pointing out here: 10 | 11 | ### ModemManager 12 | 13 | This is a very important point to note. The official documentation seems to suggest that `modemmanager` is only applicable on Kali, but I had issue with ubuntu and did get my Proxmark3 bricked (this is not the end of the world, as it can normally be recovered easily by flashing the firmware again) So please check [this](https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/md/Installation_Instructions/Linux-Installation-Instructions.md#check-modemmanager 14 | ) out before you start. 15 | 16 | ### Recovering a bricked device 17 | 18 | If, in the unfortunate event, the device is bricked, as long as the bootrom is not corrupted, (which is most of the cases), it can be recovered as follows (answer taken from [here](http://www.proxmark.org/forum/viewtopic.php?id=2055)) 19 | 20 | 1. Unplug proxmark from PC 21 | 2. Press and hold button and then connect to PC (while still holding the button) 22 | 3. Wait until proxmark recognised by host OS. 23 | 4. Flash bootrom: 24 | 25 | ``` 26 | ./proxmark3/client/flasher -b ./proxmark3/bootrom/obj/bootrom.elf 27 | ``` 28 | 29 | 5. Wait until flashing is done and then release the button. 30 | 31 | Important thing is that the button needs to be held the whole time until the bootrom had finished flashing. 32 | 33 | ### Unplug before flashing firmware 34 | 35 | The device can sometimes be bricked if you try to flash the firmware while it is in the middle of something. To be on the safe side, unplug the device and then plug it in again before flashing the firmware. 36 | 37 | ### Avoid flashing bootrom when it is not necessary 38 | 39 | During the initial set up, it is necessary to flash the bootrom, but normally when testing new payload, it is sufficient to just flash the fullimage, which would reduce the chance of bootrom getting corrupted. For the official branch, this is done by 40 | 41 | ``` 42 | ./proxmark3/client/flasher /dev/ttyACM0 armsrc/obj/fullimage.elf 43 | ``` 44 | 45 | On the RfidResearchGroup branch, this is done by: 46 | 47 | ``` 48 | ./proxmark3/pm3-flash-fullimage 49 | ``` 50 | 51 | ## Creating test case 52 | 53 | Due to the various custom parsing done by the fuzzer, it is probably easiest to reconstruct the payload by starting a debugging session (see [here](coverage_debug.md) for more details) 54 | 55 | First set up a remote debugging session, then set break points at the following functions: `create_t2t_default_response`, `create_t2t_wait_cc`, `create_t2t_wait_select_sector` and `num2tlv`. The first 3 functions are used for converting protobuf messages into NFC format, they basically take 2 8 byte integers (normally called `hdr_0` and `hdr_1` ) and concatenating them to form a 16 byte payload. This 16 byte array is the one that is needed to construct the payload. However some bytes are overwritten by other fields, for example, `create_t2t_wait_cc` overwrites the following bytes: 56 | 57 | ```cpp 58 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + 3 + 0x0F, wait_cc.cc3(), 1); 59 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + 3 + 0x0D, wait_cc.cc1(), 1); 60 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + 3 + 0x0C, T2T_CC0_NMN, 1); 61 | ``` 62 | 63 | In all cases, the final payload is the array that goes from `p_msg->offset + 3` to `p_msg->offset + 19`, so it is probably more useful to inspect them after all the processing is done. 64 | 65 | This, however, is not the only modification of the payload. As some data is interpreted as enums with only 6 valid values, while others interpreted as raw data, there is a further processing in the fuzzer to convert data to enums whenever appropriate to make fuzzing more efficient. This is done in `num2tlv`. Whenever `num2tlv` is called, it will convert the entry of the payload into an enum by simply taking a module of 6. 66 | 67 | ```cpp 68 | static uint8_t num2tlv(uint8_t input) { 69 | switch (input % 6) { 70 | case 0: 71 | return TAG_NULL_TLV; 72 | case 1: 73 | return TAG_LOCK_CTRL_TLV; 74 | case 2: 75 | return TAG_MEM_CTRL_TLV; 76 | case 3: 77 | return TAG_NDEF_TLV; 78 | case 4: 79 | return TAG_PROPRIETARY_TLV; 80 | case 5: 81 | return TAG_TERMINATOR_TLV; 82 | default: 83 | return TAG_NDEF_TLV; 84 | } 85 | } 86 | ``` 87 | 88 | This is called in `rw_t2t_handle_tlv_detect_rsp` to convert the payload. So to get the final payload, set a break point in `num2tlv`, then go up a frame and replace the `offset - 1` entry by its module of 6 in the current block of 16 byte payload. (In the following, `p_data` is the current block of 16 byte) 89 | 90 | ```cpp 91 | static void rw_t2t_handle_tlv_detect_rsp(uint8_t* p_data) { 92 | ... 93 | for (offset = 0; offset < T2T_READ_DATA_LEN && !failed && !found;) { 94 | if (rw_t2t_is_lock_res_byte((uint16_t)(p_t2t->work_offset + offset)) == 95 | true) { 96 | /* Skip locks, reserved bytes while searching for TLV */ 97 | offset++; 98 | continue; 99 | } 100 | switch (p_t2t->substate) { 101 | case RW_T2T_SUBSTATE_WAIT_TLV_DETECT: 102 | /* Search for the tlv */ 103 | p_t2t->found_tlv = num2tlv(p_data[offset++]); 104 | ``` 105 | 106 | Repeat this procedure and you should be able to get the complete payload in blocks of 16 bytes: 107 | 108 | ``` 109 | {{... array of 16 byte}, {... array of 16 byte}, ...} 110 | ``` 111 | 112 | This is more or less the payload to be used in the proxmark3 [templates](templates). Once you obtained the payload, replace `FUZZER_PAYLOAD` in the template files by the payload arrays, but pad the 16 byte blocks with zeros to form 18 byte blocks, e.g. if the payload is: 113 | 114 | ``` 115 | { 116 | {0x01, 0x03, 0x00, 0x0a, 117 | 0x00, 0x00, 0x00, 0x00, 118 | 0x01, 0x03, 0x00, 0x0a, 119 | 0x0a, 0x00, 0x00, 0x00 120 | }, 121 | {0x01, 0x03, 0x00, 0x00, 122 | 0x00, 0x00, 0x00, 0x00, 123 | 0x00, 0x00, 0x00, 0x00, 124 | 0x00, 0x00, 0x00, 0x00, 125 | }, 126 | }; 127 | ``` 128 | 129 | then replace `FUZZER_PAYLOAD` in the template with this, and pad each block with 2 `0x00`: 130 | 131 | ```cpp 132 | uint8_t rsp[][MAX_MIFARE_FRAME_SIZE] = { 133 | {0x01, 0x03, 0x00, 0x0a, 134 | 0x00, 0x00, 0x00, 0x00, 135 | 0x01, 0x03, 0x00, 0x0a, 136 | 0x0a, 0x00, 0x00, 0x00, 137 | 0x00, 0x00, //<--- pad with zeros 138 | }, 139 | {0x01, 0x03, 0x00, 0x00, 140 | 0x00, 0x00, 0x00, 0x00, 141 | 0x00, 0x00, 0x00, 0x00, 142 | 0x00, 0x00, 0x00, 0x00, 143 | 0x00, 0x00, //<--- pad with zeros 144 | }, 145 | }; 146 | 147 | ``` 148 | Also replace the `FUZZER_PAYLOAD_LEN` with the number of blocks (i.e. 2): 149 | 150 | ```cpp 151 | if (tagType == 7 || tagType == 2) { 152 | // first blocks of emu are header 153 | AddCrc14A(rsp[readCount], 16); 154 | EmSendCmd(rsp[readCount], 18); 155 | if (readCount < 2) //<--- Replace FUZZER_PAYLOAD_LEN with 2 156 | readCount++; 157 | // We already responded, do not send anything with the EmSendCmd14443aRaw() that is called below 158 | p_response = NULL; 159 | ``` 160 | 161 | After that, replace the file `iso14443a.c` in the `armsrc` folder in the appropriate proxmark3 repository with the template, compile and flash the firmware, connect to proxmark3: 162 | 163 | ``` 164 | cd client 165 | ./proxmark3 /dev/ttyACM0 166 | ``` 167 | 168 | Once inside the proxmark console, run the following to simulate a tag. 169 | ``` 170 | hf 14a sim t 7 u 120F5C3C 171 | ``` 172 | 173 | The payload can then be tested against a phone. 174 | 175 | ### General troubleshooting 176 | 177 | Once the simulation has stopped, the communications between the phone and proxmark3 can be viewed with the following command in the proxmark console: 178 | 179 | ``` 180 | hf list 14a 181 | ``` 182 | 183 | This will print out details like: 184 | 185 | ``` 186 | Start | End | Src | Data (! denotes parity error, ' denotes short bytes) | CRC | Annotation | 187 | ------------|------------|-----|-----------------------------------------------------------------|-----|--------------------| 188 | 0 | 1056 | Rdr | 26' | | REQA 189 | 2228 | 4596 | Tag | 04 00 | | 190 | 7804506 | 7805562 | Rdr | 26' | | REQA 191 | 7806734 | 7809102 | Tag | 04 00 | | 192 | 7816592 | 7821360 | Rdr | 50 00 57 cd | ok | HALT 193 | 7846488 | 7847480 | Rdr | 52' | | WUPA 194 | 7848716 | 7851084 | Tag | 04 00 | | 195 | 7858942 | 7861406 | Rdr | 93 20 | | ANTICOLL 196 | 7862578 | 7868402 | Tag | 12 0f 5c 3c 7d | | 197 | 7875200 | 7885728 | Rdr | 93 70 12 0f 5c 3c 7d 8d 58 | ok | SELECT_UID 198 | 7886900 | 7890484 | Tag | 00 fe 51 | | 199 | 8056736 | 8061504 | Rdr | 50 00 57 cd | ok | HALT 200 | 8172886 | 8173878 | Rdr | 52' | | WUPA 201 | 8175114 | 8177482 | Tag | 04 00 | | 202 | 8195234 | 8205762 | Rdr | 93 70 12 0f 5c 3c 7d 8d 58 | ok | SELECT_UID 203 | 8206934 | 8210518 | Tag | 00 fe 51 | | 204 | 8250880 | 8255648 | Rdr | 30 00 02 a8 | ok | READBLOCK(0) 205 | 8258356 | 8279156 | Tag | 41 41 41 41 41 41 41 41 fa ff ff ff e1 11 ff 00 | | 206 | ``` 207 | 208 | If connection is successful, then you should see the payload in the console output (last line in the above) Sometimes it may take multiple trials to get things working. 209 | 210 | 211 | -------------------------------------------------------------------------------- /tools/src/field_instance.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 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 | #ifndef SRC_FIELD_INSTANCE_H_ 16 | #define SRC_FIELD_INSTANCE_H_ 17 | 18 | #include 19 | #include 20 | 21 | #include "port/protobuf.h" 22 | 23 | namespace protobuf_mutator { 24 | 25 | // Helper class for common protobuf fields operations. 26 | class ConstFieldInstance { 27 | public: 28 | static const size_t kInvalidIndex = -1; 29 | 30 | struct Enum { 31 | size_t index; 32 | size_t count; 33 | }; 34 | 35 | ConstFieldInstance() 36 | : message_(nullptr), descriptor_(nullptr), index_(kInvalidIndex) {} 37 | 38 | ConstFieldInstance(const protobuf::Message* message, 39 | const protobuf::FieldDescriptor* field, size_t index) 40 | : message_(message), descriptor_(field), index_(index) { 41 | assert(message_); 42 | assert(descriptor_); 43 | assert(index_ != kInvalidIndex); 44 | assert(descriptor_->is_repeated()); 45 | } 46 | 47 | ConstFieldInstance(const protobuf::Message* message, 48 | const protobuf::FieldDescriptor* field) 49 | : message_(message), descriptor_(field), index_(kInvalidIndex) { 50 | assert(message_); 51 | assert(descriptor_); 52 | assert(!descriptor_->is_repeated()); 53 | } 54 | 55 | void GetDefault(int32_t* out) const { 56 | *out = descriptor_->default_value_int32(); 57 | } 58 | 59 | void GetDefault(int64_t* out) const { 60 | *out = descriptor_->default_value_int64(); 61 | } 62 | 63 | void GetDefault(uint32_t* out) const { 64 | *out = descriptor_->default_value_uint32(); 65 | } 66 | 67 | void GetDefault(uint64_t* out) const { 68 | *out = descriptor_->default_value_uint64(); 69 | } 70 | 71 | void GetDefault(double* out) const { 72 | *out = descriptor_->default_value_double(); 73 | } 74 | 75 | void GetDefault(float* out) const { 76 | *out = descriptor_->default_value_float(); 77 | } 78 | 79 | void GetDefault(bool* out) const { *out = descriptor_->default_value_bool(); } 80 | 81 | void GetDefault(Enum* out) const { 82 | const protobuf::EnumValueDescriptor* value = 83 | descriptor_->default_value_enum(); 84 | const protobuf::EnumDescriptor* type = value->type(); 85 | *out = {static_cast(value->index()), 86 | static_cast(type->value_count())}; 87 | } 88 | 89 | void GetDefault(std::string* out) const { 90 | *out = descriptor_->default_value_string(); 91 | } 92 | 93 | void GetDefault(std::unique_ptr* out) const { 94 | out->reset(reflection() 95 | .GetMessageFactory() 96 | ->GetPrototype(descriptor_->message_type()) 97 | ->New()); 98 | } 99 | 100 | void Load(int32_t* value) const { 101 | *value = is_repeated() 102 | ? reflection().GetRepeatedInt32(*message_, descriptor_, index_) 103 | : reflection().GetInt32(*message_, descriptor_); 104 | } 105 | 106 | void Load(int64_t* value) const { 107 | *value = is_repeated() 108 | ? reflection().GetRepeatedInt64(*message_, descriptor_, index_) 109 | : reflection().GetInt64(*message_, descriptor_); 110 | } 111 | 112 | void Load(uint32_t* value) const { 113 | *value = is_repeated() ? reflection().GetRepeatedUInt32(*message_, 114 | descriptor_, index_) 115 | : reflection().GetUInt32(*message_, descriptor_); 116 | } 117 | 118 | void Load(uint64_t* value) const { 119 | *value = is_repeated() ? reflection().GetRepeatedUInt64(*message_, 120 | descriptor_, index_) 121 | : reflection().GetUInt64(*message_, descriptor_); 122 | } 123 | 124 | void Load(double* value) const { 125 | *value = is_repeated() ? reflection().GetRepeatedDouble(*message_, 126 | descriptor_, index_) 127 | : reflection().GetDouble(*message_, descriptor_); 128 | } 129 | 130 | void Load(float* value) const { 131 | *value = is_repeated() 132 | ? reflection().GetRepeatedFloat(*message_, descriptor_, index_) 133 | : reflection().GetFloat(*message_, descriptor_); 134 | } 135 | 136 | void Load(bool* value) const { 137 | *value = is_repeated() 138 | ? reflection().GetRepeatedBool(*message_, descriptor_, index_) 139 | : reflection().GetBool(*message_, descriptor_); 140 | } 141 | 142 | void Load(Enum* value) const { 143 | const protobuf::EnumValueDescriptor* value_descriptor = 144 | is_repeated() 145 | ? reflection().GetRepeatedEnum(*message_, descriptor_, index_) 146 | : reflection().GetEnum(*message_, descriptor_); 147 | *value = {static_cast(value_descriptor->index()), 148 | static_cast(value_descriptor->type()->value_count())}; 149 | if (value->index >= value->count) GetDefault(value); 150 | } 151 | 152 | void Load(std::string* value) const { 153 | *value = is_repeated() ? reflection().GetRepeatedString(*message_, 154 | descriptor_, index_) 155 | : reflection().GetString(*message_, descriptor_); 156 | } 157 | 158 | void Load(std::unique_ptr* value) const { 159 | const protobuf::Message& source = 160 | is_repeated() 161 | ? reflection().GetRepeatedMessage(*message_, descriptor_, index_) 162 | : reflection().GetMessage(*message_, descriptor_); 163 | value->reset(source.New()); 164 | (*value)->CopyFrom(source); 165 | } 166 | 167 | template 168 | bool CanStore(const T& value) const { 169 | return true; 170 | } 171 | 172 | bool CanStore(const std::string& value) const { 173 | if (!EnforceUtf8()) return true; 174 | using protobuf::internal::WireFormatLite; 175 | return WireFormatLite::VerifyUtf8String(value.data(), value.length(), 176 | WireFormatLite::PARSE, ""); 177 | } 178 | 179 | std::string name() const { return descriptor_->name(); } 180 | 181 | protobuf::FieldDescriptor::CppType cpp_type() const { 182 | return descriptor_->cpp_type(); 183 | } 184 | 185 | const protobuf::EnumDescriptor* enum_type() const { 186 | return descriptor_->enum_type(); 187 | } 188 | 189 | const protobuf::Descriptor* message_type() const { 190 | return descriptor_->message_type(); 191 | } 192 | 193 | bool EnforceUtf8() const { 194 | return descriptor_->type() == protobuf::FieldDescriptor::TYPE_STRING && 195 | descriptor()->file()->syntax() == 196 | protobuf::FileDescriptor::SYNTAX_PROTO3; 197 | } 198 | 199 | const protobuf::FieldDescriptor* descriptor() const { return descriptor_; } 200 | 201 | std::string DebugString() const { 202 | std::string s = descriptor_->DebugString(); 203 | if (is_repeated()) s += "[" + std::to_string(index_) + "]"; 204 | return s + " of\n" + message_->DebugString(); 205 | } 206 | 207 | protected: 208 | bool is_repeated() const { return descriptor_->is_repeated(); } 209 | 210 | const protobuf::Reflection& reflection() const { 211 | return *message_->GetReflection(); 212 | } 213 | 214 | size_t index() const { return index_; } 215 | 216 | private: 217 | template 218 | friend struct FieldFunction; 219 | 220 | const protobuf::Message* message_; 221 | const protobuf::FieldDescriptor* descriptor_; 222 | size_t index_; 223 | }; 224 | 225 | class FieldInstance : public ConstFieldInstance { 226 | public: 227 | static const size_t kInvalidIndex = -1; 228 | 229 | FieldInstance() : ConstFieldInstance(), message_(nullptr) {} 230 | 231 | FieldInstance(protobuf::Message* message, 232 | const protobuf::FieldDescriptor* field, size_t index) 233 | : ConstFieldInstance(message, field, index), message_(message) {} 234 | 235 | FieldInstance(protobuf::Message* message, 236 | const protobuf::FieldDescriptor* field) 237 | : ConstFieldInstance(message, field), message_(message) {} 238 | 239 | void Delete() const { 240 | if (!is_repeated()) return reflection().ClearField(message_, descriptor()); 241 | int field_size = reflection().FieldSize(*message_, descriptor()); 242 | // API has only method to delete the last message, so we move method from 243 | // the 244 | // middle to the end. 245 | for (int i = index() + 1; i < field_size; ++i) 246 | reflection().SwapElements(message_, descriptor(), i, i - 1); 247 | reflection().RemoveLast(message_, descriptor()); 248 | } 249 | 250 | template 251 | void Create(const T& value) const { 252 | if (!is_repeated()) return Store(value); 253 | InsertRepeated(value); 254 | } 255 | 256 | void Store(int32_t value) const { 257 | if (is_repeated()) 258 | reflection().SetRepeatedInt32(message_, descriptor(), index(), value); 259 | else 260 | reflection().SetInt32(message_, descriptor(), value); 261 | } 262 | 263 | void Store(int64_t value) const { 264 | if (is_repeated()) 265 | reflection().SetRepeatedInt64(message_, descriptor(), index(), value); 266 | else 267 | reflection().SetInt64(message_, descriptor(), value); 268 | } 269 | 270 | void Store(uint32_t value) const { 271 | if (is_repeated()) 272 | reflection().SetRepeatedUInt32(message_, descriptor(), index(), value); 273 | else 274 | reflection().SetUInt32(message_, descriptor(), value); 275 | } 276 | 277 | void Store(uint64_t value) const { 278 | if (is_repeated()) 279 | reflection().SetRepeatedUInt64(message_, descriptor(), index(), value); 280 | else 281 | reflection().SetUInt64(message_, descriptor(), value); 282 | } 283 | 284 | void Store(double value) const { 285 | if (is_repeated()) 286 | reflection().SetRepeatedDouble(message_, descriptor(), index(), value); 287 | else 288 | reflection().SetDouble(message_, descriptor(), value); 289 | } 290 | 291 | void Store(float value) const { 292 | if (is_repeated()) 293 | reflection().SetRepeatedFloat(message_, descriptor(), index(), value); 294 | else 295 | reflection().SetFloat(message_, descriptor(), value); 296 | } 297 | 298 | void Store(bool value) const { 299 | if (is_repeated()) 300 | reflection().SetRepeatedBool(message_, descriptor(), index(), value); 301 | else 302 | reflection().SetBool(message_, descriptor(), value); 303 | } 304 | 305 | void Store(const Enum& value) const { 306 | assert(value.index < value.count); 307 | const protobuf::EnumValueDescriptor* enum_value = 308 | descriptor()->enum_type()->value(value.index); 309 | if (is_repeated()) 310 | reflection().SetRepeatedEnum(message_, descriptor(), index(), enum_value); 311 | else 312 | reflection().SetEnum(message_, descriptor(), enum_value); 313 | } 314 | 315 | void Store(const std::string& value) const { 316 | if (is_repeated()) 317 | reflection().SetRepeatedString(message_, descriptor(), index(), value); 318 | else 319 | reflection().SetString(message_, descriptor(), value); 320 | } 321 | 322 | void Store(const std::unique_ptr& value) const { 323 | protobuf::Message* mutable_message = 324 | is_repeated() ? reflection().MutableRepeatedMessage( 325 | message_, descriptor(), index()) 326 | : reflection().MutableMessage(message_, descriptor()); 327 | mutable_message->Clear(); 328 | if (value) mutable_message->CopyFrom(*value); 329 | } 330 | 331 | private: 332 | template 333 | void InsertRepeated(const T& value) const { 334 | PushBackRepeated(value); 335 | size_t field_size = reflection().FieldSize(*message_, descriptor()); 336 | if (field_size == 1) return; 337 | // API has only method to add field to the end of the list. So we add 338 | // descriptor() 339 | // and move it into the middle. 340 | for (size_t i = field_size - 1; i > index(); --i) 341 | reflection().SwapElements(message_, descriptor(), i, i - 1); 342 | } 343 | 344 | void PushBackRepeated(int32_t value) const { 345 | assert(is_repeated()); 346 | reflection().AddInt32(message_, descriptor(), value); 347 | } 348 | 349 | void PushBackRepeated(int64_t value) const { 350 | assert(is_repeated()); 351 | reflection().AddInt64(message_, descriptor(), value); 352 | } 353 | 354 | void PushBackRepeated(uint32_t value) const { 355 | assert(is_repeated()); 356 | reflection().AddUInt32(message_, descriptor(), value); 357 | } 358 | 359 | void PushBackRepeated(uint64_t value) const { 360 | assert(is_repeated()); 361 | reflection().AddUInt64(message_, descriptor(), value); 362 | } 363 | 364 | void PushBackRepeated(double value) const { 365 | assert(is_repeated()); 366 | reflection().AddDouble(message_, descriptor(), value); 367 | } 368 | 369 | void PushBackRepeated(float value) const { 370 | assert(is_repeated()); 371 | reflection().AddFloat(message_, descriptor(), value); 372 | } 373 | 374 | void PushBackRepeated(bool value) const { 375 | assert(is_repeated()); 376 | reflection().AddBool(message_, descriptor(), value); 377 | } 378 | 379 | void PushBackRepeated(const Enum& value) const { 380 | assert(value.index < value.count); 381 | const protobuf::EnumValueDescriptor* enum_value = 382 | descriptor()->enum_type()->value(value.index); 383 | assert(is_repeated()); 384 | reflection().AddEnum(message_, descriptor(), enum_value); 385 | } 386 | 387 | void PushBackRepeated(const std::string& value) const { 388 | assert(is_repeated()); 389 | reflection().AddString(message_, descriptor(), value); 390 | } 391 | 392 | void PushBackRepeated(const std::unique_ptr& value) const { 393 | assert(is_repeated()); 394 | protobuf::Message* mutable_message = 395 | reflection().AddMessage(message_, descriptor()); 396 | mutable_message->Clear(); 397 | if (value) mutable_message->CopyFrom(*value); 398 | } 399 | 400 | protobuf::Message* message_; 401 | }; 402 | 403 | template 404 | struct FieldFunction { 405 | template 406 | R operator()(const Field& field, const Args&... args) const { 407 | assert(field.descriptor()); 408 | using protobuf::FieldDescriptor; 409 | switch (field.cpp_type()) { 410 | case FieldDescriptor::CPPTYPE_INT32: 411 | return static_cast(this)->template ForType(field, 412 | args...); 413 | case FieldDescriptor::CPPTYPE_INT64: 414 | return static_cast(this)->template ForType(field, 415 | args...); 416 | case FieldDescriptor::CPPTYPE_UINT32: 417 | return static_cast(this)->template ForType( 418 | field, args...); 419 | case FieldDescriptor::CPPTYPE_UINT64: 420 | return static_cast(this)->template ForType( 421 | field, args...); 422 | case FieldDescriptor::CPPTYPE_DOUBLE: 423 | return static_cast(this)->template ForType(field, 424 | args...); 425 | case FieldDescriptor::CPPTYPE_FLOAT: 426 | return static_cast(this)->template ForType(field, 427 | args...); 428 | case FieldDescriptor::CPPTYPE_BOOL: 429 | return static_cast(this)->template ForType(field, 430 | args...); 431 | case FieldDescriptor::CPPTYPE_ENUM: 432 | return static_cast(this) 433 | ->template ForType(field, args...); 434 | case FieldDescriptor::CPPTYPE_STRING: 435 | return static_cast(this)->template ForType( 436 | field, args...); 437 | case FieldDescriptor::CPPTYPE_MESSAGE: 438 | return static_cast(this) 439 | ->template ForType>(field, 440 | args...); 441 | } 442 | assert(false && "Unknown type"); 443 | abort(); 444 | } 445 | }; 446 | 447 | } // namespace protobuf_mutator 448 | 449 | #endif // SRC_FIELD_INSTANCE_H_ 450 | -------------------------------------------------------------------------------- /tools/src/mutator_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 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 "src/mutator.h" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "port/gtest.h" 25 | #include "src/binary_format.h" 26 | #include "src/mutator_test_proto2.pb.h" 27 | #include "src/mutator_test_proto3.pb.h" 28 | #include "src/text_format.h" 29 | 30 | namespace protobuf_mutator { 31 | 32 | using protobuf::util::MessageDifferencer; 33 | using testing::TestWithParam; 34 | using testing::ValuesIn; 35 | 36 | const char kMessages[] = R"( 37 | required_msg {} 38 | optional_msg {} 39 | repeated_msg {} 40 | repeated_msg {required_sint32: 56} 41 | repeated_msg {} 42 | repeated_msg { 43 | required_msg {} 44 | optional_msg {} 45 | repeated_msg {} 46 | repeated_msg { required_int32: 67 } 47 | repeated_msg {} 48 | } 49 | )"; 50 | 51 | const char kMessagesProto3[] = R"( 52 | optional_msg {} 53 | repeated_msg {} 54 | repeated_msg {optional_sint32: 56} 55 | repeated_msg {} 56 | repeated_msg { 57 | optional_msg {} 58 | repeated_msg {} 59 | repeated_msg { optional_int32: 67 } 60 | repeated_msg {} 61 | } 62 | )"; 63 | 64 | const char kRequiredFields[] = R"( 65 | required_double: 1.26685288449177e-313 66 | required_float: 5.9808638e-39 67 | required_int32: 67 68 | required_int64: 5285068 69 | required_uint32: 14486213 70 | required_uint64: 520229415 71 | required_sint32: 56 72 | required_sint64: -6057486163525532641 73 | required_fixed32: 8812173 74 | required_fixed64: 273731277756 75 | required_sfixed32: 43142 76 | required_sfixed64: 132 77 | required_bool: false 78 | required_string: "qwert" 79 | required_bytes: "asdf" 80 | )"; 81 | 82 | const char kOptionalFields[] = R"( 83 | optional_double: 1.93177850152856e-314 84 | optional_float: 4.7397519e-41 85 | optional_int32: 40020 86 | optional_int64: 10 87 | optional_uint32: 40 88 | optional_uint64: 159 89 | optional_sint32: 44015 90 | optional_sint64: 17493625000076 91 | optional_fixed32: 193 92 | optional_fixed64: 8542688694448488723 93 | optional_sfixed32: 4926 94 | optional_sfixed64: 60 95 | optional_bool: true 96 | optional_string: "QWERT" 97 | optional_bytes: "ASDF" 98 | optional_enum: ENUM_5 99 | )"; 100 | 101 | const char kRepeatedFields[] = R"( 102 | repeated_double: 1.93177850152856e-314 103 | repeated_double: 1.26685288449177e-313 104 | repeated_float: 4.7397519e-41 105 | repeated_float: 5.9808638e-39 106 | repeated_int32: 40020 107 | repeated_int32: 67 108 | repeated_int64: 10 109 | repeated_int64: 5285068 110 | repeated_uint32: 40 111 | repeated_uint32: 14486213 112 | repeated_uint64: 159 113 | repeated_uint64: 520229415 114 | repeated_sint32: 44015 115 | repeated_sint32: 56 116 | repeated_sint64: 17493625000076 117 | repeated_sint64: -6057486163525532641 118 | repeated_fixed32: 193 119 | repeated_fixed32: 8812173 120 | repeated_fixed64: 8542688694448488723 121 | repeated_fixed64: 273731277756 122 | repeated_sfixed32: 4926 123 | repeated_sfixed32: 43142 124 | repeated_sfixed64: 60 125 | repeated_sfixed64: 132 126 | repeated_bool: false 127 | repeated_bool: true 128 | repeated_string: "QWERT" 129 | repeated_string: "qwert" 130 | repeated_bytes: "ASDF" 131 | repeated_bytes: "asdf" 132 | repeated_enum: ENUM_5 133 | repeated_enum: ENUM_4 134 | )"; 135 | 136 | const char kRequiredNestedFields[] = R"( 137 | required_int32: 123 138 | optional_msg { 139 | required_double: 1.26685288449177e-313 140 | required_float: 5.9808638e-39 141 | required_int32: 67 142 | required_int64: 5285068 143 | required_uint32: 14486213 144 | required_uint64: 520229415 145 | required_sint32: 56 146 | required_sint64: -6057486163525532641 147 | required_fixed32: 8812173 148 | required_fixed64: 273731277756 149 | required_sfixed32: 43142 150 | required_sfixed64: 132 151 | required_bool: false 152 | required_string: "qwert" 153 | required_bytes: "asdf" 154 | } 155 | )"; 156 | 157 | const char kOptionalNestedFields[] = R"( 158 | optional_int32: 123 159 | optional_msg { 160 | optional_double: 1.93177850152856e-314 161 | optional_float: 4.7397519e-41 162 | optional_int32: 40020 163 | optional_int64: 10 164 | optional_uint32: 40 165 | optional_uint64: 159 166 | optional_sint32: 44015 167 | optional_sint64: 17493625000076 168 | optional_fixed32: 193 169 | optional_fixed64: 8542688694448488723 170 | optional_sfixed32: 4926 171 | optional_sfixed64: 60 172 | optional_bool: true 173 | optional_string: "QWERT" 174 | optional_bytes: "ASDF" 175 | optional_enum: ENUM_5 176 | } 177 | )"; 178 | 179 | const char kRepeatedNestedFields[] = R"( 180 | optional_int32: 123 181 | optional_msg { 182 | repeated_double: 1.93177850152856e-314 183 | repeated_double: 1.26685288449177e-313 184 | repeated_float: 4.7397519e-41 185 | repeated_float: 5.9808638e-39 186 | repeated_int32: 40020 187 | repeated_int32: 67 188 | repeated_int64: 10 189 | repeated_int64: 5285068 190 | repeated_uint32: 40 191 | repeated_uint32: 14486213 192 | repeated_uint64: 159 193 | repeated_uint64: 520229415 194 | repeated_sint32: 44015 195 | repeated_sint32: 56 196 | repeated_sint64: 17493625000076 197 | repeated_sint64: -6057486163525532641 198 | repeated_fixed32: 193 199 | repeated_fixed32: 8812173 200 | repeated_fixed64: 8542688694448488723 201 | repeated_fixed64: 273731277756 202 | repeated_sfixed32: 4926 203 | repeated_sfixed32: 43142 204 | repeated_sfixed64: 60 205 | repeated_sfixed64: 132 206 | repeated_bool: false 207 | repeated_bool: true 208 | repeated_string: "QWERT" 209 | repeated_string: "qwert" 210 | repeated_bytes: "ASDF" 211 | repeated_bytes: "asdf" 212 | repeated_enum: ENUM_5 213 | repeated_enum: ENUM_4 214 | } 215 | )"; 216 | 217 | class TestMutator : public Mutator { 218 | public: 219 | explicit TestMutator(bool keep_initialized, 220 | size_t random_to_default_ratio = 0) { 221 | Seed(17); 222 | if (random_to_default_ratio) 223 | random_to_default_ratio_ = random_to_default_ratio; 224 | keep_initialized_ = keep_initialized; 225 | } 226 | 227 | // Avoids dedup logic for some tests. 228 | void NoDeDupCrossOver(const protobuf::Message& message1, 229 | protobuf::Message* message2) { 230 | CrossOverImpl(message1, message2); 231 | } 232 | 233 | private: 234 | RandomEngine random_; 235 | }; 236 | 237 | class ReducedTestMutator : public TestMutator { 238 | public: 239 | ReducedTestMutator() : TestMutator(false, 4) { 240 | for (float i = 1000; i > 0.1; i /= 7) { 241 | values_.push_back(i); 242 | values_.push_back(-i); 243 | } 244 | values_.push_back(-1.0); 245 | values_.push_back(0.0); 246 | values_.push_back(1.0); 247 | } 248 | 249 | protected: 250 | int32_t MutateInt32(int32_t value) override { return GetRandomValue(); } 251 | int64_t MutateInt64(int64_t value) override { return GetRandomValue(); } 252 | uint32_t MutateUInt32(uint32_t value) override { 253 | return fabs(GetRandomValue()); 254 | } 255 | uint64_t MutateUInt64(uint64_t value) override { 256 | return fabs(GetRandomValue()); 257 | } 258 | float MutateFloat(float value) override { return GetRandomValue(); } 259 | double MutateDouble(double value) override { return GetRandomValue(); } 260 | std::string MutateString(const std::string& value, 261 | size_t size_increase_hint) override { 262 | return strings_[std::uniform_int_distribution<>( 263 | 0, strings_.size() - 1)(*random())]; 264 | } 265 | 266 | private: 267 | float GetRandomValue() { 268 | return values_[std::uniform_int_distribution<>( 269 | 0, values_.size() - 1)(*random())]; 270 | } 271 | 272 | std::vector values_; 273 | std::vector strings_ = { 274 | "", "\001", "\000", "a", "b", "ab", 275 | }; 276 | }; 277 | 278 | std::vector Split(const std::string& str) { 279 | std::istringstream iss(str); 280 | std::vector result; 281 | for (std::string line; std::getline(iss, line, '\n');) result.push_back(line); 282 | return result; 283 | } 284 | 285 | using TestParams = std::tuple; 286 | 287 | template 288 | std::vector GetFieldTestParams( 289 | const std::vector& tests) { 290 | std::vector results; 291 | for (auto t : tests) { 292 | auto lines = Split(t); 293 | for (size_t i = 0; i != lines.size(); ++i) { 294 | if (lines[i].find(':') != std::string::npos) 295 | results.push_back(std::make_tuple(&T::default_instance(), t, i)); 296 | } 297 | } 298 | return results; 299 | } 300 | 301 | template 302 | std::vector GetMessageTestParams( 303 | const std::vector& tests) { 304 | std::vector results; 305 | for (auto t : tests) { 306 | auto lines = Split(t); 307 | for (size_t i = 0; i != lines.size(); ++i) { 308 | if (lines[i].find("{}") != std::string::npos) 309 | results.push_back(std::make_tuple(&T::default_instance(), t, i)); 310 | } 311 | } 312 | return results; 313 | } 314 | 315 | bool Mutate(const protobuf::Message& from, const protobuf::Message& to) { 316 | EXPECT_FALSE(MessageDifferencer::Equals(from, to)); 317 | ReducedTestMutator mutator; 318 | std::unique_ptr message(from.New()); 319 | EXPECT_FALSE(MessageDifferencer::Equals(from, to)); 320 | for (int j = 0; j < 1000000; ++j) { 321 | message->CopyFrom(from); 322 | mutator.Mutate(message.get(), 1000); 323 | if (MessageDifferencer::Equals(*message, to)) return true; 324 | } 325 | 326 | ADD_FAILURE() << "Failed to get from:\n" 327 | << SaveMessageAsText(from) << "\nto:\n" 328 | << SaveMessageAsText(to); 329 | return false; 330 | } 331 | 332 | class MutatorTest : public TestWithParam { 333 | protected: 334 | void SetUp() override { 335 | m1_.reset(std::get<0>(GetParam())->New()); 336 | m2_.reset(std::get<0>(GetParam())->New()); 337 | text_ = std::get<1>(GetParam()); 338 | line_ = std::get<2>(GetParam()); 339 | } 340 | 341 | void LoadMessage(protobuf::Message* message) { 342 | EXPECT_TRUE(ParseTextMessage(text_, message)); 343 | } 344 | 345 | void LoadWithoutLine(protobuf::Message* message) { 346 | std::ostringstream oss; 347 | auto lines = Split(text_); 348 | for (size_t i = 0; i != lines.size(); ++i) { 349 | if (i != line_) oss << lines[i] << '\n'; 350 | } 351 | EXPECT_TRUE(ParseTextMessage(oss.str(), message)); 352 | } 353 | 354 | void LoadWithChangedLine(protobuf::Message* message, int value) { 355 | auto lines = Split(text_); 356 | std::ostringstream oss; 357 | for (size_t i = 0; i != lines.size(); ++i) { 358 | if (i != line_) { 359 | oss << lines[i] << '\n'; 360 | } else { 361 | std::string s = lines[i]; 362 | s.resize(s.find(':') + 2); 363 | 364 | if (lines[i].back() == '\"') { 365 | // strings 366 | s += value ? "\"\\" + std::to_string(value) + "\"" : "\"\""; 367 | } else if (lines[i].back() == 'e') { 368 | // bools 369 | s += value ? "true" : "false"; 370 | } else { 371 | s += std::to_string(value); 372 | } 373 | oss << s << '\n'; 374 | } 375 | } 376 | EXPECT_TRUE(ParseTextMessage(oss.str(), message)); 377 | } 378 | 379 | std::string text_; 380 | size_t line_; 381 | std::unique_ptr m1_; 382 | std::unique_ptr m2_; 383 | }; 384 | 385 | // These tests are irrelevant for Proto3 as it has no required fields and 386 | // insertion/deletion. 387 | 388 | class MutatorFieldInsDelTest : public MutatorTest {}; 389 | INSTANTIATE_TEST_SUITE_P(Proto2, MutatorFieldInsDelTest, 390 | ValuesIn(GetFieldTestParams( 391 | {kRequiredFields, kOptionalFields, kRepeatedFields, 392 | kRequiredNestedFields, kOptionalNestedFields, 393 | kRepeatedNestedFields}))); 394 | 395 | TEST_P(MutatorFieldInsDelTest, DeleteField) { 396 | LoadMessage(m1_.get()); 397 | LoadWithoutLine(m2_.get()); 398 | EXPECT_TRUE(Mutate(*m1_, *m2_)); 399 | } 400 | 401 | TEST_P(MutatorFieldInsDelTest, InsertField) { 402 | LoadWithoutLine(m1_.get()); 403 | LoadWithChangedLine(m2_.get(), 0); 404 | EXPECT_TRUE(Mutate(*m1_, *m2_)); 405 | } 406 | 407 | class MutatorFieldTest : public MutatorTest { 408 | public: 409 | template 410 | void TestCopyField(); 411 | }; 412 | INSTANTIATE_TEST_SUITE_P(Proto2, MutatorFieldTest, 413 | ValuesIn(GetFieldTestParams( 414 | {kRequiredFields, kOptionalFields, kRepeatedFields, 415 | kRequiredNestedFields, kOptionalNestedFields, 416 | kRepeatedNestedFields}))); 417 | INSTANTIATE_TEST_SUITE_P(Proto3, MutatorFieldTest, 418 | ValuesIn(GetFieldTestParams( 419 | {kOptionalFields, kRepeatedFields, 420 | kOptionalNestedFields, kRepeatedNestedFields}))); 421 | 422 | TEST_P(MutatorFieldTest, Initialized) { 423 | LoadWithoutLine(m1_.get()); 424 | TestMutator mutator(true); 425 | mutator.Mutate(m1_.get(), 1000); 426 | EXPECT_TRUE(m1_->IsInitialized()); 427 | } 428 | 429 | TEST_P(MutatorFieldTest, ChangeField) { 430 | LoadWithChangedLine(m1_.get(), 0); 431 | LoadWithChangedLine(m2_.get(), 1); 432 | EXPECT_TRUE(Mutate(*m1_, *m2_)); 433 | EXPECT_TRUE(Mutate(*m2_, *m1_)); 434 | } 435 | 436 | template 437 | void MutatorFieldTest::TestCopyField() { 438 | LoadWithChangedLine(m1_.get(), 7); 439 | LoadWithChangedLine(m2_.get(), 0); 440 | 441 | Msg from; 442 | from.add_repeated_msg()->CopyFrom(*m1_); 443 | from.add_repeated_msg()->CopyFrom(*m2_); 444 | 445 | Msg to; 446 | to.add_repeated_msg()->CopyFrom(*m1_); 447 | to.add_repeated_msg()->CopyFrom(*m1_); 448 | EXPECT_TRUE(Mutate(from, to)); 449 | 450 | to.Clear(); 451 | to.add_repeated_msg()->CopyFrom(*m2_); 452 | to.add_repeated_msg()->CopyFrom(*m2_); 453 | EXPECT_TRUE(Mutate(from, to)); 454 | } 455 | 456 | TEST_P(MutatorFieldTest, CopyField) { 457 | if (m1_->GetDescriptor() == Msg::descriptor()) 458 | TestCopyField(); 459 | else 460 | TestCopyField(); 461 | } 462 | 463 | class MutatorSingleFieldTest : public MutatorTest {}; 464 | INSTANTIATE_TEST_SUITE_P(Proto2, MutatorSingleFieldTest, 465 | ValuesIn(GetFieldTestParams({ 466 | kRequiredFields, 467 | kOptionalFields, 468 | kRequiredNestedFields, 469 | kOptionalNestedFields, 470 | }))); 471 | INSTANTIATE_TEST_SUITE_P(Proto3, MutatorSingleFieldTest, 472 | ValuesIn(GetFieldTestParams({ 473 | kOptionalFields, 474 | kOptionalNestedFields, 475 | }))); 476 | 477 | TEST_P(MutatorSingleFieldTest, CrossOver) { 478 | LoadWithoutLine(m1_.get()); 479 | LoadMessage(m2_.get()); 480 | 481 | EXPECT_FALSE(MessageDifferencer::Equals(*m1_, *m2_)); 482 | TestMutator mutator(false); 483 | 484 | int match_m1_ = 0; 485 | int match_m2_ = 0; 486 | int iterations = 1000; 487 | std::unique_ptr message(m1_->New()); 488 | for (int j = 0; j < iterations; ++j) { 489 | message->CopyFrom(*m1_); 490 | mutator.NoDeDupCrossOver(*m2_, message.get()); 491 | if (MessageDifferencer::Equals(*message, *m2_)) ++match_m2_; 492 | if (MessageDifferencer::Equals(*message, *m1_)) ++match_m1_; 493 | } 494 | 495 | EXPECT_LT(iterations * .4, match_m1_); 496 | EXPECT_GE(iterations * .6, match_m1_); 497 | EXPECT_LT(iterations * .4, match_m2_); 498 | EXPECT_GE(iterations * .6, match_m2_); 499 | } 500 | 501 | template 502 | class MutatorTypedTest : public ::testing::Test { 503 | public: 504 | using Message = T; 505 | }; 506 | 507 | using MutatorTypedTestTypes = testing::Types; 508 | TYPED_TEST_SUITE(MutatorTypedTest, MutatorTypedTestTypes); 509 | 510 | TYPED_TEST(MutatorTypedTest, CrossOverRepeated) { 511 | typename TestFixture::Message m1; 512 | m1.add_repeated_int32(1); 513 | m1.add_repeated_int32(2); 514 | m1.add_repeated_int32(3); 515 | 516 | typename TestFixture::Message m2; 517 | m2.add_repeated_int32(4); 518 | m2.add_repeated_int32(5); 519 | m2.add_repeated_int32(6); 520 | 521 | int iterations = 10000; 522 | std::set> sets; 523 | TestMutator mutator(false); 524 | for (int j = 0; j < iterations; ++j) { 525 | typename TestFixture::Message message; 526 | message.CopyFrom(m1); 527 | mutator.NoDeDupCrossOver(m2, &message); 528 | sets.insert( 529 | {message.repeated_int32().begin(), message.repeated_int32().end()}); 530 | } 531 | 532 | EXPECT_EQ(1u << 6, sets.size()); 533 | } 534 | 535 | TYPED_TEST(MutatorTypedTest, CrossOverRepeatedMessages) { 536 | typename TestFixture::Message m1; 537 | auto* rm1 = m1.add_repeated_msg(); 538 | rm1->add_repeated_int32(1); 539 | rm1->add_repeated_int32(2); 540 | 541 | typename TestFixture::Message m2; 542 | auto* rm2 = m2.add_repeated_msg(); 543 | rm2->add_repeated_int32(3); 544 | rm2->add_repeated_int32(4); 545 | rm2->add_repeated_int32(5); 546 | rm2->add_repeated_int32(6); 547 | 548 | int iterations = 10000; 549 | std::set> sets; 550 | TestMutator mutator(false); 551 | for (int j = 0; j < iterations; ++j) { 552 | typename TestFixture::Message message; 553 | message.CopyFrom(m1); 554 | mutator.NoDeDupCrossOver(m2, &message); 555 | for (const auto& msg : message.repeated_msg()) 556 | sets.insert({msg.repeated_int32().begin(), msg.repeated_int32().end()}); 557 | } 558 | 559 | EXPECT_EQ(1u << 6, sets.size()); 560 | } 561 | 562 | TYPED_TEST(MutatorTypedTest, FailedMutations) { 563 | TestMutator mutator(false); 564 | size_t crossovers = 0; 565 | for (int i = 0; i < 1000; ++i) { 566 | typename TestFixture::Message messages[2]; 567 | typename TestFixture::Message tmp; 568 | for (int j = 0; j < 20; ++j) { 569 | for (auto& m : messages) { 570 | tmp.CopyFrom(m); 571 | mutator.Mutate(&m, 1000); 572 | // Mutate must not produce the same result. 573 | EXPECT_FALSE(MessageDifferencer::Equals(m, tmp)); 574 | } 575 | } 576 | 577 | tmp.CopyFrom(messages[1]); 578 | mutator.CrossOver(messages[0], &tmp); 579 | if (MessageDifferencer::Equals(tmp, messages[1]) || 580 | MessageDifferencer::Equals(tmp, messages[0])) 581 | ++crossovers; 582 | } 583 | 584 | // CrossOver may fail but very rare. 585 | EXPECT_LT(crossovers, 10u); 586 | } 587 | 588 | TYPED_TEST(MutatorTypedTest, RegisterPostProcessor) { 589 | std::set top_mutations = {"0123456789abcdef", 590 | "abcdef0123456789"}; 591 | TestMutator mutator(false); 592 | for (auto& v : top_mutations) { 593 | mutator.RegisterPostProcessor( 594 | TestFixture::Message::descriptor(), 595 | [=](protobuf::Message* message, unsigned int seed) { 596 | auto test_message = 597 | static_cast(message); 598 | if (seed % 2) test_message->set_optional_string(v); 599 | }); 600 | } 601 | 602 | std::set nested_mutations = {1234567, 567890}; 603 | for (auto& v : nested_mutations) { 604 | mutator.RegisterPostProcessor( 605 | TestFixture::Message::SubMsg::descriptor(), 606 | [=](protobuf::Message* message, unsigned int seed) { 607 | auto test_message = 608 | static_cast(message); 609 | if (seed % 2) test_message->set_optional_int64(v); 610 | }); 611 | } 612 | 613 | bool regular_mutation = false; 614 | 615 | for (int j = 0; j < 100000; ++j) { 616 | // Include this field to increase the probability of mutation. 617 | typename TestFixture::Message message; 618 | message.set_optional_string("a"); 619 | mutator.Mutate(&message, 1000); 620 | 621 | top_mutations.erase(message.optional_string()); 622 | nested_mutations.erase(message.mutable_sub_message()->optional_int64()); 623 | if (message.optional_string().empty()) regular_mutation = true; 624 | 625 | if (top_mutations.empty() && nested_mutations.empty() && regular_mutation) 626 | break; 627 | } 628 | 629 | EXPECT_TRUE(top_mutations.empty()); 630 | EXPECT_TRUE(nested_mutations.empty()); 631 | EXPECT_TRUE(regular_mutation); 632 | } 633 | 634 | TYPED_TEST(MutatorTypedTest, Serialization) { 635 | TestMutator mutator(false); 636 | for (int i = 0; i < 10000; ++i) { 637 | typename TestFixture::Message message; 638 | for (int j = 0; j < 5; ++j) { 639 | mutator.Mutate(&message, 1000); 640 | typename TestFixture::Message parsed; 641 | 642 | EXPECT_TRUE(ParseTextMessage(SaveMessageAsText(message), &parsed)); 643 | EXPECT_TRUE(MessageDifferencer::Equals(parsed, message)); 644 | 645 | EXPECT_TRUE(ParseBinaryMessage(SaveMessageAsBinary(message), &parsed)); 646 | EXPECT_TRUE(MessageDifferencer::Equals(parsed, message)); 647 | } 648 | } 649 | } 650 | 651 | TYPED_TEST(MutatorTypedTest, DeepRecursion) { 652 | typename TestFixture::Message message; 653 | typename TestFixture::Message* last = &message; 654 | for (int i = 0; i < 150; ++i) { 655 | last = last->mutable_optional_msg(); 656 | std::string text = SaveMessageAsText(message); 657 | std::string binary = SaveMessageAsBinary(message); 658 | typename TestFixture::Message parsed; 659 | EXPECT_EQ(i < 100, ParseTextMessage(SaveMessageAsText(message), &parsed)); 660 | EXPECT_EQ(i < 100, 661 | ParseBinaryMessage(SaveMessageAsBinary(message), &parsed)); 662 | } 663 | } 664 | 665 | TYPED_TEST(MutatorTypedTest, EmptyMessage) { 666 | typename TestFixture::Message::EmptyMessage message; 667 | TestMutator mutator(false); 668 | for (int j = 0; j < 10000; ++j) mutator.Mutate(&message, 1000); 669 | } 670 | 671 | TYPED_TEST(MutatorTypedTest, Regressions) { 672 | typename TestFixture::Message::RegressionMessage message; 673 | TestMutator mutator(false); 674 | for (int j = 0; j < 10000; ++j) mutator.Mutate(&message, 1000); 675 | } 676 | 677 | TYPED_TEST(MutatorTypedTest, UsageExample) { 678 | typename TestFixture::Message::SmallMessage message; 679 | TestMutator mutator(false); 680 | 681 | // Test that we can generate all variation of the message. 682 | std::set mutations; 683 | for (int j = 0; j < 1000; ++j) { 684 | mutator.Mutate(&message, 1000); 685 | std::string str = SaveMessageAsText(message); 686 | mutations.insert(str); 687 | } 688 | 689 | if (std::is_same::value) { 690 | // 3 states for boolean and 5 for enum, including missing fields. 691 | EXPECT_EQ(3u * 5u, mutations.size()); 692 | } else { 693 | // 2 states for boolean and 4 for enum. 694 | EXPECT_EQ(2u * 4u, mutations.size()); 695 | } 696 | } 697 | 698 | TYPED_TEST(MutatorTypedTest, Maps) { 699 | TestMutator mutator(true); 700 | 701 | typename TestFixture::Message::MapMessage message; 702 | for (int j = 0; j < 10000; ++j) mutator.Mutate(&message, 1000); 703 | } 704 | 705 | class MutatorMessagesTest : public MutatorTest {}; 706 | INSTANTIATE_TEST_SUITE_P(Proto2, MutatorMessagesTest, 707 | ValuesIn(GetMessageTestParams({kMessages}))); 708 | INSTANTIATE_TEST_SUITE_P( 709 | Proto3, MutatorMessagesTest, 710 | ValuesIn(GetMessageTestParams({kMessagesProto3}))); 711 | 712 | TEST_P(MutatorMessagesTest, DeletedMessage) { 713 | LoadMessage(m1_.get()); 714 | LoadWithoutLine(m2_.get()); 715 | EXPECT_TRUE(Mutate(*m1_, *m2_)); 716 | } 717 | 718 | TEST_P(MutatorMessagesTest, InsertMessage) { 719 | LoadWithoutLine(m1_.get()); 720 | LoadMessage(m2_.get()); 721 | EXPECT_TRUE(Mutate(*m1_, *m2_)); 722 | } 723 | 724 | // TODO(vitalybuka): Special tests for oneof. 725 | 726 | TEST(MutatorMessagesTest, NeverCopyUnknownEnum) { 727 | TestMutator mutator(false); 728 | for (int j = 0; j < 10000; ++j) { 729 | Msg3 message; 730 | message.set_optional_enum(Msg3::ENUM_5); 731 | message.add_repeated_enum(static_cast(100)); 732 | mutator.Mutate(&message, 100); 733 | EXPECT_NE(message.optional_enum(), 100); 734 | } 735 | } 736 | 737 | } // namespace protobuf_mutator 738 | -------------------------------------------------------------------------------- /tools/harness.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "harness.h" 6 | #include "NfcAdaptation.h" 7 | #include "nfc_int.h" 8 | #include "nfa_sys.h" 9 | #include "nfc_api.h" 10 | #include "rw_api.h" 11 | #include "nfa_api.h" 12 | #include "nfa_rw_int.h" 13 | #include "nfc_config.h" 14 | #include "gki_int.h" 15 | #include "nfc_target.h" 16 | 17 | extern void nfa_rw_handle_i93_evt(tRW_EVENT event, tRW_DATA* p_rw_data); 18 | extern void nfa_rw_handle_t4t_evt(tRW_EVENT event, tRW_DATA* p_rw_data); 19 | extern void nfa_rw_handle_t3t_evt(tRW_EVENT event, tRW_DATA* p_rw_data); 20 | extern void nfa_rw_handle_t2t_evt(tRW_EVENT event, tRW_DATA* p_rw_data); 21 | extern void nfa_rw_handle_t1t_evt(tRW_EVENT event, tRW_DATA* p_rw_data); 22 | extern tNFC_STATUS nfa_rw_start_ndef_detection(void); 23 | extern void GKI_shutdown(); 24 | extern void gki_buffer_init(); 25 | extern void gki_timers_init(); 26 | extern void NFC_Init_RW(tHAL_NFC_ENTRY* p_hal_entry_tbl); 27 | extern void gki_buffers_cleanup(void); 28 | extern void gki_reset(); 29 | extern void allocate_all_pools(); 30 | 31 | static NfcAdaptation* adaptation; 32 | 33 | #define T5T_PROTOCOL 0x06 //Need to fix it for some reason. 34 | 35 | void initialize_rf_conn() { 36 | tNFC_CONN_CB* p_cb = &nfc_cb.conn_cb[NFC_RF_CONN_ID]; 37 | p_cb->init_credits = p_cb->num_buff = 0; 38 | nfc_set_conn_id(p_cb, NFC_RF_CONN_ID); 39 | } 40 | /* 41 | uint32_t append_meta_data_i93(bool use_uid, int64_t uid, const nfc::NfcNci& nfc_nci, NFC_HDR* p_msg) { 42 | //offset at 3 byte. First 3 bytes belongs to header. 43 | uint32_t offset = 3; 44 | uint32_t meta = 0; 45 | uint8_t* meta_ptr = NULL; 46 | int64_t this_uid = 0; 47 | int32_t cc = 0; 48 | switch(nfc_nci.sequence().sequence_case()) { 49 | case nfc::Sequence::kWaitUid: 50 | meta = nfc_nci.sequence().wait_uid().meta(); 51 | meta_ptr = (uint8_t*)(&meta); 52 | this_uid = use_uid ? uid : nfc_nci.sequence().wait_uid().uid(); 53 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + offset, meta_ptr[0] & (meta_ptr[0] - 1), 1); //clear the lowest bit in the flag. 54 | offset++; 55 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + offset, 0, 1); //set dsfid to zero. 56 | offset++; 57 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + offset, (uint8_t*)(&this_uid), sizeof(int64_t)); //set uid. 58 | offset += sizeof(int64_t); 59 | break; 60 | case nfc::Sequence::kSysInfo: 61 | meta = nfc_nci.sequence().sys_info().meta(); 62 | meta_ptr = (uint8_t*)(&meta); 63 | this_uid = use_uid ? uid : nfc_nci.sequence().sys_info().uid(); 64 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + offset, meta_ptr[0] & (meta_ptr[0] - 1), 1); //clear the lowest bit in the flag. 65 | offset++; 66 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + offset, meta_ptr[1], 1); //set info_flag. 67 | offset++; 68 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + offset, (uint8_t*)(&this_uid), sizeof(int64_t)); //set uid. 69 | offset += sizeof(int64_t); 70 | break; 71 | case nfc::Sequence::kWaitCc: 72 | meta = nfc_nci.sequence().wait_cc().meta(); 73 | meta_ptr = (uint8_t*)(&meta); 74 | cc = nfc_nci.sequence().wait_cc().cc(); 75 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + offset, meta_ptr[0] & (meta_ptr[0] - 1), 1); //clear the lowest bit in the flag. 76 | offset++; 77 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + offset, (uint8_t*)(&cc), sizeof(int32_t)); //set cc. 78 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + offset, nfc_nci.sequence().wait_cc().e2() ? 0xE2 : 0xE1, 1); //set cc[0] to magic value 0xE1 or 0xE2 79 | offset += sizeof(int32_t); 80 | break; 81 | default: 82 | break; 83 | } 84 | return offset; 85 | } 86 | 87 | void modify_meta_data_t4t(const nfc::NfcNci& nfc_nci, NFC_HDR* p_msg) { 88 | if (p_msg->len < T4T_RSP_STATUS_WORDS_SIZE + 3) return; 89 | //modify status words 90 | uint16_t status_word = nfc_nci.status_word(); 91 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + (p_msg->len - T4T_RSP_STATUS_WORDS_SIZE), (uint8_t*)(&status_word), 2); 92 | } 93 | */ 94 | uint16_t cap_data_len(size_t data_len) { 95 | if (data_len < 3) return data_len; 96 | if (data_len - NCI_MSG_HDR_SIZE > 255) return 255 + NCI_MSG_HDR_SIZE; //Some hack to prevent buffer too large. Looks like message length cannot be longer than max of 8bit. 97 | return data_len; 98 | } 99 | 100 | NFC_HDR* create_data_msg_meta(uint16_t data_len, const char* p_data) { 101 | NFC_HDR* p_msg; 102 | /* ignore all data while shutting down NFCC */ 103 | if (nfc_cb.nfc_state == NFC_STATE_W4_HAL_CLOSE) { 104 | return NULL; 105 | } 106 | 107 | if (data_len < 3) return NULL; 108 | p_msg = (NFC_HDR*)GKI_getpoolbuf(NFC_NCI_POOL_ID); 109 | if (p_msg != NULL) { 110 | /* Initialize NFC_HDR */ 111 | p_msg->event = BT_EVT_TO_NFC_NCI; 112 | p_msg->offset = NFC_RECEIVE_MSGS_OFFSET; 113 | //First write the 3 byte header 114 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset, p_data, 3); 115 | memset((uint8_t*)(p_msg + 1) + p_msg->offset, p_data[0] & NCI_PBF_MASK, 1); //set everything other than pbf to zero (mt -> data event and cid -> NFC_RF_CONN_ID). 116 | return p_msg; 117 | } 118 | return NULL; 119 | } 120 | 121 | void create_t5t_wait_uid(nfc::T5TMboxEvt& evt, NFC_HDR** p_msgs, const nfc::WaitUidSysInfo* wait_uid_sys_info) { 122 | uint32_t offset = 3; 123 | size_t data_len = cap_data_len(evt.wait_uid().data().length()); 124 | NFC_HDR* p_msg = create_data_msg_meta(data_len, evt.wait_uid().data().c_str()); 125 | if (p_msg == NULL) return; 126 | int32_t meta = evt.wait_uid().meta(); 127 | uint8_t* meta_ptr = (uint8_t*)(&meta); 128 | int64_t this_uid = wait_uid_sys_info ? wait_uid_sys_info->uid() : evt.wait_uid().uid(); 129 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + offset, meta_ptr[0] & (meta_ptr[0] - 1), 1); //clear the lowest bit in the flag. 130 | offset++; 131 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + offset, 0, 1); //set dsfid to zero. 132 | offset++; 133 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + offset, (uint8_t*)(&this_uid), sizeof(int64_t)); //set uid. 134 | //set the first 3 bytes in uid 135 | nfc::T5TUid0 uid_0 = wait_uid_sys_info ? wait_uid_sys_info->uid_0() : evt.wait_uid().uid_0(); 136 | if (uid_0 != nfc::UID_0_DEFAULT) 137 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + offset, (uint8_t)uid_0, 1); 138 | nfc::T5TUid1 uid_1 = wait_uid_sys_info ? wait_uid_sys_info->uid_1() : evt.wait_uid().uid_1(); 139 | if (uid_1 != nfc::UID_1_DEFAULT) 140 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + offset + 1, (uint8_t)uid_1, 1); 141 | nfc::T5TUid2 uid_2 = wait_uid_sys_info ? wait_uid_sys_info->uid_2() : evt.wait_uid().uid_2(); 142 | if (uid_2 != nfc::UID_2_DEFAULT) 143 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + offset + 2, uid_2, 1); 144 | offset += sizeof(int64_t); 145 | p_msg->len = (uint16_t)(data_len + offset - 3); 146 | //truncate 147 | if (evt.wait_uid().truncate_prob() != 0) { 148 | p_msg->len = 3 + evt.wait_uid().truncate_wait_uid(); 149 | p_msgs[0] = p_msg; 150 | return; 151 | } 152 | //copy the rest of the data 153 | if (data_len > 3) 154 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + offset, evt.wait_uid().data().c_str() + 3, data_len - 3); 155 | p_msgs[0] = p_msg; 156 | } 157 | 158 | void create_t5t_sys_info(nfc::T5TMboxEvt& evt, NFC_HDR** p_msgs, const nfc::WaitUidSysInfo* wait_uid_sys_info) { 159 | uint32_t offset = 3; 160 | size_t data_len = cap_data_len(evt.sys_info().data().length()); 161 | NFC_HDR* p_msg = create_data_msg_meta(data_len, evt.sys_info().data().c_str()); 162 | if (p_msg == NULL) return; 163 | int32_t meta = evt.sys_info().meta(); 164 | uint8_t* meta_ptr = (uint8_t*)(&meta); 165 | int64_t this_uid = wait_uid_sys_info ? wait_uid_sys_info->uid() : evt.sys_info().uid(); 166 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + offset, meta_ptr[0] & (meta_ptr[0] - 1), 1); //clear the lowest bit in the flag. 167 | offset++; 168 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + offset, meta_ptr[1], 1); //set info_flag. 169 | offset++; 170 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + offset, (uint8_t*)(&this_uid), sizeof(int64_t)); //set uid. 171 | //set the first 3 bytes in uid 172 | nfc::T5TUid0 uid_0 = wait_uid_sys_info ? wait_uid_sys_info->uid_0() : evt.sys_info().uid_0(); 173 | if (uid_0 != nfc::UID_0_DEFAULT) 174 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + offset, (uint8_t)uid_0, 1); 175 | nfc::T5TUid1 uid_1 = wait_uid_sys_info ? wait_uid_sys_info->uid_1() : evt.sys_info().uid_1(); 176 | if (uid_1 != nfc::UID_1_DEFAULT) 177 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + offset + 1, (uint8_t)uid_1, 1); 178 | nfc::T5TUid2 uid_2 = wait_uid_sys_info ? wait_uid_sys_info->uid_2() : evt.sys_info().uid_2(); 179 | if (uid_2 != nfc::UID_2_DEFAULT) 180 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + offset + 2, (uint8_t)uid_2, 1); 181 | offset += sizeof(int64_t); 182 | p_msg->len = (uint16_t)(data_len + offset - 3); 183 | //truncate 184 | if (evt.sys_info().truncate_prob() != 0) { 185 | p_msg->len = 3 + evt.sys_info().truncate_sys_info(); 186 | p_msgs[0] = p_msg; 187 | return; 188 | } 189 | //copy the rest of the data 190 | if (data_len > 3) 191 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + offset, evt.sys_info().data().c_str() + 3, data_len - 3); 192 | //set ic_reference 193 | uint16_t ic_reference_offset = 0; 194 | if (meta_ptr[1] & I93_INFO_FLAG_DSFID) ic_reference_offset++; 195 | if (meta_ptr[1] & I93_INFO_FLAG_AFI) ic_reference_offset++; 196 | if (meta_ptr[1] & I93_INFO_FLAG_MEM_SIZE) ic_reference_offset += 2; 197 | if ( (meta_ptr[1] & I93_INFO_FLAG_IC_REF) && (evt.sys_info().ic_reference() != nfc::ICReference_DEFAULT)) { 198 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + offset + ic_reference_offset, (uint8_t)(evt.sys_info().ic_reference()), 1); 199 | } 200 | p_msgs[0] = p_msg; 201 | return; 202 | } 203 | 204 | void create_t5t_wait_cc(nfc::T5TMboxEvt& evt, NFC_HDR** p_msgs) { 205 | uint32_t offset = 3; 206 | size_t data_len = cap_data_len(evt.wait_cc().data().length()); 207 | NFC_HDR* p_msg = create_data_msg_meta(data_len, evt.sys_info().data().c_str()); 208 | if (p_msg == NULL) return; 209 | int32_t meta = evt.wait_cc().meta(); 210 | uint8_t* meta_ptr = (uint8_t*)(&meta); 211 | int32_t cc = evt.wait_cc().cc(); 212 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + offset, meta_ptr[0] & (meta_ptr[0] - 1), 1); //clear the lowest bit in the flag. 213 | offset++; 214 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + offset, (uint8_t*)(&cc), sizeof(int32_t)); //set cc. 215 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + offset, evt.wait_cc().e2() ? 0xE2 : 0xE1, 1); //set cc[0] to magic value 0xE1 or 0xE2 216 | if (evt.wait_cc().multi_block()) 217 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + offset + 1, (uint8_t)I93_ICODE_CC_MBREAD_MASK, 1); //set cc[3] to multi_block 218 | offset += sizeof(int32_t); 219 | p_msg->len = (uint16_t)(data_len + offset - 3); 220 | //truncate 221 | if (evt.wait_cc().truncate_prob() != 0) { 222 | p_msg->len = 3 + evt.wait_cc().truncate_wait_cc(); 223 | p_msgs[0] = p_msg; 224 | return; 225 | } 226 | 227 | //copy the rest of the data 228 | if (data_len > 3) 229 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + offset, evt.wait_cc().data().c_str() + 3, data_len - 3); 230 | p_msgs[0] = p_msg; 231 | return; 232 | } 233 | 234 | void create_t5t_wait_uid_sys_info(nfc::T5TMboxEvt& evt, NFC_HDR** p_msgs) { 235 | create_t5t_wait_uid(evt, p_msgs, &(evt.wait_uid_sys_info())); 236 | create_t5t_sys_info(evt, p_msgs + 1, &(evt.wait_uid_sys_info())); 237 | return; 238 | } 239 | 240 | void create_t5t_default_message(nfc::T5TMboxEvt& evt, NFC_HDR** p_msgs) { 241 | size_t data_len = cap_data_len(evt.df().data().length()); 242 | NFC_HDR* p_msg = create_data_msg_meta(data_len, evt.df().data().c_str()); 243 | if (p_msg == NULL) return; 244 | p_msg->len = (uint16_t)(data_len); 245 | //copy the rest of the data 246 | if (data_len > 3) 247 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + 3, evt.df().data().c_str() + 3, data_len - 3); 248 | p_msgs[0] = p_msg; 249 | return; 250 | } 251 | 252 | void create_data_msg_t5t(nfc::T5TMboxEvt& evt, NFC_HDR** p_msgs) { 253 | switch (evt.evt_case()) { 254 | case nfc::T5TMboxEvt::kWaitUid: 255 | create_t5t_wait_uid(evt, p_msgs, NULL); 256 | break; 257 | case nfc::T5TMboxEvt::kSysInfo: 258 | create_t5t_sys_info(evt, p_msgs, NULL); 259 | break; 260 | case nfc::T5TMboxEvt::kWaitCc: 261 | create_t5t_wait_cc(evt, p_msgs); 262 | break; 263 | case nfc::T5TMboxEvt::kWaitUidSysInfo: 264 | create_t5t_wait_uid_sys_info(evt, p_msgs); 265 | break; 266 | case nfc::T5TMboxEvt::kDf: 267 | create_t5t_default_message(evt, p_msgs); 268 | break; 269 | default: 270 | return; 271 | } 272 | } 273 | 274 | NFC_HDR* create_t4t_default_message(nfc::T4TMboxEvt& evt) { 275 | size_t data_len = cap_data_len(evt.df().data().length()); 276 | NFC_HDR* p_msg = create_data_msg_meta(data_len, evt.df().data().c_str()); 277 | if (!p_msg) return NULL; 278 | p_msg->len = data_len; 279 | if (data_len > 3) 280 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + 3, evt.df().data().c_str() + 3, data_len - 3); 281 | if (p_msg->len < T4T_RSP_STATUS_WORDS_SIZE + 3) { 282 | GKI_freebuf(p_msg); 283 | return NULL; 284 | } 285 | //modify status words 286 | uint16_t status_word = evt.df().status_word(); 287 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + (p_msg->len - T4T_RSP_STATUS_WORDS_SIZE), (uint8_t*)(&status_word), 2); 288 | return p_msg; 289 | } 290 | 291 | void set_message_len(NFC_HDR* p_msg) { 292 | //Cap message len at 255 293 | if (p_msg->len > 258) { 294 | p_msg->len = 258; 295 | } 296 | uint8_t len = (uint8_t)(p_msg->len - NCI_MSG_HDR_SIZE); 297 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + 2, len, 1); //set len to match message length. 298 | } 299 | 300 | NFC_HDR* create_data_msg_t4t(nfc::T4TMboxEvt& evt) { 301 | switch (evt.evt_case()) { 302 | case nfc::T4TMboxEvt::kDf: 303 | return create_t4t_default_message(evt); 304 | break; 305 | default: 306 | return NULL; 307 | } 308 | } 309 | 310 | /* 311 | NFC_HDR* create_data_msg(const nfc::NfcNci& nfc_nci, const nfc::MboxEvt& evt, uint8_t protocol) { 312 | NFC_HDR* p_msg; 313 | 314 | if (nfc_cb.nfc_state == NFC_STATE_W4_HAL_CLOSE) { 315 | return NULL; 316 | } 317 | bool use_uid = evt.use_uid(); 318 | int64_t uid = evt.uid(); 319 | size_t data_len = nfc_nci.data().length(); 320 | const char* p_data = nfc_nci.data().c_str(); 321 | bool use_sequence = nfc_nci.use_sequence(); 322 | 323 | //Need at least the length of the header. 324 | if (data_len < 3) return NULL; 325 | if (data_len - NCI_MSG_HDR_SIZE > 230) data_len = 230 + NCI_MSG_HDR_SIZE; //Some hack to prevent buffer too large. Looks like message length cannot be longer than max of 8bit. 326 | p_msg = (NFC_HDR*)GKI_getpoolbuf(NFC_NCI_POOL_ID); 327 | if (p_msg != NULL) { 328 | p_msg->event = BT_EVT_TO_NFC_NCI; 329 | p_msg->offset = NFC_RECEIVE_MSGS_OFFSET; 330 | //First write the 3 byte header 331 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset, p_data, 3); 332 | memset((uint8_t*)(p_msg + 1) + p_msg->offset, p_data[0] & NCI_PBF_MASK, 1); //set everything other than pbf to zero (mt -> data event and cid -> NFC_RF_CONN_ID). 333 | if (protocol == NFC_PROTOCOL_T5T) { 334 | //Add sequence meta data, if use. 335 | uint32_t offset = use_sequence ? append_meta_data_i93(use_uid, uid, nfc_nci, p_msg) : 3; 336 | p_msg->len = (uint16_t)(data_len + offset - 3); 337 | //Writes the rest of the data. 338 | if (data_len > 3) { 339 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + offset, p_data + 3, data_len - 3); 340 | if (!use_sequence) 341 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + 3, p_data[3] & (p_data[3] - 1), 1); //clear the lowest bit in the flag. 342 | } 343 | } else if(NFC_PROTOCOL_ISO_DEP == protocol) { 344 | p_msg->len = (uint16_t)data_len; 345 | //copy rest of data 346 | if (data_len > 3) 347 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + 3, p_data + 3, data_len - 3); 348 | //Add status word. 349 | modify_meta_data_t4t(nfc_nci, p_msg); 350 | } else { 351 | //copy rest of sequence. 352 | if (data_len > 3) 353 | memcpy((uint8_t*)(p_msg + 1) + p_msg->offset + 3, p_data + 3, data_len - 3); 354 | } 355 | uint8_t len = (uint8_t)(p_msg->len - NCI_MSG_HDR_SIZE); 356 | memset((uint8_t*)(p_msg + 1) + p_msg->offset + 2, len, 1); //set len to match message length. 357 | 358 | return p_msg; 359 | } else { 360 | return NULL; 361 | } 362 | return NULL; 363 | } 364 | */ 365 | tNFC_HAL_EVT_MSG* create_hal_evt(uint8_t hal_evt, tHAL_NFC_STATUS status) { 366 | tNFC_HAL_EVT_MSG* p_msg; 367 | 368 | p_msg = (tNFC_HAL_EVT_MSG*)GKI_getbuf(sizeof(tNFC_HAL_EVT_MSG)); 369 | if (p_msg != NULL) { 370 | /* Initialize NFC_HDR */ 371 | p_msg->hdr.len = 0; 372 | p_msg->hdr.event = BT_EVT_TO_NFC_MSGS; 373 | p_msg->hdr.offset = 0; 374 | p_msg->hdr.layer_specific = 0; 375 | p_msg->hal_evt = hal_evt; 376 | p_msg->status = status; 377 | return p_msg; 378 | } else { 379 | return NULL; 380 | } 381 | return NULL; 382 | } 383 | 384 | void handleT5TRead(const nfc::T5TRead& t5t_read) { 385 | bool free_buf; 386 | for (nfc::T5TMboxEvt evt : t5t_read.evt()) { 387 | free_buf = true; 388 | NFC_HDR* p_msgs[2]; 389 | p_msgs[0] = NULL; 390 | p_msgs[1] = NULL; 391 | create_data_msg_t5t(evt, p_msgs); 392 | for (int i = 0; i < 2; i++) { 393 | if (p_msgs[i]) { 394 | set_message_len(p_msgs[i]); 395 | free_buf = nfc_ncif_process_event(p_msgs[i]); 396 | if (free_buf) { 397 | GKI_freebuf(p_msgs[i]); 398 | } 399 | } 400 | } 401 | } 402 | } 403 | 404 | void handleT5TWrite(const nfc::T5TWrite& t5t_write) { 405 | bool free_buf; 406 | for (nfc::T5TMboxEvt evt : t5t_write.evt()) { 407 | free_buf = true; 408 | NFC_HDR* p_msgs[2]; 409 | p_msgs[0] = NULL; 410 | p_msgs[1] = NULL; 411 | create_data_msg_t5t(evt, p_msgs); 412 | for (int i = 0; i < 2; i++) { 413 | if (p_msgs[i]) { 414 | set_message_len(p_msgs[i]); 415 | free_buf = nfc_ncif_process_event(p_msgs[i]); 416 | if (free_buf) { 417 | GKI_freebuf(p_msgs[i]); 418 | } 419 | } 420 | } 421 | } 422 | } 423 | 424 | void handleT4TRead(const nfc::T4TRead& t4t_read) { 425 | bool free_buf; 426 | for (nfc::T4TMboxEvt evt : t4t_read.evt()) { 427 | free_buf = true; 428 | NFC_HDR* p_msg; 429 | p_msg = create_data_msg_t4t(evt); 430 | if (p_msg) { 431 | set_message_len(p_msg); 432 | free_buf = nfc_ncif_process_event(p_msg); 433 | if (free_buf) { 434 | GKI_freebuf(p_msg); 435 | } 436 | } 437 | } 438 | } 439 | 440 | void handleT4TWrite(const nfc::T4TWrite& t4t_write) { 441 | bool free_buf; 442 | for (nfc::T4TMboxEvt evt : t4t_write.evt()) { 443 | free_buf = true; 444 | NFC_HDR* p_msg; 445 | p_msg = create_data_msg_t4t(evt); 446 | if (p_msg) { 447 | set_message_len(p_msg); 448 | free_buf = nfc_ncif_process_event(p_msg); 449 | if (free_buf) { 450 | GKI_freebuf(p_msg); 451 | } 452 | } 453 | } 454 | } 455 | 456 | 457 | /* 458 | void handleMboxEvt(const nfc::NFCTask& task, uint8_t protocol) { 459 | bool free_buf; 460 | for (nfc::MboxMsg msg : task.mbox_evt().mbox_msg()) { 461 | free_buf = true; 462 | switch (msg.msg_case()) { 463 | case nfc::MboxMsg::kNfcNci: 464 | NFC_HDR* p_msg; 465 | p_msg = create_data_msg(msg.nfc_nci(), task.mbox_evt(), protocol); 466 | if (p_msg) { 467 | free_buf = nfc_ncif_process_event(p_msg); 468 | if (free_buf) { 469 | GKI_freebuf(p_msg); 470 | } 471 | } 472 | break; 473 | case nfc::MboxMsg::kStartTimer: 474 | GKI_start_timer(NFC_TIMER_ID, GKI_SECS_TO_TICKS(1), true); 475 | break; 476 | case nfc::MboxMsg::kStartQuickTimer: 477 | GKI_start_timer( 478 | NFC_QUICK_TIMER_ID, 479 | ((GKI_SECS_TO_TICKS(1) / QUICK_TIMER_TICKS_PER_SEC)), true); 480 | break; 481 | case nfc::MboxMsg::kNfcMsgs: 482 | tNFC_HAL_EVT_MSG* hal_msg; 483 | hal_msg = create_hal_evt(msg.nfc_msgs().hal_evt(), msg.nfc_msgs().status()); 484 | if (hal_msg) { 485 | nfc_main_handle_hal_evt(hal_msg); 486 | GKI_freebuf(hal_msg); 487 | } 488 | break; 489 | default: 490 | break; 491 | } 492 | } 493 | } 494 | */ 495 | void selectProtocol(nfc::Session::ProtoSessionCase protocol) { 496 | tNFC_ACTIVATE_DEVT* p_activate_params = new tNFC_ACTIVATE_DEVT; 497 | /* not a tag NFC_PROTOCOL_NFCIP1: NFCDEP/LLCP - NFC-A or NFC-F */ 498 | if (false) { 499 | /* Type1Tag - NFC-A */ 500 | p_activate_params->protocol = NFC_PROTOCOL_T1T; 501 | p_activate_params->rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_A; 502 | //Initialize uid 503 | p_activate_params->rf_tech_param.param.pa.nfcid1_len = 4; 504 | for (int i = 0; i < NCI_NFCID1_MAX_LEN; i++) { 505 | p_activate_params->rf_tech_param.param.pa.nfcid1[i] = 0; 506 | } 507 | //Initialize hr 508 | for (int i = 0; i < NCI_T1T_HR_LEN; i++) { 509 | p_activate_params->rf_tech_param.param.pa.hr[i] = 0; 510 | p_activate_params->intf_param.intf_param.frame.param[i] = 0; 511 | } 512 | } else if (false) { 513 | /* Type2Tag - NFC-A */ 514 | p_activate_params->protocol = NFC_PROTOCOL_T2T; 515 | p_activate_params->rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_A; 516 | p_activate_params->rf_tech_param.param.pa.sel_rsp = NFC_SEL_RES_NFC_FORUM_T2T; 517 | nfa_rw_cb.pa_sel_res = NFC_SEL_RES_NFC_FORUM_T2T; 518 | //Initialize uid 519 | p_activate_params->rf_tech_param.param.pa.nfcid1_len = 4; 520 | for (int i = 0; i < NCI_NFCID1_MAX_LEN; i++) { 521 | p_activate_params->rf_tech_param.param.pa.nfcid1[i] = 0; 522 | } 523 | } else if (false) { 524 | /* Type3Tag - NFC-F */ 525 | p_activate_params->protocol = NFC_PROTOCOL_T3T; 526 | p_activate_params->rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_F; 527 | } else if (nfc::Session::kT4TRead == protocol || nfc::Session::kT4TWrite == protocol) { 528 | /* ISODEP/4A,4B- NFC-A or NFC-B */ 529 | p_activate_params->protocol = NFC_PROTOCOL_ISO_DEP; 530 | p_activate_params->rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_B; 531 | //p_activate_params->rf_tech_param.mode == NFC_DISCOVERY_TYPE_POLL_A; 532 | } else if (nfc::Session::kT5TRead == protocol || nfc::Session::kT5TWrite == protocol) { 533 | /* T5T */ 534 | p_activate_params->protocol = NFC_PROTOCOL_T5T; 535 | p_activate_params->rf_tech_param.mode = NFC_DISCOVERY_TYPE_POLL_V; 536 | } 537 | tNFA_RW_MSG* p_data = new tNFA_RW_MSG; 538 | p_data->activate_ntf.p_activate_params = p_activate_params; 539 | nfa_rw_activate_ntf(p_data); 540 | delete p_data; 541 | delete p_activate_params; 542 | } 543 | 544 | extern "C" int LLVMFuzzerInitialize(int *argc, char*** argv) { 545 | return initialize(); 546 | } 547 | 548 | int initialize() { 549 | allocate_all_pools(); 550 | adaptation = &NfcAdaptation::GetInstance(); 551 | // NFC_Init(NULL); 552 | adaptation->InitializeFuzzer(); 553 | return 0; 554 | } 555 | 556 | void cleanup() { 557 | GKI_shutdown(); 558 | NfcConfig::clear(); 559 | } 560 | 561 | void TestRW(const nfc::Session& session, uint8_t protocol) { 562 | // adaptation->InitializeFuzzer(); 563 | NFC_Init_RW(NULL); 564 | // gki_buffers_cleanup(); 565 | gki_reset(); 566 | reset_task(); 567 | initialize_rf_conn(); 568 | // NFC_ConnCreate(NCI_DEST_TYPE_REMOTE, NFC_RF_CONN_ID, protocol,NULL); 569 | selectProtocol(session.ProtoSession_case()); 570 | //Initialize to reader. 571 | switch (session.ProtoSession_case()) { 572 | case nfc::Session::kT5TRead: 573 | nfa_rw_cb.cur_op = NFA_RW_OP_READ_NDEF; 574 | nfa_rw_start_ndef_detection(); 575 | handleT5TRead(session.t5t_read()); 576 | break; 577 | case nfc::Session::kT5TWrite: 578 | nfa_rw_cb.cur_op = NFA_RW_OP_READ_NDEF; 579 | nfa_rw_start_ndef_detection(); 580 | handleT5TWrite(session.t5t_write()); 581 | break; 582 | case nfc::Session::kT4TRead: 583 | nfa_rw_cb.cur_op = NFA_RW_OP_READ_NDEF; 584 | nfa_rw_start_ndef_detection(); 585 | handleT4TRead(session.t4t_read()); 586 | break; 587 | case nfc::Session::kT4TWrite: 588 | nfa_rw_cb.cur_op = NFA_RW_OP_WRITE_NDEF; 589 | nfa_rw_start_ndef_detection(); 590 | handleT4TWrite(session.t4t_write()); 591 | default: 592 | break; 593 | } 594 | nfa_rw_deactivate_ntf(NULL); 595 | // cleanup(); 596 | // GKI_shutdown(); 597 | // NfcConfig::clear(); 598 | // NFC_ConnClose(NFC_RF_CONN_ID); 599 | } 600 | /* 601 | void create_initial_sequence(nfc::MboxEvt* evt) { 602 | std::string data = "abca"; 603 | //Only needs to be 0 for the first step 604 | data.push_back('\0'); 605 | std::string uid = std::string("abcdefgh"); 606 | //Get UID 607 | nfc::MboxMsg* msg0 = evt->add_mbox_msg(); 608 | nfc::NfcNci* data_evt0 = new nfc::NfcNci; 609 | data_evt0->set_data(data + uid); 610 | msg0->set_allocated_nfc_nci(data_evt0); 611 | //Get_SYS_INFO 612 | nfc::MboxMsg* msg1 = evt->add_mbox_msg(); 613 | nfc::NfcNci* data_evt1 = new nfc::NfcNci; 614 | data_evt1->set_data(data); 615 | msg1->set_allocated_nfc_nci(data_evt1); 616 | } 617 | */ 618 | -------------------------------------------------------------------------------- /tools/src/mutator.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 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 "src/mutator.h" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "src/field_instance.h" 24 | #include "src/utf8_fix.h" 25 | #include "src/weighted_reservoir_sampler.h" 26 | 27 | namespace protobuf_mutator { 28 | 29 | using protobuf::Descriptor; 30 | using protobuf::FieldDescriptor; 31 | using protobuf::FileDescriptor; 32 | using protobuf::Message; 33 | using protobuf::OneofDescriptor; 34 | using protobuf::Reflection; 35 | using protobuf::util::MessageDifferencer; 36 | using std::placeholders::_1; 37 | 38 | namespace { 39 | 40 | const int kMaxInitializeDepth = 200; 41 | const uint64_t kDefaultMutateWeight = 1000000; 42 | 43 | enum class Mutation { 44 | None, 45 | Add, // Adds new field with default value. 46 | Mutate, // Mutates field contents. 47 | Delete, // Deletes field. 48 | Copy, // Copy values copied from another field. 49 | 50 | // TODO(vitalybuka): 51 | // Clone, // Adds new field with value copied from another field. 52 | }; 53 | 54 | // Return random integer from [0, count) 55 | size_t GetRandomIndex(RandomEngine* random, size_t count) { 56 | assert(count > 0); 57 | if (count == 1) return 0; 58 | return std::uniform_int_distribution(0, count - 1)(*random); 59 | } 60 | 61 | // Flips random bit in the buffer. 62 | void FlipBit(size_t size, uint8_t* bytes, RandomEngine* random) { 63 | size_t bit = GetRandomIndex(random, size * 8); 64 | bytes[bit / 8] ^= (1u << (bit % 8)); 65 | } 66 | 67 | // Flips random bit in the value. 68 | template 69 | T FlipBit(T value, RandomEngine* random) { 70 | FlipBit(sizeof(value), reinterpret_cast(&value), random); 71 | return value; 72 | } 73 | 74 | // Return true with probability about 1-of-n. 75 | bool GetRandomBool(RandomEngine* random, size_t n = 2) { 76 | return GetRandomIndex(random, n) == 0; 77 | } 78 | 79 | bool IsProto3SimpleField(const FieldDescriptor& field) { 80 | assert(field.file()->syntax() == FileDescriptor::SYNTAX_PROTO3 || 81 | field.file()->syntax() == FileDescriptor::SYNTAX_PROTO2); 82 | return field.file()->syntax() == FileDescriptor::SYNTAX_PROTO3 && 83 | field.cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE && 84 | !field.containing_oneof() && !field.is_repeated(); 85 | } 86 | 87 | struct CreateDefaultField : public FieldFunction { 88 | template 89 | void ForType(const FieldInstance& field) const { 90 | T value; 91 | field.GetDefault(&value); 92 | field.Create(value); 93 | } 94 | }; 95 | 96 | struct DeleteField : public FieldFunction { 97 | template 98 | void ForType(const FieldInstance& field) const { 99 | field.Delete(); 100 | } 101 | }; 102 | 103 | struct CopyField : public FieldFunction { 104 | template 105 | void ForType(const ConstFieldInstance& source, 106 | const FieldInstance& field) const { 107 | T value; 108 | source.Load(&value); 109 | field.Store(value); 110 | } 111 | }; 112 | 113 | struct AppendField : public FieldFunction { 114 | template 115 | void ForType(const ConstFieldInstance& source, 116 | const FieldInstance& field) const { 117 | T value; 118 | source.Load(&value); 119 | field.Create(value); 120 | } 121 | }; 122 | 123 | class CanCopyAndDifferentField 124 | : public FieldFunction { 125 | public: 126 | template 127 | bool ForType(const ConstFieldInstance& src, 128 | const ConstFieldInstance& dst) const { 129 | T s; 130 | src.Load(&s); 131 | if (!dst.CanStore(s)) return false; 132 | T d; 133 | dst.Load(&d); 134 | return !IsEqual(s, d); 135 | } 136 | 137 | private: 138 | bool IsEqual(const ConstFieldInstance::Enum& a, 139 | const ConstFieldInstance::Enum& b) const { 140 | assert(a.count == b.count); 141 | return a.index == b.index; 142 | } 143 | 144 | bool IsEqual(const std::unique_ptr& a, 145 | const std::unique_ptr& b) const { 146 | return MessageDifferencer::Equals(*a, *b); 147 | } 148 | 149 | template 150 | bool IsEqual(const T& a, const T& b) const { 151 | return a == b; 152 | } 153 | }; 154 | 155 | // Selects random field and mutation from the given proto message. 156 | class MutationSampler { 157 | public: 158 | MutationSampler(bool keep_initialized, RandomEngine* random, Message* message) 159 | : keep_initialized_(keep_initialized), random_(random), sampler_(random) { 160 | Sample(message); 161 | assert(mutation() != Mutation::None || 162 | message->GetDescriptor()->field_count() == 0); 163 | } 164 | 165 | // Returns selected field. 166 | const FieldInstance& field() const { return sampler_.selected().field; } 167 | 168 | // Returns selected mutation. 169 | Mutation mutation() const { return sampler_.selected().mutation; } 170 | 171 | private: 172 | void Sample(Message* message) { 173 | const Descriptor* descriptor = message->GetDescriptor(); 174 | const Reflection* reflection = message->GetReflection(); 175 | 176 | int field_count = descriptor->field_count(); 177 | for (int i = 0; i < field_count; ++i) { 178 | const FieldDescriptor* field = descriptor->field(i); 179 | if (const OneofDescriptor* oneof = field->containing_oneof()) { 180 | // Handle entire oneof group on the first field. 181 | if (field->index_in_oneof() == 0) { 182 | assert(oneof->field_count()); 183 | const FieldDescriptor* current_field = 184 | reflection->GetOneofFieldDescriptor(*message, oneof); 185 | for (;;) { 186 | const FieldDescriptor* add_field = 187 | oneof->field(GetRandomIndex(random_, oneof->field_count())); 188 | if (add_field != current_field) { 189 | sampler_.Try(kDefaultMutateWeight, 190 | {{message, add_field}, Mutation::Add}); 191 | break; 192 | } 193 | if (oneof->field_count() < 2) break; 194 | } 195 | if (current_field) { 196 | if (current_field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { 197 | sampler_.Try(kDefaultMutateWeight, 198 | {{message, current_field}, Mutation::Mutate}); 199 | } 200 | sampler_.Try(kDefaultMutateWeight, 201 | {{message, current_field}, Mutation::Delete}); 202 | sampler_.Try(kDefaultMutateWeight, 203 | {{message, current_field}, Mutation::Copy}); 204 | } 205 | } 206 | } else { 207 | if (field->is_repeated()) { 208 | int field_size = reflection->FieldSize(*message, field); 209 | sampler_.Try( 210 | kDefaultMutateWeight, 211 | {{message, field, GetRandomIndex(random_, field_size + 1)}, 212 | Mutation::Add}); 213 | 214 | if (field_size) { 215 | size_t random_index = GetRandomIndex(random_, field_size); 216 | if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { 217 | sampler_.Try(kDefaultMutateWeight, 218 | {{message, field, random_index}, Mutation::Mutate}); 219 | } 220 | sampler_.Try(kDefaultMutateWeight, 221 | {{message, field, random_index}, Mutation::Delete}); 222 | sampler_.Try(kDefaultMutateWeight, 223 | {{message, field, random_index}, Mutation::Copy}); 224 | } 225 | } else { 226 | if (reflection->HasField(*message, field) || 227 | IsProto3SimpleField(*field)) { 228 | if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { 229 | sampler_.Try(kDefaultMutateWeight, 230 | {{message, field}, Mutation::Mutate}); 231 | } 232 | if (!IsProto3SimpleField(*field) && 233 | (!field->is_required() || !keep_initialized_)) { 234 | sampler_.Try(kDefaultMutateWeight, 235 | {{message, field}, Mutation::Delete}); 236 | } 237 | sampler_.Try(kDefaultMutateWeight, 238 | {{message, field}, Mutation::Copy}); 239 | } else { 240 | sampler_.Try(kDefaultMutateWeight, 241 | {{message, field}, Mutation::Add}); 242 | } 243 | } 244 | } 245 | 246 | if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { 247 | if (field->is_repeated()) { 248 | const int field_size = reflection->FieldSize(*message, field); 249 | for (int j = 0; j < field_size; ++j) 250 | Sample(reflection->MutableRepeatedMessage(message, field, j)); 251 | } else if (reflection->HasField(*message, field)) { 252 | Sample(reflection->MutableMessage(message, field)); 253 | } 254 | } 255 | } 256 | } 257 | 258 | bool keep_initialized_ = false; 259 | 260 | RandomEngine* random_; 261 | 262 | struct Result { 263 | Result() = default; 264 | Result(const FieldInstance& f, Mutation m) : field(f), mutation(m) {} 265 | 266 | FieldInstance field; 267 | Mutation mutation = Mutation::None; 268 | }; 269 | WeightedReservoirSampler sampler_; 270 | }; 271 | 272 | // Selects random field of compatible type to use for clone mutations. 273 | class DataSourceSampler { 274 | public: 275 | DataSourceSampler(const ConstFieldInstance& match, RandomEngine* random, 276 | Message* message) 277 | : match_(match), random_(random), sampler_(random) { 278 | Sample(message); 279 | } 280 | 281 | // Returns selected field. 282 | const ConstFieldInstance& field() const { 283 | assert(!IsEmpty()); 284 | return sampler_.selected(); 285 | } 286 | 287 | bool IsEmpty() const { return sampler_.IsEmpty(); } 288 | 289 | private: 290 | void Sample(Message* message) { 291 | const Descriptor* descriptor = message->GetDescriptor(); 292 | const Reflection* reflection = message->GetReflection(); 293 | 294 | int field_count = descriptor->field_count(); 295 | for (int i = 0; i < field_count; ++i) { 296 | const FieldDescriptor* field = descriptor->field(i); 297 | if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { 298 | if (field->is_repeated()) { 299 | const int field_size = reflection->FieldSize(*message, field); 300 | for (int j = 0; j < field_size; ++j) { 301 | Sample(reflection->MutableRepeatedMessage(message, field, j)); 302 | } 303 | } else if (reflection->HasField(*message, field)) { 304 | Sample(reflection->MutableMessage(message, field)); 305 | } 306 | } 307 | 308 | if (field->cpp_type() != match_.cpp_type()) continue; 309 | if (match_.cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { 310 | if (field->enum_type() != match_.enum_type()) continue; 311 | } else if (match_.cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { 312 | if (field->message_type() != match_.message_type()) continue; 313 | } 314 | 315 | if (field->is_repeated()) { 316 | if (int field_size = reflection->FieldSize(*message, field)) { 317 | ConstFieldInstance source(message, field, 318 | GetRandomIndex(random_, field_size)); 319 | if (CanCopyAndDifferentField()(source, match_)) 320 | sampler_.Try(field_size, source); 321 | } 322 | } else { 323 | if (reflection->HasField(*message, field)) { 324 | ConstFieldInstance source(message, field); 325 | if (CanCopyAndDifferentField()(source, match_)) 326 | sampler_.Try(1, source); 327 | } 328 | } 329 | } 330 | } 331 | 332 | ConstFieldInstance match_; 333 | RandomEngine* random_; 334 | 335 | WeightedReservoirSampler sampler_; 336 | }; 337 | 338 | } // namespace 339 | 340 | class FieldMutator { 341 | public: 342 | FieldMutator(size_t size_increase_hint, bool enforce_changes, 343 | bool enforce_utf8_strings, Mutator* mutator) 344 | : size_increase_hint_(size_increase_hint), 345 | enforce_changes_(enforce_changes), 346 | enforce_utf8_strings_(enforce_utf8_strings), 347 | mutator_(mutator) {} 348 | 349 | void Mutate(int32_t* value) const { 350 | RepeatMutate(value, std::bind(&Mutator::MutateInt32, mutator_, _1)); 351 | } 352 | 353 | void Mutate(int64_t* value) const { 354 | RepeatMutate(value, std::bind(&Mutator::MutateInt64, mutator_, _1)); 355 | } 356 | 357 | void Mutate(uint32_t* value) const { 358 | RepeatMutate(value, std::bind(&Mutator::MutateUInt32, mutator_, _1)); 359 | } 360 | 361 | void Mutate(uint64_t* value) const { 362 | RepeatMutate(value, std::bind(&Mutator::MutateUInt64, mutator_, _1)); 363 | } 364 | 365 | void Mutate(float* value) const { 366 | RepeatMutate(value, std::bind(&Mutator::MutateFloat, mutator_, _1)); 367 | } 368 | 369 | void Mutate(double* value) const { 370 | RepeatMutate(value, std::bind(&Mutator::MutateDouble, mutator_, _1)); 371 | } 372 | 373 | void Mutate(bool* value) const { 374 | RepeatMutate(value, std::bind(&Mutator::MutateBool, mutator_, _1)); 375 | } 376 | 377 | void Mutate(FieldInstance::Enum* value) const { 378 | RepeatMutate(&value->index, 379 | std::bind(&Mutator::MutateEnum, mutator_, _1, value->count)); 380 | assert(value->index < value->count); 381 | } 382 | 383 | void Mutate(std::string* value) const { 384 | if (enforce_utf8_strings_) { 385 | RepeatMutate(value, std::bind(&Mutator::MutateUtf8String, mutator_, _1, 386 | size_increase_hint_)); 387 | } else { 388 | RepeatMutate(value, std::bind(&Mutator::MutateString, mutator_, _1, 389 | size_increase_hint_)); 390 | } 391 | } 392 | 393 | void Mutate(std::unique_ptr* message) const { 394 | assert(!enforce_changes_); 395 | assert(*message); 396 | if (GetRandomBool(mutator_->random(), mutator_->random_to_default_ratio_)) 397 | return; 398 | mutator_->MutateImpl(message->get(), size_increase_hint_); 399 | } 400 | 401 | private: 402 | template 403 | void RepeatMutate(T* value, F mutate) const { 404 | if (!enforce_changes_ && 405 | GetRandomBool(mutator_->random(), mutator_->random_to_default_ratio_)) { 406 | return; 407 | } 408 | T tmp = *value; 409 | for (int i = 0; i < 10; ++i) { 410 | *value = mutate(*value); 411 | if (!enforce_changes_ || *value != tmp) return; 412 | } 413 | } 414 | 415 | size_t size_increase_hint_; 416 | size_t enforce_changes_; 417 | bool enforce_utf8_strings_; 418 | Mutator* mutator_; 419 | }; 420 | 421 | namespace { 422 | 423 | struct MutateField : public FieldFunction { 424 | template 425 | void ForType(const FieldInstance& field, size_t size_increase_hint, 426 | Mutator* mutator) const { 427 | T value; 428 | field.Load(&value); 429 | FieldMutator(size_increase_hint, true, field.EnforceUtf8(), mutator) 430 | .Mutate(&value); 431 | field.Store(value); 432 | } 433 | }; 434 | 435 | struct CreateField : public FieldFunction { 436 | public: 437 | template 438 | void ForType(const FieldInstance& field, size_t size_increase_hint, 439 | Mutator* mutator) const { 440 | T value; 441 | field.GetDefault(&value); 442 | FieldMutator field_mutator(size_increase_hint, 443 | false /* defaults could be useful */, 444 | field.EnforceUtf8(), mutator); 445 | field_mutator.Mutate(&value); 446 | field.Create(value); 447 | } 448 | }; 449 | 450 | } // namespace 451 | 452 | void Mutator::Seed(uint32_t value) { random_.seed(value); } 453 | 454 | void Mutator::Mutate(Message* message, size_t size_increase_hint) { 455 | MutateImpl(message, size_increase_hint); 456 | 457 | InitializeAndTrim(message, kMaxInitializeDepth); 458 | assert(IsInitialized(*message)); 459 | 460 | if (!post_processors_.empty()) { 461 | ApplyPostProcessing(message); 462 | } 463 | } 464 | 465 | void Mutator::RegisterPostProcessor(const protobuf::Descriptor* desc, 466 | PostProcess callback) { 467 | post_processors_.emplace(desc, callback); 468 | } 469 | 470 | void Mutator::ApplyPostProcessing(Message* message) { 471 | const Descriptor* descriptor = message->GetDescriptor(); 472 | 473 | auto range = post_processors_.equal_range(descriptor); 474 | for (auto it = range.first; it != range.second; ++it) 475 | it->second(message, random_()); 476 | 477 | // Now recursively apply custom mutators. 478 | const Reflection* reflection = message->GetReflection(); 479 | for (int i = 0; i < descriptor->field_count(); i++) { 480 | const FieldDescriptor* field = descriptor->field(i); 481 | if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { 482 | continue; 483 | } 484 | if (field->is_repeated()) { 485 | const int field_size = reflection->FieldSize(*message, field); 486 | for (int j = 0; j < field_size; ++j) { 487 | Message* nested_message = 488 | reflection->MutableRepeatedMessage(message, field, j); 489 | ApplyPostProcessing(nested_message); 490 | } 491 | } else if (reflection->HasField(*message, field)) { 492 | Message* nested_message = reflection->MutableMessage(message, field); 493 | ApplyPostProcessing(nested_message); 494 | } 495 | } 496 | } 497 | 498 | void Mutator::MutateImpl(Message* message, size_t size_increase_hint) { 499 | for (;;) { 500 | MutationSampler mutation(keep_initialized_, &random_, message); 501 | switch (mutation.mutation()) { 502 | case Mutation::None: 503 | return; 504 | case Mutation::Add: 505 | CreateField()(mutation.field(), size_increase_hint / 2, this); 506 | return; 507 | case Mutation::Mutate: 508 | MutateField()(mutation.field(), size_increase_hint / 2, this); 509 | return; 510 | case Mutation::Delete: 511 | DeleteField()(mutation.field()); 512 | return; 513 | case Mutation::Copy: { 514 | DataSourceSampler source(mutation.field(), &random_, message); 515 | if (source.IsEmpty()) break; 516 | CopyField()(source.field(), mutation.field()); 517 | return; 518 | } 519 | default: 520 | assert(false && "unexpected mutation"); 521 | return; 522 | } 523 | } 524 | } 525 | 526 | void Mutator::CrossOver(const protobuf::Message& message1, 527 | protobuf::Message* message2) { 528 | // CrossOver can produce result which still equals to inputs. So we backup 529 | // message2 to later comparison. message1 is already constant. 530 | std::unique_ptr message2_copy(message2->New()); 531 | message2_copy->CopyFrom(*message2); 532 | 533 | CrossOverImpl(message1, message2); 534 | 535 | InitializeAndTrim(message2, kMaxInitializeDepth); 536 | assert(IsInitialized(*message2)); 537 | 538 | if (!post_processors_.empty()) { 539 | ApplyPostProcessing(message2); 540 | } 541 | 542 | // Can't call mutate from crossover because of a bug in libFuzzer. 543 | // if (MessageDifferencer::Equals(*message2_copy, *message2) || 544 | // MessageDifferencer::Equals(message1, *message2)) { 545 | // Mutate(message2, 0); 546 | // } 547 | } 548 | 549 | void Mutator::CrossOverImpl(const protobuf::Message& message1, 550 | protobuf::Message* message2) { 551 | const Descriptor* descriptor = message2->GetDescriptor(); 552 | const Reflection* reflection = message2->GetReflection(); 553 | assert(message1.GetDescriptor() == descriptor); 554 | assert(message1.GetReflection() == reflection); 555 | 556 | for (int i = 0; i < descriptor->field_count(); ++i) { 557 | const FieldDescriptor* field = descriptor->field(i); 558 | 559 | if (field->is_repeated()) { 560 | const int field_size1 = reflection->FieldSize(message1, field); 561 | int field_size2 = reflection->FieldSize(*message2, field); 562 | for (int j = 0; j < field_size1; ++j) { 563 | ConstFieldInstance source(&message1, field, j); 564 | FieldInstance destination(message2, field, field_size2++); 565 | AppendField()(source, destination); 566 | } 567 | 568 | assert(field_size2 == reflection->FieldSize(*message2, field)); 569 | 570 | // Shuffle 571 | for (int j = 0; j < field_size2; ++j) { 572 | if (int k = GetRandomIndex(&random_, field_size2 - j)) { 573 | reflection->SwapElements(message2, field, j, j + k); 574 | } 575 | } 576 | 577 | int keep = GetRandomIndex(&random_, field_size2 + 1); 578 | 579 | if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { 580 | int remove = field_size2 - keep; 581 | // Cross some message to keep with messages to remove. 582 | int cross = GetRandomIndex(&random_, std::min(keep, remove) + 1); 583 | for (int j = 0; j < cross; ++j) { 584 | int k = GetRandomIndex(&random_, keep); 585 | int r = keep + GetRandomIndex(&random_, remove); 586 | assert(k != r); 587 | CrossOverImpl(reflection->GetRepeatedMessage(*message2, field, r), 588 | reflection->MutableRepeatedMessage(message2, field, k)); 589 | } 590 | } 591 | 592 | for (int j = keep; j < field_size2; ++j) 593 | reflection->RemoveLast(message2, field); 594 | assert(keep == reflection->FieldSize(*message2, field)); 595 | 596 | } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { 597 | if (!reflection->HasField(message1, field)) { 598 | if (GetRandomBool(&random_)) 599 | DeleteField()(FieldInstance(message2, field)); 600 | } else if (!reflection->HasField(*message2, field)) { 601 | if (GetRandomBool(&random_)) { 602 | ConstFieldInstance source(&message1, field); 603 | CopyField()(source, FieldInstance(message2, field)); 604 | } 605 | } else { 606 | CrossOverImpl(reflection->GetMessage(message1, field), 607 | reflection->MutableMessage(message2, field)); 608 | } 609 | } else { 610 | if (GetRandomBool(&random_)) { 611 | if (reflection->HasField(message1, field)) { 612 | ConstFieldInstance source(&message1, field); 613 | CopyField()(source, FieldInstance(message2, field)); 614 | } else { 615 | DeleteField()(FieldInstance(message2, field)); 616 | } 617 | } 618 | } 619 | } 620 | } 621 | 622 | void Mutator::InitializeAndTrim(Message* message, int max_depth) { 623 | const Descriptor* descriptor = message->GetDescriptor(); 624 | const Reflection* reflection = message->GetReflection(); 625 | for (int i = 0; i < descriptor->field_count(); ++i) { 626 | const FieldDescriptor* field = descriptor->field(i); 627 | if (keep_initialized_ && 628 | (field->is_required() || descriptor->options().map_entry()) && 629 | !reflection->HasField(*message, field)) { 630 | CreateDefaultField()(FieldInstance(message, field)); 631 | } 632 | 633 | if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { 634 | if (max_depth <= 0 && !field->is_required()) { 635 | // Clear deep optional fields to avoid stack overflow. 636 | reflection->ClearField(message, field); 637 | if (field->is_repeated()) 638 | assert(!reflection->FieldSize(*message, field)); 639 | else 640 | assert(!reflection->HasField(*message, field)); 641 | continue; 642 | } 643 | 644 | if (field->is_repeated()) { 645 | const int field_size = reflection->FieldSize(*message, field); 646 | for (int j = 0; j < field_size; ++j) { 647 | Message* nested_message = 648 | reflection->MutableRepeatedMessage(message, field, j); 649 | InitializeAndTrim(nested_message, max_depth - 1); 650 | } 651 | } else if (reflection->HasField(*message, field)) { 652 | Message* nested_message = reflection->MutableMessage(message, field); 653 | InitializeAndTrim(nested_message, max_depth - 1); 654 | } 655 | } 656 | } 657 | } 658 | 659 | int32_t Mutator::MutateInt32(int32_t value) { return FlipBit(value, &random_); } 660 | 661 | int64_t Mutator::MutateInt64(int64_t value) { return FlipBit(value, &random_); } 662 | 663 | uint32_t Mutator::MutateUInt32(uint32_t value) { 664 | return FlipBit(value, &random_); 665 | } 666 | 667 | uint64_t Mutator::MutateUInt64(uint64_t value) { 668 | return FlipBit(value, &random_); 669 | } 670 | 671 | float Mutator::MutateFloat(float value) { return FlipBit(value, &random_); } 672 | 673 | double Mutator::MutateDouble(double value) { return FlipBit(value, &random_); } 674 | 675 | bool Mutator::MutateBool(bool value) { return !value; } 676 | 677 | size_t Mutator::MutateEnum(size_t index, size_t item_count) { 678 | if (item_count <= 1) return 0; 679 | return (index + 1 + GetRandomIndex(&random_, item_count - 1)) % item_count; 680 | } 681 | 682 | std::string Mutator::MutateString(const std::string& value, 683 | size_t size_increase_hint) { 684 | std::string result = value; 685 | 686 | while (!result.empty() && GetRandomBool(&random_)) { 687 | result.erase(GetRandomIndex(&random_, result.size()), 1); 688 | } 689 | 690 | while (result.size() < size_increase_hint && GetRandomBool(&random_)) { 691 | size_t index = GetRandomIndex(&random_, result.size() + 1); 692 | result.insert(result.begin() + index, GetRandomIndex(&random_, 1 << 8)); 693 | } 694 | 695 | if (result != value) return result; 696 | 697 | if (result.empty()) { 698 | result.push_back(GetRandomIndex(&random_, 1 << 8)); 699 | return result; 700 | } 701 | 702 | if (!result.empty()) 703 | FlipBit(result.size(), reinterpret_cast(&result[0]), &random_); 704 | return result; 705 | } 706 | 707 | std::string Mutator::MutateUtf8String(const std::string& value, 708 | size_t size_increase_hint) { 709 | std::string str = MutateString(value, size_increase_hint); 710 | FixUtf8String(&str, &random_); 711 | return str; 712 | } 713 | 714 | bool Mutator::IsInitialized(const Message& message) const { 715 | if (!keep_initialized_ || message.IsInitialized()) return true; 716 | std::cerr << "Uninitialized: " << message.DebugString() << "\n"; 717 | return false; 718 | } 719 | 720 | } // namespace protobuf_mutator 721 | -------------------------------------------------------------------------------- /nfc.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/Android.bp b/src/Android.bp 2 | index 9d2ae92..6d47a52 100644 3 | --- a/src/Android.bp 4 | +++ b/src/Android.bp 5 | @@ -1,10 +1,10 @@ 6 | -cc_library_shared { 7 | +cc_defaults { 8 | + name: "libnfc-nci-defaults", 9 | arch: { 10 | arm: { 11 | instruction_set: "arm", 12 | }, 13 | }, 14 | - name: "libnfc-nci", 15 | shared_libs: [ 16 | "libcutils", 17 | "liblog", 18 | @@ -63,3 +63,46 @@ cc_library_shared { 19 | }, 20 | }, 21 | } 22 | + 23 | +cc_library_shared { 24 | + name: "libnfc-nci", 25 | + defaults: ["libnfc-nci-defaults"], 26 | +} 27 | + 28 | +cc_library_static { 29 | + name: "libnfc-nci-static", 30 | + defaults: ["libnfc-nci-defaults"], 31 | +} 32 | + 33 | +cc_library_shared { 34 | + name: "libnfc-nci-fuzz", 35 | + defaults: ["libnfc-nci-defaults"], 36 | + cflags: [ 37 | + "-DFUZZ", 38 | + "-DDCHECK_ALWAYS_ON", 39 | + ], 40 | + 41 | + sanitize: { 42 | + misc_undefined: [ 43 | + "bounds", 44 | + ], 45 | + } 46 | +} 47 | + 48 | +cc_library_shared { 49 | + name: "libnfc-nci-dbg", 50 | + defaults: ["libnfc-nci-defaults"], 51 | + cflags: [ 52 | + "-g", 53 | + "-O0", 54 | + "-DFUZZ", 55 | + "-DDCHECK_ALWAYS_ON", 56 | + ], 57 | +} 58 | + 59 | +cc_library_shared { 60 | + name: "libnfc-nci-coverage", 61 | + native_coverage: true, 62 | + defaults: ["libnfc-nci-defaults"], 63 | + cflags: ["-DFUZZ"], 64 | +} 65 | diff --git a/src/adaptation/NfcAdaptation.cc b/src/adaptation/NfcAdaptation.cc 66 | index b0fc549..162d36a 100644 67 | --- a/src/adaptation/NfcAdaptation.cc 68 | +++ b/src/adaptation/NfcAdaptation.cc 69 | @@ -375,6 +375,106 @@ void NfcAdaptation::Initialize() { 70 | DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", func); 71 | } 72 | 73 | +/******************************************************************************* 74 | +** 75 | +** Function: NfcAdaptation::InitializeFuzzer() 76 | +** 77 | +** Description: class initializer 78 | +** 79 | +** Returns: none 80 | +** 81 | +*******************************************************************************/ 82 | + 83 | +void NfcAdaptation::InitializeFuzzer() { 84 | + const char* func = "NfcAdaptation::InitializeFuzzer"; 85 | + const char* argv[] = {"libnfc_nci"}; 86 | + 87 | + logging::SetMinLogLevel(3); 88 | + // Init log tag 89 | + base::CommandLine::Init(1, argv); 90 | + 91 | + // Android already logs thread_id, proc_id, timestamp, so disable those. 92 | + logging::SetLogItems(false, false, false, false); 93 | + 94 | + DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", func); 95 | + 96 | + nfc_storage_path = NfcConfig::getString(NAME_NFA_STORAGE, "/data/nfc"); 97 | + 98 | + if (NfcConfig::hasKey(NAME_NFA_DM_CFG)) { 99 | + std::vector dm_config = NfcConfig::getBytes(NAME_NFA_DM_CFG); 100 | + if (dm_config.size() > 0) nfa_dm_cfg.auto_detect_ndef = dm_config[0]; 101 | + if (dm_config.size() > 1) nfa_dm_cfg.auto_read_ndef = dm_config[1]; 102 | + if (dm_config.size() > 2) nfa_dm_cfg.auto_presence_check = dm_config[2]; 103 | + if (dm_config.size() > 3) nfa_dm_cfg.presence_check_option = dm_config[3]; 104 | + // NOTE: The timeout value is not configurable here because the endianess 105 | + // of a byte array is ambiguous and needlessly difficult to configure. 106 | + // If this value needs to be configgurable, a numeric config option should 107 | + // be used. 108 | + } 109 | + 110 | + if (NfcConfig::hasKey(NAME_NFA_MAX_EE_SUPPORTED)) { 111 | + nfa_ee_max_ee_cfg = NfcConfig::getUnsigned(NAME_NFA_MAX_EE_SUPPORTED); 112 | + DLOG_IF(INFO, nfc_debug_enabled) 113 | + << StringPrintf("%s: Overriding NFA_EE_MAX_EE_SUPPORTED to use %d", 114 | + func, nfa_ee_max_ee_cfg); 115 | + } 116 | + 117 | + if (NfcConfig::hasKey(NAME_NFA_POLL_BAIL_OUT_MODE)) { 118 | + nfa_poll_bail_out_mode = 119 | + NfcConfig::getUnsigned(NAME_NFA_POLL_BAIL_OUT_MODE); 120 | + DLOG_IF(INFO, nfc_debug_enabled) 121 | + << StringPrintf("%s: Overriding NFA_POLL_BAIL_OUT_MODE to use %d", func, 122 | + nfa_poll_bail_out_mode); 123 | + } 124 | + 125 | + if (NfcConfig::hasKey(NAME_NFA_PROPRIETARY_CFG)) { 126 | + std::vector p_config = 127 | + NfcConfig::getBytes(NAME_NFA_PROPRIETARY_CFG); 128 | + if (p_config.size() > 0) 129 | + nfa_proprietary_cfg.pro_protocol_18092_active = p_config[0]; 130 | + if (p_config.size() > 1) 131 | + nfa_proprietary_cfg.pro_protocol_b_prime = p_config[1]; 132 | + if (p_config.size() > 2) 133 | + nfa_proprietary_cfg.pro_protocol_dual = p_config[2]; 134 | + if (p_config.size() > 3) 135 | + nfa_proprietary_cfg.pro_protocol_15693 = p_config[3]; 136 | + if (p_config.size() > 4) 137 | + nfa_proprietary_cfg.pro_protocol_kovio = p_config[4]; 138 | + if (p_config.size() > 5) nfa_proprietary_cfg.pro_protocol_mfc = p_config[5]; 139 | + if (p_config.size() > 6) 140 | + nfa_proprietary_cfg.pro_discovery_kovio_poll = p_config[6]; 141 | + if (p_config.size() > 7) 142 | + nfa_proprietary_cfg.pro_discovery_b_prime_poll = p_config[7]; 143 | + if (p_config.size() > 8) 144 | + nfa_proprietary_cfg.pro_discovery_b_prime_listen = p_config[8]; 145 | + } 146 | + 147 | + // Configure whitelist of HCI host ID's 148 | + // See specification: ETSI TS 102 622, section 6.1.3.1 149 | + if (NfcConfig::hasKey(NAME_DEVICE_HOST_WHITE_LIST)) { 150 | + host_whitelist = NfcConfig::getBytes(NAME_DEVICE_HOST_WHITE_LIST); 151 | + nfa_hci_cfg.num_whitelist_host = host_whitelist.size(); 152 | + nfa_hci_cfg.p_whitelist = &host_whitelist[0]; 153 | + } 154 | + 155 | + initializeGlobalDebugEnabledFlag(); 156 | + 157 | + verify_stack_non_volatile_store(); 158 | + if (NfcConfig::hasKey(NAME_PRESERVE_STORAGE) && 159 | + NfcConfig::getUnsigned(NAME_PRESERVE_STORAGE) == 1) { 160 | + DLOG_IF(INFO, nfc_debug_enabled) 161 | + << StringPrintf("%s: preserve stack NV store", __func__); 162 | + } else { 163 | + delete_stack_non_volatile_store(FALSE); 164 | + } 165 | + 166 | + GKI_init(); 167 | + GKI_enable(); 168 | + debug_nfcsnoop_init(); 169 | + DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", func); 170 | +} 171 | + 172 | + 173 | /******************************************************************************* 174 | ** 175 | ** Function: NfcAdaptation::Finalize() 176 | diff --git a/src/gki/common/gki_buffer.cc b/src/gki/common/gki_buffer.cc 177 | index dbb1d8b..eaab3df 100644 178 | --- a/src/gki/common/gki_buffer.cc 179 | +++ b/src/gki/common/gki_buffer.cc 180 | @@ -310,6 +310,9 @@ void* GKI_getbuf(uint16_t size) { 181 | p_hdr->status = BUF_STATUS_UNLINKED; 182 | p_hdr->p_next = nullptr; 183 | p_hdr->Type = 0; 184 | + #ifdef FUZZ 185 | + p_hdr->p_this = p_hdr; 186 | + #endif //FUZZ 187 | return ((void*)((uint8_t*)p_hdr + BUFFER_HDR_SIZE)); 188 | } 189 | } 190 | @@ -371,6 +374,9 @@ void* GKI_getpoolbuf(uint8_t pool_id) { 191 | p_hdr->status = BUF_STATUS_UNLINKED; 192 | p_hdr->p_next = nullptr; 193 | p_hdr->Type = 0; 194 | + #ifdef FUZZ 195 | + p_hdr->p_this = p_hdr; 196 | + #endif //FUZZ 197 | 198 | return ((void*)((uint8_t*)p_hdr + BUFFER_HDR_SIZE)); 199 | } 200 | @@ -424,11 +430,23 @@ void GKI_freebuf(void* p_buf) { 201 | */ 202 | Q = &gki_cb.com.freeq[p_hdr->q_id]; 203 | if (Q->p_last) 204 | +#ifdef FUZZ 205 | + Q->p_last->p_next = p_hdr->p_this; 206 | +#else //FUZZ 207 | Q->p_last->p_next = p_hdr; 208 | +#endif 209 | else 210 | +#ifdef FUZZ 211 | + Q->p_first = p_hdr->p_this; 212 | +#else //FUZZ 213 | Q->p_first = p_hdr; 214 | +#endif 215 | 216 | +#ifdef FUZZ 217 | + Q->p_last = p_hdr->p_this; 218 | +#else //FUZZ 219 | Q->p_last = p_hdr; 220 | +#endif 221 | p_hdr->p_next = nullptr; 222 | p_hdr->status = BUF_STATUS_FREE; 223 | p_hdr->task_id = GKI_INVALID_TASK; 224 | @@ -473,9 +491,10 @@ uint16_t GKI_get_buf_size(void* p_buf) { 225 | ** Returns TRUE if there is a problem, else FALSE 226 | ** 227 | *******************************************************************************/ 228 | -bool gki_chk_buf_damage(void* p_buf) { 229 | -#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE) 230 | - 231 | +bool gki_chk_buf_damage(void* __attribute__((unused)) p_buf) { 232 | +#ifdef FUZZ 233 | + return false; 234 | +#else 235 | uint32_t* magic; 236 | magic = (uint32_t*)((uint8_t*)p_buf + GKI_get_buf_size(p_buf)); 237 | 238 | @@ -484,11 +503,6 @@ bool gki_chk_buf_damage(void* p_buf) { 239 | if (*magic == MAGIC_NO) return false; 240 | 241 | return true; 242 | - 243 | -#else 244 | - 245 | - return false; 246 | - 247 | #endif 248 | } 249 | 250 | diff --git a/src/gki/common/gki_common.h b/src/gki/common/gki_common.h 251 | index 5cf7028..f1f9a5a 100644 252 | --- a/src/gki/common/gki_common.h 253 | +++ b/src/gki/common/gki_common.h 254 | @@ -54,6 +54,9 @@ typedef struct _buffer_hdr { 255 | uint8_t task_id; /* task which allocated the buffer*/ 256 | uint8_t status; /* FREE, UNLINKED or QUEUED */ 257 | uint8_t Type; 258 | +#ifdef FUZZ 259 | + struct _buffer_hdr* p_this; /* pointer to indicate the buffer_hdr to put in queue when freed. */ 260 | +#endif //FUZZ 261 | } BUFFER_HDR_T; 262 | 263 | typedef struct _free_queue { 264 | diff --git a/src/gki/common/gki_time.cc b/src/gki/common/gki_time.cc 265 | index 1265220..6dcf983 100644 266 | --- a/src/gki/common/gki_time.cc 267 | +++ b/src/gki/common/gki_time.cc 268 | @@ -187,7 +187,9 @@ void GKI_start_timer(uint8_t tnum, int32_t ticks, bool is_continuous) { 269 | int32_t orig_ticks; 270 | uint8_t task_id = GKI_get_taskid(); 271 | bool bad_timer = false; 272 | - 273 | +#ifdef FUZZ 274 | + return; 275 | +#endif 276 | if (ticks <= 0) ticks = 1; 277 | 278 | orig_ticks = ticks; /* save the ticks in case adjustment is necessary */ 279 | @@ -284,7 +286,9 @@ void GKI_start_timer(uint8_t tnum, int32_t ticks, bool is_continuous) { 280 | *******************************************************************************/ 281 | void GKI_stop_timer(uint8_t tnum) { 282 | uint8_t task_id = GKI_get_taskid(); 283 | - 284 | +#ifdef FUZZ 285 | + return; 286 | +#endif 287 | GKI_disable(); 288 | 289 | switch (tnum) { 290 | diff --git a/src/gki/ulinux/gki_ulinux.cc b/src/gki/ulinux/gki_ulinux.cc 291 | index 093b58d..91a52fb 100644 292 | --- a/src/gki/ulinux/gki_ulinux.cc 293 | +++ b/src/gki/ulinux/gki_ulinux.cc 294 | @@ -73,7 +73,14 @@ typedef struct { 295 | pthread_mutex_t* pMutex; /* for android*/ 296 | } gki_pthread_info_t; 297 | gki_pthread_info_t gki_pthread_info[GKI_MAX_TASKS]; 298 | - 299 | +#ifdef FUZZ 300 | +void gki_reset() { 301 | + memset(&gki_cb, 0, sizeof(gki_cb)); 302 | + gki_buffer_init(); 303 | + gki_timers_init(); 304 | + gki_cb.com.OSTicks = (uint32_t)times(0); 305 | +} 306 | +#endif 307 | /******************************************************************************* 308 | ** 309 | ** Function gki_task_entry 310 | diff --git a/src/include/NfcAdaptation.h b/src/include/NfcAdaptation.h 311 | index df12a44..15d5b6c 100644 312 | --- a/src/include/NfcAdaptation.h 313 | +++ b/src/include/NfcAdaptation.h 314 | @@ -89,6 +89,9 @@ class NfcAdaptation { 315 | public: 316 | virtual ~NfcAdaptation(); 317 | void Initialize(); 318 | +#ifdef FUZZ 319 | + void InitializeFuzzer(); 320 | +#endif 321 | void Finalize(); 322 | void FactoryReset(); 323 | void DeviceShutdown(); 324 | diff --git a/src/nfa/dm/nfa_dm_act.cc b/src/nfa/dm/nfa_dm_act.cc 325 | index aa494fb..04f0979 100644 326 | --- a/src/nfa/dm/nfa_dm_act.cc 327 | +++ b/src/nfa/dm/nfa_dm_act.cc 328 | @@ -633,7 +633,13 @@ void nfa_dm_conn_cback_event_notify(uint8_t event, tNFA_CONN_EVT_DATA* p_data) { 329 | if (nfa_dm_cb.p_excl_conn_cback) 330 | (*nfa_dm_cb.p_excl_conn_cback)(event, p_data); 331 | } else { 332 | +#ifdef FUZZ 333 | + if (nfa_dm_cb.p_conn_cback) { 334 | + (*nfa_dm_cb.p_conn_cback)(event, p_data); 335 | + } 336 | +#else 337 | (*nfa_dm_cb.p_conn_cback)(event, p_data); 338 | +#endif 339 | } 340 | } 341 | 342 | @@ -660,8 +666,15 @@ void nfa_dm_rel_excl_rf_control_and_notify(void) { 343 | 344 | /* Notify app that exclusive RF control has stopped */ 345 | conn_evt.status = NFA_STATUS_OK; 346 | +#ifdef FUZZ 347 | + if (nfa_dm_cb.p_excl_conn_cback) { 348 | + (*nfa_dm_cb.p_excl_conn_cback)(NFA_EXCLUSIVE_RF_CONTROL_STOPPED_EVT, 349 | + &conn_evt); 350 | + } 351 | +#else 352 | (*nfa_dm_cb.p_excl_conn_cback)(NFA_EXCLUSIVE_RF_CONTROL_STOPPED_EVT, 353 | &conn_evt); 354 | +#endif 355 | nfa_dm_cb.p_excl_conn_cback = nullptr; 356 | nfa_dm_cb.p_excl_ndef_cback = nullptr; 357 | } 358 | @@ -680,7 +693,7 @@ bool nfa_dm_act_request_excl_rf_ctrl(tNFA_DM_MSG* p_data) { 359 | 360 | DLOG_IF(INFO, nfc_debug_enabled) << __func__; 361 | 362 | - if (!nfa_dm_cb.p_excl_conn_cback) { 363 | + if (!nfa_dm_cb.p_excl_conn_cback && p_data->req_excl_rf_ctrl.p_conn_cback) { 364 | if (nfa_dm_cb.disc_cb.disc_state != NFA_DM_RFST_IDLE) { 365 | conn_evt.status = NFA_STATUS_FAILED; 366 | (*p_data->req_excl_rf_ctrl.p_conn_cback)( 367 | @@ -702,8 +715,10 @@ bool nfa_dm_act_request_excl_rf_ctrl(tNFA_DM_MSG* p_data) { 368 | LOG(ERROR) << StringPrintf("Exclusive rf control already requested"); 369 | 370 | conn_evt.status = NFA_STATUS_FAILED; 371 | +#ifndef FUZZ 372 | (*p_data->req_excl_rf_ctrl.p_conn_cback)( 373 | NFA_EXCLUSIVE_RF_CONTROL_STARTED_EVT, &conn_evt); 374 | +#endif 375 | } 376 | 377 | return true; 378 | diff --git a/src/nfa/dm/nfa_dm_api.cc b/src/nfa/dm/nfa_dm_api.cc 379 | index 20b1730..c37bc64 100644 380 | --- a/src/nfa/dm/nfa_dm_api.cc 381 | +++ b/src/nfa/dm/nfa_dm_api.cc 382 | @@ -1019,9 +1019,9 @@ tNFA_STATUS NFA_RegisterNDefTypeHandler(bool handle_whole_message, tNFA_TNF tnf, 383 | p_msg->name_len = type_name_len; 384 | p_msg->p_ndef_cback = p_ndef_cback; 385 | memcpy(p_msg->name, p_type_name, type_name_len); 386 | - 387 | +#ifndef FUZZ 388 | nfa_sys_sendmsg(p_msg); 389 | - 390 | +#endif 391 | return (NFA_STATUS_OK); 392 | } 393 | 394 | diff --git a/src/nfa/include/nfa_rw_int.h b/src/nfa/include/nfa_rw_int.h 395 | index f9a53c2..c8ed15e 100644 396 | --- a/src/nfa/include/nfa_rw_int.h 397 | +++ b/src/nfa/include/nfa_rw_int.h 398 | @@ -315,6 +315,9 @@ typedef struct { 399 | uint8_t i93_block_size; 400 | uint16_t i93_num_block; 401 | uint8_t i93_uid[I93_UID_BYTE_LEN]; 402 | +#ifdef FUZZ 403 | + bool detect_succeeded; 404 | +#endif 405 | } tNFA_RW_CB; 406 | extern tNFA_RW_CB nfa_rw_cb; 407 | 408 | diff --git a/src/nfa/rw/nfa_rw_act.cc b/src/nfa/rw/nfa_rw_act.cc 409 | index 0c0e608..42d9db9 100644 410 | --- a/src/nfa/rw/nfa_rw_act.cc 411 | +++ b/src/nfa/rw/nfa_rw_act.cc 412 | @@ -44,7 +44,11 @@ uint8_t NFA_RW_TAG_SLP_REQ[] = {0x50, 0x00}; 413 | /* Local static function prototypes */ 414 | static tNFC_STATUS nfa_rw_start_ndef_read(void); 415 | static tNFC_STATUS nfa_rw_start_ndef_write(void); 416 | +#ifdef FUZZ 417 | +tNFC_STATUS nfa_rw_start_ndef_detection(void); 418 | +#else 419 | static tNFC_STATUS nfa_rw_start_ndef_detection(void); 420 | +#endif 421 | static tNFC_STATUS nfa_rw_config_tag_ro(bool b_hard_lock); 422 | static bool nfa_rw_op_req_while_busy(tNFA_RW_MSG* p_data); 423 | static bool nfa_rw_op_req_while_inactive(tNFA_RW_MSG* p_data); 424 | @@ -52,7 +56,11 @@ static void nfa_rw_error_cleanup(uint8_t event); 425 | static void nfa_rw_presence_check(tNFA_RW_MSG* p_data); 426 | static void nfa_rw_handle_t2t_evt(tRW_EVENT event, tRW_DATA* p_rw_data); 427 | static bool nfa_rw_detect_ndef(void); 428 | +#ifdef FUZZ 429 | +void nfa_rw_cback(tRW_EVENT event, tRW_DATA* p_rw_data); 430 | +#else 431 | static void nfa_rw_cback(tRW_EVENT event, tRW_DATA* p_rw_data); 432 | +#endif 433 | static void nfa_rw_handle_mfc_evt(tRW_EVENT event, tRW_DATA* p_rw_data); 434 | 435 | /******************************************************************************* 436 | @@ -230,6 +238,11 @@ static void nfa_rw_handle_ndef_detect(tRW_DATA* p_rw_data) { 437 | else 438 | nfa_rw_cb.flags &= ~NFA_RW_FL_TAG_IS_READONLY; 439 | 440 | +#ifdef FUZZ 441 | + //Give RW for reading 442 | + nfa_rw_cb.flags &= ~NFA_RW_FL_TAG_IS_READONLY; 443 | + nfa_rw_cb.detect_succeeded = true; 444 | +#endif 445 | /* Determine what operation triggered the NDEF detection procedure */ 446 | if (nfa_rw_cb.cur_op == NFA_RW_OP_READ_NDEF) { 447 | /* if ndef detection was done as part of ndef-read operation, then perform 448 | @@ -1492,7 +1505,11 @@ static void nfa_rw_handle_mfc_evt(tRW_EVENT event, tRW_DATA* p_rw_data) { 449 | ** Returns Nothing 450 | ** 451 | *******************************************************************************/ 452 | +#ifdef FUZZ 453 | +void nfa_rw_cback(tRW_EVENT event, tRW_DATA* p_rw_data) { 454 | +#else 455 | static void nfa_rw_cback(tRW_EVENT event, tRW_DATA* p_rw_data) { 456 | +#endif 457 | DLOG_IF(INFO, nfc_debug_enabled) 458 | << StringPrintf("nfa_rw_cback: event=0x%02x", event); 459 | 460 | @@ -1529,7 +1546,11 @@ static void nfa_rw_cback(tRW_EVENT event, tRW_DATA* p_rw_data) { 461 | ** Returns Nothing 462 | ** 463 | *******************************************************************************/ 464 | +#ifdef FUZZ 465 | +tNFC_STATUS nfa_rw_start_ndef_detection(void) { 466 | +#else 467 | static tNFC_STATUS nfa_rw_start_ndef_detection(void) { 468 | +#endif 469 | tNFC_PROTOCOL protocol = nfa_rw_cb.protocol; 470 | tNFC_STATUS status = NFC_STATUS_FAILED; 471 | 472 | @@ -1669,7 +1690,10 @@ static bool nfa_rw_detect_ndef() { 473 | static tNFC_STATUS nfa_rw_start_ndef_write(void) { 474 | tNFC_PROTOCOL protocol = nfa_rw_cb.protocol; 475 | tNFC_STATUS status = NFC_STATUS_FAILED; 476 | - 477 | +#ifdef FUZZ 478 | + //make it read write: 479 | + nfa_rw_cb.flags &= ~NFA_RW_FL_TAG_IS_READONLY; 480 | +#endif 481 | if (nfa_rw_cb.flags & NFA_RW_FL_TAG_IS_READONLY) { 482 | /* error: ndef tag is read-only */ 483 | status = NFC_STATUS_FAILED; 484 | @@ -1759,12 +1783,19 @@ static bool nfa_rw_read_ndef() { 485 | ** Returns TRUE (message buffer to be freed by caller) 486 | ** 487 | *******************************************************************************/ 488 | +#ifdef FUZZ 489 | +bool nfa_rw_write_ndef(tNFA_RW_MSG* p_data) { 490 | +#else 491 | static bool nfa_rw_write_ndef(tNFA_RW_MSG* p_data) { 492 | +#endif 493 | +#ifndef FUZZ 494 | tNDEF_STATUS ndef_status; 495 | +#endif 496 | tNFA_STATUS write_status = NFA_STATUS_OK; 497 | tNFA_CONN_EVT_DATA conn_evt_data; 498 | DLOG_IF(INFO, nfc_debug_enabled) << __func__; 499 | 500 | +#ifndef FUZZ 501 | /* Validate NDEF message */ 502 | ndef_status = NDEF_MsgValidate(p_data->op_req.params.write_ndef.p_data, 503 | p_data->op_req.params.write_ndef.len, false); 504 | @@ -1778,7 +1809,7 @@ static bool nfa_rw_write_ndef(tNFA_RW_MSG* p_data) { 505 | nfa_dm_act_conn_cback_notify(NFA_WRITE_CPLT_EVT, &conn_evt_data); 506 | return true; 507 | } 508 | - 509 | +#endif 510 | /* Store pointer to source NDEF */ 511 | nfa_rw_cb.p_ndef_wr_buf = p_data->op_req.params.write_ndef.p_data; 512 | nfa_rw_cb.ndef_wr_len = p_data->op_req.params.write_ndef.len; 513 | @@ -1948,7 +1979,11 @@ bool nfa_rw_presence_check_timeout(__attribute__((unused)) 514 | ** Returns Nothing 515 | ** 516 | *******************************************************************************/ 517 | +#ifdef FUZZ 518 | +void nfa_rw_format_tag() { 519 | +#else 520 | static void nfa_rw_format_tag() { 521 | +#endif 522 | tNFC_PROTOCOL protocol = nfa_rw_cb.protocol; 523 | tNFC_STATUS status = NFC_STATUS_FAILED; 524 | 525 | diff --git a/src/nfc/include/rw_int.h b/src/nfc/include/rw_int.h 526 | index f4027a5..bb2667b 100644 527 | --- a/src/nfc/include/rw_int.h 528 | +++ b/src/nfc/include/rw_int.h 529 | @@ -734,6 +734,9 @@ typedef struct { 530 | uint8_t* p_update_data; /* pointer of data to update */ 531 | uint16_t rw_length; /* bytes to read/write */ 532 | uint16_t rw_offset; /* offset to read/write */ 533 | +#ifdef FUZZ 534 | + bool idle; 535 | +#endif 536 | } tRW_I93_CB; 537 | 538 | /* RW memory control blocks */ 539 | diff --git a/src/nfc/nfc/nfc_main.cc b/src/nfc/nfc/nfc_main.cc 540 | index a1a2c7f..5d020d4 100644 541 | --- a/src/nfc/nfc/nfc_main.cc 542 | +++ b/src/nfc/nfc/nfc_main.cc 543 | @@ -744,7 +744,32 @@ void NFC_Init(tHAL_NFC_ENTRY* p_hal_entry_tbl) { 544 | llcp_init(); 545 | NFC_SET_MAX_CONN_DEFAULT(); 546 | } 547 | +#ifdef FUZZ 548 | +void NFC_Init_RW(tHAL_NFC_ENTRY* p_hal_entry_tbl) { 549 | + int xx; 550 | + 551 | + /* Clear nfc control block */ 552 | + memset(&nfc_cb, 0, sizeof(tNFC_CB)); 553 | 554 | + /* Reset the nfc control block */ 555 | + for (xx = 0; xx < NCI_MAX_CONN_CBS; xx++) { 556 | + nfc_cb.conn_cb[xx].conn_id = NFC_ILLEGAL_CONN_ID; 557 | + } 558 | + 559 | + /* NCI init */ 560 | + nfc_cb.p_hal = p_hal_entry_tbl; 561 | + nfc_cb.nfc_state = NFC_STATE_NONE; 562 | + nfc_cb.nci_cmd_window = NCI_MAX_CMD_WINDOW; 563 | + nfc_cb.nci_wait_rsp_tout = NFC_CMD_CMPL_TIMEOUT; 564 | + nfc_cb.p_disc_maps = nfc_interface_mapping; 565 | + nfc_cb.num_disc_maps = NFC_NUM_INTERFACE_MAP; 566 | + nfc_cb.nci_ctrl_size = NCI_CTRL_INIT_SIZE; 567 | + nfc_cb.reassembly = true; 568 | + nfc_cb.nci_version = NCI_VERSION_UNKNOWN; 569 | + rw_init(); 570 | + NFC_SET_MAX_CONN_DEFAULT(); 571 | +} 572 | +#endif 573 | /******************************************************************************* 574 | ** 575 | ** Function NFC_GetLmrtSize 576 | @@ -1063,7 +1088,11 @@ void NFC_SetReassemblyFlag(bool reassembly) { nfc_cb.reassembly = reassembly; } 577 | ** 578 | *******************************************************************************/ 579 | tNFC_STATUS NFC_SendData(uint8_t conn_id, NFC_HDR* p_data) { 580 | +#ifdef FUZZ 581 | + return NFC_STATUS_OK; 582 | +#endif 583 | tNFC_STATUS status = NFC_STATUS_FAILED; 584 | + 585 | tNFC_CONN_CB* p_cb = nfc_find_conn_cb_by_conn_id(conn_id); 586 | 587 | if (p_cb && p_data && 588 | diff --git a/src/nfc/nfc/nfc_ncif.cc b/src/nfc/nfc/nfc_ncif.cc 589 | index 462ddfe..017e3b6 100644 590 | --- a/src/nfc/nfc/nfc_ncif.cc 591 | +++ b/src/nfc/nfc/nfc_ncif.cc 592 | @@ -259,6 +259,9 @@ void nfc_ncif_check_cmd_queue(NFC_HDR* p_buf) { 593 | /* If there are commands waiting in the xmit queue, or if the controller 594 | * cannot accept any more commands, */ 595 | /* then enqueue this command */ 596 | +#ifdef FUZZ 597 | + return; 598 | +#endif 599 | if (p_buf) { 600 | if ((nfc_cb.nci_cmd_xmit_q.count) || (nfc_cb.nci_cmd_window == 0)) { 601 | GKI_enqueue(&nfc_cb.nci_cmd_xmit_q, p_buf); 602 | diff --git a/src/nfc/nfc/nfc_task.cc b/src/nfc/nfc/nfc_task.cc 603 | index 19bbb8c..7ca75b2 100644 604 | --- a/src/nfc/nfc/nfc_task.cc 605 | +++ b/src/nfc/nfc/nfc_task.cc 606 | @@ -58,6 +58,21 @@ extern bool nfc_debug_enabled; 607 | ** 608 | *******************************************************************************/ 609 | void nfc_start_timer(TIMER_LIST_ENT* p_tle, uint16_t type, uint32_t timeout) { 610 | +#ifdef FUZZ 611 | + /* if timer list is currently empty, start periodic GKI timer */ 612 | + if (nfc_cb.timer_queue.p_first == NULL) { 613 | + /* if timer starts on other than NFC task (scritp wrapper) */ 614 | + GKI_start_timer(NFC_TIMER_ID, GKI_SECS_TO_TICKS(1), true); 615 | + } 616 | + 617 | + GKI_remove_from_timer_list(&nfc_cb.timer_queue, p_tle); 618 | + 619 | + p_tle->event = type; 620 | + p_tle->ticks = timeout; /* Save the number of seconds for the timer */ 621 | + 622 | + GKI_add_to_timer_list(&nfc_cb.timer_queue, p_tle); 623 | +} 624 | +#else 625 | NFC_HDR* p_msg; 626 | 627 | /* if timer list is currently empty, start periodic GKI timer */ 628 | @@ -83,6 +98,7 @@ void nfc_start_timer(TIMER_LIST_ENT* p_tle, uint16_t type, uint32_t timeout) { 629 | 630 | GKI_add_to_timer_list(&nfc_cb.timer_queue, p_tle); 631 | } 632 | +#endif 633 | 634 | /******************************************************************************* 635 | ** 636 | @@ -175,8 +191,22 @@ void nfc_stop_timer(TIMER_LIST_ENT* p_tle) { 637 | *******************************************************************************/ 638 | void nfc_start_quick_timer(TIMER_LIST_ENT* p_tle, uint16_t type, 639 | uint32_t timeout) { 640 | - NFC_HDR* p_msg; 641 | +#ifdef FUZZ 642 | + /* if timer list is currently empty, start periodic GKI timer */ 643 | + if (nfc_cb.quick_timer_queue.p_first == nullptr) { 644 | + GKI_start_timer(NFC_QUICK_TIMER_ID, 645 | + ((GKI_SECS_TO_TICKS(1) / QUICK_TIMER_TICKS_PER_SEC)), 646 | + true); 647 | + } 648 | 649 | + GKI_remove_from_timer_list(&nfc_cb.quick_timer_queue, p_tle); 650 | + p_tle->event = type; 651 | + p_tle->ticks = timeout; /* Save the number of ticks for the timer */ 652 | + 653 | + GKI_add_to_timer_list(&nfc_cb.quick_timer_queue, p_tle); 654 | +} 655 | +#else 656 | + NFC_HDR* p_msg; 657 | /* if timer list is currently empty, start periodic GKI timer */ 658 | if (nfc_cb.quick_timer_queue.p_first == nullptr) { 659 | /* if timer starts on other than NFC task (scritp wrapper) */ 660 | @@ -194,14 +224,12 @@ void nfc_start_quick_timer(TIMER_LIST_ENT* p_tle, uint16_t type, 661 | true); 662 | } 663 | } 664 | - 665 | GKI_remove_from_timer_list(&nfc_cb.quick_timer_queue, p_tle); 666 | - 667 | p_tle->event = type; 668 | p_tle->ticks = timeout; /* Save the number of ticks for the timer */ 669 | - 670 | GKI_add_to_timer_list(&nfc_cb.quick_timer_queue, p_tle); 671 | } 672 | +#endif 673 | 674 | /******************************************************************************* 675 | ** 676 | @@ -332,6 +360,13 @@ void nfc_task_shutdown_nfcc(void) { 677 | } 678 | } 679 | 680 | +#ifdef FUZZ 681 | +//Reset the NFC controller 682 | +void reset_task() { 683 | + nfc_set_state(NFC_STATE_CORE_INIT); 684 | + nci_snd_core_reset(NCI_RESET_TYPE_RESET_CFG); 685 | +} 686 | +#endif 687 | /******************************************************************************* 688 | ** 689 | ** Function nfc_task 690 | diff --git a/src/nfc/tags/rw_t2t_ndef.cc b/src/nfc/tags/rw_t2t_ndef.cc 691 | index 707f86b..12d4199 100644 692 | --- a/src/nfc/tags/rw_t2t_ndef.cc 693 | +++ b/src/nfc/tags/rw_t2t_ndef.cc 694 | @@ -387,6 +387,32 @@ static void rw_t2t_handle_lock_read_rsp(uint8_t* p_data) { 695 | } 696 | } 697 | 698 | +#ifdef FUZZ 699 | +//converts uint8_t to one of the tlv states (see tags_defs.h) 700 | +static uint8_t num2tlv(uint8_t input) { 701 | + switch (input % 6) { 702 | + case 0: 703 | + return TAG_NULL_TLV; 704 | + case 1: 705 | + return TAG_LOCK_CTRL_TLV; 706 | + case 2: 707 | + return TAG_MEM_CTRL_TLV; 708 | + case 3: 709 | + return TAG_NDEF_TLV; 710 | + case 4: 711 | + return TAG_PROPRIETARY_TLV; 712 | + case 5: 713 | + return TAG_TERMINATOR_TLV; 714 | + default: 715 | + return TAG_NDEF_TLV; 716 | + } 717 | +} 718 | +#else 719 | +static uint8_t num2tlv(uint8_t input) { 720 | + return input; 721 | +} 722 | +#endif //FUZZ 723 | + 724 | /******************************************************************************* 725 | ** 726 | ** Function rw_t2t_handle_tlv_detect_rsp 727 | @@ -430,7 +456,7 @@ static void rw_t2t_handle_tlv_detect_rsp(uint8_t* p_data) { 728 | switch (p_t2t->substate) { 729 | case RW_T2T_SUBSTATE_WAIT_TLV_DETECT: 730 | /* Search for the tlv */ 731 | - p_t2t->found_tlv = p_data[offset++]; 732 | + p_t2t->found_tlv = num2tlv(p_data[offset++]); 733 | switch (p_t2t->found_tlv) { 734 | case TAG_NULL_TLV: /* May be used for padding. SHALL ignore this */ 735 | break; 736 | --------------------------------------------------------------------------------