blob: ce6f97f455491fc3e31f21babd94278bba9a80e6 [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
hscham1574c7e2020-10-13 12:40:01 +09008#include <base/json/json_reader.h>
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -07009#include <base/strings/string_number_conversions.h>
hscham1574c7e2020-10-13 12:40:01 +090010#include <base/values.h>
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070011
Xiaochu Liue61e1d62018-11-12 13:20:09 -080012#include "imageloader/manifest.h"
13
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070014namespace imageloader {
15
16namespace {
17// The current version of the manifest file.
18constexpr int kCurrentManifestVersion = 1;
19// The name of the version field in the manifest.
20constexpr char kManifestVersionField[] = "manifest-version";
21// The name of the component version field in the manifest.
22constexpr char kVersionField[] = "version";
23// The name of the field containing the image hash.
24constexpr char kImageHashField[] = "image-sha256-hash";
25// The name of the bool field indicating whether component is removable.
26constexpr char kIsRemovableField[] = "is-removable";
27// The name of the metadata field.
28constexpr char kMetadataField[] = "metadata";
29// The name of the field containing the table hash.
30constexpr char kTableHashField[] = "table-sha256-hash";
Colin Howesdc15ba22018-12-12 11:02:42 -080031// Optional manifest fields.
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070032constexpr char kFSType[] = "fs-type";
Colin Howesdc15ba22018-12-12 11:02:42 -080033constexpr char kId[] = "id";
Amin Hassani0badef12019-03-18 17:08:02 -070034constexpr char kPackage[] = "package";
Colin Howesdc15ba22018-12-12 11:02:42 -080035constexpr char kName[] = "name";
36constexpr char kImageType[] = "image-type";
37constexpr char kPreallocatedSize[] = "pre-allocated-size";
38constexpr char kSize[] = "size";
Jae Hoon Kim81d2b6d2020-01-06 16:09:32 -080039constexpr char kPreloadAllowed[] = "preload-allowed";
Jae Hoon Kim99ee2732020-06-25 15:59:35 -070040constexpr char kMountFileRequired[] = "mount-file-required";
Amin Hassani192c59a2020-04-13 15:11:04 -070041constexpr char kUsedBy[] = "used-by";
Amin Hassanib7c20d62020-04-23 23:14:53 -070042constexpr char kDescription[] = "description";
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070043
44bool GetSHA256FromString(const std::string& hash_str,
45 std::vector<uint8_t>* bytes) {
46 if (!base::HexStringToBytes(hash_str, bytes))
47 return false;
48 return bytes->size() == 32;
49}
50
51// Ensure the metadata entry is a dictionary mapping strings to strings and
52// parse it into |out_metadata| and return true if so.
hscham1574c7e2020-10-13 12:40:01 +090053bool ParseMetadata(const base::Value& metadata_dict,
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070054 std::map<std::string, std::string>* out_metadata) {
55 DCHECK(out_metadata);
56
hscham1574c7e2020-10-13 12:40:01 +090057 if (!metadata_dict.is_dict()) {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070058 return false;
hscham1574c7e2020-10-13 12:40:01 +090059 }
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070060
hscham1574c7e2020-10-13 12:40:01 +090061 for (const auto& item : metadata_dict.DictItems()) {
62 if (!item.second.is_string()) {
63 LOG(ERROR) << "Key \"" << item.first << "\" did not map to string value";
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070064 return false;
65 }
66
hscham1574c7e2020-10-13 12:40:01 +090067 (*out_metadata)[item.first] = item.second.GetString();
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070068 }
69
70 return true;
71}
72
73} // namespace
74
Ben Chan791bee22018-09-27 12:54:21 -070075Manifest::Manifest()
Xiaochu Liud9d853a2019-01-23 12:54:18 -080076 : manifest_version_(0),
77 fs_type_(FileSystem::kExt4),
Jae Hoon Kim9c012ac2020-02-03 17:37:49 -080078 preallocated_size_(0),
79 size_(0),
Xiaochu Liud9d853a2019-01-23 12:54:18 -080080 is_removable_(false) {}
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070081
82bool Manifest::ParseManifest(const std::string& manifest_raw) {
83 // Now deserialize the manifest json and read out the rest of the component.
hscham1574c7e2020-10-13 12:40:01 +090084 auto manifest_value = base::JSONReader::ReadAndReturnValueWithError(
85 manifest_raw, base::JSON_PARSE_RFC);
86 if (!manifest_value.value) {
hschamab8d1db2020-12-02 14:45:20 +090087 LOG(ERROR) << "Could not parse the manifest file as JSON. Error: "
hscham1574c7e2020-10-13 12:40:01 +090088 << manifest_value.error_message;
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070089 return false;
90 }
91
hscham1574c7e2020-10-13 12:40:01 +090092 if (!manifest_value.value->is_dict()) {
93 LOG(ERROR) << "Manifest file is not dictionary.";
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070094 return false;
95 }
hscham1574c7e2020-10-13 12:40:01 +090096 base::Value manifest_dict = std::move(*manifest_value.value);
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -070097
98 // This will have to be changed if the manifest version is bumped.
hscham1574c7e2020-10-13 12:40:01 +090099 base::Optional<int> manifest_version =
100 manifest_dict.FindIntKey(kManifestVersionField);
101 if (!manifest_version.has_value()) {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700102 LOG(ERROR) << "Could not parse manifest version field from manifest.";
103 return false;
104 }
hscham1574c7e2020-10-13 12:40:01 +0900105 if (manifest_version != kCurrentManifestVersion) {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700106 LOG(ERROR) << "Unsupported version of the manifest.";
107 return false;
108 }
hscham1574c7e2020-10-13 12:40:01 +0900109 manifest_version_ = *manifest_version;
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700110
hscham1574c7e2020-10-13 12:40:01 +0900111 const std::string* image_hash_str =
112 manifest_dict.FindStringKey(kImageHashField);
113 if (!image_hash_str) {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700114 LOG(ERROR) << "Could not parse image hash from manifest.";
115 return false;
116 }
117
hscham1574c7e2020-10-13 12:40:01 +0900118 if (!GetSHA256FromString(*image_hash_str, &(image_sha256_))) {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700119 LOG(ERROR) << "Could not convert image hash to bytes.";
120 return false;
121 }
122
hscham1574c7e2020-10-13 12:40:01 +0900123 const std::string* table_hash_str =
124 manifest_dict.FindStringKey(kTableHashField);
125 if (table_hash_str == nullptr) {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700126 LOG(ERROR) << "Could not parse table hash from manifest.";
127 return false;
128 }
129
hscham1574c7e2020-10-13 12:40:01 +0900130 if (!GetSHA256FromString(*table_hash_str, &(table_sha256_))) {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700131 LOG(ERROR) << "Could not convert table hash to bytes.";
132 return false;
133 }
134
hscham1574c7e2020-10-13 12:40:01 +0900135 const std::string* version = manifest_dict.FindStringKey(kVersionField);
136 if (!version) {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700137 LOG(ERROR) << "Could not parse component version from manifest.";
138 return false;
139 }
hscham1574c7e2020-10-13 12:40:01 +0900140 version_ = *version;
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700141
142 // The fs_type field is optional, and squashfs by default.
hscham1574c7e2020-10-13 12:40:01 +0900143 const std::string* fs_type = manifest_dict.FindStringKey(kFSType);
144 if (fs_type) {
145 if (*fs_type == "ext4") {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700146 fs_type_ = FileSystem::kExt4;
hscham1574c7e2020-10-13 12:40:01 +0900147 } else if (*fs_type == "squashfs") {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700148 fs_type_ = FileSystem::kSquashFS;
149 } else {
hscham1574c7e2020-10-13 12:40:01 +0900150 LOG(ERROR) << "Unsupported file system type: " << *fs_type;
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700151 return false;
152 }
hscham1574c7e2020-10-13 12:40:01 +0900153 } else {
154 fs_type_ = FileSystem::kSquashFS;
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700155 }
156
hscham1574c7e2020-10-13 12:40:01 +0900157 base::Optional<bool> is_removable =
158 manifest_dict.FindBoolKey(kIsRemovableField);
159 // If |is-removable| field does not exist, by default it is false.
160 is_removable_ = is_removable.value_or(false);
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700161
hscham1574c7e2020-10-13 12:40:01 +0900162 base::Optional<bool> preload_allowed =
163 manifest_dict.FindBoolKey(kPreloadAllowed);
164 // If |preaload-allowed| field does not exist, by default it is false.
165 preload_allowed_ = preload_allowed.value_or(false);
Jae Hoon Kim81d2b6d2020-01-06 16:09:32 -0800166
hscham1574c7e2020-10-13 12:40:01 +0900167 base::Optional<bool> mount_file_required =
168 manifest_dict.FindBoolKey(kMountFileRequired);
169 // If 'mount-file-required' field does not exist, by default it is false.
170 mount_file_required_ = mount_file_required.value_or(false);
Jae Hoon Kim99ee2732020-06-25 15:59:35 -0700171
Colin Howesdc15ba22018-12-12 11:02:42 -0800172 // All of these fields are optional.
hscham1574c7e2020-10-13 12:40:01 +0900173 const std::string* id = manifest_dict.FindStringKey(kId);
174 if (id)
175 id_ = *id;
176 const std::string* package = manifest_dict.FindStringKey(kPackage);
177 if (package)
178 package_ = *package;
179 const std::string* name = manifest_dict.FindStringKey(kName);
180 if (name)
181 name_ = *name;
182 const std::string* image_type = manifest_dict.FindStringKey(kImageType);
183 if (image_type)
184 image_type_ = *image_type;
185 const std::string* used_by = manifest_dict.FindStringKey(kUsedBy);
186 if (used_by)
187 used_by_ = *used_by;
188 const std::string* description = manifest_dict.FindStringKey(kDescription);
189 if (description)
190 description_ = *description;
Jae Hoon Kim9c012ac2020-02-03 17:37:49 -0800191
hscham1574c7e2020-10-13 12:40:01 +0900192 const std::string* preallocated_size_str =
193 manifest_dict.FindStringKey(kPreallocatedSize);
194 if (preallocated_size_str) {
195 if (!base::StringToInt64(*preallocated_size_str, &preallocated_size_)) {
Jae Hoon Kim9c012ac2020-02-03 17:37:49 -0800196 LOG(ERROR) << "Manifest pre-allocated-size was malformed: "
hscham1574c7e2020-10-13 12:40:01 +0900197 << *preallocated_size_str;
Jae Hoon Kim9c012ac2020-02-03 17:37:49 -0800198 return false;
199 }
200 }
201
hscham1574c7e2020-10-13 12:40:01 +0900202 const std::string* size_str = manifest_dict.FindStringKey(kSize);
203 if (size_str) {
204 if (!base::StringToInt64(*size_str, &size_)) {
205 LOG(ERROR) << "Manifest size was malformed: " << *size_str;
Jae Hoon Kim9c012ac2020-02-03 17:37:49 -0800206 return false;
207 }
208 }
Colin Howesdc15ba22018-12-12 11:02:42 -0800209
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700210 // Copy out the metadata, if it's there.
hscham1574c7e2020-10-13 12:40:01 +0900211 const base::Value* metadata = manifest_dict.FindKey(kMetadataField);
212 if (metadata) {
213 if (!ParseMetadata(*metadata, &metadata_)) {
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700214 LOG(ERROR) << "Manifest metadata was malformed";
215 return false;
216 }
217 }
218
219 return true;
220}
221
Xiaochu Liucc7ff8c2018-07-23 11:54:02 -0700222} // namespace imageloader