/* * Copyright (c) 2017, Linaro Limited * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include static TEE_Result delete_object(uint32_t param_types, TEE_Param params[4]) { const uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE); TEE_ObjectHandle object; TEE_Result res; char *obj_id; size_t obj_id_sz; /* * Safely get the invocation parameters */ if (param_types != exp_param_types) return TEE_ERROR_BAD_PARAMETERS; obj_id_sz = params[0].memref.size; obj_id = TEE_Malloc(obj_id_sz, 0); if (!obj_id) return TEE_ERROR_OUT_OF_MEMORY; TEE_MemMove(obj_id, params[0].memref.buffer, obj_id_sz); /* * Check object exists and delete it */ res = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, obj_id, obj_id_sz, TEE_DATA_FLAG_ACCESS_READ | TEE_DATA_FLAG_ACCESS_WRITE_META, /* we must be allowed to delete it */ &object); if (res != TEE_SUCCESS) { EMSG("Failed to open persistent object, res=0x%08x", res); TEE_Free(obj_id); return res; } TEE_CloseAndDeletePersistentObject1(object); TEE_Free(obj_id); return res; } static TEE_Result create_raw_object(uint32_t param_types, TEE_Param params[4]) { const uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, TEE_PARAM_TYPE_MEMREF_INPUT, TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE); TEE_ObjectHandle object; TEE_Result res; char *obj_id; size_t obj_id_sz; char *data; size_t data_sz; uint32_t obj_data_flag; /* * Safely get the invocation parameters */ if (param_types != exp_param_types) return TEE_ERROR_BAD_PARAMETERS; obj_id_sz = params[0].memref.size; obj_id = TEE_Malloc(obj_id_sz, 0); if (!obj_id) return TEE_ERROR_OUT_OF_MEMORY; TEE_MemMove(obj_id, params[0].memref.buffer, obj_id_sz); data_sz = params[1].memref.size; data = TEE_Malloc(data_sz, 0); if (!data) return TEE_ERROR_OUT_OF_MEMORY; TEE_MemMove(data, params[1].memref.buffer, data_sz); /* * Create object in secure storage and fill with data */ obj_data_flag = TEE_DATA_FLAG_ACCESS_READ | /* we can later read the oject */ TEE_DATA_FLAG_ACCESS_WRITE | /* we can later write into the object */ TEE_DATA_FLAG_ACCESS_WRITE_META | /* we can later destroy or rename the object */ TEE_DATA_FLAG_OVERWRITE; /* destroy existing object of same ID */ res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE, obj_id, obj_id_sz, obj_data_flag, TEE_HANDLE_NULL, NULL, 0, /* we may not fill it right now */ &object); if (res != TEE_SUCCESS) { EMSG("TEE_CreatePersistentObject failed 0x%08x", res); TEE_Free(obj_id); TEE_Free(data); return res; } res = TEE_WriteObjectData(object, data, data_sz); if (res != TEE_SUCCESS) { EMSG("TEE_WriteObjectData failed 0x%08x", res); TEE_CloseAndDeletePersistentObject1(object); } else { TEE_CloseObject(object); } TEE_Free(obj_id); TEE_Free(data); return res; } static TEE_Result read_raw_object(uint32_t param_types, TEE_Param params[4]) { const uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, TEE_PARAM_TYPE_MEMREF_OUTPUT, TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE); TEE_ObjectHandle object; TEE_ObjectInfo object_info; TEE_Result res; uint32_t read_bytes; char *obj_id; size_t obj_id_sz; char *data; size_t data_sz; /* * Safely get the invocation parameters */ if (param_types != exp_param_types) return TEE_ERROR_BAD_PARAMETERS; obj_id_sz = params[0].memref.size; obj_id = TEE_Malloc(obj_id_sz, 0); if (!obj_id) return TEE_ERROR_OUT_OF_MEMORY; TEE_MemMove(obj_id, params[0].memref.buffer, obj_id_sz); data_sz = params[1].memref.size; data = TEE_Malloc(data_sz, 0); if (!data) return TEE_ERROR_OUT_OF_MEMORY; /* * Check the object exist and can be dumped into output buffer * then dump it. */ res = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, obj_id, obj_id_sz, TEE_DATA_FLAG_ACCESS_READ | TEE_DATA_FLAG_SHARE_READ, &object); if (res != TEE_SUCCESS) { EMSG("Failed to open persistent object, res=0x%08x", res); TEE_Free(obj_id); TEE_Free(data); return res; } res = TEE_GetObjectInfo1(object, &object_info); if (res != TEE_SUCCESS) { EMSG("Failed to create persistent object, res=0x%08x", res); goto exit; } if (object_info.dataSize > data_sz) { /* * Provided buffer is too short. * Return the expected size together with status "short buffer" */ params[1].memref.size = object_info.dataSize; res = TEE_ERROR_SHORT_BUFFER; goto exit; } res = TEE_ReadObjectData(object, data, object_info.dataSize, &read_bytes); if (res == TEE_SUCCESS) TEE_MemMove(params[1].memref.buffer, data, read_bytes); if (res != TEE_SUCCESS || read_bytes != object_info.dataSize) { EMSG("TEE_ReadObjectData failed 0x%08x, read %" PRIu32 " over %u", res, read_bytes, object_info.dataSize); goto exit; } /* Return the number of byte effectively filled */ params[1].memref.size = read_bytes; exit: TEE_CloseObject(object); TEE_Free(obj_id); TEE_Free(data); return res; } TEE_Result TA_CreateEntryPoint(void) { /* Nothing to do */ return TEE_SUCCESS; } void TA_DestroyEntryPoint(void) { /* Nothing to do */ } TEE_Result TA_OpenSessionEntryPoint(uint32_t __unused param_types, TEE_Param __unused params[4], void __unused **session) { /* Nothing to do */ return TEE_SUCCESS; } void TA_CloseSessionEntryPoint(void __unused *session) { /* Nothing to do */ } TEE_Result TA_InvokeCommandEntryPoint(void __unused *session, uint32_t command, uint32_t param_types, TEE_Param params[4]) { switch (command) { case TA_SECURE_STORAGE_CMD_WRITE_RAW: return create_raw_object(param_types, params); case TA_SECURE_STORAGE_CMD_READ_RAW: return read_raw_object(param_types, params); case TA_SECURE_STORAGE_CMD_DELETE: return delete_object(param_types, params); default: EMSG("Command ID 0x%x is not supported", command); return TEE_ERROR_NOT_SUPPORTED; } }