Skip to content

Commit 7fb312d

Browse files
committed
Merge tag 'trace-v6.0-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace
Pull tracing fixes from Steven Rostedt: "Various fixes for tracing: - Fix a return value of traceprobe_parse_event_name() - Fix NULL pointer dereference from failed ftrace enabling - Fix NULL pointer dereference when asking for registers from eprobes - Make eprobes consistent with kprobes/uprobes, filters and histograms" * tag 'trace-v6.0-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: tracing: Have filter accept "common_cpu" to be consistent tracing/probes: Have kprobes and uprobes use $COMM too tracing/eprobes: Have event probes be consistent with kprobes and uprobes tracing/eprobes: Fix reading of string fields tracing/eprobes: Do not hardcode $comm as a string tracing/eprobes: Do not allow eprobes to use $stack, or % for regs ftrace: Fix NULL pointer dereference in is_ftrace_trampoline when ftrace is dead tracing/perf: Fix double put of trace event when init fails tracing: React to error return from traceprobe_parse_event_name()
2 parents e3f259d + b238057 commit 7fb312d

File tree

5 files changed

+119
-21
lines changed

5 files changed

+119
-21
lines changed

kernel/trace/ftrace.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2974,6 +2974,16 @@ int ftrace_startup(struct ftrace_ops *ops, int command)
29742974

29752975
ftrace_startup_enable(command);
29762976

2977+
/*
2978+
* If ftrace is in an undefined state, we just remove ops from list
2979+
* to prevent the NULL pointer, instead of totally rolling it back and
2980+
* free trampoline, because those actions could cause further damage.
2981+
*/
2982+
if (unlikely(ftrace_disabled)) {
2983+
__unregister_ftrace_function(ops);
2984+
return -ENODEV;
2985+
}
2986+
29772987
ops->flags &= ~FTRACE_OPS_FL_ADDING;
29782988

29792989
return 0;

kernel/trace/trace_eprobe.c

Lines changed: 86 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ static int trace_eprobe_tp_arg_update(struct trace_eprobe *ep, int i)
227227
struct probe_arg *parg = &ep->tp.args[i];
228228
struct ftrace_event_field *field;
229229
struct list_head *head;
230+
int ret = -ENOENT;
230231

231232
head = trace_get_fields(ep->event);
232233
list_for_each_entry(field, head, link) {
@@ -236,9 +237,20 @@ static int trace_eprobe_tp_arg_update(struct trace_eprobe *ep, int i)
236237
return 0;
237238
}
238239
}
240+
241+
/*
242+
* Argument not found on event. But allow for comm and COMM
243+
* to be used to get the current->comm.
244+
*/
245+
if (strcmp(parg->code->data, "COMM") == 0 ||
246+
strcmp(parg->code->data, "comm") == 0) {
247+
parg->code->op = FETCH_OP_COMM;
248+
ret = 0;
249+
}
250+
239251
kfree(parg->code->data);
240252
parg->code->data = NULL;
241-
return -ENOENT;
253+
return ret;
242254
}
243255

244256
static int eprobe_event_define_fields(struct trace_event_call *event_call)
@@ -311,6 +323,27 @@ static unsigned long get_event_field(struct fetch_insn *code, void *rec)
311323

312324
addr = rec + field->offset;
313325

