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