Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 90a9393e authored by Yifan Hong's avatar Yifan Hong
Browse files

libsnapshot_fuzzer: use protobuf

Use protobuf because it already has all the fuzzing implemenetations.
Delete fuzz_utils.

Pros:
- Fuzzing protobuf is faster; it is easy to achieve 4K exec/s
- It is more guided; protobufs are fuzzed using mutators, and mutators
  should have better knowledge of the structure of the fuzz data
- No more hand-written parsing code of the fuzz data. That code in
  fuzz_utils.h is deleted.
- Corpus data can be reused even after adding new fields in the protobuf
- Corpus data is human-readable and easily manually written (it is
  the text format of the protobuf)

Cons:
- The "actions" are "declared" in protobuf definition and "defined" in
  C++, so there's more boilerplate to write. Adding a new "Action"
  requires changes in both.

Test: run libsnapshot_fuzzer
Bug: 154633114
Change-Id: Idc2a6b2c087e370e4cfef53142a244b9b275389e
parent 5eb2d6fa
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -254,9 +254,11 @@ cc_fuzz {

    native_coverage : true,
    srcs: [
        // Compile the protobuf definition again with type full.
        "android/snapshot/snapshot_fuzz.proto",
        "fuzz_utils.cpp",
        "snapshot_fuzz.cpp",
        "snapshot_fuzz_utils.cpp",
        "fuzz_utils.cpp",
    ],
    static_libs: [
        "libbase",
@@ -269,12 +271,16 @@ cc_fuzz {
        "liblp",
        "libsnapshot_init", // don't use binder or hwbinder
        "libsnapshot_test_helpers",
        "libprotobuf-cpp-lite",
        "libprotobuf-mutator",
        "update_metadata-protos",
    ],
    header_libs: [
        "libstorage_literals_headers",
    ],
    proto: {
        type: "full",
        canonical_path_from_root: false,
    },

    fuzz_config: {
        cc: ["android-virtual-ab+bugs@google.com"],
+76 −0
Original line number Diff line number Diff line
// Copyright (C) 2020 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.

syntax = "proto3";
package android.snapshot;

// Controls the behavior of IDeviceInfo.
// Next: 6
message FuzzDeviceInfoData {
    bool slot_suffix_is_a = 1;
    bool is_overlayfs_setup = 2;
    bool allow_set_boot_control_merge_status = 3;
    bool allow_set_slot_as_unbootable = 4;
    bool is_recovery = 5;
}

// Controls the behavior of the test SnapshotManager.
// Next: 2
message FuzzSnapshotManagerData {
    bool is_local_image_manager = 1;
}

// Mimics the API of ISnapshotManager. Defines one action on the snapshot
// manager.
// Next: 18
message SnapshotManagerActionProto {
    message NoArgs {}
    message ProcessUpdateStateArgs {
        bool has_before_cancel = 1;
        bool fail_before_cancel = 2;
    }
    reserved 7;
    reserved "create_update_snapshots";
    reserved 8;
    reserved "map_update_snapshot";
    reserved 9;
    reserved "unmap_update_snapshot";
    reserved 11;
    reserved "create_logical_and_snapshot_partitions";
    reserved 14;
    reserved "recovery_create_snapshot_devices_with_metadata";
    oneof value {
        NoArgs begin_update = 1;
        NoArgs cancel_update = 2;
        bool finished_snapshot_writes = 3;
        NoArgs initiate_merge = 4;
        ProcessUpdateStateArgs process_update_state = 5;
        bool get_update_state = 6;
        NoArgs need_snapshots_in_first_stage_mount = 10;
        bool handle_imminent_data_wipe = 12;
        NoArgs recovery_create_snapshot_devices = 13;
        NoArgs dump = 15;
        NoArgs ensure_metadata_mounted = 16;
        NoArgs get_snapshot_merge_stats_instance = 17;
    }
}

// Includes all data that needs to be fuzzed.
message SnapshotFuzzData {
    FuzzDeviceInfoData device_info_data = 1;
    FuzzSnapshotManagerData manager_data = 2;
    // More data used to prep the test before running actions.
    reserved 3 to 9999;
    repeated SnapshotManagerActionProto actions = 10000;
}
+2 −2
Original line number Diff line number Diff line
@@ -18,8 +18,8 @@ build_normal() (

build_cov() {
    pushd $(gettop)
    ret=$?
    NATIVE_COVERAGE="true" NATIVE_LINE_COVERAGE="true" COVERAGE_PATHS="${PROJECT_PATH}" m ${FUZZ_TARGET}
    ret=$?
    popd
    return ${ret}
}
@@ -46,7 +46,7 @@ prepare_host() {
}

# run_snapshot_fuzz -runs=10000
generate_corpse() {
generate_corpus() {
    [[ "$@" ]] || { echo "run with -runs=X"; return 1; }

    prepare_device &&
+13 −0
Original line number Diff line number Diff line
@@ -22,4 +22,17 @@ void CheckInternal(bool value, std::string_view msg) {
    CHECK(value) << msg;
}

const google::protobuf::OneofDescriptor* GetProtoValueDescriptor(
        const google::protobuf::Descriptor* action_desc) {
    CHECK(action_desc);
    CHECK(action_desc->oneof_decl_count() == 1)
            << action_desc->oneof_decl_count() << " oneof fields found in " << action_desc->name()
            << "; only one is expected.";
    auto* oneof_value_desc = action_desc->oneof_decl(0);
    CHECK(oneof_value_desc);
    CHECK(oneof_value_desc->name() == "value")
            << "oneof field has name " << oneof_value_desc->name();
    return oneof_value_desc;
}

}  // namespace android::fuzz
+202 −216

File changed.

Preview size limit exceeded, changes collapsed.

Loading