blob: 592347dce95ce3744676f5f2a060a8c1984d384a [file] [log] [blame]
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (c) 2014, STMicroelectronics International N.V.
*/
#include <kernel/mutex.h>
#include <stdlib.h>
#include <string.h>
#include <tee/tee_pobj.h>
#include <trace.h>
static TAILQ_HEAD(tee_pobjs, tee_pobj) tee_pobjs =
TAILQ_HEAD_INITIALIZER(tee_pobjs);
static struct mutex pobjs_mutex = MUTEX_INITIALIZER;
static TEE_Result tee_pobj_check_access(uint32_t oflags, uint32_t nflags)
{
/* meta is exclusive */
if ((oflags & TEE_DATA_FLAG_ACCESS_WRITE_META) ||
(nflags & TEE_DATA_FLAG_ACCESS_WRITE_META))
return TEE_ERROR_ACCESS_CONFLICT;
/*
* Excerpt of TEE Internal Core API Specification v1.1:
* If more than one handle is opened on the same object, and if any
* of these object handles was opened with the flag
* TEE_DATA_FLAG_ACCESS_READ, then all the object handles MUST have been
* opened with the flag TEE_DATA_FLAG_SHARE_READ
*/
if (((oflags & TEE_DATA_FLAG_ACCESS_READ) ||
(nflags & TEE_DATA_FLAG_ACCESS_READ)) &&
!((nflags & TEE_DATA_FLAG_SHARE_READ) &&
(oflags & TEE_DATA_FLAG_SHARE_READ)))
return TEE_ERROR_ACCESS_CONFLICT;
/*
* Excerpt of TEE Internal Core API Specification v1.1:
* An object can be opened with only share flags, which locks the access
* to an object against a given mode.
* An object can be opened with no flag set, which completely locks all
* subsequent attempts to access the object
*/
if ((nflags & TEE_DATA_FLAG_SHARE_READ) !=
(oflags & TEE_DATA_FLAG_SHARE_READ))
return TEE_ERROR_ACCESS_CONFLICT;
/* Same on WRITE access */
if (((oflags & TEE_DATA_FLAG_ACCESS_WRITE) ||
(nflags & TEE_DATA_FLAG_ACCESS_WRITE)) &&
!((nflags & TEE_DATA_FLAG_SHARE_WRITE) &&
(oflags & TEE_DATA_FLAG_SHARE_WRITE)))
return TEE_ERROR_ACCESS_CONFLICT;
if ((nflags & TEE_DATA_FLAG_SHARE_WRITE) !=
(oflags & TEE_DATA_FLAG_SHARE_WRITE))
return TEE_ERROR_ACCESS_CONFLICT;
return TEE_SUCCESS;
}
TEE_Result tee_pobj_get(TEE_UUID *uuid, void *obj_id, uint32_t obj_id_len,
uint32_t flags, bool temporary,
const struct tee_file_operations *fops,
struct tee_pobj **obj)
{
struct tee_pobj *o;
TEE_Result res;
*obj = NULL;
mutex_lock(&pobjs_mutex);
/* Check if file is open */
TAILQ_FOREACH(o, &tee_pobjs, link) {
if ((obj_id_len == o->obj_id_len) &&
(memcmp(obj_id, o->obj_id, obj_id_len) == 0) &&
(memcmp(uuid, &o->uuid, sizeof(TEE_UUID)) == 0) &&
(fops == o->fops)) {
*obj = o;
}
}
if (*obj) {
if (temporary != (*obj)->temporary) {
res = TEE_ERROR_ACCESS_CONFLICT;
goto out;
}
res = tee_pobj_check_access((*obj)->flags, flags);
if (res == TEE_SUCCESS)
(*obj)->refcnt++;
goto out;
}
/* new file */
o = calloc(1, sizeof(struct tee_pobj));
if (!o) {
res = TEE_ERROR_OUT_OF_MEMORY;
goto out;
}
o->refcnt = 1;
memcpy(&o->uuid, uuid, sizeof(TEE_UUID));
o->flags = flags;
o->fops = fops;
o->temporary = temporary;
o->obj_id = malloc(obj_id_len);
if (o->obj_id == NULL) {
free(o);
res = TEE_ERROR_OUT_OF_MEMORY;
goto out;
}
memcpy(o->obj_id, obj_id, obj_id_len);
o->obj_id_len = obj_id_len;
TAILQ_INSERT_TAIL(&tee_pobjs, o, link);
*obj = o;
res = TEE_SUCCESS;
out:
if (res != TEE_SUCCESS)
*obj = NULL;
mutex_unlock(&pobjs_mutex);
return res;
}
TEE_Result tee_pobj_release(struct tee_pobj *obj)
{
if (obj == NULL)
return TEE_ERROR_BAD_PARAMETERS;
mutex_lock(&pobjs_mutex);
obj->refcnt--;
if (obj->refcnt == 0) {
TAILQ_REMOVE(&tee_pobjs, obj, link);
free(obj->obj_id);
free(obj);
}
mutex_unlock(&pobjs_mutex);
return TEE_SUCCESS;
}
TEE_Result tee_pobj_rename(struct tee_pobj *obj, void *obj_id,
uint32_t obj_id_len)
{
TEE_Result res = TEE_SUCCESS;
void *new_obj_id = NULL;
if (obj == NULL || obj_id == NULL)
return TEE_ERROR_BAD_PARAMETERS;
mutex_lock(&pobjs_mutex);
if (obj->refcnt != 1) {
res = TEE_ERROR_BAD_STATE;
goto exit;
}
new_obj_id = malloc(obj_id_len);
if (new_obj_id == NULL) {
res = TEE_ERROR_OUT_OF_MEMORY;
goto exit;
}
memcpy(new_obj_id, obj_id, obj_id_len);
/* update internal data */
free(obj->obj_id);
obj->obj_id = new_obj_id;
obj->obj_id_len = obj_id_len;
new_obj_id = NULL;
exit:
mutex_unlock(&pobjs_mutex);
free(new_obj_id);
return res;
}