[PERF_AUXTRACE_ERROR_ITRACE] = "instruction trace",
};
-static const char *auxtrace_error_name(int type)
+static const char *auxtrace_error_name(unsigned int type)
{
const char *error_type_name = NULL;
struct perf_record_auxtrace_error *e = &event->auxtrace_error;
unsigned long long nsecs = e->time;
const char *msg = e->msg;
+ int msg_max;
int ret;
ret = fprintf(fp, " %s error type %u",
if (!e->fmt)
msg = (const char *)&e->time;
- if (e->fmt >= 2 && e->machine_pid)
+ /* Bound msg to the bytes actually within the event, capped at the array size */
+ msg_max = (int)((void *)event + event->header.size - (void *)msg);
+ if (msg_max < 0)
+ msg_max = 0;
+ if (msg_max > (int)sizeof(e->msg))
+ msg_max = sizeof(e->msg);
+
+ /*
+ * Unlike the swap path which downgrades fmt in place,
+ * native-endian events are mmap'd read-only — check size
+ * instead to avoid accessing machine_pid/vcpu OOB.
+ */
+ if (e->fmt >= 2 &&
+ event->header.size >= offsetof(typeof(event->auxtrace_error), vcpu) +
+ sizeof(event->auxtrace_error.vcpu) &&
+ e->machine_pid)
ret += fprintf(fp, " machine_pid %d vcpu %d", e->machine_pid, e->vcpu);
- ret += fprintf(fp, " cpu %d pid %d tid %d ip %#"PRI_lx64" code %u: %s\n",
- e->cpu, e->pid, e->tid, e->ip, e->code, msg);
+ ret += fprintf(fp, " cpu %d pid %d tid %d ip %#"PRI_lx64" code %u: %.*s\n",
+ e->cpu, e->pid, e->tid, e->ip, e->code, msg_max, msg);
return ret;
}
const char *handler_name = "auxtrace_error";
unsigned long long tm = e->time;
const char *msg = e->msg;
+ s32 machine_pid = 0, vcpu = 0;
+ char msg_buf[MAX_AUXTRACE_ERROR_MSG + 1];
+ int msg_max;
PyObject *handler, *t;
handler = get_handler(handler_name);
msg = (const char *)&e->time;
}
+ /* Bound msg to the bytes within the event, ensure NUL-termination */
+ msg_max = (int)((void *)event + event->header.size - (void *)msg);
+ if (msg_max <= 0) {
+ msg_buf[0] = '\0';
+ } else {
+ if (msg_max > (int)sizeof(msg_buf) - 1)
+ msg_max = sizeof(msg_buf) - 1;
+ memcpy(msg_buf, msg, msg_max);
+ msg_buf[msg_max] = '\0';
+ }
+
+ /* Only access fmt >= 2 fields if the event is large enough */
+ if (e->fmt >= 2 &&
+ event->header.size >= offsetof(typeof(event->auxtrace_error), vcpu) +
+ sizeof(event->auxtrace_error.vcpu)) {
+ machine_pid = e->machine_pid;
+ vcpu = e->vcpu;
+ }
+
t = tuple_new(11);
tuple_set_u32(t, 0, e->type);
tuple_set_s32(t, 4, e->tid);
tuple_set_u64(t, 5, e->ip);
tuple_set_u64(t, 6, tm);
- tuple_set_string(t, 7, msg);
+ tuple_set_string(t, 7, msg_buf);
tuple_set_u32(t, 8, cpumode);
- tuple_set_s32(t, 9, e->machine_pid);
- tuple_set_s32(t, 10, e->vcpu);
+ tuple_set_s32(t, 9, machine_pid);
+ tuple_set_s32(t, 10, vcpu);
call_object(handler, t, handler_name);
if (event->auxtrace_error.fmt)
event->auxtrace_error.time = bswap_64(event->auxtrace_error.time);
if (event->auxtrace_error.fmt >= 2) {
- event->auxtrace_error.machine_pid = bswap_32(event->auxtrace_error.machine_pid);
- event->auxtrace_error.vcpu = bswap_32(event->auxtrace_error.vcpu);
+ /*
+ * fmt >= 2 adds machine_pid and vcpu after msg[64].
+ * Older files may have fmt >= 2 but an event size
+ * that doesn't include these fields — downgrade to
+ * avoid swapping out of bounds.
+ */
+ if (event->header.size < offsetof(typeof(event->auxtrace_error), vcpu) +
+ sizeof(event->auxtrace_error.vcpu)) {
+ pr_warning("WARNING: PERF_RECORD_AUXTRACE_ERROR: fmt %u but event too small for machine_pid/vcpu (%u bytes), downgrading fmt\n",
+ event->auxtrace_error.fmt,
+ event->header.size);
+ event->auxtrace_error.fmt = 1;
+ } else {
+ event->auxtrace_error.machine_pid = bswap_32(event->auxtrace_error.machine_pid);
+ event->auxtrace_error.vcpu = bswap_32(event->auxtrace_error.vcpu);
+ }
}
return 0;
}