Wednesday, November 2, 2016

optee exposed to TA indirect attacking NSEL1

This in optee_os/core/tee/tee_svc.c has a potential security hole:


static TEE_Result tee_svc_copy_param(struct tee_ta_session *sess,
                                     struct tee_ta_session *called_sess,
                                     struct utee_params *callee_params,
                                     struct tee_ta_param *param,
                                     void *tmp_buf_va[TEE_NUM_PARAMS],
                                     tee_mm_entry_t **mm)
{
        size_t n;
        TEE_Result res;
        size_t req_mem = 0;
        size_t s;
        uint8_t *dst = 0;
        tee_paddr_t dst_pa, src_pa = 0;
        bool ta_private_memref[TEE_NUM_PARAMS];
        struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
        const uint32_t sec_ddr_attr = TEE_MATTR_CACHE_CACHED;

        /* fill 'param' input struct with caller params description buffer */
        if (!callee_params) {
                memset(param, 0, sizeof(*param));
        } else {
                res = tee_mmu_check_access_rights(utc,
                        TEE_MEMORY_ACCESS_READ | TEE_MEMORY_ACCESS_ANY_OWNER,
                        (tee_uaddr_t)callee_params, sizeof(struct utee_params));
                if (res != TEE_SUCCESS)
                        return res;
                utee_param_to_param(param, callee_params);
        }

        if (called_sess && is_static_ta_ctx(called_sess->ctx)) {
                /*
                 * static TA, borrow the mapping of the calling
                 * during this call.
                 */
                return TEE_SUCCESS;
        }
                                   

  for (n = 0; n < TEE_NUM_PARAMS; n++) {

                ta_private_memref[n] = false;

                switch (TEE_PARAM_TYPE_GET(param->types, n)) {
                case TEE_PARAM_TYPE_MEMREF_INPUT:
                case TEE_PARAM_TYPE_MEMREF_OUTPUT:
                case TEE_PARAM_TYPE_MEMREF_INOUT:
                        if (param->params[n].memref.buffer == NULL) {
                                if (param->params[n].memref.size != 0)
                                        return TEE_ERROR_BAD_PARAMETERS;
                                break;
                        }
                        /* uTA cannot expose its private memory */
                        if (tee_mmu_is_vbuf_inside_ta_private(utc,
                                    param->params[n].memref.buffer,
                                    param->params[n].memref.size)) {

                                s = ROUNDUP(param->params[n].memref.size,
                                                sizeof(uint32_t));
                                /* Check overflow */
                                if (req_mem + s < req_mem)
                                        return TEE_ERROR_BAD_PARAMETERS;
                                req_mem += s;
                                ta_private_memref[n] = true;
                                break;
                        }
                        if (tee_mmu_is_vbuf_intersect_ta_private(utc,
                                    param->params[n].memref.buffer,
                                    param->params[n].memref.size))
                                return TEE_ERROR_BAD_PARAMETERS;

                        src_pa = virt_to_phys(param->params[n].memref.buffer);
                        if (!src_pa)
                                return TEE_ERROR_BAD_PARAMETERS;

                        param->param_attr[n] = tee_mmu_user_get_cache_attr(
                                utc, (void *)param->params[n].memref.buffer);

                        param->params[n].memref.buffer = (void *)src_pa;
                        break;

                default:
                        break;
                }
        }

No comments: