Remove building with NOCRYPTO option
[minix.git] / minix / kernel / system / do_safecopy.c
blob83ad0ad4ecf98903eaef15b3a9109377ba491479
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 * m_lsys_kern_safecopy.from_to other endpoint
6 * m_lsys_kern_safecopy.gid grant id
7 * m_lsys_kern_safecopy.offset offset within granted space
8 * m_lsys_kern_safecopy.address address in own address space
9 * m_lsys_kern_safecopy.bytes bytes to be copied
11 * For the vectored variant (do_vsafecopy):
12 * m_lsys_kern_vsafecopy.vec_addr address of vector
13 * m_lsys_kern_vsafecopy.vec_size number of significant elements in vector
16 #include <assert.h>
18 #include "kernel/system.h"
19 #include "kernel/vm.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 struct cp_sfinfo { /* information for handling soft faults */
32 int try; /* if nonzero, try copy only, stop on fault */
33 endpoint_t endpt; /* endpoint owning grant with CPF_TRY flag */
34 vir_bytes addr; /* address to write mark upon soft fault */
35 cp_grant_id_t value; /* grant ID to use as mark value to write */
38 /*===========================================================================*
39 * verify_grant *
40 *===========================================================================*/
41 int verify_grant(
42 endpoint_t granter, /* copyee */
43 endpoint_t grantee, /* copyer */
44 cp_grant_id_t grant, /* grant id */
45 vir_bytes bytes, /* copy size */
46 int access, /* direction (read/write) */
47 vir_bytes offset_in, /* copy offset within grant */
48 vir_bytes *offset_result, /* copy offset within virtual address space */
49 endpoint_t *e_granter, /* new granter (magic grants) */
50 struct cp_sfinfo *sfinfo /* storage for soft fault information */
53 cp_grant_t g;
54 int proc_nr;
55 const struct proc *granter_proc;
56 int grant_idx, grant_seq;
57 int depth = 0;
59 do {
60 /* Get granter process slot (if valid), and check range of
61 * grant id.
63 if(!isokendpt(granter, &proc_nr) ) {
64 printf(
65 "grant verify failed: invalid granter %d\n", (int) granter);
66 return(EINVAL);
68 if(!GRANT_VALID(grant)) {
69 printf(
70 "grant verify failed: invalid grant %d\n", (int) grant);
71 return(EINVAL);
73 granter_proc = proc_addr(proc_nr);
75 /* If the granter has a temporary grant table, always allow
76 * requests with unspecified access and return ENOTREADY if
77 * no grant table is present or if the grantee's endpoint is not
78 * the endpoint the table belongs to. When ENOTREADY is returned
79 * the same verify_grant() request will be replayed again in a
80 * while until the grant table is final. This is necessary to
81 * avoid races at live update time.
83 if(priv(granter_proc)->s_grant_endpoint != granter_proc->p_endpoint) {
84 if(!access) {
85 return OK;
87 else if(!HASGRANTTABLE(granter_proc) || grantee != priv(granter_proc)->s_grant_endpoint) {
88 return ENOTREADY;
92 /* If there is no priv. structure, or no grant table in the
93 * priv. structure, or the grant table in the priv. structure
94 * is too small for the grant, return EPERM.
96 if(!HASGRANTTABLE(granter_proc)) {
97 printf(
98 "grant verify failed: granter %d has no grant table\n",
99 granter);
100 return(EPERM);
103 grant_idx = GRANT_IDX(grant);
104 grant_seq = GRANT_SEQ(grant);
106 if(priv(granter_proc)->s_grant_entries <= grant_idx) {
107 printf(
108 "verify_grant: grant verify failed in ep %d "
109 "proc %d: grant 0x%x (#%d) out of range "
110 "for table size %d\n",
111 granter, proc_nr, grant, grant_idx,
112 priv(granter_proc)->s_grant_entries);
113 return(EPERM);
116 /* Copy the grant entry corresponding to this ID's index to see
117 * what it looks like. If it fails, hide the fact that granter
118 * has (presumably) set an invalid grant table entry by
119 * returning EPERM, just like with an invalid grant id.
121 if(data_copy(granter, priv(granter_proc)->s_grant_table +
122 sizeof(g) * grant_idx,
123 KERNEL, (vir_bytes) &g, sizeof(g)) != OK) {
124 printf(
125 "verify_grant: grant verify: data_copy failed\n");
126 return EPERM;
129 /* Check validity: flags and sequence number. */
130 if((g.cp_flags & (CPF_USED | CPF_VALID)) !=
131 (CPF_USED | CPF_VALID)) {
132 printf("verify_grant: grant failed: invalid flags "
133 "(0x%x, 0x%lx)\n", grant, g.cp_flags);
134 return EPERM;
137 if (g.cp_seq != grant_seq) {
138 printf("verify_grant: grant failed: invalid sequence "
139 "(0x%x, %d vs %d)\n", grant, grant_seq, g.cp_seq);
140 return EPERM;
143 /* The given grant may be an indirect grant, that is, a grant
144 * that provides permission to use a grant given to the
145 * granter (i.e., for which it is the grantee). This can lead
146 * to a chain of indirect grants which must be followed back.
148 if((g.cp_flags & CPF_INDIRECT)) {
149 /* Stop after a few iterations. There may be a loop. */
150 if (depth == MAX_INDIRECT_DEPTH) {
151 printf(
152 "verify grant: indirect grant verify "
153 "failed: exceeded maximum depth\n");
154 return ELOOP;
156 depth++;
158 /* Verify actual grantee. */
159 if(g.cp_u.cp_indirect.cp_who_to != grantee &&
160 grantee != ANY &&
161 g.cp_u.cp_indirect.cp_who_to != ANY) {
162 printf(
163 "verify_grant: indirect grant verify "
164 "failed: bad grantee\n");
165 return EPERM;
168 /* Start over with new granter, grant, and grantee. */
169 grantee = granter;
170 granter = g.cp_u.cp_indirect.cp_who_from;
171 grant = g.cp_u.cp_indirect.cp_grant;
173 } while(g.cp_flags & CPF_INDIRECT);
175 /* Check access of grant. */
176 if(((g.cp_flags & access) != access)) {
177 printf(
178 "verify_grant: grant verify failed: access invalid; want 0x%x, have 0x%x\n",
179 access, g.cp_flags);
180 return EPERM;
183 if((g.cp_flags & CPF_DIRECT)) {
184 /* Don't fiddle around with grants that wrap, arithmetic
185 * below may be confused.
187 if(MEM_TOP - g.cp_u.cp_direct.cp_len + 1 <
188 g.cp_u.cp_direct.cp_start) {
189 printf(
190 "verify_grant: direct grant verify failed: len too long\n");
191 return EPERM;
194 /* Verify actual grantee. */
195 if(g.cp_u.cp_direct.cp_who_to != grantee && grantee != ANY
196 && g.cp_u.cp_direct.cp_who_to != ANY) {
197 printf(
198 "verify_grant: direct grant verify failed: bad grantee\n");
199 return EPERM;
202 /* Verify actual copy range. */
203 if((offset_in+bytes < offset_in) ||
204 offset_in+bytes > g.cp_u.cp_direct.cp_len) {
205 printf(
206 "verify_grant: direct grant verify failed: bad size or range. "
207 "granted %d bytes @ 0x%lx; wanted %d bytes @ 0x%lx\n",
208 g.cp_u.cp_direct.cp_len,
209 g.cp_u.cp_direct.cp_start,
210 bytes, offset_in);
211 return EPERM;
214 /* Verify successful - tell caller what address it is. */
215 *offset_result = g.cp_u.cp_direct.cp_start + offset_in;
216 *e_granter = granter;
217 } else if(g.cp_flags & CPF_MAGIC) {
218 /* Currently, it is hardcoded that only VFS and MIB may do
219 * magic grants. TODO: this should be a system.conf flag.
221 if(granter != VFS_PROC_NR && granter != MIB_PROC_NR) {
222 printf(
223 "verify_grant: magic grant verify failed: granter (%d) "
224 "not allowed\n", granter);
225 return EPERM;
228 /* Verify actual grantee. */
229 if(g.cp_u.cp_magic.cp_who_to != grantee && grantee != ANY
230 && g.cp_u.cp_direct.cp_who_to != ANY) {
231 printf(
232 "verify_grant: magic grant verify failed: bad grantee\n");
233 return EPERM;
236 /* Verify actual copy range. */
237 if((offset_in+bytes < offset_in) ||
238 offset_in+bytes > g.cp_u.cp_magic.cp_len) {
239 printf(
240 "verify_grant: magic grant verify failed: bad size or range. "
241 "granted %d bytes @ 0x%lx; wanted %d bytes @ 0x%lx\n",
242 g.cp_u.cp_magic.cp_len,
243 g.cp_u.cp_magic.cp_start,
244 bytes, offset_in);
245 return EPERM;
248 /* Verify successful - tell caller what address it is. */
249 *offset_result = g.cp_u.cp_magic.cp_start + offset_in;
250 *e_granter = g.cp_u.cp_magic.cp_who_from;
251 } else {
252 printf(
253 "verify_grant: grant verify failed: unknown grant type\n");
254 return EPERM;
257 /* If requested, store information regarding soft faults. */
258 if (sfinfo != NULL && (sfinfo->try = !!(g.cp_flags & CPF_TRY))) {
259 sfinfo->endpt = granter;
260 sfinfo->addr = priv(granter_proc)->s_grant_table +
261 sizeof(g) * grant_idx + offsetof(cp_grant_t, cp_faulted);
262 sfinfo->value = grant;
265 return OK;
268 /*===========================================================================*
269 * safecopy *
270 *===========================================================================*/
271 static int safecopy(
272 struct proc * caller,
273 endpoint_t granter,
274 endpoint_t grantee,
275 cp_grant_id_t grantid,
276 size_t bytes,
277 vir_bytes g_offset,
278 vir_bytes addr,
279 int access /* CPF_READ for a copy from granter to grantee, CPF_WRITE
280 * for a copy from grantee to granter.
284 static struct vir_addr v_src, v_dst;
285 static vir_bytes v_offset;
286 endpoint_t new_granter, *src, *dst;
287 int r;
288 struct cp_sfinfo sfinfo;
290 if(granter == NONE || grantee == NONE) {
291 printf("safecopy: nonsense processes\n");
292 return EFAULT;
295 /* Decide who is src and who is dst. */
296 if(access & CPF_READ) {
297 src = &granter;
298 dst = &grantee;
299 } else {
300 src = &grantee;
301 dst = &granter;
304 /* Verify permission exists. */
305 if((r=verify_grant(granter, grantee, grantid, bytes, access,
306 g_offset, &v_offset, &new_granter, &sfinfo)) != OK) {
307 if(r == ENOTREADY) return r;
308 printf(
309 "grant %d verify to copy %d->%d by %d failed: err %d\n",
310 grantid, *src, *dst, grantee, r);
311 return r;
314 /* verify_grant() can redirect the grantee to someone else,
315 * meaning the source or destination changes.
317 granter = new_granter;
319 /* Now it's a regular copy. */
320 v_src.proc_nr_e = *src;
321 v_dst.proc_nr_e = *dst;
323 /* Now the offset in virtual addressing is known in 'offset'.
324 * Depending on the access, this is the source or destination
325 * address.
327 if(access & CPF_READ) {
328 v_src.offset = v_offset;
329 v_dst.offset = (vir_bytes) addr;
330 } else {
331 v_src.offset = (vir_bytes) addr;
332 v_dst.offset = v_offset;
335 /* Do the regular copy. */
336 if (sfinfo.try) {
338 * Try copying without transparently faulting in pages.
339 * TODO: while CPF_TRY is meant to protect against deadlocks on
340 * memory-mapped files in file systems, it seems that this case
341 * triggers faults a whole lot more often, resulting in extra
342 * overhead due to retried file system operations. It might be
343 * a good idea to go through VM even in this case, and have VM
344 * fail (only) if the affected page belongs to a file mapping.
346 r = virtual_copy(&v_src, &v_dst, bytes);
347 if (r == EFAULT_SRC || r == EFAULT_DST) {
349 * Mark the magic grant as having experienced a soft
350 * fault during its lifetime. The exact value does not
351 * matter, but we use the grant ID (including its
352 * sequence number) as a form of protection in the
353 * light of CPU concurrency.
355 r = data_copy(KERNEL, (vir_bytes)&sfinfo.value,
356 sfinfo.endpt, sfinfo.addr, sizeof(sfinfo.value));
358 * Failure means the creator of the magic grant messed
359 * up, which can only be unintentional, so report..
361 if (r != OK)
362 printf("Kernel: writing soft fault marker %d "
363 "into %d at 0x%lx failed (%d)\n",
364 sfinfo.value, sfinfo.endpt, sfinfo.addr,
367 return EFAULT;
369 return r;
371 return virtual_copy_vmcheck(caller, &v_src, &v_dst, bytes);
374 /*===========================================================================*
375 * do_safecopy_to *
376 *===========================================================================*/
377 int do_safecopy_to(struct proc * caller, message * m_ptr)
379 return safecopy(caller, m_ptr->m_lsys_kern_safecopy.from_to, caller->p_endpoint,
380 (cp_grant_id_t) m_ptr->m_lsys_kern_safecopy.gid,
381 m_ptr->m_lsys_kern_safecopy.bytes, m_ptr->m_lsys_kern_safecopy.offset,
382 (vir_bytes) m_ptr->m_lsys_kern_safecopy.address, CPF_WRITE);
385 /*===========================================================================*
386 * do_safecopy_from *
387 *===========================================================================*/
388 int do_safecopy_from(struct proc * caller, message * m_ptr)
390 return safecopy(caller, m_ptr->m_lsys_kern_safecopy.from_to, caller->p_endpoint,
391 (cp_grant_id_t) m_ptr->m_lsys_kern_safecopy.gid,
392 m_ptr->m_lsys_kern_safecopy.bytes, m_ptr->m_lsys_kern_safecopy.offset,
393 (vir_bytes) m_ptr->m_lsys_kern_safecopy.address, CPF_READ);
396 /*===========================================================================*
397 * do_vsafecopy *
398 *===========================================================================*/
399 int do_vsafecopy(struct proc * caller, message * m_ptr)
401 static struct vscp_vec vec[SCPVEC_NR];
402 static struct vir_addr src, dst;
403 int r, i, els;
404 size_t bytes;
406 /* Set vector copy parameters. */
407 src.proc_nr_e = caller->p_endpoint;
408 assert(src.proc_nr_e != NONE);
409 src.offset = (vir_bytes) m_ptr->m_lsys_kern_vsafecopy.vec_addr;
410 dst.proc_nr_e = KERNEL;
411 dst.offset = (vir_bytes) vec;
413 /* No. of vector elements. */
414 els = m_ptr->m_lsys_kern_vsafecopy.vec_size;
415 bytes = els * sizeof(struct vscp_vec);
417 /* Obtain vector of copies. */
418 if((r=virtual_copy_vmcheck(caller, &src, &dst, bytes)) != OK)
419 return r;
421 /* Perform safecopies. */
422 for(i = 0; i < els; i++) {
423 int access;
424 endpoint_t granter;
425 if(vec[i].v_from == SELF) {
426 access = CPF_WRITE;
427 granter = vec[i].v_to;
428 } else if(vec[i].v_to == SELF) {
429 access = CPF_READ;
430 granter = vec[i].v_from;
431 } else {
432 printf("vsafecopy: %d: element %d/%d: no SELF found\n",
433 caller->p_endpoint, i, els);
434 return EINVAL;
437 /* Do safecopy for this element. */
438 if((r=safecopy(caller, granter, caller->p_endpoint,
439 vec[i].v_gid,
440 vec[i].v_bytes, vec[i].v_offset,
441 vec[i].v_addr, access)) != OK) {
442 return r;
446 return OK;