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
) {
173 int str_loc
= entry_size
& 0xffff;
175 str_item
= (u32
*)(entry
+ field
->offset
);
176 *str_item
= str_loc
; /* string length is 0. */
180 paddr
= (char **)(entry
+ field
->offset
);
185 *size
= entry_size
+ 1;
189 #define INJECT_STRING "STATIC STRING CAN NOT BE INJECTED"
191 /* Caller is responsible to free the *pentry. */
192 static int parse_entry(char *str
, struct trace_event_call
*call
, void **pentry
)
194 struct ftrace_event_field
*field
;
195 unsigned long irq_flags
;
201 entry
= trace_alloc_entry(call
, &entry_size
);
206 local_save_flags(irq_flags
);
207 tracing_generic_entry_update(entry
, call
->event
.type
, irq_flags
,
210 while ((len
= parse_field(str
, call
, &field
, &val
)) > 0) {
211 if (is_function_field(field
))
214 if (is_string_field(field
)) {
215 char *addr
= (char *)(unsigned long) val
;
217 if (field
->filter_type
== FILTER_STATIC_STRING
) {
218 strlcpy(entry
+ field
->offset
, addr
, field
->size
);
219 } else if (field
->filter_type
== FILTER_DYN_STRING
) {
220 int str_len
= strlen(addr
) + 1;
221 int str_loc
= entry_size
& 0xffff;
224 entry_size
+= str_len
;
225 *pentry
= krealloc(entry
, entry_size
, GFP_KERNEL
);
232 strlcpy(entry
+ (entry_size
- str_len
), addr
, str_len
);
233 str_item
= (u32
*)(entry
+ field
->offset
);
234 *str_item
= (str_len
<< 16) | str_loc
;
238 paddr
= (char **)(entry
+ field
->offset
);
239 *paddr
= INJECT_STRING
;
242 switch (field
->size
) {
246 memcpy(entry
+ field
->offset
, &tmp
, 1);
252 memcpy(entry
+ field
->offset
, &tmp
, 2);
258 memcpy(entry
+ field
->offset
, &tmp
, 4);
262 memcpy(entry
+ field
->offset
, &val
, 8);
279 event_inject_write(struct file
*filp
, const char __user
*ubuf
, size_t cnt
,
282 struct trace_event_call
*call
;
283 struct trace_event_file
*file
;
284 int err
= -ENODEV
, size
;
288 if (cnt
>= PAGE_SIZE
)
291 buf
= memdup_user_nul(ubuf
, cnt
);
296 mutex_lock(&event_mutex
);
297 file
= event_file_data(filp
);
299 call
= file
->event_call
;
300 size
= parse_entry(buf
, call
, &entry
);
304 err
= trace_inject_entry(file
, entry
, size
);
306 mutex_unlock(&event_mutex
);
319 event_inject_read(struct file
*file
, char __user
*buf
, size_t size
,
325 const struct file_operations event_inject_fops
= {
326 .open
= tracing_open_generic
,
327 .read
= event_inject_read
,
328 .write
= event_inject_write
,