make vfs & filesystems use failable copying
[minix3.git] / kernel / system / do_safecopy.c
blob62cb6a7c04e8b57d1326a466931ab4ea1ff5ab91
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/kernel.h"
20 #include "kernel/vm.h"
22 #define MAX_INDIRECT_DEPTH 5 /* up to how many indirect grants to follow? */
24 #define MEM_TOP 0xFFFFFFFFUL
26 static int safecopy(struct proc *, endpoint_t, endpoint_t,
27 cp_grant_id_t, size_t, vir_bytes, vir_bytes, int);
29 #define HASGRANTTABLE(gr) \
30 (priv(gr) && priv(gr)->s_grant_table)
32 /*===========================================================================*
33 * verify_grant *
34 *===========================================================================*/
35 int verify_grant(granter, grantee, grant, bytes, access,
36 offset_in, offset_result, e_granter, flags)
37 endpoint_t granter, grantee; /* copyee, copyer */
38 cp_grant_id_t grant; /* grant id */
39 vir_bytes bytes; /* copy size */
40 int access; /* direction (read/write) */
41 vir_bytes offset_in; /* copy offset within grant */
42 vir_bytes *offset_result; /* copy offset within virtual address space */
43 endpoint_t *e_granter; /* new granter (magic grants) */
44 u32_t *flags; /* CPF_* */
46 static cp_grant_t g;
47 static int proc_nr;
48 static const struct proc *granter_proc;
49 int depth = 0;
51 do {
52 /* Get granter process slot (if valid), and check range of
53 * grant id.
55 if(!isokendpt(granter, &proc_nr) ) {
56 printf(
57 "grant verify failed: invalid granter %d\n", (int) granter);
58 return(EINVAL);
60 if(!GRANT_VALID(grant)) {
61 printf(
62 "grant verify failed: invalid grant %d\n", (int) grant);
63 return(EINVAL);
65 granter_proc = proc_addr(proc_nr);
67 /* If there is no priv. structure, or no grant table in the
68 * priv. structure, or the grant table in the priv. structure
69 * is too small for the grant, return EPERM.
71 if(!HASGRANTTABLE(granter_proc)) {
72 printf(
73 "grant verify failed: granter %d has no grant table\n",
74 granter);
75 return(EPERM);
78 if(priv(granter_proc)->s_grant_entries <= grant) {
79 printf(
80 "verify_grant: grant verify failed in ep %d "
81 "proc %d: grant %d out of range "
82 "for table size %d\n",
83 granter, proc_nr, grant,
84 priv(granter_proc)->s_grant_entries);
85 return(EPERM);
88 /* Copy the grant entry corresponding to this id to see what it
89 * looks like. If it fails, hide the fact that granter has
90 * (presumably) set an invalid grant table entry by returning
91 * EPERM, just like with an invalid grant id.
93 if(data_copy(granter,
94 priv(granter_proc)->s_grant_table + sizeof(g)*grant,
95 KERNEL, (vir_bytes) &g, sizeof(g)) != OK) {
96 printf(
97 "verify_grant: grant verify: data_copy failed\n");
98 return EPERM;
101 if(flags) *flags = g.cp_flags;
103 /* Check validity. */
104 if((g.cp_flags & (CPF_USED | CPF_VALID)) !=
105 (CPF_USED | CPF_VALID)) {
106 printf(
107 "verify_grant: grant failed: invalid (%d flags 0x%lx)\n",
108 grant, g.cp_flags);
109 return EPERM;
112 /* The given grant may be an indirect grant, that is, a grant
113 * that provides permission to use a grant given to the
114 * granter (i.e., for which it is the grantee). This can lead
115 * to a chain of indirect grants which must be followed back.
117 if((g.cp_flags & CPF_INDIRECT)) {
118 /* Stop after a few iterations. There may be a loop. */
119 if (depth == MAX_INDIRECT_DEPTH) {
120 printf(
121 "verify grant: indirect grant verify "
122 "failed: exceeded maximum depth\n");
123 return ELOOP;
125 depth++;
127 /* Verify actual grantee. */
128 if(g.cp_u.cp_indirect.cp_who_to != grantee &&
129 grantee != ANY &&
130 g.cp_u.cp_indirect.cp_who_to != ANY) {
131 printf(
132 "verify_grant: indirect grant verify "
133 "failed: bad grantee\n");
134 return EPERM;
137 /* Start over with new granter, grant, and grantee. */
138 grantee = granter;
139 granter = g.cp_u.cp_indirect.cp_who_from;
140 grant = g.cp_u.cp_indirect.cp_grant;
142 } while(g.cp_flags & CPF_INDIRECT);
144 /* Check access of grant. */
145 if(((g.cp_flags & access) != access)) {
146 printf(
147 "verify_grant: grant verify failed: access invalid; want 0x%x, have 0x%x\n",
148 access, g.cp_flags);
149 return EPERM;
152 if((g.cp_flags & CPF_DIRECT)) {
153 /* Don't fiddle around with grants that wrap, arithmetic
154 * below may be confused.
156 if(MEM_TOP - g.cp_u.cp_direct.cp_len + 1 <
157 g.cp_u.cp_direct.cp_start) {
158 printf(
159 "verify_grant: direct grant verify failed: len too long\n");
160 return EPERM;
163 /* Verify actual grantee. */
164 if(g.cp_u.cp_direct.cp_who_to != grantee && grantee != ANY
165 && g.cp_u.cp_direct.cp_who_to != ANY) {
166 printf(
167 "verify_grant: direct grant verify failed: bad grantee\n");
168 return EPERM;
171 /* Verify actual copy range. */
172 if((offset_in+bytes < offset_in) ||
173 offset_in+bytes > g.cp_u.cp_direct.cp_len) {
174 printf(
175 "verify_grant: direct grant verify failed: bad size or range. "
176 "granted %d bytes @ 0x%lx; wanted %d bytes @ 0x%lx\n",
177 g.cp_u.cp_direct.cp_len,
178 g.cp_u.cp_direct.cp_start,
179 bytes, offset_in);
180 return EPERM;
183 /* Verify successful - tell caller what address it is. */
184 *offset_result = g.cp_u.cp_direct.cp_start + offset_in;
185 *e_granter = granter;
186 } else if(g.cp_flags & CPF_MAGIC) {
187 /* Currently, it is hardcoded that only FS may do
188 * magic grants.
190 if(granter != VFS_PROC_NR) {
191 printf(
192 "verify_grant: magic grant verify failed: granter (%d) "
193 "is not FS (%d)\n", granter, VFS_PROC_NR);
194 return EPERM;
197 /* Verify actual grantee. */
198 if(g.cp_u.cp_magic.cp_who_to != grantee && grantee != ANY
199 && g.cp_u.cp_direct.cp_who_to != ANY) {
200 printf(
201 "verify_grant: magic grant verify failed: bad grantee\n");
202 return EPERM;
205 /* Verify actual copy range. */
206 if((offset_in+bytes < offset_in) ||
207 offset_in+bytes > g.cp_u.cp_magic.cp_len) {
208 printf(
209 "verify_grant: magic grant verify failed: bad size or range. "
210 "granted %d bytes @ 0x%lx; wanted %d bytes @ 0x%lx\n",
211 g.cp_u.cp_magic.cp_len,
212 g.cp_u.cp_magic.cp_start,
213 bytes, offset_in);
214 return EPERM;
217 /* Verify successful - tell caller what address it is. */
218 *offset_result = g.cp_u.cp_magic.cp_start + offset_in;
219 *e_granter = g.cp_u.cp_magic.cp_who_from;
220 } else {
221 printf(
222 "verify_grant: grant verify failed: unknown grant type\n");
223 return EPERM;
226 return OK;
229 /*===========================================================================*
230 * safecopy *
231 *===========================================================================*/
232 static int safecopy(caller, granter, grantee, grantid, bytes,
233 g_offset, addr, access)
234 struct proc * caller;
235 endpoint_t granter, grantee;
236 cp_grant_id_t grantid;
237 size_t bytes;
238 vir_bytes g_offset, addr;
239 int access; /* CPF_READ for a copy from granter to grantee, CPF_WRITE
240 * for a copy from grantee to granter.
243 static struct vir_addr v_src, v_dst;
244 static vir_bytes v_offset;
245 endpoint_t new_granter, *src, *dst;
246 struct proc *granter_p;
247 int r;
248 u32_t flags;
249 #if PERF_USE_COW_SAFECOPY
250 vir_bytes size;
251 #endif
253 if(granter == NONE || grantee == NONE) {
254 printf("safecopy: nonsense processes\n");
255 return EFAULT;
258 /* See if there is a reasonable grant table. */
259 if(!(granter_p = endpoint_lookup(granter))) return EINVAL;
260 if(!HASGRANTTABLE(granter_p)) {
261 printf(
262 "safecopy failed: granter %d has no grant table\n", granter);
263 return(EPERM);
266 /* Decide who is src and who is dst. */
267 if(access & CPF_READ) {
268 src = &granter;
269 dst = &grantee;
270 } else {
271 src = &grantee;
272 dst = &granter;
275 /* Verify permission exists. */
276 if((r=verify_grant(granter, grantee, grantid, bytes, access,
277 g_offset, &v_offset, &new_granter, &flags)) != OK) {
278 printf(
279 "grant %d verify to copy %d->%d by %d failed: err %d\n",
280 grantid, *src, *dst, grantee, r);
281 return r;
284 /* verify_grant() can redirect the grantee to someone else,
285 * meaning the source or destination changes.
287 granter = new_granter;
289 /* Now it's a regular copy. */
290 v_src.proc_nr_e = *src;
291 v_dst.proc_nr_e = *dst;
293 /* Now the offset in virtual addressing is known in 'offset'.
294 * Depending on the access, this is the source or destination
295 * address.
297 if(access & CPF_READ) {
298 v_src.offset = v_offset;
299 v_dst.offset = (vir_bytes) addr;
300 } else {
301 v_src.offset = (vir_bytes) addr;
302 v_dst.offset = v_offset;
305 /* Do the regular copy. */
306 if(flags & CPF_TRY) {
307 int r;
308 /* Try copy without transparently faulting in pages. */
309 r = virtual_copy(&v_src, &v_dst, bytes);
310 if(r == EFAULT_SRC || r == EFAULT_DST) return EFAULT;
311 return r;
313 return virtual_copy_vmcheck(caller, &v_src, &v_dst, bytes);
316 /*===========================================================================*
317 * do_safecopy_to *
318 *===========================================================================*/
319 int do_safecopy_to(struct proc * caller, message * m_ptr)
321 return safecopy(caller, m_ptr->SCP_FROM_TO, caller->p_endpoint,
322 (cp_grant_id_t) m_ptr->SCP_GID,
323 m_ptr->SCP_BYTES, m_ptr->SCP_OFFSET,
324 (vir_bytes) m_ptr->SCP_ADDRESS, CPF_WRITE);
327 /*===========================================================================*
328 * do_safecopy_from *
329 *===========================================================================*/
330 int do_safecopy_from(struct proc * caller, message * m_ptr)
332 return safecopy(caller, m_ptr->SCP_FROM_TO, caller->p_endpoint,
333 (cp_grant_id_t) m_ptr->SCP_GID,
334 m_ptr->SCP_BYTES, m_ptr->SCP_OFFSET,
335 (vir_bytes) m_ptr->SCP_ADDRESS, CPF_READ);
338 /*===========================================================================*
339 * do_vsafecopy *
340 *===========================================================================*/
341 int do_vsafecopy(struct proc * caller, message * m_ptr)
343 static struct vscp_vec vec[SCPVEC_NR];
344 static struct vir_addr src, dst;
345 int r, i, els;
346 size_t bytes;
348 /* Set vector copy parameters. */
349 src.proc_nr_e = caller->p_endpoint;
350 assert(src.proc_nr_e != NONE);
351 src.offset = (vir_bytes) m_ptr->VSCP_VEC_ADDR;
352 dst.proc_nr_e = KERNEL;
353 dst.offset = (vir_bytes) vec;
355 /* No. of vector elements. */
356 els = m_ptr->VSCP_VEC_SIZE;
357 bytes = els * sizeof(struct vscp_vec);
359 /* Obtain vector of copies. */
360 if((r=virtual_copy_vmcheck(caller, &src, &dst, bytes)) != OK)
361 return r;
363 /* Perform safecopies. */
364 for(i = 0; i < els; i++) {
365 int access;
366 endpoint_t granter;
367 if(vec[i].v_from == SELF) {
368 access = CPF_WRITE;
369 granter = vec[i].v_to;
370 } else if(vec[i].v_to == SELF) {
371 access = CPF_READ;
372 granter = vec[i].v_from;
373 } else {
374 printf("vsafecopy: %d: element %d/%d: no SELF found\n",
375 caller->p_endpoint, i, els);
376 return EINVAL;
379 /* Do safecopy for this element. */
380 if((r=safecopy(caller, granter, caller->p_endpoint,
381 vec[i].v_gid,
382 vec[i].v_bytes, vec[i].v_offset,
383 vec[i].v_addr, access)) != OK) {
384 return r;
388 return OK;