Merge changes I264d0891,I1af733e7,Iae344c1e

* changes:
  Added init_ueventHandler_fuzzer
  Added init_property_fuzzer
  Added init_parser_fuzzer
This commit is contained in:
Treehugger Robot 2022-10-06 13:59:37 +00:00 committed by Gerrit Code Review
commit 71d9f3607b
5 changed files with 579 additions and 0 deletions

72
init/fuzzer/Android.bp Normal file
View File

@ -0,0 +1,72 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* 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.
*/
cc_defaults {
name: "libinit_defaults",
static_libs: [
"libc++fs",
"liblmkd_utils",
"libmodprobe",
"libprotobuf-cpp-lite",
"libpropertyinfoparser",
"libsnapshot_init",
"libinit",
],
shared_libs: [
"libbase",
"libfs_mgr",
"libhidl-gen-utils",
"libkeyutils",
"liblog",
"libprocessgroup",
"libselinux",
],
header_libs: ["libinit_headers"],
fuzz_config: {
cc: [
"android-media-fuzzing-reports@google.com",
],
componentid: 155276,
},
}
cc_fuzz {
name: "init_parser_fuzzer",
srcs: [
"init_parser_fuzzer.cpp",
],
shared_libs: ["libhidlmetadata",],
defaults: [
"libinit_defaults",
],
}
cc_fuzz {
name: "init_property_fuzzer",
srcs: [
"init_property_fuzzer.cpp",
],
defaults: ["libinit_defaults"],
}
cc_fuzz {
name: "init_ueventHandler_fuzzer",
srcs: [
"init_ueventHandler_fuzzer.cpp",
],
defaults: [
"libinit_defaults",
],
}

98
init/fuzzer/README.md Normal file
View File

@ -0,0 +1,98 @@
# Fuzzers for libinit
## Table of contents
+ [init_parser_fuzzer](#InitParser)
+ [init_property_fuzzer](#InitProperty)
+ [init_ueventHandler_fuzzer](#InitUeventHandler)
# <a name="InitParser"></a> Fuzzer for InitParser
InitParser supports the following parameters:
1. ValidPathNames (parameter name: "kValidPaths")
2. ValidParseInputs (parameter name: "kValidInputs")
| Parameter| Valid Values| Configured Value|
|------------- |-------------| ----- |
|`kValidPaths`| 0.`/system/etc/init/hw/init.rc`,<br/> 1.`/system/etc/init` |Value obtained from FuzzedDataProvider|
|`kValidInputs`| 0.`{"","cpu", "10", "10"}`,<br/> 1.`{"","RLIM_CPU", "10", "10"}`,<br/> 2.`{"","12", "unlimited", "10"}`,<br/> 3.`{"","13", "-1", "10"}`,<br/> 4.`{"","14", "10", "unlimited"}`,<br/> 5.`{"","15", "10", "-1"}` |Value obtained from FuzzedDataProvider|
#### Steps to run
1. Build the fuzzer
```
$ mm -j$(nproc) init_parser_fuzzer
```
2. Run on device
```
$ adb sync data
$ adb shell /data/fuzz/arm64/init_parser_fuzzer/init_parser_fuzzer
```
# <a name="InitProperty"></a> Fuzzer for InitProperty
InitProperty supports the following parameters:
PropertyType (parameter name: "PropertyType")
| Parameter| Valid Values |Configured Value|
|-------------|----------|----- |
|`PropertyType`| 0.`STRING`,<br/> 1.`BOOL`,<br/> 2.`INT`,<br/> 3.`UINT`,<br/> 4.`DOUBLE`,<br/> 5.`SIZE`,<br/>6.`ENUM`,<br/>7.`RANDOM`|Value obtained from FuzzedDataProvider|
#### Steps to run
1. Build the fuzzer
```
$ mm -j$(nproc) init_property_fuzzer
```
2. Run on device
```
$ adb sync data
$ adb shell /data/fuzz/arm64/init_property_fuzzer/init_property_fuzzer
```
# <a name="InitUeventHandler"></a> Fuzzer for InitUeventHandler
##### Maximize code coverage
The configuration parameters are not hardcoded, but instead selected based on
incoming data. This ensures more code paths are reached by the fuzzer.
InitUeventHandler supports the following parameters:
1. Major (parameter name: `major`)
2. Minor (parameter name: `minor`)
3. PartitionNum (parameter name: `partition_num`)
4. Uid (parameter name: `uid`)
5. Gid (parameter name: `gid`)
6. Action (parameter name: `action`)
7. Path (parameter name: `path`)
8. Subsystem (parameter name: `subsystem`)
9. PartitionName (parameter name: `partition_name`)
10. DeviceName (parameter name: `device_name`)
11. Modalias (parameter name: `modalias`)
12. DevPath (parameter name: `devPath`)
13. HandlerPath (parameter name: `handlerPath`)
| Parameter| Valid Values| Configured Value|
|------------- |-------------| ----- |
| `major` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
| `minor` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
| `partition_num ` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
| `uid` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
| `gid` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
| `action` | `String` | Value obtained from FuzzedDataProvider|
| `path` | `String` | Value obtained from FuzzedDataProvider|
| `subsystem` | `String` | Value obtained from FuzzedDataProvider|
| `partition_name` | `String` | Value obtained from FuzzedDataProvider|
| `device_name` | `String` | Value obtained from FuzzedDataProvider|
| `modalias` | `String` | Value obtained from FuzzedDataProvider|
| `devPath` | `String` | Value obtained from FuzzedDataProvider|
| `handlerPath` | `String` | Value obtained from FuzzedDataProvider|
This also ensures that the plugin is always deterministic for any given input.
#### Steps to run
1. Build the fuzzer
```
$ mm -j$(nproc) init_ueventHandler_fuzzer
```
2. Run on device
```
$ adb sync data
$ adb shell /data/fuzz/arm64/init_ueventHandler_fuzzer/init_ueventHandler_fuzzer
```

View File

@ -0,0 +1,146 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* 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 <fuzzer/FuzzedDataProvider.h>
#include <hidl/metadata.h>
#include <import_parser.h>
#include <interface_utils.h>
#include <rlimit_parser.h>
using namespace android;
using namespace android::init;
const std::vector<std::string> kValidInputs[] = {
{"", "cpu", "10", "10"}, {"", "RLIM_CPU", "10", "10"}, {"", "12", "unlimited", "10"},
{"", "13", "-1", "10"}, {"", "14", "10", "unlimited"}, {"", "15", "10", "-1"},
};
const std::string kValidPaths[] = {
"/system/etc/init/hw/init.rc",
"/system/etc/init",
};
const int32_t kMaxBytes = 256;
const std::string kValidInterfaces = "android.frameworks.vr.composer@2.0::IVrComposerClient";
class InitParserFuzzer {
public:
InitParserFuzzer(const uint8_t* data, size_t size) : fdp_(data, size){};
void Process();
private:
void InvokeParser();
void InvokeLimitParser();
void InvokeInterfaceUtils();
InterfaceInheritanceHierarchyMap GenerateHierarchyMap();
std::vector<HidlInterfaceMetadata> GenerateInterfaceMetadata();
FuzzedDataProvider fdp_;
};
void InitParserFuzzer::InvokeLimitParser() {
if (fdp_.ConsumeBool()) {
std::vector<std::string> input;
input.push_back("");
input.push_back(fdp_.ConsumeRandomLengthString(kMaxBytes));
input.push_back(fdp_.ConsumeRandomLengthString(kMaxBytes));
input.push_back(fdp_.ConsumeRandomLengthString(kMaxBytes));
ParseRlimit(input);
} else {
ParseRlimit(fdp_.PickValueInArray(kValidInputs));
}
}
std::vector<HidlInterfaceMetadata> InitParserFuzzer::GenerateInterfaceMetadata() {
std::vector<HidlInterfaceMetadata> random_interface;
for (size_t idx = 0; idx < fdp_.ConsumeIntegral<size_t>(); ++idx) {
HidlInterfaceMetadata metadata;
metadata.name = fdp_.ConsumeRandomLengthString(kMaxBytes);
for (size_t idx1 = 0; idx1 < fdp_.ConsumeIntegral<size_t>(); ++idx1) {
metadata.inherited.push_back(fdp_.ConsumeRandomLengthString(kMaxBytes));
}
random_interface.push_back(metadata);
}
return random_interface;
}
InterfaceInheritanceHierarchyMap InitParserFuzzer::GenerateHierarchyMap() {
InterfaceInheritanceHierarchyMap result;
std::vector<HidlInterfaceMetadata> random_interface;
if (fdp_.ConsumeBool()) {
random_interface = GenerateInterfaceMetadata();
} else {
random_interface = HidlInterfaceMetadata::all();
}
for (const HidlInterfaceMetadata& iface : random_interface) {
std::set<FQName> inherited_interfaces;
for (const std::string& intf : iface.inherited) {
FQName fqname;
(void)fqname.setTo(intf);
inherited_interfaces.insert(fqname);
}
FQName fqname;
(void)fqname.setTo(iface.name);
result[fqname] = inherited_interfaces;
}
return result;
}
void InitParserFuzzer::InvokeInterfaceUtils() {
InterfaceInheritanceHierarchyMap hierarchy_map = GenerateHierarchyMap();
SetKnownInterfaces(hierarchy_map);
IsKnownInterface(fdp_.ConsumeRandomLengthString(kMaxBytes));
std::set<std::string> interface_set;
for (size_t idx = 0; idx < fdp_.ConsumeIntegral<size_t>(); ++idx) {
auto set_interface_values = fdp_.PickValueInArray<const std::function<void()>>({
[&]() {
interface_set.insert(("aidl/" + fdp_.ConsumeRandomLengthString(kMaxBytes)));
},
[&]() { interface_set.insert(fdp_.ConsumeRandomLengthString(kMaxBytes)); },
[&]() { interface_set.insert(kValidInterfaces); },
});
set_interface_values();
}
CheckInterfaceInheritanceHierarchy(interface_set, hierarchy_map);
}
void InitParserFuzzer::InvokeParser() {
Parser parser;
std::string name = fdp_.ConsumeBool() ? fdp_.ConsumeRandomLengthString(kMaxBytes) : "import";
parser.AddSectionParser(name, std::make_unique<ImportParser>(&parser));
std::string path = fdp_.ConsumeBool() ? fdp_.PickValueInArray(kValidPaths)
: fdp_.ConsumeRandomLengthString(kMaxBytes);
parser.ParseConfig(path);
parser.ParseConfigFileInsecure(path);
}
void InitParserFuzzer::Process() {
while (fdp_.remaining_bytes()) {
auto invoke_parser_fuzzer = fdp_.PickValueInArray<const std::function<void()>>({
[&]() { InvokeParser(); },
[&]() { InvokeInterfaceUtils(); },
[&]() { InvokeLimitParser(); },
});
invoke_parser_fuzzer();
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
InitParserFuzzer init_parser_fuzzer(data, size);
init_parser_fuzzer.Process();
return 0;
}

View File

@ -0,0 +1,140 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* 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 <persistent_properties.h>
#include <property_type.h>
#include <sys/stat.h>
#include <fstream>
#include "fuzzer/FuzzedDataProvider.h"
using namespace android;
using namespace android::init;
using android::init::persistent_property_filename;
const std::string kTempDir = "/data/local/tmp/";
const std::string kFuzzerPropertyFile = kTempDir + "persistent_properties";
constexpr int32_t kMaxPropertyLength = 10;
const std::string kPrefix = "persist.";
const std::string kPropertyName = kPrefix + "sys.timezone";
const std::string kPropertyValue = "America/Los_Angeles";
const std::string kLegacyPropertyFile = "/data/property/persist.properties";
const std::string kSizeSuffix[3] = {"g", "k", "m"};
constexpr int32_t kMinNumStrings = 1;
constexpr int32_t kMaxNumStrings = 10;
enum PropertyType { STRING, BOOL, INT, UINT, DOUBLE, SIZE, ENUM, RANDOM, kMaxValue = RANDOM };
class InitPropertyFuzzer {
public:
InitPropertyFuzzer(const uint8_t* data, size_t size) : fdp_(data, size){};
void process();
private:
void InvokeCheckType();
void InvokeWritePersistentProperty();
void RemoveFiles();
void CreateFuzzerPropertyFile(const std::string property_file);
FuzzedDataProvider fdp_;
};
void InitPropertyFuzzer::InvokeCheckType() {
std::string property_type;
std::string value;
int type = fdp_.ConsumeEnum<PropertyType>();
switch (type) {
case STRING:
value = fdp_.ConsumeRandomLengthString(kMaxPropertyLength);
property_type = "string";
break;
case BOOL:
value = fdp_.ConsumeBool();
property_type = "bool";
break;
case INT:
value = fdp_.ConsumeIntegral<int>();
property_type = "int";
break;
case UINT:
value = fdp_.ConsumeIntegral<uint_t>();
property_type = "uint";
break;
case DOUBLE:
value = fdp_.ConsumeFloatingPoint<double>();
property_type = "double";
break;
case SIZE:
value = fdp_.ConsumeIntegral<uint_t>();
value = value.append(fdp_.PickValueInArray(kSizeSuffix));
property_type = "size";
break;
case ENUM:
value = fdp_.ConsumeIntegral<uint_t>();
property_type = "enum";
break;
case RANDOM:
value = fdp_.ConsumeRandomLengthString(kMaxPropertyLength);
property_type = fdp_.ConsumeRandomLengthString(kMaxPropertyLength);
break;
}
CheckType(property_type, value);
}
void InitPropertyFuzzer::InvokeWritePersistentProperty() {
if (fdp_.ConsumeBool()) {
WritePersistentProperty(kPropertyName, kPropertyValue);
} else {
WritePersistentProperty((kPrefix + fdp_.ConsumeRandomLengthString(kMaxPropertyLength)),
fdp_.ConsumeRandomLengthString(kMaxPropertyLength));
}
}
void InitPropertyFuzzer::RemoveFiles() {
remove(kFuzzerPropertyFile.c_str());
remove(kLegacyPropertyFile.c_str());
}
void InitPropertyFuzzer::CreateFuzzerPropertyFile(const std::string property_file) {
std::ofstream out;
out.open(property_file, std::ios::binary | std::ofstream::trunc);
chmod(property_file.c_str(), S_IRWXU);
const int32_t numStrings = fdp_.ConsumeIntegralInRange(kMinNumStrings, kMaxNumStrings);
for (int32_t i = 0; i < numStrings; ++i) {
out << fdp_.ConsumeRandomLengthString(kMaxPropertyLength) << "\n";
}
out.close();
}
void InitPropertyFuzzer::process() {
persistent_property_filename = kFuzzerPropertyFile;
/* Property and legacy files are created using createFuzzerPropertyFile() and */
/* are used in the below APIs. Hence createFuzzerPropertyFile() is not a part */
/* of the lambda construct. */
CreateFuzzerPropertyFile(kFuzzerPropertyFile);
CreateFuzzerPropertyFile(kLegacyPropertyFile);
auto property_type = fdp_.PickValueInArray<const std::function<void()>>({
[&]() { InvokeCheckType(); },
[&]() { InvokeWritePersistentProperty(); },
[&]() { LoadPersistentProperties(); },
});
property_type();
RemoveFiles();
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
InitPropertyFuzzer initPropertyFuzzer(data, size);
initPropertyFuzzer.process();
return 0;
}

View File

@ -0,0 +1,123 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* 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 <devices.h>
#include <firmware_handler.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <modalias_handler.h>
#include <sys/stat.h>
#include <util.h>
#include <fstream>
using namespace android;
using namespace android::init;
constexpr int32_t kMaxBytes = 100;
constexpr int32_t kMaxSize = 1000;
constexpr int32_t kMinSize = 1;
/*'HandleUevent' prefixes the path with '/sys' and hence this is required to point
* to'/data/local/tmp' dir.*/
const std::string kPath = "/../data/local/tmp/";
const std::string kPathPrefix = "/..";
void MakeFile(FuzzedDataProvider* fdp, std::string s) {
std::ofstream out;
out.open(s, std::ios::binary | std::ofstream::trunc);
for (int32_t idx = 0; idx < fdp->ConsumeIntegralInRange(kMinSize, kMaxSize); ++idx) {
out << fdp->ConsumeRandomLengthString(kMaxBytes) << "\n";
}
out.close();
}
void CreateDir(std::string Directory, FuzzedDataProvider* fdp) {
std::string tmp = Directory.substr(kPathPrefix.length());
mkdir_recursive(android::base::Dirname(tmp.c_str()),
S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
MakeFile(fdp, tmp + "/data");
MakeFile(fdp, tmp + "/loading");
}
std::string SelectRandomString(FuzzedDataProvider* fdp, std::string s) {
if (fdp->ConsumeBool()) {
if (fdp->ConsumeBool()) {
return fdp->ConsumeRandomLengthString(kMaxBytes);
} else {
return s;
}
}
return "";
}
Uevent CreateUevent(FuzzedDataProvider* fdp) {
Uevent uevent;
uevent.action = SelectRandomString(fdp, "add");
uevent.subsystem = SelectRandomString(fdp, "firmware");
uevent.path = SelectRandomString(fdp, kPath + fdp->ConsumeRandomLengthString(kMaxBytes));
uevent.firmware = fdp->ConsumeBool() ? fdp->ConsumeRandomLengthString(kMaxBytes) : "";
uevent.partition_name = fdp->ConsumeBool() ? fdp->ConsumeRandomLengthString(kMaxBytes) : "";
uevent.device_name = fdp->ConsumeBool() ? fdp->ConsumeRandomLengthString(kMaxBytes) : "";
uevent.modalias = fdp->ConsumeBool() ? fdp->ConsumeRandomLengthString(kMaxBytes) : "";
uevent.partition_num = fdp->ConsumeIntegral<int32_t>();
uevent.major = fdp->ConsumeIntegral<int32_t>();
uevent.minor = fdp->ConsumeIntegral<int32_t>();
return uevent;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
FuzzedDataProvider fdp(data, size);
while (fdp.remaining_bytes()) {
auto invoke_uevent_handler_fuzzer = fdp.PickValueInArray<const std::function<void()>>({
[&]() {
std::vector<std::string> modalias_vector;
for (size_t idx = 0;
idx < fdp.ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize); ++idx) {
modalias_vector.push_back(fdp.ConsumeRandomLengthString(kMaxBytes));
}
ModaliasHandler modalias_handler = ModaliasHandler(modalias_vector);
modalias_handler.HandleUevent(CreateUevent(&fdp));
},
[&]() {
std::vector<ExternalFirmwareHandler> external_handlers;
std::vector<std::string> firmware_directories;
for (size_t idx = 0;
idx < fdp.ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize); ++idx) {
std::string devPath = fdp.ConsumeRandomLengthString(kMaxBytes);
uid_t uid = fdp.ConsumeIntegral<uid_t>();
gid_t gid = fdp.ConsumeIntegral<gid_t>();
std::string handlerPath = fdp.ConsumeRandomLengthString(kMaxBytes);
ExternalFirmwareHandler externalFirmwareHandler =
ExternalFirmwareHandler(devPath, uid, gid, handlerPath);
external_handlers.push_back(externalFirmwareHandler);
firmware_directories.push_back(fdp.ConsumeRandomLengthString(kMaxBytes));
}
FirmwareHandler firmware_handler =
FirmwareHandler(firmware_directories, external_handlers);
Uevent uevent = CreateUevent(&fdp);
if (fdp.ConsumeBool() && uevent.path.size() != 0 &&
uevent.path.find(kPath) == 0) {
CreateDir(uevent.path, &fdp);
firmware_handler.HandleUevent(uevent);
std::string s = uevent.path.substr(kPathPrefix.length());
remove(s.c_str());
} else {
firmware_handler.HandleUevent(uevent);
}
},
});
invoke_uevent_handler_fuzzer();
}
return 0;
}