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

Unified Diff: ppapi/native_client/src/trusted/plugin/json_manifest.cc

Issue 16296005: Split pnacl and nacl mime types (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: After (hopefully) last rebase. Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ppapi/native_client/src/trusted/plugin/json_manifest.cc
diff --git a/ppapi/native_client/src/trusted/plugin/json_manifest.cc b/ppapi/native_client/src/trusted/plugin/json_manifest.cc
index d1f70ff39f96e278f197b6151e01f34c58b7818b..1aa8d23a15a5248788fa2e2fec2224f48c3e12fa 100644
--- a/ppapi/native_client/src/trusted/plugin/json_manifest.cc
+++ b/ppapi/native_client/src/trusted/plugin/json_manifest.cc
@@ -45,19 +45,12 @@ const char* const kCacheIdentityKey = "sha256";
const char* const kOptLevelKey = "-O";
const char* const kPnaclExperimentalFlags = "experimental_flags";
-// Sample manifest file:
+// Sample NaCL manifest file:
// {
// "program": {
// "x86-32": {"url": "myprogram_x86-32.nexe"},
// "x86-64": {"url": "myprogram_x86-64.nexe"},
-// "arm": {"url": "myprogram_arm.nexe"},
-// "portable": {
-// "pnacl-translate": {
-// "url": "myprogram.pexe",
-// "sha256": "...",
-// "-O": 0
-// }
-// }
+// "arm": {"url": "myprogram_arm.nexe"}
// },
// "interpreter": {
// "x86-32": {"url": "interpreter_x86-32.nexe"},
@@ -73,10 +66,28 @@ const char* const kPnaclExperimentalFlags = "experimental_flags";
// "portable": {"url": "bar.txt"}
// },
// "libfoo.so": {
-// "x86-64-ivybridge-foo": { "url": "..."},
-// "x86-64-ivybridge" : { "pnacl-translate": { "url": "..."}},
-// "x86-64" : { "url": "..." },
-// "portable": {"pnacl-translate": {"url": "..."}}
+// "x86-64" : { "url": "..." }
+// }
+// }
+// }
+
+// Sample PNaCl manifest file:
+// {
+// "program": {
+// "portable": {
+// "pnacl-translate": {
+// "url": "myprogram.pexe",
+// "sha256": "...",
+// "-O": 0
+// }
+// }
+// },
+// "files": {
+// "foo.txt": {
+// "portable": {"url": "foo.txt"}
+// },
+// "bar.txt": {
+// "portable": {"url": "bar.txt"}
// }
// }
// }
@@ -122,7 +133,8 @@ bool IsValidDictionary(const Json::Value& dictionary,
if (!FindMatchingProperty(property_name,
valid_keys,
valid_key_count)) {
- // TODO(jvoung): Should this set error_string and return false?
+ // For forward compatibility, we do not prohibit other keys being in
+ // the dictionary.
PLUGIN_PRINTF(("WARNING: '%s' property '%s' has unknown key '%s'.\n",
parent_key.c_str(),
container_key.c_str(), property_name.c_str()));
@@ -147,22 +159,44 @@ bool IsValidDictionary(const Json::Value& dictionary,
bool IsValidUrlSpec(const Json::Value& url_spec,
const nacl::string& container_key,
const nacl::string& parent_key,
+ const nacl::string& sandbox_isa,
nacl::string* error_string) {
static const char* kManifestUrlSpecRequired[] = {
kUrlKey
};
- static const char* kManifestUrlSpecPlusOptional[] = {
- kUrlKey,
- kCacheIdentityKey
- };
+ const char** urlSpecPlusOptional;
+ size_t urlSpecPlusOptionalLength;
+ if (sandbox_isa == kPortableKey) {
+ static const char* kPnaclUrlSpecPlusOptional[] = {
+ kUrlKey,
+ kCacheIdentityKey,
+ kOptLevelKey,
+ };
+ urlSpecPlusOptional = kPnaclUrlSpecPlusOptional;
+ urlSpecPlusOptionalLength = NACL_ARRAY_SIZE(kPnaclUrlSpecPlusOptional);
+ } else {
+ urlSpecPlusOptional = kManifestUrlSpecRequired;
+ urlSpecPlusOptionalLength = NACL_ARRAY_SIZE(kManifestUrlSpecRequired);
+ }
if (!IsValidDictionary(url_spec, container_key, parent_key,
- kManifestUrlSpecPlusOptional,
- NACL_ARRAY_SIZE(kManifestUrlSpecPlusOptional),
+ urlSpecPlusOptional,
+ urlSpecPlusOptionalLength,
kManifestUrlSpecRequired,
NACL_ARRAY_SIZE(kManifestUrlSpecRequired),
error_string)) {
return false;
}
+ // URL specifications must not contain "pnacl-translate" keys.
+ // This prohibits NaCl clients from invoking PNaCl.
+ Json::Value translate = url_spec[kPnaclTranslateKey];
+ if (!translate.empty()) {
+ nacl::stringstream error_stream;
+ error_stream << parent_key << " property '" << container_key <<
+ "' has '" << kPnaclTranslateKey << "' inside URL spec.";
+ *error_string = error_stream.str();
+ return false;
+ }
+ // Verify the correct types of the fields if they exist.
Json::Value url = url_spec[kUrlKey];
if (!url.isString()) {
nacl::stringstream error_stream;
@@ -172,6 +206,24 @@ bool IsValidUrlSpec(const Json::Value& url_spec,
*error_string = error_stream.str();
return false;
}
+ Json::Value cache_identity = url_spec[kCacheIdentityKey];
+ if (!cache_identity.empty() && !cache_identity.isString()) {
+ nacl::stringstream error_stream;
+ error_stream << parent_key << " property '" << container_key <<
+ "' has non-string value '" << cache_identity.toStyledString() <<
+ "' for key '" << kCacheIdentityKey << "'.";
+ *error_string = error_stream.str();
+ return false;
+ }
+ Json::Value opt_level = url_spec[kOptLevelKey];
+ if (!opt_level.empty() && !opt_level.isNumeric()) {
+ nacl::stringstream error_stream;
+ error_stream << parent_key << " property '" << container_key <<
+ "' has non-numeric value '" << opt_level.toStyledString() <<
+ "' for key '" << kOptLevelKey << "'.";
+ *error_string = error_stream.str();
+ return false;
+ }
return true;
}
@@ -180,6 +232,7 @@ bool IsValidUrlSpec(const Json::Value& url_spec,
bool IsValidPnaclTranslateSpec(const Json::Value& pnacl_spec,
const nacl::string& container_key,
const nacl::string& parent_key,
+ const nacl::string& sandbox_isa,
nacl::string* error_string) {
static const char* kManifestPnaclSpecProperties[] = {
kPnaclTranslateKey
@@ -194,7 +247,7 @@ bool IsValidPnaclTranslateSpec(const Json::Value& pnacl_spec,
}
Json::Value url_spec = pnacl_spec[kPnaclTranslateKey];
if (!IsValidUrlSpec(url_spec, kPnaclTranslateKey,
- container_key, error_string)) {
+ container_key, sandbox_isa, error_string)) {
return false;
}
return true;
@@ -210,6 +263,7 @@ bool IsValidPnaclTranslateSpec(const Json::Value& pnacl_spec,
bool IsValidISADictionary(const Json::Value& dictionary,
const nacl::string& parent_key,
const nacl::string& sandbox_isa,
+ bool must_find_matching_entry,
ErrorInfo* error_info) {
if (error_info == NULL) return false;
@@ -220,39 +274,86 @@ bool IsValidISADictionary(const Json::Value& dictionary,
" property is not an ISA to URL dictionary");
return false;
}
- // The keys to the dictionary have to be valid ISA names.
- Json::Value::Members members = dictionary.getMemberNames();
- for (size_t i = 0; i < members.size(); ++i) {
- // The known ISA values for ISA dictionaries in the manifest.
- static const char* kManifestISAProperties[] = {
+ // Build the set of reserved ISA dictionary keys.
+ const char** isaProperties;
+ size_t isaPropertiesLength;
+ if (sandbox_isa == kPortableKey) {
+ // The known values for PNaCl ISA dictionaries in the manifest.
+ static const char* kPnaclManifestISAProperties[] = {
+ kPortableKey
+ };
+ isaProperties = kPnaclManifestISAProperties;
+ isaPropertiesLength = NACL_ARRAY_SIZE(kPnaclManifestISAProperties);
+ } else {
+ // The known values for NaCl ISA dictionaries in the manifest.
+ static const char* kNaClManifestISAProperties[] = {
kX8632Key,
kX8664Key,
kArmKey,
+ // "portable" is here to allow checking that, if present, it can
+ // only refer to an URL, such as for a data file, and not to
+ // "pnacl-translate", which would cause the creation of a nexe.
kPortableKey
};
+ isaProperties = kNaClManifestISAProperties;
+ isaPropertiesLength = NACL_ARRAY_SIZE(kNaClManifestISAProperties);
+ }
+ // Check that entries in the dictionary are structurally correct.
+ Json::Value::Members members = dictionary.getMemberNames();
+ for (size_t i = 0; i < members.size(); ++i) {
nacl::string property_name = members[i];
- if (!FindMatchingProperty(property_name,
- kManifestISAProperties,
- NACL_ARRAY_SIZE(kManifestISAProperties))) {
- PLUGIN_PRINTF(("IsValidISADictionary: unrecognized ISA '%s'.\n",
- property_name.c_str()));
- }
- // Could be "arch/portable" : URLSpec, or
- // it could be "arch/portable" : { "pnacl-translate": URLSpec }
- // for executables that need to be translated.
Json::Value property_value = dictionary[property_name];
nacl::string error_string;
- if (!IsValidUrlSpec(property_value, property_name, parent_key,
- &error_string) &&
- !IsValidPnaclTranslateSpec(property_value, property_name,
- parent_key, &error_string)) {
- error_info->SetReport(ERROR_MANIFEST_SCHEMA_VALIDATE,
- nacl::string("manifest: ") + error_string);
- return false;
+ if (FindMatchingProperty(property_name,
+ isaProperties,
+ isaPropertiesLength)) {
+ // For NaCl, arch entries can only be
+ // "arch/portable" : URLSpec
+ // For PNaCl arch in "program" dictionary entries can only be
+ // "portable" : { "pnacl-translate": URLSpec }
+ // For PNaCl arch elsewhere, dictionary entries can only be
+ // "portable" : URLSpec
+ if ((sandbox_isa != kPortableKey &&
+ !IsValidUrlSpec(property_value, property_name, parent_key,
+ sandbox_isa, &error_string)) ||
+ (sandbox_isa == kPortableKey &&
+ parent_key == kProgramKey &&
+ !IsValidPnaclTranslateSpec(property_value, property_name, parent_key,
+ sandbox_isa, &error_string)) ||
+ (sandbox_isa == kPortableKey &&
+ parent_key != kProgramKey &&
+ !IsValidUrlSpec(property_value, property_name, parent_key,
+ sandbox_isa, &error_string))) {
+ error_info->SetReport(ERROR_MANIFEST_SCHEMA_VALIDATE,
+ nacl::string("manifest: ") + error_string);
+ return false;
+ }
+ } else {
+ // For forward compatibility, we do not prohibit other keys being in
+ // the dictionary, as they may be architectures supported in later
+ // versions. However, the value of these entries must be an URLSpec.
+ PLUGIN_PRINTF(("IsValidISADictionary: unrecognized key '%s'.\n",
+ property_name.c_str()));
+ if (!IsValidUrlSpec(property_value, property_name, parent_key,
+ sandbox_isa, &error_string)) {
+ error_info->SetReport(ERROR_MANIFEST_SCHEMA_VALIDATE,
+ nacl::string("manifest: ") + error_string);
+ return false;
+ }
}
}
- if (!sandbox_isa.empty()) {
+ if (sandbox_isa == kPortableKey) {
+ bool has_portable = dictionary.isMember(kPortableKey);
+
+ if (!has_portable) {
+ error_info->SetReport(
+ ERROR_MANIFEST_PROGRAM_MISSING_ARCH,
+ nacl::string("manifest: no version of ") + parent_key +
+ " given for portable.");
+ return false;
+ }
+ } else if (must_find_matching_entry) {
// TODO(elijahtaylor) add ISA resolver here if we expand ISAs to include
// micro-architectures that can resolve to multiple valid sandboxes.
bool has_isa = dictionary.isMember(sandbox_isa);
@@ -293,14 +394,16 @@ void GrabUrlAndPnaclOptions(const Json::Value& url_spec,
bool GetURLFromISADictionary(const Json::Value& dictionary,
const nacl::string& parent_key,
const nacl::string& sandbox_isa,
- bool prefer_portable,
nacl::string* url,
PnaclOptions* pnacl_options,
ErrorInfo* error_info) {
if (url == NULL || pnacl_options == NULL || error_info == NULL)
return false;
- if (!IsValidISADictionary(dictionary, parent_key, sandbox_isa, error_info)) {
+ // When the application actually requests a resolved URL, we must have
+ // a matching entry (sandbox_isa or portable) for NaCl.
+ if (!IsValidISADictionary(dictionary, parent_key, sandbox_isa, true,
+ error_info)) {
error_info->SetReport(ERROR_MANIFEST_RESOLVE_URL,
"architecture " + sandbox_isa +
" is not found for file " + parent_key);
@@ -314,7 +417,7 @@ bool GetURLFromISADictionary(const Json::Value& dictionary,
bool has_portable = dictionary.isMember(kPortableKey);
bool has_isa = dictionary.isMember(sandbox_isa);
nacl::string chosen_isa;
- if ((has_portable && prefer_portable) || !has_isa) {
+ if ((sandbox_isa == kPortableKey) || (has_portable && !has_isa)) {
chosen_isa = kPortableKey;
} else {
chosen_isa = sandbox_isa;
@@ -323,9 +426,11 @@ bool GetURLFromISADictionary(const Json::Value& dictionary,
// Check if this requires a pnacl-translate, otherwise just grab the URL.
// We may have pnacl-translate for isa-specific bitcode for CPU tuning.
if (isa_spec.isMember(kPnaclTranslateKey)) {
+ // PNaCl
GrabUrlAndPnaclOptions(isa_spec[kPnaclTranslateKey], url, pnacl_options);
pnacl_options->set_translate(true);
} else {
+ // NaCl
*url = isa_spec[kUrlKey].asString();
pnacl_options->set_translate(false);
}
@@ -337,7 +442,6 @@ bool GetKeyUrl(const Json::Value& dictionary,
const nacl::string& key,
const nacl::string& sandbox_isa,
const Manifest* manifest,
- bool prefer_portable,
nacl::string* full_url,
PnaclOptions* pnacl_options,
ErrorInfo* error_info) {
@@ -349,8 +453,8 @@ bool GetKeyUrl(const Json::Value& dictionary,
}
const Json::Value& isa_dict = dictionary[key];
nacl::string relative_url;
- if (!GetURLFromISADictionary(isa_dict, key, sandbox_isa, prefer_portable,
- &relative_url, pnacl_options, error_info)) {
+ if (!GetURLFromISADictionary(isa_dict, key, sandbox_isa, &relative_url,
+ pnacl_options, error_info)) {
return false;
}
return manifest->ResolveURL(relative_url, full_url, error_info);
@@ -410,24 +514,33 @@ bool JsonManifest::MatchesSchema(ErrorInfo* error_info) {
}
// Validate the program section.
+ // There must be a matching (portable or sandbox_isa_) entry for program for
+ // NaCl.
if (!IsValidISADictionary(dictionary_[kProgramKey],
kProgramKey,
sandbox_isa_,
+ true,
error_info)) {
return false;
}
// Validate the interpreter section (if given).
+ // There must be a matching (portable or sandbox_isa_) entry for interpreter
+ // for NaCl.
if (dictionary_.isMember(kInterpreterKey)) {
if (!IsValidISADictionary(dictionary_[kInterpreterKey],
kInterpreterKey,
sandbox_isa_,
+ true,
error_info)) {
return false;
}
}
// Validate the file dictionary (if given).
+ // The "files" key does not require a matching (portable or sandbox_isa_)
+ // entry at schema validation time for NaCl. This allows manifests to specify
+ // resources that are only loaded for a particular sandbox_isa.
if (dictionary_.isMember(kFilesKey)) {
const Json::Value& files = dictionary_[kFilesKey];
if (!files.isObject()) {
@@ -440,7 +553,8 @@ bool JsonManifest::MatchesSchema(ErrorInfo* error_info) {
nacl::string file_name = members[i];
if (!IsValidISADictionary(files[file_name],
file_name,
- nacl::string(),
+ sandbox_isa_,
+ false,
error_info)) {
return false;
}
@@ -484,7 +598,6 @@ bool JsonManifest::GetProgramURL(nacl::string* full_url,
if (!GetURLFromISADictionary(program,
kProgramKey,
sandbox_isa_,
- prefer_portable_,
&nexe_url,
pnacl_options,
error_info)) {
@@ -519,8 +632,8 @@ bool JsonManifest::ResolveKey(const nacl::string& key,
return false;
if (key == kProgramKey) {
- return GetKeyUrl(dictionary_, key, sandbox_isa_, this, prefer_portable_,
- full_url, pnacl_options, error_info);
+ return GetKeyUrl(dictionary_, key, sandbox_isa_, this, full_url,
+ pnacl_options, error_info);
}
nacl::string::const_iterator p = find(key.begin(), key.end(), '/');
if (p == key.end()) {
@@ -554,8 +667,8 @@ bool JsonManifest::ResolveKey(const nacl::string& key,
nacl::string("ResolveKey: no such \"files\" entry: ") + key);
return false;
}
- return GetKeyUrl(files, rest, sandbox_isa_, this, prefer_portable_,
- full_url, pnacl_options, error_info);
+ return GetKeyUrl(files, rest, sandbox_isa_, this, full_url, pnacl_options,
+ error_info);
}
} // namespace plugin
« no previous file with comments | « ppapi/native_client/src/trusted/plugin/json_manifest.h ('k') | ppapi/native_client/src/trusted/plugin/plugin.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698