various coverity-inspired fixes
[minix3.git] / kernel / system / do_safecopy.c
blob65f7230f55acd04623570a0ffda9c524dc0a35be
1 /* The kernel call implemented in this file:
2 * m_type: SYS_SAFECOPYFROM or SYS_SAFECOPYTO or SYS_VSAFECOPY
4 * The parameters for this kernel call are:
5 * SCP_FROM_TO other endpoint
6 * SCP_GID grant id
7 * SCP_OFFSET offset within granted space
8 * SCP_ADDRESS address in own address space
9 * SCP_BYTES bytes to be copied
11 * For the vectored variant (do_vsafecopy):
12 * VSCP_VEC_ADDR address of vector
13 * VSCP_VEC_SIZE number of significant elements in vector
16 #include <assert.h>
18 #include "kernel/system.h"
19 #include "kernel.h"
21 #define MAX_INDIRECT_DEPTH 5 /* up to how many indirect grants to follow? */
23 #define MEM_TOP 0xFFFFFFFFUL
25 static int safecopy(struct proc *, endpoint_t, endpoint_t,
26 cp_grant_id_t, size_t, vir_bytes, vir_bytes, int);
28 #define HASGRANTTABLE(gr) \
29 (priv(gr) && priv(gr)->s_grant_table)
31 /*===========================================================================*
32 * verify_grant *
33 *===========================================================================*/
34 int verify_grant(granter, grantee, grant, bytes, access,
35 offset_in, offset_result, e_granter)
36 endpoint_t granter, grantee; /* copyee, copyer */
37 cp_grant_id_t grant; /* grant id */
38 vir_bytes bytes; /* copy size */
39 int access; /* direction (read/write) */
40 vir_bytes offset_in; /* copy offset within grant */
41 vir_bytes *offset_result; /* copy offset within virtual address space */
42 endpoint_t *e_granter; /* new granter (magic grants) */
44 static cp_grant_t g;
45 static int proc_nr;
46 static const struct proc *granter_proc;
47 int depth = 0;
49 do {
50 /* Get granter process slot (if valid), and check range of
51 * grant id.
53 if(!isokendpt(granter, &proc_nr) ) {
54 printf(
55 "grant verify failed: invalid granter %d\n", (int) granter);
56 return(EINVAL);
58 if(!GRANT_VALID(grant)) {
59 printf(
60 "grant verify failed: invalid grant %d\n", (int) grant);
61 return(EINVAL);
63 granter_proc = proc_addr(proc_nr);
65 /* If there is no priv. structure, or no grant table in the
66 * priv. structure, or the grant table in the priv. structure
67 * is too small for the grant, return EPERM.
69 if(!HASGRANTTABLE(granter_proc)) {
70 printf(
71 "grant verify failed: granter %d has no grant table\n",
72 granter);
73 return(EPERM);
76 if(priv(granter_proc)->s_grant_entries <= grant) {
77 printf(
78 "verify_grant: grant verify failed in ep %d "
79 "proc %d: grant %d out of range "
80 "for table size %d\n",
81 granter, proc_nr, grant,
82 priv(granter_proc)->s_grant_entries);
83 return(EPERM);
86 /* Copy the grant entry corresponding to this id to see what it
87 * looks like. If it fails, hide the fact that granter has
88 * (presumably) set an invalid grant table entry by returning
89 * EPERM, just like with an invalid grant id.
91 if(data_copy(granter,
92 priv(granter_proc)->s_grant_table + sizeof(g)*grant,
93 KERNEL, (vir_bytes) &g, sizeof(g)) != OK) {
94 printf(
95 "verify_grant: grant verify: data_copy failed\n");
96 return EPERM;
99 /* Check validity. */
100 if((g.cp_flags & (CPF_USED | CPF_VALID)) !=
101 (CPF_USED | CPF_VALID)) {
102 printf(
103 "verify_grant: grant failed: invalid (%d flags 0x%lx)\n",
104 grant, g.cp_flags);
105 return EPERM;
108 /* The given grant may be an indirect grant, that is, a grant
109 * that provides permission to use a grant given to the
110 * granter (i.e., for which it is the grantee). This can lead
111 * to a chain of indirect grants which must be followed back.
113 if((g.cp_flags & CPF_INDIRECT)) {
114 /* Stop after a few iterations. There may be a loop. */
115 if (depth == MAX_INDIRECT_DEPTH) {
116 printf(
117 "verify grant: indirect grant verify "
118 "failed: exceeded maximum depth\n");
119 return ELOOP;
121 depth++;
123 /* Verify actual grantee. */
124 if(g.cp_u.cp_indirect.cp_who_to != grantee &&
125 grantee != ANY &&
126 g.cp_u.cp_indirect.cp_who_to != ANY) {
127 printf(
128 "verify_grant: indirect grant verify "
129 "failed: bad grantee\n");
130 return EPERM;
133 /* Start over with new granter, grant, and grantee. */
134 grantee = granter;
135 granter = g.cp_u.cp_indirect.cp_who_from;
136 grant = g.cp_u.cp_indirect.cp_grant;
138 } while(g.cp_flags & CPF_INDIRECT);
140 /* Check access of grant. */
141 if(((g.cp_flags & access) != access)) {
142 printf(
143 "verify_grant: grant verify failed: access invalid; want 0x%x, have 0x%x\n",
144 access, g.cp_flags);
145 return EPERM;
148 if((g.cp_flags & CPF_DIRECT)) {
149 /* Don't fiddle around with grants that wrap, arithmetic
150 * below may be confused.
152 if(MEM_TOP - g.cp_u.cp_direct.cp_len + 1 <
153 g.cp_u.cp_direct.cp_start) {
154 printf(
155 "verify_grant: direct grant verify failed: len too long\n");
156 return EPERM;
159 /* Verify actual grantee. */
160 if(g.cp_u.cp_direct.cp_who_to != grantee && grantee != ANY
161 && g.cp_u.cp_direct.cp_who_to != ANY) {
162 printf(
163 "verify_grant: direct grant verify failed: bad grantee\n");
164 return EPERM;
167 /* Verify actual copy range. */
168 if((offset_in+bytes < offset_in) ||
169 offset_in+bytes > g.cp_u.cp_direct.cp_len) {
170 printf(
171 "verify_grant: direct grant verify failed: bad size or range. "
172 "granted %d bytes @ 0x%lx; wanted %d bytes @ 0x%lx\n",
173 g.cp_u.cp_direct.cp_len,
174 g.cp_u.cp_direct.cp_start,
175 bytes, offset_in);
176 return EPERM;
179 /* Verify successful - tell caller what address it is. */
180 *offset_result = g.cp_u.cp_direct.cp_start + offset_in;
181 *e_granter = granter;
182 } else if(g.cp_flags & CPF_MAGIC) {
183 /* Currently, it is hardcoded that only FS may do
184 * magic grants.
186 if(granter != VFS_PROC_NR) {
187 printf(
188 "verify_grant: magic grant verify failed: granter (%d) "
189 "is not FS (%d)\n", granter, VFS_PROC_NR);
190 return EPERM;
193 /* Verify actual grantee. */
194 if(g.cp_u.cp_magic.cp_who_to != grantee && grantee != ANY
195 && g.cp_u.cp_direct.cp_who_to != ANY) {
196 printf(
197 "verify_grant: magic grant verify failed: bad grantee\n");
198 return EPERM;
201 /* Verify actual copy range. */
202 if((offset_in+bytes < offset_in) ||
203 offset_in+bytes > g.cp_u.cp_magic.cp_len) {
204 printf(
205 "verify_grant: magic grant verify failed: bad size or range. "
206 "granted %d bytes @ 0x%lx; wanted %d bytes @ 0x%lx\n",
207 g.cp_u.cp_magic.cp_len,
208 g.cp_u.cp_magic.cp_start,
209 bytes, offset_in);
210 return EPERM;
213 /* Verify successful - tell caller what address it is. */
214 *offset_result = g.cp_u.cp_magic.cp_start + offset_in;
215 *e_granter = g.cp_u.cp_magic.cp_who_from;
216 } else {
217 printf(
218 "verify_grant: grant verify failed: unknown grant type\n");
219 return EPERM;
222 return OK;
225 /*===========================================================================*
226 * safecopy *
227 *===========================================================================*/
228 static int safecopy(caller, granter, grantee, grantid, bytes,
229 g_offset, addr, access)
230 struct proc * caller;
231 endpoint_t granter, grantee;
232 cp_grant_id_t grantid;
233 size_t bytes;
234 vir_bytes g_offset, addr;
235 int access; /* CPF_READ for a copy from granter to grantee, CPF_WRITE
236 * for a copy from grantee to granter.
239 static struct vir_addr v_src, v_dst;
240 static vir_bytes v_offset;
241 endpoint_t new_granter, *src, *dst;
242 struct proc *granter_p;
243 int r;
244 #if PERF_USE_COW_SAFECOPY
245 vir_bytes size;
246 #endif
248 if(granter == NONE || grantee == NONE) {
249 printf("safecopy: nonsense processes\n");
250 return EFAULT;
253 /* See if there is a reasonable grant table. */
254 if(!(granter_p = endpoint_lookup(granter))) return EINVAL;
255 if(!HASGRANTTABLE(granter_p)) {
256 printf(
257 "safecopy failed: granter %d has no grant table\n", granter);
258 return(EPERM);
261 /* Decide who is src and who is dst. */
262 if(access & CPF_READ) {
263 src = &granter;
264 dst = &grantee;
265 } else {
266 src = &grantee;
267 dst = &granter;
270 /* Verify permission exists. */
271 if((r=verify_grant(granter, grantee, grantid, bytes, access,
272 g_offset, &v_offset, &new_granter)) != OK) {
273 printf(
274 "grant %d verify to copy %d->%d by %d failed: err %d\n",
275 grantid, *src, *dst, grantee, r);
276 return r;
279 /* verify_grant() can redirect the grantee to someone else,
280 * meaning the source or destination changes.
282 granter = new_granter;
284 /* Now it's a regular copy. */
285 v_src.proc_nr_e = *src;
286 v_dst.proc_nr_e = *dst;
288 /* Now the offset in virtual addressing is known in 'offset'.
289 * Depending on the access, this is the source or destination
290 * address.
292 if(access & CPF_READ) {
293 v_src.offset = v_offset;
294 v_dst.offset = (vir_bytes) addr;
295 } else {
296 v_src.offset = (vir_bytes) addr;
297 v_dst.offset = v_offset;
300 /* Do the regular copy. */
301 #if PERF_USE_COW_SAFECOPY
302 if(v_offset % CLICK_SIZE != addr % CLICK_SIZE || bytes < CLICK_SIZE) {
303 /* Give up on COW immediately when offsets are not aligned
304 * or we are copying less than a page.
306 return virtual_copy_vmcheck(caller, &v_src, &v_dst, bytes);
309 if((size = v_offset % CLICK_SIZE) != 0) {
310 /* Normal copy for everything before the first page boundary. */
311 size = CLICK_SIZE - size;
312 r = virtual_copy_vmcheck(caller, &v_src, &v_dst, size);
313 if(r != OK)
314 return r;
315 v_src.offset += size;
316 v_dst.offset += size;
317 bytes -= size;
319 if((size = bytes / CLICK_SIZE) != 0) {
320 /* Use COW optimization when copying entire pages. */
321 size *= CLICK_SIZE;
322 r = map_invoke_vm(VMPTYPE_COWMAP,
323 v_dst.proc_nr_e, v_dst.segment, v_dst.offset,
324 v_src.proc_nr_e, v_src.segment, v_src.offset,
325 size, 0);
326 if(r != OK)
327 return r;
328 v_src.offset += size;
329 v_dst.offset += size;
330 bytes -= size;
332 if(bytes != 0) {
333 /* Normal copy for everything after the last page boundary. */
334 r = virtual_copy_vmcheck(caller, &v_src, &v_dst, bytes);
335 if(r != OK)
336 return r;
339 return OK;
340 #else
341 return virtual_copy_vmcheck(caller, &v_src, &v_dst, bytes);
342 #endif
345 /*===========================================================================*
346 * do_safecopy_to *
347 *===========================================================================*/
348 int do_safecopy_to(struct proc * caller, message * m_ptr)
350 return safecopy(caller, m_ptr->SCP_FROM_TO, caller->p_endpoint,
351 (cp_grant_id_t) m_ptr->SCP_GID,
352 m_ptr->SCP_BYTES, m_ptr->SCP_OFFSET,
353 (vir_bytes) m_ptr->SCP_ADDRESS, CPF_WRITE);
356 /*===========================================================================*
357 * do_safecopy_from *
358 *===========================================================================*/
359 int do_safecopy_from(struct proc * caller, message * m_ptr)
361 return safecopy(caller, m_ptr->SCP_FROM_TO, caller->p_endpoint,
362 (cp_grant_id_t) m_ptr->SCP_GID,
363 m_ptr->SCP_BYTES, m_ptr->SCP_OFFSET,
364 (vir_bytes) m_ptr->SCP_ADDRESS, CPF_READ);
367 /*===========================================================================*
368 * do_vsafecopy *
369 *===========================================================================*/
370 int do_vsafecopy(struct proc * caller, message * m_ptr)
372 static struct vscp_vec vec[SCPVEC_NR];
373 static struct vir_addr src, dst;
374 int r, i, els;
375 size_t bytes;
377 /* Set vector copy parameters. */
378 src.proc_nr_e = caller->p_endpoint;
379 assert(src.proc_nr_e != NONE);
380 src.offset = (vir_bytes) m_ptr->VSCP_VEC_ADDR;
381 dst.proc_nr_e = KERNEL;
382 dst.offset = (vir_bytes) vec;
384 /* No. of vector elements. */
385 els = m_ptr->VSCP_VEC_SIZE;
386 bytes = els * sizeof(struct vscp_vec);
388 /* Obtain vector of copies. */
389 if((r=virtual_copy_vmcheck(caller, &src, &dst, bytes)) != OK)
390 return r;
392 /* Perform safecopies. */
393 for(i = 0; i < els; i++) {
394 int access;
395 endpoint_t granter;
396 if(vec[i].v_from == SELF) {
397 access = CPF_WRITE;
398 granter = vec[i].v_to;
399 } else if(vec[i].v_to == SELF) {
400 access = CPF_READ;
401 granter = vec[i].v_from;
402 } else {
403 printf("vsafecopy: %d: element %d/%d: no SELF found\n",
404 caller->p_endpoint, i, els);
405 return EINVAL;
408 /* Do safecopy for this element. */
409 if((r=safecopy(caller, granter, caller->p_endpoint,
410 vec[i].v_gid,
411 vec[i].v_bytes, vec[i].v_offset,
412 vec[i].v_addr, access)) != OK) {
413 return r;
417 return OK;