diff options
| author | Han Pingtian <phan@redhat.com> | 2011-01-06 17:39:22 +0800 | 
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-01-06 18:04:46 -0200 | 
| commit | f006d25a15216a483cec71e886786874f66f9452 (patch) | |
| tree | 66420a0098c774f4d8c29bb43f81e2ba967c59cb /tools | |
| parent | 4b95f135f606c87e4056b6d7fd3c5781c818858b (diff) | |
| download | linux-f006d25a15216a483cec71e886786874f66f9452.tar.bz2 | |
perf tools: Fix buffer overflow error when specifying all tracepoints
I found when specifying all tracepoints with -e to one of subcommand,
such as 'stat', the program will trigger a buffer overflow error, like
this:
*** buffer overflow detected ***: ./perf terminated
======= Backtrace: =========
/lib64/libc.so.6(__fortify_fail+0x37)[0x382cefb2c7]
....
The tracepoints are separated by comma, something like this:
$ perf stat -a -e `perf list |grep Tracepoint|awk -F'[' '{gsub(/[[:space:]]+/,"",$1);array[FNR]=$1}END{outputs=array[1];for (i=2;i<=FNR;i++){ outputs=outputs "," array[i];};print outputs}'`
The root reason of this problem is that store_event_type() is called for all
events, and will overflow the 'filename' at:
    strncat(filename, orgname, strlen(orgname));
This patch fixes it by calling store_event_type() only when the event name has
been found.
LKML-Reference: <20110106093922.GB6713@hpt.nay.redhat.com>
Signed-off-by: Han Pingtian <phan@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/perf/util/parse-events.c | 61 | 
1 files changed, 30 insertions, 31 deletions
| diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 649083f27e08..917a0ca521c1 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -490,6 +490,31 @@ parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp,  	return EVT_HANDLED_ALL;  } +static int store_event_type(const char *orgname) +{ +	char filename[PATH_MAX], *c; +	FILE *file; +	int id, n; + +	sprintf(filename, "%s/", debugfs_path); +	strncat(filename, orgname, strlen(orgname)); +	strcat(filename, "/id"); + +	c = strchr(filename, ':'); +	if (c) +		*c = '/'; + +	file = fopen(filename, "r"); +	if (!file) +		return 0; +	n = fscanf(file, "%i", &id); +	fclose(file); +	if (n < 1) { +		pr_err("cannot store event ID\n"); +		return -EINVAL; +	} +	return perf_header__push_event(id, orgname); +}  static enum event_result parse_tracepoint_event(const char **strp,  				    struct perf_event_attr *attr) @@ -533,9 +558,13 @@ static enum event_result parse_tracepoint_event(const char **strp,  		*strp += strlen(sys_name) + evt_length;  		return parse_multiple_tracepoint_event(sys_name, evt_name,  						       flags); -	} else +	} else { +		if (store_event_type(evt_name) < 0) +			return EVT_FAILED; +  		return parse_single_tracepoint_event(sys_name, evt_name,  						     evt_length, attr, strp); +	}  }  static enum event_result @@ -778,41 +807,11 @@ modifier:  	return ret;  } -static int store_event_type(const char *orgname) -{ -	char filename[PATH_MAX], *c; -	FILE *file; -	int id, n; - -	sprintf(filename, "%s/", debugfs_path); -	strncat(filename, orgname, strlen(orgname)); -	strcat(filename, "/id"); - -	c = strchr(filename, ':'); -	if (c) -		*c = '/'; - -	file = fopen(filename, "r"); -	if (!file) -		return 0; -	n = fscanf(file, "%i", &id); -	fclose(file); -	if (n < 1) { -		pr_err("cannot store event ID\n"); -		return -EINVAL; -	} -	return perf_header__push_event(id, orgname); -} -  int parse_events(const struct option *opt __used, const char *str, int unset __used)  {  	struct perf_event_attr attr;  	enum event_result ret; -	if (strchr(str, ':')) -		if (store_event_type(str) < 0) -			return -1; -  	for (;;) {  		memset(&attr, 0, sizeof(attr));  		ret = parse_event_symbols(&str, &attr); |