326+
if (is_string_field(field)) {
327+
switch (field->filter_type) {
328+
case FILTER_DYN_STRING:
329+
val = (unsigned long)(rec + (*(unsigned int *)addr & 0xffff));
330+
break;
331+
case FILTER_RDYN_STRING:
332+
val = (unsigned long)(addr + (*(unsigned int *)addr & 0xffff));
333+
break;
334+
case FILTER_STATIC_STRING:
335+
val = (unsigned long)addr;
336+
break;
337+
case FILTER_PTR_STRING:
338+
val = (unsigned long)(*(char *)addr);
339+
break;
340+
default:
341+
WARN_ON_ONCE(1);
342+
return 0;
343+
}
344+
return val;
345+
}
346+
314347
switch (field->size) {
315348
case 1:
316349
if (field->is_signed)
@@ -342,16 +375,38 @@ static unsigned long get_event_field(struct fetch_insn *code, void *rec)
342375

343376
static int get_eprobe_size(struct trace_probe *tp, void *rec)
344377
{
378+
struct fetch_insn *code;
345379
struct probe_arg *arg;
346380
int i, len, ret = 0;
347381

348382
for (i = 0; i < tp->nr_args; i++) {
349383
arg = tp->args + i;
350-
if (unlikely(arg->dynamic)) {
384+
if (arg->dynamic) {
351385
unsigned long val;
352386

353-
val = get_event_field(arg->code, rec);
354-
len = process_fetch_insn_bottom(arg->code + 1, val, NULL, NULL);
387+
code = arg->code;
388+
retry:
389+
switch (code->op) {
390+
case FETCH_OP_TP_ARG:
391+
val = get_event_field(code, rec);
392+
break;
393+
case FETCH_OP_IMM:
394+
val = code->immediate;
395+
break;
396+
case FETCH_OP_COMM:
397+
val = (unsigned long)current->comm;
398+
break;
399+
case FETCH_OP_DATA:
400+
val = (unsigned long)code->data;
401+
break;
402+
case FETCH_NOP_SYMBOL: /* Ignore a place holder */
403+
code++;
404+
goto retry;
405+
default:
406+
continue;
407+
}
408+
code++;
409+
len = process_fetch_insn_bottom(code, val, NULL, NULL);
355410
if (len > 0)
356411
ret += len;
357412
}
@@ -369,8 +424,28 @@ process_fetch_insn(struct fetch_insn *code, void *rec, void *dest,
369424
{
370425
unsigned long val;
371426

372-
val = get_event_field(code, rec);
373-
return process_fetch_insn_bottom(code + 1, val, dest, base);
427+
retry:
428+
switch (code->op) {
429+
case FETCH_OP_TP_ARG:
430+
val = get_event_field(code, rec);
431+
break;
432+
case FETCH_OP_IMM:
433+
val = code->immediate;
434+
break;
435+
case FETCH_OP_COMM:
436+
val = (unsigned long)current->comm;
437+
break;
438+
case FETCH_OP_DATA:
439+
val = (unsigned long)code->data;
440+
break;
441+
case FETCH_NOP_SYMBOL: /* Ignore a place holder */
442+
code++;
443+
goto retry;
444+
default:
445+
return -EILSEQ;
446+
}
447+
code++;
448+
return process_fetch_insn_bottom(code, val, dest, base);
374449
}
375450
NOKPROBE_SYMBOL(process_fetch_insn)
376451

@@ -845,6 +920,10 @@ static int trace_eprobe_tp_update_arg(struct trace_eprobe *ep, const char *argv[
845920
trace_probe_log_err(0, BAD_ATTACH_ARG);
846921
}
847922

923+
/* Handle symbols "@" */
924+
if (!ret)
925+
ret = traceprobe_update_arg(&ep->tp.args[i]);
926+
848927
return ret;
849928
}
850929

@@ -883,7 +962,7 @@ static int __trace_eprobe_create(int argc, const char *argv[])
883962
trace_probe_log_set_index(1);
884963
sys_event = argv[1];
885964
ret = traceprobe_parse_event_name(&sys_event, &sys_name, buf2, 0);
886-
if (!sys_event || !sys_name) {
965+
if (ret || !sys_event || !sys_name) {
887966
trace_probe_log_err(0, NO_EVENT_INFO);
888967
goto parse_error;
889968
}

kernel/trace/trace_event_perf.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ static void perf_trace_event_unreg(struct perf_event *p_event)
157157
int i;
158158

159159
if (--tp_event->perf_refcount > 0)
160-
goto out;
160+
return;
161161

162162
tp_event->class->reg(tp_event, TRACE_REG_PERF_UNREGISTER, NULL);
163163

@@ -176,8 +176,6 @@ static void perf_trace_event_unreg(struct perf_event *p_event)
176176
perf_trace_buf[i] = NULL;
177177
}
178178
}
179-
out:
180-
trace_event_put_ref(tp_event);
181179
}
182180

183181
static int perf_trace_event_open(struct perf_event *p_event)
@@ -241,6 +239,7 @@ void perf_trace_destroy(struct perf_event *p_event)
241239
mutex_lock(&event_mutex);
242240
perf_trace_event_close(p_event);
243241
perf_trace_event_unreg(p_event);
242+
trace_event_put_ref(p_event->tp_event);
244243
mutex_unlock(&event_mutex);
245244
}
246245

@@ -292,6 +291,7 @@ void perf_kprobe_destroy(struct perf_event *p_event)
292291
mutex_lock(&event_mutex);
293292
perf_trace_event_close(p_event);
294293
perf_trace_event_unreg(p_event);
294+
trace_event_put_ref(p_event->tp_event);
295295
mutex_unlock(&event_mutex);
296296

297297
destroy_local_trace_kprobe(p_event->tp_event);
@@ -347,6 +347,7 @@ void perf_uprobe_destroy(struct perf_event *p_event)
347347
mutex_lock(&event_mutex);
348348
perf_trace_event_close(p_event);
349349
perf_trace_event_unreg(p_event);
350+
trace_event_put_ref(p_event->tp_event);
350351
mutex_unlock(&event_mutex);
351352
destroy_local_trace_uprobe(p_event->tp_event);
352353
}

kernel/trace/trace_events.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ static int trace_define_generic_fields(void)
176176

177177
__generic_field(int, CPU, FILTER_CPU);
178178
__generic_field(int, cpu, FILTER_CPU);
179+
__generic_field(int, common_cpu, FILTER_CPU);
179180
__generic_field(char *, COMM, FILTER_COMM);
180181
__generic_field(char *, comm, FILTER_COMM);
181182

kernel/trace/trace_probe.c

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,14 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
283283
int ret = 0;
284284
int len;
285285

286-
if (strcmp(arg, "retval") == 0) {
286+
if (flags & TPARG_FL_TPOINT) {
287+
if (code->data)
288+
return -EFAULT;
289+
code->data = kstrdup(arg, GFP_KERNEL);
290+
if (!code->data)
291+
return -ENOMEM;
292+
code->op = FETCH_OP_TP_ARG;
293+
} else if (strcmp(arg, "retval") == 0) {
287294
if (flags & TPARG_FL_RETURN) {
288295
code->op = FETCH_OP_RETVAL;
289296
} else {
@@ -307,7 +314,7 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
307314
}
308315
} else
309316
goto inval_var;
310-
} else if (strcmp(arg, "comm") == 0) {
317+
} else if (strcmp(arg, "comm") == 0 || strcmp(arg, "COMM") == 0) {
311318
code->op = FETCH_OP_COMM;
312319
#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
313320
} else if (((flags & TPARG_FL_MASK) ==
@@ -323,13 +330,6 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
323330
code->op = FETCH_OP_ARG;
324331
code->param = (unsigned int)param - 1;
325332
#endif
326-
} else if (flags & TPARG_FL_TPOINT) {
327-
if (code->data)
328-
return -EFAULT;
329-
code->data = kstrdup(arg, GFP_KERNEL);
330-
if (!code->data)
331-
return -ENOMEM;
332-
code->op = FETCH_OP_TP_ARG;
333333
} else
334334
goto inval_var;
335335

@@ -384,6 +384,11 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
384384
break;
385385

386386
case '%': /* named register */
387+
if (flags & TPARG_FL_TPOINT) {
388+
/* eprobes do not handle registers */
389+
trace_probe_log_err(offs, BAD_VAR);
390+
break;
391+
}
387392
ret = regs_query_register_offset(arg + 1);
388393
if (ret >= 0) {
389394
code->op = FETCH_OP_REG;
@@ -617,9 +622,11 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
617622

618623
/*
619624
* Since $comm and immediate string can not be dereferenced,
620-
* we can find those by strcmp.
625+
* we can find those by strcmp. But ignore for eprobes.
621626
*/
622-
if (strcmp(arg, "$comm") == 0 || strncmp(arg, "\\\"", 2) == 0) {
627+
if (!(flags & TPARG_FL_TPOINT) &&
628+
(strcmp(arg, "$comm") == 0 || strcmp(arg, "$COMM") == 0 ||
629+
strncmp(arg, "\\\"", 2) == 0)) {
623630
/* The type of $comm must be "string", and not an array. */
624631
if (parg->count || (t && strcmp(t, "string")))
625632
goto out;

0 commit comments

Comments
 (0)