Skip to content

Commit

Permalink
Add Fuzz testing for Desk Templates
Browse files Browse the repository at this point in the history
Adds round trip fuzz testing for desk templates.

TESED: desk_template_fuzzer
Bug: b/228367971
Change-Id: I16d2c120d072bb7d2113afff76e9be9206de2877
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4804063
Commit-Queue: Avynn Donaghe <avynn@google.com>
Reviewed-by: Yanzhu Du <yzd@google.com>
Cr-Commit-Position: refs/heads/main@{#1187466}
  • Loading branch information
avynn authored and Chromium LUCI CQ committed Aug 23, 2023
1 parent 8e6b882 commit af8cfb9
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 54 deletions.
17 changes: 17 additions & 0 deletions components/desks_storage/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import("//third_party/libprotobuf-mutator/fuzzable_proto_library.gni")

static_library("desks_storage") {
output_name = "desks_storage_lib"

Expand Down Expand Up @@ -102,3 +104,18 @@ source_set("unit_tests") {
"//ui/gfx/range",
]
}

if (use_libfuzzer) {
fuzzer_test("desk_template_fuzzer") {
sources = [ "core/desk_template_fuzzer.cc" ]
seed_corpus = "fuzzer_corpus"
deps = [
":desks_storage",
":test_support",
"//components/account_id",
"//components/services/app_service",
"//components/sync:test_support",
"//third_party/libprotobuf-mutator",
]
}
}
72 changes: 72 additions & 0 deletions components/desks_storage/core/desk_template_fuzzer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/json/json_string_value_serializer.h"
#include "components/account_id/account_id.h"
#include "components/desks_storage/core/desk_template_conversion.h"
#include "components/desks_storage/core/desk_template_util.h"
#include "components/desks_storage/core/desk_test_util.h"
#include "components/services/app_service/public/cpp/app_registry_cache.h"
#include "components/sync/protocol/workspace_desk_specifics.pb.h"
#include "testing/libfuzzer/proto/lpm_interface.h"

namespace desks_storage {

// Attempts to parse proto from fuzz data, if succeeds verifies semantic
// equivalency between the various formats.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// parse string into value.
std::string str = std::string(reinterpret_cast<const char*>(data), size);
std::string error_message;
int error_code;
std::unique_ptr<base::Value> desk_template_value =
JSONStringValueDeserializer(str).Deserialize(&error_code, &error_message);

if (desk_template_value == nullptr) {
return 0;
}

// Init dependencies for conversion.
AccountId account_id;
std::unique_ptr<apps::AppRegistryCache> apps_cache =
std::make_unique<apps::AppRegistryCache>();
desk_test_util::PopulateAppRegistryCache(account_id, apps_cache.get());

desk_template_conversion::ParseSavedDeskResult desk_template_result =
desk_template_conversion::ParseDeskTemplateFromBaseValue(
*desk_template_value, ash::DeskTemplateSource::kUser);

if (!desk_template_result.has_value()) {
return 0;
}

std::unique_ptr<ash::DeskTemplate> desk_template =
std::move(desk_template_result.value());

// Round trip for sync protos.
sync_pb::WorkspaceDeskSpecifics template_to_proto =
desk_template_conversion::ToSyncProto(desk_template.get(),
apps_cache.get());
std::unique_ptr<ash::DeskTemplate> proto_to_template =
desk_template_conversion::FromSyncProto(template_to_proto);

CHECK(desk_template_util::AreDeskTemplatesEqual(desk_template.get(),
proto_to_template.get()));

// Round trip for JSON format.
base::Value template_to_value =
desk_template_conversion::SerializeDeskTemplateAsBaseValue(
desk_template.get(), apps_cache.get());
desk_template_conversion::ParseSavedDeskResult parse_result =
desk_template_conversion::ParseDeskTemplateFromBaseValue(
template_to_value, desk_template->source());

CHECK(parse_result.has_value());
CHECK(desk_template_util::AreDeskTemplatesEqual(desk_template.get(),
parse_result.value().get()));

return 0;
}

} // namespace desks_storage
53 changes: 53 additions & 0 deletions components/desks_storage/core/desk_template_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,59 @@ ash::DeskTemplate* FindOtherEntryWithName(
return iter->second.get();
}

