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