| OLD | NEW |
| 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" | |
| 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 Loading... |
| 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 Loading... |
| 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 | |
| OLD | NEW |