Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f006d25a authored by Han Pingtian's avatar Han Pingtian Committed by Arnaldo Carvalho de Melo
Browse files

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: default avatarHan Pingtian <phan@redhat.com>
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 4b95f135
Loading
Loading
Loading
Loading
+30 −31
Original line number Diff line number Diff line
@@ -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,10 +558,14 @@ 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
parse_breakpoint_type(const char *type, const char **strp,
@@ -778,41 +807,11 @@ parse_event_symbols(const char **str, struct perf_event_attr *attr)
	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);