X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/2d21ac55c334faf3a56e5634905ed6987fc787d4..e2fac8b15b12a7979f72090454d850e612fc5b13:/bsd/kern/ubc_subr.c?ds=sidebyside diff --git a/bsd/kern/ubc_subr.c b/bsd/kern/ubc_subr.c index 75abf3d39..df8047ea8 100644 --- a/bsd/kern/ubc_subr.c +++ b/bsd/kern/ubc_subr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2007 Apple Inc. All rights reserved. + * Copyright (c) 1999-2008 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -66,6 +66,8 @@ #include +#include + /* XXX These should be in a BSD accessible Mach header, but aren't. */ extern kern_return_t memory_object_pages_resident(memory_object_control_t, boolean_t *); @@ -217,11 +219,17 @@ CS_CodeDirectory *findCodeDirectory( */ cd = (const CS_CodeDirectory *) embedded; } - if (cd && cs_valid_range(cd, cd + 1, lower_bound, upper_bound) && cs_valid_range(cd, (const char *) cd + ntohl(cd->length), lower_bound, upper_bound) && + cs_valid_range(cd, (const char *) cd + ntohl(cd->hashOffset), + lower_bound, upper_bound) && + cs_valid_range(cd, (const char *) cd + + ntohl(cd->hashOffset) + + (ntohl(cd->nCodeSlots) * SHA1_RESULTLEN), + lower_bound, upper_bound) && + ntohl(cd->magic) == CSMAGIC_CODEDIRECTORY) { return cd; } @@ -1462,10 +1470,7 @@ ubc_unmap(struct vnode *vp) struct ubc_info *uip; int need_rele = 0; int need_wakeup = 0; -#if NAMEDRSRCFORK - int named_fork = 0; -#endif - + if (vnode_getwithref(vp)) return; @@ -1480,30 +1485,15 @@ ubc_unmap(struct vnode *vp) } SET(uip->ui_flags, UI_MAPBUSY); -#if NAMEDRSRCFORK - if ((vp->v_flag & VISNAMEDSTREAM) && - (vp->v_parent != NULLVP) && - !(vp->v_parent->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS)) { - named_fork = 1; - } -#endif - if (ISSET(uip->ui_flags, UI_ISMAPPED)) { - CLR(uip->ui_flags, UI_ISMAPPED); + CLR(uip->ui_flags, UI_ISMAPPED); need_rele = 1; } vnode_unlock(vp); - + if (need_rele) { - (void)VNOP_MNOMAP(vp, vfs_context_current()); - -#if NAMEDRSRCFORK - if (named_fork) { - vnode_relenamedstream(vp->v_parent, vp, vfs_context_current()); - } -#endif - - vnode_rele(vp); + (void) VNOP_MNOMAP(vp, vfs_context_current()); + vnode_rele(vp); } vnode_lock_spin(vp); @@ -1516,7 +1506,7 @@ ubc_unmap(struct vnode *vp) vnode_unlock(vp); if (need_wakeup) - wakeup(&uip->ui_flags); + wakeup(&uip->ui_flags); } /* @@ -1795,7 +1785,7 @@ upl_size_t ubc_upl_maxbufsize( void) { - return(MAX_UPL_TRANSFER * PAGE_SIZE); + return(MAX_UPL_SIZE * PAGE_SIZE); } /* @@ -1875,7 +1865,7 @@ ubc_upl_commit( kern_return_t kr; pl = UPL_GET_INTERNAL_PAGE_LIST(upl); - kr = upl_commit(upl, pl, MAX_UPL_TRANSFER); + kr = upl_commit(upl, pl, MAX_UPL_SIZE); upl_deallocate(upl); return kr; } @@ -1947,10 +1937,14 @@ ubc_upl_commit_range( if (flags & UPL_COMMIT_FREE_ON_EMPTY) flags |= UPL_COMMIT_NOTIFY_EMPTY; + if (flags & UPL_COMMIT_KERNEL_ONLY_FLAGS) { + return KERN_INVALID_ARGUMENT; + } + pl = UPL_GET_INTERNAL_PAGE_LIST(upl); kr = upl_commit_range(upl, offset, size, flags, - pl, MAX_UPL_TRANSFER, &empty); + pl, MAX_UPL_SIZE, &empty); if((flags & UPL_COMMIT_FREE_ON_EMPTY) && empty) upl_deallocate(upl); @@ -2117,7 +2111,7 @@ UBCINFOEXISTS(struct vnode * vp) /* * CODE SIGNING */ -#define CS_BLOB_KEEP_IN_KERNEL 1 +#define CS_BLOB_PAGEABLE 0 static volatile SInt32 cs_blob_size = 0; static volatile SInt32 cs_blob_count = 0; static SInt32 cs_blob_size_peak = 0; @@ -2134,6 +2128,39 @@ SYSCTL_INT(_vm, OID_AUTO, cs_blob_count_peak, CTLFLAG_RD, &cs_blob_count_peak, 0 SYSCTL_INT(_vm, OID_AUTO, cs_blob_size_peak, CTLFLAG_RD, &cs_blob_size_peak, 0, "Peak size of code signature blobs"); SYSCTL_INT(_vm, OID_AUTO, cs_blob_size_max, CTLFLAG_RD, &cs_blob_size_max, 0, "Size of biggest code signature blob"); +kern_return_t +ubc_cs_blob_allocate( + vm_offset_t *blob_addr_p, + vm_size_t *blob_size_p) +{ + kern_return_t kr; + +#if CS_BLOB_PAGEABLE + *blob_size_p = round_page(*blob_size_p); + kr = kmem_alloc(kernel_map, blob_addr_p, *blob_size_p); +#else /* CS_BLOB_PAGEABLE */ + *blob_addr_p = (vm_offset_t) kalloc(*blob_size_p); + if (*blob_addr_p == 0) { + kr = KERN_NO_SPACE; + } else { + kr = KERN_SUCCESS; + } +#endif /* CS_BLOB_PAGEABLE */ + return kr; +} + +void +ubc_cs_blob_deallocate( + vm_offset_t blob_addr, + vm_size_t blob_size) +{ +#if CS_BLOB_PAGEABLE + kmem_free(kernel_map, blob_addr, blob_size); +#else /* CS_BLOB_PAGEABLE */ + kfree((void *) blob_addr, blob_size); +#endif /* CS_BLOB_PAGEABLE */ +} + int ubc_cs_blob_add( struct vnode *vp, @@ -2159,6 +2186,7 @@ ubc_cs_blob_add( return ENOMEM; } +#if CS_BLOB_PAGEABLE /* get a memory entry on the blob */ blob_size = (memory_object_size_t) size; kr = mach_make_memory_entry_64(kernel_map, @@ -2179,7 +2207,10 @@ ubc_cs_blob_add( error = EINVAL; goto out; } - +#else + blob_size = (memory_object_size_t) size; + blob_handle = IPC_PORT_NULL; +#endif /* fill in the new blob */ blob->csb_cpu_type = cputype; @@ -2188,7 +2219,6 @@ ubc_cs_blob_add( blob->csb_mem_offset = 0; blob->csb_mem_handle = blob_handle; blob->csb_mem_kaddr = addr; - /* * Validate the blob's contents @@ -2218,14 +2248,24 @@ ubc_cs_blob_add( SHA1Final(blob->csb_sha1, &sha1ctxt); } - + /* + * Let policy module check whether the blob's signature is accepted. + */ +#if CONFIG_MACF + error = mac_vnode_check_signature(vp, blob->csb_sha1, (void*)addr, size); + if (error) + goto out; +#endif + /* * Validate the blob's coverage */ blob_start_offset = blob->csb_base_offset + blob->csb_start_offset; blob_end_offset = blob->csb_base_offset + blob->csb_end_offset; - if (blob_start_offset >= blob_end_offset) { + if (blob_start_offset >= blob_end_offset || + blob_start_offset < 0 || + blob_end_offset <= 0) { /* reject empty or backwards blob */ error = EINVAL; goto out; @@ -2337,10 +2377,6 @@ ubc_cs_blob_add( blob->csb_flags); } -#if !CS_BLOB_KEEP_IN_KERNEL - blob->csb_mem_kaddr = 0; -#endif /* CS_BLOB_KEEP_IN_KERNEL */ - vnode_unlock(vp); error = 0; /* success ! */ @@ -2356,10 +2392,6 @@ out: mach_memory_entry_port_release(blob_handle); blob_handle = IPC_PORT_NULL; } - } else { -#if !CS_BLOB_KEEP_IN_KERNEL - kmem_free(kernel_map, addr, size); -#endif /* CS_BLOB_KEEP_IN_KERNEL */ } if (error == EAGAIN) { @@ -2372,7 +2404,7 @@ out: /* * Since we're not failing, consume the data we received. */ - kmem_free(kernel_map, addr, size); + ubc_cs_blob_deallocate(addr, size); } return error; @@ -2430,12 +2462,13 @@ ubc_cs_free( blob = next_blob) { next_blob = blob->csb_next; if (blob->csb_mem_kaddr != 0) { - kmem_free(kernel_map, - blob->csb_mem_kaddr, - blob->csb_mem_size); + ubc_cs_blob_deallocate(blob->csb_mem_kaddr, + blob->csb_mem_size); blob->csb_mem_kaddr = 0; } - mach_memory_entry_port_release(blob->csb_mem_handle); + if (blob->csb_mem_handle != IPC_PORT_NULL) { + mach_memory_entry_port_release(blob->csb_mem_handle); + } blob->csb_mem_handle = IPC_PORT_NULL; OSAddAtomic(-1, &cs_blob_count); OSAddAtomic(-blob->csb_mem_size, &cs_blob_size); @@ -2546,9 +2579,6 @@ cs_validate_page( cd->hashType != 0x1 || cd->hashSize != SHA1_RESULTLEN) { /* bogus blob ? */ -#if !CS_BLOB_KEEP_IN_KERNEL - kmem_free(kernel_map, kaddr, ksize); -#endif /* CS_BLOB_KEEP_IN_KERNEL */ continue; } @@ -2558,22 +2588,17 @@ cs_validate_page( if (offset < start_offset || offset >= end_offset) { /* our page is not covered by this blob */ -#if !CS_BLOB_KEEP_IN_KERNEL - kmem_free(kernel_map, kaddr, ksize); -#endif /* CS_BLOB_KEEP_IN_KERNEL */ continue; } codeLimit = ntohl(cd->codeLimit); hash = hashes(cd, atop(offset), lower_bound, upper_bound); - bcopy(hash, expected_hash, sizeof (expected_hash)); - found_hash = TRUE; - -#if !CS_BLOB_KEEP_IN_KERNEL - /* we no longer need that blob in the kernel map */ - kmem_free(kernel_map, kaddr, ksize); -#endif /* CS_BLOB_KEEP_IN_KERNEL */ + if (hash != NULL) { + bcopy(hash, expected_hash, + sizeof (expected_hash)); + found_hash = TRUE; + } break; } @@ -2597,9 +2622,9 @@ cs_validate_page( validated = FALSE; *tainted = FALSE; } else { - const uint32_t *asha1, *esha1; size = PAGE_SIZE; + const uint32_t *asha1, *esha1; if (offset + size > codeLimit) { /* partial page at end of segment */ assert(offset < codeLimit); @@ -2607,7 +2632,7 @@ cs_validate_page( } /* compute the actual page's SHA1 hash */ SHA1Init(&sha1ctxt); - SHA1Update(&sha1ctxt, data, size); + SHA1UpdateUsePhysicalAddress(&sha1ctxt, data, size); SHA1Final(actual_hash, &sha1ctxt); asha1 = (const uint32_t *) actual_hash;