Skip to content

Commit 2233cf6

Browse files
committed
Single-process-lifetime rollback protection for protected files (WIP)
* adds libos_encrypted_volume as mount-data for protected fileystem which includes map <name, <last-root-hash, ...>> to keep track of root hashes across open/close cycles of a particular value, ensuring consistency across the whole enclave life-time Signed-off-by: g2flyer <[email protected]>
1 parent e6abd2b commit 2233cf6

File tree

8 files changed

+224
-66
lines changed

8 files changed

+224
-66
lines changed

common/src/protected_files/protected_files.c

+14-3
Original file line numberDiff line numberDiff line change
@@ -1184,23 +1184,31 @@ void pf_set_callbacks(pf_read_f read_f, pf_write_f write_f, pf_fsync_f fsync_f,
11841184
}
11851185

11861186
pf_status_t pf_open(pf_handle_t handle, const char* path, uint64_t underlying_size,
1187-
pf_file_mode_t mode, bool create, const pf_key_t* key, pf_context_t** context) {
1187+
pf_file_mode_t mode, bool create, const pf_key_t* key,
1188+
pf_mac_t* opening_root_gmac, pf_context_t** context) {
11881189
if (!g_initialized)
11891190
return PF_STATUS_UNINITIALIZED;
11901191

11911192
pf_status_t status;
11921193
*context = ipf_open(path, mode, create, handle, underlying_size, key, &status);
1194+
if (opening_root_gmac != NULL) {
1195+
memcpy(opening_root_gmac, (*context)->file_metadata.plain_part.metadata_gmac,
1196+
sizeof(pf_mac_t));
1197+
}
11931198
return status;
11941199
}
11951200

