| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 * Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 * 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 |
| 4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
| 5 */ | 5 */ |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "native_client/src/trusted/plugin/json_manifest.h" | 9 #include "native_client/src/trusted/plugin/json_manifest.h" |
| 10 | 10 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 38 | 38 |
| 39 // Url Resolution keys | 39 // Url Resolution keys |
| 40 const char* const kPnaclTranslateKey = "pnacl-translate"; | 40 const char* const kPnaclTranslateKey = "pnacl-translate"; |
| 41 const char* const kUrlKey = "url"; | 41 const char* const kUrlKey = "url"; |
| 42 | 42 |
| 43 // Pnacl keys | 43 // Pnacl keys |
| 44 const char* const kCacheIdentityKey = "sha256"; | 44 const char* const kCacheIdentityKey = "sha256"; |
| 45 const char* const kOptLevelKey = "-O"; | 45 const char* const kOptLevelKey = "-O"; |
| 46 const char* const kPnaclExperimentalFlags = "experimental_flags"; | 46 const char* const kPnaclExperimentalFlags = "experimental_flags"; |
| 47 | 47 |
| 48 // Sample manifest file: | 48 // Sample NaCL manifest file: |
| 49 // { | 49 // { |
| 50 // "program": { | 50 // "program": { |
| 51 // "x86-32": {"url": "myprogram_x86-32.nexe"}, | 51 // "x86-32": {"url": "myprogram_x86-32.nexe"}, |
| 52 // "x86-64": {"url": "myprogram_x86-64.nexe"}, | 52 // "x86-64": {"url": "myprogram_x86-64.nexe"}, |
| 53 // "arm": {"url": "myprogram_arm.nexe"}, | 53 // "arm": {"url": "myprogram_arm.nexe"} |
| 54 // "portable": { | |
| 55 // "pnacl-translate": { | |
| 56 // "url": "myprogram.pexe", | |
| 57 // "sha256": "...", | |
| 58 // "-O": 0 | |
| 59 // } | |
| 60 // } | |
| 61 // }, | 54 // }, |
| 62 // "interpreter": { | 55 // "interpreter": { |
| 63 // "x86-32": {"url": "interpreter_x86-32.nexe"}, | 56 // "x86-32": {"url": "interpreter_x86-32.nexe"}, |
| 64 // "x86-64": {"url": "interpreter_x86-64.nexe"}, | 57 // "x86-64": {"url": "interpreter_x86-64.nexe"}, |
| 65 // "arm": {"url": "interpreter_arm.nexe"} | 58 // "arm": {"url": "interpreter_arm.nexe"} |
| 66 // }, | 59 // }, |
| 67 // "files": { | 60 // "files": { |
| 68 // "foo.txt": { | 61 // "foo.txt": { |
| 69 // "portable": {"url": "foo.txt"} | 62 // "portable": {"url": "foo.txt"} |
| 70 // }, | 63 // }, |
| 71 // "bar.txt": { | 64 // "bar.txt": { |
| 72 // "x86-32": {"url": "x86-32/bar.txt"}, | 65 // "x86-32": {"url": "x86-32/bar.txt"}, |
| 73 // "portable": {"url": "bar.txt"} | 66 // "portable": {"url": "bar.txt"} |
| 74 // }, | 67 // }, |
| 75 // "libfoo.so": { | 68 // "libfoo.so": { |
| 76 // "x86-64-ivybridge-foo": { "url": "..."}, | 69 // "x86-64" : { "url": "..." } |
| 77 // "x86-64-ivybridge" : { "pnacl-translate": { "url": "..."}}, | |
| 78 // "x86-64" : { "url": "..." }, | |
| 79 // "portable": {"pnacl-translate": {"url": "..."}} | |
| 80 // } | 70 // } |
| 81 // } | 71 // } |
| 82 // } | 72 // } |
| 73 |
| 74 // Sample PNaCl manifest file: |
| 75 // { |
| 76 // "program": { |
| 77 // "portable": { |
| 78 // "pnacl-translate": { |
| 79 // "url": "myprogram.pexe", |
| 80 // "sha256": "...", |
| 81 // "-O": 0 |
| 82 // } |
| 83 // } |
| 84 // }, |
| 85 // "files": { |
| 86 // "foo.txt": { |
| 87 // "portable": {"url": "foo.txt"} |
| 88 // }, |
| 89 // "bar.txt": { |
| 90 // "portable": {"url": "bar.txt"} |
| 91 // } |
| 92 // } |
| 93 // } |
| 83 | 94 |
| 84 // Looks up |property_name| in the vector |valid_names| with length | 95 // Looks up |property_name| in the vector |valid_names| with length |
| 85 // |valid_name_count|. Returns true if |property_name| is found. | 96 // |valid_name_count|. Returns true if |property_name| is found. |
| 86 bool FindMatchingProperty(const nacl::string& property_name, | 97 bool FindMatchingProperty(const nacl::string& property_name, |
| 87 const char** valid_names, | 98 const char** valid_names, |
| 88 size_t valid_name_count) { | 99 size_t valid_name_count) { |
| 89 for (size_t i = 0; i < valid_name_count; ++i) { | 100 for (size_t i = 0; i < valid_name_count; ++i) { |
| 90 if (property_name == valid_names[i]) { | 101 if (property_name == valid_names[i]) { |
| 91 return true; | 102 return true; |
| 92 } | 103 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 115 *error_string = error_stream.str(); | 126 *error_string = error_stream.str(); |
| 116 return false; | 127 return false; |
| 117 } | 128 } |
| 118 // Check for unknown dictionary members. | 129 // Check for unknown dictionary members. |
| 119 Json::Value::Members members = dictionary.getMemberNames(); | 130 Json::Value::Members members = dictionary.getMemberNames(); |
| 120 for (size_t i = 0; i < members.size(); ++i) { | 131 for (size_t i = 0; i < members.size(); ++i) { |
| 121 nacl::string property_name = members[i]; | 132 nacl::string property_name = members[i]; |
| 122 if (!FindMatchingProperty(property_name, | 133 if (!FindMatchingProperty(property_name, |
| 123 valid_keys, | 134 valid_keys, |
| 124 valid_key_count)) { | 135 valid_key_count)) { |
| 125 // TODO(jvoung): Should this set error_string and return false? | 136 // For forward compatibility, we do not prohibit other keys being in |
| 137 // the dictionary. |
| 126 PLUGIN_PRINTF(("WARNING: '%s' property '%s' has unknown key '%s'.\n", | 138 PLUGIN_PRINTF(("WARNING: '%s' property '%s' has unknown key '%s'.\n", |
| 127 parent_key.c_str(), | 139 parent_key.c_str(), |
| 128 container_key.c_str(), property_name.c_str())); | 140 container_key.c_str(), property_name.c_str())); |
| 129 } | 141 } |
| 130 } | 142 } |
| 131 // Check for required members. | 143 // Check for required members. |
| 132 for (size_t i = 0; i < required_key_count; ++i) { | 144 for (size_t i = 0; i < required_key_count; ++i) { |
| 133 if (!dictionary.isMember(required_keys[i])) { | 145 if (!dictionary.isMember(required_keys[i])) { |
| 134 nacl::stringstream error_stream; | 146 nacl::stringstream error_stream; |
| 135 error_stream << parent_key << " property '" << container_key | 147 error_stream << parent_key << " property '" << container_key |
| 136 << "' does not have required key: '" | 148 << "' does not have required key: '" |
| 137 << required_keys[i] << "'."; | 149 << required_keys[i] << "'."; |
| 138 *error_string = error_stream.str(); | 150 *error_string = error_stream.str(); |
| 139 return false; | 151 return false; |
| 140 } | 152 } |
| 141 } | 153 } |
| 142 return true; | 154 return true; |
| 143 } | 155 } |
| 144 | 156 |
| 145 // Validate a "url" dictionary assuming it was resolved from container_key. | 157 // Validate a "url" dictionary assuming it was resolved from container_key. |
| 146 // E.g., "container_key" : { "url": "foo.txt" } | 158 // E.g., "container_key" : { "url": "foo.txt" } |
| 147 bool IsValidUrlSpec(const Json::Value& url_spec, | 159 bool IsValidUrlSpec(const Json::Value& url_spec, |
| 148 const nacl::string& container_key, | 160 const nacl::string& container_key, |
| 149 const nacl::string& parent_key, | 161 const nacl::string& parent_key, |
| 162 const nacl::string& sandbox_isa, |
| 150 nacl::string* error_string) { | 163 nacl::string* error_string) { |
| 151 static const char* kManifestUrlSpecRequired[] = { | 164 static const char* kManifestUrlSpecRequired[] = { |
| 152 kUrlKey | 165 kUrlKey |
| 153 }; | 166 }; |
| 154 static const char* kManifestUrlSpecPlusOptional[] = { | 167 const char** urlSpecPlusOptional; |
| 155 kUrlKey, | 168 size_t urlSpecPlusOptionalLength; |
| 156 kCacheIdentityKey | 169 if (sandbox_isa == kPortableKey) { |
| 157 }; | 170 static const char* kPnaclUrlSpecPlusOptional[] = { |
| 171 kUrlKey, |
| 172 kCacheIdentityKey, |
| 173 kOptLevelKey, |
| 174 }; |
| 175 urlSpecPlusOptional = kPnaclUrlSpecPlusOptional; |
| 176 urlSpecPlusOptionalLength = NACL_ARRAY_SIZE(kPnaclUrlSpecPlusOptional); |
| 177 } else { |
| 178 urlSpecPlusOptional = kManifestUrlSpecRequired; |
| 179 urlSpecPlusOptionalLength = NACL_ARRAY_SIZE(kManifestUrlSpecRequired); |
| 180 } |
| 158 if (!IsValidDictionary(url_spec, container_key, parent_key, | 181 if (!IsValidDictionary(url_spec, container_key, parent_key, |
| 159 kManifestUrlSpecPlusOptional, | 182 urlSpecPlusOptional, |
| 160 NACL_ARRAY_SIZE(kManifestUrlSpecPlusOptional), | 183 urlSpecPlusOptionalLength, |
| 161 kManifestUrlSpecRequired, | 184 kManifestUrlSpecRequired, |
| 162 NACL_ARRAY_SIZE(kManifestUrlSpecRequired), | 185 NACL_ARRAY_SIZE(kManifestUrlSpecRequired), |
| 163 error_string)) { | 186 error_string)) { |
| 164 return false; | 187 return false; |
| 165 } | 188 } |
| 189 // URL specifications must not contain "pnacl-translate" keys. |
| 190 // This prohibits NaCl clients from invoking PNaCl. |
| 191 Json::Value translate = url_spec[kPnaclTranslateKey]; |
| 192 if (!translate.empty()) { |
| 193 nacl::stringstream error_stream; |
| 194 error_stream << parent_key << " property '" << container_key << |
| 195 "' has '" << kPnaclTranslateKey << "' inside URL spec."; |
| 196 *error_string = error_stream.str(); |
| 197 return false; |
| 198 } |
| 199 // Verify the correct types of the fields if they exist. |
| 166 Json::Value url = url_spec[kUrlKey]; | 200 Json::Value url = url_spec[kUrlKey]; |
| 167 if (!url.isString()) { | 201 if (!url.isString()) { |
| 168 nacl::stringstream error_stream; | 202 nacl::stringstream error_stream; |
| 169 error_stream << parent_key << " property '" << container_key << | 203 error_stream << parent_key << " property '" << container_key << |
| 170 "' has non-string value '" << url.toStyledString() << | 204 "' has non-string value '" << url.toStyledString() << |
| 171 "' for key '" << kUrlKey << "'."; | 205 "' for key '" << kUrlKey << "'."; |
| 172 *error_string = error_stream.str(); | 206 *error_string = error_stream.str(); |
| 173 return false; | 207 return false; |
| 174 } | 208 } |
| 209 Json::Value cache_identity = url_spec[kCacheIdentityKey]; |
| 210 if (!cache_identity.empty() && !cache_identity.isString()) { |
| 211 nacl::stringstream error_stream; |
| 212 error_stream << parent_key << " property '" << container_key << |
| 213 "' has non-string value '" << cache_identity.toStyledString() << |
| 214 "' for key '" << kCacheIdentityKey << "'."; |
| 215 *error_string = error_stream.str(); |
| 216 return false; |
| 217 } |
| 218 Json::Value opt_level = url_spec[kOptLevelKey]; |
| 219 if (!opt_level.empty() && !opt_level.isNumeric()) { |
| 220 nacl::stringstream error_stream; |
| 221 error_stream << parent_key << " property '" << container_key << |
| 222 "' has non-numeric value '" << opt_level.toStyledString() << |
| 223 "' for key '" << kOptLevelKey << "'."; |
| 224 *error_string = error_stream.str(); |
| 225 return false; |
| 226 } |
| 175 return true; | 227 return true; |
| 176 } | 228 } |
| 177 | 229 |
| 178 // Validate a "pnacl-translate" dictionary, assuming it was resolved from | 230 // Validate a "pnacl-translate" dictionary, assuming it was resolved from |
| 179 // container_key. E.g., "container_key" : { "pnacl_translate" : URLSpec } | 231 // container_key. E.g., "container_key" : { "pnacl_translate" : URLSpec } |
| 180 bool IsValidPnaclTranslateSpec(const Json::Value& pnacl_spec, | 232 bool IsValidPnaclTranslateSpec(const Json::Value& pnacl_spec, |
| 181 const nacl::string& container_key, | 233 const nacl::string& container_key, |
| 182 const nacl::string& parent_key, | 234 const nacl::string& parent_key, |
| 235 const nacl::string& sandbox_isa, |
| 183 nacl::string* error_string) { | 236 nacl::string* error_string) { |
| 184 static const char* kManifestPnaclSpecProperties[] = { | 237 static const char* kManifestPnaclSpecProperties[] = { |
| 185 kPnaclTranslateKey | 238 kPnaclTranslateKey |
| 186 }; | 239 }; |
| 187 if (!IsValidDictionary(pnacl_spec, container_key, parent_key, | 240 if (!IsValidDictionary(pnacl_spec, container_key, parent_key, |
| 188 kManifestPnaclSpecProperties, | 241 kManifestPnaclSpecProperties, |
| 189 NACL_ARRAY_SIZE(kManifestPnaclSpecProperties), | 242 NACL_ARRAY_SIZE(kManifestPnaclSpecProperties), |
| 190 kManifestPnaclSpecProperties, | 243 kManifestPnaclSpecProperties, |
| 191 NACL_ARRAY_SIZE(kManifestPnaclSpecProperties), | 244 NACL_ARRAY_SIZE(kManifestPnaclSpecProperties), |
| 192 error_string)) { | 245 error_string)) { |
| 193 return false; | 246 return false; |
| 194 } | 247 } |
| 195 Json::Value url_spec = pnacl_spec[kPnaclTranslateKey]; | 248 Json::Value url_spec = pnacl_spec[kPnaclTranslateKey]; |
| 196 if (!IsValidUrlSpec(url_spec, kPnaclTranslateKey, | 249 if (!IsValidUrlSpec(url_spec, kPnaclTranslateKey, |
| 197 container_key, error_string)) { | 250 container_key, sandbox_isa, error_string)) { |
| 198 return false; | 251 return false; |
| 199 } | 252 } |
| 200 return true; | 253 return true; |
| 201 } | 254 } |
| 202 | 255 |
| 203 // Validates that |dictionary| is a valid ISA dictionary. An ISA dictionary | 256 // Validates that |dictionary| is a valid ISA dictionary. An ISA dictionary |
| 204 // is validated to have keys from within the set of recognized ISAs. Unknown | 257 // is validated to have keys from within the set of recognized ISAs. Unknown |
| 205 // ISAs are allowed, but ignored and warnings are produced. It is also validated | 258 // ISAs are allowed, but ignored and warnings are produced. It is also validated |
| 206 // that it must have an entry to match the ISA specified in |sandbox_isa| or | 259 // that it must have an entry to match the ISA specified in |sandbox_isa| or |
| 207 // have a fallback 'portable' entry if there is no match. Returns true if | 260 // have a fallback 'portable' entry if there is no match. Returns true if |
| 208 // |dictionary| is an ISA to URL map. Sets |error_info| to something | 261 // |dictionary| is an ISA to URL map. Sets |error_info| to something |
| 209 // descriptive if it fails. | 262 // descriptive if it fails. |
| 210 bool IsValidISADictionary(const Json::Value& dictionary, | 263 bool IsValidISADictionary(const Json::Value& dictionary, |
| 211 const nacl::string& parent_key, | 264 const nacl::string& parent_key, |
| 212 const nacl::string& sandbox_isa, | 265 const nacl::string& sandbox_isa, |
| 213 ErrorInfo* error_info) { | 266 ErrorInfo* error_info) { |
| 214 if (error_info == NULL) return false; | 267 if (error_info == NULL) return false; |
| 215 | 268 |
| 216 // An ISA to URL dictionary has to be an object. | 269 // An ISA to URL dictionary has to be an object. |
| 217 if (!dictionary.isObject()) { | 270 if (!dictionary.isObject()) { |
| 218 error_info->SetReport(ERROR_MANIFEST_SCHEMA_VALIDATE, | 271 error_info->SetReport(ERROR_MANIFEST_SCHEMA_VALIDATE, |
| 219 nacl::string("manifest: ") + parent_key + | 272 nacl::string("manifest: ") + parent_key + |
| 220 " property is not an ISA to URL dictionary"); | 273 " property is not an ISA to URL dictionary"); |
| 221 return false; | 274 return false; |
| 222 } | 275 } |
| 223 // The keys to the dictionary have to be valid ISA names. | 276 // The keys to the dictionary have to be valid ISA names. |
| 224 Json::Value::Members members = dictionary.getMemberNames(); | 277 Json::Value::Members members = dictionary.getMemberNames(); |
| 225 for (size_t i = 0; i < members.size(); ++i) { | 278 for (size_t i = 0; i < members.size(); ++i) { |
| 226 // The known ISA values for ISA dictionaries in the manifest. | 279 const char** isaProperties; |
| 227 static const char* kManifestISAProperties[] = { | 280 size_t isaPropertiesLength; |
| 228 kX8632Key, | 281 if (sandbox_isa == kPortableKey) { |
| 229 kX8664Key, | 282 // The known values for PNaCl ISA dictionaries in the manifest. |
| 230 kArmKey, | 283 static const char* kPnaclManifestISAProperties[] = { |
| 231 kPortableKey | 284 kPortableKey |
| 232 }; | 285 }; |
| 286 isaProperties = kPnaclManifestISAProperties; |
| 287 isaPropertiesLength = NACL_ARRAY_SIZE(kPnaclManifestISAProperties); |
| 288 } else { |
| 289 // The known values for NaCl ISA dictionaries in the manifest. |
| 290 static const char* kNaClManifestISAProperties[] = { |
| 291 kX8632Key, |
| 292 kX8664Key, |
| 293 kArmKey, |
| 294 // "portable" is here to allow checking that, if present, it can |
| 295 // only refer to an URL, such as for a data file, and not to |
| 296 // "pnacl-translate", which would cause the creation of a nexe. |
| 297 kPortableKey |
| 298 }; |
| 299 isaProperties = kNaClManifestISAProperties; |
| 300 isaPropertiesLength = NACL_ARRAY_SIZE(kNaClManifestISAProperties); |
| 301 } |
| 233 nacl::string property_name = members[i]; | 302 nacl::string property_name = members[i]; |
| 234 if (!FindMatchingProperty(property_name, | 303 if (FindMatchingProperty(property_name, |
| 235 kManifestISAProperties, | 304 isaProperties, |
| 236 NACL_ARRAY_SIZE(kManifestISAProperties))) { | 305 isaPropertiesLength)) { |
| 237 PLUGIN_PRINTF(("IsValidISADictionary: unrecognized ISA '%s'.\n", | 306 Json::Value property_value = dictionary[property_name]; |
| 307 nacl::string error_string; |
| 308 // For NaCl, arch entries can only be |
| 309 // "arch/portable" : URLSpec |
| 310 // For PNaCl arch in "program" dictionary entries can only be |
| 311 // "portable" : { "pnacl-translate": URLSpec } |
| 312 // For PNaCl arch elsewhere, dictionary entries can only be |
| 313 // "portable" : URLSpec |
| 314 if ((sandbox_isa != kPortableKey && |
| 315 !IsValidUrlSpec(property_value, property_name, parent_key, |
| 316 sandbox_isa, &error_string)) || |
| 317 (sandbox_isa == kPortableKey && |
| 318 parent_key == kProgramKey && |
| 319 !IsValidPnaclTranslateSpec(property_value, property_name, parent_key, |
| 320 sandbox_isa, &error_string)) || |
| 321 (sandbox_isa == kPortableKey && |
| 322 parent_key != kProgramKey && |
| 323 !IsValidUrlSpec(property_value, property_name, parent_key, |
| 324 sandbox_isa, &error_string))) { |
| 325 error_info->SetReport(ERROR_MANIFEST_SCHEMA_VALIDATE, |
| 326 nacl::string("manifest: ") + error_string); |
| 327 return false; |
| 328 } |
| 329 } else { |
| 330 // For forward compatibility, we do not prohibit other keys being in |
| 331 // the dictionary. |
| 332 PLUGIN_PRINTF(("IsValidISADictionary: unrecognized key '%s'.\n", |
| 238 property_name.c_str())); | 333 property_name.c_str())); |
| 239 } | 334 } |
| 240 // Could be "arch/portable" : URLSpec, or | |
| 241 // it could be "arch/portable" : { "pnacl-translate": URLSpec } | |
| 242 // for executables that need to be translated. | |
| 243 Json::Value property_value = dictionary[property_name]; | |
| 244 nacl::string error_string; | |
| 245 if (!IsValidUrlSpec(property_value, property_name, parent_key, | |
| 246 &error_string) && | |
| 247 !IsValidPnaclTranslateSpec(property_value, property_name, | |
| 248 parent_key, &error_string)) { | |
| 249 error_info->SetReport(ERROR_MANIFEST_SCHEMA_VALIDATE, | |
| 250 nacl::string("manifest: ") + error_string); | |
| 251 return false; | |
| 252 } | |
| 253 } | 335 } |
| 254 | 336 |
| 255 if (!sandbox_isa.empty()) { | 337 if (sandbox_isa == kPortableKey) { |
| 338 bool has_portable = dictionary.isMember(kPortableKey); |
| 339 |
| 340 if (!has_portable) { |
| 341 error_info->SetReport( |
| 342 ERROR_MANIFEST_PROGRAM_MISSING_ARCH, |
| 343 nacl::string("manifest: no version of ") + parent_key + |
| 344 " given for portable."); |
| 345 return false; |
| 346 } |
| 347 } else { |
| 256 // TODO(elijahtaylor) add ISA resolver here if we expand ISAs to include | 348 // TODO(elijahtaylor) add ISA resolver here if we expand ISAs to include |
| 257 // micro-architectures that can resolve to multiple valid sandboxes. | 349 // micro-architectures that can resolve to multiple valid sandboxes. |
| 258 bool has_isa = dictionary.isMember(sandbox_isa); | 350 bool has_isa = dictionary.isMember(sandbox_isa); |
| 259 bool has_portable = dictionary.isMember(kPortableKey); | 351 bool has_portable = dictionary.isMember(kPortableKey); |
| 260 | 352 |
| 261 if (!has_isa && !has_portable) { | 353 if (!has_isa && !has_portable) { |
| 262 error_info->SetReport( | 354 error_info->SetReport( |
| 263 ERROR_MANIFEST_PROGRAM_MISSING_ARCH, | 355 ERROR_MANIFEST_PROGRAM_MISSING_ARCH, |
| 264 nacl::string("manifest: no version of ") + parent_key + | 356 nacl::string("manifest: no version of ") + parent_key + |
| 265 " given for current arch and no portable version found."); | 357 " given for current arch and no portable version found."); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 286 } | 378 } |
| 287 if (url_spec.isMember(kPnaclExperimentalFlags)) { | 379 if (url_spec.isMember(kPnaclExperimentalFlags)) { |
| 288 pnacl_options->set_experimental_flags( | 380 pnacl_options->set_experimental_flags( |
| 289 url_spec[kPnaclExperimentalFlags].asString()); | 381 url_spec[kPnaclExperimentalFlags].asString()); |
| 290 } | 382 } |
| 291 } | 383 } |
| 292 | 384 |
| 293 bool GetURLFromISADictionary(const Json::Value& dictionary, | 385 bool GetURLFromISADictionary(const Json::Value& dictionary, |
| 294 const nacl::string& parent_key, | 386 const nacl::string& parent_key, |
| 295 const nacl::string& sandbox_isa, | 387 const nacl::string& sandbox_isa, |
| 296 bool prefer_portable, | |
| 297 nacl::string* url, | 388 nacl::string* url, |
| 298 PnaclOptions* pnacl_options, | 389 PnaclOptions* pnacl_options, |
| 299 ErrorInfo* error_info) { | 390 ErrorInfo* error_info) { |
| 300 if (url == NULL || pnacl_options == NULL || error_info == NULL) | 391 if (url == NULL || pnacl_options == NULL || error_info == NULL) |
| 301 return false; | 392 return false; |
| 302 | 393 |
| 303 if (!IsValidISADictionary(dictionary, parent_key, sandbox_isa, error_info)) { | 394 if (!IsValidISADictionary(dictionary, parent_key, sandbox_isa, error_info)) { |
| 304 error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL, | 395 error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL, |
| 305 "architecture " + sandbox_isa + | 396 "architecture " + sandbox_isa + |
| 306 " is not found for file " + parent_key); | 397 " is not found for file " + parent_key); |
| 307 return false; | 398 return false; |
| 308 } | 399 } |
| 309 | 400 |
| 310 *url = ""; | 401 *url = ""; |
| 311 | 402 |
| 312 // The call to IsValidISADictionary() above guarantees that either | 403 // The call to IsValidISADictionary() above guarantees that either |
| 313 // sandbox_isa or kPortableKey is present in the dictionary. | 404 // sandbox_isa or kPortableKey is present in the dictionary. |
| 314 bool has_portable = dictionary.isMember(kPortableKey); | 405 bool has_portable = dictionary.isMember(kPortableKey); |
| 315 bool has_isa = dictionary.isMember(sandbox_isa); | 406 bool has_isa = dictionary.isMember(sandbox_isa); |
| 316 nacl::string chosen_isa; | 407 nacl::string chosen_isa; |
| 317 if ((has_portable && prefer_portable) || !has_isa) { | 408 if ((sandbox_isa == kPortableKey) || (has_portable && !has_isa)) { |
| 318 chosen_isa = kPortableKey; | 409 chosen_isa = kPortableKey; |
| 319 } else { | 410 } else { |
| 320 chosen_isa = sandbox_isa; | 411 chosen_isa = sandbox_isa; |
| 321 } | 412 } |
| 322 const Json::Value& isa_spec = dictionary[chosen_isa]; | 413 const Json::Value& isa_spec = dictionary[chosen_isa]; |
| 323 // Check if this requires a pnacl-translate, otherwise just grab the URL. | 414 // Check if this requires a pnacl-translate, otherwise just grab the URL. |
| 324 // We may have pnacl-translate for isa-specific bitcode for CPU tuning. | 415 // We may have pnacl-translate for isa-specific bitcode for CPU tuning. |
| 325 if (isa_spec.isMember(kPnaclTranslateKey)) { | 416 if (isa_spec.isMember(kPnaclTranslateKey)) { |
| 417 // PNaCl |
| 326 GrabUrlAndPnaclOptions(isa_spec[kPnaclTranslateKey], url, pnacl_options); | 418 GrabUrlAndPnaclOptions(isa_spec[kPnaclTranslateKey], url, pnacl_options); |
| 327 pnacl_options->set_translate(true); | 419 pnacl_options->set_translate(true); |
| 328 } else { | 420 } else { |
| 421 // NaCl |
| 329 *url = isa_spec[kUrlKey].asString(); | 422 *url = isa_spec[kUrlKey].asString(); |
| 330 pnacl_options->set_translate(false); | 423 pnacl_options->set_translate(false); |
| 331 } | 424 } |
| 332 | 425 |
| 333 return true; | 426 return true; |
| 334 } | 427 } |
| 335 | 428 |
| 336 bool GetKeyUrl(const Json::Value& dictionary, | 429 bool GetKeyUrl(const Json::Value& dictionary, |
| 337 const nacl::string& key, | 430 const nacl::string& key, |
| 338 const nacl::string& sandbox_isa, | 431 const nacl::string& sandbox_isa, |
| 339 const Manifest* manifest, | 432 const Manifest* manifest, |
| 340 bool prefer_portable, | |
| 341 nacl::string* full_url, | 433 nacl::string* full_url, |
| 342 PnaclOptions* pnacl_options, | 434 PnaclOptions* pnacl_options, |
| 343 ErrorInfo* error_info) { | 435 ErrorInfo* error_info) { |
| 344 CHECK(full_url != NULL && error_info != NULL); | 436 CHECK(full_url != NULL && error_info != NULL); |
| 345 if (!dictionary.isMember(key)) { | 437 if (!dictionary.isMember(key)) { |
| 346 error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL, | 438 error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL, |
| 347 "file key not found in manifest"); | 439 "file key not found in manifest"); |
| 348 return false; | 440 return false; |
| 349 } | 441 } |
| 350 const Json::Value& isa_dict = dictionary[key]; | 442 const Json::Value& isa_dict = dictionary[key]; |
| 351 nacl::string relative_url; | 443 nacl::string relative_url; |
| 352 if (!GetURLFromISADictionary(isa_dict, key, sandbox_isa, prefer_portable, | 444 if (!GetURLFromISADictionary(isa_dict, key, sandbox_isa, &relative_url, |
| 353 &relative_url, pnacl_options, error_info)) { | 445 pnacl_options, error_info)) { |
| 354 return false; | 446 return false; |
| 355 } | 447 } |
| 356 return manifest->ResolveURL(relative_url, full_url, error_info); | 448 return manifest->ResolveURL(relative_url, full_url, error_info); |
| 357 } | 449 } |
| 358 | 450 |
| 359 } // namespace | 451 } // namespace |
| 360 | 452 |
| 361 bool JsonManifest::Init(const nacl::string& manifest_json, | 453 bool JsonManifest::Init(const nacl::string& manifest_json, |
| 362 ErrorInfo* error_info) { | 454 ErrorInfo* error_info) { |
| 363 if (error_info == NULL) { | 455 if (error_info == NULL) { |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 433 if (!files.isObject()) { | 525 if (!files.isObject()) { |
| 434 error_info->SetReport( | 526 error_info->SetReport( |
| 435 ERROR_MANIFEST_SCHEMA_VALIDATE, | 527 ERROR_MANIFEST_SCHEMA_VALIDATE, |
| 436 nacl::string("manifest: '") + kFilesKey + "' is not a dictionary."); | 528 nacl::string("manifest: '") + kFilesKey + "' is not a dictionary."); |
| 437 } | 529 } |
| 438 Json::Value::Members members = files.getMemberNames(); | 530 Json::Value::Members members = files.getMemberNames(); |
| 439 for (size_t i = 0; i < members.size(); ++i) { | 531 for (size_t i = 0; i < members.size(); ++i) { |
| 440 nacl::string file_name = members[i]; | 532 nacl::string file_name = members[i]; |
| 441 if (!IsValidISADictionary(files[file_name], | 533 if (!IsValidISADictionary(files[file_name], |
| 442 file_name, | 534 file_name, |
| 443 nacl::string(), | 535 sandbox_isa_, |
| 444 error_info)) { | 536 error_info)) { |
| 445 return false; | 537 return false; |
| 446 } | 538 } |
| 447 } | 539 } |
| 448 } | 540 } |
| 449 | 541 |
| 450 return true; | 542 return true; |
| 451 } | 543 } |
| 452 | 544 |
| 453 bool JsonManifest::ResolveURL(const nacl::string& relative_url, | 545 bool JsonManifest::ResolveURL(const nacl::string& relative_url, |
| (...skipping 23 matching lines...) Expand all Loading... |
| 477 return false; | 569 return false; |
| 478 | 570 |
| 479 Json::Value program = dictionary_[kProgramKey]; | 571 Json::Value program = dictionary_[kProgramKey]; |
| 480 | 572 |
| 481 nacl::string nexe_url; | 573 nacl::string nexe_url; |
| 482 nacl::string error_string; | 574 nacl::string error_string; |
| 483 | 575 |
| 484 if (!GetURLFromISADictionary(program, | 576 if (!GetURLFromISADictionary(program, |
| 485 kProgramKey, | 577 kProgramKey, |
| 486 sandbox_isa_, | 578 sandbox_isa_, |
| 487 prefer_portable_, | |
| 488 &nexe_url, | 579 &nexe_url, |
| 489 pnacl_options, | 580 pnacl_options, |
| 490 error_info)) { | 581 error_info)) { |
| 491 return false; | 582 return false; |
| 492 } | 583 } |
| 493 | 584 |
| 494 return ResolveURL(nexe_url, full_url, error_info); | 585 return ResolveURL(nexe_url, full_url, error_info); |
| 495 } | 586 } |
| 496 | 587 |
| 497 bool JsonManifest::GetFileKeys(std::set<nacl::string>* keys) const { | 588 bool JsonManifest::GetFileKeys(std::set<nacl::string>* keys) const { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 512 nacl::string* full_url, | 603 nacl::string* full_url, |
| 513 PnaclOptions* pnacl_options, | 604 PnaclOptions* pnacl_options, |
| 514 ErrorInfo* error_info) const { | 605 ErrorInfo* error_info) const { |
| 515 NaClLog(3, "JsonManifest::ResolveKey(%s)\n", key.c_str()); | 606 NaClLog(3, "JsonManifest::ResolveKey(%s)\n", key.c_str()); |
| 516 // key must be one of kProgramKey or kFileKey '/' file-section-key | 607 // key must be one of kProgramKey or kFileKey '/' file-section-key |
| 517 | 608 |
| 518 if (full_url == NULL || pnacl_options == NULL || error_info == NULL) | 609 if (full_url == NULL || pnacl_options == NULL || error_info == NULL) |
| 519 return false; | 610 return false; |
| 520 | 611 |
| 521 if (key == kProgramKey) { | 612 if (key == kProgramKey) { |
| 522 return GetKeyUrl(dictionary_, key, sandbox_isa_, this, prefer_portable_, | 613 return GetKeyUrl(dictionary_, key, sandbox_isa_, this, full_url, |
| 523 full_url, pnacl_options, error_info); | 614 pnacl_options, error_info); |
| 524 } | 615 } |
| 525 nacl::string::const_iterator p = find(key.begin(), key.end(), '/'); | 616 nacl::string::const_iterator p = find(key.begin(), key.end(), '/'); |
| 526 if (p == key.end()) { | 617 if (p == key.end()) { |
| 527 error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL, | 618 error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL, |
| 528 nacl::string("ResolveKey: invalid key, no slash: ") | 619 nacl::string("ResolveKey: invalid key, no slash: ") |
| 529 + key); | 620 + key); |
| 530 return false; | 621 return false; |
| 531 } | 622 } |
| 532 | 623 |
| 533 // generalize to permit other sections? | 624 // generalize to permit other sections? |
| (...skipping 13 matching lines...) Expand all Loading... |
| 547 ERROR_MANIFEST_RESOLVE_URL, | 638 ERROR_MANIFEST_RESOLVE_URL, |
| 548 nacl::string("ResolveKey: no \"files\" dictionary")); | 639 nacl::string("ResolveKey: no \"files\" dictionary")); |
| 549 return false; | 640 return false; |
| 550 } | 641 } |
| 551 if (!files.isMember(rest)) { | 642 if (!files.isMember(rest)) { |
| 552 error_info->SetReport( | 643 error_info->SetReport( |
| 553 ERROR_MANIFEST_RESOLVE_URL, | 644 ERROR_MANIFEST_RESOLVE_URL, |
| 554 nacl::string("ResolveKey: no such \"files\" entry: ") + key); | 645 nacl::string("ResolveKey: no such \"files\" entry: ") + key); |
| 555 return false; | 646 return false; |
| 556 } | 647 } |
| 557 return GetKeyUrl(files, rest, sandbox_isa_, this, prefer_portable_, | 648 return GetKeyUrl(files, rest, sandbox_isa_, this, full_url, pnacl_options, |
| 558 full_url, pnacl_options, error_info); | 649 error_info); |
| 559 } | 650 } |
| 560 | 651 |
| 561 } // namespace plugin | 652 } // namespace plugin |
| OLD | NEW |