1cbe7e1b8SBalint Dobszay // SPDX-License-Identifier: BSD-2-Clause
2cbe7e1b8SBalint Dobszay /*
36105aa86SJens Wiklander * Copyright (c) 2018-2019, 2022 Linaro Limited
4c185655eSJelle Sels * Copyright (c) 2020-2021, Arm Limited
5cbe7e1b8SBalint Dobszay */
6cbe7e1b8SBalint Dobszay
7cbe7e1b8SBalint Dobszay #include <assert.h>
8baa5161dSBalint Dobszay #include <crypto/crypto.h>
9cbe7e1b8SBalint Dobszay #include <kernel/ldelf_syscalls.h>
10*f7e461dcSJens Wiklander #include <kernel/user_access.h>
11cbe7e1b8SBalint Dobszay #include <kernel/user_mode_ctx.h>
12cbe7e1b8SBalint Dobszay #include <ldelf.h>
13cbe7e1b8SBalint Dobszay #include <mm/file.h>
14cbe7e1b8SBalint Dobszay #include <mm/fobj.h>
15cbe7e1b8SBalint Dobszay #include <mm/mobj.h>
16cbe7e1b8SBalint Dobszay #include <mm/vm.h>
17cbe7e1b8SBalint Dobszay #include <stdlib.h>
18cbe7e1b8SBalint Dobszay #include <string.h>
19cbe7e1b8SBalint Dobszay #include <trace.h>
20cbe7e1b8SBalint Dobszay #include <util.h>
21cbe7e1b8SBalint Dobszay
22cbe7e1b8SBalint Dobszay struct bin_handle {
23cbe7e1b8SBalint Dobszay const struct ts_store_ops *op;
24cbe7e1b8SBalint Dobszay struct ts_store_handle *h;
25cbe7e1b8SBalint Dobszay struct file *f;
26cbe7e1b8SBalint Dobszay size_t offs_bytes;
27cbe7e1b8SBalint Dobszay size_t size_bytes;
28cbe7e1b8SBalint Dobszay };
29cbe7e1b8SBalint Dobszay
unmap_or_panic(struct user_mode_ctx * uctx,vaddr_t va,size_t byte_count)30*f7e461dcSJens Wiklander static void unmap_or_panic(struct user_mode_ctx *uctx, vaddr_t va,
31*f7e461dcSJens Wiklander size_t byte_count)
32*f7e461dcSJens Wiklander {
33*f7e461dcSJens Wiklander TEE_Result res = vm_unmap(uctx, va, byte_count);
34*f7e461dcSJens Wiklander
35*f7e461dcSJens Wiklander if (res) {
36*f7e461dcSJens Wiklander EMSG("vm_unmap(%#"PRIxVA", %#zx) returned %#"PRIx32,
37*f7e461dcSJens Wiklander va, byte_count, res);
38*f7e461dcSJens Wiklander panic("Can't restore memory map");
39*f7e461dcSJens Wiklander }
40*f7e461dcSJens Wiklander }
41*f7e461dcSJens Wiklander
ldelf_syscall_map_zi(vaddr_t * va,size_t num_bytes,size_t pad_begin,size_t pad_end,unsigned long flags)42baa5161dSBalint Dobszay TEE_Result ldelf_syscall_map_zi(vaddr_t *va, size_t num_bytes, size_t pad_begin,
43baa5161dSBalint Dobszay size_t pad_end, unsigned long flags)
44baa5161dSBalint Dobszay {
45baa5161dSBalint Dobszay TEE_Result res = TEE_SUCCESS;
46baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session();
47baa5161dSBalint Dobszay struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx);
48baa5161dSBalint Dobszay struct fobj *f = NULL;
49baa5161dSBalint Dobszay struct mobj *mobj = NULL;
50baa5161dSBalint Dobszay uint32_t prot = TEE_MATTR_URW | TEE_MATTR_PRW;
51baa5161dSBalint Dobszay uint32_t vm_flags = 0;
52*f7e461dcSJens Wiklander vaddr_t va_copy = 0;
53baa5161dSBalint Dobszay
54baa5161dSBalint Dobszay if (flags & ~LDELF_MAP_FLAG_SHAREABLE)
55baa5161dSBalint Dobszay return TEE_ERROR_BAD_PARAMETERS;
56baa5161dSBalint Dobszay
57*f7e461dcSJens Wiklander res = GET_USER_SCALAR(va_copy, va);
58*f7e461dcSJens Wiklander if (res)
59*f7e461dcSJens Wiklander return res;
60*f7e461dcSJens Wiklander
61baa5161dSBalint Dobszay if (flags & LDELF_MAP_FLAG_SHAREABLE)
62baa5161dSBalint Dobszay vm_flags |= VM_FLAG_SHAREABLE;
63baa5161dSBalint Dobszay
64baa5161dSBalint Dobszay f = fobj_ta_mem_alloc(ROUNDUP_DIV(num_bytes, SMALL_PAGE_SIZE));
65baa5161dSBalint Dobszay if (!f)
66baa5161dSBalint Dobszay return TEE_ERROR_OUT_OF_MEMORY;
676105aa86SJens Wiklander mobj = mobj_with_fobj_alloc(f, NULL, TEE_MATTR_MEM_TYPE_TAGGED);
68baa5161dSBalint Dobszay fobj_put(f);
69baa5161dSBalint Dobszay if (!mobj)
70baa5161dSBalint Dobszay return TEE_ERROR_OUT_OF_MEMORY;
71*f7e461dcSJens Wiklander res = vm_map_pad(uctx, &va_copy, num_bytes, prot, vm_flags,
72baa5161dSBalint Dobszay mobj, 0, pad_begin, pad_end, 0);
73baa5161dSBalint Dobszay mobj_put(mobj);
74*f7e461dcSJens Wiklander if (!res) {
75*f7e461dcSJens Wiklander res = PUT_USER_SCALAR(va_copy, va);
76*f7e461dcSJens Wiklander if (res)
77*f7e461dcSJens Wiklander unmap_or_panic(uctx, va_copy, num_bytes);
78*f7e461dcSJens Wiklander }
79baa5161dSBalint Dobszay
80baa5161dSBalint Dobszay return res;
81baa5161dSBalint Dobszay }
82baa5161dSBalint Dobszay
ldelf_syscall_unmap(vaddr_t va,size_t num_bytes)83baa5161dSBalint Dobszay TEE_Result ldelf_syscall_unmap(vaddr_t va, size_t num_bytes)
84baa5161dSBalint Dobszay {
85baa5161dSBalint Dobszay TEE_Result res = TEE_SUCCESS;
86baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session();
87baa5161dSBalint Dobszay struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx);
88baa5161dSBalint Dobszay size_t sz = ROUNDUP(num_bytes, SMALL_PAGE_SIZE);
89baa5161dSBalint Dobszay uint32_t vm_flags = 0;
90baa5161dSBalint Dobszay vaddr_t end_va = 0;
91baa5161dSBalint Dobszay
92baa5161dSBalint Dobszay /*
93baa5161dSBalint Dobszay * The vm_get_flags() and vm_unmap() are supposed to detect or handle
94baa5161dSBalint Dobszay * overflow directly or indirectly. However, since this function is an
95baa5161dSBalint Dobszay * API function it's worth having an extra guard here. If nothing else,
96baa5161dSBalint Dobszay * to increase code clarity.
97baa5161dSBalint Dobszay */
98baa5161dSBalint Dobszay if (ADD_OVERFLOW(va, sz, &end_va))
99baa5161dSBalint Dobszay return TEE_ERROR_BAD_PARAMETERS;
100baa5161dSBalint Dobszay
101baa5161dSBalint Dobszay res = vm_get_flags(uctx, va, sz, &vm_flags);
102baa5161dSBalint Dobszay if (res)
103baa5161dSBalint Dobszay return res;
104baa5161dSBalint Dobszay if (vm_flags & VM_FLAG_PERMANENT)
105baa5161dSBalint Dobszay return TEE_ERROR_ACCESS_DENIED;
106baa5161dSBalint Dobszay
107baa5161dSBalint Dobszay return vm_unmap(uctx, va, sz);
108baa5161dSBalint Dobszay }
109baa5161dSBalint Dobszay
bin_close(void * ptr)110baa5161dSBalint Dobszay static void bin_close(void *ptr)
111cbe7e1b8SBalint Dobszay {
112cbe7e1b8SBalint Dobszay struct bin_handle *binh = ptr;
113cbe7e1b8SBalint Dobszay
114cbe7e1b8SBalint Dobszay if (binh) {
115cbe7e1b8SBalint Dobszay if (binh->op && binh->h)
116cbe7e1b8SBalint Dobszay binh->op->close(binh->h);
117cbe7e1b8SBalint Dobszay file_put(binh->f);
118cbe7e1b8SBalint Dobszay }
119cbe7e1b8SBalint Dobszay free(binh);
120cbe7e1b8SBalint Dobszay }
121cbe7e1b8SBalint Dobszay
ldelf_syscall_open_bin(const TEE_UUID * uuid,size_t uuid_size,uint32_t * handle)122baa5161dSBalint Dobszay TEE_Result ldelf_syscall_open_bin(const TEE_UUID *uuid, size_t uuid_size,
123baa5161dSBalint Dobszay uint32_t *handle)
124cbe7e1b8SBalint Dobszay {
125cbe7e1b8SBalint Dobszay TEE_Result res = TEE_SUCCESS;
126baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session();
127baa5161dSBalint Dobszay struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx);
128baa5161dSBalint Dobszay struct system_ctx *sys_ctx = sess->user_ctx;
129cbe7e1b8SBalint Dobszay struct bin_handle *binh = NULL;
130cbe7e1b8SBalint Dobszay uint8_t tag[FILE_TAG_SIZE] = { 0 };
131cbe7e1b8SBalint Dobszay unsigned int tag_len = sizeof(tag);
132*f7e461dcSJens Wiklander TEE_UUID *bb_uuid = NULL;
133baa5161dSBalint Dobszay int h = 0;
134cbe7e1b8SBalint Dobszay
135*f7e461dcSJens Wiklander res = BB_MEMDUP_USER(uuid, sizeof(*uuid), &bb_uuid);
136baa5161dSBalint Dobszay if (res)
137baa5161dSBalint Dobszay return res;
138baa5161dSBalint Dobszay
139baa5161dSBalint Dobszay res = vm_check_access_rights(uctx,
140baa5161dSBalint Dobszay TEE_MEMORY_ACCESS_WRITE |
141baa5161dSBalint Dobszay TEE_MEMORY_ACCESS_ANY_OWNER,
142baa5161dSBalint Dobszay (uaddr_t)handle, sizeof(uint32_t));
143baa5161dSBalint Dobszay if (res)
144baa5161dSBalint Dobszay return res;
145baa5161dSBalint Dobszay
146baa5161dSBalint Dobszay if (uuid_size != sizeof(*uuid))
147cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS;
148cbe7e1b8SBalint Dobszay
149baa5161dSBalint Dobszay if (!sys_ctx) {
150baa5161dSBalint Dobszay sys_ctx = calloc(1, sizeof(*sys_ctx));
151baa5161dSBalint Dobszay if (!sys_ctx)
152baa5161dSBalint Dobszay return TEE_ERROR_OUT_OF_MEMORY;
153baa5161dSBalint Dobszay sess->user_ctx = sys_ctx;
154baa5161dSBalint Dobszay }
155cbe7e1b8SBalint Dobszay
156cbe7e1b8SBalint Dobszay binh = calloc(1, sizeof(*binh));
157cbe7e1b8SBalint Dobszay if (!binh)
158cbe7e1b8SBalint Dobszay return TEE_ERROR_OUT_OF_MEMORY;
159cbe7e1b8SBalint Dobszay
160c185655eSJelle Sels if (is_user_ta_ctx(sess->ctx) || is_stmm_ctx(sess->ctx)) {
161c185655eSJelle Sels SCATTERED_ARRAY_FOREACH(binh->op, ta_stores,
162c185655eSJelle Sels struct ts_store_ops) {
163cbe7e1b8SBalint Dobszay DMSG("Lookup user TA ELF %pUl (%s)",
164*f7e461dcSJens Wiklander (void *)bb_uuid, binh->op->description);
165cbe7e1b8SBalint Dobszay
166*f7e461dcSJens Wiklander res = binh->op->open(bb_uuid, &binh->h);
167baa5161dSBalint Dobszay DMSG("res=%#"PRIx32, res);
168cbe7e1b8SBalint Dobszay if (res != TEE_ERROR_ITEM_NOT_FOUND &&
169cbe7e1b8SBalint Dobszay res != TEE_ERROR_STORAGE_NOT_AVAILABLE)
170cbe7e1b8SBalint Dobszay break;
171cbe7e1b8SBalint Dobszay }
172c185655eSJelle Sels } else if (is_sp_ctx(sess->ctx)) {
173c185655eSJelle Sels SCATTERED_ARRAY_FOREACH(binh->op, sp_stores,
174c185655eSJelle Sels struct ts_store_ops) {
175c185655eSJelle Sels DMSG("Lookup user SP ELF %pUl (%s)",
176*f7e461dcSJens Wiklander (void *)bb_uuid, binh->op->description);
177c185655eSJelle Sels
178*f7e461dcSJens Wiklander res = binh->op->open(bb_uuid, &binh->h);
179c185655eSJelle Sels DMSG("res=%#"PRIx32, res);
180c185655eSJelle Sels if (res != TEE_ERROR_ITEM_NOT_FOUND &&
181c185655eSJelle Sels res != TEE_ERROR_STORAGE_NOT_AVAILABLE)
182c185655eSJelle Sels break;
183c185655eSJelle Sels }
184c185655eSJelle Sels } else {
185c185655eSJelle Sels res = TEE_ERROR_ITEM_NOT_FOUND;
186c185655eSJelle Sels }
187c185655eSJelle Sels
188cbe7e1b8SBalint Dobszay if (res)
189cbe7e1b8SBalint Dobszay goto err;
190cbe7e1b8SBalint Dobszay
191cbe7e1b8SBalint Dobszay res = binh->op->get_size(binh->h, &binh->size_bytes);
192cbe7e1b8SBalint Dobszay if (res)
193cbe7e1b8SBalint Dobszay goto err;
194cbe7e1b8SBalint Dobszay res = binh->op->get_tag(binh->h, tag, &tag_len);
195cbe7e1b8SBalint Dobszay if (res)
196cbe7e1b8SBalint Dobszay goto err;
197cbe7e1b8SBalint Dobszay binh->f = file_get_by_tag(tag, tag_len);
198cbe7e1b8SBalint Dobszay if (!binh->f)
199cbe7e1b8SBalint Dobszay goto err_oom;
200cbe7e1b8SBalint Dobszay
201baa5161dSBalint Dobszay h = handle_get(&sys_ctx->db, binh);
202cbe7e1b8SBalint Dobszay if (h < 0)
203cbe7e1b8SBalint Dobszay goto err_oom;
204*f7e461dcSJens Wiklander res = PUT_USER_SCALAR(h, handle);
205*f7e461dcSJens Wiklander if (res) {
206*f7e461dcSJens Wiklander handle_put(&sys_ctx->db, h);
207*f7e461dcSJens Wiklander goto err;
208*f7e461dcSJens Wiklander }
209cbe7e1b8SBalint Dobszay
210cbe7e1b8SBalint Dobszay return TEE_SUCCESS;
211baa5161dSBalint Dobszay
212cbe7e1b8SBalint Dobszay err_oom:
213cbe7e1b8SBalint Dobszay res = TEE_ERROR_OUT_OF_MEMORY;
214cbe7e1b8SBalint Dobszay err:
215baa5161dSBalint Dobszay bin_close(binh);
216cbe7e1b8SBalint Dobszay return res;
217cbe7e1b8SBalint Dobszay }
218cbe7e1b8SBalint Dobszay
ldelf_syscall_close_bin(unsigned long handle)219baa5161dSBalint Dobszay TEE_Result ldelf_syscall_close_bin(unsigned long handle)
220cbe7e1b8SBalint Dobszay {
221cbe7e1b8SBalint Dobszay TEE_Result res = TEE_SUCCESS;
222baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session();
223baa5161dSBalint Dobszay struct system_ctx *sys_ctx = sess->user_ctx;
224cbe7e1b8SBalint Dobszay struct bin_handle *binh = NULL;
225cbe7e1b8SBalint Dobszay
226baa5161dSBalint Dobszay if (!sys_ctx)
227cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS;
228cbe7e1b8SBalint Dobszay
229baa5161dSBalint Dobszay binh = handle_put(&sys_ctx->db, handle);
230cbe7e1b8SBalint Dobszay if (!binh)
231cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS;
232cbe7e1b8SBalint Dobszay
233cbe7e1b8SBalint Dobszay if (binh->offs_bytes < binh->size_bytes)
234ef44161fSJens Wiklander res = binh->op->read(binh->h, NULL, NULL,
235cbe7e1b8SBalint Dobszay binh->size_bytes - binh->offs_bytes);
236cbe7e1b8SBalint Dobszay
237baa5161dSBalint Dobszay bin_close(binh);
238baa5161dSBalint Dobszay if (handle_db_is_empty(&sys_ctx->db)) {
239baa5161dSBalint Dobszay handle_db_destroy(&sys_ctx->db, bin_close);
240baa5161dSBalint Dobszay free(sys_ctx);
241baa5161dSBalint Dobszay sess->user_ctx = NULL;
242baa5161dSBalint Dobszay }
243cbe7e1b8SBalint Dobszay
244cbe7e1b8SBalint Dobszay return res;
245cbe7e1b8SBalint Dobszay }
246cbe7e1b8SBalint Dobszay
binh_copy_to(struct bin_handle * binh,vaddr_t va_core,vaddr_t va_user,size_t offs_bytes,size_t num_bytes)247ef44161fSJens Wiklander static TEE_Result binh_copy_to(struct bin_handle *binh, vaddr_t va_core,
248ef44161fSJens Wiklander vaddr_t va_user, size_t offs_bytes,
249ef44161fSJens Wiklander size_t num_bytes)
250cbe7e1b8SBalint Dobszay {
251cbe7e1b8SBalint Dobszay TEE_Result res = TEE_SUCCESS;
252cbe7e1b8SBalint Dobszay size_t next_offs = 0;
253cbe7e1b8SBalint Dobszay
254cbe7e1b8SBalint Dobszay if (offs_bytes < binh->offs_bytes)
255cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_STATE;
256cbe7e1b8SBalint Dobszay
257cbe7e1b8SBalint Dobszay if (ADD_OVERFLOW(offs_bytes, num_bytes, &next_offs))
258cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS;
259cbe7e1b8SBalint Dobszay
260cbe7e1b8SBalint Dobszay if (offs_bytes > binh->offs_bytes) {
261ef44161fSJens Wiklander res = binh->op->read(binh->h, NULL, NULL,
262cbe7e1b8SBalint Dobszay offs_bytes - binh->offs_bytes);
263cbe7e1b8SBalint Dobszay if (res)
264cbe7e1b8SBalint Dobszay return res;
265cbe7e1b8SBalint Dobszay binh->offs_bytes = offs_bytes;
266cbe7e1b8SBalint Dobszay }
267cbe7e1b8SBalint Dobszay
268cbe7e1b8SBalint Dobszay if (next_offs > binh->size_bytes) {
269cbe7e1b8SBalint Dobszay size_t rb = binh->size_bytes - binh->offs_bytes;
270cbe7e1b8SBalint Dobszay
271ef44161fSJens Wiklander res = binh->op->read(binh->h, (void *)va_core,
272ef44161fSJens Wiklander (void *)va_user, rb);
273cbe7e1b8SBalint Dobszay if (res)
274cbe7e1b8SBalint Dobszay return res;
275ef44161fSJens Wiklander if (va_core)
276ef44161fSJens Wiklander memset((uint8_t *)va_core + rb, 0, num_bytes - rb);
277ef44161fSJens Wiklander if (va_user) {
278ef44161fSJens Wiklander res = clear_user((uint8_t *)va_user + rb,
279ef44161fSJens Wiklander num_bytes - rb);
280ef44161fSJens Wiklander if (res)
281ef44161fSJens Wiklander return res;
282ef44161fSJens Wiklander }
283cbe7e1b8SBalint Dobszay binh->offs_bytes = binh->size_bytes;
284cbe7e1b8SBalint Dobszay } else {
285ef44161fSJens Wiklander res = binh->op->read(binh->h, (void *)va_core,
286ef44161fSJens Wiklander (void *)va_user, num_bytes);
287cbe7e1b8SBalint Dobszay if (res)
288cbe7e1b8SBalint Dobszay return res;
289cbe7e1b8SBalint Dobszay binh->offs_bytes = next_offs;
290cbe7e1b8SBalint Dobszay }
291cbe7e1b8SBalint Dobszay
292cbe7e1b8SBalint Dobszay return TEE_SUCCESS;
293cbe7e1b8SBalint Dobszay }
294cbe7e1b8SBalint Dobszay
ldelf_syscall_map_bin(vaddr_t * va,size_t num_bytes,unsigned long handle,size_t offs_bytes,size_t pad_begin,size_t pad_end,unsigned long flags)295baa5161dSBalint Dobszay TEE_Result ldelf_syscall_map_bin(vaddr_t *va, size_t num_bytes,
296baa5161dSBalint Dobszay unsigned long handle, size_t offs_bytes,
297baa5161dSBalint Dobszay size_t pad_begin, size_t pad_end,
298baa5161dSBalint Dobszay unsigned long flags)
299cbe7e1b8SBalint Dobszay {
300baa5161dSBalint Dobszay TEE_Result res = TEE_SUCCESS;
301baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session();
302baa5161dSBalint Dobszay struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx);
303baa5161dSBalint Dobszay struct system_ctx *sys_ctx = sess->user_ctx;
304cbe7e1b8SBalint Dobszay struct bin_handle *binh = NULL;
305cbe7e1b8SBalint Dobszay uint32_t num_rounded_bytes = 0;
306cbe7e1b8SBalint Dobszay struct file_slice *fs = NULL;
307cbe7e1b8SBalint Dobszay bool file_is_locked = false;
308cbe7e1b8SBalint Dobszay struct mobj *mobj = NULL;
309cbe7e1b8SBalint Dobszay uint32_t offs_pages = 0;
310cbe7e1b8SBalint Dobszay size_t num_pages = 0;
311*f7e461dcSJens Wiklander vaddr_t va_copy = 0;
312cbe7e1b8SBalint Dobszay uint32_t prot = 0;
313baa5161dSBalint Dobszay const uint32_t accept_flags = LDELF_MAP_FLAG_SHAREABLE |
314baa5161dSBalint Dobszay LDELF_MAP_FLAG_WRITEABLE |
3150d482f82SRuchika Gupta LDELF_MAP_FLAG_BTI |
316baa5161dSBalint Dobszay LDELF_MAP_FLAG_EXECUTABLE;
317cbe7e1b8SBalint Dobszay
318*f7e461dcSJens Wiklander res = GET_USER_SCALAR(va_copy, va);
319*f7e461dcSJens Wiklander if (res)
320*f7e461dcSJens Wiklander return res;
321*f7e461dcSJens Wiklander
322baa5161dSBalint Dobszay if (!sys_ctx)
323cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS;
324cbe7e1b8SBalint Dobszay
325baa5161dSBalint Dobszay binh = handle_lookup(&sys_ctx->db, handle);
326cbe7e1b8SBalint Dobszay if (!binh)
327cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS;
328cbe7e1b8SBalint Dobszay
329cbe7e1b8SBalint Dobszay if ((flags & accept_flags) != flags)
330cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS;
331cbe7e1b8SBalint Dobszay
332baa5161dSBalint Dobszay if ((flags & LDELF_MAP_FLAG_SHAREABLE) &&
333baa5161dSBalint Dobszay (flags & LDELF_MAP_FLAG_WRITEABLE))
334cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS;
335cbe7e1b8SBalint Dobszay
336baa5161dSBalint Dobszay if ((flags & LDELF_MAP_FLAG_EXECUTABLE) &&
337baa5161dSBalint Dobszay (flags & LDELF_MAP_FLAG_WRITEABLE))
338cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS;
339cbe7e1b8SBalint Dobszay
340cbe7e1b8SBalint Dobszay if (offs_bytes & SMALL_PAGE_MASK)
341cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS;
342cbe7e1b8SBalint Dobszay
343cbe7e1b8SBalint Dobszay prot = TEE_MATTR_UR | TEE_MATTR_PR;
344baa5161dSBalint Dobszay if (flags & LDELF_MAP_FLAG_WRITEABLE)
345cbe7e1b8SBalint Dobszay prot |= TEE_MATTR_UW | TEE_MATTR_PW;
346baa5161dSBalint Dobszay if (flags & LDELF_MAP_FLAG_EXECUTABLE)
347cbe7e1b8SBalint Dobszay prot |= TEE_MATTR_UX;
3480d482f82SRuchika Gupta if (flags & LDELF_MAP_FLAG_BTI)
3490d482f82SRuchika Gupta prot |= TEE_MATTR_GUARDED;
350cbe7e1b8SBalint Dobszay
351cbe7e1b8SBalint Dobszay offs_pages = offs_bytes >> SMALL_PAGE_SHIFT;
352cbe7e1b8SBalint Dobszay if (ROUNDUP_OVERFLOW(num_bytes, SMALL_PAGE_SIZE, &num_rounded_bytes))
353cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS;
354cbe7e1b8SBalint Dobszay num_pages = num_rounded_bytes / SMALL_PAGE_SIZE;
355cbe7e1b8SBalint Dobszay
356cbe7e1b8SBalint Dobszay if (!file_trylock(binh->f)) {
357cbe7e1b8SBalint Dobszay /*
358cbe7e1b8SBalint Dobszay * Before we can block on the file lock we must make all
359cbe7e1b8SBalint Dobszay * our page tables available for reclaiming in order to
360cbe7e1b8SBalint Dobszay * avoid a dead-lock with the other thread (which already
361cbe7e1b8SBalint Dobszay * is holding the file lock) mapping lots of memory below.
362cbe7e1b8SBalint Dobszay */
363cbe7e1b8SBalint Dobszay vm_set_ctx(NULL);
364cbe7e1b8SBalint Dobszay file_lock(binh->f);
365cbe7e1b8SBalint Dobszay vm_set_ctx(uctx->ts_ctx);
366cbe7e1b8SBalint Dobszay }
367cbe7e1b8SBalint Dobszay file_is_locked = true;
368cbe7e1b8SBalint Dobszay fs = file_find_slice(binh->f, offs_pages);
369cbe7e1b8SBalint Dobszay if (fs) {
370cbe7e1b8SBalint Dobszay /* If there's registered slice it has to match */
371cbe7e1b8SBalint Dobszay if (fs->page_offset != offs_pages ||
372cbe7e1b8SBalint Dobszay num_pages > fs->fobj->num_pages) {
373cbe7e1b8SBalint Dobszay res = TEE_ERROR_BAD_PARAMETERS;
374cbe7e1b8SBalint Dobszay goto err;
375cbe7e1b8SBalint Dobszay }
376cbe7e1b8SBalint Dobszay
377cbe7e1b8SBalint Dobszay /* If there's a slice we must be mapping shareable */
378baa5161dSBalint Dobszay if (!(flags & LDELF_MAP_FLAG_SHAREABLE)) {
379cbe7e1b8SBalint Dobszay res = TEE_ERROR_BAD_PARAMETERS;
380cbe7e1b8SBalint Dobszay goto err;
381cbe7e1b8SBalint Dobszay }
382cbe7e1b8SBalint Dobszay
3836105aa86SJens Wiklander mobj = mobj_with_fobj_alloc(fs->fobj, binh->f,
3846105aa86SJens Wiklander TEE_MATTR_MEM_TYPE_TAGGED);
385cbe7e1b8SBalint Dobszay if (!mobj) {
386cbe7e1b8SBalint Dobszay res = TEE_ERROR_OUT_OF_MEMORY;
387cbe7e1b8SBalint Dobszay goto err;
388cbe7e1b8SBalint Dobszay }
389*f7e461dcSJens Wiklander res = vm_map_pad(uctx, &va_copy, num_rounded_bytes,
390cbe7e1b8SBalint Dobszay prot, VM_FLAG_READONLY,
391cbe7e1b8SBalint Dobszay mobj, 0, pad_begin, pad_end, 0);
392cbe7e1b8SBalint Dobszay mobj_put(mobj);
393cbe7e1b8SBalint Dobszay if (res)
394cbe7e1b8SBalint Dobszay goto err;
395cbe7e1b8SBalint Dobszay } else {
396cbe7e1b8SBalint Dobszay struct fobj *f = fobj_ta_mem_alloc(num_pages);
397cbe7e1b8SBalint Dobszay struct file *file = NULL;
398cbe7e1b8SBalint Dobszay uint32_t vm_flags = 0;
399cbe7e1b8SBalint Dobszay
400cbe7e1b8SBalint Dobszay if (!f) {
401cbe7e1b8SBalint Dobszay res = TEE_ERROR_OUT_OF_MEMORY;
402cbe7e1b8SBalint Dobszay goto err;
403cbe7e1b8SBalint Dobszay }
404baa5161dSBalint Dobszay if (!(flags & LDELF_MAP_FLAG_WRITEABLE)) {
405cbe7e1b8SBalint Dobszay file = binh->f;
406cbe7e1b8SBalint Dobszay vm_flags |= VM_FLAG_READONLY;
407cbe7e1b8SBalint Dobszay }
408cbe7e1b8SBalint Dobszay
4096105aa86SJens Wiklander mobj = mobj_with_fobj_alloc(f, file, TEE_MATTR_MEM_TYPE_TAGGED);
410cbe7e1b8SBalint Dobszay fobj_put(f);
411cbe7e1b8SBalint Dobszay if (!mobj) {
412cbe7e1b8SBalint Dobszay res = TEE_ERROR_OUT_OF_MEMORY;
413cbe7e1b8SBalint Dobszay goto err;
414cbe7e1b8SBalint Dobszay }
415*f7e461dcSJens Wiklander res = vm_map_pad(uctx, &va_copy, num_rounded_bytes,
416cbe7e1b8SBalint Dobszay TEE_MATTR_PRW, vm_flags, mobj, 0,
417cbe7e1b8SBalint Dobszay pad_begin, pad_end, 0);
418cbe7e1b8SBalint Dobszay mobj_put(mobj);
419cbe7e1b8SBalint Dobszay if (res)
420cbe7e1b8SBalint Dobszay goto err;
421*f7e461dcSJens Wiklander res = binh_copy_to(binh, va_copy, 0, offs_bytes, num_bytes);
422cbe7e1b8SBalint Dobszay if (res)
423cbe7e1b8SBalint Dobszay goto err_unmap_va;
424*f7e461dcSJens Wiklander res = vm_set_prot(uctx, va_copy, num_rounded_bytes,
425cbe7e1b8SBalint Dobszay prot);
426cbe7e1b8SBalint Dobszay if (res)
427cbe7e1b8SBalint Dobszay goto err_unmap_va;
428cbe7e1b8SBalint Dobszay
429cbe7e1b8SBalint Dobszay /*
430cbe7e1b8SBalint Dobszay * The context currently is active set it again to update
431cbe7e1b8SBalint Dobszay * the mapping.
432cbe7e1b8SBalint Dobszay */
433cbe7e1b8SBalint Dobszay vm_set_ctx(uctx->ts_ctx);
434cbe7e1b8SBalint Dobszay
435baa5161dSBalint Dobszay if (!(flags & LDELF_MAP_FLAG_WRITEABLE)) {
436cbe7e1b8SBalint Dobszay res = file_add_slice(binh->f, f, offs_pages);
437cbe7e1b8SBalint Dobszay if (res)
438cbe7e1b8SBalint Dobszay goto err_unmap_va;
439cbe7e1b8SBalint Dobszay }
440cbe7e1b8SBalint Dobszay }
441cbe7e1b8SBalint Dobszay
442*f7e461dcSJens Wiklander res = PUT_USER_SCALAR(va_copy, va);
443*f7e461dcSJens Wiklander if (res)
444*f7e461dcSJens Wiklander goto err_unmap_va;
445*f7e461dcSJens Wiklander
446cbe7e1b8SBalint Dobszay file_unlock(binh->f);
447cbe7e1b8SBalint Dobszay
448cbe7e1b8SBalint Dobszay return TEE_SUCCESS;
449cbe7e1b8SBalint Dobszay
450cbe7e1b8SBalint Dobszay err_unmap_va:
451*f7e461dcSJens Wiklander unmap_or_panic(uctx, va_copy, num_rounded_bytes);
452cbe7e1b8SBalint Dobszay
453cbe7e1b8SBalint Dobszay /*
454cbe7e1b8SBalint Dobszay * The context currently is active set it again to update
455cbe7e1b8SBalint Dobszay * the mapping.
456cbe7e1b8SBalint Dobszay */
457cbe7e1b8SBalint Dobszay vm_set_ctx(uctx->ts_ctx);
458cbe7e1b8SBalint Dobszay
459cbe7e1b8SBalint Dobszay err:
460cbe7e1b8SBalint Dobszay if (file_is_locked)
461cbe7e1b8SBalint Dobszay file_unlock(binh->f);
462cbe7e1b8SBalint Dobszay
463cbe7e1b8SBalint Dobszay return res;
464cbe7e1b8SBalint Dobszay }
465cbe7e1b8SBalint Dobszay
ldelf_syscall_copy_from_bin(void * dst,size_t offs,size_t num_bytes,unsigned long handle)466baa5161dSBalint Dobszay TEE_Result ldelf_syscall_copy_from_bin(void *dst, size_t offs, size_t num_bytes,
467baa5161dSBalint Dobszay unsigned long handle)
468cbe7e1b8SBalint Dobszay {
469baa5161dSBalint Dobszay TEE_Result res = TEE_SUCCESS;
470baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session();
471baa5161dSBalint Dobszay struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx);
472baa5161dSBalint Dobszay struct system_ctx *sys_ctx = sess->user_ctx;
473cbe7e1b8SBalint Dobszay struct bin_handle *binh = NULL;
474cbe7e1b8SBalint Dobszay
475baa5161dSBalint Dobszay res = vm_check_access_rights(uctx,
476baa5161dSBalint Dobszay TEE_MEMORY_ACCESS_WRITE |
477baa5161dSBalint Dobszay TEE_MEMORY_ACCESS_ANY_OWNER,
478baa5161dSBalint Dobszay (uaddr_t)dst, num_bytes);
479baa5161dSBalint Dobszay if (res)
480baa5161dSBalint Dobszay return res;
481baa5161dSBalint Dobszay
482baa5161dSBalint Dobszay if (!sys_ctx)
483cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS;
484cbe7e1b8SBalint Dobszay
485baa5161dSBalint Dobszay binh = handle_lookup(&sys_ctx->db, handle);
486cbe7e1b8SBalint Dobszay if (!binh)
487cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS;
488cbe7e1b8SBalint Dobszay
489ef44161fSJens Wiklander return binh_copy_to(binh, 0, (vaddr_t)dst, offs, num_bytes);
490cbe7e1b8SBalint Dobszay }
491cbe7e1b8SBalint Dobszay
ldelf_syscall_set_prot(unsigned long va,size_t num_bytes,unsigned long flags)492baa5161dSBalint Dobszay TEE_Result ldelf_syscall_set_prot(unsigned long va, size_t num_bytes,
493baa5161dSBalint Dobszay unsigned long flags)
494cbe7e1b8SBalint Dobszay {
495cbe7e1b8SBalint Dobszay TEE_Result res = TEE_SUCCESS;
496baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session();
497baa5161dSBalint Dobszay struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx);
498baa5161dSBalint Dobszay size_t sz = ROUNDUP(num_bytes, SMALL_PAGE_SIZE);
499baa5161dSBalint Dobszay uint32_t prot = TEE_MATTR_UR | TEE_MATTR_PR;
500cbe7e1b8SBalint Dobszay uint32_t vm_flags = 0;
501cbe7e1b8SBalint Dobszay vaddr_t end_va = 0;
502baa5161dSBalint Dobszay const uint32_t accept_flags = LDELF_MAP_FLAG_WRITEABLE |
5030d482f82SRuchika Gupta LDELF_MAP_FLAG_BTI |
504baa5161dSBalint Dobszay LDELF_MAP_FLAG_EXECUTABLE;
505cbe7e1b8SBalint Dobszay
506cbe7e1b8SBalint Dobszay if ((flags & accept_flags) != flags)
507cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS;
508baa5161dSBalint Dobszay if (flags & LDELF_MAP_FLAG_WRITEABLE)
509cbe7e1b8SBalint Dobszay prot |= TEE_MATTR_UW | TEE_MATTR_PW;
510baa5161dSBalint Dobszay if (flags & LDELF_MAP_FLAG_EXECUTABLE)
511cbe7e1b8SBalint Dobszay prot |= TEE_MATTR_UX;
5120d482f82SRuchika Gupta if (flags & LDELF_MAP_FLAG_BTI)
5130d482f82SRuchika Gupta prot |= TEE_MATTR_GUARDED;
514cbe7e1b8SBalint Dobszay
515cbe7e1b8SBalint Dobszay /*
516baa5161dSBalint Dobszay * The vm_get_flags() and vm_unmap() are supposed to detect or handle
517baa5161dSBalint Dobszay * overflow directly or indirectly. However, since this function is an
518baa5161dSBalint Dobszay * API function it's worth having an extra guard here. If nothing else,
519baa5161dSBalint Dobszay * to increase code clarity.
520cbe7e1b8SBalint Dobszay */
521cbe7e1b8SBalint Dobszay if (ADD_OVERFLOW(va, sz, &end_va))
522cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS;
523cbe7e1b8SBalint Dobszay
524cbe7e1b8SBalint Dobszay res = vm_get_flags(uctx, va, sz, &vm_flags);
525cbe7e1b8SBalint Dobszay if (res)
526cbe7e1b8SBalint Dobszay return res;
527cbe7e1b8SBalint Dobszay if (vm_flags & VM_FLAG_PERMANENT)
528cbe7e1b8SBalint Dobszay return TEE_ERROR_ACCESS_DENIED;
529cbe7e1b8SBalint Dobszay
530cbe7e1b8SBalint Dobszay /*
531cbe7e1b8SBalint Dobszay * If the segment is a mapping of a part of a file (vm_flags &
532cbe7e1b8SBalint Dobszay * VM_FLAG_READONLY) it cannot be made writeable as all mapped
533cbe7e1b8SBalint Dobszay * files are mapped read-only.
534cbe7e1b8SBalint Dobszay */
535cbe7e1b8SBalint Dobszay if ((vm_flags & VM_FLAG_READONLY) &&
536cbe7e1b8SBalint Dobszay (prot & (TEE_MATTR_UW | TEE_MATTR_PW)))
537cbe7e1b8SBalint Dobszay return TEE_ERROR_ACCESS_DENIED;
538cbe7e1b8SBalint Dobszay
539cbe7e1b8SBalint Dobszay return vm_set_prot(uctx, va, sz, prot);
540cbe7e1b8SBalint Dobszay }
541cbe7e1b8SBalint Dobszay
ldelf_syscall_remap(unsigned long old_va,vaddr_t * new_va,size_t num_bytes,size_t pad_begin,size_t pad_end)542baa5161dSBalint Dobszay TEE_Result ldelf_syscall_remap(unsigned long old_va, vaddr_t *new_va,
543baa5161dSBalint Dobszay size_t num_bytes, size_t pad_begin,
544baa5161dSBalint Dobszay size_t pad_end)
545cbe7e1b8SBalint Dobszay {
546cbe7e1b8SBalint Dobszay TEE_Result res = TEE_SUCCESS;
547baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session();
548baa5161dSBalint Dobszay struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx);
549cbe7e1b8SBalint Dobszay uint32_t vm_flags = 0;
550*f7e461dcSJens Wiklander vaddr_t va_copy = 0;
551cbe7e1b8SBalint Dobszay
552*f7e461dcSJens Wiklander res = GET_USER_SCALAR(va_copy, new_va);
553*f7e461dcSJens Wiklander if (res)
554*f7e461dcSJens Wiklander return res;
555cbe7e1b8SBalint Dobszay res = vm_get_flags(uctx, old_va, num_bytes, &vm_flags);
556cbe7e1b8SBalint Dobszay if (res)
557cbe7e1b8SBalint Dobszay return res;
558cbe7e1b8SBalint Dobszay if (vm_flags & VM_FLAG_PERMANENT)
559cbe7e1b8SBalint Dobszay return TEE_ERROR_ACCESS_DENIED;
560cbe7e1b8SBalint Dobszay
561*f7e461dcSJens Wiklander res = vm_remap(uctx, &va_copy, old_va, num_bytes, pad_begin, pad_end);
562*f7e461dcSJens Wiklander if (res)
563cbe7e1b8SBalint Dobszay return res;
564*f7e461dcSJens Wiklander
565*f7e461dcSJens Wiklander res = PUT_USER_SCALAR(va_copy, new_va);
566*f7e461dcSJens Wiklander if (res) {
567*f7e461dcSJens Wiklander TEE_Result res2 = TEE_SUCCESS;
568*f7e461dcSJens Wiklander vaddr_t va = old_va;
569*f7e461dcSJens Wiklander
570*f7e461dcSJens Wiklander res2 = vm_remap(uctx, &va, va_copy, num_bytes, 0, 0);
571*f7e461dcSJens Wiklander if (res2) {
572*f7e461dcSJens Wiklander EMSG("vm_remap(%#"PRIxVA", %#"PRIxVA", %#zx) returned %#"PRIx32,
573*f7e461dcSJens Wiklander va, va_copy, num_bytes, res2);
574*f7e461dcSJens Wiklander panic("Can't restore memory map");
575*f7e461dcSJens Wiklander }
576*f7e461dcSJens Wiklander return res;
577*f7e461dcSJens Wiklander }
578*f7e461dcSJens Wiklander
579*f7e461dcSJens Wiklander return TEE_SUCCESS;
580cbe7e1b8SBalint Dobszay }
581baa5161dSBalint Dobszay
ldelf_syscall_gen_rnd_num(void * buf,size_t num_bytes)582baa5161dSBalint Dobszay TEE_Result ldelf_syscall_gen_rnd_num(void *buf, size_t num_bytes)
583baa5161dSBalint Dobszay {
584baa5161dSBalint Dobszay TEE_Result res = TEE_SUCCESS;
585*f7e461dcSJens Wiklander void *bb = NULL;
586baa5161dSBalint Dobszay
587*f7e461dcSJens Wiklander bb = bb_alloc(num_bytes);
588*f7e461dcSJens Wiklander if (!bb)
589*f7e461dcSJens Wiklander return TEE_ERROR_OUT_OF_MEMORY;
590*f7e461dcSJens Wiklander
591*f7e461dcSJens Wiklander res = crypto_rng_read(bb, num_bytes);
592baa5161dSBalint Dobszay if (res)
593baa5161dSBalint Dobszay return res;
594baa5161dSBalint Dobszay
595*f7e461dcSJens Wiklander return copy_to_user(buf, bb, num_bytes);
596baa5161dSBalint Dobszay }
597baa5161dSBalint Dobszay
598baa5161dSBalint Dobszay /*
599baa5161dSBalint Dobszay * Should be called after returning from ldelf. If user_ctx is not NULL means
600baa5161dSBalint Dobszay * that ldelf crashed or otherwise didn't complete properly. This function will
601baa5161dSBalint Dobszay * close the remaining handles and free the context structs allocated by ldelf.
602baa5161dSBalint Dobszay */
ldelf_sess_cleanup(struct ts_session * sess)603baa5161dSBalint Dobszay void ldelf_sess_cleanup(struct ts_session *sess)
604baa5161dSBalint Dobszay {
605baa5161dSBalint Dobszay struct system_ctx *sys_ctx = sess->user_ctx;
606baa5161dSBalint Dobszay
607baa5161dSBalint Dobszay if (sys_ctx) {
608baa5161dSBalint Dobszay handle_db_destroy(&sys_ctx->db, bin_close);
609baa5161dSBalint Dobszay free(sys_ctx);
610baa5161dSBalint Dobszay sess->user_ctx = NULL;
611baa5161dSBalint Dobszay }
612baa5161dSBalint Dobszay }
613