Skip to content

Commit 5ea5888

Browse files
WangNan0acmel
authored andcommitted
perf ctf: Convert invalid chars in a string before set value
We observed some crazy apps on Android set their comm to unprintable string. For example: # cat /proc/10607/task/*/comm tencent.qqmusic ... Binder_2 日志输出线 <-- Chinese word 'log output thread' WifiManager ... 'perf data convert' fails to convert perf.data with such string to CTF format. For example: # cat << EOF > ./badguy.c #include <sys/prctl.h> int main(int argc, char *argv[]) { prctl(PR_SET_NAME, "\xe6\x97\xa5\xe5\xbf\x97\xe8\xbe\x93\xe5\x87\xba\xe7\xba\xbf"); while(1) sleep(1); return 0; } EOF # gcc ./badguy.c # perf record -e sched:* ./a.out # perf data convert --to-ctf ./bad.ctf CTF stream 4 flush failed [ perf data convert: Converted 'perf.data' into CTF data './bad.ctf' ] [ perf data convert: Converted and wrote 0.008 MB (78 samples) ] # babeltrace ./bad.ctf/ [error] Packet size (18446744073709551615 bits) is larger than remaining file size (262144 bits). [error] Stream index creation error. [error] Open file stream error. [warning] [Context] Cannot open_trace of format ctf at path ./bad.ctf. [warning] [Context] cannot open trace "./bad.ctf" from ./bad.ctf/ for reading. [error] Cannot open any trace for reading. [error] opening trace "./bad.ctf/" for reading. [error] none of the specified trace paths could be opened. This patch converts unprintable characters to hexadecimal word. After applying this patch the above test works correctly: # ~/perf data convert --to-ctf ./good.ctf [ perf data convert: Converted 'perf.data' into CTF data './good.ctf' ] [ perf data convert: Converted and wrote 0.008 MB (78 samples) ] # babeltrace ./good.ctf .. [23:14:35.491665268] (+0.000001100) sched:sched_wakeup: { cpu_id = 4 }, { perf_ip = 0xFFFFFFFF810AEF33, perf_tid = 0, perf_pid = 0, perf_id = 5123, perf_period = 1, common_type = 270, common_flags = 45, common_preempt_count = 4, common_pid = 0, comm = "\xe6\x97\xa5\xe5\xbf\x97\xe8\xbe\x93\xe5\x87\xba\xe7\xba\xbf", pid = 1057, prio = 120, success = 1, target_cpu = 4 } [23:14:35.491666230] (+0.000000962) sched:sched_wakeup: { cpu_id = 4 }, { perf_ip = 0xFFFFFFFF810AEF33, perf_tid = 0, perf_pid = 0, perf_id = 5122, perf_period = 1, common_type = 270, common_flags = 45, common_preempt_count = 4, common_pid = 0, comm = "\xe6\x97\xa5\xe5\xbf\x97\xe8\xbe\x93\xe5\x87\xba\xe7\xba\xbf", pid = 1057, prio = 120, success = 1, target_cpu = 4 } .. Committer note: To build perf with libabeltrace, use: $ mkdir -p /tmp/build/perf $ make LIBBABELTRACE=1 LIBBABELTRACE_DIR=/usr/local O=/tmp/build/perf -C tools/perf install-bin Or equivalent (no O=, fixup LIBBABELTRACE_DIR, etc). Signed-off-by: Wang Nan <[email protected]> Tested-by: Arnaldo Carvalho de Melo <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: [email protected] Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 3dc6c1d commit 5ea5888

File tree

1 file changed

+39
-2
lines changed

1 file changed

+39
-2
lines changed

tools/perf/util/data-convert-bt.c

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,44 @@ static unsigned long long adjust_signedness(unsigned long long value_int, int si
204204
return (value_int & value_mask) | ~value_mask;
205205
}
206206

207+
static int string_set_value(struct bt_ctf_field *field, const char *string)
208+
{
209+
char *buffer = NULL;
210+
size_t len = strlen(string), i, p;
211+
int err;
212+
213+
for (i = p = 0; i < len; i++, p++) {
214+
if (isprint(string[i])) {
215+
if (!buffer)
216+
continue;
217+
buffer[p] = string[i];
218+
} else {
219+
char numstr[5];
220+
221+
snprintf(numstr, sizeof(numstr), "\\x%02x",
222+
(unsigned int)(string[i]) & 0xff);
223+
224+
if (!buffer) {
225+
buffer = zalloc(i + (len - i) * 4 + 2);
226+
if (!buffer) {
227+
pr_err("failed to set unprintable string '%s'\n", string);
228+
return bt_ctf_field_string_set_value(field, "UNPRINTABLE-STRING");
229+
}
230+
if (i > 0)
231+
strncpy(buffer, string, i);
232+
}
233+
strncat(buffer + p, numstr, 4);
234+
p += 3;
235+
}
236+
}
237+
238+
if (!buffer)
239+
return bt_ctf_field_string_set_value(field, string);
240+
err = bt_ctf_field_string_set_value(field, buffer);
241+
free(buffer);
242+
return err;
243+
}
244+
207245
static int add_tracepoint_field_value(struct ctf_writer *cw,
208246
struct bt_ctf_event_class *event_class,
209247
struct bt_ctf_event *event,
@@ -270,8 +308,7 @@ static int add_tracepoint_field_value(struct ctf_writer *cw,
270308
}
271309

272310
if (flags & FIELD_IS_STRING)
273-
ret = bt_ctf_field_string_set_value(field,
274-
data + offset + i * len);
311+
ret = string_set_value(field, data + offset + i * len);
275312
else {
276313
unsigned long long value_int;
277314

0 commit comments

Comments
 (0)