MOKB-28-11-2006 OMG! PWNIES! M4C BUGS NOW COME IN P1NK!

Bug details
Title: Mac OS X shared_region_make_private_np() Memory Corruption OMG! PWNIES! DADDY I WANT M4C P0NYMONK3YS!
Description: Mac OS X shared_region_make_private_np() system call fails to handle crafted user input, leading to an exploitable memory corruption condition. Unprivileged local users can abuse this issue in order to escalate privileges (via arbitrary code execution) or cause a denial of service.
Author/Contributor: NA<NA[at] info-pull.com> - discovery, MoKB release, debugging.
References:
Proof of concept or exploit: The following (one-liner) proof of concept / exploit can be used to reproduce the bug (requires Xcode/GNU GCC compiler to be installed): MOKB-28-11-2006.c
gcc MOKB-28-11-2006.c -o  MOKB-28-11-2006 && ./MOKB-28-11-2006
Debugging information:

It's been tested on an up-to-date (28-11-2006) Mac OS X installation, running on an Intel "shipping" Mac (x86).

---------------- beware: scary code. Oh yes, there will be blood.
---------------- bsd/vm/vm_unix.c
443 int
444 shared_region_make_private_np(
445         struct proc                                     *p,
446         struct shared_region_make_private_np_args       *uap,                    <--- syscall arg
447         __unused int                                    *retvalp)
448 {
449         int                             error;
450         kern_return_t                   kr;
451         boolean_t                       using_shared_regions;
452         user_addr_t                     user_ranges;
453         unsigned int                    range_count;
454         struct shared_region_range_np   *ranges;
455         shared_region_mapping_t         shared_region;
456         struct shared_region_task_mappings      task_mapping_info;
457         shared_region_mapping_t         next;
458 
459         ranges = NULL;
460 
461         range_count = uap->rangeCount;                                            <--- user controlled
462         user_ranges = uap->ranges;                                                <--- user controlled
463 
464         /* allocate kernel space for the "ranges" */
465         if (range_count != 0) {
466                 kr = kmem_alloc(kernel_map,
467                                 (vm_offset_t *) &ranges,
468                                 (vm_size_t) (range_count * sizeof (ranges[0])));  <--- nice 
469                 if (kr != KERN_SUCCESS) {
470                         error = ENOMEM;
471                         goto done;
472                 }
473 
474                 /* copy "ranges" from user-space */
475                 error = copyin(user_ranges,                                       <--- even better
476                                ranges,
477                                (range_count * sizeof (ranges[0])));
478                 if (error) {
479                         goto done;
480                 }
481         }
482 
483         if (p->p_flag & P_NOSHLIB) {
484                 /* no split library has been mapped for this process so far */
485                 using_shared_regions = FALSE;
486         } else {
487                 /* this process has already mapped some split libraries */
488                 using_shared_regions = TRUE;
489         }
490 
(...)
498         error = clone_system_shared_regions(using_shared_regions,
499                                             FALSE, /* chain_regions */
500                                             ENV_DEFAULT_ROOT);
501         if (error) {
502                 goto done;
503         }
504 
505         /* get info on the newly allocated shared region */
506         vm_get_shared_region(current_task(), &shared_region);
507         task_mapping_info.self = (vm_offset_t) shared_region;
508         shared_region_mapping_info(shared_region,
509                                    &(task_mapping_info.text_region),
510                                    &(task_mapping_info.text_size),
511                                    &(task_mapping_info.data_region),
512                                    &(task_mapping_info.data_size),
513                                    &(task_mapping_info.region_mappings),
514                                    &(task_mapping_info.client_base),
515                                    &(task_mapping_info.alternate_base),
516                                    &(task_mapping_info.alternate_next),
517                                    &(task_mapping_info.fs_base),
518                                    &(task_mapping_info.system),
519                                    &(task_mapping_info.flags),
520                                    &next);
521 
(...)
527         kr = shared_region_cleanup(range_count, ranges, &task_mapping_info);
528         switch (kr) {
529         case KERN_SUCCESS:
530                 error = 0;
531                 break;
532         default:
533                 error = EINVAL;
534                 goto done;
535         }
536 
537 done:
538         if (ranges != NULL) {
539                 kmem_free(kernel_map,
540                           (vm_offset_t) ranges,
541                           range_count * sizeof (ranges[0]));
542                 ranges = NULL;
543         }
544         
545         return error;
546 }
---------------- bsd/vm/vm_unix.c