1196-
pf_status_t pf_close(pf_context_t* pf) {
1201+
pf_status_t pf_close(pf_context_t* pf, pf_mac_t* closing_root_gmac) {
11971202
if (!g_initialized)
11981203
return PF_STATUS_UNINITIALIZED;
11991204

12001205
if (ipf_close(pf)) {
12011206
free(pf);
12021207
return PF_STATUS_SUCCESS;
12031208
}
1209+
if (closing_root_gmac != NULL) {
1210+
memcpy(closing_root_gmac, pf->file_metadata.plain_part.metadata_gmac, sizeof(pf_mac_t));
1211+
}
12041212

12051213
pf_status_t ret = pf->last_error;
12061214
free(pf);
@@ -1267,7 +1275,7 @@ pf_status_t pf_set_size(pf_context_t* pf, uint64_t size) {
12671275
return PF_STATUS_SUCCESS;
12681276
}
12691277

1270-
pf_status_t pf_rename(pf_context_t* pf, const char* new_path) {
1278+
pf_status_t pf_rename(pf_context_t* pf, const char* new_path, pf_mac_t* new_root_gmac) {
12711279
if (!g_initialized)
12721280
return PF_STATUS_UNINITIALIZED;
12731281

@@ -1283,6 +1291,9 @@ pf_status_t pf_rename(pf_context_t* pf, const char* new_path) {
12831291
pf->need_writing = true;
12841292
if (!ipf_internal_flush(pf))
12851293
return pf->last_error;
1294+
if (new_root_gmac != NULL) {
1295+
memcpy(new_root_gmac, pf->file_metadata.plain_part.metadata_gmac, sizeof(pf_mac_t));
1296+
}
12861297

12871298
return PF_STATUS_SUCCESS;
12881299
}

common/src/protected_files/protected_files.h

+18-14
Original file line numberDiff line numberDiff line change
@@ -214,28 +214,31 @@ const char* pf_strerror(int err);
214214
/*!
215215
* \brief Open a protected file.
216216
*
217-
* \param handle Open underlying file handle.
218-
* \param path Path to the file. If NULL and \p create is false, don't check path
219-
* for validity.
220-
* \param underlying_size Underlying file size.
221-
* \param mode Access mode.
222-
* \param create Overwrite file contents if true.
223-
* \param key Wrap key.
224-
* \param[out] context PF context for later calls.
217+
* \param handle Open underlying file handle.
218+
* \param path Path to the file. If NULL and \p create is false, don't check path
219+
* for validity.
220+
* \param underlying_size Underlying file size.
221+
* \param mode Access mode.
222+
* \param create Overwrite file contents if true.
223+
* \param key Wrap key.
224+
* \param opening_root_gmac If non-NULL, !create & successfull open, returns root-hash of file
225+
* \param[out] context PF context for later calls.
225226
*
226227
* \returns PF status.
227228
*/
228229
pf_status_t pf_open(pf_handle_t handle, const char* path, uint64_t underlying_size,
229-
pf_file_mode_t mode, bool create, const pf_key_t* key, pf_context_t** context);
230+
pf_file_mode_t mode, bool create, const pf_key_t* key,
231+
pf_mac_t* opening_root_gmac, pf_context_t** context);
230232

231233
/*!
232234
* \brief Close a protected file and commit all changes to disk.
233235
*
234-
* \param pf PF context.
236+
* \param pf PF context.
237+
* \param closing_root_gmac If non-NULL, returns root-hash of file at closing time
235238
*
236239
* \returns PF status.
237240
*/
238-
pf_status_t pf_close(pf_context_t* pf);
241+
pf_status_t pf_close(pf_context_t* pf, pf_mac_t* closing_root_gmac);
239242

240243
/*!
241244
* \brief Read from a protected file.
@@ -288,13 +291,14 @@ pf_status_t pf_set_size(pf_context_t* pf, uint64_t size);
288291
/*!
289292
* \brief Rename a PF.
290293
*
291-
* \param pf PF context.
292-
* \param new_path New file path.
294+
* \param pf PF context.
295+
* \param new_path New file path.
296+
* \param new_root_gmac if non-NULL, returns new root-hash of file
293297
*
294298
* Updates the path inside protected file header, and flushes all changes. The caller is responsible
295299
* for renaming the underlying file.
296300
*/
297-
pf_status_t pf_rename(pf_context_t* pf, const char* new_path);
301+
pf_status_t pf_rename(pf_context_t* pf, const char* new_path, pf_mac_t* new_root_gmac);
298302

299303
/*!
300304
* \brief Get underlying handle of a PF.

libos/include/libos_fs.h

+3
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ struct libos_mount_params {
3535

3636
/* Key name (used by `chroot_encrypted` filesystem), or NULL if not applicable */
3737
const char* key_name;
38+
39+
/* Enforcement type (used by `chroot_encrypted` filesystem), or NULL if not applicable */
40+
const char* protection_mode;
3841
};
3942

4043
struct libos_fs_ops {

libos/include/libos_fs_encrypted.h

+40-5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include <stddef.h>
1616

17+
#include "libos_checkpoint.h" // ofr include of uthash.h _and_ consistent uthash_fatal macros
1718
#include "libos_types.h"
1819
#include "list.h"
1920
#include "pal.h"
@@ -34,6 +35,40 @@ struct libos_encrypted_files_key {
3435
LIST_TYPE(libos_encrypted_files_key) list;
3536
};
3637

38+
typedef enum {
39+
PF_FILE_IN_USE_NEW = 0, // file is currently in-use but did not exist at open time
40+
PF_FILE_IN_USE_EXISTING = 1, // file is currently in-use and existed at open time
41+
PF_FILE_CLOSED = 2, // file was provisously seend with known (good committed) state
42+
PF_FILE_DELETED = 3, // the old path of renames is also considered deleted
43+
PF_FILE_ERROR = 4, // file is in non-determined state due to some errors
44+
} libos_encrypted_file_state_t;
45+
46+
/*
47+
* Map mapping file URIs to state providing information on files, in particular whether we have seen
48+
* them before and what the last seen root-hash is. This is necessary to provide rollback
49+
*/
50+
struct libos_encrypted_volume_state_map {
51+
char* uri; // assumptions: all paths canonicalized, symlinks are resolved & no hard links
52+
libos_encrypted_file_state_t state;
53+
pf_mac_t last_seen_root_gmac;
54+
UT_hash_handle hh;
55+
};
56+
57+
typedef enum {
58+
PF_ENCLAVE_LIFE_RB_PROTECTION_NONE = 0,
59+
PF_ENCLAVE_LIFE_RB_PROTECTION_NON_STRICT = 1,
60+
PF_ENCLAVE_LIFE_RB_PROTECTION_STRICT = 2,
61+
} libos_encrypted_files_mode_t;
62+
63+
struct libos_encrypted_volume {
64+
libos_encrypted_files_mode_t protection_mode;
65+
66+
struct libos_encrypted_volume_state_map* files_state_map;
67+
struct libos_lock files_state_map_lock;
68+
69+
struct libos_encrypted_files_key* key;
70+
};
71+
3772
/*
3873
* Represents a specific encrypted file. The file is open as long as `use_count` is greater than 0.
3974
* Note that the file can be open and closed multiple times before it's destroyed.
@@ -44,7 +79,7 @@ struct libos_encrypted_files_key {
4479
struct libos_encrypted_file {
4580
size_t use_count;
4681
char* uri;
47-
struct libos_encrypted_files_key* key;
82+
struct libos_encrypted_volume* volume;
4883

4984
/* `pf` and `pal_handle` are non-null as long as `use_count` is greater than 0 */
5085
pf_context_t* pf;
@@ -110,29 +145,29 @@ void update_encrypted_files_key(struct libos_encrypted_files_key* key, const pf_
110145
* \brief Open an existing encrypted file.
111146
*
112147
* \param uri PAL URI to open, has to begin with "file:".
113-
* \param key Key, has to be already set.
148+
* \param volume Volume assocated with file, has to be already set.
114149
* \param[out] out_enc On success, set to a newly created `libos_encrypted_file` object.
115150
*
116151
* `uri` has to correspond to an existing file that can be decrypted with `key`.
117152
*
118153
* The newly created `libos_encrypted_file` object will have `use_count` set to 1.
119154
*/
120-
int encrypted_file_open(const char* uri, struct libos_encrypted_files_key* key,
155+
int encrypted_file_open(const char* uri, struct libos_encrypted_volume* volume,
121156
struct libos_encrypted_file** out_enc);
122157

123158
/*
124159
* \brief Create a new encrypted file.
125160
*
126161
* \param uri PAL URI to open, has to begin with "file:".
127162
* \param perm Permissions for the new file.
128-
* \param key Key, has to be already set.
163+
* \param volume Volume assocated with file, has to be already set.
129164
* \param[out] out_enc On success, set to a newly created `libos_encrypted_file` object.
130165
*
131166
* `uri` must not correspond to an existing file.
132167
*
133168
* The newly created `libos_encrypted_file` object will have `use_count` set to 1.
134169
*/
135-
int encrypted_file_create(const char* uri, mode_t perm, struct libos_encrypted_files_key* key,
170+
int encrypted_file_create(const char* uri, mode_t perm, struct libos_encrypted_volume* volume,
136171
struct libos_encrypted_file** out_enc);
137172

138173
/*

libos/src/fs/chroot/encrypted.c

+49-12
Original file line numberDiff line numberDiff line change
@@ -68,27 +68,64 @@ static int chroot_encrypted_mount(struct libos_mount_params* params, void** moun
6868
if (ret < 0)
6969
return ret;
7070

71-
*mount_data = key;
71+
libos_encrypted_files_mode_t protection_mode =
72+
PF_ENCLAVE_LIFE_RB_PROTECTION_STRICT; // default mode
73+
if (params->protection_mode) {
74+
if (strncmp(params->protection_mode, "strict", strlen("strict")) == 0)
75+
protection_mode = PF_ENCLAVE_LIFE_RB_PROTECTION_STRICT;
76+
else if (strncmp(params->protection_mode, "non-strict", strlen("non-strict")) == 0)
77+
protection_mode = PF_ENCLAVE_LIFE_RB_PROTECTION_NON_STRICT;
78+
else if (strncmp(params->protection_mode, "none", strlen("none")) == 0)
79+
protection_mode = PF_ENCLAVE_LIFE_RB_PROTECTION_NONE;
80+
else {
81+
log_error("Invalid enforcement type: %s", params->protection_mode);
82+
return -EINVAL;
83+
}
84+
protection_mode = PF_ENCLAVE_LIFE_RB_PROTECTION_STRICT;
85+
protection_mode = PF_ENCLAVE_LIFE_RB_PROTECTION_NON_STRICT;
86+
protection_mode = PF_ENCLAVE_LIFE_RB_PROTECTION_NONE;
87+
}
88+
89+
struct libos_encrypted_volume* volume = malloc(sizeof(struct libos_encrypted_volume));
90+
if (!volume)
91+
return -ENOMEM;
92+
volume->protection_mode = protection_mode;
93+
volume->key = key;
94+
if (!create_lock(&volume->files_state_map_lock)) {
95+
free(volume);
96+
return -ENOMEM;
97+
}
98+
volume->files_state_map = NULL;
99+
100+
*mount_data = volume;
72101
return 0;
73102
}
74103

75104
static ssize_t chroot_encrypted_checkpoint(void** checkpoint, void* mount_data) {
76-
struct libos_encrypted_files_key* key = mount_data;
105+
struct libos_encrypted_volume* volume = mount_data;
77106

78-
*checkpoint = strdup(key->name);
107+
// TODO (MST): fix below, doesn't really makes sense: i guess i have to duplicate something
108+
// about volume?
109+
*checkpoint = strdup(volume->key->name);
79110
if (!*checkpoint)
80111
return -ENOMEM;
81-
return strlen(key->name) + 1;
112+
return strlen(volume->key->name) + 1;
82113
}
83114

84115
static int chroot_encrypted_migrate(void* checkpoint, void** mount_data) {
85116
const char* name = checkpoint;
86117

87-
struct libos_encrypted_files_key* key;
88-
int ret = get_or_create_encrypted_files_key(name, &key);
118+
struct libos_encrypted_volume* volume = malloc(sizeof(struct libos_encrypted_volume));
119+
if (!volume)
120+
return -ENOMEM;
121+
122+
if (!create_lock(&volume->files_state_map_lock))
123+
return -ENOMEM;
124+
// TODO (MST): initialize map
125+
int ret = get_or_create_encrypted_files_key(name, &(volume->key));
89126
if (ret < 0)
90127
return ret;
91-
*mount_data = key;
128+
*mount_data = volume;
92129
return 0;
93130
}
94131

@@ -153,8 +190,8 @@ static int chroot_encrypted_lookup(struct libos_dentry* dent) {
153190
struct libos_encrypted_file* enc;
154191
file_off_t size;
155192

156-
struct libos_encrypted_files_key* key = dent->mount->data;
157-
ret = encrypted_file_open(uri, key, &enc);
193+
struct libos_encrypted_volume* volume = dent->mount->data;
194+
ret = encrypted_file_open(uri, volume, &enc);
158195
if (ret < 0) {
159196
if (ret == -EACCES) {
160197
/* allow the inode to be created even if the underlying encrypted file is corrupted;
@@ -210,7 +247,7 @@ static int chroot_encrypted_open(struct libos_handle* hdl, struct libos_dentry*
210247
get_inode(dent->inode);
211248
hdl->type = TYPE_CHROOT_ENCRYPTED;
212249
hdl->seekable = true;
213-
hdl->pos = 0;
250+
hdl->pos = 0;
214251
return 0;
215252
}
216253

@@ -231,9 +268,9 @@ static int chroot_encrypted_creat(struct libos_handle* hdl, struct libos_dentry*
231268
goto out;
232269
}
233270

234-
struct libos_encrypted_files_key* key = dent->mount->data;
271+
struct libos_encrypted_volume* volume = dent->mount->data;
235272
struct libos_encrypted_file* enc;
236-
ret = encrypted_file_create(uri, HOST_PERM(perm), key, &enc);
273+
ret = encrypted_file_create(uri, HOST_PERM(perm), volume, &enc);
237274
if (ret < 0)
238275
goto out;
239276

libos/src/fs/libos_fs.c

+17-8
Original file line numberDiff line numberDiff line change
@@ -195,10 +195,11 @@ static int mount_one_nonroot(toml_table_t* mount, const char* prefix) {
195195

196196
int ret;
197197

198-
char* mount_type = NULL;
199-
char* mount_path = NULL;
200-
char* mount_uri = NULL;
201-
char* mount_key_name = NULL;
198+
char* mount_type = NULL;
199+
char* mount_path = NULL;
200+
char* mount_uri = NULL;
201+
char* mount_key_name = NULL;
202+
char* mount_protection_mode = NULL;
202203

203204
ret = toml_string_in(mount, "type", &mount_type);
204205
if (ret < 0) {
@@ -228,6 +229,13 @@ static int mount_one_nonroot(toml_table_t* mount, const char* prefix) {
228229
goto out;
229230
}
230231

232+
ret = toml_string_in(mount, "protection_mode", &mount_protection_mode);
233+
if (ret < 0) {
234+
log_error("Cannot parse '%s.key_name'", prefix);
235+
ret = -EINVAL;
236+
goto out;
237+
}
238+
231239
if (!mount_path) {
232240
log_error("No value provided for '%s.path'", prefix);
233241
ret = -EINVAL;
@@ -269,10 +277,11 @@ static int mount_one_nonroot(toml_table_t* mount, const char* prefix) {
269277
}
270278

271279
struct libos_mount_params params = {
272-
.type = mount_type ?: "chroot",
273-
.path = mount_path,
274-
.uri = mount_uri,
275-
.key_name = mount_key_name,
280+
.type = mount_type ?: "chroot",
281+
.path = mount_path,
282+
.uri = mount_uri,
283+
.key_name = mount_key_name,
284+
.protection_mode = mount_protection_mode,
276285
};
277286
ret = mount_fs(&params);
278287

0 commit comments

Comments
 (0)