1c40a6505SJens Wiklander /* SPDX-License-Identifier: BSD-2-Clause */
2c40a6505SJens Wiklander /*
3c40a6505SJens Wiklander * Copyright (c) 2014, STMicroelectronics International N.V.
4c40a6505SJens Wiklander * Copyright (c) 2020, Linaro Limited
5c40a6505SJens Wiklander */
6c40a6505SJens Wiklander #ifndef __KERNEL_USER_ACCESS_H
7c40a6505SJens Wiklander #define __KERNEL_USER_ACCESS_H
8c40a6505SJens Wiklander
9c40a6505SJens Wiklander #include <assert.h>
106fa59c9aSSeonghyun Park #include <kernel/user_access_arch.h>
11c40a6505SJens Wiklander #include <tee_api_types.h>
12c40a6505SJens Wiklander #include <types_ext.h>
13c40a6505SJens Wiklander
14c40a6505SJens Wiklander #ifdef CFG_WITH_USER_TA
15e59bc1dbSJens Wiklander TEE_Result check_user_access(uint32_t flags, const void *uaddr, size_t len);
167e4100f3SJens Wiklander TEE_Result copy_from_user_private(void *kaddr, const void *uaddr, size_t len);
17c40a6505SJens Wiklander TEE_Result copy_from_user(void *kaddr, const void *uaddr, size_t len);
18f6b5feb1SJens Wiklander TEE_Result copy_to_user_private(void *uaddr, const void *kaddr, size_t len);
19f6b5feb1SJens Wiklander TEE_Result copy_to_user(void *uaddr, const void *kaddr, size_t len);
20c40a6505SJens Wiklander #else
check_user_access(uint32_t flags __unused,const void * uaddr __unused,size_t len __unused)21e59bc1dbSJens Wiklander static inline TEE_Result check_user_access(uint32_t flags __unused,
22e59bc1dbSJens Wiklander const void *uaddr __unused,
23e59bc1dbSJens Wiklander size_t len __unused)
24e59bc1dbSJens Wiklander {
25e59bc1dbSJens Wiklander return TEE_ERROR_NOT_SUPPORTED;
26e59bc1dbSJens Wiklander }
27e59bc1dbSJens Wiklander
copy_from_user_private(void * kaddr __unused,const void * uaddr __unused,size_t len __unused)287e4100f3SJens Wiklander static inline TEE_Result copy_from_user_private(void *kaddr __unused,
297e4100f3SJens Wiklander const void *uaddr __unused,
307e4100f3SJens Wiklander size_t len __unused)
317e4100f3SJens Wiklander {
327e4100f3SJens Wiklander return TEE_ERROR_NOT_SUPPORTED;
337e4100f3SJens Wiklander }
347e4100f3SJens Wiklander
copy_from_user(void * kaddr __unused,const void * uaddr __unused,size_t len __unused)35c40a6505SJens Wiklander static inline TEE_Result copy_from_user(void *kaddr __unused,
36c40a6505SJens Wiklander const void *uaddr __unused,
37c40a6505SJens Wiklander size_t len __unused)
38c40a6505SJens Wiklander {
39c40a6505SJens Wiklander return TEE_ERROR_NOT_SUPPORTED;
40c40a6505SJens Wiklander }
417e4100f3SJens Wiklander
copy_to_user_private(void * uaddr __unused,const void * kaddr __unused,size_t len __unused)42f6b5feb1SJens Wiklander static inline TEE_Result copy_to_user_private(void *uaddr __unused,
43f6b5feb1SJens Wiklander const void *kaddr __unused,
44f6b5feb1SJens Wiklander size_t len __unused)
45f6b5feb1SJens Wiklander {
46f6b5feb1SJens Wiklander return TEE_ERROR_NOT_SUPPORTED;
47f6b5feb1SJens Wiklander }
48f6b5feb1SJens Wiklander
copy_to_user(void * uaddr __unused,const void * kaddr __unused,size_t len __unused)49f6b5feb1SJens Wiklander static inline TEE_Result copy_to_user(void *uaddr __unused,
50f6b5feb1SJens Wiklander const void *kaddr __unused,
51f6b5feb1SJens Wiklander size_t len __unused)
52f6b5feb1SJens Wiklander {
53f6b5feb1SJens Wiklander return TEE_ERROR_NOT_SUPPORTED;
54f6b5feb1SJens Wiklander }
55c40a6505SJens Wiklander #endif
56c40a6505SJens Wiklander
57c5a0db99SJens Wiklander /*
58c5a0db99SJens Wiklander * bb_alloc() - Allocate a bounce buffer
59c5a0db99SJens Wiklander * @len: Length of bounce buffer
60c5a0db99SJens Wiklander *
61c5a0db99SJens Wiklander * The bounce buffer is allocated from a per user TA context region reserved
62c5a0db99SJens Wiklander * for bounce buffers. Buffers are allocated in a stack like fashion so
63c5a0db99SJens Wiklander * only the last buffer can be free. Buffers generally don't have to be
64c5a0db99SJens Wiklander * freed, all bounce buffer allocations are reset on each syscall entry.
65c5a0db99SJens Wiklander *
66c5a0db99SJens Wiklander * Return NULL on failure or a valid pointer on success.
67c5a0db99SJens Wiklander */
68c5a0db99SJens Wiklander void *bb_alloc(size_t len);
69c5a0db99SJens Wiklander
70c5a0db99SJens Wiklander /*
71c5a0db99SJens Wiklander * bb_free() - Free a bounce buffer
72c5a0db99SJens Wiklander * @bb: Buffer
73c5a0db99SJens Wiklander * @len: Length of buffer
74c5a0db99SJens Wiklander *
75c5a0db99SJens Wiklander * The bounce buffer is only freed if it is last on the stack of allocated
76c5a0db99SJens Wiklander * bounce buffers. This function does normally not need to be called, see
77c5a0db99SJens Wiklander * description of bb_alloc().
78c5a0db99SJens Wiklander */
79c5a0db99SJens Wiklander void bb_free(void *bb, size_t len);
80c5a0db99SJens Wiklander
81c5a0db99SJens Wiklander /*
82*b39fcd95SJens Wiklander * bb_free_wipe() - Wipe and free a bounce buffer
83*b39fcd95SJens Wiklander * @bb: Buffer
84*b39fcd95SJens Wiklander * @len: Length of buffer
85*b39fcd95SJens Wiklander *
86*b39fcd95SJens Wiklander * The bounce buffer is always wiped if @bb is non-NULL, but only freed if
87*b39fcd95SJens Wiklander * it is last on the stack of allocated bounce buffers.
88*b39fcd95SJens Wiklander */
89*b39fcd95SJens Wiklander void bb_free_wipe(void *bb, size_t len);
90*b39fcd95SJens Wiklander
91*b39fcd95SJens Wiklander /*
92c5a0db99SJens Wiklander * bb_reset() - Reset bounce buffer allocation
93c5a0db99SJens Wiklander *
94c5a0db99SJens Wiklander * Resets the bounce buffer allocatation state, old pointers allocated
95c5a0db99SJens Wiklander * with bb_alloc() should not be used any longer.
96c5a0db99SJens Wiklander */
97c5a0db99SJens Wiklander void bb_reset(void);
98c5a0db99SJens Wiklander
99e5aa0f8cSSeonghyun Park TEE_Result clear_user(void *uaddr, size_t n);
100e5aa0f8cSSeonghyun Park
101e5aa0f8cSSeonghyun Park size_t strnlen_user(const void *s, size_t n);
102e5aa0f8cSSeonghyun Park
103107f49d1SJens Wiklander #define __BB_MEMDUP(memdup_func, src, len, p) ({ \
104107f49d1SJens Wiklander TEE_Result __res = TEE_SUCCESS; \
105107f49d1SJens Wiklander void *__p = NULL; \
106107f49d1SJens Wiklander \
107107f49d1SJens Wiklander __res = memdup_func((src), (len), &__p); \
108107f49d1SJens Wiklander if (!__res) \
109107f49d1SJens Wiklander *(p) = __p; \
110107f49d1SJens Wiklander __res; \
111107f49d1SJens Wiklander })
112107f49d1SJens Wiklander
113e5aa0f8cSSeonghyun Park /*
114e5aa0f8cSSeonghyun Park * bb_memdup_user() - Duplicate a user-space buffer into a bounce buffer
115e5aa0f8cSSeonghyun Park * @src: Pointer to the user buffer to be duplicated.
116e5aa0f8cSSeonghyun Park * @len: Length of the user buffer to be duplicated.
117e5aa0f8cSSeonghyun Park * @p: Holds duplicated bounce buffer on success, or unchanged on failure.
118e5aa0f8cSSeonghyun Park * Note that the returned buffer is allocated by bb_alloc() and
119e5aa0f8cSSeonghyun Park * normally doesn't have to be freed.
120e5aa0f8cSSeonghyun Park * Return TEE_SUCCESS on success.
121e5aa0f8cSSeonghyun Park * Return TEE_ERROR_OUT_OF_MEMORY or TEE_ERROR_ACCESS_DENIED on error.
122e5aa0f8cSSeonghyun Park */
123e5aa0f8cSSeonghyun Park TEE_Result bb_memdup_user(const void *src, size_t len, void **p);
124107f49d1SJens Wiklander #define BB_MEMDUP_USER(src, len, p) \
125107f49d1SJens Wiklander __BB_MEMDUP(bb_memdup_user, (src), (len), (p))
126e5aa0f8cSSeonghyun Park
127e5aa0f8cSSeonghyun Park /*
128e5aa0f8cSSeonghyun Park * bb_memdup_user_private() - Duplicate a private user-space buffer
129e5aa0f8cSSeonghyun Park * @src: Pointer to the user buffer to be duplicated. The buffer should
130e5aa0f8cSSeonghyun Park * be private to current TA (i.e., !TEE_MEMORY_ACCESS_ANY_OWNER).
131e5aa0f8cSSeonghyun Park * @len: Length of the user buffer to be duplicated.
132e5aa0f8cSSeonghyun Park * @p: Holds duplicated kernel buffer on success, or unchanged on failure.
133e5aa0f8cSSeonghyun Park * Note that the returned buffer is allocated by bb_alloc() and
134e5aa0f8cSSeonghyun Park * normally doesn't have to be freed.
135e5aa0f8cSSeonghyun Park * Return TEE_SUCCESS on success.
136e5aa0f8cSSeonghyun Park * Return TEE_ERROR_OUT_OF_MEMORY or TEE_ERROR_ACCESS_DENIED on error.
137e5aa0f8cSSeonghyun Park */
138e5aa0f8cSSeonghyun Park TEE_Result bb_memdup_user_private(const void *src, size_t len, void **p);
139107f49d1SJens Wiklander #define BB_MEMDUP_USER_PRIVATE(src, len, p) \
140107f49d1SJens Wiklander __BB_MEMDUP(bb_memdup_user_private, (src), (len), (p))
141e5aa0f8cSSeonghyun Park
1429c99bb1dSJens Wiklander /*
1439c99bb1dSJens Wiklander * bb_strndup_user() - Duplicate a user-space string into a bounce buffer
1449c99bb1dSJens Wiklander * @src: Pointer to the user string to be duplicated.
1459c99bb1dSJens Wiklander * @maxlen: Maximum length of the user string
1469c99bb1dSJens Wiklander * @dst: Holds duplicated string on success, or unchanged on failure.
1479c99bb1dSJens Wiklander * @dstlen: Length of string, excluding the terminating zero, returned in
1489c99bb1dSJens Wiklander * @dst.
1499c99bb1dSJens Wiklander *
1509c99bb1dSJens Wiklander * Note that the returned buffer is allocated by bb_alloc() and normally
1519c99bb1dSJens Wiklander * doesn't have to be freed. But if it is to be freed the supplied length
1529c99bb1dSJens Wiklander * to bb_free() should be dstlen + 1.
1539c99bb1dSJens Wiklander *
1549c99bb1dSJens Wiklander * Return TEE_SUCCESS on success.
1559c99bb1dSJens Wiklander * Return TEE_ERROR_OUT_OF_MEMORY or TEE_ERROR_ACCESS_DENIED on error.
1569c99bb1dSJens Wiklander */
1579c99bb1dSJens Wiklander TEE_Result bb_strndup_user(const char *src, size_t maxlen, char **dst,
1589c99bb1dSJens Wiklander size_t *dstlen);
1599c99bb1dSJens Wiklander
160c40a6505SJens Wiklander TEE_Result copy_kaddr_to_uref(uint32_t *uref, void *kaddr);
161c40a6505SJens Wiklander
162c40a6505SJens Wiklander uint32_t kaddr_to_uref(void *kaddr);
163c40a6505SJens Wiklander vaddr_t uref_to_vaddr(uint32_t uref);
uref_to_kaddr(uint32_t uref)164c40a6505SJens Wiklander static inline void *uref_to_kaddr(uint32_t uref)
165c40a6505SJens Wiklander {
166c40a6505SJens Wiklander return (void *)uref_to_vaddr(uref);
167c40a6505SJens Wiklander }
168c40a6505SJens Wiklander
169e5aa0f8cSSeonghyun Park #define GET_USER_SCALAR(_x, _p) ({ \
170e5aa0f8cSSeonghyun Park TEE_Result __res = TEE_SUCCESS; \
171e5aa0f8cSSeonghyun Park typeof(_p) __p = (_p); \
172e5aa0f8cSSeonghyun Park \
173e5aa0f8cSSeonghyun Park static_assert(sizeof(_x) == sizeof(*__p)); \
174e5aa0f8cSSeonghyun Park \
175e5aa0f8cSSeonghyun Park __res = copy_from_user(&(_x), (const void *)__p, sizeof(*__p)); \
176e5aa0f8cSSeonghyun Park __res; \
177e5aa0f8cSSeonghyun Park })
178e5aa0f8cSSeonghyun Park
179e5aa0f8cSSeonghyun Park #define PUT_USER_SCALAR(_x, _p) ({ \
180e5aa0f8cSSeonghyun Park TEE_Result __res = TEE_SUCCESS; \
181e5aa0f8cSSeonghyun Park typeof(_p) __p = (_p); \
182e5aa0f8cSSeonghyun Park \
183e5aa0f8cSSeonghyun Park static_assert(sizeof(_x) == sizeof(*__p)); \
184e5aa0f8cSSeonghyun Park \
185e5aa0f8cSSeonghyun Park __res = copy_to_user((void *)__p, &(_x), sizeof(*__p)); \
186e5aa0f8cSSeonghyun Park __res; \
187e5aa0f8cSSeonghyun Park })
188e5aa0f8cSSeonghyun Park
189c40a6505SJens Wiklander #endif /*__KERNEL_USER_ACCESS_H*/
190