Files
graphene/Scripts/regression.py
T
Rafał Wojdyła cf84489cd5 [Linux-SGX] Add protected files implementation
Protected files (PF) are a new type of file that can be specified in
the manifest (SGX only). They are encrypted on disk and transparently
decrypted when accessed by the Graphene payload.

Other features:
- data is integrity protected (tamper resistance)
- file swap protection (a PF can only be accessed when in a specific path)
- transparency (Graphene payload sees PFs as regular files, no need to modify
  the payload)

See Linux-SGX/protected-files directory for implementation. PF format is
based on protected files from the SGX SDK:
https://github.com/intel/linux-sgx/tree/master/sdk/protected_fs

The following new manifest elements are added:

sgx.protected_files_key = <16-byte hex value>
sgx.protected_files.<name> = file:<host path>

sgx.protected_files_key specifies the encryption key and is only a temporary
implementation. This key should be provisioned with local/remote attestation
in the future.

Paths specifying PF entries can be files or directories. If a directory is
specified, all files/directories within are registered as protected
recursively (and are expected to be encrypted in the PF format).

Linux-SGX/tools directory contains the pf_crypt utility that converts files
to/from the protected format.
2020-07-13 20:19:42 +02:00

88 lines
3.0 KiB
Python

import contextlib
import os
import pathlib
import signal
import subprocess
import unittest
HAS_SGX = os.environ.get('SGX') == '1'
ON_X86 = os.uname().machine in ['x86_64']
def expectedFailureIf(predicate):
if predicate:
return unittest.expectedFailure
return lambda func: func
class RegressionTestCase(unittest.TestCase):
LOADER_ENV = 'PAL_LOADER'
DEFAULT_TIMEOUT = (20 if HAS_SGX else 10)
def get_manifest(self, filename):
return filename + '.manifest' + ('.sgx' if HAS_SGX else '')
def run_binary(self, args, *, timeout=None, **kwds):
timeout = (max(self.DEFAULT_TIMEOUT, timeout) if timeout is not None
else self.DEFAULT_TIMEOUT)
try:
loader = os.environ[self.LOADER_ENV]
except KeyError:
self.skipTest(
'environment variable {} unset'.format(self.LOADER_ENV))
if not pathlib.Path(loader).exists():
self.skipTest('loader ({}) not found'.format(loader))
with subprocess.Popen([loader, 'init', *args],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
preexec_fn=os.setpgrp,
**kwds) as process:
try:
stdout, stderr = process.communicate(timeout=timeout)
except subprocess.TimeoutExpired:
os.killpg(process.pid, signal.SIGKILL)
self.fail('timeout ({} s) expired'.format(timeout))
if process.returncode:
raise subprocess.CalledProcessError(
process.returncode, args, stdout, stderr)
return stdout.decode(), stderr.decode()
def run_native_binary(self, args, timeout=None, libpath=None, **kwds):
timeout = (max(self.DEFAULT_TIMEOUT, timeout) if timeout is not None
else self.DEFAULT_TIMEOUT)
my_env = os.environ.copy()
if not libpath is None:
my_env["LD_LIBRARY_PATH"] = libpath
with subprocess.Popen(args,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
env=my_env,
preexec_fn=os.setpgrp,
**kwds) as process:
try:
stdout, stderr = process.communicate(timeout=timeout)
except subprocess.TimeoutExpired:
os.killpg(process.pid, signal.SIGKILL)
self.fail('timeout ({} s) expired'.format(timeout))
if process.returncode:
raise subprocess.CalledProcessError(
process.returncode, args, stdout, stderr)
return stdout.decode(), stderr.decode()
@contextlib.contextmanager
def expect_returncode(self, returncode):
if returncode == 0:
raise ValueError('expected returncode should be nonzero')
try:
yield
self.fail('did not fail (expected {})'.format(returncode))
except subprocess.CalledProcessError as e:
self.assertEqual(e.returncode, returncode,
'failed with returncode {} (expected {})'.format(
e.returncode, returncode))