In classical UNIX, there were no threads as such; therefore, there were no problems with their synchronization. There was no practical need in them because we had the fork function and advanced tools of interprocess communications. However, threads were introduced and pierced the entire system, making a great hole in it. Because of this, the kernel turned into the cluster of bugs . Here is only one such bug, detected early in January 2005 and typical for all version 2.2 kernels . As relates to version 2.4 kernels, they are vulnerable through version 2.4.29-pre3. Version 2.6 kernels are vulnerable through version 2.6.10.
Consider the fragment of the load_elf_library function automatically called by the sys_uselib function when loading a new library (Listing 14.4).
| |
static int load_elf_library(struct file *file) { down_write(¤t->mm->mmap_sem); error = do_mmap(file, ELF_PAGESTART(elf_phdata->p_vaddr), (elf_phdata->p_filesz + ELF_PAGEOFFSET(elf_phdata->p_vaddr)), PROT_READ PROT_WRITE PROT_EXEC, MAP_FIXED MAP_PRIVATE MAP_DENYWRITE, (elf_phdata->p_offset - ELF_PAGEOFFSET(elf_phdata->p_vaddr))); up_write(¤t->mm->mmap_sem); if (error != ELF_PAGESTART(elf_phdata->p_vaddr)) goto out_free_ph; elf_bss = elf_phdata->p_vaddr + elf_phdata->p_filesz; padzero(elf_bss); len = ELF_PAGESTART(elf_phdata->p_filesz elf_phdata->p_vaddr + ELF_MIN_ALIGN - 1); bss = elf_phdata->p_memsz + elf_phdata->p_vaddr; if (bss > len) do_brk(len, bss - len); | |
As you can see, the mmap_sem semaphore is released before the call to the do_brk function, thus causing the problem of thread synchronization. At the same time, analysis of the sys_brk function shows that the do_brk function must be called with the semaphore set. Consider the fragment of the source code (Listing 14.5) from the mm/mmap.c file.
| |
[1094] vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!vma) return -ENOMEM; vma->vm_mm = mm; vma->vm_start = addr; vma->vm_end = addr + len; vma->vm_flags = flags; vma->vm_page_prot = protection_map[flags & 0x0f]; vma->vm_ops = NULL; vma->vm_pgoff = 0; vma->vm_file = NULL; vma->vm_private_data = NULL; vma_link(mm, vma, prev, rb_link, rb_parent);
| |
If there is no semaphore, the virtual memory state can be changed between the calls to the kmem_cache_alloc and the vma_link functions. After this, the newly-created vma descriptor will be placed in a different location than the developers expected. This is enough for the hacker to obtain root privileges.
Unfortunately, even the simplest exploit is too large and, therefore, cannot be provided here. However, its source code can be easily found on the Internet The original version of this exploit with a detailed description of the hacking procedure is available at http://www.isec.pl/vulnerabilities/isec-0021-uselib.txt .