1 // SPDX-License-Identifier: GPL-2.0
3 * trace_events_inject - trace event injection
5 * Copyright (C) 2019 Cong Wang <cwang@twitter.com>
8 #include <linux/module.h>
9 #include <linux/ctype.h>
10 #include <linux/mutex.h>
11 #include <linux/slab.h>
12 #include <linux/rculist.h>
17 trace_inject_entry(struct trace_event_file
*file
, void *rec
, int len
)
19 struct trace_event_buffer fbuffer
;
23 rcu_read_lock_sched();
24 entry
= trace_event_buffer_reserve(&fbuffer
, file
, len
);
26 memcpy(entry
, rec
, len
);
28 trace_event_buffer_commit(&fbuffer
);
30 rcu_read_unlock_sched();
36 parse_field(char *str
, struct trace_event_call
*call
,
37 struct ftrace_event_field
**pf
, u64
*pv
)
39 struct ftrace_event_field
*field
;
47 /* First find the field to associate to */
48 while (isspace(str
[i
]))
51 while (isalnum(str
[i
]) || str
[i
] == '_')
57 field_name
= kmemdup_nul(str
+ s
, len
, GFP_KERNEL
);
60 field
= trace_find_event_field(call
, field_name
);
66 while (isspace(str
[i
]))
71 while (isspace(str
[i
]))
74 if (isdigit(str
[i
]) || str
[i
] == '-') {
78 /* Make sure the field is not a string */
79 if (is_string_field(field
))
85 /* We allow 0xDEADBEEF */
86 while (isalnum(str
[i
]))
90 if (c
!= '\0' && !isspace(c
))
93 /* Make sure it is a value */
95 ret
= kstrtoll(num
, 0, &val
);
97 ret
= kstrtoull(num
, 0, &val
);
104 } else if (str
[i
] == '\'' || str
[i
] == '"') {
107 /* Make sure the field is OK for strings */
108 if (!is_string_field(field
))
111 for (i
++; str
[i
]; i
++) {
112 if (str
[i
] == '\\' && str
[i
+ 1]) {
125 if (len
>= MAX_FILTER_STR_VAL
)
128 *pv
= (unsigned long)(str
+ s
);
130 /* go past the last quote */
138 static int trace_get_entry_size(struct trace_event_call
*call
)
140 struct ftrace_event_field
*field
;
141 struct list_head
*head
;
144 head
= trace_get_fields(call
);
145 list_for_each_entry(field
, head
, link
) {
146 if (field
->size
+ field
->offset
> size
)
147 size
= field
->size
+ field
->offset
;
153 static void *trace_alloc_entry(struct trace_event_call
*call
, int *size
)
155 int entry_size
= trace_get_entry_size(call
);
156 struct ftrace_event_field
*field
;
157 struct list_head
*head
;
160 /* We need an extra '\0' at the end. */
161 entry
= kzalloc(entry_size
+ 1, GFP_KERNEL
);
165 head
= trace_get_fields(call
);
166 list_for_each_entry(field
, head
, link
) {
167 if (!is_string_field(field
))
169 if (field
->filter_type
== FILTER_STATIC_STRING
)
171 if (field
->filter_type
== FILTER_DYN_STRING
||
172 field
->filter_type
== FILTER_RDYN_STRING
) {
174 int str_loc
= entry_size
& 0xffff;
176 if (field
->filter_type
== FILTER_RDYN_STRING
)
177 str_loc
-= field
->offset
+ field
->size
;
179 str_item
= (u32
*)(entry
+ field
->offset
);
180 *str_item
= str_loc
; /* string length is 0. */
184 paddr
= (char **)(entry
+ field
->offset
);
189 *size
= entry_size
+ 1;
193 #define INJECT_STRING "STATIC STRING CAN NOT BE INJECTED"
195 /* Caller is responsible to free the *pentry. */
196 static int parse_entry(char *str
, struct trace_event_call
*call
, void **pentry
)
198 struct ftrace_event_field
*field
;
204 entry
= trace_alloc_entry(call
, &entry_size
);
209 tracing_generic_entry_update(entry
, call
->event
.type
,
212 while ((len
= parse_field(str
, call
, &field
, &val
)) > 0) {
213 if (is_function_field(field
))
216 if (is_string_field(field
)) {
217 char *addr
= (char *)(unsigned long) val
;
219 if (field
->filter_type
== FILTER_STATIC_STRING
) {
220 strscpy(entry
+ field
->offset
, addr
, field
->size
);
221 } else if (field
->filter_type
== FILTER_DYN_STRING
||
222 field
->filter_type
== FILTER_RDYN_STRING
) {
223 int str_len
= strlen(addr
) + 1;
224 int str_loc
= entry_size
& 0xffff;
227 entry_size
+= str_len
;
228 *pentry
= krealloc(entry
, entry_size
, GFP_KERNEL
);
235 strscpy(entry
+ (entry_size
- str_len
), addr
, str_len
);
236 str_item
= (u32
*)(entry
+ field
->offset
);
237 if (field
->filter_type
== FILTER_RDYN_STRING
)
238 str_loc
-= field
->offset
+ field
->size
;
239 *str_item
= (str_len
<< 16) | str_loc
;
243 paddr
= (char **)(entry
+ field
->offset
);
244 *paddr
= INJECT_STRING
;
247 switch (field
->size
) {
251 memcpy(entry
+ field
->offset
, &tmp
, 1);
257 memcpy(entry
+ field
->offset
, &tmp
, 2);
263 memcpy(entry
+ field
->offset
, &tmp
, 4);
267 memcpy(entry
+ field
->offset
, &val
, 8);
284 event_inject_write(struct file
*filp
, const char __user
*ubuf
, size_t cnt
,
287 struct trace_event_call
*call
;
288 struct trace_event_file
*file
;
289 int err
= -ENODEV
, size
;
293 if (cnt
>= PAGE_SIZE
)
296 buf
= memdup_user_nul(ubuf
, cnt
);
301 mutex_lock(&event_mutex
);
302 file
= event_file_file(filp
);
304 call
= file
->event_call
;
305 size
= parse_entry(buf
, call
, &entry
);
309 err
= trace_inject_entry(file
, entry
, size
);
311 mutex_unlock(&event_mutex
);
324 event_inject_read(struct file
*file
, char __user
*buf
, size_t size
,
330 const struct file_operations event_inject_fops
= {
331 .open
= tracing_open_file_tr
,
332 .read
= event_inject_read
,
333 .write
= event_inject_write
,
334 .release
= tracing_release_file_tr
,