diff options
author | Jens Wiklander <jens.wiklander@linaro.org> | 2020-09-04 09:29:34 +0200 |
---|---|---|
committer | Jérôme Forissier <jerome@forissier.org> | 2020-09-04 17:29:41 +0200 |
commit | 4f3d4cbb7824bab8f5c0a445f301528a53142f6b (patch) | |
tree | 11842316f3ca5cbf8cadf8d01cb9b7641b9fccdd | |
parent | e7a4706e08c8fbdd53530868a6ac4937193dd73c (diff) | |
download | optee_client-4f3d4cbb7824bab8f5c0a445f301528a53142f6b.tar.gz |
libteec: fix TEEC_RegisterSharedMemory() with a fallback option
Adds a fallback option to TEEC_RegisterSharedMemory() where
TEE_IOC_SHM_REGISTER fails, likely due to the caller supplying read-only
memory. Instead of failing and burden the caller to handle this,
implement it here instead. If TEE_IOC_SHM_REGISTER fails, malloc() a
buffer and register that as a shadow buffer instead.
The size of the TEEC_SharedMemory is kept unchanged, but the last field
bool buffer_allocated is replaced with a union of the same size but with
a flags field which will be used instead. This allows keeping track of
two internal flags, SHM_FLAG_BUFFER_ALLOCED and
SHM_FLAG_SHADOW_BUFFER_ALLOCED while avoiding changing the ABI. There
are a few bits left for future use.
Reviewed-by: Etienne Carriere <etienne.carriere@linaro.org>
Reviewed-by: Jerome Forissier <jerome@forissier.org>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
-rw-r--r-- | libteec/src/tee_client_api.c | 59 | ||||
-rw-r--r-- | public/tee_client_api.h | 5 |
2 files changed, 54 insertions, 10 deletions
diff --git a/libteec/src/tee_client_api.c b/libteec/src/tee_client_api.c index 6de957f..3375752 100644 --- a/libteec/src/tee_client_api.c +++ b/libteec/src/tee_client_api.c @@ -56,6 +56,12 @@ #define MEMREF_SHM_OFFS(p) ((p)->a) #define MEMREF_SIZE(p) ((p)->b) +/* + * Internal flags of TEEC_SharedMemory::internal.flags + */ +#define SHM_FLAG_BUFFER_ALLOCED (1u << 0) +#define SHM_FLAG_SHADOW_BUFFER_ALLOCED (1u << 1) + static pthread_mutex_t teec_mutex = PTHREAD_MUTEX_INITIALIZER; static void teec_mutex_lock(pthread_mutex_t *mu) @@ -739,6 +745,7 @@ void TEEC_RequestCancellation(TEEC_Operation *operation) TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *ctx, TEEC_SharedMemory *shm) { + TEEC_Result res = TEEC_SUCCESS; int fd = 0; size_t s = 0; @@ -756,10 +763,40 @@ TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *ctx, TEEC_SharedMemory *shm) s = 8; if (ctx->reg_mem) { fd = teec_shm_register(ctx->fd, shm->buffer, s, &shm->id); - if (fd < 0) + if (fd >= 0) { + shm->registered_fd = fd; + shm->shadow_buffer = NULL; + shm->internal.flags = 0; + goto out; + } + + /* + * If we're here TEE_IOC_SHM_REGISTER failed, probably + * because some read-only memory was supplied and the Linux + * kernel doesn't like that at the moment. + * + * The error could also have some other origin. In any case + * we're not making matters worse by trying to allocate and + * register a shadow buffer before giving up. + */ + shm->shadow_buffer = malloc(s); + if (!shm->shadow_buffer) return TEEC_ERROR_OUT_OF_MEMORY; - shm->registered_fd = fd; + fd = teec_shm_register(ctx->fd, shm->shadow_buffer, s, + &shm->id); + if (fd >= 0) { + shm->registered_fd = fd; + shm->internal.flags = SHM_FLAG_SHADOW_BUFFER_ALLOCED; + goto out; + } + + if (errno == ENOMEM) + res = TEEC_ERROR_OUT_OF_MEMORY; + else + res = TEEC_ERROR_GENERIC; + free(shm->shadow_buffer); shm->shadow_buffer = NULL; + return res; } else { fd = teec_shm_alloc(ctx->fd, s, &shm->id); if (fd < 0) @@ -773,10 +810,11 @@ TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *ctx, TEEC_SharedMemory *shm) return TEEC_ERROR_OUT_OF_MEMORY; } shm->registered_fd = -1; + shm->internal.flags = 0; } +out: shm->alloced_size = s; - shm->buffer_allocated = false; return TEEC_SUCCESS; } @@ -852,7 +890,7 @@ TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context *ctx, TEEC_SharedMemory *shm) shm->shadow_buffer = NULL; shm->alloced_size = s; - shm->buffer_allocated = true; + shm->internal.flags = SHM_FLAG_BUFFER_ALLOCED; return TEEC_SUCCESS; } @@ -861,11 +899,14 @@ void TEEC_ReleaseSharedMemory(TEEC_SharedMemory *shm) if (!shm || shm->id == -1) return; - if (shm->shadow_buffer) - munmap(shm->shadow_buffer, shm->alloced_size); - else if (shm->buffer) { + if (shm->shadow_buffer) { + if (shm->internal.flags & SHM_FLAG_SHADOW_BUFFER_ALLOCED) + free(shm->shadow_buffer); + else + munmap(shm->shadow_buffer, shm->alloced_size); + } else if (shm->buffer) { if (shm->registered_fd >= 0) { - if (shm->buffer_allocated) + if (shm->internal.flags & SHM_FLAG_BUFFER_ALLOCED) free(shm->buffer); close(shm->registered_fd); } else @@ -877,5 +918,5 @@ void TEEC_ReleaseSharedMemory(TEEC_SharedMemory *shm) shm->shadow_buffer = NULL; shm->buffer = NULL; shm->registered_fd = -1; - shm->buffer_allocated = false; + shm->internal.flags = 0; } diff --git a/public/tee_client_api.h b/public/tee_client_api.h index 5c1e7d7..715ca6b 100644 --- a/public/tee_client_api.h +++ b/public/tee_client_api.h @@ -298,7 +298,10 @@ typedef struct { size_t alloced_size; void *shadow_buffer; int registered_fd; - bool buffer_allocated; + union { + bool dummy; + uint8_t flags; + } internal; } TEEC_SharedMemory; /** |