NaCl Manifest Specification

Grammar

<manifest> ::= “{“ <sections> “}”

<sections> ::= <section> | <section> “,” <sections>
<section> ::= <manifest_metadata_section>
           | <program_section>
           | <interpreter_section>
           | <include_section>
           | <files_section>

<program_section> ::= “program” “:” <sandbox_isa_dictionary>
<interpreter_section> ::= “interpreter” “:” <sandbox_isa_dictionary>

<files_section> ::= “files” “:” “{“ <file_dictionary> “}”
<file_dictionary> ::= <file_entry> [ “,” <file_entry> ]*
<file_entry> ::= <file_name> “:” <sandbox_isa_dictionary>
<file_name> ::= JavaScript string

<sandbox_isa_dictionary> ::=
   “{“ <sandbox_isa_url> [ “,” <sandbox_isa_url> ]* “}”
<sandbox_isa_url> ::= <sandbox_isa> “:” <url_spec> | <translate_dictionary>
<sandbox_isa> ::= “x86-32” | “x86-64” | “arm-32” | “portable”

<url_spec_list> ::= <url_spec> [ “,” <url_spec> ]*
<url_spec> ::= “{ <url_value> [, <url_metadata>] }
<url_value> ::= “url” “:” <url>
<url> ::= JavaScript string

// Additions for PNaCl (not finalized)
<translate_dictionary> ::= “{“ “pnacl-translate” “:” <translate_spec> }
<translate_spec> ::= <url_value>
| <opt_value>
           | <cache_hash>
<opt_value> ::= -O : JavaScript number
<cache_hash> ::= “sha256 : JavaScript string


// POST v1.0 features under consideration
<manifest_metadata_section> ::=  TO BE DETERMINED
<url_metadata> ::= TO BE DETERMINED
<include_section> ::= “includes” “:” <include_array>
<include_array> ::= “[“ <url_spec_list> “]”

Examples

Example NaCl newlib:

{ "program": { "x86-32": { "url": "x86-32/myapp.nexe" },
              "x86-64": { "url": "x86-64/myapp.nexe" },
              "arm-32": { "url": "arm/myapp.nexe" }
}
}

Example for NaCl glibc (see NaCl Manifest File Format for GLibC):

{
 "program": {
   "x86-64": {"url": "lib64/runnable-ld.so"},
   "x86-32": {"url": "lib32/runnable-ld.so"}
 },
 "files": {
   "libpthread.so.5055067a" : {
     "x86-64": {"url": "lib64/libpthread.so.5055067a"},
     "x86-32": {"url": "lib32/libpthread.so.5055067a"}
   },
   "libppapi_cpp.so" : {
     "x86-64": {"url": "lib64/libppapi_cpp.so"},
     "x86-32": {"url": "lib32/libppapi_cpp.so"}
   },
   "libstdc++.so.6" : {
     "x86-64": {"url": "lib64/libstdc++.so.6"},
     "x86-32": {"url": "lib32/libstdc++.so.6"}
   },
   "libm.so.5055067a" : {  
     "x86-64": {"url": "lib64/libm.so.5055067a"},
     "x86-32": {"url": "lib32/libm.so.5055067a"}
   },
   "libgcc_s.so.1" : {
     "x86-64": {"url": "lib64/libgcc_s.so.1"},
     "x86-32": {"url": "lib32/libgcc_s.so.1"}
   },
   "libc.so.5055067a" : {  
     "x86-64": {"url": "lib64/libc.so.5055067a"},
     "x86-32": {"url": "lib32/libc.so.5055067a"}
   },
   "main.nexe" : {
     "x86-64": {"url": "pi_generator_x86_64.nexe"},
     "x86-32": {"url": "pi_generator_x86_32.nexe"}
   }
 }
}

Example for Portable NaCl:

{
"program": {
"portable": {
"pnacl-translate": {
"url": "simple_app.pexe",
"-O": 0,
"sha256": "abc1023..."
}
}
}
}


Future use cases, which involve mutiple PNaCl modules:

{ "program": {
"portable": {
"pnacl-translate": {
"url": "myapp.pexe",
"-O": 0,
"sha256": "3294890db..."
}
}
}
 "files": { "/usr/local/lib/mylib.so": {
"portable": {
"pnacl-translate": {
"url": "libm.pso",
   "-O": 2,
"sha256": "94382ae..."
}
}
},
            "background.jpg": {
"portable": {
"url": "http://my.com/background.jpg"
}
}
          
}
}


Semantics

URL resolution

All URLs contained in a manifest are resolved relative to the URL of the manifest.  If the manifest was specified as a data URI, the URLs must all be absolute.

Include processing (NOT IN V1.0)

The include_section specifies a list of URLs that should be included when processing the manifest file.  Each URL specified in an include must follow the same schema as the topmost manifest, except that only the topmost manifest may specify a program_section.

Nexe matching

The main nexe for the application is determined by looking up the current sandbox ISA in  sandbox_isa_dictionary specifying the URL to use for given sandbox ISAs.  Lookup is from most to least specific.  That is, if there is an exact match for the current sandbox ISA (e.g., “x86-32”) it is used in preference to more general (e.g., “portable”).  This rule can be extended for sandbox ISAs to encode micro-architectural information (e.g., “x86-32-atom” is more specific than “x86-32”).  If the lookup concludes with ‘portable’, the nexe is a pnacl bitcode file, and will need to be translated to the current most specific sandbox architecture, of course.  

File matching

All files (shared objects and other assets, typically) are looked up by a UTF8 string file_name, through an interface from the nexe TBD.  From this we lookup the file_dictionary corresponding to that file_name.  Failure to find file_name in the files_section is a run-time error. The matching rule from there is identical to that used by nexe identification.

Schema validation

Manifests are validated before the nexe is started.  Schema validation ensures that each manifest
  1. is valid JSON
  2. conforms to the grammar given above, but allows freedom for other keys in the manifest and url_spec dictionaries.
  3. contains at least one applicable match for the current sandbox ISA in program_section, interpreter section, and every file_entry mentioned in the manifest

Manifest inlining combines the multiple manifests into one and further ensures
  1. there is exactly one program_section
  2. there is at most one interpreter_section
Comments