| /* Copyright 2020 Google Inc. |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| #include "phonenumbers/phonenumbermatcher.h" |
| #include <string> |
| #include <vector> |
| #include <limits> |
| #include <unicode/unistr.h> |
| |
| #include "phonenumbers/base/basictypes.h" |
| #include "phonenumbers/base/memory/scoped_ptr.h" |
| #include "phonenumbers/base/memory/singleton.h" |
| #include "phonenumbers/default_logger.h" |
| #include "phonenumbers/phonenumber.h" |
| #include "phonenumbers/phonenumbermatch.h" |
| #include "phonenumbers/phonenumberutil.h" |
| #include "phonenumbers/stringutil.h" |
| #include "phonenumbers/asyoutypeformatter.h" |
| #include "phonenumbers/shortnumberinfo.h" |
| #include <fuzzer/FuzzedDataProvider.h> |
| |
| using google::protobuf::RepeatedPtrField; |
| |
| // consume PhoneNumberUtil::PhoneNumberType from libfuzzer data |
| i18n::phonenumbers::PhoneNumberUtil::PhoneNumberType ConsumePhoneNumberType( |
| FuzzedDataProvider& fuzzed_data) { |
| switch (fuzzed_data.ConsumeIntegralInRange(0, 11)) { |
| case 0: |
| return i18n::phonenumbers::PhoneNumberUtil::FIXED_LINE; |
| case 1: |
| return i18n::phonenumbers::PhoneNumberUtil::MOBILE; |
| case 2: |
| return i18n::phonenumbers::PhoneNumberUtil::FIXED_LINE_OR_MOBILE; |
| case 3: |
| return i18n::phonenumbers::PhoneNumberUtil::TOLL_FREE; |
| case 4: |
| return i18n::phonenumbers::PhoneNumberUtil::PREMIUM_RATE; |
| case 5: |
| return i18n::phonenumbers::PhoneNumberUtil::SHARED_COST; |
| case 6: |
| return i18n::phonenumbers::PhoneNumberUtil::VOIP; |
| case 7: |
| return i18n::phonenumbers::PhoneNumberUtil::PERSONAL_NUMBER; |
| case 8: |
| return i18n::phonenumbers::PhoneNumberUtil::PAGER; |
| case 9: |
| return i18n::phonenumbers::PhoneNumberUtil::UAN; |
| case 10: |
| return i18n::phonenumbers::PhoneNumberUtil::VOICEMAIL; |
| default: |
| return i18n::phonenumbers::PhoneNumberUtil::UNKNOWN; |
| } |
| } |
| |
| // consume PhoneNumberUtil::PhoneNumberFormat from libfuzzer data |
| i18n::phonenumbers::PhoneNumberUtil::PhoneNumberFormat ConsumePhoneNumberFormat( |
| FuzzedDataProvider& fuzzed_data) { |
| switch (fuzzed_data.ConsumeIntegralInRange(0, 3)) { |
| case 0: |
| return i18n::phonenumbers::PhoneNumberUtil::E164; |
| case 1: |
| return i18n::phonenumbers::PhoneNumberUtil::INTERNATIONAL; |
| case 2: |
| return i18n::phonenumbers::PhoneNumberUtil::NATIONAL; |
| default: |
| return i18n::phonenumbers::PhoneNumberUtil::RFC3966; |
| } |
| } |
| |
| extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
| // initialize the phone util |
| i18n::phonenumbers::PhoneNumberUtil* phone_util = |
| i18n::phonenumbers::PhoneNumberUtil::GetInstance(); |
| FuzzedDataProvider fuzzed_data(data, size); |
| |
| // initialize the first phone number, region and country calling code |
| i18n::phonenumbers::PhoneNumber phone_number; |
| bool region_is_2_bytes = fuzzed_data.ConsumeBool(); |
| std::string region = fuzzed_data.ConsumeBytesAsString(region_is_2_bytes ? 2 : 3); |
| std::string number = fuzzed_data.ConsumeRandomLengthString(32); |
| int country_calling_code = fuzzed_data.ConsumeIntegral<int>(); |
| |
| // trigger either one of the public parse methods |
| if (fuzzed_data.ConsumeBool()) { |
| phone_util->ParseAndKeepRawInput(number, region, &phone_number); |
| } else { |
| phone_util->Parse(number, region, &phone_number); |
| } |
| |
| // initialize the second phone number, this is used only for the |
| // isNumberMatch* methods |
| i18n::phonenumbers::PhoneNumber phone_number2; |
| std::string number2 = fuzzed_data.ConsumeRandomLengthString(32); |
| if (fuzzed_data.ConsumeBool()) { |
| phone_util->ParseAndKeepRawInput(number2, region, &phone_number2); |
| } else { |
| phone_util->Parse(number2, region, &phone_number2); |
| } |
| |
| // randomly trigger the truncate method, this may affect state of the input |
| // for the method calls that follow it |
| if (fuzzed_data.ConsumeIntegralInRange(0, 10) == 5) { |
| phone_util->TruncateTooLongNumber(&phone_number); |
| } |
| |
| // fuzz public methods |
| phone_util->IsAlphaNumber(number); |
| phone_util->IsPossibleNumber(phone_number); |
| phone_util->IsNumberMatch(phone_number, phone_number2); |
| phone_util->IsNumberMatchWithOneString(phone_number, number2); |
| phone_util->IsNumberMatchWithTwoStrings(number, number2); |
| phone_util->CanBeInternationallyDialled(phone_number); |
| phone_util->GetNumberType(phone_number); |
| phone_util->GetLengthOfGeographicalAreaCode(phone_number); |
| phone_util->GetLengthOfNationalDestinationCode(phone_number); |
| phone_util->IsNANPACountry(region); |
| phone_util->GetCountryCodeForRegion(region); |
| phone_util->IsPossibleNumberForString(number, region); |
| phone_util->IsNumberGeographical(phone_number); |
| i18n::phonenumbers::PhoneNumberUtil::PhoneNumberType number_type = |
| ConsumePhoneNumberType(fuzzed_data); |
| phone_util->IsNumberGeographical(number_type, country_calling_code); |
| phone_util->IsPossibleNumberForType(phone_number, number_type); |
| |
| i18n::phonenumbers::PhoneNumber example_number; |
| phone_util->GetExampleNumberForType(region, number_type, &example_number); |
| |
| i18n::phonenumbers::PhoneNumber example_number_2; |
| phone_util->GetExampleNumberForType(number_type, &example_number_2); |
| |
| i18n::phonenumbers::PhoneNumber invalid_number; |
| phone_util->GetInvalidExampleNumber(region, &invalid_number); |
| |
| i18n::phonenumbers::PhoneNumber non_geo_number; |
| phone_util->GetExampleNumberForNonGeoEntity(country_calling_code, &non_geo_number); |
| |
| std::string output; |
| phone_util->GetCountryMobileToken(country_calling_code, &output); |
| output.clear(); |
| |
| phone_util->GetRegionCodeForNumber(phone_number, &output); |
| output.clear(); |
| |
| phone_util->GetNddPrefixForRegion(region, fuzzed_data.ConsumeBool(), &output); |
| output.clear(); |
| |
| // Fuzz the methods which affect the input string, but not the PhoneNumber object |
| std::string input = fuzzed_data.ConsumeRandomLengthString(32); |
| phone_util->ConvertAlphaCharactersInNumber(&input); |
| input.clear(); |
| |
| input = fuzzed_data.ConsumeRandomLengthString(32); |
| phone_util->NormalizeDigitsOnly(&input); |
| input.clear(); |
| |
| input = fuzzed_data.ConsumeRandomLengthString(32); |
| phone_util->NormalizeDiallableCharsOnly(&input); |
| input.clear(); |
| |
| // Fuzz the formatting methods |
| i18n::phonenumbers::PhoneNumberUtil::PhoneNumberFormat format = ConsumePhoneNumberFormat(fuzzed_data); |
| |
| std::string formatted; |
| phone_util->Format(phone_number, format, &formatted); |
| formatted.clear(); |
| |
| phone_util->FormatInOriginalFormat(phone_number, region, &formatted); |
| formatted.clear(); |
| |
| phone_util->FormatNumberForMobileDialing(phone_number, region, |
| fuzzed_data.ConsumeBool(), &formatted); |
| formatted.clear(); |
| |
| phone_util->FormatNationalNumberWithPreferredCarrierCode(phone_number, region, &formatted); |
| formatted.clear(); |
| |
| phone_util->FormatOutOfCountryKeepingAlphaChars(phone_number, region, &formatted); |
| formatted.clear(); |
| |
| std::string carrier = fuzzed_data.ConsumeRandomLengthString(8); |
| phone_util->FormatNationalNumberWithCarrierCode(phone_number, carrier, &formatted); |
| formatted.clear(); |
| |
| // setup the parameters for FormatByPattern |
| i18n::phonenumbers::PhoneNumberUtil::PhoneNumberFormat number_format = ConsumePhoneNumberFormat(fuzzed_data); |
| RepeatedPtrField<i18n::phonenumbers::NumberFormat> number_formats; |
| i18n::phonenumbers::NumberFormat* temp_number_format = number_formats.Add(); |
| std::string pattern = fuzzed_data.ConsumeRandomLengthString(16); |
| std::string format_string = fuzzed_data.ConsumeRandomLengthString(16); |
| temp_number_format->set_pattern(pattern); |
| temp_number_format->set_format(format_string); |
| |
| // fuzz FormatByPattern |
| phone_util->FormatByPattern(phone_number, number_format, number_formats, &formatted); |
| formatted.clear(); |
| |
| return 0; |
| } |