1*cbe7e1b8SBalint Dobszay // SPDX-License-Identifier: BSD-2-Clause 2*cbe7e1b8SBalint Dobszay /* 3*cbe7e1b8SBalint Dobszay * Copyright (c) 2018-2019, Linaro Limited 4*cbe7e1b8SBalint Dobszay * Copyright (c) 2020, Arm Limited 5*cbe7e1b8SBalint Dobszay */ 6*cbe7e1b8SBalint Dobszay 7*cbe7e1b8SBalint Dobszay #include <assert.h> 8*cbe7e1b8SBalint Dobszay #include <kernel/ldelf_syscalls.h> 9*cbe7e1b8SBalint Dobszay #include <kernel/user_mode_ctx.h> 10*cbe7e1b8SBalint Dobszay #include <ldelf.h> 11*cbe7e1b8SBalint Dobszay #include <mm/file.h> 12*cbe7e1b8SBalint Dobszay #include <mm/fobj.h> 13*cbe7e1b8SBalint Dobszay #include <mm/mobj.h> 14*cbe7e1b8SBalint Dobszay #include <mm/vm.h> 15*cbe7e1b8SBalint Dobszay #include <pta_system.h> 16*cbe7e1b8SBalint Dobszay #include <stdlib.h> 17*cbe7e1b8SBalint Dobszay #include <string.h> 18*cbe7e1b8SBalint Dobszay #include <trace.h> 19*cbe7e1b8SBalint Dobszay #include <util.h> 20*cbe7e1b8SBalint Dobszay 21*cbe7e1b8SBalint Dobszay struct bin_handle { 22*cbe7e1b8SBalint Dobszay const struct ts_store_ops *op; 23*cbe7e1b8SBalint Dobszay struct ts_store_handle *h; 24*cbe7e1b8SBalint Dobszay struct file *f; 25*cbe7e1b8SBalint Dobszay size_t offs_bytes; 26*cbe7e1b8SBalint Dobszay size_t size_bytes; 27*cbe7e1b8SBalint Dobszay }; 28*cbe7e1b8SBalint Dobszay 29*cbe7e1b8SBalint Dobszay void ta_bin_close(void *ptr) 30*cbe7e1b8SBalint Dobszay { 31*cbe7e1b8SBalint Dobszay struct bin_handle *binh = ptr; 32*cbe7e1b8SBalint Dobszay 33*cbe7e1b8SBalint Dobszay if (binh) { 34*cbe7e1b8SBalint Dobszay if (binh->op && binh->h) 35*cbe7e1b8SBalint Dobszay binh->op->close(binh->h); 36*cbe7e1b8SBalint Dobszay file_put(binh->f); 37*cbe7e1b8SBalint Dobszay } 38*cbe7e1b8SBalint Dobszay free(binh); 39*cbe7e1b8SBalint Dobszay } 40*cbe7e1b8SBalint Dobszay 41*cbe7e1b8SBalint Dobszay TEE_Result ldelf_open_ta_binary(struct system_ctx *ctx, uint32_t param_types, 42*cbe7e1b8SBalint Dobszay TEE_Param params[TEE_NUM_PARAMS]) 43*cbe7e1b8SBalint Dobszay { 44*cbe7e1b8SBalint Dobszay TEE_Result res = TEE_SUCCESS; 45*cbe7e1b8SBalint Dobszay struct bin_handle *binh = NULL; 46*cbe7e1b8SBalint Dobszay int h = 0; 47*cbe7e1b8SBalint Dobszay TEE_UUID *uuid = NULL; 48*cbe7e1b8SBalint Dobszay uint8_t tag[FILE_TAG_SIZE] = { 0 }; 49*cbe7e1b8SBalint Dobszay unsigned int tag_len = sizeof(tag); 50*cbe7e1b8SBalint Dobszay uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, 51*cbe7e1b8SBalint Dobszay TEE_PARAM_TYPE_VALUE_OUTPUT, 52*cbe7e1b8SBalint Dobszay TEE_PARAM_TYPE_NONE, 53*cbe7e1b8SBalint Dobszay TEE_PARAM_TYPE_NONE); 54*cbe7e1b8SBalint Dobszay 55*cbe7e1b8SBalint Dobszay if (exp_pt != param_types) 56*cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 57*cbe7e1b8SBalint Dobszay if (params[0].memref.size != sizeof(*uuid)) 58*cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 59*cbe7e1b8SBalint Dobszay 60*cbe7e1b8SBalint Dobszay uuid = params[0].memref.buffer; 61*cbe7e1b8SBalint Dobszay 62*cbe7e1b8SBalint Dobszay binh = calloc(1, sizeof(*binh)); 63*cbe7e1b8SBalint Dobszay if (!binh) 64*cbe7e1b8SBalint Dobszay return TEE_ERROR_OUT_OF_MEMORY; 65*cbe7e1b8SBalint Dobszay 66*cbe7e1b8SBalint Dobszay SCATTERED_ARRAY_FOREACH(binh->op, ta_stores, struct ts_store_ops) { 67*cbe7e1b8SBalint Dobszay DMSG("Lookup user TA ELF %pUl (%s)", 68*cbe7e1b8SBalint Dobszay (void *)uuid, binh->op->description); 69*cbe7e1b8SBalint Dobszay 70*cbe7e1b8SBalint Dobszay res = binh->op->open(uuid, &binh->h); 71*cbe7e1b8SBalint Dobszay DMSG("res=0x%x", res); 72*cbe7e1b8SBalint Dobszay if (res != TEE_ERROR_ITEM_NOT_FOUND && 73*cbe7e1b8SBalint Dobszay res != TEE_ERROR_STORAGE_NOT_AVAILABLE) 74*cbe7e1b8SBalint Dobszay break; 75*cbe7e1b8SBalint Dobszay } 76*cbe7e1b8SBalint Dobszay if (res) 77*cbe7e1b8SBalint Dobszay goto err; 78*cbe7e1b8SBalint Dobszay 79*cbe7e1b8SBalint Dobszay res = binh->op->get_size(binh->h, &binh->size_bytes); 80*cbe7e1b8SBalint Dobszay if (res) 81*cbe7e1b8SBalint Dobszay goto err; 82*cbe7e1b8SBalint Dobszay res = binh->op->get_tag(binh->h, tag, &tag_len); 83*cbe7e1b8SBalint Dobszay if (res) 84*cbe7e1b8SBalint Dobszay goto err; 85*cbe7e1b8SBalint Dobszay binh->f = file_get_by_tag(tag, tag_len); 86*cbe7e1b8SBalint Dobszay if (!binh->f) 87*cbe7e1b8SBalint Dobszay goto err_oom; 88*cbe7e1b8SBalint Dobszay 89*cbe7e1b8SBalint Dobszay h = handle_get(&ctx->db, binh); 90*cbe7e1b8SBalint Dobszay if (h < 0) 91*cbe7e1b8SBalint Dobszay goto err_oom; 92*cbe7e1b8SBalint Dobszay params[0].value.a = h; 93*cbe7e1b8SBalint Dobszay 94*cbe7e1b8SBalint Dobszay return TEE_SUCCESS; 95*cbe7e1b8SBalint Dobszay err_oom: 96*cbe7e1b8SBalint Dobszay res = TEE_ERROR_OUT_OF_MEMORY; 97*cbe7e1b8SBalint Dobszay err: 98*cbe7e1b8SBalint Dobszay ta_bin_close(binh); 99*cbe7e1b8SBalint Dobszay return res; 100*cbe7e1b8SBalint Dobszay } 101*cbe7e1b8SBalint Dobszay 102*cbe7e1b8SBalint Dobszay TEE_Result ldelf_close_ta_binary(struct system_ctx *ctx, uint32_t param_types, 103*cbe7e1b8SBalint Dobszay TEE_Param params[TEE_NUM_PARAMS]) 104*cbe7e1b8SBalint Dobszay { 105*cbe7e1b8SBalint Dobszay TEE_Result res = TEE_SUCCESS; 106*cbe7e1b8SBalint Dobszay struct bin_handle *binh = NULL; 107*cbe7e1b8SBalint Dobszay uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 108*cbe7e1b8SBalint Dobszay TEE_PARAM_TYPE_NONE, 109*cbe7e1b8SBalint Dobszay TEE_PARAM_TYPE_NONE, 110*cbe7e1b8SBalint Dobszay TEE_PARAM_TYPE_NONE); 111*cbe7e1b8SBalint Dobszay 112*cbe7e1b8SBalint Dobszay if (exp_pt != param_types) 113*cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 114*cbe7e1b8SBalint Dobszay 115*cbe7e1b8SBalint Dobszay if (params[0].value.b) 116*cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 117*cbe7e1b8SBalint Dobszay 118*cbe7e1b8SBalint Dobszay binh = handle_put(&ctx->db, params[0].value.a); 119*cbe7e1b8SBalint Dobszay if (!binh) 120*cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 121*cbe7e1b8SBalint Dobszay 122*cbe7e1b8SBalint Dobszay if (binh->offs_bytes < binh->size_bytes) 123*cbe7e1b8SBalint Dobszay res = binh->op->read(binh->h, NULL, 124*cbe7e1b8SBalint Dobszay binh->size_bytes - binh->offs_bytes); 125*cbe7e1b8SBalint Dobszay 126*cbe7e1b8SBalint Dobszay ta_bin_close(binh); 127*cbe7e1b8SBalint Dobszay 128*cbe7e1b8SBalint Dobszay return res; 129*cbe7e1b8SBalint Dobszay } 130*cbe7e1b8SBalint Dobszay 131*cbe7e1b8SBalint Dobszay static TEE_Result binh_copy_to(struct bin_handle *binh, vaddr_t va, 132*cbe7e1b8SBalint Dobszay size_t offs_bytes, size_t num_bytes) 133*cbe7e1b8SBalint Dobszay { 134*cbe7e1b8SBalint Dobszay TEE_Result res = TEE_SUCCESS; 135*cbe7e1b8SBalint Dobszay size_t next_offs = 0; 136*cbe7e1b8SBalint Dobszay 137*cbe7e1b8SBalint Dobszay if (offs_bytes < binh->offs_bytes) 138*cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_STATE; 139*cbe7e1b8SBalint Dobszay 140*cbe7e1b8SBalint Dobszay if (ADD_OVERFLOW(offs_bytes, num_bytes, &next_offs)) 141*cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 142*cbe7e1b8SBalint Dobszay 143*cbe7e1b8SBalint Dobszay if (offs_bytes > binh->offs_bytes) { 144*cbe7e1b8SBalint Dobszay res = binh->op->read(binh->h, NULL, 145*cbe7e1b8SBalint Dobszay offs_bytes - binh->offs_bytes); 146*cbe7e1b8SBalint Dobszay if (res) 147*cbe7e1b8SBalint Dobszay return res; 148*cbe7e1b8SBalint Dobszay binh->offs_bytes = offs_bytes; 149*cbe7e1b8SBalint Dobszay } 150*cbe7e1b8SBalint Dobszay 151*cbe7e1b8SBalint Dobszay if (next_offs > binh->size_bytes) { 152*cbe7e1b8SBalint Dobszay size_t rb = binh->size_bytes - binh->offs_bytes; 153*cbe7e1b8SBalint Dobszay 154*cbe7e1b8SBalint Dobszay res = binh->op->read(binh->h, (void *)va, rb); 155*cbe7e1b8SBalint Dobszay if (res) 156*cbe7e1b8SBalint Dobszay return res; 157*cbe7e1b8SBalint Dobszay memset((uint8_t *)va + rb, 0, num_bytes - rb); 158*cbe7e1b8SBalint Dobszay binh->offs_bytes = binh->size_bytes; 159*cbe7e1b8SBalint Dobszay } else { 160*cbe7e1b8SBalint Dobszay res = binh->op->read(binh->h, (void *)va, num_bytes); 161*cbe7e1b8SBalint Dobszay if (res) 162*cbe7e1b8SBalint Dobszay return res; 163*cbe7e1b8SBalint Dobszay binh->offs_bytes = next_offs; 164*cbe7e1b8SBalint Dobszay } 165*cbe7e1b8SBalint Dobszay 166*cbe7e1b8SBalint Dobszay return TEE_SUCCESS; 167*cbe7e1b8SBalint Dobszay } 168*cbe7e1b8SBalint Dobszay 169*cbe7e1b8SBalint Dobszay TEE_Result ldelf_map_ta_binary(struct system_ctx *ctx, 170*cbe7e1b8SBalint Dobszay struct user_mode_ctx *uctx, 171*cbe7e1b8SBalint Dobszay uint32_t param_types, 172*cbe7e1b8SBalint Dobszay TEE_Param params[TEE_NUM_PARAMS]) 173*cbe7e1b8SBalint Dobszay { 174*cbe7e1b8SBalint Dobszay const uint32_t accept_flags = PTA_SYSTEM_MAP_FLAG_SHAREABLE | 175*cbe7e1b8SBalint Dobszay PTA_SYSTEM_MAP_FLAG_WRITEABLE | 176*cbe7e1b8SBalint Dobszay PTA_SYSTEM_MAP_FLAG_EXECUTABLE; 177*cbe7e1b8SBalint Dobszay uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 178*cbe7e1b8SBalint Dobszay TEE_PARAM_TYPE_VALUE_INPUT, 179*cbe7e1b8SBalint Dobszay TEE_PARAM_TYPE_VALUE_INOUT, 180*cbe7e1b8SBalint Dobszay TEE_PARAM_TYPE_VALUE_INPUT); 181*cbe7e1b8SBalint Dobszay struct bin_handle *binh = NULL; 182*cbe7e1b8SBalint Dobszay uint32_t num_rounded_bytes = 0; 183*cbe7e1b8SBalint Dobszay TEE_Result res = TEE_SUCCESS; 184*cbe7e1b8SBalint Dobszay struct file_slice *fs = NULL; 185*cbe7e1b8SBalint Dobszay bool file_is_locked = false; 186*cbe7e1b8SBalint Dobszay struct mobj *mobj = NULL; 187*cbe7e1b8SBalint Dobszay uint32_t offs_bytes = 0; 188*cbe7e1b8SBalint Dobszay uint32_t offs_pages = 0; 189*cbe7e1b8SBalint Dobszay uint32_t num_bytes = 0; 190*cbe7e1b8SBalint Dobszay uint32_t pad_begin = 0; 191*cbe7e1b8SBalint Dobszay uint32_t pad_end = 0; 192*cbe7e1b8SBalint Dobszay size_t num_pages = 0; 193*cbe7e1b8SBalint Dobszay uint32_t flags = 0; 194*cbe7e1b8SBalint Dobszay uint32_t prot = 0; 195*cbe7e1b8SBalint Dobszay vaddr_t va = 0; 196*cbe7e1b8SBalint Dobszay 197*cbe7e1b8SBalint Dobszay if (exp_pt != param_types) 198*cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 199*cbe7e1b8SBalint Dobszay 200*cbe7e1b8SBalint Dobszay binh = handle_lookup(&ctx->db, params[0].value.a); 201*cbe7e1b8SBalint Dobszay if (!binh) 202*cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 203*cbe7e1b8SBalint Dobszay flags = params[0].value.b; 204*cbe7e1b8SBalint Dobszay offs_bytes = params[1].value.a; 205*cbe7e1b8SBalint Dobszay num_bytes = params[1].value.b; 206*cbe7e1b8SBalint Dobszay va = reg_pair_to_64(params[2].value.a, params[2].value.b); 207*cbe7e1b8SBalint Dobszay pad_begin = params[3].value.a; 208*cbe7e1b8SBalint Dobszay pad_end = params[3].value.b; 209*cbe7e1b8SBalint Dobszay 210*cbe7e1b8SBalint Dobszay if ((flags & accept_flags) != flags) 211*cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 212*cbe7e1b8SBalint Dobszay 213*cbe7e1b8SBalint Dobszay if ((flags & PTA_SYSTEM_MAP_FLAG_SHAREABLE) && 214*cbe7e1b8SBalint Dobszay (flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE)) 215*cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 216*cbe7e1b8SBalint Dobszay 217*cbe7e1b8SBalint Dobszay if ((flags & PTA_SYSTEM_MAP_FLAG_EXECUTABLE) && 218*cbe7e1b8SBalint Dobszay (flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE)) 219*cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 220*cbe7e1b8SBalint Dobszay 221*cbe7e1b8SBalint Dobszay if (offs_bytes & SMALL_PAGE_MASK) 222*cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 223*cbe7e1b8SBalint Dobszay 224*cbe7e1b8SBalint Dobszay prot = TEE_MATTR_UR | TEE_MATTR_PR; 225*cbe7e1b8SBalint Dobszay if (flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE) 226*cbe7e1b8SBalint Dobszay prot |= TEE_MATTR_UW | TEE_MATTR_PW; 227*cbe7e1b8SBalint Dobszay if (flags & PTA_SYSTEM_MAP_FLAG_EXECUTABLE) 228*cbe7e1b8SBalint Dobszay prot |= TEE_MATTR_UX; 229*cbe7e1b8SBalint Dobszay 230*cbe7e1b8SBalint Dobszay offs_pages = offs_bytes >> SMALL_PAGE_SHIFT; 231*cbe7e1b8SBalint Dobszay if (ROUNDUP_OVERFLOW(num_bytes, SMALL_PAGE_SIZE, &num_rounded_bytes)) 232*cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 233*cbe7e1b8SBalint Dobszay num_pages = num_rounded_bytes / SMALL_PAGE_SIZE; 234*cbe7e1b8SBalint Dobszay 235*cbe7e1b8SBalint Dobszay if (!file_trylock(binh->f)) { 236*cbe7e1b8SBalint Dobszay /* 237*cbe7e1b8SBalint Dobszay * Before we can block on the file lock we must make all 238*cbe7e1b8SBalint Dobszay * our page tables available for reclaiming in order to 239*cbe7e1b8SBalint Dobszay * avoid a dead-lock with the other thread (which already 240*cbe7e1b8SBalint Dobszay * is holding the file lock) mapping lots of memory below. 241*cbe7e1b8SBalint Dobszay */ 242*cbe7e1b8SBalint Dobszay vm_set_ctx(NULL); 243*cbe7e1b8SBalint Dobszay file_lock(binh->f); 244*cbe7e1b8SBalint Dobszay vm_set_ctx(uctx->ts_ctx); 245*cbe7e1b8SBalint Dobszay } 246*cbe7e1b8SBalint Dobszay file_is_locked = true; 247*cbe7e1b8SBalint Dobszay fs = file_find_slice(binh->f, offs_pages); 248*cbe7e1b8SBalint Dobszay if (fs) { 249*cbe7e1b8SBalint Dobszay /* If there's registered slice it has to match */ 250*cbe7e1b8SBalint Dobszay if (fs->page_offset != offs_pages || 251*cbe7e1b8SBalint Dobszay num_pages > fs->fobj->num_pages) { 252*cbe7e1b8SBalint Dobszay res = TEE_ERROR_BAD_PARAMETERS; 253*cbe7e1b8SBalint Dobszay goto err; 254*cbe7e1b8SBalint Dobszay } 255*cbe7e1b8SBalint Dobszay 256*cbe7e1b8SBalint Dobszay /* If there's a slice we must be mapping shareable */ 257*cbe7e1b8SBalint Dobszay if (!(flags & PTA_SYSTEM_MAP_FLAG_SHAREABLE)) { 258*cbe7e1b8SBalint Dobszay res = TEE_ERROR_BAD_PARAMETERS; 259*cbe7e1b8SBalint Dobszay goto err; 260*cbe7e1b8SBalint Dobszay } 261*cbe7e1b8SBalint Dobszay 262*cbe7e1b8SBalint Dobszay mobj = mobj_with_fobj_alloc(fs->fobj, binh->f); 263*cbe7e1b8SBalint Dobszay if (!mobj) { 264*cbe7e1b8SBalint Dobszay res = TEE_ERROR_OUT_OF_MEMORY; 265*cbe7e1b8SBalint Dobszay goto err; 266*cbe7e1b8SBalint Dobszay } 267*cbe7e1b8SBalint Dobszay res = vm_map_pad(uctx, &va, num_rounded_bytes, 268*cbe7e1b8SBalint Dobszay prot, VM_FLAG_READONLY, 269*cbe7e1b8SBalint Dobszay mobj, 0, pad_begin, pad_end, 0); 270*cbe7e1b8SBalint Dobszay mobj_put(mobj); 271*cbe7e1b8SBalint Dobszay if (res) 272*cbe7e1b8SBalint Dobszay goto err; 273*cbe7e1b8SBalint Dobszay } else { 274*cbe7e1b8SBalint Dobszay struct fobj *f = fobj_ta_mem_alloc(num_pages); 275*cbe7e1b8SBalint Dobszay struct file *file = NULL; 276*cbe7e1b8SBalint Dobszay uint32_t vm_flags = 0; 277*cbe7e1b8SBalint Dobszay 278*cbe7e1b8SBalint Dobszay if (!f) { 279*cbe7e1b8SBalint Dobszay res = TEE_ERROR_OUT_OF_MEMORY; 280*cbe7e1b8SBalint Dobszay goto err; 281*cbe7e1b8SBalint Dobszay } 282*cbe7e1b8SBalint Dobszay if (!(flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE)) { 283*cbe7e1b8SBalint Dobszay file = binh->f; 284*cbe7e1b8SBalint Dobszay vm_flags |= VM_FLAG_READONLY; 285*cbe7e1b8SBalint Dobszay } 286*cbe7e1b8SBalint Dobszay 287*cbe7e1b8SBalint Dobszay mobj = mobj_with_fobj_alloc(f, file); 288*cbe7e1b8SBalint Dobszay fobj_put(f); 289*cbe7e1b8SBalint Dobszay if (!mobj) { 290*cbe7e1b8SBalint Dobszay res = TEE_ERROR_OUT_OF_MEMORY; 291*cbe7e1b8SBalint Dobszay goto err; 292*cbe7e1b8SBalint Dobszay } 293*cbe7e1b8SBalint Dobszay res = vm_map_pad(uctx, &va, num_rounded_bytes, 294*cbe7e1b8SBalint Dobszay TEE_MATTR_PRW, vm_flags, mobj, 0, 295*cbe7e1b8SBalint Dobszay pad_begin, pad_end, 0); 296*cbe7e1b8SBalint Dobszay mobj_put(mobj); 297*cbe7e1b8SBalint Dobszay if (res) 298*cbe7e1b8SBalint Dobszay goto err; 299*cbe7e1b8SBalint Dobszay res = binh_copy_to(binh, va, offs_bytes, num_bytes); 300*cbe7e1b8SBalint Dobszay if (res) 301*cbe7e1b8SBalint Dobszay goto err_unmap_va; 302*cbe7e1b8SBalint Dobszay res = vm_set_prot(uctx, va, num_rounded_bytes, 303*cbe7e1b8SBalint Dobszay prot); 304*cbe7e1b8SBalint Dobszay if (res) 305*cbe7e1b8SBalint Dobszay goto err_unmap_va; 306*cbe7e1b8SBalint Dobszay 307*cbe7e1b8SBalint Dobszay /* 308*cbe7e1b8SBalint Dobszay * The context currently is active set it again to update 309*cbe7e1b8SBalint Dobszay * the mapping. 310*cbe7e1b8SBalint Dobszay */ 311*cbe7e1b8SBalint Dobszay vm_set_ctx(uctx->ts_ctx); 312*cbe7e1b8SBalint Dobszay 313*cbe7e1b8SBalint Dobszay if (!(flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE)) { 314*cbe7e1b8SBalint Dobszay res = file_add_slice(binh->f, f, offs_pages); 315*cbe7e1b8SBalint Dobszay if (res) 316*cbe7e1b8SBalint Dobszay goto err_unmap_va; 317*cbe7e1b8SBalint Dobszay } 318*cbe7e1b8SBalint Dobszay } 319*cbe7e1b8SBalint Dobszay 320*cbe7e1b8SBalint Dobszay file_unlock(binh->f); 321*cbe7e1b8SBalint Dobszay 322*cbe7e1b8SBalint Dobszay reg_pair_from_64(va, ¶ms[2].value.a, ¶ms[2].value.b); 323*cbe7e1b8SBalint Dobszay return TEE_SUCCESS; 324*cbe7e1b8SBalint Dobszay 325*cbe7e1b8SBalint Dobszay err_unmap_va: 326*cbe7e1b8SBalint Dobszay if (vm_unmap(uctx, va, num_rounded_bytes)) 327*cbe7e1b8SBalint Dobszay panic(); 328*cbe7e1b8SBalint Dobszay 329*cbe7e1b8SBalint Dobszay /* 330*cbe7e1b8SBalint Dobszay * The context currently is active set it again to update 331*cbe7e1b8SBalint Dobszay * the mapping. 332*cbe7e1b8SBalint Dobszay */ 333*cbe7e1b8SBalint Dobszay vm_set_ctx(uctx->ts_ctx); 334*cbe7e1b8SBalint Dobszay 335*cbe7e1b8SBalint Dobszay err: 336*cbe7e1b8SBalint Dobszay if (file_is_locked) 337*cbe7e1b8SBalint Dobszay file_unlock(binh->f); 338*cbe7e1b8SBalint Dobszay 339*cbe7e1b8SBalint Dobszay return res; 340*cbe7e1b8SBalint Dobszay } 341*cbe7e1b8SBalint Dobszay 342*cbe7e1b8SBalint Dobszay TEE_Result ldelf_copy_from_ta_binary(struct system_ctx *ctx, 343*cbe7e1b8SBalint Dobszay uint32_t param_types, 344*cbe7e1b8SBalint Dobszay TEE_Param params[TEE_NUM_PARAMS]) 345*cbe7e1b8SBalint Dobszay { 346*cbe7e1b8SBalint Dobszay struct bin_handle *binh = NULL; 347*cbe7e1b8SBalint Dobszay uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 348*cbe7e1b8SBalint Dobszay TEE_PARAM_TYPE_MEMREF_OUTPUT, 349*cbe7e1b8SBalint Dobszay TEE_PARAM_TYPE_NONE, 350*cbe7e1b8SBalint Dobszay TEE_PARAM_TYPE_NONE); 351*cbe7e1b8SBalint Dobszay 352*cbe7e1b8SBalint Dobszay if (exp_pt != param_types) 353*cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 354*cbe7e1b8SBalint Dobszay 355*cbe7e1b8SBalint Dobszay binh = handle_lookup(&ctx->db, params[0].value.a); 356*cbe7e1b8SBalint Dobszay if (!binh) 357*cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 358*cbe7e1b8SBalint Dobszay 359*cbe7e1b8SBalint Dobszay return binh_copy_to(binh, (vaddr_t)params[1].memref.buffer, 360*cbe7e1b8SBalint Dobszay params[0].value.b, params[1].memref.size); 361*cbe7e1b8SBalint Dobszay } 362*cbe7e1b8SBalint Dobszay 363*cbe7e1b8SBalint Dobszay TEE_Result ldelf_set_prot(struct user_mode_ctx *uctx, uint32_t param_types, 364*cbe7e1b8SBalint Dobszay TEE_Param params[TEE_NUM_PARAMS]) 365*cbe7e1b8SBalint Dobszay { 366*cbe7e1b8SBalint Dobszay const uint32_t accept_flags = PTA_SYSTEM_MAP_FLAG_WRITEABLE | 367*cbe7e1b8SBalint Dobszay PTA_SYSTEM_MAP_FLAG_EXECUTABLE; 368*cbe7e1b8SBalint Dobszay uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 369*cbe7e1b8SBalint Dobszay TEE_PARAM_TYPE_VALUE_INPUT, 370*cbe7e1b8SBalint Dobszay TEE_PARAM_TYPE_NONE, 371*cbe7e1b8SBalint Dobszay TEE_PARAM_TYPE_NONE); 372*cbe7e1b8SBalint Dobszay uint32_t prot = TEE_MATTR_UR | TEE_MATTR_PR; 373*cbe7e1b8SBalint Dobszay TEE_Result res = TEE_SUCCESS; 374*cbe7e1b8SBalint Dobszay uint32_t vm_flags = 0; 375*cbe7e1b8SBalint Dobszay uint32_t flags = 0; 376*cbe7e1b8SBalint Dobszay vaddr_t end_va = 0; 377*cbe7e1b8SBalint Dobszay vaddr_t va = 0; 378*cbe7e1b8SBalint Dobszay size_t sz = 0; 379*cbe7e1b8SBalint Dobszay 380*cbe7e1b8SBalint Dobszay if (exp_pt != param_types) 381*cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 382*cbe7e1b8SBalint Dobszay 383*cbe7e1b8SBalint Dobszay flags = params[0].value.b; 384*cbe7e1b8SBalint Dobszay 385*cbe7e1b8SBalint Dobszay if ((flags & accept_flags) != flags) 386*cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 387*cbe7e1b8SBalint Dobszay if (flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE) 388*cbe7e1b8SBalint Dobszay prot |= TEE_MATTR_UW | TEE_MATTR_PW; 389*cbe7e1b8SBalint Dobszay if (flags & PTA_SYSTEM_MAP_FLAG_EXECUTABLE) 390*cbe7e1b8SBalint Dobszay prot |= TEE_MATTR_UX; 391*cbe7e1b8SBalint Dobszay 392*cbe7e1b8SBalint Dobszay va = reg_pair_to_64(params[1].value.a, params[1].value.b); 393*cbe7e1b8SBalint Dobszay sz = ROUNDUP(params[0].value.a, SMALL_PAGE_SIZE); 394*cbe7e1b8SBalint Dobszay 395*cbe7e1b8SBalint Dobszay /* 396*cbe7e1b8SBalint Dobszay * The vm_get_flags() and vm_set_prot() are supposed to detect or 397*cbe7e1b8SBalint Dobszay * handle overflow directly or indirectly. However, this function 398*cbe7e1b8SBalint Dobszay * an API function so an extra guard here is in order. If nothing 399*cbe7e1b8SBalint Dobszay * else to make it easier to review the code. 400*cbe7e1b8SBalint Dobszay */ 401*cbe7e1b8SBalint Dobszay if (ADD_OVERFLOW(va, sz, &end_va)) 402*cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 403*cbe7e1b8SBalint Dobszay 404*cbe7e1b8SBalint Dobszay res = vm_get_flags(uctx, va, sz, &vm_flags); 405*cbe7e1b8SBalint Dobszay if (res) 406*cbe7e1b8SBalint Dobszay return res; 407*cbe7e1b8SBalint Dobszay if (vm_flags & VM_FLAG_PERMANENT) 408*cbe7e1b8SBalint Dobszay return TEE_ERROR_ACCESS_DENIED; 409*cbe7e1b8SBalint Dobszay 410*cbe7e1b8SBalint Dobszay /* 411*cbe7e1b8SBalint Dobszay * If the segment is a mapping of a part of a file (vm_flags & 412*cbe7e1b8SBalint Dobszay * VM_FLAG_READONLY) it cannot be made writeable as all mapped 413*cbe7e1b8SBalint Dobszay * files are mapped read-only. 414*cbe7e1b8SBalint Dobszay */ 415*cbe7e1b8SBalint Dobszay if ((vm_flags & VM_FLAG_READONLY) && 416*cbe7e1b8SBalint Dobszay (prot & (TEE_MATTR_UW | TEE_MATTR_PW))) 417*cbe7e1b8SBalint Dobszay return TEE_ERROR_ACCESS_DENIED; 418*cbe7e1b8SBalint Dobszay 419*cbe7e1b8SBalint Dobszay return vm_set_prot(uctx, va, sz, prot); 420*cbe7e1b8SBalint Dobszay } 421*cbe7e1b8SBalint Dobszay 422*cbe7e1b8SBalint Dobszay TEE_Result ldelf_remap(struct user_mode_ctx *uctx, uint32_t param_types, 423*cbe7e1b8SBalint Dobszay TEE_Param params[TEE_NUM_PARAMS]) 424*cbe7e1b8SBalint Dobszay { 425*cbe7e1b8SBalint Dobszay uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT, 426*cbe7e1b8SBalint Dobszay TEE_PARAM_TYPE_VALUE_INPUT, 427*cbe7e1b8SBalint Dobszay TEE_PARAM_TYPE_VALUE_INOUT, 428*cbe7e1b8SBalint Dobszay TEE_PARAM_TYPE_VALUE_INPUT); 429*cbe7e1b8SBalint Dobszay TEE_Result res = TEE_SUCCESS; 430*cbe7e1b8SBalint Dobszay uint32_t num_bytes = 0; 431*cbe7e1b8SBalint Dobszay uint32_t pad_begin = 0; 432*cbe7e1b8SBalint Dobszay uint32_t vm_flags = 0; 433*cbe7e1b8SBalint Dobszay uint32_t pad_end = 0; 434*cbe7e1b8SBalint Dobszay vaddr_t old_va = 0; 435*cbe7e1b8SBalint Dobszay vaddr_t new_va = 0; 436*cbe7e1b8SBalint Dobszay 437*cbe7e1b8SBalint Dobszay if (exp_pt != param_types) 438*cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 439*cbe7e1b8SBalint Dobszay 440*cbe7e1b8SBalint Dobszay num_bytes = params[0].value.a; 441*cbe7e1b8SBalint Dobszay old_va = reg_pair_to_64(params[1].value.a, params[1].value.b); 442*cbe7e1b8SBalint Dobszay new_va = reg_pair_to_64(params[2].value.a, params[2].value.b); 443*cbe7e1b8SBalint Dobszay pad_begin = params[3].value.a; 444*cbe7e1b8SBalint Dobszay pad_end = params[3].value.b; 445*cbe7e1b8SBalint Dobszay 446*cbe7e1b8SBalint Dobszay res = vm_get_flags(uctx, old_va, num_bytes, &vm_flags); 447*cbe7e1b8SBalint Dobszay if (res) 448*cbe7e1b8SBalint Dobszay return res; 449*cbe7e1b8SBalint Dobszay if (vm_flags & VM_FLAG_PERMANENT) 450*cbe7e1b8SBalint Dobszay return TEE_ERROR_ACCESS_DENIED; 451*cbe7e1b8SBalint Dobszay 452*cbe7e1b8SBalint Dobszay res = vm_remap(uctx, &new_va, old_va, num_bytes, pad_begin, 453*cbe7e1b8SBalint Dobszay pad_end); 454*cbe7e1b8SBalint Dobszay if (!res) 455*cbe7e1b8SBalint Dobszay reg_pair_from_64(new_va, ¶ms[2].value.a, 456*cbe7e1b8SBalint Dobszay ¶ms[2].value.b); 457*cbe7e1b8SBalint Dobszay 458*cbe7e1b8SBalint Dobszay return res; 459*cbe7e1b8SBalint Dobszay } 460