blob: 9b4853f298758fb415905bbffc9748f74edac9c1 [file] [log] [blame]
// Copyright 2016 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cobalt/media/sandbox/fuzzer_app.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "starboard/common/string.h"
#include "starboard/configuration_constants.h"
#include "starboard/directory.h"
namespace cobalt {
namespace media {
namespace sandbox {
FuzzerApp::FuzzerApp() : number_of_iterations_(-1) {}
bool FuzzerApp::Init(int argc, char* argv[], double min_ratio,
double max_ratio) {
file_entries_.clear();
int initial_seed;
if (ParseInitialSeedAndNumberOfIterations(argc, argv, &initial_seed)) {
CollectFiles(argv[argc - 1], min_ratio, max_ratio, initial_seed);
}
return !file_entries_.empty() && number_of_iterations_ > 0;
}
void FuzzerApp::RunFuzzingLoop() {
DCHECK_GT(number_of_iterations_, 0);
for (int i = 0; i < number_of_iterations_; ++i) {
for (FileEntries::iterator iter = file_entries_.begin();
iter != file_entries_.end(); ++iter) {
LOG(INFO) << "Fuzzing \"" << iter->first << "\" "
<< "with seed " << iter->second.fuzzer.seed();
Fuzz(iter->first, iter->second.fuzzer.GetFuzzedContent());
iter->second.fuzzer.AdvanceSeed();
}
}
}
const std::vector<uint8>& FuzzerApp::GetFileContent(
const std::string& filename) const {
FileEntries::const_iterator iter = file_entries_.find(filename);
DCHECK(iter != file_entries_.end());
return iter->second.file_content;
}
bool FuzzerApp::ParseInitialSeedAndNumberOfIterations(int argc, char* argv[],
int* initial_seed) {
DCHECK(initial_seed);
*initial_seed = ZzufFuzzer::kSeedForOriginalContent;
if (argc != 3 && argc != 4) {
LOG(ERROR) << "Usage: " << argv[0]
<< " [initial seed (non-negative integer)]"
<< " <number of iterations>"
<< " <file name|directory name contains files to be fuzzed>";
LOG(ERROR) << "For example: " << argv[0] << " 200000 /data/video-files";
LOG(ERROR) << " " << argv[0] << " 115 200000 /data/video-files";
return false;
}
if (argc == 3) {
*initial_seed = ZzufFuzzer::kSeedForOriginalContent;
number_of_iterations_ = strtol(argv[1], NULL, 10);
if (number_of_iterations_ <= 0) {
LOG(ERROR) << "Invalid 'number of iterations' " << argv[1];
return false;
}
} else {
DCHECK_EQ(argc, 4);
*initial_seed = strtol(argv[1], NULL, 10);
if (*initial_seed < 0) {
LOG(ERROR) << "Invalid 'initial seed' " << argv[1];
return false;
}
number_of_iterations_ = strtol(argv[2], NULL, 10);
if (number_of_iterations_ <= 0) {
LOG(ERROR) << "Invalid 'number of iterations' " << argv[2];
return false;
}
}
return true;
}
void FuzzerApp::CollectFiles(const std::string& path_name, double min_ratio,
double max_ratio, int initial_seed) {
file_entries_.clear();
SbDirectory directory = SbDirectoryOpen(path_name.c_str(), NULL);
if (!SbDirectoryIsValid(directory)) {
// Assuming it is a file.
AddFile(path_name, min_ratio, max_ratio, initial_seed);
return;
}
#if SB_API_VERSION >= 12
std::vector<char> entry(kSbFileMaxName);
while (SbDirectoryGetNext(directory, entry.data(), entry.size())) {
std::string file_name = path_name + kSbFileSepString + entry.data();
AddFile(file_name, min_ratio, max_ratio, initial_seed);
}
#else // SB_API_VERSION >= 12
SbDirectoryEntry entry;
while (SbDirectoryGetNext(directory, &entry)) {
std::string file_name = path_name + kSbFileSepString + entry.name;
AddFile(file_name, min_ratio, max_ratio, initial_seed);
}
#endif // SB_API_VERSION >= 12
SbDirectoryClose(directory);
}
void FuzzerApp::AddFile(const std::string& file_name, double min_ratio,
double max_ratio, int initial_seed) {
LOG(INFO) << "Loading " << file_name;
std::string content;
if (!base::ReadFileToString(base::FilePath(file_name), &content)) {
LOG(ERROR) << "Failed to load file " << file_name;
return;
}
if (content.empty()) {
LOG(ERROR) << file_name << " is empty";
return;
}
std::vector<uint8> uint8_content(content.begin(), content.end());
std::vector<uint8> parsed_content =
ParseFileContent(file_name, uint8_content);
if (parsed_content.empty()) {
return;
}
file_entries_.insert(
std::make_pair(file_name, FileEntry(uint8_content, parsed_content,
min_ratio, max_ratio, initial_seed)));
}
FuzzerApp::FileEntry::FileEntry(const std::vector<uint8>& file_content,
const std::vector<uint8>& fuzz_content,
double min_ratio, double max_ratio,
int initial_seed)
: file_content(file_content),
fuzzer(fuzz_content, min_ratio, max_ratio, initial_seed) {}
} // namespace sandbox
} // namespace media
} // namespace cobalt