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