Clone of chromium aad1ce808763f59c7a3753e08f1500a104ecc6fd refs/remotes/origin/HEAD
diff --git a/mojo/nacl/DEPS b/mojo/nacl/DEPS
new file mode 100644
index 0000000..69e7ada
--- /dev/null
+++ b/mojo/nacl/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+ "+native_client/src/public",
+ "+native_client/src/trusted/desc",
+ "+native_client/src/trusted/service_runtime",
+]
diff --git a/mojo/nacl/README b/mojo/nacl/README
new file mode 100644
index 0000000..36913ac
--- /dev/null
+++ b/mojo/nacl/README
@@ -0,0 +1,24 @@
+This is a prototype for plumbing Mojo into the NaCl sandbox. It is
+currently insecure (see below), does not provide a stable ABI (IRT
+support must be added), and does not support Mojo functions that
+return pointers (for example, MojoMapBuffer).
+
+generator/interface.py contains a programmatic description of the
+stable Mojo interface. This will need to be updated as the interface
+changes. Run generator/generate_nacl_bindings.py to generate the
+bindings that plumb this interface into the NaCl sandbox.
+
+To test: Build "monacl_shell" and "monacl_test". Run monacl_shell
+with the IRT as the first argument and the monacl_test as the second
+argument. For example, to run a Debug 32-bit Intel build:
+
+ cd out/Debug
+ ./monacl_shell irt_core_newlib_x32.nexe monacl_test_newlib_x32.nexe
+
+Security TODO list:
+ Separate trusted and untrusted Mojo handles.
+ Validate and copy option structures.
+ Protect untrusted buffers passed into Mojo:
+ NaClVmIoWillStart/HasEnded.
+ volatile accesses to untrusted memory (untrusted code could race).
+ Overflow checking in array bounds validation.
\ No newline at end of file
diff --git a/mojo/nacl/generator/generate_nacl_bindings.py b/mojo/nacl/generator/generate_nacl_bindings.py
new file mode 100755
index 0000000..2c8ae9d
--- /dev/null
+++ b/mojo/nacl/generator/generate_nacl_bindings.py
@@ -0,0 +1,404 @@
+#!/usr/bin/python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# pylint: disable=W0104,W0106,F0401,R0201
+
+import optparse
+import os.path
+import sys
+
+import interface
+
+
+def _ScriptDir():
+ return os.path.dirname(os.path.abspath(__file__))
+
+
+def _GetDirAbove(dirname):
+ """Returns the directory "above" this file containing |dirname| (which must
+ also be "above" this file)."""
+ path = _ScriptDir()
+ while True:
+ path, tail = os.path.split(path)
+ assert tail
+ if tail == dirname:
+ return path
+
+
+def _AddThirdPartyImportPath():
+ sys.path.append(os.path.join(_GetDirAbove('mojo'), 'third_party'))
+
+
+_AddThirdPartyImportPath()
+import jinja2
+
+loader = jinja2.FileSystemLoader(_ScriptDir())
+jinja_env = jinja2.Environment(loader=loader, keep_trailing_newline=True)
+
+
+# Accumulate lines of code with varying levels of indentation.
+class CodeWriter(object):
+ def __init__(self):
+ self._lines = []
+ self._margin = ''
+ self._margin_stack = []
+
+ def __lshift__(self, line):
+ self._lines.append((self._margin + line).rstrip())
+
+ def PushMargin(self):
+ self._margin_stack.append(self._margin)
+ self._margin += ' '
+
+ def PopMargin(self):
+ self._margin = self._margin_stack.pop()
+
+ def GetValue(self):
+ return '\n'.join(self._lines).rstrip() + '\n'
+
+ def Indent(self):
+ return Indent(self)
+
+
+# Context handler that automatically indents and dedents a CodeWriter
+class Indent(object):
+ def __init__(self, writer):
+ self._writer = writer
+
+ def __enter__(self):
+ self._writer.PushMargin()
+
+ def __exit__(self, type_, value, traceback):
+ self._writer.PopMargin()
+
+
+def TemplateFile(name):
+ return os.path.join(os.path.dirname(__file__), name)
+
+
+# Wraps comma separated lists as needed.
+def Wrap(pre, items, post):
+ complete = pre + ', '.join(items) + post
+ if len(complete) <= 80:
+ return [complete]
+ lines = [pre]
+ indent = ' '
+ for i, item in enumerate(items):
+ if i < len(items) - 1:
+ lines.append(indent + item + ',')
+ else:
+ lines.append(indent + item + post)
+ return lines
+
+
+def GeneratorWarning():
+ return ('// WARNING this file was generated by %s\n// Do not edit by hand.' %
+ os.path.basename(__file__))
+
+
+# Untrusted library implementing the public Mojo API.
+def GenerateLibMojo(functions, out):
+ template = jinja_env.get_template('libmojo.cc.tmpl')
+
+ code = CodeWriter()
+
+ for f in functions:
+ for line in Wrap('%s %s(' % (f.return_type, f.name), f.ParamList(), ') {'):
+ code << line
+
+ # 2 extra parameters: message ID and return value.
+ num_params = len(f.params) + 2
+
+ with code.Indent():
+ code << 'uint32_t params[%d];' % num_params
+ return_type = f.result_param.base_type
+ if return_type == 'MojoResult':
+ default = 'MOJO_RESULT_INVALID_ARGUMENT'
+ elif return_type == 'MojoTimeTicks':
+ default = '0'
+ else:
+ raise Exception('Unhandled return type: ' + return_type)
+ code << '%s %s = %s;' % (return_type, f.result_param.name, default)
+
+ # Message ID
+ code << 'params[0] = %d;' % f.uid
+ # Parameter pointers
+ cast_template = 'params[%d] = reinterpret_cast<uint32_t>(%s);'
+ for p in f.params:
+ ptr = p.name
+ if p.IsPassedByValue():
+ ptr = '&' + ptr
+ code << cast_template % (p.uid + 1, ptr)
+ # Return value pointer
+ code << cast_template % (num_params - 1, '&' + f.result_param.name)
+
+ code << 'DoMojoCall(params, sizeof(params));'
+ code << 'return %s;' % f.result_param.name
+
+ code << '}'
+ code << ''
+
+ body = code.GetValue()
+ text = template.render(
+ generator_warning=GeneratorWarning(),
+ body=body)
+ out.write(text)
+
+
+# Parameters passed into trusted code are handled differently depending on
+# details of the parameter. ParamImpl instances encapsulate these differences
+# and are used to generate the code that transfers parameters across the
+# untrusted/trusted boundary.
+class ParamImpl(object):
+ def __init__(self, param):
+ self.param = param
+
+ # Declare whatever variables are needed to handle this particular parameter.
+ def DeclareVars(self, code):
+ raise NotImplementedError()
+
+ # Convert the untrusted representation of the parameter into a trusted
+ # representation, such as a scalar value or a trusted pointer into the
+ # untrusted address space.
+ def ConvertParam(self):
+ raise NotImplementedError()
+
+ # For this particular parameter, what expression should be passed when
+ # invoking the trusted Mojo API function?
+ def CallParam(self):
+ raise NotImplementedError()
+
+ # After invoking the trusted Mojo API function, transfer data back into
+ # untrusted memory. Overriden for Out and InOut parameters.
+ def CopyOut(self, code):
+ pass
+
+ # Converting array parameters needs to be defered until after the scalar
+ # parameter containing the size of the array has itself been converted.
+ def IsArray(self):
+ return False
+
+
+class ScalarInputImpl(ParamImpl):
+ def DeclareVars(self, code):
+ code << '%s %s_value;' % (self.param.base_type, self.param.name)
+
+ def ConvertParam(self):
+ p = self.param
+ return ('ConvertScalarInput(nap, params[%d], &%s_value)' %
+ (p.uid + 1, p.name))
+
+ def CallParam(self):
+ return '%s_value' % self.param.name
+
+
+class ScalarOutputImpl(ParamImpl):
+ def DeclareVars(self, code):
+ code << '%s volatile* %s_ptr;' % (self.param.base_type, self.param.name)
+ code << '%s %s_value;' % (self.param.base_type, self.param.name)
+
+ def ConvertParam(self):
+ p = self.param
+ return 'ConvertScalarOutput(nap, params[%d], &%s_ptr)' % (p.uid + 1, p.name)
+
+ def CallParam(self):
+ return '&%s_value' % self.param.name
+
+ def CopyOut(self, code):
+ name = self.param.name
+ code << '*%s_ptr = %s_value;' % (name, name)
+
+
+class ScalarInOutImpl(ParamImpl):
+ def DeclareVars(self, code):
+ code << '%s volatile* %s_ptr;' % (self.param.base_type, self.param.name)
+ code << '%s %s_value;' % (self.param.base_type, self.param.name)
+
+ def ConvertParam(self):
+ p = self.param
+ return ('ConvertScalarInOut(nap, params[%d], %s, &%s_value, &%s_ptr)' %
+ (p.uid + 1, CBool(p.is_optional), p.name, p.name))
+
+ def CallParam(self):
+ name = self.param.name
+ expr = '&%s_value' % name
+ if self.param.is_optional:
+ expr = '%s_ptr ? %s : NULL' % (name, expr)
+ return expr
+
+ def CopyOut(self, code):
+ name = self.param.name
+ if self.param.is_optional:
+ code << 'if (%s_ptr != NULL) {' % (name)
+ with code.Indent():
+ code << '*%s_ptr = %s_value;' % (name, name)
+ code << '}'
+ else:
+ code << '*%s_ptr = %s_value;' % (name, name)
+
+
+class ArrayImpl(ParamImpl):
+ def DeclareVars(self, code):
+ code << '%s %s;' % (self.param.param_type, self.param.name)
+
+ def ConvertParam(self):
+ p = self.param
+ if p.base_type == 'void':
+ element_size = '1'
+ else:
+ element_size = 'sizeof(*%s)' % p.name
+
+ return ('ConvertArray(nap, params[%d], %s, %s, %s, &%s)' %
+ (p.uid + 1, p.size + '_value', element_size, CBool(p.is_optional),
+ p.name))
+
+ def CallParam(self):
+ return self.param.name
+
+ def IsArray(self):
+ return True
+
+
+class StructInputImpl(ParamImpl):
+ def DeclareVars(self, code):
+ code << '%s %s;' % (self.param.param_type, self.param.name)
+
+ def ConvertParam(self):
+ p = self.param
+ return ('ConvertStruct(nap, params[%d], %s, &%s)' %
+ (p.uid + 1, CBool(p.is_optional), p.name))
+
+ def CallParam(self):
+ return self.param.name
+
+
+def ImplForParam(p):
+ if p.IsScalar():
+ if p.is_output:
+ if p.is_input:
+ return ScalarInOutImpl(p)
+ else:
+ return ScalarOutputImpl(p)
+ else:
+ return ScalarInputImpl(p)
+ elif p.is_array:
+ return ArrayImpl(p)
+ elif p.is_struct:
+ return StructInputImpl(p)
+ else:
+ assert False, p
+
+
+def CBool(value):
+ return 'true' if value else 'false'
+
+
+# A trusted wrapper that validates the arguments passed from untrusted code
+# before passing them to the underlying public Mojo API.
+def GenerateMojoSyscall(functions, out):
+ template = jinja_env.get_template('mojo_syscall.cc.tmpl')
+
+ code = CodeWriter()
+ code.PushMargin()
+
+ for f in functions:
+ impls = [ImplForParam(p) for p in f.params]
+ impls.append(ImplForParam(f.result_param))
+
+ code << 'case %d:' % f.uid
+
+ code.PushMargin()
+
+ code << '{'
+
+ with code.Indent():
+ num_params = len(f.params) + 2
+ code << 'if (num_params != %d) {' % num_params
+ with code.Indent():
+ code << 'return -1;'
+ code << '}'
+
+ # Declare temporaries.
+ for impl in impls:
+ impl.DeclareVars(code)
+
+ def ConvertParam(code, impl):
+ code << 'if (!%s) {' % impl.ConvertParam()
+ with code.Indent():
+ code << 'return -1;'
+ code << '}'
+
+ code << '{'
+ with code.Indent():
+ code << 'ScopedCopyLock copy_lock(nap);'
+ # Convert and validate pointers in two passes.
+ # Arrays cannot be validated until the size parameter has been
+ # converted.
+ for impl in impls:
+ if not impl.IsArray():
+ ConvertParam(code, impl)
+ for impl in impls:
+ if impl.IsArray():
+ ConvertParam(code, impl)
+ code << '}'
+ code << ''
+
+ # Call
+ getParams = [impl.CallParam() for impl in impls[:-1]]
+ code << 'result_value = %s(%s);' % (f.name, ', '.join(getParams))
+ code << ''
+
+ # Write outputs
+ code << '{'
+ with code.Indent():
+ code << 'ScopedCopyLock copy_lock(nap);'
+ for impl in impls:
+ impl.CopyOut(code)
+ code << '}'
+ code << ''
+
+ code << 'return 0;'
+ code << '}'
+
+ code.PopMargin()
+
+ body = code.GetValue()
+ text = template.render(
+ generator_warning=GeneratorWarning(),
+ body=body)
+ out.write(text)
+
+
+def OutFile(dir_path, name):
+ if not os.path.exists(dir_path):
+ os.makedirs(dir_path)
+ return open(os.path.join(dir_path, name), 'w')
+
+
+def main(args):
+ usage = 'usage: %prog [options]'
+ parser = optparse.OptionParser(usage=usage)
+ parser.add_option(
+ '-d',
+ dest='out_dir',
+ metavar='DIR',
+ help='output generated code into directory DIR')
+ options, args = parser.parse_args(args=args)
+ if not options.out_dir:
+ parser.error('-d is required')
+ if args:
+ parser.error('unexpected positional arguments: %s' % ' '.join(args))
+
+ mojo = interface.MakeInterface()
+
+ out = OutFile(options.out_dir, 'libmojo.cc')
+ GenerateLibMojo(mojo.functions, out)
+
+ out = OutFile(options.out_dir, 'mojo_syscall.cc')
+ GenerateMojoSyscall(mojo.functions, out)
+
+
+if __name__ == '__main__':
+ main(sys.argv[1:])
diff --git a/mojo/nacl/generator/interface.py b/mojo/nacl/generator/interface.py
new file mode 100644
index 0000000..2a23fd7
--- /dev/null
+++ b/mojo/nacl/generator/interface.py
@@ -0,0 +1,108 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# pylint: disable=F0401
+
+import interface_dsl
+
+def MakeInterface():
+ mojo = interface_dsl.Interface()
+
+ f = mojo.Func('MojoCreateSharedBuffer', 'MojoResult')
+ f.Param('options').InStruct('MojoCreateSharedBufferOptions').Optional()
+ f.Param('num_bytes').In('uint64_t')
+ f.Param('shared_buffer_handle').Out('MojoHandle')
+
+ f = mojo.Func('MojoDuplicateBufferHandle', 'MojoResult')
+ f.Param('buffer_handle').In('MojoHandle')
+ f.Param('options').InStruct('MojoDuplicateBufferHandleOptions').Optional()
+ f.Param('new_buffer_handle').Out('MojoHandle')
+
+ f = mojo.Func('MojoMapBuffer', 'MojoResult')
+ f.Param('buffer_handle').In('MojoHandle')
+ f.Param('offset').In('uint64_t')
+ f.Param('num_bytes').In('uint64_t')
+ f.Param('buffer').Out('void*')
+ f.Param('flags').In('MojoMapBufferFlags')
+
+ f = mojo.Func('MojoUnmapBuffer', 'MojoResult')
+ f.Param('buffer').In('void*')
+
+ f = mojo.Func('MojoCreateDataPipe', 'MojoResult')
+ f.Param('options').InStruct('MojoCreateDataPipeOptions').Optional()
+ f.Param('data_pipe_producer_handle').Out('MojoHandle')
+ f.Param('data_pipe_consumer_handle').Out('MojoHandle')
+
+ f = mojo.Func('MojoWriteData', 'MojoResult')
+ f.Param('data_pipe_producer_handle').In('MojoHandle')
+ f.Param('elements').InArray('void', 'num_bytes')
+ f.Param('num_bytes').InOut('uint32_t')
+ f.Param('flags').In('MojoWriteDataFlags')
+
+ f = mojo.Func('MojoBeginWriteData', 'MojoResult')
+ f.Param('data_pipe_producer_handle').In('MojoHandle')
+ f.Param('buffer').Out('void*')
+ f.Param('buffer_num_bytes').InOut('uint32_t')
+ f.Param('flags').In('MojoWriteDataFlags')
+
+ f = mojo.Func('MojoEndWriteData', 'MojoResult')
+ f.Param('data_pipe_producer_handle').In('MojoHandle')
+ f.Param('num_bytes_written').In('uint32_t')
+
+ f = mojo.Func('MojoReadData', 'MojoResult')
+ f.Param('data_pipe_consumer_handle').In('MojoHandle')
+ f.Param('elements').OutArray('void', 'num_bytes')
+ f.Param('num_bytes').InOut('uint32_t')
+ f.Param('flags').In('MojoReadDataFlags')
+
+ f = mojo.Func('MojoBeginReadData', 'MojoResult')
+ f.Param('data_pipe_consumer_handle').In('MojoHandle')
+ f.Param('buffer').Out('const void*')
+ f.Param('buffer_num_bytes').InOut('uint32_t')
+ f.Param('flags').In('MojoReadDataFlags')
+
+ f = mojo.Func('MojoEndReadData', 'MojoResult')
+ f.Param('data_pipe_consumer_handle').In('MojoHandle')
+ f.Param('num_bytes_read').In('uint32_t')
+
+ f = mojo.Func('MojoGetTimeTicksNow', 'MojoTimeTicks')
+
+ f = mojo.Func('MojoClose', 'MojoResult')
+ f.Param('handle').In('MojoHandle')
+
+ f = mojo.Func('MojoWait', 'MojoResult')
+ f.Param('handle').In('MojoHandle')
+ f.Param('signals').In('MojoHandleSignals')
+ f.Param('deadline').In('MojoDeadline')
+
+ f = mojo.Func('MojoWaitMany', 'MojoResult')
+ f.Param('handles').InArray('MojoHandle', 'num_handles')
+ f.Param('signals').InArray('MojoHandleSignals', 'num_handles')
+ f.Param('num_handles').In('uint32_t')
+ f.Param('deadline').In('MojoDeadline')
+
+ f = mojo.Func('MojoCreateMessagePipe', 'MojoResult')
+ f.Param('options').InStruct('MojoCreateMessagePipeOptions').Optional()
+ f.Param('message_pipe_handle0').Out('MojoHandle')
+ f.Param('message_pipe_handle1').Out('MojoHandle')
+
+ f = mojo.Func('MojoWriteMessage', 'MojoResult')
+ f.Param('message_pipe_handle').In('MojoHandle')
+ f.Param('bytes').InArray('void', 'num_bytes').Optional()
+ f.Param('num_bytes').In('uint32_t')
+ f.Param('handles').InArray('MojoHandle', 'num_handles').Optional()
+ f.Param('num_handles').In('uint32_t')
+ f.Param('flags').In('MojoWriteMessageFlags')
+
+ f = mojo.Func('MojoReadMessage', 'MojoResult')
+ f.Param('message_pipe_handle').In('MojoHandle')
+ f.Param('bytes').OutArray('void', 'num_bytes').Optional()
+ f.Param('num_bytes').InOut('uint32_t').Optional()
+ f.Param('handles').OutArray('MojoHandle', 'num_handles').Optional()
+ f.Param('num_handles').InOut('uint32_t').Optional()
+ f.Param('flags').In('MojoReadMessageFlags')
+
+ mojo.Finalize()
+
+ return mojo
diff --git a/mojo/nacl/generator/interface_dsl.py b/mojo/nacl/generator/interface_dsl.py
new file mode 100644
index 0000000..dfc85aa
--- /dev/null
+++ b/mojo/nacl/generator/interface_dsl.py
@@ -0,0 +1,116 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+class Interface(object):
+ def __init__(self):
+ self.functions = []
+
+ def Func(self, name, return_type):
+ f = Function(self, len(self.functions), name, return_type)
+ self.functions.append(f)
+ return f
+
+ def Finalize(self):
+ for f in self.functions:
+ f.Finalize()
+
+class Function(object):
+ def __init__(self, parent, uid, name, return_type):
+ self.parent = parent
+ self.uid = uid
+ self.name = name
+ self.return_type = return_type
+ self.params = []
+ self.param_by_name = {}
+ self.result_param = None
+
+ def Param(self, name, param_type=None):
+ p = Param(self, len(self.params), name, param_type)
+ self.params.append(p)
+ self.param_by_name[name] = p
+ return p
+
+ def ParamList(self):
+ return [param.param_type + ' ' + param.name for param in self.params]
+
+ def ParamDecl(self):
+ if self.params:
+ return ', '.join(self.ParamList())
+ else:
+ return 'void'
+
+ def Finalize(self):
+ self.result_param = Param(self, len(self.params), 'result')
+ self.result_param.Out(self.return_type)
+
+class Param(object):
+ def __init__(self, parent, uid, name, param_type=None):
+ self.parent = parent
+ self.uid = uid
+ self.name = name
+ self.base_type = param_type
+ self.param_type = param_type
+ self.size = None
+ self.is_input = False
+ self.is_output = False
+ self.is_array = False
+ self.is_struct = False
+ self.is_optional = False
+
+ def GetSizeParam(self):
+ assert self.size
+ return self.parent.param_by_name[self.size]
+
+ def In(self, ty):
+ self.base_type = ty
+ self.param_type = ty
+ self.is_input = True
+ return self
+
+ def InArray(self, ty, size):
+ self.base_type = ty
+ self.param_type = 'const ' + ty + '*'
+ self.size = size
+ self.is_input = True
+ self.is_array = True
+ return self
+
+ def InStruct(self, ty):
+ self.base_type = ty
+ self.param_type = 'const struct ' + ty + '*'
+ self.is_input = True
+ self.is_struct = True
+ return self
+
+ def InOut(self, ty):
+ self.base_type = ty
+ self.param_type = ty + '*'
+ self.is_input = True
+ self.is_output = True
+ return self
+
+ def Out(self, ty):
+ self.base_type = ty
+ self.param_type = ty + '*'
+ self.is_output = True
+ return self
+
+ def OutArray(self, ty, size):
+ self.base_type = ty
+ self.param_type = ty + '*'
+ self.size = size
+ self.is_array = True
+ self.is_output = True
+ return self
+
+ def Optional(self):
+ assert not self.IsPassedByValue()
+ self.is_optional = True
+ return self
+
+ def IsScalar(self):
+ return not self.is_array and not self.is_struct
+
+ def IsPassedByValue(self):
+ return not self.is_output and self.IsScalar()
diff --git a/mojo/nacl/generator/libmojo.cc.tmpl b/mojo/nacl/generator/libmojo.cc.tmpl
new file mode 100644
index 0000000..7690d82
--- /dev/null
+++ b/mojo/nacl/generator/libmojo.cc.tmpl
@@ -0,0 +1,25 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+{{generator_warning}}
+
+#include "mojo/public/c/system/core.h"
+#include "native_client/src/public/chrome_main.h"
+#include "native_client/src/public/imc_syscalls.h"
+#include "native_client/src/public/imc_types.h"
+
+#define NACL_MOJO_DESC (NACL_CHROME_DESC_BASE + 2)
+
+static void DoMojoCall(uint32_t params[], nacl_abi_size_t num_params) {
+ NaClAbiNaClImcMsgIoVec iov[1] = {
+ {params, num_params}
+ };
+ NaClAbiNaClImcMsgHdr msgh = {iov, 1, NULL, 0};
+ // Note: return value unchecked. We're relying on the result parameter being
+ // unmodified - if the syscall fails, the Mojo function will return whatever
+ // the result parameter was initialized to before this function was called.
+ imc_sendmsg(NACL_MOJO_DESC, &msgh, 0);
+}
+
+{{body}}
diff --git a/mojo/nacl/generator/mojo_syscall.cc.tmpl b/mojo/nacl/generator/mojo_syscall.cc.tmpl
new file mode 100644
index 0000000..136e672
--- /dev/null
+++ b/mojo/nacl/generator/mojo_syscall.cc.tmpl
@@ -0,0 +1,66 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+{{generator_warning}}
+
+#include "mojo/nacl/mojo_syscall.h"
+
+#include <stdio.h>
+
+#include "mojo/nacl/mojo_syscall_internal.h"
+#include "mojo/public/c/system/core.h"
+#include "native_client/src/public/chrome_main.h"
+#include "native_client/src/public/nacl_app.h"
+#include "native_client/src/trusted/desc/nacl_desc_custom.h"
+
+namespace {
+
+void MojoDescDestroy(void* handle) {
+}
+
+ssize_t MojoDescSendMsg(void* handle,
+ const struct NaClImcTypedMsgHdr* msg,
+ int flags) {
+ struct NaClApp* nap = static_cast<struct NaClApp*>(handle);
+
+ if (msg->iov_length != 1 || msg->ndesc_length != 0) {
+ return -1;
+ }
+
+ uint32_t volatile* params = static_cast<uint32_t volatile*>(msg->iov[0].base);
+ size_t num_params = msg->iov[0].length / sizeof(*params);
+
+ if (num_params < 1) {
+ return -1;
+ }
+
+ uint32_t msg_type = params[0];
+ switch (msg_type) {
+{{body}}
+ }
+
+ return -1;
+}
+
+ssize_t MojoDescRecvMsg(void* handle,
+ struct NaClImcTypedMsgHdr* msg,
+ int flags) {
+ return -1;
+}
+
+struct NaClDesc* MakeMojoDesc(struct NaClApp* nap) {
+ struct NaClDescCustomFuncs funcs = NACL_DESC_CUSTOM_FUNCS_INITIALIZER;
+ funcs.Destroy = MojoDescDestroy;
+ funcs.SendMsg = MojoDescSendMsg;
+ funcs.RecvMsg = MojoDescRecvMsg;
+ return NaClDescMakeCustomDesc(nap, &funcs);
+}
+
+} // namespace
+
+#define NACL_MOJO_DESC (NACL_CHROME_DESC_BASE + 2)
+
+void InjectMojo(struct NaClApp* nap) {
+ NaClAppSetDesc(nap, NACL_MOJO_DESC, MakeMojoDesc(nap));
+}
diff --git a/mojo/nacl/mojo_syscall.h b/mojo/nacl/mojo_syscall.h
new file mode 100644
index 0000000..f195769
--- /dev/null
+++ b/mojo/nacl/mojo_syscall.h
@@ -0,0 +1,10 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_NACL_MOJO_SYSCALL_H_
+#define MOJO_NACL_MOJO_SYSCALL_H_
+
+void InjectMojo(struct NaClApp* nap);
+
+#endif // MOJO_NACL_MOJO_SYSCALL_H_
diff --git a/mojo/nacl/mojo_syscall_internal.h b/mojo/nacl/mojo_syscall_internal.h
new file mode 100644
index 0000000..f0795e6
--- /dev/null
+++ b/mojo/nacl/mojo_syscall_internal.h
@@ -0,0 +1,150 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_NACL_MOJO_SYSCALL_INTERNAL_H_
+#define MOJO_NACL_MOJO_SYSCALL_INTERNAL_H_
+
+#include "native_client/src/trusted/service_runtime/nacl_copy.h"
+#include "native_client/src/trusted/service_runtime/sel_ldr.h"
+
+namespace {
+
+class ScopedCopyLock {
+ public:
+ explicit ScopedCopyLock(struct NaClApp* nap) : nap_(nap) {
+ NaClCopyTakeLock(nap_);
+ }
+ ~ScopedCopyLock() {
+ NaClCopyDropLock(nap_);
+ }
+ private:
+ struct NaClApp* nap_;
+};
+
+static inline uintptr_t NaClUserToSysAddrArray(
+ struct NaClApp* nap,
+ uint32_t uaddr,
+ size_t count,
+ size_t size) {
+ // TODO(ncbray): overflow checking
+ size_t range = count * size;
+ return NaClUserToSysAddrRange(nap, uaddr, range);
+}
+
+template <typename T> bool ConvertScalarInput(
+ struct NaClApp* nap,
+ uint32_t user_ptr,
+ T* value) {
+ if (user_ptr) {
+ uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, sizeof(T));
+ if (temp != kNaClBadAddress) {
+ *value = *reinterpret_cast<T volatile*>(temp);
+ return true;
+ }
+ }
+ return false;
+}
+
+template <typename T> bool ConvertScalarOutput(
+ struct NaClApp* nap,
+ uint32_t user_ptr,
+ T volatile** sys_ptr) {
+ if (user_ptr) {
+ uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, sizeof(T));
+ if (temp != kNaClBadAddress) {
+ *sys_ptr = reinterpret_cast<T volatile*>(temp);
+ return true;
+ }
+ }
+ *sys_ptr = 0; // Paranoia.
+ return false;
+}
+
+template <typename T> bool ConvertScalarInOut(
+ struct NaClApp* nap,
+ uint32_t user_ptr,
+ bool optional,
+ T* value,
+ T volatile** sys_ptr) {
+ if (user_ptr) {
+ uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, sizeof(T));
+ if (temp != kNaClBadAddress) {
+ T volatile* converted = reinterpret_cast<T volatile*>(temp);
+ *sys_ptr = converted;
+ *value = *converted;
+ return true;
+ }
+ } else if (optional) {
+ *sys_ptr = 0;
+ *value = static_cast<T>(0); // Paranoia.
+ return true;
+ }
+ *sys_ptr = 0; // Paranoia.
+ *value = static_cast<T>(0); // Paranoia.
+ return false;
+}
+
+template <typename T> bool ConvertArray(
+ struct NaClApp* nap,
+ uint32_t user_ptr,
+ uint32_t length,
+ size_t element_size,
+ bool optional,
+ T** sys_ptr) {
+ if (user_ptr) {
+ uintptr_t temp = NaClUserToSysAddrArray(nap, user_ptr, length,
+ element_size);
+ if (temp != kNaClBadAddress) {
+ *sys_ptr = reinterpret_cast<T*>(temp);
+ return true;
+ }
+ } else if (optional) {
+ *sys_ptr = 0;
+ return true;
+ }
+ return false;
+}
+
+template <typename T> bool ConvertBytes(
+ struct NaClApp* nap,
+ uint32_t user_ptr,
+ uint32_t length,
+ bool optional,
+ T** sys_ptr) {
+ if (user_ptr) {
+ uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, length);
+ if (temp != kNaClBadAddress) {
+ *sys_ptr = reinterpret_cast<T*>(temp);
+ return true;
+ }
+ } else if (optional) {
+ *sys_ptr = 0;
+ return true;
+ }
+ return false;
+}
+
+// TODO(ncbray): size validation and complete copy.
+// TODO(ncbray): ensure non-null / missized structs are covered by a test case.
+template <typename T> bool ConvertStruct(
+ struct NaClApp* nap,
+ uint32_t user_ptr,
+ bool optional,
+ T** sys_ptr) {
+ if (user_ptr) {
+ uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, sizeof(T));
+ if (temp != kNaClBadAddress) {
+ *sys_ptr = reinterpret_cast<T*>(temp);
+ return true;
+ }
+ } else if (optional) {
+ *sys_ptr = 0;
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
+#endif // MOJO_NACL_MOJO_SYSCALL_INTERNAL_H_
diff --git a/mojo/nacl/monacl_sel_main.cc b/mojo/nacl/monacl_sel_main.cc
new file mode 100644
index 0000000..4fbc575
--- /dev/null
+++ b/mojo/nacl/monacl_sel_main.cc
@@ -0,0 +1,52 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mojo/nacl/monacl_sel_main.h"
+
+#include <stdio.h>
+
+#include "mojo/nacl/mojo_syscall.h"
+#include "native_client/src/public/chrome_main.h"
+#include "native_client/src/public/nacl_app.h"
+#include "native_client/src/trusted/desc/nacl_desc_io.h"
+#include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
+
+namespace mojo {
+
+void LaunchNaCl(const char* nexe_file, const char* irt_file,
+ int app_argc, char* app_argv[]) {
+ NaClChromeMainInit();
+
+ // Open the IRT.
+ struct NaClDesc* irt_desc = (struct NaClDesc*) NaClDescIoDescOpen(
+ irt_file, NACL_ABI_O_RDONLY, 0);
+ if (NULL == irt_desc) {
+ perror(irt_file);
+ exit(1);
+ }
+
+ // Open the main executable.
+ struct NaClDesc* nexe_desc = (struct NaClDesc*) NaClDescIoDescOpen(
+ nexe_file, NACL_ABI_O_RDONLY, 0);
+ if (NULL == nexe_desc) {
+ perror(nexe_file);
+ exit(1);
+ }
+
+ struct NaClChromeMainArgs* args = NaClChromeMainArgsCreate();
+ args->nexe_desc = nexe_desc;
+ args->irt_desc = irt_desc;
+
+ args->argc = app_argc;
+ args->argv = app_argv;
+
+ struct NaClApp* nap = NaClAppCreate();
+ InjectMojo(nap);
+
+ int exit_status = 1;
+ NaClChromeMainStart(nap, args, &exit_status);
+ NaClExit(exit_status);
+}
+
+} // namespace mojo
diff --git a/mojo/nacl/monacl_sel_main.h b/mojo/nacl/monacl_sel_main.h
new file mode 100644
index 0000000..f543d16
--- /dev/null
+++ b/mojo/nacl/monacl_sel_main.h
@@ -0,0 +1,15 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MOJO_NACL_MONACL_SEL_MAIN_H_
+#define MOJO_NACL_MONACL_SEL_MAIN_H_
+
+namespace mojo {
+
+void LaunchNaCl(const char* nexe_file, const char* irt_file,
+ int app_argc, char* app_argv[]);
+
+} // namespace mojo
+
+#endif // MOJO_NACL_MONACL_SEL_MAIN_H_
diff --git a/mojo/nacl/monacl_shell.cc b/mojo/nacl/monacl_shell.cc
new file mode 100644
index 0000000..7922d9a
--- /dev/null
+++ b/mojo/nacl/monacl_shell.cc
@@ -0,0 +1,28 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <iostream>
+
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/simple_platform_support.h"
+#include "mojo/nacl/monacl_sel_main.h"
+
+
+int main(int argc, char* argv[]) {
+ if (argc < 3) {
+ std::cout << "Usage: " << argv[0] << " irt.nexe app.nexe [args for app]" <<
+ std::endl;
+ return 1;
+ }
+
+ const char* irt_file = argv[1];
+ const char* nexe_file = argv[2];
+
+ mojo::embedder::Init(scoped_ptr<mojo::embedder::PlatformSupport>(
+ new mojo::embedder::SimplePlatformSupport()));
+
+ // Does not return.
+ mojo::LaunchNaCl(nexe_file, irt_file, argc - 2, argv + 2);
+ return 1;
+}