bool AreDeskTemplatesEqual(const ash::DeskTemplate* template_one,
const ash::DeskTemplate* template_two) {
// confirm metadata is equal.
if (template_one->uuid() != template_two->uuid() ||
template_one->source() != template_two->source() ||
template_one->created_time() != template_two->created_time() ||
template_one->GetLastUpdatedTime() !=
template_two->GetLastUpdatedTime() ||
template_one->should_launch_on_startup() !=
template_two->should_launch_on_startup()) {
return false;
}

if (template_one->uuid() != template_two->uuid() ||
template_one->source() != template_two->source() ||
template_one->created_time() != template_two->created_time() ||
template_one->GetLastUpdatedTime() !=
template_two->GetLastUpdatedTime()) {
return false;
}

const auto* restore_data_one = template_one->desk_restore_data();
const auto* restore_data_two = template_two->desk_restore_data();

// iterate over each app, confirm its in the other's list.
for (const auto& launch_list_one :
restore_data_one->app_id_to_launch_list()) {
const auto& launch_list_two_iter =
restore_data_two->app_id_to_launch_list().find(launch_list_one.first);
if (launch_list_two_iter ==
restore_data_two->app_id_to_launch_list().end()) {
return false;
}
const auto& launch_list_two_app = launch_list_two_iter->second;

// iterate over each window, confirm its in the other's list.
for (const auto& restore_window_one : launch_list_one.second) {
const auto& restore_window_two_iter =
launch_list_two_app.find(restore_window_one.first);
if (restore_window_two_iter == launch_list_two_app.end()) {
return false;
}

// Compare app restore data structs.
if (*restore_window_one.second != *restore_window_two_iter->second) {
return false;
}
}
}

return true;
}

} // namespace desk_template_util

} // namespace desks_storage
3 changes: 3 additions & 0 deletions components/desks_storage/core/desk_template_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ ash::DeskTemplate* FindOtherEntryWithName(
const base::flat_map<base::Uuid, std::unique_ptr<ash::DeskTemplate>>&
entries);

bool AreDeskTemplatesEqual(const ash::DeskTemplate* template_one,
const ash::DeskTemplate* template_two);

} // namespace desks_storage::desk_template_util

#endif // COMPONENTS_DESKS_STORAGE_CORE_DESK_TEMPLATE_UTIL_H_
56 changes: 2 additions & 54 deletions components/desks_storage/core/local_desk_data_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -139,59 +139,6 @@ std::string StorageLocationToDirName(
}
}

bool AreDeskTemplatesEqual(const ash::DeskTemplate* template_one,
const ash::DeskTemplate* template_two) {
// confirm metadata is equal.
if (template_one->uuid() != template_two->uuid() ||
template_one->source() != template_two->source() ||
template_one->created_time() != template_two->created_time() ||
template_one->GetLastUpdatedTime() !=
template_two->GetLastUpdatedTime() ||
template_one->should_launch_on_startup() !=
template_two->should_launch_on_startup()) {
return false;
}

if (template_one->uuid() != template_two->uuid() ||
template_one->source() != template_two->source() ||
template_one->created_time() != template_two->created_time() ||
template_one->GetLastUpdatedTime() !=
template_two->GetLastUpdatedTime()) {
return false;
}

const auto* restore_data_one = template_one->desk_restore_data();
const auto* restore_data_two = template_two->desk_restore_data();

// iterate over each app, confirm its in the other's list.
for (const auto& launch_list_one :
restore_data_one->app_id_to_launch_list()) {
const auto& launch_list_two_iter =
restore_data_two->app_id_to_launch_list().find(launch_list_one.first);
if (launch_list_two_iter ==
restore_data_two->app_id_to_launch_list().end()) {
return false;
}
const auto& launch_list_two_app = launch_list_two_iter->second;

// iterate over each window, confirm its in the other's list.
for (const auto& restore_window_one : launch_list_one.second) {
const auto& restore_window_two_iter =
launch_list_two_app.find(restore_window_one.first);
if (restore_window_two_iter == launch_list_two_app.end()) {
return false;
}

// Compare app restore data structs.
if (*restore_window_one.second != *restore_window_two_iter->second) {
return false;
}
}
}

return true;
}

} // namespace

