[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <175223151834.2878276.11017360679500958621.stgit@mhiramat.tok.corp.google.com>
Date: Fri, 11 Jul 2025 19:58:38 +0900
From: "Masami Hiramatsu (Google)" <mhiramat@...nel.org>
To: Steven Rostedt <rostedt@...dmis.org>,
Masami Hiramatsu <mhiramat@...nel.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@...icios.com>,
linux-kernel@...r.kernel.org,
linux-trace-kernel@...r.kernel.org
Subject: [PATCH v2 1/1] tracing: Remove "__attribute__()" from the type field of event format
From: Masami Hiramatsu (Google) <mhiramat@...nel.org>
With CONFIG_DEBUG_INFO_BTF=y and PAHOLE_HAS_BTF_TAG=y, `__user` is
converted to `__attribute__((btf_type_tag("user")))`. In this case,
some syscall events have it for __user data, like below;
/sys/kernel/tracing # cat events/syscalls/sys_enter_openat/format
name: sys_enter_openat
ID: 720
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;
field:int __syscall_nr; offset:8; size:4; signed:1;
field:int dfd; offset:16; size:8; signed:0;
field:const char __attribute__((btf_type_tag("user"))) * filename; offset:24; size:8; signed:0;
field:int flags; offset:32; size:8; signed:0;
field:umode_t mode; offset:40; size:8; signed:0;
Then the trace event filter fails to set the string acceptable flag
(FILTER_PTR_STRING) to the field and rejects setting string filter;
# echo 'filename.ustring ~ "*ftracetest-dir.wbx24v*"' \
>> events/syscalls/sys_enter_openat/filter
sh: write error: Invalid argument
# cat error_log
[ 723.743637] event filter parse error: error: Expecting numeric field
Command: filename.ustring ~ "*ftracetest-dir.wbx24v*"
Since this __attribute__ makes format parsing complicated and not
needed, remove the __attribute__(.*) from the type string.
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@...nel.org>
---
Changes in v2:
- Add memory allocation check flag.
- Check the flag in update_event_fields() to avoid memory leak.
- Fix 'static const int ... strlen()' issue.
- Fix to find 2nd __attribute__ correctly. (adjust next after strcpy)
---
kernel/trace/trace.h | 1 +
kernel/trace/trace_events.c | 74 ++++++++++++++++++++++++++++++++++++++-----
2 files changed, 67 insertions(+), 8 deletions(-)
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index bd084953a98b..cd7be4ce6ee9 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -1468,6 +1468,7 @@ struct ftrace_event_field {
int size;
unsigned int is_signed:1;
unsigned int needs_test:1;
+ unsigned int alloc_type:1;
int len;
};
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 120531268abf..2e607afefff3 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -112,22 +112,74 @@ trace_find_event_field(struct trace_event_call *call, char *name)
return __find_event_field(&ftrace_common_fields, name);
}
-static int __trace_define_field(struct list_head *head, const char *type,
+#define ATTRIBUTE_STR "__attribute__"
+#define ATTRIBUTE_STR_LEN (sizeof(ATTRIBUTE_STR) - 1)
+
+/* Remove all __attribute__() from type */
+static void sanitize_field_type(char *type)
+{
+ char *attr, *tmp, *next;
+ int depth;
+
+ next = type;
+ while ((attr = strstr(next, ATTRIBUTE_STR))) {
+ next = attr + ATTRIBUTE_STR_LEN;
+
+ /* Retry if __attribute__ is a part of type name. */
+ if ((attr != type && !isspace(attr[-1])) ||
+ *next != '(')
+ continue;
+
+ depth = 0;
+ while ((tmp = strpbrk(next, "()"))) {
+ if (*tmp == '(')
+ depth++;
+ else
+ depth--;
+ next = tmp + 1;
+ if (depth == 0)
+ break;
+ }
+ next = skip_spaces(next);
+ strcpy(attr, next);
+ next = attr;
+ }
+}
+
+static bool need_sanitize_field_type(const char *type)
+{
+ return !!strstr(type, ATTRIBUTE_STR);
+}
+
+static int __trace_define_field(struct list_head *head, const char *__type,
const char *name, int offset, int size,
int is_signed, int filter_type, int len,
int need_test)
{
struct ftrace_event_field *field;
+ char *type;
field = kmem_cache_alloc(field_cachep, GFP_TRACE);
if (!field)
return -ENOMEM;
field->name = name;
- field->type = type;
+ if (need_sanitize_field_type(__type)) {
+ type = kstrdup(__type, GFP_KERNEL);
+ if (!type) {
+ kfree(field);
+ return -ENOMEM;
+ }
+ sanitize_field_type(type);
+ field->type = type;
+ field->alloc_type = 1;
+ } else {
+ field->type = __type;
+ field->alloc_type = 0;
+ }
if (filter_type == FILTER_OTHER)
- field->filter_type = filter_assign_type(type);
+ field->filter_type = filter_assign_type(field->type);
else
field->filter_type = filter_type;
@@ -225,6 +277,8 @@ static void trace_destroy_fields(struct trace_event_call *call)
head = trace_get_fields(call);
list_for_each_entry_safe(field, next, head, link) {
list_del(&field->link);
+ if (field->alloc_type)
+ kfree(field->type);
kmem_cache_free(field_cachep, field);
}
}
@@ -3290,10 +3344,14 @@ static void update_event_fields(struct trace_event_call *call,
if (strncmp(map->eval_string, ptr, len) != 0)
continue;
- str = kstrdup(field->type, GFP_KERNEL);
- if (WARN_ON_ONCE(!str))
- return;
- ptr = str + (ptr - field->type);
+ if (!field->alloc_type) {
+ str = kstrdup(field->type, GFP_KERNEL);
+ if (WARN_ON_ONCE(!str))
+ return;
+ ptr = str + (ptr - field->type);
+ } else
+ str = (char *)field->type;
+
ptr = eval_replace(ptr, map, len);
/* enum/sizeof string smaller than value */
if (WARN_ON_ONCE(!ptr)) {
@@ -3306,7 +3364,7 @@ static void update_event_fields(struct trace_event_call *call,
* when the module is removed. Otherwise, it will stay allocated
* until a reboot.
*/
- if (call->module)
+ if (!field->alloc_type && call->module)
add_str_to_module(call->module, str);
field->type = str;
Powered by blists - more mailing lists