Linux Kernel是开放源代码操作系统Linux的内核。 Linux二进制格式装载器(binary format loaders)uselib()函数存在缺陷,本地攻击者可以利用这个漏洞获得root用户权限。 Linux内核提供二进制格式装载器层来装载不同格式的程序如ELF或者a.out或其他的,内核也提供sys_uselib()函数装载对应的二进制程序。从binfmt_elf.c文件中对load_elf_library()的uselib函数分析,在对库的BRK段(VMA)处理上存在问题,此段通过current->mm->mmap_sem建立,当修改调用进程的内存布局时\'\'信号灯\'\'(semaphore)没有保持,这可以用来扰乱内存管理并提升特权。 部分源代码fs/binfmt_elf.c如下: static int load_elf_library(struct file *file) { [904] 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 +...
Linux Kernel是开放源代码操作系统Linux的内核。 Linux二进制格式装载器(binary format loaders)uselib()函数存在缺陷,本地攻击者可以利用这个漏洞获得root用户权限。 Linux内核提供二进制格式装载器层来装载不同格式的程序如ELF或者a.out或其他的,内核也提供sys_uselib()函数装载对应的二进制程序。从binfmt_elf.c文件中对load_elf_library()的uselib函数分析,在对库的BRK段(VMA)处理上存在问题,此段通过current->mm->mmap_sem建立,当修改调用进程的内存布局时\'\'信号灯\'\'(semaphore)没有保持,这可以用来扰乱内存管理并提升特权。 部分源代码fs/binfmt_elf.c如下: static int load_elf_library(struct file *file) { [904] 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); 上面可以看到为了建立ELF二进制的数据段mmap_sem在调用do_brk()前释放,换句话说,查看mm/mmap.c文件中的sys_brk()可看出do_brk()必须以信号灯保持方式来调用。 再看下do_brk()代码: [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); rb_link和rb_parent由find_vma_prepare()查询,很明显,如果kmem_cache_alloc()调用休眠,由于进程的VMA列表和VMA RB-tree可以被其他线程更改,新建立的VMA描述符可以被插入到其他位置。导致特权提升