Skip to content

Commit 27973e5

Browse files
committed
tracing/probes: Add string type check with BTF
Add a string type checking with BTF information if possible. This will check whether the given BTF argument (and field) is signed char array or pointer to signed char. If not, it reject the 'string' type. If it is pointer to signed char, it adds a dereference opration so that it can correctly fetch the string data from memory. # echo 'f getname_flags%return retval->name:string' >> dynamic_events # echo 't sched_switch next->comm:string' >> dynamic_events The above cases, 'struct filename::name' is 'char *' and 'struct task_struct::comm' is 'char []'. But in both case, user can specify ':string' to fetch the string data. Link: https://lore.kernel.org/all/169272159250.160970.1881112937198526188.stgit@devnote2/ Signed-off-by: Masami Hiramatsu (Google) <[email protected]> Acked-by: Steven Rostedt (Google) <[email protected]>
1 parent d157d76 commit 27973e5

File tree

2 files changed

+89
-3
lines changed

2 files changed

+89
-3
lines changed

kernel/trace/trace_probe.c

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,77 @@ static u32 btf_type_int(const struct btf_type *t)
310310
return *(u32 *)(t + 1);
311311
}
312312

313+
static bool btf_type_is_char_ptr(struct btf *btf, const struct btf_type *type)
314+
{
315+
const struct btf_type *real_type;
316+
u32 intdata;
317+
s32 tid;
318+
319+
real_type = btf_type_skip_modifiers(btf, type->type, &tid);
320+
if (!real_type)
321+
return false;
322+
323+
if (BTF_INFO_KIND(real_type->info) != BTF_KIND_INT)
324+
return false;
325+
326+
intdata = btf_type_int(real_type);
327+
return !(BTF_INT_ENCODING(intdata) & BTF_INT_SIGNED)
328+
&& BTF_INT_BITS(intdata) == 8;
329+
}
330+
331+
static bool btf_type_is_char_array(struct btf *btf, const struct btf_type *type)
332+
{
333+
const struct btf_type *real_type;
334+
const struct btf_array *array;
335+
u32 intdata;
336+
s32 tid;
337+
338+
if (BTF_INFO_KIND(type->info) != BTF_KIND_ARRAY)
339+
return false;
340+
341+
array = (const struct btf_array *)(type + 1);
342+
343+
real_type = btf_type_skip_modifiers(btf, array->type, &tid);
344+
345+
intdata = btf_type_int(real_type);
346+
return !(BTF_INT_ENCODING(intdata) & BTF_INT_SIGNED)
347+
&& BTF_INT_BITS(intdata) == 8;
348+
}
349+
350+
static int check_prepare_btf_string_fetch(char *typename,
351+
struct fetch_insn **pcode,
352+
struct traceprobe_parse_context *ctx)
353+
{
354+
struct btf *btf = ctx->btf;
355+
356+
if (!btf || !ctx->last_type)
357+
return 0;
358+
359+
/* char [] does not need any change. */
360+
if (btf_type_is_char_array(btf, ctx->last_type))
361+
return 0;
362+
363+
/* char * requires dereference the pointer. */
364+
if (btf_type_is_char_ptr(btf, ctx->last_type)) {
365+
struct fetch_insn *code = *pcode + 1;
366+
367+
if (code->op == FETCH_OP_END) {
368+
trace_probe_log_err(ctx->offset, TOO_MANY_OPS);
369+
return -E2BIG;
370+
}
371+
if (typename[0] == 'u')
372+
code->op = FETCH_OP_UDEREF;
373+
else
374+
code->op = FETCH_OP_DEREF;
375+
code->offset = 0;
376+
*pcode = code;
377+
return 0;
378+
}
379+
/* Other types are not available for string */
380+
trace_probe_log_err(ctx->offset, BAD_TYPE4STR);
381+
return -EINVAL;
382+
}
383+
313384
static const char *fetch_type_from_btf_type(struct btf *btf,
314385
const struct btf_type *type,
315386
struct traceprobe_parse_context *ctx)
@@ -675,6 +746,13 @@ static int parse_btf_bitfield(struct fetch_insn **pcode,
675746
#define find_fetch_type_from_btf_type(ctx) \
676747
find_fetch_type(NULL, ctx->flags)
677748

749+
static int check_prepare_btf_string_fetch(char *typename,
750+
struct fetch_insn **pcode,
751+
struct traceprobe_parse_context *ctx)
752+
{
753+
return 0;
754+
}
755+
678756
#endif
679757

680758
#define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long))
@@ -1117,8 +1195,15 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
11171195

11181196
/* Update storing type if BTF is available */
11191197
if (IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS) &&
1120-
!t && ctx->last_type)
1121-
parg->type = find_fetch_type_from_btf_type(ctx);
1198+
ctx->last_type) {
1199+
if (!t) {
1200+
parg->type = find_fetch_type_from_btf_type(ctx);
1201+
} else if (strstr(t, "string")) {
1202+
ret = check_prepare_btf_string_fetch(t, &code, ctx);
1203+
if (ret)
1204+
goto fail;
1205+
}
1206+
}
11221207

11231208
ret = -EINVAL;
11241209
/* Store operation */

kernel/trace/trace_probe.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,8 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
513513
C(NOSUP_DAT_ARG, "Non pointer structure/union argument is not supported."),\
514514
C(BAD_HYPHEN, "Failed to parse single hyphen. Forgot '>'?"), \
515515
C(NO_BTF_FIELD, "This field is not found."), \
516-
C(BAD_BTF_TID, "Failed to get BTF type info."),
516+
C(BAD_BTF_TID, "Failed to get BTF type info."),\
517+
C(BAD_TYPE4STR, "This type does not fit for string."),
517518

518519
#undef C
519520
#define C(a, b) TP_ERR_##a

0 commit comments

Comments
 (0)