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
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 /*===========================================================================*
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) */
49 static const struct proc
*granter_proc
;
53 /* Get granter process slot (if valid), and check range of
56 if(!isokendpt(granter
, &proc_nr
) || !GRANT_VALID(grant
)) {
58 "grant verify failed: invalid granter or grant\n");
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
) {
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
);
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
) {
88 "verify_grant: grant verify: data_copy failed\n");
93 if((g
.cp_flags
& (CPF_USED
| CPF_VALID
)) !=
94 (CPF_USED
| CPF_VALID
)) {
96 "verify_grant: grant failed: invalid (%d flags 0x%lx)\n",
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
) {
110 "verify grant: indirect grant verify "
111 "failed: exceeded maximum depth\n");
116 /* Verify actual grantee. */
117 if(g
.cp_u
.cp_indirect
.cp_who_to
!= grantee
&&
119 g
.cp_u
.cp_indirect
.cp_who_to
!= ANY
) {
121 "verify_grant: indirect grant verify "
122 "failed: bad grantee\n");
126 /* Start over with new granter, grant, and grantee. */
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
)) {
136 "verify_grant: grant verify failed: access invalid; want 0x%x, have 0x%x\n",
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) {
148 "verify_grant: direct grant verify failed: len too long\n");
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
) {
156 "verify_grant: direct grant verify failed: bad grantee\n");
160 /* Verify actual copy range. */
161 if((offset_in
+bytes
< offset_in
) ||
162 offset_in
+bytes
> g
.cp_u
.cp_direct
.cp_len
) {
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
,
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
179 if(granter
!= FS_PROC_NR
) {
181 "verify_grant: magic grant verify failed: granter (%d) "
182 "is not FS (%d)\n", granter
, FS_PROC_NR
);
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
) {
190 "verify_grant: magic grant verify failed: bad grantee\n");
194 /* Verify actual copy range. */
195 if((offset_in
+bytes
< offset_in
) ||
196 offset_in
+bytes
> g
.cp_u
.cp_magic
.cp_len
) {
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
,
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
;
211 "verify_grant: grant verify failed: unknown grant type\n");
218 /*===========================================================================*
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
;
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
;
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
) {
255 /* Verify permission exists. */
256 if((r
=verify_grant(granter
, grantee
, grantid
, bytes
, access
,
257 g_offset
, &v_offset
, &new_granter
)) != OK
) {
259 "grant %d verify to copy %d->%d by %d failed: err %d\n",
260 grantid
, *src
, *dst
, grantee
, 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
279 if(access
& CPF_READ
) {
280 v_src
.offset
= v_offset
;
281 v_dst
.offset
= (vir_bytes
) addr
;
283 v_src
.offset
= (vir_bytes
) addr
;
284 v_dst
.offset
= v_offset
;
287 /* Do the regular copy. */
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
);
302 v_src
.offset
+= size
;
303 v_dst
.offset
+= size
;
306 if((size
= bytes
/ CLICK_SIZE
) != 0) {
307 /* Use COW optimization when copying entire pages. */
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
,
315 v_src
.offset
+= size
;
316 v_dst
.offset
+= size
;
320 /* Normal copy for everything after the last page boundary. */
321 r
= virtual_copy_vmcheck(caller
, &v_src
, &v_dst
, bytes
);
328 return virtual_copy_vmcheck(caller
, &v_src
, &v_dst
, bytes
);
332 /*===========================================================================*
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
) {
342 dst_seg
= m_ptr
->SCP_SEG
;
344 } else if(m_ptr
->m_type
== SYS_SAFECOPYTO
) {
345 src_seg
= m_ptr
->SCP_SEG
;
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 /*===========================================================================*
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
;
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
)
380 /* Perform safecopies. */
381 for(i
= 0; i
< els
; i
++) {
384 if(vec
[i
].v_from
== SELF
) {
386 granter
= vec
[i
].v_to
;
387 } else if(vec
[i
].v_to
== SELF
) {
389 granter
= vec
[i
].v_from
;
391 kprintf("vsafecopy: %d: element %d/%d: no SELF found\n",
392 caller
->p_endpoint
, i
, els
);
396 /* Do safecopy for this element. */
397 if((r
=safecopy(caller
, granter
, caller
->p_endpoint
,
399 vec
[i
].v_bytes
, vec
[i
].v_offset
,
400 vec
[i
].v_addr
, access
)) != OK
) {