aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Wiklander <jens.wiklander@linaro.org>2020-09-04 09:29:34 +0200
committerJérôme Forissier <jerome@forissier.org>2020-09-04 17:29:41 +0200
commit4f3d4cbb7824bab8f5c0a445f301528a53142f6b (patch)
tree11842316f3ca5cbf8cadf8d01cb9b7641b9fccdd
parente7a4706e08c8fbdd53530868a6ac4937193dd73c (diff)
downloadoptee_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.c59
-rw-r--r--public/tee_client_api.h5
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;
/**