Skip to content

Commit 6193a19

Browse files
committed
fixup! Single-process-lifetime rollback protection for protected files (WIP)
Signed-off-by: g2flyer <[email protected]>
1 parent bbeb3e7 commit 6193a19

File tree

4 files changed

+130
-67
lines changed

4 files changed

+130
-67
lines changed

common/src/protected_files/protected_files.c

+8-7
Original file line numberDiff line numberDiff line change
@@ -1133,7 +1133,7 @@ static void ipf_delete_cache(pf_context_t* pf) {
11331133
}
11341134
}
11351135

1136-
static bool ipf_close(pf_context_t* pf) {
1136+
static bool ipf_close(pf_context_t* pf, pf_mac_t* closing_root_gmac) {
11371137
bool retval = true;
11381138

11391139
if (pf->file_status != PF_STATUS_SUCCESS) {
@@ -1146,6 +1146,10 @@ static bool ipf_close(pf_context_t* pf) {
11461146
}
11471147
}
11481148

1149+
if (closing_root_gmac != NULL) {
1150+
memcpy(*closing_root_gmac, pf->file_metadata.plain_part.metadata_gmac, sizeof(pf_mac_t));
1151+
}
1152+
11491153
// omeg: fs close is done by Gramine handler
11501154
pf->file_status = PF_STATUS_UNINITIALIZED;
11511155

@@ -1192,7 +1196,7 @@ pf_status_t pf_open(pf_handle_t handle, const char* path, uint64_t underlying_si
11921196
pf_status_t status;
11931197
*context = ipf_open(path, mode, create, handle, underlying_size, key, &status);
11941198
if (opening_root_gmac != NULL) {
1195-
memcpy(opening_root_gmac, (*context)->file_metadata.plain_part.metadata_gmac,
1199+
memcpy(*opening_root_gmac, (*context)->file_metadata.plain_part.metadata_gmac,
11961200
sizeof(pf_mac_t));
11971201
}
11981202
return status;
@@ -1202,13 +1206,10 @@ pf_status_t pf_close(pf_context_t* pf, pf_mac_t* closing_root_gmac) {
12021206
if (!g_initialized)
12031207
return PF_STATUS_UNINITIALIZED;
12041208

1205-
if (ipf_close(pf)) {
1209+
if (ipf_close(pf, closing_root_gmac)) {
12061210
free(pf);
12071211
return PF_STATUS_SUCCESS;
12081212
}
1209-
if (closing_root_gmac != NULL) {
1210-
memcpy(closing_root_gmac, pf->file_metadata.plain_part.metadata_gmac, sizeof(pf_mac_t));
1211-
}
12121213

12131214
pf_status_t ret = pf->last_error;
12141215
free(pf);
@@ -1292,7 +1293,7 @@ pf_status_t pf_rename(pf_context_t* pf, const char* new_path, pf_mac_t* new_root
12921293
if (!ipf_internal_flush(pf))
12931294
return pf->last_error;
12941295
if (new_root_gmac != NULL) {
1295-
memcpy(new_root_gmac, pf->file_metadata.plain_part.metadata_gmac, sizeof(pf_mac_t));
1296+
memcpy(*new_root_gmac, pf->file_metadata.plain_part.metadata_gmac, sizeof(pf_mac_t));
12961297
}
12971298

12981299
return PF_STATUS_SUCCESS;

common/src/protected_files/protected_files.h

+5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ typedef uint8_t pf_mac_t[PF_MAC_SIZE];
2626
typedef uint8_t pf_key_t[PF_KEY_SIZE];
2727
typedef uint8_t pf_keyid_t[32]; /* key derivation material */
2828

29+
// convenience macros to print out some mac fingerprint: printf( "some text " MAC_PRINTF_PATTERN "
30+
// yet other text", MAC_PRINTF_ARGS(mac) );
31+
#define MAC_PRINTF_PATTERN "0x%02x%02x%02x%02x..."
32+
#define MAC_PRINTF_ARGS(mac) (mac)[0], (mac)[1], (mac)[2], (mac)[3]
33+
2934
typedef enum _pf_status_t {
3035
PF_STATUS_SUCCESS = 0,
3136
PF_STATUS_UNKNOWN_ERROR = -1,

libos/include/libos_fs_encrypted.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ typedef enum {
4848
* them before and what the last seen root-hash is. This is necessary to provide rollback
4949
*/
5050
struct libos_encrypted_volume_state_map {
51-
char* uri; // assumptions: all paths canonicalized, symlinks are resolved & no hard links
51+
char* norm_path; // assumptions: all paths canonicalized, symlinks are resolved & no hard links
5252
libos_encrypted_file_state_t state;
5353
pf_mac_t last_seen_root_gmac;
5454
UT_hash_handle hh;
@@ -79,6 +79,7 @@ struct libos_encrypted_volume {
7979
struct libos_encrypted_file {
8080
size_t use_count;
8181
char* uri;
82+
char* norm_path; // normalized path of of uri
8283
struct libos_encrypted_volume* volume;
8384

8485
/* `pf` and `pal_handle` are non-null as long as `use_count` is greater than 0 */

libos/src/fs/libos_fs_encrypted.c

+115-59
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,6 @@ static int encrypted_file_internal_open(struct libos_encrypted_file* enc, PAL_HA
164164
assert(!enc->pf);
165165

166166
int ret;
167-
char* normpath = NULL;
168167

169168
if (!pal_handle) {
170169
enum pal_create_mode create_mode = create ? PAL_CREATE_ALWAYS : PAL_CREATE_NEVER;
@@ -185,21 +184,6 @@ static int encrypted_file_internal_open(struct libos_encrypted_file* enc, PAL_HA
185184
}
186185
size_t size = pal_attr.pending_size;
187186

188-
assert(strstartswith(enc->uri, URI_PREFIX_FILE));
189-
const char* path = enc->uri + static_strlen(URI_PREFIX_FILE);
190-
191-
size_t normpath_size = strlen(path) + 1;
192-
normpath = malloc(normpath_size);
193-
if (!normpath) {
194-
ret = -ENOMEM;
195-
goto out;
196-
}
197-
198-
if (!get_norm_path(path, normpath, &normpath_size)) {
199-
ret = -EINVAL;
200-
goto out;
201-
}
202-
203187
pf_context_t* pf;
204188
lock(&g_keys_lock);
205189
if (!enc->volume->key->is_set) {
@@ -209,8 +193,9 @@ static int encrypted_file_internal_open(struct libos_encrypted_file* enc, PAL_HA
209193
goto out;
210194
}
211195
pf_mac_t opening_root_gmac;
212-
pf_status_t pfs = pf_open(pal_handle, normpath, size, PF_FILE_MODE_READ | PF_FILE_MODE_WRITE,
213-
create, &enc->volume->key->pf_key, &opening_root_gmac, &pf);
196+
pf_status_t pfs =
197+
pf_open(pal_handle, enc->norm_path, size, PF_FILE_MODE_READ | PF_FILE_MODE_WRITE, create,
198+
&enc->volume->key->pf_key, &opening_root_gmac, &pf);
214199
unlock(&g_keys_lock);
215200
if (PF_FAILURE(pfs)) {
216201
log_warning("pf_open failed: %s", pf_strerror(pfs));
@@ -219,17 +204,26 @@ static int encrypted_file_internal_open(struct libos_encrypted_file* enc, PAL_HA
219204
}
220205
// rollback protection
221206
struct libos_encrypted_volume_state_map* file_state = NULL;
207+
log_debug("file '%s' opened with MAC=" MAC_PRINTF_PATTERN, enc->norm_path,
208+
MAC_PRINTF_ARGS(opening_root_gmac)); // TODO (MST): remove me eventually?
222209
lock(&(enc->volume->files_state_map_lock));
223210
// - check current state
224211
if ((!create) && (enc->volume->protection_mode != PF_ENCLAVE_LIFE_RB_PROTECTION_NONE)) {
225-
HASH_FIND_STR(enc->volume->files_state_map, normpath, file_state);
212+
HASH_FIND_STR(enc->volume->files_state_map, enc->norm_path, file_state);
226213
if (file_state) {
227-
if ((file_state->state != PF_FILE_CLOSED) ||
228-
(memcmp(file_state->last_seen_root_gmac, opening_root_gmac, sizeof(pf_mac_t)) !=
229-
0)) {
214+
/* TODO (MST): figure out what to test. Seems our test-cases, e.g., in open_close do
215+
* allow for scenarios such as two concurrent open writeable fds for same file which i
216+
* thought would be illegal
217+
* (file_state->state != PF_FILE_CLOSED) ||
218+
*/
219+
if (memcmp(file_state->last_seen_root_gmac, opening_root_gmac, sizeof(pf_mac_t)) != 0) {
230220
log_warning(
231-
"file '%s' was seen before but in different inconsistent (rolled-back?) state",
232-
normpath);
221+
"file '%s' was seen before but in different inconsistent (rolled-back?) "
222+
"state, expected MAC=" MAC_PRINTF_PATTERN
223+
" but file had "
224+
"MAC=" MAC_PRINTF_PATTERN,
225+
enc->norm_path, MAC_PRINTF_ARGS(file_state->last_seen_root_gmac),
226+
MAC_PRINTF_ARGS(opening_root_gmac));
233227
pf_set_corrupted(pf);
234228
ret = -EACCES;
235229
goto out_unlock_map;
@@ -238,24 +232,24 @@ static int encrypted_file_internal_open(struct libos_encrypted_file* enc, PAL_HA
238232
if (enc->volume->protection_mode == PF_ENCLAVE_LIFE_RB_PROTECTION_STRICT) {
239233
log_warning(
240234
"file '%s' was not seen before, not allowing strict rollback protection",
241-
normpath);
235+
enc->norm_path);
242236
pf_set_corrupted(pf);
243237
ret = -EACCES;
244238
goto out_unlock_map;
245239
}
246240
}
247241
}
248242
// - uodate map with new state
249-
if (!file_state) {
243+
if (file_state == NULL) {
250244
file_state = malloc(sizeof(struct libos_encrypted_volume_state_map));
251-
if (!file_state) {
245+
if (file_state == NULL) {
252246
ret = -ENOMEM;
253247
goto out_unlock_map;
254248
}
255-
file_state->uri = normpath;
249+
file_state->norm_path = enc->norm_path;
256250
memcpy(file_state->last_seen_root_gmac, opening_root_gmac, sizeof(pf_mac_t));
257-
HASH_ADD_KEYPTR(hh, enc->volume->files_state_map, file_state->uri, strlen(file_state->uri),
258-
file_state);
251+
HASH_ADD_KEYPTR(hh, enc->volume->files_state_map, file_state->norm_path,
252+
strlen(file_state->norm_path), file_state);
259253
}
260254
file_state->state = (create ? PF_FILE_IN_USE_NEW : PF_FILE_IN_USE_EXISTING);
261255

@@ -267,7 +261,6 @@ static int encrypted_file_internal_open(struct libos_encrypted_file* enc, PAL_HA
267261
unlock(&(enc->volume->files_state_map_lock));
268262
out:
269263
if (ret < 0) {
270-
free(normpath);
271264
PalObjectDestroy(pal_handle);
272265
}
273266
return ret;
@@ -296,10 +289,12 @@ static void encrypted_file_internal_close(struct libos_encrypted_file* enc) {
296289

297290
pf_mac_t closing_root_gmac;
298291
pf_status_t pfs = pf_close(enc->pf, &closing_root_gmac);
299-
struct libos_encrypted_volume_state_map* file_state = NULL;
292+
log_debug("file '%s' closed with MAC=" MAC_PRINTF_PATTERN, enc->norm_path,
293+
MAC_PRINTF_ARGS(closing_root_gmac)); // TODO (MST): remove me eventually?
300294
lock(&(enc->volume->files_state_map_lock));
301-
HASH_FIND_STR(enc->volume->files_state_map, enc->uri, file_state);
302-
// TODO (MST): error handling if filestate is not found
295+
struct libos_encrypted_volume_state_map* file_state = NULL;
296+
HASH_FIND_STR(enc->volume->files_state_map, enc->norm_path, file_state);
297+
assert(file_state != NULL);
303298
if (PF_FAILURE(pfs)) {
304299
log_warning("pf_close failed: %s", pf_strerror(pfs));
305300
file_state->state = PF_FILE_ERROR;
@@ -515,17 +510,47 @@ static int encrypted_file_alloc(const char* uri, struct libos_encrypted_volume*
515510
if (!enc)
516511
return -ENOMEM;
517512

513+
int ret;
514+
enc->uri = NULL;
515+
enc->norm_path = NULL;
516+
518517
enc->uri = strdup(uri);
519518
if (!enc->uri) {
520-
free(enc);
521-
return -ENOMEM;
519+
ret = -ENOMEM;
520+
goto err;
522521
}
522+
523+
assert(strstartswith(enc->uri, URI_PREFIX_FILE));
524+
const char* path = enc->uri + static_strlen(URI_PREFIX_FILE);
525+
526+
size_t norm_path_size = strlen(path) + 1;
527+
enc->norm_path = malloc(norm_path_size);
528+
if (!enc->norm_path) {
529+
ret = -ENOMEM;
530+
goto err;
531+
}
532+
533+
if (!get_norm_path(path, enc->norm_path, &norm_path_size)) {
534+
ret = -EINVAL;
535+
goto err;
536+
}
537+
523538
enc->volume = volume;
524539
enc->use_count = 0;
525540
enc->pf = NULL;
526541
enc->pal_handle = NULL;
527542
*out_enc = enc;
528543
return 0;
544+
545+
err:
546+
if (enc) {
547+
if (enc->uri)
548+
free(enc->uri);
549+
if (enc->norm_path)
550+
free(enc->norm_path);
551+
free(enc);
552+
}
553+
return ret;
529554
}
530555

531556
int encrypted_file_open(const char* uri, struct libos_encrypted_volume* volume,
@@ -568,6 +593,7 @@ void encrypted_file_destroy(struct libos_encrypted_file* enc) {
568593
assert(!enc->pf);
569594
assert(!enc->pal_handle);
570595
free(enc->uri);
596+
// do _not_ free enc->norm_path as this is still used in file_state_map!
571597
free(enc);
572598
}
573599

@@ -679,32 +705,30 @@ int encrypted_file_rename(struct libos_encrypted_file* enc, const char* new_uri)
679705
assert(enc->pf);
680706

681707
int ret;
682-
char* new_normpath = NULL;
708+
char* new_norm_path = NULL;
709+
char* old_norm_path = enc->norm_path;
683710

684711
char* new_uri_copy = strdup(new_uri);
685712
if (!new_uri_copy)
686713
return -ENOMEM;
687714

688-
assert(strstartswith(enc->uri, URI_PREFIX_FILE));
689-
const char* old_path = enc->uri + static_strlen(URI_PREFIX_FILE);
690-
691715
assert(strstartswith(new_uri, URI_PREFIX_FILE));
692716
const char* new_path = new_uri + static_strlen(URI_PREFIX_FILE);
693717

694-
size_t new_normpath_size = strlen(new_path) + 1;
695-
new_normpath = malloc(new_normpath_size);
696-
if (!new_normpath) {
718+
size_t new_norm_path_size = strlen(new_path) + 1;
719+
new_norm_path = malloc(new_norm_path_size);
720+
if (!new_norm_path) {
697721
ret = -ENOMEM;
698722
goto out;
699723
}
700724

701-
if (!get_norm_path(new_path, new_normpath, &new_normpath_size)) {
725+
if (!get_norm_path(new_path, new_norm_path, &new_norm_path_size)) {
702726
ret = -EINVAL;
703727
goto out;
704728
}
705729

706730
pf_mac_t new_root_gmac;
707-
pf_status_t pfs = pf_rename(enc->pf, new_normpath, &new_root_gmac);
731+
pf_status_t pfs = pf_rename(enc->pf, new_norm_path, &new_root_gmac);
708732
if (PF_FAILURE(pfs)) {
709733
log_warning("pf_rename failed: %s", pf_strerror(pfs));
710734
ret = -EACCES;
@@ -716,33 +740,65 @@ int encrypted_file_rename(struct libos_encrypted_file* enc, const char* new_uri)
716740
log_warning("PalStreamChangeName failed: %s", pal_strerror(ret));
717741

718742
/* We failed to rename the file. Try to restore the name in header. */
719-
pfs = pf_rename(enc->pf, old_path, &new_root_gmac);
743+
pfs = pf_rename(enc->pf, old_norm_path, &new_root_gmac);
720744
if (PF_FAILURE(pfs)) {
721745
log_warning("pf_rename (during cleanup) failed, the file might be unusable: %s",
722746
pf_strerror(pfs));
723747
}
724-
748+
old_norm_path = NULL; // don't free it later ...
725749
ret = pal_to_unix_errno(ret);
726750
goto out;
727751
}
728-
// TODO (MST): everything worked fine, so
729-
// - get state for old_path
730-
// abort if it doesn't exist and we are in strict protection_mode
731-
// - add new_path together with new_root_gmac and copy state from old_path entry (should be
732-
// either PF_FILE_IN_USE_EXISTING, PF_FILE_IN_USE_NEW or PF_FILE_CLOSED)
733-
// - remove old_path from map & set its state to PF_FILE_DELETED.
752+
log_debug("file '%s' renamed to '%s' with MAC=" MAC_PRINTF_PATTERN, old_norm_path,
753+
new_norm_path,
754+
MAC_PRINTF_ARGS(new_root_gmac)); // TODO (MST): remove me eventually?
755+
lock(&(enc->volume->files_state_map_lock));
756+
struct libos_encrypted_volume_state_map* old_file_state = NULL;
757+
HASH_FIND_STR(enc->volume->files_state_map, old_norm_path, old_file_state);
758+
assert(old_file_state != NULL);
759+
struct libos_encrypted_volume_state_map* new_file_state = NULL;
760+
HASH_FIND_STR(enc->volume->files_state_map, new_norm_path, new_file_state);
761+
if (new_file_state == NULL) {
762+
new_file_state = malloc(sizeof(struct libos_encrypted_volume_state_map));
763+
if (new_file_state == NULL) {
764+
ret = -ENOMEM;
765+
goto out;
766+
}
767+
new_file_state->norm_path = new_norm_path;
768+
HASH_ADD_KEYPTR(hh, enc->volume->files_state_map, new_file_state->norm_path,
769+
strlen(new_file_state->norm_path), new_file_state);
770+
} else {
771+
free(new_file_state->norm_path); // should be same but free old one to simplify below
772+
new_file_state->norm_path = new_norm_path;
773+
}
774+
new_file_state->state = old_file_state->state;
775+
memcpy(new_file_state->last_seen_root_gmac, new_root_gmac, sizeof(pf_mac_t));
776+
old_file_state->state = PF_FILE_DELETED;
777+
memset(old_file_state->last_seen_root_gmac, 0, sizeof(pf_mac_t));
778+
unlock(&(enc->volume->files_state_map_lock));
734779

735780
free(enc->uri);
736-
enc->uri = new_uri_copy;
781+
enc->uri = new_uri_copy;
737782
new_uri_copy = NULL;
783+
enc->norm_path = new_norm_path;
784+
new_norm_path = NULL;
785+
738786
ret = 0;
739787

740788
out:
741-
// TODO (MST): in case of error
742-
// - set state for old_path to PF_FILE_ERROR (even when restore rename worked? or just update
743-
// hash in that case?) Also correspondingly set pf->file_status =
744-
// PF_STATUS_CORRUPTED?)
745-
free(new_normpath);
789+
if (ret) {
790+
// store in file state map fact that we could not rename file properly
791+
if (!locked(&(enc->volume->files_state_map_lock))) // for OOM case from above!
792+
lock(&(enc->volume->files_state_map_lock));
793+
if (old_file_state == NULL) // we might already have it!
794+
HASH_FIND_STR(enc->volume->files_state_map, old_norm_path, old_file_state);
795+
assert(old_file_state != NULL);
796+
old_file_state->state = PF_FILE_ERROR;
797+
pf_set_corrupted(enc->pf);
798+
unlock(&(enc->volume->files_state_map_lock));
799+
}
800+
free(old_norm_path);
801+
free(new_norm_path);
746802
free(new_uri_copy);
747803
return ret;
748804
}

0 commit comments

Comments
 (0)