Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(195)

Side by Side Diff: components/nacl/renderer/json_manifest.cc

Issue 264943003: Pepper: Move manifest logic to components/nacl. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 * Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be
3 * Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file.
4 * found in the LICENSE file.
5 */
6 4
7 #include <algorithm> 5 #include "components/nacl/renderer/json_manifest.h"
8 6
9 #include "ppapi/native_client/src/trusted/plugin/json_manifest.h" 7 #include <set>
10 8
11 #include <stdlib.h> 9 #include "base/logging.h"
10 #include "base/macros.h"
11 #include "components/nacl/renderer/nexe_load_manager.h"
12 #include "third_party/jsoncpp/source/include/json/reader.h"
13 #include "third_party/jsoncpp/source/include/json/value.h"
14 #include "url/gurl.h"
12 15
13 #include "native_client/src/include/nacl_base.h" 16 namespace nacl {
14 #include "native_client/src/include/nacl_macros.h"
15 #include "native_client/src/include/nacl_string.h"
16 #include "native_client/src/include/portability.h"
17 #include "native_client/src/shared/platform/nacl_check.h"
18 #include "ppapi/c/private/ppb_nacl_private.h"
19 #include "ppapi/cpp/dev/url_util_dev.h"
20 #include "ppapi/cpp/var.h"
21 #include "ppapi/native_client/src/trusted/plugin/plugin_error.h"
22 #include "ppapi/native_client/src/trusted/plugin/utility.h"
23 #include "third_party/jsoncpp/source/include/json/reader.h"
bbudge 2014/05/01 23:32:33 Nice to get rid of all this!
24
25 namespace plugin {
26 17
27 namespace { 18 namespace {
28 // Top-level section name keys 19 // Top-level section name keys
29 const char* const kProgramKey = "program"; 20 const char* const kProgramKey = "program";
30 const char* const kInterpreterKey = "interpreter"; 21 const char* const kInterpreterKey = "interpreter";
31 const char* const kFilesKey = "files"; 22 const char* const kFilesKey = "files";
32 23
33 // ISA Dictionary keys 24 // ISA Dictionary keys
34 const char* const kX8632Key = "x86-32"; 25 const char* const kX8632Key = "x86-32";
35 const char* const kX8632NonSFIKey = "x86-32-nonsfi"; 26 const char* const kX8632NonSFIKey = "x86-32-nonsfi";
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
90 // "foo.txt": { 81 // "foo.txt": {
91 // "portable": {"url": "foo.txt"} 82 // "portable": {"url": "foo.txt"}
92 // }, 83 // },
93 // "bar.txt": { 84 // "bar.txt": {
94 // "portable": {"url": "bar.txt"} 85 // "portable": {"url": "bar.txt"}
95 // } 86 // }
96 // } 87 // }
97 // } 88 // }
98 89
99 // Returns the key for the architecture in non-SFI mode. 90 // Returns the key for the architecture in non-SFI mode.
100 nacl::string GetNonSFIKey(const nacl::string& sandbox_isa) { 91 std::string GetNonSFIKey(const std::string& sandbox_isa) {
101 return sandbox_isa + "-nonsfi"; 92 return sandbox_isa + "-nonsfi";
102 } 93 }
103 94
104 // Looks up |property_name| in the vector |valid_names| with length 95 // Looks up |property_name| in the vector |valid_names| with length
105 // |valid_name_count|. Returns true if |property_name| is found. 96 // |valid_name_count|. Returns true if |property_name| is found.
106 bool FindMatchingProperty(const nacl::string& property_name, 97 bool FindMatchingProperty(const std::string& property_name,
107 const char** valid_names, 98 const char** valid_names,
108 size_t valid_name_count) { 99 size_t valid_name_count) {
109 for (size_t i = 0; i < valid_name_count; ++i) { 100 for (size_t i = 0; i < valid_name_count; ++i) {
110 if (property_name == valid_names[i]) { 101 if (property_name == valid_names[i]) {
111 return true; 102 return true;
112 } 103 }
113 } 104 }
114 return false; 105 return false;
115 } 106 }
116 107
117 // Return true if this is a valid dictionary. Having only keys present in 108 // Return true if this is a valid dictionary. Having only keys present in
118 // |valid_keys| and having at least the keys in |required_keys|. 109 // |valid_keys| and having at least the keys in |required_keys|.
119 // Error messages will be placed in |error_string|, given that the dictionary 110 // Error messages will be placed in |error_string|, given that the dictionary
120 // was the property value of |container_key|. 111 // was the property value of |container_key|.
121 // E.g., "container_key" : dictionary 112 // E.g., "container_key" : dictionary
122 bool IsValidDictionary(const Json::Value& dictionary, 113 bool IsValidDictionary(const Json::Value& dictionary,
123 const nacl::string& container_key, 114 const std::string& container_key,
124 const nacl::string& parent_key, 115 const std::string& parent_key,
125 const char** valid_keys, 116 const char** valid_keys,
126 size_t valid_key_count, 117 size_t valid_key_count,
127 const char** required_keys, 118 const char** required_keys,
128 size_t required_key_count, 119 size_t required_key_count,
129 nacl::string* error_string) { 120 std::string* error_string) {
130 if (!dictionary.isObject()) { 121 if (!dictionary.isObject()) {
131 nacl::stringstream error_stream; 122 std::stringstream error_stream;
132 error_stream << parent_key << " property '" << container_key 123 error_stream << parent_key << " property '" << container_key
133 << "' is non-dictionary value '" 124 << "' is non-dictionary value '"
134 << dictionary.toStyledString() << "'."; 125 << dictionary.toStyledString() << "'.";
135 *error_string = error_stream.str(); 126 *error_string = error_stream.str();
136 return false; 127 return false;
137 } 128 }
138 // Check for unknown dictionary members. 129 // Check for unknown dictionary members.
139 Json::Value::Members members = dictionary.getMemberNames(); 130 Json::Value::Members members = dictionary.getMemberNames();
140 for (size_t i = 0; i < members.size(); ++i) { 131 for (size_t i = 0; i < members.size(); ++i) {
141 nacl::string property_name = members[i]; 132 std::string property_name = members[i];
142 if (!FindMatchingProperty(property_name, 133 if (!FindMatchingProperty(property_name,
143 valid_keys, 134 valid_keys,
144 valid_key_count)) { 135 valid_key_count)) {
145 // For forward compatibility, we do not prohibit other keys being in 136 // For forward compatibility, we do not prohibit other keys being in
146 // the dictionary. 137 // the dictionary.
147 PLUGIN_PRINTF(("WARNING: '%s' property '%s' has unknown key '%s'.\n", 138 VLOG(1) << "WARNING: '" << parent_key << "' property '"
148 parent_key.c_str(), 139 << container_key << "' has unknown key '"
149 container_key.c_str(), property_name.c_str())); 140 << property_name << "'.";
150 } 141 }
151 } 142 }
152 // Check for required members. 143 // Check for required members.
153 for (size_t i = 0; i < required_key_count; ++i) { 144 for (size_t i = 0; i < required_key_count; ++i) {
154 if (!dictionary.isMember(required_keys[i])) { 145 if (!dictionary.isMember(required_keys[i])) {
155 nacl::stringstream error_stream; 146 std::stringstream error_stream;
156 error_stream << parent_key << " property '" << container_key 147 error_stream << parent_key << " property '" << container_key
157 << "' does not have required key: '" 148 << "' does not have required key: '"
158 << required_keys[i] << "'."; 149 << required_keys[i] << "'.";
159 *error_string = error_stream.str(); 150 *error_string = error_stream.str();
160 return false; 151 return false;
161 } 152 }
162 } 153 }
163 return true; 154 return true;
164 } 155 }
165 156
166 // Validate a "url" dictionary assuming it was resolved from container_key. 157 // Validate a "url" dictionary assuming it was resolved from container_key.
167 // E.g., "container_key" : { "url": "foo.txt" } 158 // E.g., "container_key" : { "url": "foo.txt" }
168 bool IsValidUrlSpec(const Json::Value& url_spec, 159 bool IsValidUrlSpec(const Json::Value& url_spec,
169 const nacl::string& container_key, 160 const std::string& container_key,
170 const nacl::string& parent_key, 161 const std::string& parent_key,
171 const nacl::string& sandbox_isa, 162 const std::string& sandbox_isa,
172 nacl::string* error_string) { 163 std::string* error_string) {
173 static const char* kManifestUrlSpecRequired[] = { 164 static const char* kManifestUrlSpecRequired[] = {
174 kUrlKey 165 kUrlKey
175 }; 166 };
176 const char** urlSpecPlusOptional; 167 const char** urlSpecPlusOptional;
177 size_t urlSpecPlusOptionalLength; 168 size_t urlSpecPlusOptionalLength;
178 if (sandbox_isa == kPortableKey) { 169 if (sandbox_isa == kPortableKey) {
179 static const char* kPnaclUrlSpecPlusOptional[] = { 170 static const char* kPnaclUrlSpecPlusOptional[] = {
180 kUrlKey, 171 kUrlKey,
181 kOptLevelKey, 172 kOptLevelKey,
182 }; 173 };
183 urlSpecPlusOptional = kPnaclUrlSpecPlusOptional; 174 urlSpecPlusOptional = kPnaclUrlSpecPlusOptional;
184 urlSpecPlusOptionalLength = NACL_ARRAY_SIZE(kPnaclUrlSpecPlusOptional); 175 urlSpecPlusOptionalLength = arraysize(kPnaclUrlSpecPlusOptional);
185 } else { 176 } else {
186 // URL specifications must not contain "pnacl-translate" keys. 177 // URL specifications must not contain "pnacl-translate" keys.
187 // This prohibits NaCl clients from invoking PNaCl. 178 // This prohibits NaCl clients from invoking PNaCl.
188 if (url_spec.isMember(kPnaclTranslateKey)) { 179 if (url_spec.isMember(kPnaclTranslateKey)) {
189 nacl::stringstream error_stream; 180 std::stringstream error_stream;
190 error_stream << "PNaCl-like NMF with application/x-nacl mimetype instead " 181 error_stream << "PNaCl-like NMF with application/x-nacl mimetype instead "
191 << "of x-pnacl mimetype (has " << kPnaclTranslateKey << ")."; 182 << "of x-pnacl mimetype (has " << kPnaclTranslateKey << ").";
192 *error_string = error_stream.str(); 183 *error_string = error_stream.str();
193 return false; 184 return false;
194 } 185 }
195 urlSpecPlusOptional = kManifestUrlSpecRequired; 186 urlSpecPlusOptional = kManifestUrlSpecRequired;
196 urlSpecPlusOptionalLength = NACL_ARRAY_SIZE(kManifestUrlSpecRequired); 187 urlSpecPlusOptionalLength = arraysize(kManifestUrlSpecRequired);
197 } 188 }
198 if (!IsValidDictionary(url_spec, container_key, parent_key, 189 if (!IsValidDictionary(url_spec, container_key, parent_key,
199 urlSpecPlusOptional, 190 urlSpecPlusOptional,
200 urlSpecPlusOptionalLength, 191 urlSpecPlusOptionalLength,
201 kManifestUrlSpecRequired, 192 kManifestUrlSpecRequired,
202 NACL_ARRAY_SIZE(kManifestUrlSpecRequired), 193 arraysize(kManifestUrlSpecRequired),
203 error_string)) { 194 error_string)) {
204 return false; 195 return false;
205 } 196 }
206 // Verify the correct types of the fields if they exist. 197 // Verify the correct types of the fields if they exist.
207 Json::Value url = url_spec[kUrlKey]; 198 Json::Value url = url_spec[kUrlKey];
208 if (!url.isString()) { 199 if (!url.isString()) {
209 nacl::stringstream error_stream; 200 std::stringstream error_stream;
210 error_stream << parent_key << " property '" << container_key << 201 error_stream << parent_key << " property '" << container_key <<
211 "' has non-string value '" << url.toStyledString() << 202 "' has non-string value '" << url.toStyledString() <<
212 "' for key '" << kUrlKey << "'."; 203 "' for key '" << kUrlKey << "'.";
213 *error_string = error_stream.str(); 204 *error_string = error_stream.str();
214 return false; 205 return false;
215 } 206 }
216 Json::Value opt_level = url_spec[kOptLevelKey]; 207 Json::Value opt_level = url_spec[kOptLevelKey];
217 if (!opt_level.empty() && !opt_level.isNumeric()) { 208 if (!opt_level.empty() && !opt_level.isNumeric()) {
218 nacl::stringstream error_stream; 209 std::stringstream error_stream;
219 error_stream << parent_key << " property '" << container_key << 210 error_stream << parent_key << " property '" << container_key <<
220 "' has non-numeric value '" << opt_level.toStyledString() << 211 "' has non-numeric value '" << opt_level.toStyledString() <<
221 "' for key '" << kOptLevelKey << "'."; 212 "' for key '" << kOptLevelKey << "'.";
222 *error_string = error_stream.str(); 213 *error_string = error_stream.str();
223 return false; 214 return false;
224 } 215 }
225 return true; 216 return true;
226 } 217 }
227 218
228 // Validate a "pnacl-translate" or "pnacl-debug" dictionary, assuming 219 // Validate a "pnacl-translate" or "pnacl-debug" dictionary, assuming
229 // it was resolved from container_key. 220 // it was resolved from container_key.
230 // E.g., "container_key" : { "pnacl-translate" : URLSpec } 221 // E.g., "container_key" : { "pnacl-translate" : URLSpec }
231 bool IsValidPnaclTranslateSpec(const Json::Value& pnacl_spec, 222 bool IsValidPnaclTranslateSpec(const Json::Value& pnacl_spec,
232 const nacl::string& container_key, 223 const std::string& container_key,
233 const nacl::string& parent_key, 224 const std::string& parent_key,
234 const nacl::string& sandbox_isa, 225 const std::string& sandbox_isa,
235 nacl::string* error_string) { 226 std::string* error_string) {
236 static const char* kManifestPnaclSpecValid[] = { 227 static const char* kManifestPnaclSpecValid[] = {
237 kPnaclDebugKey, 228 kPnaclDebugKey,
238 kPnaclTranslateKey 229 kPnaclTranslateKey
239 }; 230 };
240 static const char* kManifestPnaclSpecRequired[] = { 231 static const char* kManifestPnaclSpecRequired[] = { kPnaclTranslateKey };
241 kPnaclTranslateKey
242 };
243 if (!IsValidDictionary(pnacl_spec, container_key, parent_key, 232 if (!IsValidDictionary(pnacl_spec, container_key, parent_key,
244 kManifestPnaclSpecValid, 233 kManifestPnaclSpecValid,
245 NACL_ARRAY_SIZE(kManifestPnaclSpecValid), 234 arraysize(kManifestPnaclSpecValid),
246 kManifestPnaclSpecRequired, 235 kManifestPnaclSpecRequired,
247 NACL_ARRAY_SIZE(kManifestPnaclSpecRequired), 236 arraysize(kManifestPnaclSpecRequired),
248 error_string)) { 237 error_string)) {
249 return false; 238 return false;
250 } 239 }
251 Json::Value url_spec = pnacl_spec[kPnaclTranslateKey]; 240 Json::Value url_spec = pnacl_spec[kPnaclTranslateKey];
252 if (!IsValidUrlSpec(url_spec, kPnaclTranslateKey, 241 return IsValidUrlSpec(url_spec, kPnaclTranslateKey,
253 container_key, sandbox_isa, error_string)) { 242 container_key, sandbox_isa, error_string);
254 return false;
255 }
256 return true;
257 } 243 }
258 244
259 // Validates that |dictionary| is a valid ISA dictionary. An ISA dictionary 245 // Validates that |dictionary| is a valid ISA dictionary. An ISA dictionary
260 // is validated to have keys from within the set of recognized ISAs. Unknown 246 // is validated to have keys from within the set of recognized ISAs. Unknown
261 // ISAs are allowed, but ignored and warnings are produced. It is also validated 247 // ISAs are allowed, but ignored and warnings are produced. It is also
248 // validated
262 // that it must have an entry to match the ISA specified in |sandbox_isa| or 249 // that it must have an entry to match the ISA specified in |sandbox_isa| or
263 // have a fallback 'portable' entry if there is no match. Returns true if 250 // have a fallback 'portable' entry if there is no match. Returns true if
264 // |dictionary| is an ISA to URL map. Sets |error_info| to something 251 // |dictionary| is an ISA to URL map. Sets |error_info| to something
265 // descriptive if it fails. 252 // descriptive if it fails.
266 bool IsValidISADictionary(const Json::Value& dictionary, 253 bool IsValidISADictionary(const Json::Value& dictionary,
267 const nacl::string& parent_key, 254 const std::string& parent_key,
268 const nacl::string& sandbox_isa, 255 const std::string& sandbox_isa,
269 bool must_find_matching_entry, 256 bool must_find_matching_entry,
270 bool nonsfi_enabled, 257 bool nonsfi_enabled,
271 ErrorInfo* error_info) { 258 JsonManifest::ErrorInfo* error_info) {
272 if (error_info == NULL) return false;
273
274 // An ISA to URL dictionary has to be an object. 259 // An ISA to URL dictionary has to be an object.
275 if (!dictionary.isObject()) { 260 if (!dictionary.isObject()) {
276 error_info->SetReport(PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE, 261 error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
277 nacl::string("manifest: ") + parent_key + 262 error_info->string = std::string("manifest: ") + parent_key +
278 " property is not an ISA to URL dictionary"); 263 " property is not an ISA to URL dictionary";
279 return false; 264 return false;
280 } 265 }
281 // Build the set of reserved ISA dictionary keys. 266 // Build the set of reserved ISA dictionary keys.
282 const char** isaProperties; 267 const char** isaProperties;
283 size_t isaPropertiesLength; 268 size_t isaPropertiesLength;
284 if (sandbox_isa == kPortableKey) { 269 if (sandbox_isa == kPortableKey) {
285 // The known values for PNaCl ISA dictionaries in the manifest. 270 // The known values for PNaCl ISA dictionaries in the manifest.
286 static const char* kPnaclManifestISAProperties[] = { 271 static const char* kPnaclManifestISAProperties[] = {
287 kPortableKey 272 kPortableKey
288 }; 273 };
289 isaProperties = kPnaclManifestISAProperties; 274 isaProperties = kPnaclManifestISAProperties;
290 isaPropertiesLength = NACL_ARRAY_SIZE(kPnaclManifestISAProperties); 275 isaPropertiesLength = arraysize(kPnaclManifestISAProperties);
291 } else { 276 } else {
292 // The known values for NaCl ISA dictionaries in the manifest. 277 // The known values for NaCl ISA dictionaries in the manifest.
293 static const char* kNaClManifestISAProperties[] = { 278 static const char* kNaClManifestISAProperties[] = {
294 kX8632Key, 279 kX8632Key,
295 kX8632NonSFIKey, 280 kX8632NonSFIKey,
296 kX8664Key, 281 kX8664Key,
297 kX8664NonSFIKey, 282 kX8664NonSFIKey,
298 kArmKey, 283 kArmKey,
299 kArmNonSFIKey, 284 kArmNonSFIKey,
300 // "portable" is here to allow checking that, if present, it can 285 // "portable" is here to allow checking that, if present, it can
301 // only refer to an URL, such as for a data file, and not to 286 // only refer to an URL, such as for a data file, and not to
302 // "pnacl-translate", which would cause the creation of a nexe. 287 // "pnacl-translate", which would cause the creation of a nexe.
303 kPortableKey 288 kPortableKey
304 }; 289 };
305 isaProperties = kNaClManifestISAProperties; 290 isaProperties = kNaClManifestISAProperties;
306 isaPropertiesLength = NACL_ARRAY_SIZE(kNaClManifestISAProperties); 291 isaPropertiesLength = arraysize(kNaClManifestISAProperties);
307 } 292 }
308 // Check that entries in the dictionary are structurally correct. 293 // Check that entries in the dictionary are structurally correct.
309 Json::Value::Members members = dictionary.getMemberNames(); 294 Json::Value::Members members = dictionary.getMemberNames();
310 for (size_t i = 0; i < members.size(); ++i) { 295 for (size_t i = 0; i < members.size(); ++i) {
311 nacl::string property_name = members[i]; 296 std::string property_name = members[i];
312 Json::Value property_value = dictionary[property_name]; 297 Json::Value property_value = dictionary[property_name];
313 nacl::string error_string; 298 std::string error_string;
314 if (FindMatchingProperty(property_name, 299 if (FindMatchingProperty(property_name,
315 isaProperties, 300 isaProperties,
316 isaPropertiesLength)) { 301 isaPropertiesLength)) {
317 // For NaCl, arch entries can only be 302 // For NaCl, arch entries can only be
318 // "arch/portable" : URLSpec 303 // "arch/portable" : URLSpec
319 // For PNaCl arch in "program" dictionary entries can be 304 // For PNaCl arch in "program" dictionary entries can be
320 // "portable" : { "pnacl-translate": URLSpec } 305 // "portable" : { "pnacl-translate": URLSpec }
321 // or "portable" : { "pnacl-debug": URLSpec } 306 // or "portable" : { "pnacl-debug": URLSpec }
322 // For PNaCl arch elsewhere, dictionary entries can only be 307 // For PNaCl arch elsewhere, dictionary entries can only be
323 // "portable" : URLSpec 308 // "portable" : URLSpec
324 if ((sandbox_isa != kPortableKey && 309 if ((sandbox_isa != kPortableKey &&
325 !IsValidUrlSpec(property_value, property_name, parent_key, 310 !IsValidUrlSpec(property_value, property_name, parent_key,
326 sandbox_isa, &error_string)) || 311 sandbox_isa, &error_string)) ||
327 (sandbox_isa == kPortableKey && 312 (sandbox_isa == kPortableKey &&
328 parent_key == kProgramKey && 313 parent_key == kProgramKey &&
329 !IsValidPnaclTranslateSpec(property_value, property_name, parent_key, 314 !IsValidPnaclTranslateSpec(property_value, property_name, parent_key,
330 sandbox_isa, &error_string)) || 315 sandbox_isa, &error_string)) ||
331 (sandbox_isa == kPortableKey && 316 (sandbox_isa == kPortableKey &&
332 parent_key != kProgramKey && 317 parent_key != kProgramKey &&
333 !IsValidUrlSpec(property_value, property_name, parent_key, 318 !IsValidUrlSpec(property_value, property_name, parent_key,
334 sandbox_isa, &error_string))) { 319 sandbox_isa, &error_string))) {
335 error_info->SetReport(PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE, 320 error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
336 nacl::string("manifest: ") + error_string); 321 error_info->string = "manifest: " + error_string;
337 return false; 322 return false;
338 } 323 }
339 } else { 324 } else {
340 // For forward compatibility, we do not prohibit other keys being in 325 // For forward compatibility, we do not prohibit other keys being in
341 // the dictionary, as they may be architectures supported in later 326 // the dictionary, as they may be architectures supported in later
342 // versions. However, the value of these entries must be an URLSpec. 327 // versions. However, the value of these entries must be an URLSpec.
343 PLUGIN_PRINTF(("IsValidISADictionary: unrecognized key '%s'.\n", 328 VLOG(1) << "IsValidISADictionary: unrecognized key '"
344 property_name.c_str())); 329 << property_name << "'.";
345 if (!IsValidUrlSpec(property_value, property_name, parent_key, 330 if (!IsValidUrlSpec(property_value, property_name, parent_key,
346 sandbox_isa, &error_string)) { 331 sandbox_isa, &error_string)) {
347 error_info->SetReport(PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE, 332 error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
348 nacl::string("manifest: ") + error_string); 333 error_info->string = "manifest: " + error_string;
349 return false; 334 return false;
350 } 335 }
351 } 336 }
352 } 337 }
353 338
354 if (sandbox_isa == kPortableKey) { 339 if (sandbox_isa == kPortableKey) {
355 bool has_portable = dictionary.isMember(kPortableKey); 340 if (!dictionary.isMember(kPortableKey)) {
356 341 error_info->error = PP_NACL_ERROR_MANIFEST_PROGRAM_MISSING_ARCH;
357 if (!has_portable) { 342 error_info->string = "manifest: no version of " + parent_key +
358 error_info->SetReport( 343 " given for portable.";
359 PP_NACL_ERROR_MANIFEST_PROGRAM_MISSING_ARCH,
360 nacl::string("manifest: no version of ") + parent_key +
361 " given for portable.");
362 return false; 344 return false;
363 } 345 }
364 } else if (must_find_matching_entry) { 346 } else if (must_find_matching_entry) {
365 // TODO(elijahtaylor) add ISA resolver here if we expand ISAs to include 347 // TODO(elijahtaylor) add ISA resolver here if we expand ISAs to include
366 // micro-architectures that can resolve to multiple valid sandboxes. 348 // micro-architectures that can resolve to multiple valid sandboxes.
367 bool has_isa = dictionary.isMember(sandbox_isa); 349 bool has_isa = dictionary.isMember(sandbox_isa);
368 bool has_nonsfi_isa = 350 bool has_nonsfi_isa =
369 nonsfi_enabled && dictionary.isMember(GetNonSFIKey(sandbox_isa)); 351 nonsfi_enabled && dictionary.isMember(GetNonSFIKey(sandbox_isa));
370 bool has_portable = dictionary.isMember(kPortableKey); 352 bool has_portable = dictionary.isMember(kPortableKey);
371 353
372 if (!has_isa && !has_nonsfi_isa && !has_portable) { 354 if (!has_isa && !has_nonsfi_isa && !has_portable) {
373 error_info->SetReport( 355 error_info->error = PP_NACL_ERROR_MANIFEST_PROGRAM_MISSING_ARCH;
374 PP_NACL_ERROR_MANIFEST_PROGRAM_MISSING_ARCH, 356 error_info->string = "manifest: no version of " + parent_key +
375 nacl::string("manifest: no version of ") + parent_key + 357 " given for current arch and no portable version found.";
376 " given for current arch and no portable version found.");
377 return false; 358 return false;
378 } 359 }
379 } 360 }
380
381 return true; 361 return true;
382 } 362 }
383 363
384 void GrabUrlAndPNaClOptions(const Json::Value& url_spec, 364 void GrabUrlAndPnaclOptions(const Json::Value& url_spec,
385 nacl::string* url, 365 std::string* url,
386 PP_PNaClOptions* pnacl_options) { 366 PP_PNaClOptions* pnacl_options) {
387 *url = url_spec[kUrlKey].asString(); 367 *url = url_spec[kUrlKey].asString();
388 pnacl_options->translate = PP_TRUE; 368 pnacl_options->translate = PP_TRUE;
389 if (url_spec.isMember(kOptLevelKey)) { 369 if (url_spec.isMember(kOptLevelKey)) {
390 int32_t opt_raw = url_spec[kOptLevelKey].asInt(); 370 int32_t opt_raw = url_spec[kOptLevelKey].asInt();
391 int32_t opt_level;
392 // Currently only allow 0 or 2, since that is what we test. 371 // Currently only allow 0 or 2, since that is what we test.
393 if (opt_raw <= 0) 372 if (opt_raw <= 0)
394 opt_level = 0; 373 pnacl_options->opt_level = 0;
395 else 374 else
396 opt_level = 2; 375 pnacl_options->opt_level = 2;
397 pnacl_options->opt_level = opt_level;
398 } 376 }
399 } 377 }
400 378
401 } // namespace 379 } // namespace
402 380
403 bool JsonManifest::Init(const nacl::string& manifest_json, 381 JsonManifest::JsonManifest(const std::string& manifest_base_url,
382 const std::string& sandbox_isa,
383 bool nonsfi_enabled,
384 bool pnacl_debug)
385 : manifest_base_url_(manifest_base_url),
386 sandbox_isa_(sandbox_isa),
387 nonsfi_enabled_(nonsfi_enabled),
388 pnacl_debug_(pnacl_debug) { }
389
390 bool JsonManifest::Init(const std::string& manifest_json,
404 ErrorInfo* error_info) { 391 ErrorInfo* error_info) {
405 if (error_info == NULL) { 392 CHECK(error_info);
406 return false; 393
407 }
408 Json::Reader reader; 394 Json::Reader reader;
409 if (!reader.parse(manifest_json, dictionary_)) { 395 if (!reader.parse(manifest_json, dictionary_)) {
410 std::string json_error = reader.getFormatedErrorMessages(); 396 std::string json_error = reader.getFormattedErrorMessages();
411 error_info->SetReport(PP_NACL_ERROR_MANIFEST_PARSING, 397 error_info->error = PP_NACL_ERROR_MANIFEST_PARSING;
412 "manifest JSON parsing failed: " + json_error); 398 error_info->string = "manifest JSON parsing failed: " + json_error;
413 return false; 399 return false;
414 } 400 }
415 // Parse has ensured the string was valid JSON. Check that it matches the 401 // Parse has ensured the string was valid JSON. Check that it matches the
416 // manifest schema. 402 // manifest schema.
417 return MatchesSchema(error_info); 403 return MatchesSchema(error_info);
418 } 404 }
419 405
420 bool JsonManifest::MatchesSchema(ErrorInfo* error_info) { 406 bool JsonManifest::GetProgramURL(std::string* full_url,
421 pp::Var exception; 407 PP_PNaClOptions* pnacl_options,
422 if (error_info == NULL) { 408 bool* uses_nonsfi_mode,
409 ErrorInfo* error_info) const {
410 if (!full_url)
411 return false;
412 CHECK(pnacl_options);
413 CHECK(uses_nonsfi_mode);
414 CHECK(error_info);
415
416 const Json::Value& program = dictionary_[kProgramKey];
417 std::string nexe_url;
418 if (!GetURLFromISADictionary(program,
419 kProgramKey,
420 &nexe_url,
421 pnacl_options,
422 uses_nonsfi_mode,
423 error_info)) {
423 return false; 424 return false;
424 } 425 }
426
427 // The contents of the manifest are resolved relative to the manifest URL.
428 GURL base_gurl(manifest_base_url_);
429 if (!base_gurl.is_valid())
430 return false;
431
432 GURL resolved_gurl = base_gurl.Resolve(nexe_url);
433 if (!resolved_gurl.is_valid()) {
434 error_info->error = PP_NACL_ERROR_MANIFEST_RESOLVE_URL;
435 error_info->string =
436 "could not resolve url '" + nexe_url +
437 "' relative to manifest base url '" + manifest_base_url_.c_str() +
438 "'.";
439 return false;
440 }
441 *full_url = resolved_gurl.possibly_invalid_spec();
442 return true;
443 }
444
445 bool JsonManifest::ResolveKey(const std::string& key,
446 std::string* full_url,
447 PP_PNaClOptions* pnacl_options) const {
448 // key must be one of kProgramKey or kFileKey '/' file-section-key
449 if (full_url == NULL || pnacl_options == NULL)
450 return false;
451
452 if (key == kProgramKey)
453 return GetKeyUrl(dictionary_, key, full_url, pnacl_options);
454
455 std::string::const_iterator p = find(key.begin(), key.end(), '/');
456 if (p == key.end()) {
457 VLOG(1) << "ResolveKey failed: invalid key, no slash: " << key;
458 return false;
459 }
460
461 // generalize to permit other sections?
462 std::string prefix(key.begin(), p);
463 if (prefix != kFilesKey) {
464 VLOG(1) << "ResolveKey failed: invalid key, no \"files\" prefix: " << key;
465 return false;
466 }
467
468 const Json::Value& files = dictionary_[kFilesKey];
469 if (!files.isObject()) {
470 VLOG(1) << "ResolveKey failed: no \"files\" dictionary";
471 return false;
472 }
473
474 std::string rest(p + 1, key.end());
475 if (!files.isMember(rest)) {
476 VLOG(1) << "ResolveKey failed: no such \"files\" entry: " << key;
477 return false;
478 }
479 return GetKeyUrl(files, rest, full_url, pnacl_options);
480 }
481
482 bool JsonManifest::MatchesSchema(ErrorInfo* error_info) {
425 if (!dictionary_.isObject()) { 483 if (!dictionary_.isObject()) {
426 error_info->SetReport( 484 error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
427 PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE, 485 error_info->string = "manifest: is not a json dictionary.";
428 "manifest: is not a json dictionary.");
429 return false; 486 return false;
430 } 487 }
431 Json::Value::Members members = dictionary_.getMemberNames(); 488 Json::Value::Members members = dictionary_.getMemberNames();
432 for (size_t i = 0; i < members.size(); ++i) { 489 for (size_t i = 0; i < members.size(); ++i) {
433 // The top level dictionary entries valid in the manifest file. 490 // The top level dictionary entries valid in the manifest file.
434 static const char* kManifestTopLevelProperties[] = { kProgramKey, 491 static const char* kManifestTopLevelProperties[] = { kProgramKey,
435 kInterpreterKey, 492 kInterpreterKey,
436 kFilesKey }; 493 kFilesKey };
437 nacl::string property_name = members[i]; 494 std::string property_name = members[i];
438 if (!FindMatchingProperty(property_name, 495 if (!FindMatchingProperty(property_name,
439 kManifestTopLevelProperties, 496 kManifestTopLevelProperties,
440 NACL_ARRAY_SIZE(kManifestTopLevelProperties))) { 497 arraysize(kManifestTopLevelProperties))) {
441 PLUGIN_PRINTF(("JsonManifest::MatchesSchema: WARNING: unknown top-level " 498 VLOG(1) << "JsonManifest::MatchesSchema: WARNING: unknown top-level "
442 "section '%s' in manifest.\n", property_name.c_str())); 499 << "section '" << property_name << "' in manifest.";
443 } 500 }
444 } 501 }
445 502
446 // A manifest file must have a program section. 503 // A manifest file must have a program section.
447 if (!dictionary_.isMember(kProgramKey)) { 504 if (!dictionary_.isMember(kProgramKey)) {
448 error_info->SetReport( 505 error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
449 PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE, 506 error_info->string = std::string("manifest: missing '") + kProgramKey +
450 nacl::string("manifest: missing '") + kProgramKey + "' section."); 507 "' section.";
451 return false; 508 return false;
452 } 509 }
453 510
454 // Validate the program section. 511 // Validate the program section.
455 // There must be a matching (portable or sandbox_isa_) entry for program for 512 // There must be a matching (portable or sandbox_isa_) entry for program for
456 // NaCl. 513 // NaCl.
457 if (!IsValidISADictionary(dictionary_[kProgramKey], 514 if (!IsValidISADictionary(dictionary_[kProgramKey],
458 kProgramKey, 515 kProgramKey,
459 sandbox_isa_, 516 sandbox_isa_,
460 true, 517 true,
(...skipping 11 matching lines...) Expand all
472 sandbox_isa_, 529 sandbox_isa_,
473 true, 530 true,
474 nonsfi_enabled_, 531 nonsfi_enabled_,
475 error_info)) { 532 error_info)) {
476 return false; 533 return false;
477 } 534 }
478 } 535 }
479 536
480 // Validate the file dictionary (if given). 537 // Validate the file dictionary (if given).
481 // The "files" key does not require a matching (portable or sandbox_isa_) 538 // The "files" key does not require a matching (portable or sandbox_isa_)
482 // entry at schema validation time for NaCl. This allows manifests to specify 539 // entry at schema validation time for NaCl. This allows manifests to
483 // resources that are only loaded for a particular sandbox_isa. 540 // specify resources that are only loaded for a particular sandbox_isa.
484 if (dictionary_.isMember(kFilesKey)) { 541 if (dictionary_.isMember(kFilesKey)) {
485 const Json::Value& files = dictionary_[kFilesKey]; 542 const Json::Value& files = dictionary_[kFilesKey];
486 if (!files.isObject()) { 543 if (!files.isObject()) {
487 error_info->SetReport( 544 error_info->error = PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE;
488 PP_NACL_ERROR_MANIFEST_SCHEMA_VALIDATE, 545 error_info->string = std::string("manifest: '") + kFilesKey +
489 nacl::string("manifest: '") + kFilesKey + "' is not a dictionary."); 546 "' is not a dictionary.";
490 } 547 }
491 Json::Value::Members members = files.getMemberNames(); 548 Json::Value::Members members = files.getMemberNames();
492 for (size_t i = 0; i < members.size(); ++i) { 549 for (size_t i = 0; i < members.size(); ++i) {
493 nacl::string file_name = members[i]; 550 std::string file_name = members[i];
494 if (!IsValidISADictionary(files[file_name], 551 if (!IsValidISADictionary(files[file_name],
495 file_name, 552 file_name,
496 sandbox_isa_, 553 sandbox_isa_,
497 false, 554 false,
498 nonsfi_enabled_, 555 nonsfi_enabled_,
499 error_info)) { 556 error_info)) {
500 return false; 557 return false;
501 } 558 }
502 } 559 }
503 } 560 }
561 return true;
562 }
504 563
564 bool JsonManifest::GetKeyUrl(const Json::Value& dictionary,
565 const std::string& key,
566 std::string* full_url,
567 PP_PNaClOptions* pnacl_options) const {
568 DCHECK(full_url && pnacl_options);
569 if (!dictionary.isMember(key)) {
570 VLOG(1) << "GetKeyUrl failed: file " << key << " not found in manifest.";
571 return false;
572 }
573 const Json::Value& isa_dict = dictionary[key];
574 std::string relative_url;
575 bool uses_nonsfi_mode;
576 ErrorInfo ignored_error_info;
577 if (!GetURLFromISADictionary(isa_dict, key, &relative_url,
578 pnacl_options, &uses_nonsfi_mode,
579 &ignored_error_info))
580 return false;
581
582 // The contents of the manifest are resolved relative to the manifest URL.
583 GURL base_gurl(manifest_base_url_);
584 if (!base_gurl.is_valid())
585 return false;
586 GURL resolved_gurl = base_gurl.Resolve(relative_url);
587 if (!resolved_gurl.is_valid())
588 return false;
589 *full_url = resolved_gurl.possibly_invalid_spec();
505 return true; 590 return true;
506 } 591 }
507 592
508 bool JsonManifest::GetURLFromISADictionary(const Json::Value& dictionary, 593 bool JsonManifest::GetURLFromISADictionary(const Json::Value& dictionary,
509 const nacl::string& parent_key, 594 const std::string& parent_key,
510 nacl::string* url, 595 std::string* url,
511 PP_PNaClOptions* pnacl_options, 596 PP_PNaClOptions* pnacl_options,
512 bool* uses_nonsfi_mode, 597 bool* uses_nonsfi_mode,
513 ErrorInfo* error_info) const { 598 ErrorInfo* error_info) const {
514 DCHECK(url != NULL && pnacl_options != NULL && error_info != NULL); 599 DCHECK(url && pnacl_options && error_info);
515 600
516 // When the application actually requests a resolved URL, we must have 601 // When the application actually requests a resolved URL, we must have
517 // a matching entry (sandbox_isa_ or portable) for NaCl. 602 // a matching entry (sandbox_isa_ or portable) for NaCl.
518 ErrorInfo ignored_error_info; 603 ErrorInfo ignored_error_info;
519 if (!IsValidISADictionary(dictionary, parent_key, sandbox_isa_, true, 604 if (!IsValidISADictionary(dictionary, parent_key, sandbox_isa_, true,
520 nonsfi_enabled_, &ignored_error_info)) { 605 nonsfi_enabled_, &ignored_error_info)) {
521 error_info->SetReport(PP_NACL_ERROR_MANIFEST_RESOLVE_URL, 606 error_info->error = PP_NACL_ERROR_MANIFEST_RESOLVE_URL;
522 "architecture " + sandbox_isa_ + 607 error_info->string = "architecture " + sandbox_isa_ +
523 " is not found for file " + parent_key); 608 " is not found for file " + parent_key;
524 return false; 609 return false;
525 } 610 }
526 611
527 // The call to IsValidISADictionary() above guarantees that either 612 // The call to IsValidISADictionary() above guarantees that either
528 // sandbox_isa_, its nonsfi mode, or kPortableKey is present in the 613 // sandbox_isa_, its nonsfi mode, or kPortableKey is present in the
529 // dictionary. 614 // dictionary.
530 *uses_nonsfi_mode = false; 615 *uses_nonsfi_mode = false;
531 nacl::string chosen_isa; 616 std::string chosen_isa;
532 if (sandbox_isa_ == kPortableKey) { 617 if (sandbox_isa_ == kPortableKey) {
533 chosen_isa = kPortableKey; 618 chosen_isa = kPortableKey;
534 } else { 619 } else {
535 nacl::string nonsfi_isa = GetNonSFIKey(sandbox_isa_); 620 std::string nonsfi_isa = GetNonSFIKey(sandbox_isa_);
536 if (nonsfi_enabled_ && dictionary.isMember(nonsfi_isa)) { 621 if (nonsfi_enabled_ && dictionary.isMember(nonsfi_isa)) {
537 chosen_isa = nonsfi_isa; 622 chosen_isa = nonsfi_isa;
538 *uses_nonsfi_mode = true; 623 *uses_nonsfi_mode = true;
539 } else if (dictionary.isMember(sandbox_isa_)) { 624 } else if (dictionary.isMember(sandbox_isa_)) {
540 chosen_isa = sandbox_isa_; 625 chosen_isa = sandbox_isa_;
541 } else if (dictionary.isMember(kPortableKey)) { 626 } else if (dictionary.isMember(kPortableKey)) {
542 chosen_isa = kPortableKey; 627 chosen_isa = kPortableKey;
543 } else { 628 } else {
544 // Should not reach here, because the earlier IsValidISADictionary() 629 // Should not reach here, because the earlier IsValidISADictionary()
545 // call checked that the manifest covers the current architecture. 630 // call checked that the manifest covers the current architecture.
546 DCHECK(false); 631 DCHECK(false);
632 return false;
547 } 633 }
548 } 634 }
549 635
550 const Json::Value& isa_spec = dictionary[chosen_isa]; 636 const Json::Value& isa_spec = dictionary[chosen_isa];
551 // If the PNaCl debug flag is turned on, look for pnacl-debug entries first. 637 // If the PNaCl debug flag is turned on, look for pnacl-debug entries first.
552 // If found, mark that it is a debug URL. Otherwise, fall back to 638 // If found, mark that it is a debug URL. Otherwise, fall back to
553 // checking for pnacl-translate URLs, etc. and don't mark it as a debug URL. 639 // checking for pnacl-translate URLs, etc. and don't mark it as a debug URL.
554 if (pnacl_debug_ && isa_spec.isMember(kPnaclDebugKey)) { 640 if (pnacl_debug_ && isa_spec.isMember(kPnaclDebugKey)) {
555 GrabUrlAndPNaClOptions(isa_spec[kPnaclDebugKey], url, pnacl_options); 641 GrabUrlAndPnaclOptions(isa_spec[kPnaclDebugKey], url, pnacl_options);
556 pnacl_options->is_debug = PP_TRUE; 642 pnacl_options->is_debug = PP_TRUE;
557 } else if (isa_spec.isMember(kPnaclTranslateKey)) { 643 } else if (isa_spec.isMember(kPnaclTranslateKey)) {
558 GrabUrlAndPNaClOptions(isa_spec[kPnaclTranslateKey], url, pnacl_options); 644 GrabUrlAndPnaclOptions(isa_spec[kPnaclTranslateKey], url, pnacl_options);
559 } else { 645 } else {
560 // NaCl 646 // NaCl
561 *url = isa_spec[kUrlKey].asString(); 647 *url = isa_spec[kUrlKey].asString();
562 pnacl_options->translate = PP_FALSE; 648 pnacl_options->translate = PP_FALSE;
563 } 649 }
564 650
565 return true; 651 return true;
566 } 652 }
567 653
568 bool JsonManifest::GetKeyUrl(const Json::Value& dictionary, 654 } // namespace nacl
569 const nacl::string& key,
570 nacl::string* full_url,
571 PP_PNaClOptions* pnacl_options) const {
572 DCHECK(full_url != NULL && pnacl_options != NULL);
573 if (!dictionary.isMember(key)) {
574 PLUGIN_PRINTF(("file key not found in manifest"));
575 return false;
576 }
577 const Json::Value& isa_dict = dictionary[key];
578 nacl::string relative_url;
579 bool uses_nonsfi_mode;
580
581 // We ignore the error_info we receive here but it's needed for the calls
582 // below.
583 ErrorInfo error_info;
584
585 if (!GetURLFromISADictionary(isa_dict, key, &relative_url,
586 pnacl_options, &uses_nonsfi_mode, &error_info)) {
587 return false;
588 }
589 return ResolveURL(relative_url, full_url, &error_info);
590 }
591
592 bool JsonManifest::GetProgramURL(nacl::string* full_url,
593 PP_PNaClOptions* pnacl_options,
594 bool* uses_nonsfi_mode,
595 ErrorInfo* error_info) const {
596 if (full_url == NULL || pnacl_options == NULL || error_info == NULL)
597 return false;
598
599 const Json::Value& program = dictionary_[kProgramKey];
600 nacl::string nexe_url;
601 if (!GetURLFromISADictionary(program,
602 kProgramKey,
603 &nexe_url,
604 pnacl_options,
605 uses_nonsfi_mode,
606 error_info)) {
607 return false;
608 }
609 return ResolveURL(nexe_url, full_url, error_info);
610 }
611
612 bool JsonManifest::ResolveKey(const nacl::string& key,
613 nacl::string* full_url,
614 PP_PNaClOptions* pnacl_options) const {
615 NaClLog(3, "JsonManifest::ResolveKey(%s)\n", key.c_str());
616 // key must be one of kProgramKey or kFileKey '/' file-section-key
617
618 if (full_url == NULL || pnacl_options == NULL)
619 return false;
620
621 if (key == kProgramKey)
622 return GetKeyUrl(dictionary_, key, full_url, pnacl_options);
623 nacl::string::const_iterator p = find(key.begin(), key.end(), '/');
624 if (p == key.end()) {
625 std::string err = "ResolveKey: invalid key, no slash: " + key;
626 PLUGIN_PRINTF((err.c_str()));
627 return false;
628 }
629
630 // generalize to permit other sections?
631 nacl::string prefix(key.begin(), p);
632 if (prefix != kFilesKey) {
633 std::string err = "ResolveKey: invalid key: no \"files\" prefix: " + key;
634 PLUGIN_PRINTF((err.c_str()));
635 return false;
636 }
637
638 nacl::string rest(p + 1, key.end());
639
640 const Json::Value& files = dictionary_[kFilesKey];
641 if (!files.isObject()) {
642 std::string err = "ResolveKey: no \"files\" dictionary";
643 PLUGIN_PRINTF((err.c_str()));
644 return false;
645 }
646 if (!files.isMember(rest)) {
647 std::string err = "ResolveKey: no such \"files\" entry: " + key;
648 PLUGIN_PRINTF((err.c_str()));
649 return false;
650 }
651 return GetKeyUrl(files, rest, full_url, pnacl_options);
652 }
653
654 bool JsonManifest::ResolveURL(const nacl::string& relative_url,
655 nacl::string* full_url,
656 ErrorInfo* error_info) const {
657 // The contents of the manifest are resolved relative to the manifest URL.
658 CHECK(url_util_ != NULL);
659 pp::Var resolved_url =
660 url_util_->ResolveRelativeToURL(pp::Var(manifest_base_url_),
661 relative_url);
662 if (!resolved_url.is_string()) {
663 error_info->SetReport(
664 PP_NACL_ERROR_MANIFEST_RESOLVE_URL,
665 "could not resolve url '" + relative_url +
666 "' relative to manifest base url '" + manifest_base_url_.c_str() +
667 "'.");
668 return false;
669 }
670 *full_url = resolved_url.AsString();
671 return true;
672 }
673
674 } // namespace plugin
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698