slight tuning of /etc/mk situation when making release.
[minix.git] / kernel / system / do_safecopy.c
blobffb1613c4ec996f2cfb21425eec688fae90f721b
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_SEG segment in own address space
7 * SCP_GID grant id
8 * SCP_OFFSET offset within granted space
9 * SCP_ADDRESS address in own address space
10 * SCP_BYTES bytes to be copied
12 * For the vectored variant (do_vsafecopy):
13 * VSCP_VEC_ADDR address of vector
14 * VSCP_VEC_SIZE number of significant elements in vector
17 #include <minix/type.h>
18 #include <minix/safecopies.h>
20 #include "../system.h"
22 #define MAX_INDIRECT_DEPTH 5 /* up to how many indirect grants to follow? */
24 #define MEM_TOP 0xFFFFFFFFUL
26 #define USE_COW_SAFECOPY 0
28 FORWARD _PROTOTYPE(int safecopy, (struct proc *, endpoint_t, endpoint_t,
29 cp_grant_id_t, int, int, size_t, vir_bytes, vir_bytes, int));
31 #define HASGRANTTABLE(gr) \
32 (!RTS_ISSET(gr, RTS_NO_PRIV) && priv(gr) && priv(gr)->s_grant_table > 0)
34 /*===========================================================================*
35 * verify_grant *
36 *===========================================================================*/
37 PUBLIC int verify_grant(granter, grantee, grant, bytes, access,
38 offset_in, offset_result, e_granter)
39 endpoint_t granter, grantee; /* copyee, copyer */
40 cp_grant_id_t grant; /* grant id */
41 vir_bytes bytes; /* copy size */
42 int access; /* direction (read/write) */
43 vir_bytes offset_in; /* copy offset within grant */
44 vir_bytes *offset_result; /* copy offset within virtual address space */
45 endpoint_t *e_granter; /* new granter (magic grants) */
47 static cp_grant_t g;
48 static int proc_nr;
49 static const struct proc *granter_proc;
50 int r, depth = 0;
52 do {
53 /* Get granter process slot (if valid), and check range of
54 * grant id.
56 if(!isokendpt(granter, &proc_nr) || !GRANT_VALID(grant)) {
57 kprintf(
58 "grant verify failed: invalid granter or grant\n");
59 return(EINVAL);
61 granter_proc = proc_addr(proc_nr);
63 /* If there is no priv. structure, or no grant table in the
64 * priv. structure, or the grant table in the priv. structure
65 * is too small for the grant, return EPERM.
67 if(!HASGRANTTABLE(granter_proc)) return EPERM;
69 if(priv(granter_proc)->s_grant_entries <= grant) {
70 kprintf(
71 "verify_grant: grant verify failed in ep %d "
72 "proc %d: grant %d out of range "
73 "for table size %d\n",
74 granter, proc_nr, grant,
75 priv(granter_proc)->s_grant_entries);
76 return(EPERM);
79 /* Copy the grant entry corresponding to this id to see what it
80 * looks like. If it fails, hide the fact that granter has
81 * (presumably) set an invalid grant table entry by returning
82 * EPERM, just like with an invalid grant id.
84 if((r=data_copy(granter,
85 priv(granter_proc)->s_grant_table + sizeof(g)*grant,
86 KERNEL, (vir_bytes) &g, sizeof(g))) != OK) {
87 kprintf(
88 "verify_grant: grant verify: data_copy failed\n");
89 return EPERM;
92 /* Check validity. */
93 if((g.cp_flags & (CPF_USED | CPF_VALID)) !=
94 (CPF_USED | CPF_VALID)) {
95 kprintf(
96 "verify_grant: grant failed: invalid (%d flags 0x%lx)\n",
97 grant, g.cp_flags);
98 return EPERM;
101 /* The given grant may be an indirect grant, that is, a grant
102 * that provides permission to use a grant given to the
103 * granter (i.e., for which it is the grantee). This can lead
104 * to a chain of indirect grants which must be followed back.
106 if((g.cp_flags & CPF_INDIRECT)) {
107 /* Stop after a few iterations. There may be a loop. */
108 if (depth == MAX_INDIRECT_DEPTH) {
109 kprintf(
110 "verify grant: indirect grant verify "
111 "failed: exceeded maximum depth\n");
112 return ELOOP;
114 depth++;
116 /* Verify actual grantee. */
117 if(g.cp_u.cp_indirect.cp_who_to != grantee &&
118 grantee != ANY &&
119 g.cp_u.cp_indirect.cp_who_to != ANY) {
120 kprintf(
121 "verify_grant: indirect grant verify "
122 "failed: bad grantee\n");
123 return EPERM;
126 /* Start over with new granter, grant, and grantee. */
127 grantee = granter;
128 granter = g.cp_u.cp_indirect.cp_who_from;
129 grant = g.cp_u.cp_indirect.cp_grant;
131 } while(g.cp_flags & CPF_INDIRECT);
133 /* Check access of grant. */
134 if(((g.cp_flags & access) != access)) {
135 kprintf(
136 "verify_grant: grant verify failed: access invalid; want 0x%x, have 0x%x\n",
137 access, g.cp_flags);
138 return EPERM;
141 if((g.cp_flags & CPF_DIRECT)) {
142 /* Don't fiddle around with grants that wrap, arithmetic
143 * below may be confused.
145 if(MEM_TOP - g.cp_u.cp_direct.cp_len <
146 g.cp_u.cp_direct.cp_start - 1) {
147 kprintf(
148 "verify_grant: direct grant verify failed: len too long\n");
149 return EPERM;
152 /* Verify actual grantee. */
153 if(g.cp_u.cp_direct.cp_who_to != grantee && grantee != ANY
154 && g.cp_u.cp_direct.cp_who_to != ANY) {
155 kprintf(
156 "verify_grant: direct grant verify failed: bad grantee\n");
157 return EPERM;
160 /* Verify actual copy range. */
161 if((offset_in+bytes < offset_in) ||
162 offset_in+bytes > g.cp_u.cp_direct.cp_len) {
163 kprintf(
164 "verify_grant: direct grant verify failed: bad size or range. "
165 "granted %d bytes @ 0x%lx; wanted %d bytes @ 0x%lx\n",
166 g.cp_u.cp_direct.cp_len,
167 g.cp_u.cp_direct.cp_start,
168 bytes, offset_in);
169 return EPERM;
172 /* Verify successful - tell caller what address it is. */
173 *offset_result = g.cp_u.cp_direct.cp_start + offset_in;
174 *e_granter = granter;
175 } else if(g.cp_flags & CPF_MAGIC) {
176 /* Currently, it is hardcoded that only FS may do
177 * magic grants.
179 if(granter != FS_PROC_NR) {
180 kprintf(
181 "verify_grant: magic grant verify failed: granter (%d) "
182 "is not FS (%d)\n", granter, FS_PROC_NR);
183 return EPERM;
186 /* Verify actual grantee. */
187 if(g.cp_u.cp_magic.cp_who_to != grantee && grantee != ANY
188 && g.cp_u.cp_direct.cp_who_to != ANY) {
189 kprintf(
190 "verify_grant: magic grant verify failed: bad grantee\n");
191 return EPERM;
194 /* Verify actual copy range. */
195 if((offset_in+bytes < offset_in) ||
196 offset_in+bytes > g.cp_u.cp_magic.cp_len) {
197 kprintf(
198 "verify_grant: magic grant verify failed: bad size or range. "
199 "granted %d bytes @ 0x%lx; wanted %d bytes @ 0x%lx\n",
200 g.cp_u.cp_magic.cp_len,
201 g.cp_u.cp_magic.cp_start,
202 bytes, offset_in);
203 return EPERM;
206 /* Verify successful - tell caller what address it is. */
207 *offset_result = g.cp_u.cp_magic.cp_start + offset_in;
208 *e_granter = g.cp_u.cp_magic.cp_who_from;
209 } else {
210 kprintf(
211 "verify_grant: grant verify failed: unknown grant type\n");
212 return EPERM;
215 return OK;
218 /*===========================================================================*
219 * safecopy *
220 *===========================================================================*/
221 PRIVATE int safecopy(caller, granter, grantee, grantid, src_seg, dst_seg, bytes,
222 g_offset, addr, access)
223 struct proc * caller;
224 endpoint_t granter, grantee;
225 cp_grant_id_t grantid;
226 int src_seg, dst_seg;
227 size_t bytes;
228 vir_bytes g_offset, addr;
229 int access; /* CPF_READ for a copy from granter to grantee, CPF_WRITE
230 * for a copy from grantee to granter.
233 static struct vir_addr v_src, v_dst;
234 static vir_bytes v_offset;
235 endpoint_t new_granter, *src, *dst;
236 struct proc *granter_p;
237 int r;
238 #if USE_COW_SAFECOPY
239 vir_bytes size;
240 #endif
242 /* See if there is a reasonable grant table. */
243 if(!(granter_p = endpoint_lookup(granter))) return EINVAL;
244 if(!HASGRANTTABLE(granter_p)) return EPERM;
246 /* Decide who is src and who is dst. */
247 if(access & CPF_READ) {
248 src = &granter;
249 dst = &grantee;
250 } else {
251 src = &grantee;
252 dst = &granter;
255 /* Verify permission exists. */
256 if((r=verify_grant(granter, grantee, grantid, bytes, access,
257 g_offset, &v_offset, &new_granter)) != OK) {
258 kprintf(
259 "grant %d verify to copy %d->%d by %d failed: err %d\n",
260 grantid, *src, *dst, grantee, r);
261 return r;
264 /* verify_grant() can redirect the grantee to someone else,
265 * meaning the source or destination changes.
267 granter = new_granter;
269 /* Now it's a regular copy. */
270 v_src.segment = src_seg;
271 v_dst.segment = dst_seg;
272 v_src.proc_nr_e = *src;
273 v_dst.proc_nr_e = *dst;
275 /* Now the offset in virtual addressing is known in 'offset'.
276 * Depending on the access, this is the source or destination
277 * address.
279 if(access & CPF_READ) {
280 v_src.offset = v_offset;
281 v_dst.offset = (vir_bytes) addr;
282 } else {
283 v_src.offset = (vir_bytes) addr;
284 v_dst.offset = v_offset;
287 /* Do the regular copy. */
288 #if USE_COW_SAFECOPY
289 if(v_offset % CLICK_SIZE != addr % CLICK_SIZE || bytes < CLICK_SIZE) {
290 /* Give up on COW immediately when offsets are not aligned
291 * or we are copying less than a page.
293 return virtual_copy_vmcheck(caller, &v_src, &v_dst, bytes);
296 if((size = v_offset % CLICK_SIZE) != 0) {
297 /* Normal copy for everything before the first page boundary. */
298 size = CLICK_SIZE - size;
299 r = virtual_copy_vmcheck(caller, &v_src, &v_dst, size);
300 if(r != OK)
301 return r;
302 v_src.offset += size;
303 v_dst.offset += size;
304 bytes -= size;
306 if((size = bytes / CLICK_SIZE) != 0) {
307 /* Use COW optimization when copying entire pages. */
308 size *= CLICK_SIZE;
309 r = map_invoke_vm(VMPTYPE_COWMAP,
310 v_dst.proc_nr_e, v_dst.segment, v_dst.offset,
311 v_src.proc_nr_e, v_src.segment, v_src.offset,
312 size, 0);
313 if(r != OK)
314 return r;
315 v_src.offset += size;
316 v_dst.offset += size;
317 bytes -= size;
319 if(bytes != 0) {
320 /* Normal copy for everything after the last page boundary. */
321 r = virtual_copy_vmcheck(caller, &v_src, &v_dst, bytes);
322 if(r != OK)
323 return r;
326 return OK;
327 #else
328 return virtual_copy_vmcheck(caller, &v_src, &v_dst, bytes);
329 #endif
332 /*===========================================================================*
333 * do_safecopy *
334 *===========================================================================*/
335 PUBLIC int do_safecopy(struct proc * caller, message * m_ptr)
337 static int access, src_seg, dst_seg;
339 /* Set src and dst parameters. */
340 if(m_ptr->m_type == SYS_SAFECOPYFROM) {
341 src_seg = D;
342 dst_seg = m_ptr->SCP_SEG;
343 access = CPF_READ;
344 } else if(m_ptr->m_type == SYS_SAFECOPYTO) {
345 src_seg = m_ptr->SCP_SEG;
346 dst_seg = D;
347 access = CPF_WRITE;
348 } else minix_panic("Impossible system call nr. ", m_ptr->m_type);
350 return safecopy(caller, m_ptr->SCP_FROM_TO, caller->p_endpoint,
351 m_ptr->SCP_GID, src_seg, dst_seg, m_ptr->SCP_BYTES,
352 m_ptr->SCP_OFFSET, (vir_bytes) m_ptr->SCP_ADDRESS, access);
355 /*===========================================================================*
356 * do_vsafecopy *
357 *===========================================================================*/
358 PUBLIC int do_vsafecopy(struct proc * caller, message * m_ptr)
360 static struct vscp_vec vec[SCPVEC_NR];
361 static struct vir_addr src, dst;
362 int r, i, els;
363 size_t bytes;
365 /* Set vector copy parameters. */
366 src.proc_nr_e = caller->p_endpoint;
367 src.offset = (vir_bytes) m_ptr->VSCP_VEC_ADDR;
368 src.segment = dst.segment = D;
369 dst.proc_nr_e = KERNEL;
370 dst.offset = (vir_bytes) vec;
372 /* No. of vector elements. */
373 els = m_ptr->VSCP_VEC_SIZE;
374 bytes = els * sizeof(struct vscp_vec);
376 /* Obtain vector of copies. */
377 if((r=virtual_copy_vmcheck(caller, &src, &dst, bytes)) != OK)
378 return r;
380 /* Perform safecopies. */
381 for(i = 0; i < els; i++) {
382 int access;
383 endpoint_t granter;
384 if(vec[i].v_from == SELF) {
385 access = CPF_WRITE;
386 granter = vec[i].v_to;
387 } else if(vec[i].v_to == SELF) {
388 access = CPF_READ;
389 granter = vec[i].v_from;
390 } else {
391 kprintf("vsafecopy: %d: element %d/%d: no SELF found\n",
392 caller->p_endpoint, i, els);
393 return EINVAL;
396 /* Do safecopy for this element. */
397 if((r=safecopy(caller, granter, caller->p_endpoint,
398 vec[i].v_gid, D, D,
399 vec[i].v_bytes, vec[i].v_offset,
400 vec[i].v_addr, access)) != OK) {
401 return r;
405 return OK;