blob: d2ab09adbdb3c0b73b9a70974fa1ed2e694c9977 [file] [log] [blame]
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -07001// Copyright 2018 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -07005#include <memory>
6#include <utility>
7
Qijiang Fan713061e2021-03-08 15:45:12 +09008#include <base/check.h>
hscham1574c7e2020-10-13 12:40:01 +09009#include <base/json/json_reader.h>
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070010#include <base/strings/string_number_conversions.h>
hscham1574c7e2020-10-13 12:40:01 +090011#include <base/values.h>
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070012
Xiaochu Liue61e1d62018-11-12 13:20:09 -080013#include "imageloader/manifest.h"
14
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070015namespace imageloader {
16
17namespace {
18// The current version of the manifest file.
19constexpr int kCurrentManifestVersion = 1;
20// The name of the version field in the manifest.
21constexpr char kManifestVersionField[] = "manifest-version";
22// The name of the component version field in the manifest.
23constexpr char kVersionField[] = "version";
24// The name of the field containing the image hash.
25constexpr char kImageHashField[] = "image-sha256-hash";
26// The name of the bool field indicating whether component is removable.
27constexpr char kIsRemovableField[] = "is-removable";
28// The name of the metadata field.
29constexpr char kMetadataField[] = "metadata";
30// The name of the field containing the table hash.
31constexpr char kTableHashField[] = "table-sha256-hash";
Colin Howesdc15ba22018-12-12 11:02:42 -080032// Optional manifest fields.
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070033constexpr char kFSType[] = "fs-type";
Colin Howesdc15ba22018-12-12 11:02:42 -080034constexpr char kId[] = "id";
Amin Hassani0badef12019-03-18 17:08:02 -070035constexpr char kPackage[] = "package";
Colin Howesdc15ba22018-12-12 11:02:42 -080036constexpr char kName[] = "name";
37constexpr char kImageType[] = "image-type";
38constexpr char kPreallocatedSize[] = "pre-allocated-size";
39constexpr char kSize[] = "size";
Jae Hoon Kim81d2b6d2020-01-06 16:09:32 -080040constexpr char kPreloadAllowed[] = "preload-allowed";
Jae Hoon Kim99ee2732020-06-25 15:59:35 -070041constexpr char kMountFileRequired[] = "mount-file-required";
Amin Hassani192c59a2020-04-13 15:11:04 -070042constexpr char kUsedBy[] = "used-by";
Amin Hassanib7c20d62020-04-23 23:14:53 -070043constexpr char kDescription[] = "description";
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070044
45bool GetSHA256FromString(const std::string& hash_str,
46 std::vector<uint8_t>* bytes) {
47 if (!base::HexStringToBytes(hash_str, bytes))
48 return false;
49 return bytes->size() == 32;
50}
51
52// Ensure the metadata entry is a dictionary mapping strings to strings and
53// parse it into |out_metadata| and return true if so.
hscham1574c7e2020-10-13 12:40:01 +090054bool ParseMetadata(const base::Value& metadata_dict,
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070055 std::map<std::string, std::string>* out_metadata) {
56 DCHECK(out_metadata);
57
hscham1574c7e2020-10-13 12:40:01 +090058 if (!metadata_dict.is_dict()) {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070059 return false;
hscham1574c7e2020-10-13 12:40:01 +090060 }
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070061
hscham1574c7e2020-10-13 12:40:01 +090062 for (const auto& item : metadata_dict.DictItems()) {
63 if (!item.second.is_string()) {
64 LOG(ERROR) << "Key \"" << item.first << "\" did not map to string value";
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070065 return false;
66 }
67
hscham1574c7e2020-10-13 12:40:01 +090068 (*out_metadata)[item.first] = item.second.GetString();
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070069 }
70
71 return true;
72}
73
74} // namespace
75
Ben Chan791bee22018-09-27 12:54:21 -070076Manifest::Manifest()
Xiaochu Liud9d853a2019-01-23 12:54:18 -080077 : manifest_version_(0),
78 fs_type_(FileSystem::kExt4),
Jae Hoon Kim9c012ac2020-02-03 17:37:49 -080079 preallocated_size_(0),
80 size_(0),
Xiaochu Liud9d853a2019-01-23 12:54:18 -080081 is_removable_(false) {}
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070082
83bool Manifest::ParseManifest(const std::string& manifest_raw) {
84 // Now deserialize the manifest json and read out the rest of the component.
hscham1574c7e2020-10-13 12:40:01 +090085 auto manifest_value = base::JSONReader::ReadAndReturnValueWithError(
86 manifest_raw, base::JSON_PARSE_RFC);
87 if (!manifest_value.value) {
hschamab8d1db2020-12-02 14:45:20 +090088 LOG(ERROR) << "Could not parse the manifest file as JSON. Error: "
hscham1574c7e2020-10-13 12:40:01 +090089 << manifest_value.error_message;
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070090 return false;
91 }
92
hscham1574c7e2020-10-13 12:40:01 +090093 if (!manifest_value.value->is_dict()) {
94 LOG(ERROR) << "Manifest file is not dictionary.";
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070095 return false;
96 }
hscham1574c7e2020-10-13 12:40:01 +090097 base::Value manifest_dict = std::move(*manifest_value.value);
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070098
99 // This will have to be changed if the manifest version is bumped.
hscham1574c7e2020-10-13 12:40:01 +0900100 base::Optional<int> manifest_version =
101 manifest_dict.FindIntKey(kManifestVersionField);
102 if (!manifest_version.has_value()) {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700103 LOG(ERROR) << "Could not parse manifest version field from manifest.";
104 return false;
105 }
hscham1574c7e2020-10-13 12:40:01 +0900106 if (manifest_version != kCurrentManifestVersion) {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700107 LOG(ERROR) << "Unsupported version of the manifest.";
108 return false;
109 }
hscham1574c7e2020-10-13 12:40:01 +0900110 manifest_version_ = *manifest_version;
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700111
hscham1574c7e2020-10-13 12:40:01 +0900112 const std::string* image_hash_str =
113 manifest_dict.FindStringKey(kImageHashField);
114 if (!image_hash_str) {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700115 LOG(ERROR) << "Could not parse image hash from manifest.";
116 return false;
117 }
118
hscham1574c7e2020-10-13 12:40:01 +0900119 if (!GetSHA256FromString(*image_hash_str, &(image_sha256_))) {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700120 LOG(ERROR) << "Could not convert image hash to bytes.";
121 return false;
122 }
123
hscham1574c7e2020-10-13 12:40:01 +0900124 const std::string* table_hash_str =
125 manifest_dict.FindStringKey(kTableHashField);
126 if (table_hash_str == nullptr) {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700127 LOG(ERROR) << "Could not parse table hash from manifest.";
128 return false;
129 }
130
hscham1574c7e2020-10-13 12:40:01 +0900131 if (!GetSHA256FromString(*table_hash_str, &(table_sha256_))) {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700132 LOG(ERROR) << "Could not convert table hash to bytes.";
133 return false;
134 }
135
hscham1574c7e2020-10-13 12:40:01 +0900136 const std::string* version = manifest_dict.FindStringKey(kVersionField);
137 if (!version) {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700138 LOG(ERROR) << "Could not parse component version from manifest.";
139 return false;
140 }
hscham1574c7e2020-10-13 12:40:01 +0900141 version_ = *version;
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700142
143 // The fs_type field is optional, and squashfs by default.
hscham1574c7e2020-10-13 12:40:01 +0900144 const std::string* fs_type = manifest_dict.FindStringKey(kFSType);
145 if (fs_type) {
146 if (*fs_type == "ext4") {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700147 fs_type_ = FileSystem::kExt4;
hscham1574c7e2020-10-13 12:40:01 +0900148 } else if (*fs_type == "squashfs") {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700149 fs_type_ = FileSystem::kSquashFS;
150 } else {
hscham1574c7e2020-10-13 12:40:01 +0900151 LOG(ERROR) << "Unsupported file system type: " << *fs_type;
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700152 return false;
153 }
hscham1574c7e2020-10-13 12:40:01 +0900154 } else {
155 fs_type_ = FileSystem::kSquashFS;
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700156 }
157
hscham1574c7e2020-10-13 12:40:01 +0900158 base::Optional<bool> is_removable =
159 manifest_dict.FindBoolKey(kIsRemovableField);
160 // If |is-removable| field does not exist, by default it is false.
161 is_removable_ = is_removable.value_or(false);
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700162
hscham1574c7e2020-10-13 12:40:01 +0900163 base::Optional<bool> preload_allowed =
164 manifest_dict.FindBoolKey(kPreloadAllowed);
165 // If |preaload-allowed| field does not exist, by default it is false.
166 preload_allowed_ = preload_allowed.value_or(false);
Jae Hoon Kim81d2b6d2020-01-06 16:09:32 -0800167
hscham1574c7e2020-10-13 12:40:01 +0900168 base::Optional<bool> mount_file_required =
169 manifest_dict.FindBoolKey(kMountFileRequired);
170 // If 'mount-file-required' field does not exist, by default it is false.
171 mount_file_required_ = mount_file_required.value_or(false);
Jae Hoon Kim99ee2732020-06-25 15:59:35 -0700172
Colin Howesdc15ba22018-12-12 11:02:42 -0800173 // All of these fields are optional.
hscham1574c7e2020-10-13 12:40:01 +0900174 const std::string* id = manifest_dict.FindStringKey(kId);
175 if (id)
176 id_ = *id;
177 const std::string* package = manifest_dict.FindStringKey(kPackage);
178 if (package)
179 package_ = *package;
180 const std::string* name = manifest_dict.FindStringKey(kName);
181 if (name)
182 name_ = *name;
183 const std::string* image_type = manifest_dict.FindStringKey(kImageType);
184 if (image_type)
185 image_type_ = *image_type;
186 const std::string* used_by = manifest_dict.FindStringKey(kUsedBy);
187 if (used_by)
188 used_by_ = *used_by;
189 const std::string* description = manifest_dict.FindStringKey(kDescription);
190 if (description)
191 description_ = *description;
Jae Hoon Kim9c012ac2020-02-03 17:37:49 -0800192
hscham1574c7e2020-10-13 12:40:01 +0900193 const std::string* preallocated_size_str =
194 manifest_dict.FindStringKey(kPreallocatedSize);
195 if (preallocated_size_str) {
196 if (!base::StringToInt64(*preallocated_size_str, &preallocated_size_)) {
Jae Hoon Kim9c012ac2020-02-03 17:37:49 -0800197 LOG(ERROR) << "Manifest pre-allocated-size was malformed: "
hscham1574c7e2020-10-13 12:40:01 +0900198 << *preallocated_size_str;
Jae Hoon Kim9c012ac2020-02-03 17:37:49 -0800199 return false;
200 }
201 }
202
hscham1574c7e2020-10-13 12:40:01 +0900203 const std::string* size_str = manifest_dict.FindStringKey(kSize);
204 if (size_str) {
205 if (!base::StringToInt64(*size_str, &size_)) {
206 LOG(ERROR) << "Manifest size was malformed: " << *size_str;
Jae Hoon Kim9c012ac2020-02-03 17:37:49 -0800207 return false;
208 }
209 }
Colin Howesdc15ba22018-12-12 11:02:42 -0800210
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700211 // Copy out the metadata, if it's there.
hscham1574c7e2020-10-13 12:40:01 +0900212 const base::Value* metadata = manifest_dict.FindKey(kMetadataField);
213 if (metadata) {
214 if (!ParseMetadata(*metadata, &metadata_)) {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700215 LOG(ERROR) << "Manifest metadata was malformed";
216 return false;
217 }
218 }
219
220 return true;
221}
222
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700223} // namespace imageloader