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