Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] [libOS] Single Process lifetime rollback protection for Protected Files #1856

Draft
wants to merge 22 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
314533d
[LibOS] Remove unused function
g2flyer Jul 2, 2024
90e907d
[LibOS] Missing lock around dentry->inode derefences
g2flyer Jul 2, 2024
a0b4832
[LibOS] Protect handle->dentry with handle->lock
g2flyer May 6, 2024
166ba45
[LibOS] Fix dentry of open files after rename
g2flyer Jul 3, 2024
a43d048
Make pytest debugging a bit more user-friendly
g2flyer Aug 22, 2024
da09629
Fix pf_tamper testing
g2flyer Aug 22, 2024
12279f9
[LibOS] Consolidate path normalization and fix missing one
g2flyer May 20, 2024
69b3edc
[LibOS] Allow run_gdb optionally exposing tty to debug scripts
g2flyer Jun 11, 2024
549e415
[LibOS] Single-process-lifetime rollback protection for protected fil…
g2flyer Apr 11, 2024
e577866
[LibOS] Test-cases for SPLRB (1)
g2flyer May 28, 2024
ac5302b
[LibOS] Test-cases for SPLRB (2)
g2flyer May 31, 2024
9ced55f
fixup! [LibOS] Single-process-lifetime rollback protection for protec…
g2flyer Jun 18, 2024
bd8006e
fixup! [LibOS] Test-cases for SPLRB (2)
g2flyer Jun 18, 2024
980835e
WIP: rollback status introspection
g2flyer Jul 1, 2024
5c4f384
fixup! [LibOS] Single-process-lifetime rollback protection for protec…
g2flyer Jul 9, 2024
b5ea57a
[LibOS] Updates to encrypted files
g2flyer Aug 15, 2024
7687328
[LibOS] Make handling of corruption more consistent (WIP)
g2flyer Aug 22, 2024
d850657
Missing mbedtls errors and more sane PAL-PF error mapping
g2flyer Aug 26, 2024
f15133b
fixup! [LibOS] Make handling of corruption more consistent (WIP)
g2flyer Aug 26, 2024
62543cd
fixup! [LibOS] Make handling of corruption more consistent (WIP)
g2flyer Aug 26, 2024
977e999
fixup! [LibOS] Make handling of corruption more consistent (WIP)
g2flyer Aug 27, 2024
ce2ad18
fixup! [LibOS] Make handling of corruption more consistent (WIP)
Aug 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions common/src/crypto/adapters/mbedtls_adapter.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ static int mbedtls_to_pal_error(int error) {

case MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH:
case MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED:
case MBEDTLS_ERR_GCM_BUFFER_TOO_SMALL:
return PAL_ERROR_CRYPTO_INVALID_INPUT_LENGTH;

case MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE:
Expand All @@ -52,6 +53,8 @@ static int mbedtls_to_pal_error(int error) {
case MBEDTLS_ERR_RSA_PUBLIC_FAILED: // see mbedtls_rsa_public()
case MBEDTLS_ERR_RSA_PRIVATE_FAILED: // see mbedtls_rsa_private()
case MBEDTLS_ERR_ECP_BAD_INPUT_DATA:
case MBEDTLS_ERR_GCM_BAD_INPUT:
case MBEDTLS_ERR_SHA256_BAD_INPUT_DATA:
return PAL_ERROR_CRYPTO_BAD_INPUT_DATA;

case MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE:
Expand All @@ -71,6 +74,7 @@ static int mbedtls_to_pal_error(int error) {
return PAL_ERROR_CRYPTO_INVALID_PADDING;

case MBEDTLS_ERR_CIPHER_AUTH_FAILED:
case MBEDTLS_ERR_GCM_AUTH_FAILED:
return PAL_ERROR_CRYPTO_AUTH_FAILED;

case MBEDTLS_ERR_CIPHER_INVALID_CONTEXT:
Expand Down
55 changes: 48 additions & 7 deletions common/src/protected_files/protected_files.c
Original file line number Diff line number Diff line change
Expand Up @@ -643,8 +643,10 @@ static file_node_t* ipf_read_data_node(pf_context_t* pf, uint64_t offset) {
if (PF_FAILURE(status)) {
free(file_data_node);
pf->last_error = status;
if (status == PF_STATUS_MAC_MISMATCH)
if (status == PF_STATUS_MAC_MISMATCH) {
pf->file_status = PF_STATUS_CORRUPTED;
pf->last_error = PF_STATUS_CORRUPTED;
}
return NULL;
}

Expand Down Expand Up @@ -706,8 +708,10 @@ static file_node_t* ipf_read_mht_node(pf_context_t* pf, uint64_t logical_mht_nod
if (PF_FAILURE(status)) {
free(file_mht_node);
pf->last_error = status;
if (status == PF_STATUS_MAC_MISMATCH)
if (status == PF_STATUS_MAC_MISMATCH) {
pf->file_status = PF_STATUS_CORRUPTED;
pf->last_error = PF_STATUS_CORRUPTED;
}
return NULL;
}

Expand Down Expand Up @@ -791,6 +795,11 @@ static bool ipf_init_existing_file(pf_context_t* pf, const char* path) {
if (PF_FAILURE(status)) {
pf->last_error = status;
DEBUG_PF("failed to decrypt metadata: %d", status);
if (status == PF_STATUS_MAC_MISMATCH) {
// MAC could also mismatch if wrong key was provided but we err on side of safety ...
pf->file_status = PF_STATUS_CORRUPTED;
pf->last_error = PF_STATUS_CORRUPTED;
}
return false;
}

Expand Down Expand Up @@ -818,6 +827,10 @@ static bool ipf_init_existing_file(pf_context_t* pf, const char* path) {
&pf->metadata_decrypted.root_mht_node_mac);
if (PF_FAILURE(status)) {
pf->last_error = status;
if (status == PF_STATUS_MAC_MISMATCH) {
pf->file_status = PF_STATUS_CORRUPTED;
pf->last_error = PF_STATUS_CORRUPTED;
}
return false;
}
}
Expand Down Expand Up @@ -1076,7 +1089,7 @@ static void ipf_delete_cache(pf_context_t* pf) {
}
}

static bool ipf_close(pf_context_t* pf) {
static bool ipf_close(pf_context_t* pf, pf_mac_t* closing_root_mac) {
bool retval = true;

if (pf->file_status != PF_STATUS_SUCCESS) {
Expand All @@ -1089,6 +1102,10 @@ static bool ipf_close(pf_context_t* pf) {
}
}

if (closing_root_mac != NULL) {
memcpy(*closing_root_mac, pf->metadata_node.plaintext_part.metadata_mac, sizeof(pf_mac_t));
}

// omeg: fs close is done by Gramine handler
pf->file_status = PF_STATUS_UNINITIALIZED;

Expand Down Expand Up @@ -1126,20 +1143,25 @@ void pf_set_callbacks(pf_read_f read_f, pf_write_f write_f, pf_fsync_f fsync_f,
}

pf_status_t pf_open(pf_handle_t handle, const char* path, uint64_t underlying_size,
pf_file_mode_t mode, bool create, const pf_key_t* key, pf_context_t** context) {
pf_file_mode_t mode, bool create, const pf_key_t* key,
pf_mac_t* opening_root_mac, pf_context_t** context) {
if (!g_initialized)
return PF_STATUS_UNINITIALIZED;

pf_status_t status;
*context = ipf_open(path, mode, create, handle, underlying_size, key, &status);
if ((*context != NULL) && (opening_root_mac != NULL)) {
memcpy(*opening_root_mac, (*context)->metadata_node.plaintext_part.metadata_mac,
sizeof(pf_mac_t));
}
return status;
}

pf_status_t pf_close(pf_context_t* pf) {
pf_status_t pf_close(pf_context_t* pf, pf_mac_t* closing_root_mac) {
if (!g_initialized)
return PF_STATUS_UNINITIALIZED;

if (ipf_close(pf)) {
if (ipf_close(pf, closing_root_mac)) {
free(pf);
return PF_STATUS_SUCCESS;
}
Expand All @@ -1153,6 +1175,9 @@ pf_status_t pf_get_size(pf_context_t* pf, uint64_t* size) {
if (!g_initialized)
return PF_STATUS_UNINITIALIZED;

if (pf->file_status == PF_STATUS_CORRUPTED)
return pf->file_status; // Make corruption "sticky"

*size = pf->metadata_decrypted.file_size;
return PF_STATUS_SUCCESS;
}
Expand All @@ -1164,6 +1189,9 @@ pf_status_t pf_set_size(pf_context_t* pf, uint64_t size) {
if (!(pf->mode & PF_FILE_MODE_WRITE))
return PF_STATUS_INVALID_MODE;

if (pf->file_status == PF_STATUS_CORRUPTED)
return pf->file_status; // Make corruption "sticky"

if (size == pf->metadata_decrypted.file_size)
return PF_STATUS_SUCCESS;

Expand Down Expand Up @@ -1208,10 +1236,13 @@ pf_status_t pf_set_size(pf_context_t* pf, uint64_t size) {
return PF_STATUS_SUCCESS;
}

pf_status_t pf_rename(pf_context_t* pf, const char* new_path) {
pf_status_t pf_rename(pf_context_t* pf, const char* new_path, pf_mac_t* new_root_mac) {
if (!g_initialized)
return PF_STATUS_UNINITIALIZED;

if (pf->file_status == PF_STATUS_CORRUPTED)
return pf->file_status; // Make corruption "sticky"

if (!(pf->mode & PF_FILE_MODE_WRITE))
return PF_STATUS_INVALID_MODE;

Expand All @@ -1224,6 +1255,9 @@ pf_status_t pf_rename(pf_context_t* pf, const char* new_path) {
pf->need_writing = true;
if (!ipf_internal_flush(pf))
return pf->last_error;
if (new_root_mac != NULL) {
memcpy(*new_root_mac, pf->metadata_node.plaintext_part.metadata_mac, sizeof(pf_mac_t));
}

return PF_STATUS_SUCCESS;
}
Expand Down Expand Up @@ -1281,6 +1315,9 @@ pf_status_t pf_flush(pf_context_t* pf) {
if (!g_initialized)
return PF_STATUS_UNINITIALIZED;

if (pf->file_status == PF_STATUS_CORRUPTED)
return pf->file_status; // Make corruption "sticky"

if (!ipf_internal_flush(pf))
return pf->last_error;

Expand All @@ -1297,3 +1334,7 @@ pf_status_t pf_flush(pf_context_t* pf) {

return PF_STATUS_SUCCESS;
}

void pf_set_corrupted(pf_context_t* pf) {
pf->file_status = PF_STATUS_CORRUPTED;
}
44 changes: 30 additions & 14 deletions common/src/protected_files/protected_files.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ typedef uint8_t pf_mac_t[PF_MAC_SIZE];
typedef uint8_t pf_key_t[PF_KEY_SIZE];
typedef uint8_t pf_nonce_t[PF_NONCE_SIZE];

// convenience macros to print out some mac fingerprint: printf( "some text " MAC_PRINTF_PATTERN "
// yet other text", MAC_PRINTF_ARGS(mac) );
#define MAC_PRINTF_PATTERN "0x%02x%02x%02x%02x..."
#define MAC_PRINTF_ARGS(mac) (mac)[0], (mac)[1], (mac)[2], (mac)[3]

typedef enum _pf_status_t {
PF_STATUS_SUCCESS = 0,
PF_STATUS_UNKNOWN_ERROR = -1,
Expand Down Expand Up @@ -212,28 +217,31 @@ const char* pf_strerror(int err);
/*!
* \brief Open a protected file.
*
* \param handle Open underlying file handle.
* \param path Path to the file. If NULL and \p create is false, don't check path
* for validity.
* \param underlying_size Underlying file size.
* \param mode Access mode.
* \param create Overwrite file contents if true.
* \param key Wrap key.
* \param[out] context PF context for later calls.
* \param handle Open underlying file handle.
* \param path Path to the file. If NULL and \p create is false, don't check path
* for validity.
* \param underlying_size Underlying file size.
* \param mode Access mode.
* \param create Overwrite file contents if true.
* \param key Wrap key.
* \param opening_root_mac If non-NULL, !create & successfull open, returns root-hash of file
* \param[out] context PF context for later calls.
*
* \returns PF status.
*/
pf_status_t pf_open(pf_handle_t handle, const char* path, uint64_t underlying_size,
pf_file_mode_t mode, bool create, const pf_key_t* key, pf_context_t** context);
pf_file_mode_t mode, bool create, const pf_key_t* key,
pf_mac_t* opening_root_mac, pf_context_t** context);

/*!
* \brief Close a protected file and commit all changes to disk.
*
* \param pf PF context.
* \param pf PF context.
* \param closing_root_mac If non-NULL, returns root-hash of file at closing time
*
* \returns PF status.
*/
pf_status_t pf_close(pf_context_t* pf);
pf_status_t pf_close(pf_context_t* pf, pf_mac_t* closing_root_mac);

/*!
* \brief Read from a protected file.
Expand Down Expand Up @@ -286,13 +294,14 @@ pf_status_t pf_set_size(pf_context_t* pf, uint64_t size);
/*!
* \brief Rename a PF.
*
* \param pf PF context.
* \param new_path New file path.
* \param pf PF context.
* \param new_path New file path.
* \param new_root_mac if non-NULL, returns new root-hash of file
*
* Updates the path inside protected file header, and flushes all changes. The caller is responsible
* for renaming the underlying file.
*/
pf_status_t pf_rename(pf_context_t* pf, const char* new_path);
pf_status_t pf_rename(pf_context_t* pf, const char* new_path, pf_mac_t* new_root_mac);

/*!
* \brief Flush any pending data of a protected file to disk.
Expand All @@ -302,3 +311,10 @@ pf_status_t pf_rename(pf_context_t* pf, const char* new_path);
* \returns PF status.
*/
pf_status_t pf_flush(pf_context_t* pf);

/*!
* \brief Set protected file state as corrupted
*
* \param pf PF context.
*/
void pf_set_corrupted(pf_context_t* pf);
3 changes: 3 additions & 0 deletions libos/include/libos_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ struct libos_mount_params {

/* Key name (used by `chroot_encrypted` filesystem), or NULL if not applicable */
const char* key_name;

/* Enforcement type (used by `chroot_encrypted` filesystem), or NULL if not applicable */
const char* protection_mode;
};

struct libos_fs_ops {
Expand Down
Loading