mirror of https://github.com/google/oss-fuzz.git
146 lines
4.4 KiB
JavaScript
146 lines
4.4 KiB
JavaScript
// Copyright 2023 Google LLC
|
|
//
|
|
// 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.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
const { FuzzedDataProvider } = require('@jazzer.js/core');
|
|
const ProtoBuf = require('./src/index');
|
|
const fs = require('fs');
|
|
|
|
module.exports.fuzz = function(data) {
|
|
try {
|
|
const provider = new FuzzedDataProvider(data);
|
|
if (provider._remainingBytes < 512) { return; }
|
|
const root = new ProtoBuf.Root();
|
|
const filePath = "fuzz.proto";
|
|
fs.writeFileSync(filePath, Buffer.from(provider.consumeBytes(provider.consumeIntegralInRange(1, 512))));
|
|
|
|
// Load the protobuf schema from the temporary file
|
|
root.loadSync(filePath);
|
|
|
|
fuzzLoadSync(root, provider);
|
|
fuzzDefine(root, provider);
|
|
fuzzLookupType(root, provider);
|
|
fuzzEncode(root, provider);
|
|
fuzzDecode(root, provider);
|
|
|
|
fs.unlinkSync(filePath);
|
|
} catch (error) {
|
|
if (!ignoredError(error)) throw error;
|
|
}
|
|
};
|
|
|
|
function ignoredError(error) {
|
|
return !!ignored.find((message) => error.message.indexOf(message) !== -1);
|
|
}
|
|
|
|
const ignored = [
|
|
"illegal",
|
|
"Unexpected",
|
|
"The value of",
|
|
"must be",
|
|
"duplicate"
|
|
];
|
|
|
|
// Fuzz the Root#loadSync method
|
|
function fuzzLoadSync(root, provider) {
|
|
const filePath = provider.consumeString();
|
|
root.loadSync(filePath);
|
|
}
|
|
|
|
// Fuzz the Root#define method
|
|
function fuzzDefine(root, provider) {
|
|
const length = provider.consumeIntegralInRange(1, 64);
|
|
const typeName = provider.consumeString(length);
|
|
const definition = provider.consumeString(provider.consumeIntegralInRange(1, 64));
|
|
root.define(typeName, definition);
|
|
}
|
|
|
|
// Fuzz the Root#lookupType method
|
|
function fuzzLookupType(root, provider) {
|
|
const typeName = provider.consumeString(provider.consumeIntegralInRange(1, 64));
|
|
root.lookupType(typeName);
|
|
}
|
|
|
|
// Fuzz the Message#encode method
|
|
function fuzzEncode(root, provider) {
|
|
const typeName = provider.consumeString();
|
|
const message = root.create(typeName);
|
|
|
|
// Construct the input for the message instance manually
|
|
const input = constructInputForEncode(message.$type, provider);
|
|
message.set(input);
|
|
|
|
message.encode();
|
|
}
|
|
|
|
// Construct the input for the message instance manually
|
|
function constructInputForEncode(type, provider) {
|
|
const input = {};
|
|
|
|
for (const field of type.fieldsArray) {
|
|
const fieldName = field.name;
|
|
const fieldType = field.resolvedType;
|
|
|
|
if (fieldType && fieldType instanceof ProtoBuf.Type && !field.repeated) {
|
|
// Recursively construct input for nested message types
|
|
const nestedInput = constructInputForEncode(fieldType, provider);
|
|
input[fieldName] = nestedInput;
|
|
} else {
|
|
// Consume a value from the provider for non-nested fields
|
|
const value = consumeValueForField(field, provider);
|
|
input[fieldName] = value;
|
|
}
|
|
}
|
|
|
|
return input;
|
|
}
|
|
|
|
// Consume a value from the provider for non-nested fields
|
|
function consumeValueForField(field, provider) {
|
|
switch (field.type) {
|
|
case "double":
|
|
case "float":
|
|
return provider.consumeFloat();
|
|
case "int32":
|
|
case "uint32":
|
|
case "sint32":
|
|
case "fixed32":
|
|
case "sfixed32":
|
|
return provider.consumeIntegral(provider.consumeIntegralInRange(0, 4), provider.consumeBool());
|
|
case "int64":
|
|
case "uint64":
|
|
case "sint64":
|
|
case "fixed64":
|
|
case "sfixed64":
|
|
return provider.consumeBigIntegral(provider.consumeIntegralInRange(0, 4), provider.consumeBool());
|
|
case "bool":
|
|
return provider.consumeBool();
|
|
case "string":
|
|
return provider.consumeString(provider.consumeIntegralInRange(0, 64));
|
|
case "bytes":
|
|
return provider.consumeBytes(provider.consumeIntegralInRange(0, 64));
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// Fuzz the Message#decode method
|
|
function fuzzDecode(root, provider) {
|
|
const typeName = provider.consumeString(provider.consumeIntegralInRange(0, 64));
|
|
const buffer = provider.consumeRemainingAsBytes();
|
|
root.lookupType(typeName).decode(buffer);
|
|
}
|
|
|