SGX IPFS: Fix a segfault and support seeking beyond the end of files while using SEEK_CUR/SEEK_END (#1916)

The current implementation throws a segmentation fault when padding
files using a large range, because the writing operation overflows the
source buffer, which was a single char.

IPFS previously assumed that the offset for the seek operation was related
to the start of the file (SEEK_SET). It now correctly checks the parameter
'whence' and computes the offset for SEEK_CUR (middle of the file) and
SEEK_END (end of the file).
This commit is contained in:
Jämes Ménétrey 2023-01-30 01:24:12 +01:00 committed by GitHub
parent 45c003e6e4
commit 0435acdd43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 89 additions and 18 deletions

View File

@ -16,6 +16,11 @@
#define SGX_ERROR_FILE_LOWEST_ERROR_ID SGX_ERROR_FILE_BAD_STATUS
#define SGX_ERROR_FILE_HIGHEST_ERROR_ID SGX_ERROR_FILE_CLOSE_FAILED
// Internal buffer filled with zeroes and used when extending the size of
// protected files.
#define ZEROES_PADDING_LENGTH 32 * 1024
char zeroes_padding[ZEROES_PADDING_LENGTH] = { 0 };
// The mapping between file descriptors and IPFS file pointers.
static HashMap *ipfs_file_list;
@ -78,6 +83,27 @@ ipfs_file_destroy(void *sgx_file)
sgx_fclose(sgx_file);
}
// Writes a given number of zeroes in file at the current offset.
// The return value is zero if successful; otherwise non-zero.
static int
ipfs_write_zeroes(void *sgx_file, size_t len)
{
int min_count;
while (len > 0) {
min_count = len < ZEROES_PADDING_LENGTH ? len : ZEROES_PADDING_LENGTH;
if (sgx_fwrite(zeroes_padding, 1, min_count, sgx_file) == 0) {
errno = convert_sgx_errno(sgx_ferror(sgx_file));
return -1;
}
len -= min_count;
}
return 0;
}
int
ipfs_init()
{
@ -104,7 +130,7 @@ ipfs_posix_fallocate(int fd, off_t offset, size_t len)
// The wrapper for fseek takes care of extending the file if sought beyond
// the end
if (ipfs_lseek(fd, offset + len, SEEK_CUR) == -1) {
if (ipfs_lseek(fd, offset + len, SEEK_SET) == -1) {
return errno;
}
@ -354,7 +380,7 @@ ipfs_fflush(int fd)
off_t
ipfs_lseek(int fd, off_t offset, int nwhence)
{
off_t new_offset;
off_t cursor_current_location;
void *sgx_file = fd2file(fd);
if (!sgx_file) {
errno = EBADF;
@ -364,20 +390,20 @@ ipfs_lseek(int fd, off_t offset, int nwhence)
// Optimization: if the offset is 0 and the whence is SEEK_CUR,
// this is equivalent of a call to ftell.
if (offset == 0 && nwhence == SEEK_CUR) {
int64_t ftell_result = (off_t)sgx_ftell(sgx_file);
cursor_current_location = (off_t)sgx_ftell(sgx_file);
if (ftell_result == -1) {
if (cursor_current_location == -1) {
errno = convert_sgx_errno(sgx_ferror(sgx_file));
return -1;
}
return ftell_result;
return cursor_current_location;
}
int fseek_result = sgx_fseek(sgx_file, offset, nwhence);
if (fseek_result == 0) {
new_offset = (__wasi_filesize_t)sgx_ftell(sgx_file);
off_t new_offset = (off_t)sgx_ftell(sgx_file);
if (new_offset == -1) {
errno = convert_sgx_errno(sgx_ferror(sgx_file));
@ -405,17 +431,39 @@ ipfs_lseek(int fd, off_t offset, int nwhence)
// manually.
// Assume the error is raised because the cursor is moved beyond the end
// of the file. Try to move the cursor at the end of the file.
// of the file.
// If the whence is the current cursor location, retrieve it
if (nwhence == SEEK_CUR) {
cursor_current_location = (off_t)sgx_ftell(sgx_file);
}
// Move the cursor at the end of the file
if (sgx_fseek(sgx_file, 0, SEEK_END) == -1) {
errno = convert_sgx_errno(sgx_ferror(sgx_file));
return -1;
}
// Compute the number of zeroes to append.
int64_t number_of_zeroes;
switch (nwhence) {
case SEEK_SET:
number_of_zeroes = offset - sgx_ftell(sgx_file);
break;
case SEEK_END:
number_of_zeroes = offset;
break;
case SEEK_CUR:
number_of_zeroes =
cursor_current_location + offset - sgx_ftell(sgx_file);
break;
default:
errno = EINVAL;
return -1;
}
// Write the missing zeroes
char zero = 0;
int64_t number_of_zeroes = offset - sgx_ftell(sgx_file);
if (sgx_fwrite(&zero, 1, number_of_zeroes, sgx_file) == 0) {
errno = convert_sgx_errno(sgx_ferror(sgx_file));
if (ipfs_write_zeroes(sgx_file, number_of_zeroes) != 0) {
return -1;
}
@ -468,9 +516,7 @@ ipfs_ftruncate(int fd, off_t len)
// Increasing the size is equal to writing from the end of the file
// with null bytes.
char null_byte = 0;
if (sgx_fwrite(&null_byte, 1, len - file_size, sgx_file) == 0) {
errno = convert_sgx_errno(sgx_ferror(sgx_file));
if (ipfs_write_zeroes(sgx_file, len - file_size) != 0) {
return -1;
}

View File

@ -18,7 +18,7 @@
#define WORLD_OFFSET 7
#define NAME_REPLACMENT "James"
#define NAME_REPLACMENT_LEN (sizeof(NAME_REPLACMENT) - 1)
#define ADDITIONAL_SPACE 10
#define ADDITIONAL_SPACE 1 * 1024 * 1024
int
main(int argc, char **argv)
@ -100,7 +100,7 @@ main(int argc, char **argv)
printf("[Test] Reading at specified offset passed.\n");
// Test: allocate more space to the file (posix_fallocate)
printf("Allocate more space to the file..\n");
printf("Allocate more space to the file (posix_fallocate)..\n");
posix_fallocate(fileno(file), ftell(file), ADDITIONAL_SPACE);
printf("File current offset: %ld\n", ftell(file));
printf("Moving to the end..\n");
@ -110,8 +110,8 @@ main(int argc, char **argv)
printf("[Test] Allocation or more space passed.\n");
// Test: allocate more space to the file (ftruncate)
printf("Extend the file size of 10 bytes using ftruncate..\n");
ftruncate(fileno(file), ftell(file) + 10);
printf("Allocate more space to the file (ftruncate)..\n");
ftruncate(fileno(file), ftell(file) + ADDITIONAL_SPACE);
assert(ftell(file) == strlen(text) + ADDITIONAL_SPACE);
printf("File current offset: %ld\n", ftell(file));
printf("Moving to the end..\n");
@ -120,6 +120,31 @@ main(int argc, char **argv)
assert(ftell(file) == strlen(text) + 2 * ADDITIONAL_SPACE);
printf("[Test] Extension of the file size passed.\n");
// Test: allocate more space to the file (fseek)
printf("Allocate more space to the file (fseek) from the start..\n");
printf("File current offset: %ld\n", ftell(file));
fseek(file, 3 * ADDITIONAL_SPACE, SEEK_SET);
printf("File current offset: %ld\n", ftell(file));
assert(ftell(file) == 3 * ADDITIONAL_SPACE);
printf("[Test] Extension of the file size passed.\n");
// Test: allocate more space to the file (fseek)
printf("Allocate more space to the file (fseek) from the end..\n");
printf("File current offset: %ld\n", ftell(file));
fseek(file, ADDITIONAL_SPACE, SEEK_END);
printf("File current offset: %ld\n", ftell(file));
assert(ftell(file) == 4 * ADDITIONAL_SPACE);
printf("[Test] Extension of the file size passed.\n");
// Test: allocate more space to the file (fseek)
printf("Allocate more space to the file (fseek) from the middle..\n");
fseek(file, 3 * ADDITIONAL_SPACE, SEEK_SET);
printf("File current offset: %ld\n", ftell(file));
fseek(file, 2 * ADDITIONAL_SPACE, SEEK_CUR);
printf("File current offset: %ld\n", ftell(file));
assert(ftell(file) == 5 * ADDITIONAL_SPACE);
printf("[Test] Extension of the file size passed.\n");
// Display some debug information
printf("Getting the size of the file on disk..\n");
struct stat st;