xref: /minix/minix/kernel/system/do_safecopy.c (revision 35b65c5a)
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/vm.h"
20 
21 #define MAX_INDIRECT_DEPTH 5	/* up to how many indirect grants to follow? */
22 
23 #define MEM_TOP 0xFFFFFFFFUL
24 
25 static int safecopy(struct proc *, endpoint_t, endpoint_t,
26 	cp_grant_id_t, size_t, vir_bytes, vir_bytes, int);
27 
28 #define HASGRANTTABLE(gr) \
29 	(priv(gr) && priv(gr)->s_grant_table)
30 
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 */
36 };
37 
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 */
51 )
52 {
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;
58 
59 	do {
60 		/* Get granter process slot (if valid), and check range of
61 		 * grant id.
62 		 */
63 		if(!isokendpt(granter, &proc_nr) ) {
64 			printf(
65 			"grant verify failed: invalid granter %d\n", (int) granter);
66 			return(EINVAL);
67 		}
68 		if(!GRANT_VALID(grant)) {
69 			printf(
70 			"grant verify failed: invalid grant %d\n", (int) grant);
71 			return(EINVAL);
72 		}
73 		granter_proc = proc_addr(proc_nr);
74 
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.
82 		 */
83 		if(priv(granter_proc)->s_grant_endpoint != granter_proc->p_endpoint) {
84 			if(!access) {
85 				return OK;
86 			}
87 			else if(!HASGRANTTABLE(granter_proc) || grantee != priv(granter_proc)->s_grant_endpoint) {
88 				return ENOTREADY;
89 			}
90 		}
91 
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.
95 		 */
96 		if(!HASGRANTTABLE(granter_proc)) {
97 			printf(
98 			"grant verify failed: granter %d has no grant table\n",
99 			granter);
100 			return(EPERM);
101 		}
102 
103 		grant_idx = GRANT_IDX(grant);
104 		grant_seq = GRANT_SEQ(grant);
105 
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);
114 		}
115 
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.
120 		 */
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;
127 		}
128 
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;
135 		}
136 
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;
141 		}
142 
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.
147 		 */
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;
155 			}
156 			depth++;
157 
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;
166 			}
167 
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;
172 		}
173 	} while(g.cp_flags & CPF_INDIRECT);
174 
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;
181 	}
182 
183 	if((g.cp_flags & CPF_DIRECT)) {
184 		/* Don't fiddle around with grants that wrap, arithmetic
185 		 * below may be confused.
186 		 */
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;
192 		}
193 
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;
200 		}
201 
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;
212 		}
213 
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.
220 		 */
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;
226 		}
227 
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;
234 		}
235 
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;
246 		}
247 
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;
255 	}
256 
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;
263 	}
264 
265 	return OK;
266 }
267 
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.
281 				 */
282 )
283 {
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;
289 
290 	if(granter == NONE || grantee == NONE) {
291 		printf("safecopy: nonsense processes\n");
292 		return EFAULT;
293 	}
294 
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;
302 	}
303 
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;
312 	}
313 
314 	/* verify_grant() can redirect the grantee to someone else,
315 	 * meaning the source or destination changes.
316 	 */
317 	granter = new_granter;
318 
319 	/* Now it's a regular copy. */
320 	v_src.proc_nr_e = *src;
321 	v_dst.proc_nr_e = *dst;
322 
323 	/* Now the offset in virtual addressing is known in 'offset'.
324 	 * Depending on the access, this is the source or destination
325 	 * address.
326 	 */
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;
333 	}
334 
335 	/* Do the regular copy. */
336 	if (sfinfo.try) {
337 		/*
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.
345 		 */
346 		r = virtual_copy(&v_src, &v_dst, bytes);
347 		if (r == EFAULT_SRC || r == EFAULT_DST) {
348 			/*
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.
354 			 */
355 			r = data_copy(KERNEL, (vir_bytes)&sfinfo.value,
356 			    sfinfo.endpt, sfinfo.addr, sizeof(sfinfo.value));
357 			/*
358 			 * Failure means the creator of the magic grant messed
359 			 * up, which can only be unintentional, so report..
360 			 */
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,
365 				    r);
366 
367 			return EFAULT;
368 		}
369 		return r;
370 	}
371 	return virtual_copy_vmcheck(caller, &v_src, &v_dst, bytes);
372 }
373 
374 /*===========================================================================*
375  *				do_safecopy_to				     *
376  *===========================================================================*/
377 int do_safecopy_to(struct proc * caller, message * m_ptr)
378 {
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);
383 }
384 
385 /*===========================================================================*
386  *				do_safecopy_from			     *
387  *===========================================================================*/
388 int do_safecopy_from(struct proc * caller, message * m_ptr)
389 {
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);
394 }
395 
396 /*===========================================================================*
397  *				do_vsafecopy				     *
398  *===========================================================================*/
399 int do_vsafecopy(struct proc * caller, message * m_ptr)
400 {
401 	static struct vscp_vec vec[SCPVEC_NR];
402 	static struct vir_addr src, dst;
403 	int r, i, els;
404 	size_t bytes;
405 
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;
412 
413 	/* No. of vector elements. */
414 	els = m_ptr->m_lsys_kern_vsafecopy.vec_size;
415 	bytes = els * sizeof(struct vscp_vec);
416 
417 	/* Obtain vector of copies. */
418 	if((r=virtual_copy_vmcheck(caller, &src, &dst, bytes)) != OK)
419 		return r;
420 
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;
435 		}
436 
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;
443 		}
444 	}
445 
446 	return OK;
447 }
448 
449