LocalDeskDataManager::LocalDeskDataManager(
Expand Down Expand Up @@ -512,7 +459,8 @@ void LocalDeskDataManager::UpdateEntry(
return;
// Make sure that there are actually new contents, otherwise don't bother
// the io thread.
} else if (AreDeskTemplatesEqual(entry.get(), old_entry->second.get())) {
} else if (desk_template_util::AreDeskTemplatesEqual(
entry.get(), old_entry->second.get())) {
last_update_status_ = UpdateEntryStatus::kDuplicate;
return;
}
Expand Down
46 changes: 46 additions & 0 deletions components/desks_storage/fuzzer_corpus/example1
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"auto_launch_on_startup": false,
"version": 1,
"uuid": "040b6112-67f2-4d3c-8ba8-53a117272eba",
"name": "BrowserTest",
"created_time_usec": "1633535632",
"updated_time_usec": "1633535632",
"desk_type": "TEMPLATE",
"desk": {
"apps": [
{
"window_bound": {
"left": 0,
"top": 1,
"height": 121,
"width": 120
},
"window_state": "NORMAL",
"z_index": 1,
"app_type": "BROWSER",
"tabs": [
{
"url": "https://example.com/"
},
{
"url": "https://example.com/2"
}
],
"tab_groups": [
{
"first_index": 1,
"last_index": 2,
"title": "sample_tab_group",
"color": "GREY",
"is_collapsed": false
}
],
"active_tab_index": 1,
"first_non_pinned_tab_index": 1,
"window_id": 0,
"display_id": "100",
"event_flag": 0
}
]
}
}
1 change: 1 addition & 0 deletions components/desks_storage/fuzzer_corpus/example2
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"auto_launch_on_startup": false,"version":1,"uuid":"040b6112-67f2-4d3c-8ba8-53a117272eba","name":"BrowserTest","created_time_usec":"1633535632","updated_time_usec":"1633535632","desk_type":"TEMPLATE","desk":{"apps":[{"window_bound":{"left":0,"top":1,"height":121,"width":120},"window_state":"MINIMIZED","z_index":1,"app_type":"BROWSER","tabs":[{"url":"https://example.com/"},{"url":"https://example.com/2"}],"tab_groups":[{"first_index":1,"last_index":2,"title":"sample_tab_group","color":"GREY","is_collapsed":false}],"active_tab_index":1,"first_non_pinned_tab_index":1,"window_id":0,"display_id":"100","event_flag":0,"pre_minimized_window_state":"NORMAL"}]}}
1 change: 1 addition & 0 deletions components/desks_storage/fuzzer_corpus/example3
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"auto_launch_on_startup": false,"version":1,"uuid":"7f4b7ff0-970a-41bb-aa91-f6c3e2724207","name":"ChromeAppTest","created_time_usec":"1633535632000","updated_time_usec": "1633535632","desk_type":"SAVE_AND_RECALL","desk":{"apps":[{"window_bound":{"left":200,"top":200,"height":1000,"width":1000},"window_state":"PRIMARY_SNAPPED","z_index":2,"app_type":"CHROME_APP","app_id":"test_chrome_app_1","window_id":0,"display_id":"100","event_flag":0, "snap_percent":75,"override_url":"https://example.com/"},{"window_bound":{"left":0,"top":0,"height":120,"width":120},"window_state":"NORMAL","z_index":1,"app_type":"CHROME_APP","app_id":"test_pwa_app_1","window_id":1,"display_id":"100","event_flag":0,"override_url":"https://example.com/"}]}}

0 comments on commit af8cfb9

Please sign in to comment.