Skip to content

Commit

Permalink
Add loader.env.[ENVIRON] = {passthrough=true} manifest option
Browse files Browse the repository at this point in the history
It is now possible to define some envvars that are passed through from
the host inside the Gramine instance (previously the only way to pass
envvars was to set `loader.insecure__use_host_env`). A new LibOS
regression test is added.

Signed-off-by: Dmitrii Kuvaiskii <dmitrii.kuvaiskii@intel.com>
  • Loading branch information
dimakuv committed Sep 29, 2021
1 parent 090db13 commit 3e778e5
Show file tree
Hide file tree
Showing 6 changed files with 272 additions and 68 deletions.
28 changes: 24 additions & 4 deletions Documentation/manifest-syntax.rst
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,20 @@ both of the following options:
::

loader.env.[ENVIRON] = "[VALUE]"
or
loader.env.[ENVIRON] = { value = "[VALUE]" }
or
loader.env.[ENVIRON] = { passthrough = true }

loader.env_src_file = "file:file_with_serialized_envs"

``loader.env.[ENVIRON]`` adds/overwrites a single environment variable and can
be used multiple times to specify more than one variable.
``loader.env.[ENVIRON]`` adds/overwrites/passes a single environment variable
and can be used multiple times to specify more than one variable. To
add/overwrite the environment variable, specify a TOML string (``"[VALUE]"``) or
a TOML table with the key-value pair ``{ value = "[VALUE]" }``. To pass the
environment variable from the host, specify a TOML table with the key-value pair
``{ passthrough = true }``. If you specify a variable, it needs to either have a
value or be a passthrough.

``loader.env_src_file`` allows to specify a URI to a file containing serialized
environment, which can be generated using :program:`gramine-argv-serializer`.
Expand All @@ -174,7 +184,17 @@ provided at runtime from an external (trusted) source.
variables.
If the same variable is set in both, then ``loader.env.[ENVIRON]`` takes
precedence.
precedence. It is prohibited to specify both ``value`` and ``passthrough`` keys
for the same environment variable. If manifest option ``insecure__use_host_env``
is specified, then ``passthrough = true`` manifest options have no effect (they
are "consumed" by ``insecure__use_host_env``).

.. note ::
It is tempting to try to passthrough all environment variables using
``insecure__use_host_env`` and then disallow some of them using ``passthrough
= false``. However, this deny list approach is intentionally prohibited
because it's inherently insecure (doesn't provide any real security).
Gramine loudly fails if ``passthrough = false`` manifest options are set.
Disabling ASLR
^^^^^^^^^^^^^^
Expand Down Expand Up @@ -308,7 +328,7 @@ Gramine currently supports two types of mount points:
* ``chroot``: Host-backed files. All host files and sub-directories found under
``[URI]`` are forwarded to the Gramine instance and placed under ``[PATH]``.
For example, with a host-level path specified as
``fs.mount.lib.uri = "file:/one/path/"`` and forwarded to Graphene via
``fs.mount.lib.uri = "file:/one/path/"`` and forwarded to Gramine via
``fs.mount.lib.path = "/another/path"``, a host-level file
``/one/path/file`` is visible to graphenized application as
``/another/path/file``. This concept is similar to FreeBSD's chroot and to
Expand Down
1 change: 1 addition & 0 deletions LibOS/shim/test/regression/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
/double_fork
/env_from_file
/env_from_host
/env_passthrough
/epoll_epollet
/epoll_wait_timeout
/eventfd
Expand Down
1 change: 1 addition & 0 deletions LibOS/shim/test/regression/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ repo_manifests = \
device_passthrough.manifest \
env_from_file.manifest \
env_from_host.manifest \
env_passthrough.manifest \
file_check_policy_allow_all_but_log.manifest \
file_check_policy_strict.manifest \
multi_pthread_exitless.manifest
Expand Down
22 changes: 22 additions & 0 deletions LibOS/shim/test/regression/env_passthrough.manifest.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
loader.preload = "file:{{ gramine.libos }}"
loader.argv0_override = "bootstrap"
libos.entrypoint = "bootstrap"

loader.env.LD_LIBRARY_PATH = "/lib"

loader.env.A = { passthrough = true }
loader.env.B = { value = "OVERWRITTEN_VALUE" }

# loader.env.C = { passthrough = false } # not allowed for security reasons
# loader.env.E = { passthrough = true, value = "THIS_IS_INCORRECT_SYNTAX" }

fs.mount.lib.type = "chroot"
fs.mount.lib.path = "/lib"
fs.mount.lib.uri = "file:{{ gramine.runtimedir() }}"

sgx.nonpie_binary = true

sgx.trusted_files = [
"file:{{ gramine.runtimedir() }}/",
"file:bootstrap",
]
22 changes: 20 additions & 2 deletions LibOS/shim/test/regression/test_libos.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,33 @@ def test_104_env_from_file(self):
finally:
os.remove('env_test_input')

def test_105_env_passthrough(self):
host_envs = {
'A': 'THIS_WILL_BE_PASSED',
'B': 'THIS_WILL_BE_OVERWRITTEN',
'C': 'THIS_SHOULDNT_BE_PASSED',
'D': 'THIS_SHOULDNT_BE_PASSED_TOO',
}
manifest_envs = {'LD_LIBRARY_PATH': '/lib'}
stdout, _ = self.run_binary(['env_passthrough'], env=host_envs)
self.assertIn('# of envs: %d\n' % (len(host_envs) - 2 + len(manifest_envs)), stdout)

# We don't enforce any specific order of envs, so we skip checking the index.
self.assertIn('] = LD_LIBRARY_PATH=/lib\n', stdout)
self.assertIn('] = A=THIS_WILL_BE_PASSED\n', stdout)
self.assertIn('] = B=OVERWRITTEN_VALUE\n', stdout)
self.assertNotIn('] = C=THIS_SHOULDNT_BE_PASSED\n', stdout)
self.assertNotIn('] = D=THIS_SHOULDNT_BE_PASSED_TOO\n', stdout)

@unittest.skipUnless(HAS_SGX,
'This test is only meaningful on SGX PAL because only SGX catches raw '
'syscalls and redirects to Gramine\'s LibOS. If we will add seccomp to '
'Linux PAL, then we should allow this test on Linux PAL as well.')
def test_105_basic_bootstrapping_static(self):
def test_106_basic_bootstrapping_static(self):
stdout, _ = self.run_binary(['bootstrap_static'])
self.assertIn('Hello world (bootstrap_static)!', stdout)

def test_106_basic_bootstrapping_pie(self):
def test_107_basic_bootstrapping_pie(self):
stdout, _ = self.run_binary(['bootstrap_pie'])
self.assertIn('User program started', stdout)
self.assertIn('Local Address in Executable: 0x', stdout)
Expand Down

0 comments on commit 3e778e5

Please sign in to comment.