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