-
Notifications
You must be signed in to change notification settings - Fork 201
/
manifest.py
208 lines (162 loc) · 6.61 KB
/
manifest.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# SPDX-License-Identifier: LGPL-3.0-or-later
# Copyright (C) 2021 Wojtek Porczyk <[email protected]>
# Copyright (C) 2022 Intel Corporation
# Michał Kowalczyk <[email protected]>
# Borys Popławski <[email protected]>
"""
Gramine manifest management and rendering
"""
import hashlib
import os
import pathlib
import tomli
import tomli_w
from . import _env
DEFAULT_ENCLAVE_SIZE_NO_EDMM = '256M'
DEFAULT_ENCLAVE_SIZE_WITH_EDMM = '1024G' # 1TB; note that DebugInfo is at 1TB and ASan at 1.5TB
DEFAULT_THREAD_NUM = 4
class ManifestError(Exception):
"""Thrown at errors in manifest parsing and handling.
Contains a string with error description.
"""
def hash_file_contents(path):
with open(path, 'rb') as f:
sha = hashlib.sha256()
for chunk in iter(lambda: f.read(128 * sha.block_size), b''):
sha.update(chunk)
return sha.hexdigest()
def uri2path(uri):
if not uri.startswith('file:'):
raise ManifestError(f'Unsupported URI type: {uri}')
return pathlib.Path(uri[len('file:'):])
def append_tf(trusted_files, path, hash_=None):
if path not in trusted_files:
trusted_files[path] = hash_ if hash_ is not None else hash_file_contents(path)
def append_trusted_dir_or_file(trusted_files, val, expanded):
if isinstance(val, dict):
uri = val['uri']
if val.get('sha256'):
append_tf(trusted_files, uri2path(uri), val['sha256'])
return
elif isinstance(val, str):
uri = val
else:
raise ManifestError(f'Unknown trusted file format: {val!r}')
path = uri2path(uri)
if not path.exists():
raise ManifestError(f'Cannot resolve {path}')
if path.is_dir():
if not uri.endswith('/'):
raise ManifestError(f'Directory URI ({uri}) does not end with "/"')
expanded.append(path)
for sub_path in sorted(path.rglob('*')):
expanded.append(sub_path)
if sub_path.is_file():
# Skip inaccessible files
if os.access(sub_path, os.R_OK):
append_tf(trusted_files, sub_path)
else:
assert path.is_file()
append_tf(trusted_files, path)
expanded.append(path)
class Manifest:
"""Just a representation of a manifest.
You can access or change specific manifest entries via ``[]`` operator (just like a normal
python ``dict``).
Args:
manifest_str (str): the manifest in the TOML format.
"""
def __init__(self, manifest_str):
manifest = tomli.loads(manifest_str)
sgx = manifest.setdefault('sgx', {})
sgx.setdefault('trusted_files', [])
sgx.setdefault('max_threads', DEFAULT_THREAD_NUM)
sgx.setdefault('isvprodid', 0)
sgx.setdefault('isvsvn', 0)
sgx.setdefault('remote_attestation', "none")
sgx.setdefault('debug', False)
sgx.setdefault('require_avx', False)
sgx.setdefault('require_avx512', False)
sgx.setdefault('require_mpx', False)
sgx.setdefault('require_pkru', False)
sgx.setdefault('require_amx', False)
sgx.setdefault('require_exinfo', False)
sgx.setdefault('enable_stats', False)
sgx.setdefault('edmm_enable', False)
if sgx['edmm_enable']:
sgx.setdefault('enclave_size', DEFAULT_ENCLAVE_SIZE_WITH_EDMM)
else:
sgx.setdefault('enclave_size', DEFAULT_ENCLAVE_SIZE_NO_EDMM)
sgx.setdefault('enable_aex_notify', False)
if not isinstance(sgx['trusted_files'], list):
raise ValueError("Unsupported trusted files syntax, more info: " +
"https://gramine.readthedocs.io/en/latest/manifest-syntax.html#trusted-files")
trusted_files = []
for tf in sgx['trusted_files']:
if isinstance(tf, dict) and 'uri' in tf:
trusted_files.append(tf)
elif isinstance(tf, str):
trusted_files.append({'uri': tf})
else:
raise ManifestError(f'Unknown trusted file format: {tf!r}')
sgx['trusted_files'] = trusted_files
self._manifest = manifest
def __getitem__(self, key):
return self._manifest[key]
def __setitem__(self, key, val):
self._manifest[key] = val
@classmethod
def from_template(cls, template, variables=None):
"""Render template into Manifest.
Creates a manifest from the jinja template given as string. Optional variables may be given
as mapping.
Args:
template (str): jinja2 template of the manifest
variables (:obj:`dict`, optional): Dictionary of variables that are used in
the template.
Returns:
Manifest: instance created from rendered template.
"""
return cls(_env.from_string(template).render(**(variables or {})))
@classmethod
def loads(cls, s):
return cls(s)
@classmethod
def load(cls, f):
return cls.loads(f.read())
def dumps(self):
return tomli_w.dumps(self._manifest)
def dump(self, f):
tomli_w.dump(self._manifest, f)
def expand_all_trusted_files(self):
"""Expand all trusted files entries.
Collects all trusted files entries, hashes each of them (skipping these which already had a
hash present) and updates ``sgx.trusted_files`` manifest entry with the result.
Returns a list of all expanded files, i.e. files that we need to hash, and directories that
we needed to list.
Raises:
ManifestError: There was an error with the format of some trusted files in the manifest
or some of them could not be loaded from the filesystem.
"""
trusted_files = {}
expanded = []
for tf in self['sgx']['trusted_files']:
append_trusted_dir_or_file(trusted_files, tf, expanded)
self['sgx']['trusted_files'] = [
{'uri': f'file:{k}', 'sha256': v} for k, v in trusted_files.items()
]
return expanded
def get_dependencies(self):
"""Generate list of files which this manifest depends on.
Collects all trusted files that are not yet expanded (do not have a hash in the entry) and
returns them.
Returns:
list(pathlib.Path): List of paths to the files this manifest depends on.
Raises:
ManifestError: One of the found URIs is in an unsupported format.
"""
deps = set()
for tf in self['sgx']['trusted_files']:
if not tf.get('sha256'):
deps.add(uri2path(tf['uri']))
return deps