xref: /minix3/minix/kernel/system/do_safecopy.c (revision b80da2a01d0bb632707b7b4e974aa32eaebbcc6f)
1 /* The kernel call implemented in this file:
2  *   m_type:	SYS_SAFECOPYFROM or SYS_SAFECOPYTO or SYS_VSAFECOPY
3  *
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
10  *
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
14  */
15 
16 #include <assert.h>
17 
18 #include "kernel/system.h"
19 #include "kernel/kernel.h"
20 #include "kernel/vm.h"
21 
22 #define MAX_INDIRECT_DEPTH 5	/* up to how many indirect grants to follow? */
23 
24 #define MEM_TOP 0xFFFFFFFFUL
25 
26 static int safecopy(struct proc *, endpoint_t, endpoint_t,
27 	cp_grant_id_t, size_t, vir_bytes, vir_bytes, int);
28 
29 #define HASGRANTTABLE(gr) \
30 	(priv(gr) && priv(gr)->s_grant_table)
31 
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_* */
45 {
46 	static cp_grant_t g;
47 	static int proc_nr;
48 	static const struct proc *granter_proc;
49 	int depth = 0;
50 
51 	do {
52 		/* Get granter process slot (if valid), and check range of
53 		 * grant id.
54 		 */
55 		if(!isokendpt(granter, &proc_nr) ) {
56 			printf(
57 			"grant verify failed: invalid granter %d\n", (int) granter);
58 			return(EINVAL);
59 		}
60 		if(!GRANT_VALID(grant)) {
61 			printf(
62 			"grant verify failed: invalid grant %d\n", (int) grant);
63 			return(EINVAL);
64 		}
65 		granter_proc = proc_addr(proc_nr);
66 
67 		/* If the granter has a temporary grant table, always allow
68 		 * requests with unspecified access and return ENOTREADY if
69 		 * no grant table is present or if the grantee's endpoint is not
70 		 * the endpoint the table belongs to. When ENOTREADY is returned
71 		 * the same verify_grant() request will be replayed again in a
72 		 * while until the grant table is final. This is necessary to
73 		 * avoid races at live update time.
74 		 */
75 		if(priv(granter_proc)->s_grant_endpoint != granter_proc->p_endpoint) {
76 			if(!access) {
77 				return OK;
78 			}
79 			else if(!HASGRANTTABLE(granter_proc) || grantee != priv(granter_proc)->s_grant_endpoint) {
80 				return ENOTREADY;
81 			}
82 		}
83 
84 		/* If there is no priv. structure, or no grant table in the
85 		 * priv. structure, or the grant table in the priv. structure
86 		 * is too small for the grant, return EPERM.
87 		 */
88 		if(!HASGRANTTABLE(granter_proc)) {
89 			printf(
90 			"grant verify failed: granter %d has no grant table\n",
91 			granter);
92 			return(EPERM);
93 		}
94 
95 		if(priv(granter_proc)->s_grant_entries <= grant) {
96 				printf(
97 				"verify_grant: grant verify failed in ep %d "
98 				"proc %d: grant %d out of range "
99 				"for table size %d\n",
100 					granter, proc_nr, grant,
101 					priv(granter_proc)->s_grant_entries);
102 			return(EPERM);
103 		}
104 
105 		/* Copy the grant entry corresponding to this id to see what it
106 		 * looks like. If it fails, hide the fact that granter has
107 		 * (presumably) set an invalid grant table entry by returning
108 		 * EPERM, just like with an invalid grant id.
109 		 */
110 		if(data_copy(granter,
111 			priv(granter_proc)->s_grant_table + sizeof(g)*grant,
112 			KERNEL, (vir_bytes) &g, sizeof(g)) != OK) {
113 			printf(
114 			"verify_grant: grant verify: data_copy failed\n");
115 			return EPERM;
116 		}
117 
118 		if(flags) *flags = g.cp_flags;
119 
120 		/* Check validity. */
121 		if((g.cp_flags & (CPF_USED | CPF_VALID)) !=
122 			(CPF_USED | CPF_VALID)) {
123 			printf(
124 			"verify_grant: grant failed: invalid (%d flags 0x%lx)\n",
125 				grant, g.cp_flags);
126 			return EPERM;
127 		}
128 
129 		/* The given grant may be an indirect grant, that is, a grant
130 		 * that provides permission to use a grant given to the
131 		 * granter (i.e., for which it is the grantee). This can lead
132 		 * to a chain of indirect grants which must be followed back.
133 		 */
134 		if((g.cp_flags & CPF_INDIRECT)) {
135 			/* Stop after a few iterations. There may be a loop. */
136 			if (depth == MAX_INDIRECT_DEPTH) {
137 				printf(
138 					"verify grant: indirect grant verify "
139 					"failed: exceeded maximum depth\n");
140 				return ELOOP;
141 			}
142 			depth++;
143 
144 			/* Verify actual grantee. */
145 			if(g.cp_u.cp_indirect.cp_who_to != grantee &&
146 				grantee != ANY &&
147 				g.cp_u.cp_indirect.cp_who_to != ANY) {
148 				printf(
149 					"verify_grant: indirect grant verify "
150 					"failed: bad grantee\n");
151 				return EPERM;
152 			}
153 
154 			/* Start over with new granter, grant, and grantee. */
155 			grantee = granter;
156 			granter = g.cp_u.cp_indirect.cp_who_from;
157 			grant = g.cp_u.cp_indirect.cp_grant;
158 		}
159 	} while(g.cp_flags & CPF_INDIRECT);
160 
161 	/* Check access of grant. */
162 	if(((g.cp_flags & access) != access)) {
163 		printf(
164 	"verify_grant: grant verify failed: access invalid; want 0x%x, have 0x%x\n",
165 			access, g.cp_flags);
166 		return EPERM;
167 	}
168 
169 	if((g.cp_flags & CPF_DIRECT)) {
170 		/* Don't fiddle around with grants that wrap, arithmetic
171 		 * below may be confused.
172 		 */
173 		if(MEM_TOP - g.cp_u.cp_direct.cp_len + 1 <
174 			g.cp_u.cp_direct.cp_start) {
175 			printf(
176 		"verify_grant: direct grant verify failed: len too long\n");
177 			return EPERM;
178 		}
179 
180 		/* Verify actual grantee. */
181 		if(g.cp_u.cp_direct.cp_who_to != grantee && grantee != ANY
182 			&& g.cp_u.cp_direct.cp_who_to != ANY) {
183 			printf(
184 		"verify_grant: direct grant verify failed: bad grantee\n");
185 			return EPERM;
186 		}
187 
188 		/* Verify actual copy range. */
189 		if((offset_in+bytes < offset_in) ||
190 		    offset_in+bytes > g.cp_u.cp_direct.cp_len) {
191 			printf(
192 		"verify_grant: direct grant verify failed: bad size or range. "
193 		"granted %d bytes @ 0x%lx; wanted %d bytes @ 0x%lx\n",
194 				g.cp_u.cp_direct.cp_len,
195 				g.cp_u.cp_direct.cp_start,
196 				bytes, offset_in);
197 			return EPERM;
198 		}
199 
200 		/* Verify successful - tell caller what address it is. */
201 		*offset_result = g.cp_u.cp_direct.cp_start + offset_in;
202 		*e_granter = granter;
203 	} else if(g.cp_flags & CPF_MAGIC) {
204 		/* Currently, it is hardcoded that only FS may do
205 		 * magic grants.
206 		 */
207 		if(granter != VFS_PROC_NR) {
208 			printf(
209 		"verify_grant: magic grant verify failed: granter (%d) "
210 		"is not FS (%d)\n", granter, VFS_PROC_NR);
211 			return EPERM;
212 		}
213 
214 		/* Verify actual grantee. */
215 		if(g.cp_u.cp_magic.cp_who_to != grantee && grantee != ANY
216 			&& g.cp_u.cp_direct.cp_who_to != ANY) {
217 			printf(
218 		"verify_grant: magic grant verify failed: bad grantee\n");
219 			return EPERM;
220 		}
221 
222 		/* Verify actual copy range. */
223 		if((offset_in+bytes < offset_in) ||
224 		    offset_in+bytes > g.cp_u.cp_magic.cp_len) {
225 			printf(
226 		"verify_grant: magic grant verify failed: bad size or range. "
227 		"granted %d bytes @ 0x%lx; wanted %d bytes @ 0x%lx\n",
228 				g.cp_u.cp_magic.cp_len,
229 				g.cp_u.cp_magic.cp_start,
230 				bytes, offset_in);
231 			return EPERM;
232 		}
233 
234 		/* Verify successful - tell caller what address it is. */
235 		*offset_result = g.cp_u.cp_magic.cp_start + offset_in;
236 		*e_granter = g.cp_u.cp_magic.cp_who_from;
237 	} else {
238 		printf(
239 		"verify_grant: grant verify failed: unknown grant type\n");
240 		return EPERM;
241 	}
242 
243 	return OK;
244 }
245 
246 /*===========================================================================*
247  *				safecopy				     *
248  *===========================================================================*/
249 static int safecopy(caller, granter, grantee, grantid, bytes,
250 	g_offset, addr, access)
251 struct proc * caller;
252 endpoint_t granter, grantee;
253 cp_grant_id_t grantid;
254 size_t bytes;
255 vir_bytes g_offset, addr;
256 int access;			/* CPF_READ for a copy from granter to grantee, CPF_WRITE
257 				 * for a copy from grantee to granter.
258 				 */
259 {
260 	static struct vir_addr v_src, v_dst;
261 	static vir_bytes v_offset;
262 	endpoint_t new_granter, *src, *dst;
263 	struct proc *granter_p;
264 	int r;
265 	u32_t flags;
266 #if PERF_USE_COW_SAFECOPY
267 	vir_bytes size;
268 #endif
269 
270 	if(granter == NONE || grantee == NONE) {
271 		printf("safecopy: nonsense processes\n");
272 		return EFAULT;
273 	}
274 
275 	/* Decide who is src and who is dst. */
276 	if(access & CPF_READ) {
277 		src = &granter;
278 		dst = &grantee;
279 	} else {
280 		src = &grantee;
281 		dst = &granter;
282 	}
283 
284 	/* Verify permission exists. */
285 	if((r=verify_grant(granter, grantee, grantid, bytes, access,
286 	    g_offset, &v_offset, &new_granter, &flags)) != OK) {
287 		if(r == ENOTREADY) return r;
288 			printf(
289 		"grant %d verify to copy %d->%d by %d failed: err %d\n",
290 				grantid, *src, *dst, grantee, r);
291 		return r;
292 	}
293 
294 	/* verify_grant() can redirect the grantee to someone else,
295 	 * meaning the source or destination changes.
296 	 */
297 	granter = new_granter;
298 
299 	/* Now it's a regular copy. */
300 	v_src.proc_nr_e = *src;
301 	v_dst.proc_nr_e = *dst;
302 
303 	/* Now the offset in virtual addressing is known in 'offset'.
304 	 * Depending on the access, this is the source or destination
305 	 * address.
306 	 */
307 	if(access & CPF_READ) {
308 		v_src.offset = v_offset;
309 		v_dst.offset = (vir_bytes) addr;
310 	} else {
311 		v_src.offset = (vir_bytes) addr;
312 		v_dst.offset = v_offset;
313 	}
314 
315 	/* Do the regular copy. */
316 	if(flags & CPF_TRY) {
317 		int r;
318 		/* Try copy without transparently faulting in pages. */
319 		r = virtual_copy(&v_src, &v_dst, bytes);
320 		if(r == EFAULT_SRC || r == EFAULT_DST) return EFAULT;
321 		return r;
322 	}
323 	return virtual_copy_vmcheck(caller, &v_src, &v_dst, bytes);
324 }
325 
326 /*===========================================================================*
327  *				do_safecopy_to				     *
328  *===========================================================================*/
329 int do_safecopy_to(struct proc * caller, message * m_ptr)
330 {
331 	return safecopy(caller, m_ptr->m_lsys_kern_safecopy.from_to, caller->p_endpoint,
332 		(cp_grant_id_t) m_ptr->m_lsys_kern_safecopy.gid,
333 		m_ptr->m_lsys_kern_safecopy.bytes, m_ptr->m_lsys_kern_safecopy.offset,
334 		(vir_bytes) m_ptr->m_lsys_kern_safecopy.address, CPF_WRITE);
335 }
336 
337 /*===========================================================================*
338  *				do_safecopy_from			     *
339  *===========================================================================*/
340 int do_safecopy_from(struct proc * caller, message * m_ptr)
341 {
342 	return safecopy(caller, m_ptr->m_lsys_kern_safecopy.from_to, caller->p_endpoint,
343 		(cp_grant_id_t) m_ptr->m_lsys_kern_safecopy.gid,
344 		m_ptr->m_lsys_kern_safecopy.bytes, m_ptr->m_lsys_kern_safecopy.offset,
345 		(vir_bytes) m_ptr->m_lsys_kern_safecopy.address, CPF_READ);
346 }
347 
348 /*===========================================================================*
349  *				do_vsafecopy				     *
350  *===========================================================================*/
351 int do_vsafecopy(struct proc * caller, message * m_ptr)
352 {
353 	static struct vscp_vec vec[SCPVEC_NR];
354 	static struct vir_addr src, dst;
355 	int r, i, els;
356 	size_t bytes;
357 
358 	/* Set vector copy parameters. */
359 	src.proc_nr_e = caller->p_endpoint;
360 	assert(src.proc_nr_e != NONE);
361 	src.offset = (vir_bytes) m_ptr->m_lsys_kern_vsafecopy.vec_addr;
362 	dst.proc_nr_e = KERNEL;
363 	dst.offset = (vir_bytes) vec;
364 
365 	/* No. of vector elements. */
366 	els = m_ptr->m_lsys_kern_vsafecopy.vec_size;
367 	bytes = els * sizeof(struct vscp_vec);
368 
369 	/* Obtain vector of copies. */
370 	if((r=virtual_copy_vmcheck(caller, &src, &dst, bytes)) != OK)
371 		return r;
372 
373 	/* Perform safecopies. */
374 	for(i = 0; i < els; i++) {
375 		int access;
376 		endpoint_t granter;
377 		if(vec[i].v_from == SELF) {
378 			access = CPF_WRITE;
379 			granter = vec[i].v_to;
380 		} else if(vec[i].v_to == SELF) {
381 			access = CPF_READ;
382 			granter = vec[i].v_from;
383 		} else {
384 			printf("vsafecopy: %d: element %d/%d: no SELF found\n",
385 				caller->p_endpoint, i, els);
386 			return EINVAL;
387 		}
388 
389 		/* Do safecopy for this element. */
390 		if((r=safecopy(caller, granter, caller->p_endpoint,
391 			vec[i].v_gid,
392 			vec[i].v_bytes, vec[i].v_offset,
393 			vec[i].v_addr, access)) != OK) {
394 			return r;
395 		}
396 	}
397 
398 	return OK;
399 }
400 
401