Skip to content

Instantly share code, notes, and snippets.

@zhuowei
Last active July 3, 2026 07:16
Show Gist options
  • Select an option

  • Save zhuowei/5a78638228263e02697e43d24c8f63b7 to your computer and use it in GitHub Desktop.

Select an option

Save zhuowei/5a78638228263e02697e43d24c8f63b7 to your computer and use it in GitHub Desktop.

Please explain why vm_shared_region_map_file is calling vm_shared_region_undo_mappings with an incorrect srf_current_mappings_count argument.


The bug occurs due to a mismatch between the caller's argument interpretation and the parameter design of vm_shared_region.c, which is exacerbated by confusing
parameter names in the function declaration.
──────

1. The Incorrect Call

In vm_shared_region.c, when a slide relocation fails in vm_shared_region_map_file , the function attempts to clean up all previously established mappings by calling vm_shared_region_undo_mappings :

vm_shared_region_undo_mappings(shared_region,                                                                                                                  
    sr_map, shared_region->sr_base_address,                                                                                                                    
    &sr_file_mappings[0],                                                                                                                                      
    &sr_file_mappings[sr_file_mappings_count - 1],                                                                                                             
    sr_file_mappings_count); // <-- INCORRECT ARGUMENT                                                                                                         

2. Why the Argument is Incorrect

The last argument is supposed to represent the number of segment/section mappings (individual mappings) within the last file mapping ( srf_mappings_current /
sr_file_mappings[sr_file_mappings_count - 1] ) to undo.

However, the caller incorrectly passes sr_file_mappings_count , which is the total number of files/vnodes mapped (i.e., the size of the sr_file_mappings
array, typically 1 or 2 ).

Instead of sr_file_mappings_count , the correct argument should be:

sr_file_mappings[sr_file_mappings_count - 1].mappings_count                                                                                                    

3. The Source of Confusion

The developer who wrote the incorrect call was likely misled by the function's declaration in vm_shared_region_internal.h:

extern void vm_shared_region_undo_mappings(                                                                                                                    
    struct vm_shared_region *shared_region,                                                                                                                      
    vm_map_t sr_map,                                                                                                                                             
    mach_vm_offset_t sr_base_address,                                                                                                                            
    struct _sr_file_mappings *srf_mappings,                                                                                                                      
    struct _sr_file_mappings *srf_mappings_count, // Parameter 5                                                                                                 
    unsigned int mappings_count);                 // Parameter 6                                                                                                 

In the header:

• Parameter 5 is named srf_mappings_count but is actually a pointer to the current file mapping ( srf_mappings_current in the implementation).
• Parameter 6 is named mappings_count but is actually the current file's mapping count ( srf_current_mappings_count in the implementation).

This confusing naming led the caller to mistakenly pass the array size sr_file_mappings_count to Parameter 6.

4. Impact of the Bug

When vm_shared_region.c is executing:

if (srfmp == srf_mappings_current) {                                                                                                                           
    mappings_count = srf_current_mappings_count; // Set to sr_file_mappings_count                                                                              
}                                                                                                                                                              

• If sr_file_mappings_count < srf_mappings_current->mappings_count (Typical Case):
Only the first few mappings of the last file are undone. The remaining successfully mapped segments of that file are left mapped, causing a resource leak and
potential overlap conflicts during subsequent attempts.
• If sr_file_mappings_count > srf_mappings_current->mappings_count :
The j < mappings_count loop will execute out of bounds of the srfmp->mappings array, accessing undefined kernel memory and potentially triggering a kernel
panic.


No, this bug does not lead to direct kernel memory corruption, but it has a high probability of causing a kernel panic (crash) or a denial of service (user-space crash).

Here is a breakdown of why kernel memory is not corrupted and what the actual consequences are:
──────

1. Why it does not corrupt kernel memory

  1. Read-Only Out-of-Bounds Access: The loop in vm_shared_region.c only reads from the mappings array (e.g., checking mappings[j].sms_size and calculating start / end ). It never writes back to the array or any out-of-bounds heap memory.
  2. User-Space Target Map: The target map passed to vm_map.c is sr_map , which represents the shared region's submap. This is a user-space map (used for
    the shared cache) and does not contain or overlap with kernel-space memory (like the kernel heap, stacks, or kernel code). Removing mappings from this map does
    not alter or corrupt kernel-space state.
    ──────

2. High Probability of Kernel Panic (Crash)

Instead of silent corruption, reading garbage values out of bounds is highly likely to panic the system in one of two ways:

  1. Misaligned Address Panic:
    In vm_map_delete_and_iunlock_internal , the kernel enforces that the deletion boundaries must be page-aligned:
    if (start & VM_MAP_PAGE_MASK(map)) {
    __vm_map_delete_misaligned_panic(map, start, end);
    }
    Because the out-of-bounds memory read contains arbitrary heap garbage, the computed start address is almost certain to not be page-aligned, immediately
    triggering vm_map.c and crashing the kernel.
  2. Kernel Page Fault:
    If the mappings array (allocated via kalloc_data ) happens to be positioned at the end of a page boundary and the next virtual page is unmapped (e.g., a guard page), the out-of-bounds read itself will trigger a kernel page fault, resulting in a system panic.
    ──────

3. User-Space Denial of Service (User-Space Crashes)

In the very unlikely event that the garbage values from the heap happen to be page-aligned and yield addresses within the valid boundaries of sr_map :

• vm_map.c will succeed in deleting those pages from sr_map .
• Since the shared region's map is shared across processes, this would unmap portions of the shared cache (like system libraries) for user-space applications.
• Any application subsequently trying to access these unmapped pages will crash with a segmentation fault ( EXC_BAD_ACCESS ), leading to a system-wide user-space denial of service.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment