1*6777b538SAndroid Build Coastguard Worker // Copyright 2014 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "components/nacl/renderer/json_manifest.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <stddef.h>
8*6777b538SAndroid Build Coastguard Worker #include <stdint.h>
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker #include <optional>
11*6777b538SAndroid Build Coastguard Worker #include <set>
12*6777b538SAndroid Build Coastguard Worker
13*6777b538SAndroid Build Coastguard Worker #include "base/json/json_reader.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/types/expected_macros.h"
16*6777b538SAndroid Build Coastguard Worker #include "components/nacl/common/nacl_types.h"
17*6777b538SAndroid Build Coastguard Worker #include "components/nacl/renderer/nexe_load_manager.h"
18*6777b538SAndroid Build Coastguard Worker #include "url/gurl.h"
19*6777b538SAndroid Build Coastguard Worker
20*6777b538SAndroid Build Coastguard Worker namespace nacl {
21*6777b538SAndroid Build Coastguard Worker
22*6777b538SAndroid Build Coastguard Worker namespace {
23*6777b538SAndroid Build Coastguard Worker // Top-level section name keys
24*6777b538SAndroid Build Coastguard Worker const char kProgramKey[] = "program";
25*6777b538SAndroid Build Coastguard Worker const char kInterpreterKey[] = "interpreter";
26*6777b538SAndroid Build Coastguard Worker const char kFilesKey[] = "files";
27*6777b538SAndroid Build Coastguard Worker
28*6777b538SAndroid Build Coastguard Worker // ISA Dictionary keys
29*6777b538SAndroid Build Coastguard Worker const char kX8632Key[] = "x86-32";
30*6777b538SAndroid Build Coastguard Worker const char kX8664Key[] = "x86-64";
31*6777b538SAndroid Build Coastguard Worker const char kArmKey[] = "arm";
32*6777b538SAndroid Build Coastguard Worker const char kPortableKey[] = "portable";
33*6777b538SAndroid Build Coastguard Worker
34*6777b538SAndroid Build Coastguard Worker // Url Resolution keys
35*6777b538SAndroid Build Coastguard Worker const char kPnaclDebugKey[] = "pnacl-debug";
36*6777b538SAndroid Build Coastguard Worker const char kPnaclTranslateKey[] = "pnacl-translate";
37*6777b538SAndroid Build Coastguard Worker const char kUrlKey[] = "url";
38*6777b538SAndroid Build Coastguard Worker
39*6777b538SAndroid Build Coastguard Worker // PNaCl keys
40*6777b538SAndroid Build Coastguard Worker const char kOptLevelKey[] = "optlevel";
41*6777b538SAndroid Build Coastguard Worker
42*6777b538SAndroid Build Coastguard Worker // Sample NaCl manifest file:
43*6777b538SAndroid Build Coastguard Worker // {
44*6777b538SAndroid Build Coastguard Worker // "program": {
45*6777b538SAndroid Build Coastguard Worker // "x86-32": {"url": "myprogram_x86-32.nexe"},
46*6777b538SAndroid Build Coastguard Worker // "x86-64": {"url": "myprogram_x86-64.nexe"},
47*6777b538SAndroid Build Coastguard Worker // "arm": {"url": "myprogram_arm.nexe"}
48*6777b538SAndroid Build Coastguard Worker // },
49*6777b538SAndroid Build Coastguard Worker // "interpreter": {
50*6777b538SAndroid Build Coastguard Worker // "x86-32": {"url": "interpreter_x86-32.nexe"},
51*6777b538SAndroid Build Coastguard Worker // "x86-64": {"url": "interpreter_x86-64.nexe"},
52*6777b538SAndroid Build Coastguard Worker // "arm": {"url": "interpreter_arm.nexe"}
53*6777b538SAndroid Build Coastguard Worker // },
54*6777b538SAndroid Build Coastguard Worker // "files": {
55*6777b538SAndroid Build Coastguard Worker // "foo.txt": {
56*6777b538SAndroid Build Coastguard Worker // "portable": {"url": "foo.txt"}
57*6777b538SAndroid Build Coastguard Worker // },
58*6777b538SAndroid Build Coastguard Worker // "bar.txt": {
59*6777b538SAndroid Build Coastguard Worker // "x86-32": {"url": "x86-32/bar.txt"},
60*6777b538SAndroid Build Coastguard Worker // "portable": {"url": "bar.txt"}
61*6777b538SAndroid Build Coastguard Worker // },
62*6777b538SAndroid Build Coastguard Worker // "libfoo.so": {
63*6777b538SAndroid Build Coastguard Worker // "x86-64" : { "url": "..." }
64*6777b538SAndroid Build Coastguard Worker // }
65*6777b538SAndroid Build Coastguard Worker // }
66*6777b538SAndroid Build Coastguard Worker // }
67*6777b538SAndroid Build Coastguard Worker
68*6777b538SAndroid Build Coastguard Worker // Sample PNaCl manifest file:
69*6777b538SAndroid Build Coastguard Worker // {
70*6777b538SAndroid Build Coastguard Worker // "program": {
71*6777b538SAndroid Build Coastguard Worker // "portable": {
72*6777b538SAndroid Build Coastguard Worker // "pnacl-translate": {
73*6777b538SAndroid Build Coastguard Worker // "url": "myprogram.pexe"
74*6777b538SAndroid Build Coastguard Worker // },
75*6777b538SAndroid Build Coastguard Worker // "pnacl-debug": {
76*6777b538SAndroid Build Coastguard Worker // "url": "myprogram.debug.pexe",
77*6777b538SAndroid Build Coastguard Worker // "opt_level": 0
78*6777b538SAndroid Build Coastguard Worker // }
79*6777b538SAndroid Build Coastguard Worker // }
80*6777b538SAndroid Build Coastguard Worker // },
81*6777b538SAndroid Build Coastguard Worker // "files": {
82*6777b538SAndroid Build Coastguard Worker // "foo.txt": {
83*6777b538SAndroid Build Coastguard Worker // "portable": {"url": "foo.txt"}
84*6777b538SAndroid Build Coastguard Worker // },
85*6777b538SAndroid Build Coastguard Worker // "bar.txt": {
86*6777b538SAndroid Build Coastguard Worker // "portable": {"url": "bar.txt"}
87*6777b538SAndroid Build Coastguard Worker // }
88*6777b538SAndroid Build Coastguard Worker // }
89*6777b538SAndroid Build Coastguard Worker // }
90*6777b538SAndroid Build Coastguard Worker
91*6777b538SAndroid Build Coastguard Worker // Looks up |property_name| in the vector |valid_names| with length
92*6777b538SAndroid Build Coastguard Worker // |valid_name_count|. Returns true if |property_name| is found.
FindMatchingProperty(const std::string & property_name,const char * const * valid_names,size_t valid_name_count)93*6777b538SAndroid Build Coastguard Worker bool FindMatchingProperty(const std::string& property_name,
94*6777b538SAndroid Build Coastguard Worker const char* const* valid_names,
95*6777b538SAndroid Build Coastguard Worker size_t valid_name_count) {
96*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < valid_name_count; ++i) {
97*6777b538SAndroid Build Coastguard Worker if (property_name == valid_names[i]) {
98*6777b538SAndroid Build Coastguard Worker return true;
99*6777b538SAndroid Build Coastguard Worker }
100*6777b538SAndroid Build Coastguard Worker }
101*6777b538SAndroid Build Coastguard Worker return false;
102*6777b538SAndroid Build Coastguard Worker }
103*6777b538SAndroid Build Coastguard Worker
104*6777b538SAndroid Build Coastguard Worker // Return true if this is a valid dictionary. Having only keys present in
105*6777b538SAndroid Build Coastguard Worker // |valid_keys| and having at least the keys in |required_keys|.
106*6777b538SAndroid Build Coastguard Worker // Error messages will be placed in |error_string|, given that the dictionary
107*6777b538SAndroid Build Coastguard Worker // was the property value of |container_key|.
108*6777b538SAndroid Build Coastguard Worker // E.g., "container_key" : dictionary
IsValidDictionary(const base::Value::Dict & dictionary,const std::string & container_key,const std::string & parent_key,const char * const * valid_keys,size_t valid_key_count,const char * const * required_keys,size_t required_key_count,std::string * error_string)109*6777b538SAndroid Build Coastguard Worker bool IsValidDictionary(const base::Value::Dict& dictionary,
110*6777b538SAndroid Build Coastguard Worker const std::string& container_key,
111*6777b538SAndroid Build Coastguard Worker const std::string& parent_key,
112*6777b538SAndroid Build Coastguard Worker const char* const* valid_keys,
113*6777b538SAndroid Build Coastguard Worker size_t valid_key_count,
114*6777b538SAndroid Build Coastguard Worker const char* const* required_keys,
115*6777b538SAndroid Build Coastguard Worker size_t required_key_count,
116*6777b538SAndroid Build Coastguard Worker std::string* error_string) {
117*6777b538SAndroid Build Coastguard Worker // Check for unknown dictionary members.
118*6777b538SAndroid Build Coastguard Worker for (const auto [property_name, unused_value] : dictionary) {
119*6777b538SAndroid Build Coastguard Worker if (!FindMatchingProperty(property_name,
120*6777b538SAndroid Build Coastguard Worker valid_keys,
121*6777b538SAndroid Build Coastguard Worker valid_key_count)) {
122*6777b538SAndroid Build Coastguard Worker // For forward compatibility, we do not prohibit other keys being in
123*6777b538SAndroid Build Coastguard Worker // the dictionary.
124*6777b538SAndroid Build Coastguard Worker VLOG(1) << "WARNING: '" << parent_key << "' property '"
125*6777b538SAndroid Build Coastguard Worker << container_key << "' has unknown key '"
126*6777b538SAndroid Build Coastguard Worker << property_name << "'.";
127*6777b538SAndroid Build Coastguard Worker }
128*6777b538SAndroid Build Coastguard Worker }
129*6777b538SAndroid Build Coastguard Worker // Check for required members.
130*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < required_key_count; ++i) {
131*6777b538SAndroid Build Coastguard Worker if (!dictionary.Find(required_keys[i])) {
132*6777b538SAndroid Build Coastguard Worker std::stringstream error_stream;
133*6777b538SAndroid Build Coastguard Worker error_stream << parent_key << " property '" << container_key
134*6777b538SAndroid Build Coastguard Worker << "' does not have required key: '"
135*6777b538SAndroid Build Coastguard Worker << required_keys[i] << "'.";
136*6777b538SAndroid Build Coastguard Worker *error_string = error_stream.str();
137*6777b538SAndroid Build Coastguard Worker return false;
138*6777b538SAndroid Build Coastguard Worker }
139*6777b538SAndroid Build Coastguard Worker }
140*6777b538SAndroid Build Coastguard Worker return true;
141*6777b538SAndroid Build Coastguard Worker }
142*6777b538SAndroid Build Coastguard Worker
143*6777b538SAndroid Build Coastguard Worker // Validate a "url" dictionary assuming it was resolved from container_key.
144*6777b538SAndroid Build Coastguard Worker // E.g., "container_key" : { "url": "foo.txt" }
IsValidUrlSpec(const base::Value & url_spec,const std::string & container_key,const std::string & parent_key,const std::string & sandbox_isa,std::string * error_string)145*6777b538SAndroid Build Coastguard Worker bool IsValidUrlSpec(const base::Value& url_spec,
146*6777b538SAndroid Build Coastguard Worker const std::string& container_key,
147*6777b538SAndroid Build Coastguard Worker const std::string& parent_key,
148*6777b538SAndroid Build Coastguard Worker const std::string& sandbox_isa,
149*6777b538SAndroid Build Coastguard Worker std::string* error_string) {
150*6777b538SAndroid Build Coastguard Worker const base::Value::Dict* url_dict = url_spec.GetIfDict();
151*6777b538SAndroid Build Coastguard Worker if (!url_dict) {
152*6777b538SAndroid Build Coastguard Worker std::stringstream error_stream;
153*6777b538SAndroid Build Coastguard Worker error_stream << parent_key << " property '" << container_key
154*6777b538SAndroid Build Coastguard Worker << "' is non-dictionary value '" << url_spec << "'.";
155*6777b538SAndroid Build Coastguard Worker *error_string = error_stream.str();
156*6777b538SAndroid Build Coastguard Worker return false;
157*6777b538SAndroid Build Coastguard Worker }
158*6777b538SAndroid Build Coastguard Worker static constexpr const char* kManifestUrlSpecRequired[] = {kUrlKey};
159*6777b538SAndroid Build Coastguard Worker const char* const* url_spec_plus_optional;
160*6777b538SAndroid Build Coastguard Worker size_t url_spec_plus_optional_length;
161*6777b538SAndroid Build Coastguard Worker if (sandbox_isa == kPortableKey) {
162*6777b538SAndroid Build Coastguard Worker static constexpr const char* kPnaclUrlSpecPlusOptional[] = {
163*6777b538SAndroid Build Coastguard Worker kUrlKey, kOptLevelKey,
164*6777b538SAndroid Build Coastguard Worker };
165*6777b538SAndroid Build Coastguard Worker url_spec_plus_optional = kPnaclUrlSpecPlusOptional;
166*6777b538SAndroid Build Coastguard Worker url_spec_plus_optional_length = std::size(kPnaclUrlSpecPlusOptional);
167*6777b538SAndroid Build Coastguard Worker } else {
168*6777b538SAndroid Build Coastguard Worker // URL specifications must not contain "pnacl-translate" keys.
169*6777b538SAndroid Build Coastguard Worker // This prohibits NaCl clients from invoking PNaCl.
170*6777b538SAndroid Build Coastguard Worker if (url_dict->Find(kPnaclTranslateKey)) {
171*6777b538SAndroid Build Coastguard Worker std::stringstream error_stream;
172*6777b538SAndroid Build Coastguard Worker error_stream << "PNaCl-like NMF with application/x-nacl mimetype instead "
173*6777b538SAndroid Build Coastguard Worker << "of x-pnacl mimetype (has " << kPnaclTranslateKey << ").";
174*6777b538SAndroid Build Coastguard Worker *error_string = error_stream.str();
175*6777b538SAndroid Build Coastguard Worker return false;
176*6777b538SAndroid Build Coastguard Worker }
177*6777b538SAndroid Build Coastguard Worker url_spec_plus_optional = kManifestUrlSpecRequired;
178*6777b538SAndroid Build Coastguard Worker url_spec_plus_optional_length = std::size(kManifestUrlSpecRequired);
179*6777b538SAndroid Build Coastguard Worker }
180*6777b538SAndroid Build Coastguard Worker if (!IsValidDictionary(*url_dict, container_key, parent_key,
181*6777b538SAndroid Build Coastguard Worker url_spec_plus_optional, url_spec_plus_optional_length,
182*6777b538SAndroid Build Coastguard Worker kManifestUrlSpecRequired,
183*6777b538SAndroid Build Coastguard Worker std::size(kManifestUrlSpecRequired), error_string)) {
184*6777b538SAndroid Build Coastguard Worker return false;
185*6777b538SAndroid Build Coastguard Worker }
186*6777b538SAndroid Build Coastguard Worker // Verify the correct types of the fields if they exist.
187*6777b538SAndroid Build Coastguard Worker // URL was already verified above by IsValidDictionary to be required.
188*6777b538SAndroid Build Coastguard Worker const base::Value* url = url_dict->Find(kUrlKey);
189*6777b538SAndroid Build Coastguard Worker DCHECK(url);
190*6777b538SAndroid Build Coastguard Worker if (!url->is_string()) {
191*6777b538SAndroid Build Coastguard Worker std::stringstream error_stream;
192*6777b538SAndroid Build Coastguard Worker error_stream << parent_key << " property '" << container_key
193*6777b538SAndroid Build Coastguard Worker << "' has non-string value '" << *url << "' for key '"
194*6777b538SAndroid Build Coastguard Worker << kUrlKey << "'.";
195*6777b538SAndroid Build Coastguard Worker *error_string = error_stream.str();
196*6777b538SAndroid Build Coastguard Worker return false;
197*6777b538SAndroid Build Coastguard Worker }
198*6777b538SAndroid Build Coastguard Worker if (const base::Value* opt_level = url_dict->Find(kOptLevelKey)) {
199*6777b538SAndroid Build Coastguard Worker if (!opt_level->is_int()) {
200*6777b538SAndroid Build Coastguard Worker std::stringstream error_stream;
201*6777b538SAndroid Build Coastguard Worker error_stream << parent_key << " property '" << container_key
202*6777b538SAndroid Build Coastguard Worker << "' has non-numeric value '" << *opt_level << "' for key '"
203*6777b538SAndroid Build Coastguard Worker << kOptLevelKey << "'.";
204*6777b538SAndroid Build Coastguard Worker *error_string = error_stream.str();
205*6777b538SAndroid Build Coastguard Worker return false;
206*6777b538SAndroid Build Coastguard Worker }
207*6777b538SAndroid Build Coastguard Worker }
208*6777b538SAndroid Build Coastguard Worker return true;
209*6777b538SAndroid Build Coastguard Worker }
210*6777b538SAndroid Build Coastguard Worker
211*6777b538SAndroid Build Coastguard Worker // Validate a "pnacl-translate" or "pnacl-debug" dictionary, assuming
212*6777b538SAndroid Build Coastguard Worker // it was resolved from container_key.
213*6777b538SAndroid Build Coastguard Worker // E.g., "container_key" : { "pnacl-translate" : URLSpec }
IsValidPnaclTranslateSpec(const base::Value & pnacl_spec,const std::string & container_key,const std::string & parent_key,const std::string & sandbox_isa,std::string * error_string)214*6777b538SAndroid Build Coastguard Worker bool IsValidPnaclTranslateSpec(const base::Value& pnacl_spec,
215*6777b538SAndroid Build Coastguard Worker const std::string& container_key,
216*6777b538SAndroid Build Coastguard Worker const std::string& parent_key,
217*6777b538SAndroid Build Coastguard Worker const std::string& sandbox_isa,
218*6777b538SAndroid Build Coastguard Worker std::string* error_string) {
219*6777b538SAndroid Build Coastguard Worker static const char* kManifestPnaclSpecValid[] = {
220*6777b538SAndroid Build Coastguard Worker kPnaclDebugKey,
221*6777b538SAndroid Build Coastguard Worker kPnaclTranslateKey
222*6777b538SAndroid Build Coastguard Worker };
223*6777b538SAndroid Build Coastguard Worker static const char* kManifestPnaclSpecRequired[] = { kPnaclTranslateKey };
224*6777b538SAndroid Build Coastguard Worker const base::Value::Dict* pnacl_dict = pnacl_spec.GetIfDict();
225*6777b538SAndroid Build Coastguard Worker if (!pnacl_dict) {
226*6777b538SAndroid Build Coastguard Worker std::stringstream error_stream;
227*6777b538SAndroid Build Coastguard Worker error_stream << parent_key << " property '" << container_key
228*6777b538SAndroid Build Coastguard Worker << "' is non-dictionary value '" << pnacl_spec << "'.";
229*6777b538SAndroid Build Coastguard Worker *error_string = error_stream.str();
230*6777b538SAndroid Build Coastguard Worker return false;
231*6777b538SAndroid Build Coastguard Worker }
232*6777b538SAndroid Build Coastguard Worker
233*6777b538SAndroid Build Coastguard Worker if (!IsValidDictionary(
234*6777b538SAndroid Build Coastguard Worker *pnacl_dict, container_key, parent_key, kManifestPnaclSpecValid,
235*6777b538SAndroid Build Coastguard Worker std::size(kManifestPnaclSpecValid), kManifestPnaclSpecRequired,
236*6777b538SAndroid Build Coastguard Worker std::size(kManifestPnaclSpecRequired), error_string)) {
237*6777b538SAndroid Build Coastguard Worker return false;
238*6777b538SAndroid Build Coastguard Worker }
239*6777b538SAndroid Build Coastguard Worker // kPnaclTranslateKey checked to be required above.
240*6777b538SAndroid Build Coastguard Worker const base::Value* url_spec = pnacl_dict->Find(kPnaclTranslateKey);
241*6777b538SAndroid Build Coastguard Worker DCHECK(url_spec);
242*6777b538SAndroid Build Coastguard Worker return IsValidUrlSpec(*url_spec, kPnaclTranslateKey, container_key,
243*6777b538SAndroid Build Coastguard Worker sandbox_isa, error_string);
244*6777b538SAndroid Build Coastguard Worker }
245*6777b538SAndroid Build Coastguard Worker
246*6777b538SAndroid Build Coastguard Worker // Validates that parent_dictionary[parent_key] is a valid ISA dictionary.
247*6777b538SAndroid Build Coastguard Worker // An ISA dictionary is validated to have keys from within the set of
248*6777b538SAndroid Build Coastguard Worker // recognized ISAs. Unknown ISAs are allowed, but ignored and warnings
249*6777b538SAndroid Build Coastguard Worker // are produced. It is also validated that it must have an entry to match the
250*6777b538SAndroid Build Coastguard Worker // ISA specified in |sandbox_isa| or have a fallback 'portable' entry if
251*6777b538SAndroid Build Coastguard Worker // there is no match. Returns true if parent_dictionary[parent_key] is an
252*6777b538SAndroid Build Coastguard Worker // ISA to URL map. Sets |error_info| to something descriptive if it fails.
IsValidISADictionary(const base::Value::Dict & parent_dictionary,const std::string & parent_key,const std::string & sandbox_isa,bool must_find_matching_entry,JsonManifest::ErrorInfo * error_info)253*6777b538SAndroid Build Coastguard Worker bool IsValidISADictionary(const base::Value::Dict& parent_dictionary,
254*6777b538SAndroid Build Coastguard Worker const std::string& parent_key,
255*6777b538SAndroid Build Coastguard Worker const std::string& sandbox_isa,
256*6777b538SAndroid Build Coastguard Worker bool must_find_matching_entry,
257*6777b538SAndroid Build Coastguard Worker JsonManifest::ErrorInfo* error_info) {
258*6777b538SAndroid Build Coastguard Worker const base::Value::Dict* dictionary = parent_dictionary.FindDict(parent_key);
259*6777b538SAndroid Build Coastguard Worker if (!dictionary) {
260*6777b538SAndroid Build Coastguard Worker error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
261*6777b538SAndroid Build Coastguard Worker error_info->string = std::string("manifest: ") + parent_key +
262*6777b538SAndroid Build Coastguard Worker " property is not an ISA to URL dictionary";
263*6777b538SAndroid Build Coastguard Worker return false;
264*6777b538SAndroid Build Coastguard Worker }
265*6777b538SAndroid Build Coastguard Worker // Build the set of reserved ISA dictionary keys.
266*6777b538SAndroid Build Coastguard Worker const char** isaProperties;
267*6777b538SAndroid Build Coastguard Worker size_t isaPropertiesLength;
268*6777b538SAndroid Build Coastguard Worker if (sandbox_isa == kPortableKey) {
269*6777b538SAndroid Build Coastguard Worker // The known values for PNaCl ISA dictionaries in the manifest.
270*6777b538SAndroid Build Coastguard Worker static const char* kPnaclManifestISAProperties[] = {
271*6777b538SAndroid Build Coastguard Worker kPortableKey
272*6777b538SAndroid Build Coastguard Worker };
273*6777b538SAndroid Build Coastguard Worker isaProperties = kPnaclManifestISAProperties;
274*6777b538SAndroid Build Coastguard Worker isaPropertiesLength = std::size(kPnaclManifestISAProperties);
275*6777b538SAndroid Build Coastguard Worker } else {
276*6777b538SAndroid Build Coastguard Worker // The known values for NaCl ISA dictionaries in the manifest.
277*6777b538SAndroid Build Coastguard Worker static const char* kNaClManifestISAProperties[] = {
278*6777b538SAndroid Build Coastguard Worker kX8632Key, kX8664Key, kArmKey,
279*6777b538SAndroid Build Coastguard Worker // "portable" is here to allow checking that, if present, it can
280*6777b538SAndroid Build Coastguard Worker // only refer to an URL, such as for a data file, and not to
281*6777b538SAndroid Build Coastguard Worker // "pnacl-translate", which would cause the creation of a nexe.
282*6777b538SAndroid Build Coastguard Worker kPortableKey};
283*6777b538SAndroid Build Coastguard Worker isaProperties = kNaClManifestISAProperties;
284*6777b538SAndroid Build Coastguard Worker isaPropertiesLength = std::size(kNaClManifestISAProperties);
285*6777b538SAndroid Build Coastguard Worker }
286*6777b538SAndroid Build Coastguard Worker // Check that entries in the dictionary are structurally correct.
287*6777b538SAndroid Build Coastguard Worker for (const auto [property_name, property_value] : *dictionary) {
288*6777b538SAndroid Build Coastguard Worker std::string error_string;
289*6777b538SAndroid Build Coastguard Worker if (FindMatchingProperty(property_name,
290*6777b538SAndroid Build Coastguard Worker isaProperties,
291*6777b538SAndroid Build Coastguard Worker isaPropertiesLength)) {
292*6777b538SAndroid Build Coastguard Worker // For NaCl, arch entries can only be
293*6777b538SAndroid Build Coastguard Worker // "arch/portable" : URLSpec
294*6777b538SAndroid Build Coastguard Worker // For PNaCl arch in "program" dictionary entries can be
295*6777b538SAndroid Build Coastguard Worker // "portable" : { "pnacl-translate": URLSpec }
296*6777b538SAndroid Build Coastguard Worker // or "portable" : { "pnacl-debug": URLSpec }
297*6777b538SAndroid Build Coastguard Worker // For PNaCl arch elsewhere, dictionary entries can only be
298*6777b538SAndroid Build Coastguard Worker // "portable" : URLSpec
299*6777b538SAndroid Build Coastguard Worker if ((sandbox_isa != kPortableKey &&
300*6777b538SAndroid Build Coastguard Worker !IsValidUrlSpec(property_value, property_name, parent_key,
301*6777b538SAndroid Build Coastguard Worker sandbox_isa, &error_string)) ||
302*6777b538SAndroid Build Coastguard Worker (sandbox_isa == kPortableKey &&
303*6777b538SAndroid Build Coastguard Worker parent_key == kProgramKey &&
304*6777b538SAndroid Build Coastguard Worker !IsValidPnaclTranslateSpec(property_value, property_name, parent_key,
305*6777b538SAndroid Build Coastguard Worker sandbox_isa, &error_string)) ||
306*6777b538SAndroid Build Coastguard Worker (sandbox_isa == kPortableKey &&
307*6777b538SAndroid Build Coastguard Worker parent_key != kProgramKey &&
308*6777b538SAndroid Build Coastguard Worker !IsValidUrlSpec(property_value, property_name, parent_key,
309*6777b538SAndroid Build Coastguard Worker sandbox_isa, &error_string))) {
310*6777b538SAndroid Build Coastguard Worker error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
311*6777b538SAndroid Build Coastguard Worker error_info->string = "manifest: " + error_string;
312*6777b538SAndroid Build Coastguard Worker return false;
313*6777b538SAndroid Build Coastguard Worker }
314*6777b538SAndroid Build Coastguard Worker } else {
315*6777b538SAndroid Build Coastguard Worker // For forward compatibility, we do not prohibit other keys being in
316*6777b538SAndroid Build Coastguard Worker // the dictionary, as they may be architectures supported in later
317*6777b538SAndroid Build Coastguard Worker // versions. However, the value of these entries must be an URLSpec.
318*6777b538SAndroid Build Coastguard Worker VLOG(1) << "IsValidISADictionary: unrecognized key '"
319*6777b538SAndroid Build Coastguard Worker << property_name << "'.";
320*6777b538SAndroid Build Coastguard Worker if (!IsValidUrlSpec(property_value, property_name, parent_key,
321*6777b538SAndroid Build Coastguard Worker sandbox_isa, &error_string)) {
322*6777b538SAndroid Build Coastguard Worker error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
323*6777b538SAndroid Build Coastguard Worker error_info->string = "manifest: " + error_string;
324*6777b538SAndroid Build Coastguard Worker return false;
325*6777b538SAndroid Build Coastguard Worker }
326*6777b538SAndroid Build Coastguard Worker }
327*6777b538SAndroid Build Coastguard Worker }
328*6777b538SAndroid Build Coastguard Worker
329*6777b538SAndroid Build Coastguard Worker if (sandbox_isa == kPortableKey) {
330*6777b538SAndroid Build Coastguard Worker if (!dictionary->Find(kPortableKey)) {
331*6777b538SAndroid Build Coastguard Worker error_info->error = PP_NACL_ERROR_MANIFEST_PROGRAM_MISSING_ARCH;
332*6777b538SAndroid Build Coastguard Worker error_info->string = "manifest: no version of " + parent_key +
333*6777b538SAndroid Build Coastguard Worker " given for portable.";
334*6777b538SAndroid Build Coastguard Worker return false;
335*6777b538SAndroid Build Coastguard Worker }
336*6777b538SAndroid Build Coastguard Worker } else if (must_find_matching_entry) {
337*6777b538SAndroid Build Coastguard Worker // TODO(elijahtaylor) add ISA resolver here if we expand ISAs to include
338*6777b538SAndroid Build Coastguard Worker // micro-architectures that can resolve to multiple valid sandboxes.
339*6777b538SAndroid Build Coastguard Worker bool has_isa = dictionary->Find(sandbox_isa);
340*6777b538SAndroid Build Coastguard Worker bool has_portable = dictionary->Find(kPortableKey);
341*6777b538SAndroid Build Coastguard Worker
342*6777b538SAndroid Build Coastguard Worker if (!has_isa && !has_portable) {
343*6777b538SAndroid Build Coastguard Worker error_info->error = PP_NACL_ERROR_MANIFEST_PROGRAM_MISSING_ARCH;
344*6777b538SAndroid Build Coastguard Worker error_info->string = "manifest: no version of " + parent_key +
345*6777b538SAndroid Build Coastguard Worker " given for current arch and no portable version found.";
346*6777b538SAndroid Build Coastguard Worker return false;
347*6777b538SAndroid Build Coastguard Worker }
348*6777b538SAndroid Build Coastguard Worker }
349*6777b538SAndroid Build Coastguard Worker return true;
350*6777b538SAndroid Build Coastguard Worker }
351*6777b538SAndroid Build Coastguard Worker
GrabUrlAndPnaclOptions(const base::Value::Dict & url_spec,std::string * url,PP_PNaClOptions * pnacl_options)352*6777b538SAndroid Build Coastguard Worker void GrabUrlAndPnaclOptions(const base::Value::Dict& url_spec,
353*6777b538SAndroid Build Coastguard Worker std::string* url,
354*6777b538SAndroid Build Coastguard Worker PP_PNaClOptions* pnacl_options) {
355*6777b538SAndroid Build Coastguard Worker // url_spec should have been validated as a first pass.
356*6777b538SAndroid Build Coastguard Worker const std::string* url_str = url_spec.FindString(kUrlKey);
357*6777b538SAndroid Build Coastguard Worker DCHECK(url_str);
358*6777b538SAndroid Build Coastguard Worker *url = *url_str;
359*6777b538SAndroid Build Coastguard Worker pnacl_options->translate = PP_TRUE;
360*6777b538SAndroid Build Coastguard Worker if (url_spec.Find(kOptLevelKey)) {
361*6777b538SAndroid Build Coastguard Worker std::optional<int32_t> opt_raw = url_spec.FindInt(kOptLevelKey);
362*6777b538SAndroid Build Coastguard Worker DCHECK(opt_raw.has_value());
363*6777b538SAndroid Build Coastguard Worker // Currently only allow 0 or 2, since that is what we test.
364*6777b538SAndroid Build Coastguard Worker if (opt_raw.value() <= 0)
365*6777b538SAndroid Build Coastguard Worker pnacl_options->opt_level = 0;
366*6777b538SAndroid Build Coastguard Worker else
367*6777b538SAndroid Build Coastguard Worker pnacl_options->opt_level = 2;
368*6777b538SAndroid Build Coastguard Worker }
369*6777b538SAndroid Build Coastguard Worker }
370*6777b538SAndroid Build Coastguard Worker
371*6777b538SAndroid Build Coastguard Worker } // namespace
372*6777b538SAndroid Build Coastguard Worker
JsonManifest(const std::string & manifest_base_url,const std::string & sandbox_isa,bool pnacl_debug)373*6777b538SAndroid Build Coastguard Worker JsonManifest::JsonManifest(const std::string& manifest_base_url,
374*6777b538SAndroid Build Coastguard Worker const std::string& sandbox_isa,
375*6777b538SAndroid Build Coastguard Worker bool pnacl_debug)
376*6777b538SAndroid Build Coastguard Worker : manifest_base_url_(manifest_base_url),
377*6777b538SAndroid Build Coastguard Worker sandbox_isa_(sandbox_isa),
378*6777b538SAndroid Build Coastguard Worker pnacl_debug_(pnacl_debug) {}
379*6777b538SAndroid Build Coastguard Worker
~JsonManifest()380*6777b538SAndroid Build Coastguard Worker JsonManifest::~JsonManifest() {}
381*6777b538SAndroid Build Coastguard Worker
Init(const std::string & manifest_json_data,ErrorInfo * error_info)382*6777b538SAndroid Build Coastguard Worker bool JsonManifest::Init(const std::string& manifest_json_data,
383*6777b538SAndroid Build Coastguard Worker ErrorInfo* error_info) {
384*6777b538SAndroid Build Coastguard Worker CHECK(error_info);
385*6777b538SAndroid Build Coastguard Worker
386*6777b538SAndroid Build Coastguard Worker ASSIGN_OR_RETURN(
387*6777b538SAndroid Build Coastguard Worker base::Value json_data,
388*6777b538SAndroid Build Coastguard Worker base::JSONReader::ReadAndReturnValueWithError(manifest_json_data),
389*6777b538SAndroid Build Coastguard Worker [&](base::JSONReader::Error error) {
390*6777b538SAndroid Build Coastguard Worker error_info->error = PP_NACL_ERROR_MANIFEST_PARSING;
391*6777b538SAndroid Build Coastguard Worker error_info->string =
392*6777b538SAndroid Build Coastguard Worker "manifest JSON parsing failed: " + std::move(error).message;
393*6777b538SAndroid Build Coastguard Worker return false;
394*6777b538SAndroid Build Coastguard Worker });
395*6777b538SAndroid Build Coastguard Worker // Ensure it's actually a dictionary before capturing as dictionary_.
396*6777b538SAndroid Build Coastguard Worker if (!json_data.is_dict()) {
397*6777b538SAndroid Build Coastguard Worker error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
398*6777b538SAndroid Build Coastguard Worker error_info->string = "manifest: is not a json dictionary.";
399*6777b538SAndroid Build Coastguard Worker return false;
400*6777b538SAndroid Build Coastguard Worker }
401*6777b538SAndroid Build Coastguard Worker dictionary_ = std::move(json_data).TakeDict();
402*6777b538SAndroid Build Coastguard Worker // Parse has ensured the string was valid JSON. Check that it matches the
403*6777b538SAndroid Build Coastguard Worker // manifest schema.
404*6777b538SAndroid Build Coastguard Worker return MatchesSchema(error_info);
405*6777b538SAndroid Build Coastguard Worker }
406*6777b538SAndroid Build Coastguard Worker
GetProgramURL(std::string * full_url,PP_PNaClOptions * pnacl_options,ErrorInfo * error_info) const407*6777b538SAndroid Build Coastguard Worker bool JsonManifest::GetProgramURL(std::string* full_url,
408*6777b538SAndroid Build Coastguard Worker PP_PNaClOptions* pnacl_options,
409*6777b538SAndroid Build Coastguard Worker ErrorInfo* error_info) const {
410*6777b538SAndroid Build Coastguard Worker if (!full_url)
411*6777b538SAndroid Build Coastguard Worker return false;
412*6777b538SAndroid Build Coastguard Worker CHECK(pnacl_options);
413*6777b538SAndroid Build Coastguard Worker CHECK(error_info);
414*6777b538SAndroid Build Coastguard Worker
415*6777b538SAndroid Build Coastguard Worker std::string nexe_url;
416*6777b538SAndroid Build Coastguard Worker if (!GetURLFromISADictionary(dictionary_, kProgramKey, &nexe_url,
417*6777b538SAndroid Build Coastguard Worker pnacl_options, error_info)) {
418*6777b538SAndroid Build Coastguard Worker return false;
419*6777b538SAndroid Build Coastguard Worker }
420*6777b538SAndroid Build Coastguard Worker
421*6777b538SAndroid Build Coastguard Worker // The contents of the manifest are resolved relative to the manifest URL.
422*6777b538SAndroid Build Coastguard Worker GURL base_gurl(manifest_base_url_);
423*6777b538SAndroid Build Coastguard Worker if (!base_gurl.is_valid())
424*6777b538SAndroid Build Coastguard Worker return false;
425*6777b538SAndroid Build Coastguard Worker
426*6777b538SAndroid Build Coastguard Worker GURL resolved_gurl = base_gurl.Resolve(nexe_url);
427*6777b538SAndroid Build Coastguard Worker if (!resolved_gurl.is_valid()) {
428*6777b538SAndroid Build Coastguard Worker error_info->error = PP_NACL_ERROR_MANIFEST_RESOLVE_URL;
429*6777b538SAndroid Build Coastguard Worker error_info->string =
430*6777b538SAndroid Build Coastguard Worker "could not resolve url '" + nexe_url +
431*6777b538SAndroid Build Coastguard Worker "' relative to manifest base url '" + manifest_base_url_.c_str() +
432*6777b538SAndroid Build Coastguard Worker "'.";
433*6777b538SAndroid Build Coastguard Worker return false;
434*6777b538SAndroid Build Coastguard Worker }
435*6777b538SAndroid Build Coastguard Worker *full_url = resolved_gurl.possibly_invalid_spec();
436*6777b538SAndroid Build Coastguard Worker return true;
437*6777b538SAndroid Build Coastguard Worker }
438*6777b538SAndroid Build Coastguard Worker
GetPrefetchableFiles(std::vector<NaClResourcePrefetchRequest> * out_files) const439*6777b538SAndroid Build Coastguard Worker void JsonManifest::GetPrefetchableFiles(
440*6777b538SAndroid Build Coastguard Worker std::vector<NaClResourcePrefetchRequest>* out_files) const {
441*6777b538SAndroid Build Coastguard Worker const base::Value::Dict* files_dict = dictionary_.FindDict(kFilesKey);
442*6777b538SAndroid Build Coastguard Worker if (!files_dict)
443*6777b538SAndroid Build Coastguard Worker return;
444*6777b538SAndroid Build Coastguard Worker
445*6777b538SAndroid Build Coastguard Worker for (const auto [file_key, unused_value] : *files_dict) {
446*6777b538SAndroid Build Coastguard Worker std::string full_url;
447*6777b538SAndroid Build Coastguard Worker PP_PNaClOptions unused_pnacl_options; // pnacl does not support "files".
448*6777b538SAndroid Build Coastguard Worker // We skip invalid entries in "files".
449*6777b538SAndroid Build Coastguard Worker if (GetKeyUrl(*files_dict, file_key, &full_url, &unused_pnacl_options)) {
450*6777b538SAndroid Build Coastguard Worker if (GURL(full_url).SchemeIs("chrome-extension"))
451*6777b538SAndroid Build Coastguard Worker out_files->push_back(NaClResourcePrefetchRequest(file_key, full_url));
452*6777b538SAndroid Build Coastguard Worker }
453*6777b538SAndroid Build Coastguard Worker }
454*6777b538SAndroid Build Coastguard Worker }
455*6777b538SAndroid Build Coastguard Worker
ResolveKey(const std::string & key,std::string * full_url,PP_PNaClOptions * pnacl_options) const456*6777b538SAndroid Build Coastguard Worker bool JsonManifest::ResolveKey(const std::string& key,
457*6777b538SAndroid Build Coastguard Worker std::string* full_url,
458*6777b538SAndroid Build Coastguard Worker PP_PNaClOptions* pnacl_options) const {
459*6777b538SAndroid Build Coastguard Worker if (full_url == NULL || pnacl_options == NULL)
460*6777b538SAndroid Build Coastguard Worker return false;
461*6777b538SAndroid Build Coastguard Worker
462*6777b538SAndroid Build Coastguard Worker const base::Value::Dict* files_dict = dictionary_.FindDict(kFilesKey);
463*6777b538SAndroid Build Coastguard Worker if (!files_dict) {
464*6777b538SAndroid Build Coastguard Worker VLOG(1) << "ResolveKey failed: no \"files\" dictionary";
465*6777b538SAndroid Build Coastguard Worker return false;
466*6777b538SAndroid Build Coastguard Worker }
467*6777b538SAndroid Build Coastguard Worker
468*6777b538SAndroid Build Coastguard Worker if (!files_dict->Find(key)) {
469*6777b538SAndroid Build Coastguard Worker VLOG(1) << "ResolveKey failed: no such \"files\" entry: " << key;
470*6777b538SAndroid Build Coastguard Worker return false;
471*6777b538SAndroid Build Coastguard Worker }
472*6777b538SAndroid Build Coastguard Worker return GetKeyUrl(*files_dict, key, full_url, pnacl_options);
473*6777b538SAndroid Build Coastguard Worker }
474*6777b538SAndroid Build Coastguard Worker
MatchesSchema(ErrorInfo * error_info)475*6777b538SAndroid Build Coastguard Worker bool JsonManifest::MatchesSchema(ErrorInfo* error_info) {
476*6777b538SAndroid Build Coastguard Worker // The top level dictionary entries valid in the manifest file.
477*6777b538SAndroid Build Coastguard Worker static const char* kManifestTopLevelProperties[] = {
478*6777b538SAndroid Build Coastguard Worker kProgramKey, kInterpreterKey, kFilesKey};
479*6777b538SAndroid Build Coastguard Worker for (const auto [property_name, unused_value] : dictionary_) {
480*6777b538SAndroid Build Coastguard Worker if (!FindMatchingProperty(property_name, kManifestTopLevelProperties,
481*6777b538SAndroid Build Coastguard Worker std::size(kManifestTopLevelProperties))) {
482*6777b538SAndroid Build Coastguard Worker VLOG(1) << "JsonManifest::MatchesSchema: WARNING: unknown top-level "
483*6777b538SAndroid Build Coastguard Worker << "section '" << property_name << "' in manifest.";
484*6777b538SAndroid Build Coastguard Worker }
485*6777b538SAndroid Build Coastguard Worker }
486*6777b538SAndroid Build Coastguard Worker
487*6777b538SAndroid Build Coastguard Worker // A manifest file must have a program section.
488*6777b538SAndroid Build Coastguard Worker if (!dictionary_.Find(kProgramKey)) {
489*6777b538SAndroid Build Coastguard Worker error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
490*6777b538SAndroid Build Coastguard Worker error_info->string = std::string("manifest: missing '") + kProgramKey +
491*6777b538SAndroid Build Coastguard Worker "' section.";
492*6777b538SAndroid Build Coastguard Worker return false;
493*6777b538SAndroid Build Coastguard Worker }
494*6777b538SAndroid Build Coastguard Worker
495*6777b538SAndroid Build Coastguard Worker // Validate the program section.
496*6777b538SAndroid Build Coastguard Worker // There must be a matching (portable or sandbox_isa_) entry for program for
497*6777b538SAndroid Build Coastguard Worker // NaCl.
498*6777b538SAndroid Build Coastguard Worker if (!IsValidISADictionary(dictionary_, kProgramKey, sandbox_isa_, true,
499*6777b538SAndroid Build Coastguard Worker error_info)) {
500*6777b538SAndroid Build Coastguard Worker return false;
501*6777b538SAndroid Build Coastguard Worker }
502*6777b538SAndroid Build Coastguard Worker
503*6777b538SAndroid Build Coastguard Worker // Validate the interpreter section (if given).
504*6777b538SAndroid Build Coastguard Worker // There must be a matching (portable or sandbox_isa_) entry for interpreter
505*6777b538SAndroid Build Coastguard Worker // for NaCl.
506*6777b538SAndroid Build Coastguard Worker if (dictionary_.Find(kInterpreterKey)) {
507*6777b538SAndroid Build Coastguard Worker if (!IsValidISADictionary(dictionary_, kInterpreterKey, sandbox_isa_, true,
508*6777b538SAndroid Build Coastguard Worker error_info)) {
509*6777b538SAndroid Build Coastguard Worker return false;
510*6777b538SAndroid Build Coastguard Worker }
511*6777b538SAndroid Build Coastguard Worker }
512*6777b538SAndroid Build Coastguard Worker
513*6777b538SAndroid Build Coastguard Worker // Validate the file dictionary (if given).
514*6777b538SAndroid Build Coastguard Worker // The "files" key does not require a matching (portable or sandbox_isa_)
515*6777b538SAndroid Build Coastguard Worker // entry at schema validation time for NaCl. This allows manifests to
516*6777b538SAndroid Build Coastguard Worker // specify resources that are only loaded for a particular sandbox_isa.
517*6777b538SAndroid Build Coastguard Worker if (base::Value* files_value = dictionary_.Find(kFilesKey)) {
518*6777b538SAndroid Build Coastguard Worker if (base::Value::Dict* files_dictionary = files_value->GetIfDict()) {
519*6777b538SAndroid Build Coastguard Worker for (const auto [file_name, unused_value] : *files_dictionary) {
520*6777b538SAndroid Build Coastguard Worker if (!IsValidISADictionary(*files_dictionary, file_name, sandbox_isa_,
521*6777b538SAndroid Build Coastguard Worker false, error_info)) {
522*6777b538SAndroid Build Coastguard Worker return false;
523*6777b538SAndroid Build Coastguard Worker }
524*6777b538SAndroid Build Coastguard Worker }
525*6777b538SAndroid Build Coastguard Worker } else {
526*6777b538SAndroid Build Coastguard Worker error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
527*6777b538SAndroid Build Coastguard Worker error_info->string = std::string("manifest: '") + kFilesKey +
528*6777b538SAndroid Build Coastguard Worker "' is not a dictionary.";
529*6777b538SAndroid Build Coastguard Worker return false;
530*6777b538SAndroid Build Coastguard Worker }
531*6777b538SAndroid Build Coastguard Worker }
532*6777b538SAndroid Build Coastguard Worker return true;
533*6777b538SAndroid Build Coastguard Worker }
534*6777b538SAndroid Build Coastguard Worker
GetKeyUrl(const base::Value::Dict & dictionary,const std::string & key,std::string * full_url,PP_PNaClOptions * pnacl_options) const535*6777b538SAndroid Build Coastguard Worker bool JsonManifest::GetKeyUrl(const base::Value::Dict& dictionary,
536*6777b538SAndroid Build Coastguard Worker const std::string& key,
537*6777b538SAndroid Build Coastguard Worker std::string* full_url,
538*6777b538SAndroid Build Coastguard Worker PP_PNaClOptions* pnacl_options) const {
539*6777b538SAndroid Build Coastguard Worker DCHECK(full_url && pnacl_options);
540*6777b538SAndroid Build Coastguard Worker if (!dictionary.Find(key)) {
541*6777b538SAndroid Build Coastguard Worker VLOG(1) << "GetKeyUrl failed: file " << key << " not found in manifest.";
542*6777b538SAndroid Build Coastguard Worker return false;
543*6777b538SAndroid Build Coastguard Worker }
544*6777b538SAndroid Build Coastguard Worker std::string relative_url;
545*6777b538SAndroid Build Coastguard Worker ErrorInfo ignored_error_info;
546*6777b538SAndroid Build Coastguard Worker if (!GetURLFromISADictionary(dictionary, key, &relative_url, pnacl_options,
547*6777b538SAndroid Build Coastguard Worker &ignored_error_info))
548*6777b538SAndroid Build Coastguard Worker return false;
549*6777b538SAndroid Build Coastguard Worker
550*6777b538SAndroid Build Coastguard Worker // The contents of the manifest are resolved relative to the manifest URL.
551*6777b538SAndroid Build Coastguard Worker GURL base_gurl(manifest_base_url_);
552*6777b538SAndroid Build Coastguard Worker if (!base_gurl.is_valid())
553*6777b538SAndroid Build Coastguard Worker return false;
554*6777b538SAndroid Build Coastguard Worker GURL resolved_gurl = base_gurl.Resolve(relative_url);
555*6777b538SAndroid Build Coastguard Worker if (!resolved_gurl.is_valid())
556*6777b538SAndroid Build Coastguard Worker return false;
557*6777b538SAndroid Build Coastguard Worker *full_url = resolved_gurl.possibly_invalid_spec();
558*6777b538SAndroid Build Coastguard Worker return true;
559*6777b538SAndroid Build Coastguard Worker }
560*6777b538SAndroid Build Coastguard Worker
GetURLFromISADictionary(const base::Value::Dict & parent_dictionary,const std::string & parent_key,std::string * url,PP_PNaClOptions * pnacl_options,ErrorInfo * error_info) const561*6777b538SAndroid Build Coastguard Worker bool JsonManifest::GetURLFromISADictionary(
562*6777b538SAndroid Build Coastguard Worker const base::Value::Dict& parent_dictionary,
563*6777b538SAndroid Build Coastguard Worker const std::string& parent_key,
564*6777b538SAndroid Build Coastguard Worker std::string* url,
565*6777b538SAndroid Build Coastguard Worker PP_PNaClOptions* pnacl_options,
566*6777b538SAndroid Build Coastguard Worker ErrorInfo* error_info) const {
567*6777b538SAndroid Build Coastguard Worker DCHECK(url && pnacl_options && error_info);
568*6777b538SAndroid Build Coastguard Worker
569*6777b538SAndroid Build Coastguard Worker const base::Value::Dict* dictionary = parent_dictionary.FindDict(parent_key);
570*6777b538SAndroid Build Coastguard Worker if (!dictionary) {
571*6777b538SAndroid Build Coastguard Worker error_info->error = PP_NACL_ERROR_MANIFEST_RESOLVE_URL;
572*6777b538SAndroid Build Coastguard Worker error_info->string = std::string("GetURLFromISADictionary failed: ") +
573*6777b538SAndroid Build Coastguard Worker parent_key + "'s value is not a json dictionary.";
574*6777b538SAndroid Build Coastguard Worker return false;
575*6777b538SAndroid Build Coastguard Worker }
576*6777b538SAndroid Build Coastguard Worker
577*6777b538SAndroid Build Coastguard Worker // When the application actually requests a resolved URL, we must have
578*6777b538SAndroid Build Coastguard Worker // a matching entry (sandbox_isa_ or portable) for NaCl.
579*6777b538SAndroid Build Coastguard Worker ErrorInfo ignored_error_info;
580*6777b538SAndroid Build Coastguard Worker if (!IsValidISADictionary(parent_dictionary, parent_key, sandbox_isa_, true,
581*6777b538SAndroid Build Coastguard Worker &ignored_error_info)) {
582*6777b538SAndroid Build Coastguard Worker error_info->error = PP_NACL_ERROR_MANIFEST_RESOLVE_URL;
583*6777b538SAndroid Build Coastguard Worker error_info->string = "architecture " + sandbox_isa_ +
584*6777b538SAndroid Build Coastguard Worker " is not found for file " + parent_key;
585*6777b538SAndroid Build Coastguard Worker return false;
586*6777b538SAndroid Build Coastguard Worker }
587*6777b538SAndroid Build Coastguard Worker
588*6777b538SAndroid Build Coastguard Worker // The call to IsValidISADictionary() above guarantees that either
589*6777b538SAndroid Build Coastguard Worker // sandbox_isa_ or kPortableKey is present in the dictionary.
590*6777b538SAndroid Build Coastguard Worker std::string chosen_isa;
591*6777b538SAndroid Build Coastguard Worker if (sandbox_isa_ == kPortableKey) {
592*6777b538SAndroid Build Coastguard Worker chosen_isa = kPortableKey;
593*6777b538SAndroid Build Coastguard Worker } else {
594*6777b538SAndroid Build Coastguard Worker if (dictionary->Find(sandbox_isa_)) {
595*6777b538SAndroid Build Coastguard Worker chosen_isa = sandbox_isa_;
596*6777b538SAndroid Build Coastguard Worker } else if (dictionary->Find(kPortableKey)) {
597*6777b538SAndroid Build Coastguard Worker chosen_isa = kPortableKey;
598*6777b538SAndroid Build Coastguard Worker } else {
599*6777b538SAndroid Build Coastguard Worker // Should not reach here, because the earlier IsValidISADictionary()
600*6777b538SAndroid Build Coastguard Worker // call checked that the manifest covers the current architecture.
601*6777b538SAndroid Build Coastguard Worker NOTREACHED();
602*6777b538SAndroid Build Coastguard Worker return false;
603*6777b538SAndroid Build Coastguard Worker }
604*6777b538SAndroid Build Coastguard Worker }
605*6777b538SAndroid Build Coastguard Worker
606*6777b538SAndroid Build Coastguard Worker const base::Value::Dict* isa_spec = dictionary->FindDict(chosen_isa);
607*6777b538SAndroid Build Coastguard Worker if (!isa_spec) {
608*6777b538SAndroid Build Coastguard Worker error_info->error = PP_NACL_ERROR_MANIFEST_RESOLVE_URL;
609*6777b538SAndroid Build Coastguard Worker error_info->string = std::string("GetURLFromISADictionary failed: ") +
610*6777b538SAndroid Build Coastguard Worker chosen_isa + "'s value is not a json dictionary.";
611*6777b538SAndroid Build Coastguard Worker return false;
612*6777b538SAndroid Build Coastguard Worker }
613*6777b538SAndroid Build Coastguard Worker // If the PNaCl debug flag is turned on, look for pnacl-debug entries first.
614*6777b538SAndroid Build Coastguard Worker // If found, mark that it is a debug URL. Otherwise, fall back to
615*6777b538SAndroid Build Coastguard Worker // checking for pnacl-translate URLs, etc. and don't mark it as a debug URL.
616*6777b538SAndroid Build Coastguard Worker if (pnacl_debug_ && isa_spec->Find(kPnaclDebugKey)) {
617*6777b538SAndroid Build Coastguard Worker const base::Value::Dict* pnacl_dict = isa_spec->FindDict(kPnaclDebugKey);
618*6777b538SAndroid Build Coastguard Worker if (!pnacl_dict) {
619*6777b538SAndroid Build Coastguard Worker error_info->error = PP_NACL_ERROR_MANIFEST_RESOLVE_URL;
620*6777b538SAndroid Build Coastguard Worker error_info->string = std::string("GetURLFromISADictionary failed: ") +
621*6777b538SAndroid Build Coastguard Worker kPnaclDebugKey +
622*6777b538SAndroid Build Coastguard Worker "'s value is not a json dictionary.";
623*6777b538SAndroid Build Coastguard Worker return false;
624*6777b538SAndroid Build Coastguard Worker }
625*6777b538SAndroid Build Coastguard Worker GrabUrlAndPnaclOptions(*pnacl_dict, url, pnacl_options);
626*6777b538SAndroid Build Coastguard Worker pnacl_options->is_debug = PP_TRUE;
627*6777b538SAndroid Build Coastguard Worker } else if (isa_spec->Find(kPnaclTranslateKey)) {
628*6777b538SAndroid Build Coastguard Worker const base::Value::Dict* pnacl_dict =
629*6777b538SAndroid Build Coastguard Worker isa_spec->FindDict(kPnaclTranslateKey);
630*6777b538SAndroid Build Coastguard Worker if (!pnacl_dict) {
631*6777b538SAndroid Build Coastguard Worker error_info->error = PP_NACL_ERROR_MANIFEST_RESOLVE_URL;
632*6777b538SAndroid Build Coastguard Worker error_info->string = std::string("GetURLFromISADictionary failed: ") +
633*6777b538SAndroid Build Coastguard Worker kPnaclTranslateKey +
634*6777b538SAndroid Build Coastguard Worker "'s value is not a json dictionary.";
635*6777b538SAndroid Build Coastguard Worker return false;
636*6777b538SAndroid Build Coastguard Worker }
637*6777b538SAndroid Build Coastguard Worker GrabUrlAndPnaclOptions(*pnacl_dict, url, pnacl_options);
638*6777b538SAndroid Build Coastguard Worker } else {
639*6777b538SAndroid Build Coastguard Worker // The native NaCl case.
640*6777b538SAndroid Build Coastguard Worker const std::string* url_str = isa_spec->FindString(kUrlKey);
641*6777b538SAndroid Build Coastguard Worker if (!url_str) {
642*6777b538SAndroid Build Coastguard Worker error_info->error = PP_NACL_ERROR_MANIFEST_RESOLVE_URL;
643*6777b538SAndroid Build Coastguard Worker error_info->string = std::string("GetURLFromISADictionary failed: ") +
644*6777b538SAndroid Build Coastguard Worker kUrlKey + "'s value is not a string.";
645*6777b538SAndroid Build Coastguard Worker return false;
646*6777b538SAndroid Build Coastguard Worker }
647*6777b538SAndroid Build Coastguard Worker *url = *url_str;
648*6777b538SAndroid Build Coastguard Worker pnacl_options->translate = PP_FALSE;
649*6777b538SAndroid Build Coastguard Worker }
650*6777b538SAndroid Build Coastguard Worker
651*6777b538SAndroid Build Coastguard Worker return true;
652*6777b538SAndroid Build Coastguard Worker }
653*6777b538SAndroid Build Coastguard Worker
654*6777b538SAndroid Build Coastguard Worker } // namespace nacl
655