1 /*
2 * Copyright (c) 2013, Google, Inc. All rights reserved
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 #include <err.h>
25 #include <lib/trusty/uio.h>
26 #include <string.h>
27
membuf_to_kern_iovec(const struct iovec_kern * iov,uint iov_cnt,const uint8_t * buf,size_t len)28 ssize_t membuf_to_kern_iovec(const struct iovec_kern* iov,
29 uint iov_cnt,
30 const uint8_t* buf,
31 size_t len) {
32 size_t copied = 0;
33
34 if (unlikely(iov_cnt == 0 || len == 0))
35 return 0;
36
37 if (unlikely(iov == NULL || buf == NULL))
38 return (ssize_t)ERR_INVALID_ARGS;
39
40 for (uint i = 0; i < iov_cnt; i++, iov++) {
41 size_t to_copy = len;
42 if (to_copy > iov->iov_len)
43 to_copy = iov->iov_len;
44
45 if (unlikely(to_copy == 0))
46 continue;
47
48 if (unlikely(iov->iov_base == NULL))
49 return (ssize_t)ERR_INVALID_ARGS;
50
51 memcpy(iov->iov_base, buf, to_copy);
52
53 copied += to_copy;
54 buf += to_copy;
55 len -= to_copy;
56
57 if (len == 0)
58 break;
59 }
60
61 return (ssize_t)copied;
62 }
63
kern_iovec_to_membuf(uint8_t * buf,size_t len,const struct iovec_kern * iov,uint iov_cnt)64 ssize_t kern_iovec_to_membuf(uint8_t* buf,
65 size_t len,
66 const struct iovec_kern* iov,
67 uint iov_cnt) {
68 size_t copied = 0;
69
70 if (unlikely(iov_cnt == 0 || len == 0))
71 return 0;
72
73 if (unlikely(buf == NULL || iov == NULL))
74 return (ssize_t)ERR_INVALID_ARGS;
75
76 for (uint i = 0; i < iov_cnt; i++, iov++) {
77 size_t to_copy = len;
78 if (to_copy > iov->iov_len)
79 to_copy = iov->iov_len;
80
81 if (unlikely(to_copy == 0))
82 continue;
83
84 if (unlikely(iov->iov_base == NULL))
85 return (ssize_t)ERR_INVALID_ARGS;
86
87 memcpy(buf, iov->iov_base, to_copy);
88
89 copied += to_copy;
90 buf += to_copy;
91 len -= to_copy;
92
93 if (len == 0)
94 break;
95 }
96
97 return (ssize_t)copied;
98 }
99
membuf_to_user_iovec(user_addr_t iov_uaddr,uint iov_cnt,const uint8_t * buf,size_t len)100 ssize_t membuf_to_user_iovec(user_addr_t iov_uaddr,
101 uint iov_cnt,
102 const uint8_t* buf,
103 size_t len) {
104 status_t ret;
105 size_t copied = 0;
106 struct iovec_user uiov;
107
108 if (unlikely(iov_cnt == 0 || len == 0))
109 return 0;
110
111 if (unlikely(buf == NULL))
112 return (ssize_t)ERR_INVALID_ARGS;
113
114 /* for each iov entry */
115 for (uint i = 0; i < iov_cnt; i++) {
116 /* copy user iovec from user space into local buffer */
117 ret = copy_from_user(&uiov, iov_uaddr + i * sizeof(struct iovec_user),
118 sizeof(struct iovec_user));
119 if (unlikely(ret != NO_ERROR))
120 return (ssize_t)ret;
121
122 size_t to_copy = len;
123 if (to_copy > uiov.iov_len)
124 to_copy = uiov.iov_len;
125
126 /* copy data to user space */
127 ret = copy_to_user(uiov.iov_base, buf, to_copy);
128 if (unlikely(ret != NO_ERROR))
129 return (ssize_t)ret;
130
131 copied += to_copy;
132 buf += to_copy;
133 len -= to_copy;
134
135 if (len == 0)
136 break;
137 ;
138 }
139
140 return (ssize_t)copied;
141 }
142
user_iovec_to_membuf_iter(uint8_t * buf,size_t buf_len,user_addr_t iov_uaddr,struct iovec_iter * iter)143 ssize_t user_iovec_to_membuf_iter(uint8_t* buf,
144 size_t buf_len,
145 user_addr_t iov_uaddr,
146 struct iovec_iter* iter) {
147 status_t ret;
148 size_t copied = 0;
149 struct iovec_user uiov;
150
151 if (unlikely(buf_len == 0))
152 return 0;
153
154 if (unlikely(buf == NULL))
155 return (ssize_t)ERR_INVALID_ARGS;
156
157 while (buf_len > 0 && iovec_iter_has_next(iter)) {
158 /* copy user iovec from user space into local buffer */
159 ret = copy_from_user(
160 &uiov, iov_uaddr + iter->iov_index * sizeof(struct iovec_user),
161 sizeof(struct iovec_user));
162 if (unlikely(ret != NO_ERROR))
163 return (ssize_t)ret;
164
165 /* we've re-read the iov from userspace, it may have changed */
166 if (uiov.iov_len < iter->data_offset)
167 return (ssize_t)ERR_INVALID_ARGS;
168
169 /* figure out how much to copy */
170 size_t to_copy = uiov.iov_len - iter->data_offset;
171 if (to_copy > buf_len)
172 to_copy = buf_len;
173
174 /* copy data from user space */
175 ret = copy_from_user(buf, uiov.iov_base + iter->data_offset, to_copy);
176 if (unlikely(ret != NO_ERROR))
177 return (ssize_t)ret;
178
179 /* update the input state */
180 iter->data_offset += to_copy;
181 if (iter->data_offset >= uiov.iov_len) {
182 iter->iov_index += 1;
183 iter->data_offset = 0;
184 }
185
186 /* update the output state */
187 copied += to_copy;
188 buf += to_copy;
189 buf_len -= to_copy;
190 }
191
192 return (ssize_t)copied;
193 }
194
user_iovec_to_membuf(uint8_t * buf,size_t buf_len,user_addr_t iov_uaddr,uint iov_cnt)195 ssize_t user_iovec_to_membuf(uint8_t* buf,
196 size_t buf_len,
197 user_addr_t iov_uaddr,
198 uint iov_cnt) {
199 struct iovec_iter iter = iovec_iter_create(iov_cnt);
200 return user_iovec_to_membuf_iter(buf, buf_len, iov_uaddr, &iter);
201 }
202