1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * trace_events_inject - trace event injection
4  *
5  * Copyright (C) 2019 Cong Wang <cwang@twitter.com>
6  */
7 
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>
13 
14 #include "trace.h"
15 
16 static int
17 trace_inject_entry(struct trace_event_file *file, void *rec, int len)
18 {
19 	struct trace_event_buffer fbuffer;
20 	struct ring_buffer *buffer;
21 	int written = 0;
22 	void *entry;
23 
24 	rcu_read_lock_sched();
25 	buffer = file->tr->trace_buffer.buffer;
26 	entry = trace_event_buffer_reserve(&fbuffer, file, len);
27 	if (entry) {
28 		memcpy(entry, rec, len);
29 		written = len;
30 		trace_event_buffer_commit(&fbuffer);
31 	}
32 	rcu_read_unlock_sched();
33 
34 	return written;
35 }
36 
37 static int
38 parse_field(char *str, struct trace_event_call *call,
39 	    struct ftrace_event_field **pf, u64 *pv)
40 {
41 	struct ftrace_event_field *field;
42 	char *field_name;
43 	int s, i = 0;
44 	int len;
45 	u64 val;
46 
47 	if (!str[i])
48 		return 0;
49 	/* First find the field to associate to */
50 	while (isspace(str[i]))
51 		i++;
52 	s = i;
53 	while (isalnum(str[i]) || str[i] == '_')
54 		i++;
55 	len = i - s;
56 	if (!len)
57 		return -EINVAL;
58 
59 	field_name = kmemdup_nul(str + s, len, GFP_KERNEL);
60 	if (!field_name)
61 		return -ENOMEM;
62 	field = trace_find_event_field(call, field_name);
63 	kfree(field_name);
64 	if (!field)
65 		return -ENOENT;
66 
67 	*pf = field;
68 	while (isspace(str[i]))
69 		i++;
70 	if (str[i] != '=')
71 		return -EINVAL;
72 	i++;
73 	while (isspace(str[i]))
74 		i++;
75 	s = i;
76 	if (isdigit(str[i]) || str[i] == '-') {
77 		char *num, c;
78 		int ret;
79 
80 		/* Make sure the field is not a string */
81 		if (is_string_field(field))
82 			return -EINVAL;
83 
84 		if (str[i] == '-')
85 			i++;
86 
87 		/* We allow 0xDEADBEEF */
88 		while (isalnum(str[i]))
89 			i++;
90 		num = str + s;
91 		c = str[i];
92 		if (c != '\0' && !isspace(c))
93 			return -EINVAL;
94 		str[i] = '\0';
95 		/* Make sure it is a value */
96 		if (field->is_signed)
97 			ret = kstrtoll(num, 0, &val);
98 		else
99 			ret = kstrtoull(num, 0, &val);
100 		str[i] = c;
101 		if (ret)
102 			return ret;
103 
104 		*pv = val;
105 		return i;
106 	} else if (str[i] == '\'' || str[i] == '"') {
107 		char q = str[i];
108 
109 		/* Make sure the field is OK for strings */
110 		if (!is_string_field(field))
111 			return -EINVAL;
112 
113 		for (i++; str[i]; i++) {
114 			if (str[i] == '\\' && str[i + 1]) {
115 				i++;
116 				continue;
117 			}
118 			if (str[i] == q)
119 				break;
120 		}
121 		if (!str[i])
122 			return -EINVAL;
123 
124 		/* Skip quotes */
125 		s++;
126 		len = i - s;
127 		if (len >= MAX_FILTER_STR_VAL)
128 			return -EINVAL;
129 
130 		*pv = (unsigned long)(str + s);
131 		str[i] = 0;
132 		/* go past the last quote */
133 		i++;
134 		return i;
135 	}
136 
137 	return -EINVAL;
138 }
139 
140 static int trace_get_entry_size(struct trace_event_call *call)
141 {
142 	struct ftrace_event_field *field;
143 	struct list_head *head;
144 	int size = 0;
145 
146 	head = trace_get_fields(call);
147 	list_for_each_entry(field, head, link) {
148 		if (field->size + field->offset > size)
149 			size = field->size + field->offset;
150 	}
151 
152 	return size;
153 }
154 
155 static void *trace_alloc_entry(struct trace_event_call *call, int *size)
156 {
157 	int entry_size = trace_get_entry_size(call);
158 	struct ftrace_event_field *field;
159 	struct list_head *head;
160 	void *entry = NULL;
161 
162 	/* We need an extra '\0' at the end. */
163 	entry = kzalloc(entry_size + 1, GFP_KERNEL);
164 	if (!entry)
165 		return NULL;
166 
167 	head = trace_get_fields(call);
168 	list_for_each_entry(field, head, link) {
169 		if (!is_string_field(field))
170 			continue;
171 		if (field->filter_type == FILTER_STATIC_STRING)
172 			continue;
173 		if (field->filter_type == FILTER_DYN_STRING) {
174 			u32 *str_item;
175 			int str_loc = entry_size & 0xffff;
176 
177 			str_item = (u32 *)(entry + field->offset);
178 			*str_item = str_loc; /* string length is 0. */
179 		} else {
180 			char **paddr;
181 
182 			paddr = (char **)(entry + field->offset);
183 			*paddr = "";
184 		}
185 	}
186 
187 	*size = entry_size + 1;
188 	return entry;
189 }
190 
191 #define INJECT_STRING "STATIC STRING CAN NOT BE INJECTED"
192 
193 /* Caller is responsible to free the *pentry. */
194 static int parse_entry(char *str, struct trace_event_call *call, void **pentry)
195 {
196 	struct ftrace_event_field *field;
197 	unsigned long irq_flags;
198 	void *entry = NULL;
199 	int entry_size;
200 	u64 val;
201 	int len;
202 
203 	entry = trace_alloc_entry(call, &entry_size);
204 	*pentry = entry;
205 	if (!entry)
206 		return -ENOMEM;
207 
208 	local_save_flags(irq_flags);
209 	tracing_generic_entry_update(entry, call->event.type, irq_flags,
210 				     preempt_count());
211 
212 	while ((len = parse_field(str, call, &field, &val)) > 0) {
213 		if (is_function_field(field))
214 			return -EINVAL;
215 
216 		if (is_string_field(field)) {
217 			char *addr = (char *)(unsigned long) val;
218 
219 			if (field->filter_type == FILTER_STATIC_STRING) {
220 				strlcpy(entry + field->offset, addr, field->size);
221 			} else if (field->filter_type == FILTER_DYN_STRING) {
222 				int str_len = strlen(addr) + 1;
223 				int str_loc = entry_size & 0xffff;
224 				u32 *str_item;
225 
226 				entry_size += str_len;
227 				*pentry = krealloc(entry, entry_size, GFP_KERNEL);
228 				if (!*pentry) {
229 					kfree(entry);
230 					return -ENOMEM;
231 				}
232 				entry = *pentry;
233 
234 				strlcpy(entry + (entry_size - str_len), addr, str_len);
235 				str_item = (u32 *)(entry + field->offset);
236 				*str_item = (str_len << 16) | str_loc;
237 			} else {
238 				char **paddr;
239 
240 				paddr = (char **)(entry + field->offset);
241 				*paddr = INJECT_STRING;
242 			}
243 		} else {
244 			switch (field->size) {
245 			case 1: {
246 				u8 tmp = (u8) val;
247 
248 				memcpy(entry + field->offset, &tmp, 1);
249 				break;
250 			}
251 			case 2: {
252 				u16 tmp = (u16) val;
253 
254 				memcpy(entry + field->offset, &tmp, 2);
255 				break;
256 			}
257 			case 4: {
258 				u32 tmp = (u32) val;
259 
260 				memcpy(entry + field->offset, &tmp, 4);
261 				break;
262 			}
263 			case 8:
264 				memcpy(entry + field->offset, &val, 8);
265 				break;
266 			default:
267 				return -EINVAL;
268 			}
269 		}
270 
271 		str += len;
272 	}
273 
274 	if (len < 0)
275 		return len;
276 
277 	return entry_size;
278 }
279 
280 static ssize_t
281 event_inject_write(struct file *filp, const char __user *ubuf, size_t cnt,
282 		   loff_t *ppos)
283 {
284 	struct trace_event_call *call;
285 	struct trace_event_file *file;
286 	int err = -ENODEV, size;
287 	void *entry = NULL;
288 	char *buf;
289 
290 	if (cnt >= PAGE_SIZE)
291 		return -EINVAL;
292 
293 	buf = memdup_user_nul(ubuf, cnt);
294 	if (IS_ERR(buf))
295 		return PTR_ERR(buf);
296 	strim(buf);
297 
298 	mutex_lock(&event_mutex);
299 	file = event_file_data(filp);
300 	if (file) {
301 		call = file->event_call;
302 		size = parse_entry(buf, call, &entry);
303 		if (size < 0)
304 			err = size;
305 		else
306 			err = trace_inject_entry(file, entry, size);
307 	}
308 	mutex_unlock(&event_mutex);
309 
310 	kfree(entry);
311 	kfree(buf);
312 
313 	if (err < 0)
314 		return err;
315 
316 	*ppos += err;
317 	return cnt;
318 }
319 
320 static ssize_t
321 event_inject_read(struct file *file, char __user *buf, size_t size,
322 		  loff_t *ppos)
323 {
324 	return -EPERM;
325 }
326 
327 const struct file_operations event_inject_fops = {
328 	.open = tracing_open_generic,
329 	.read = event_inject_read,
330 	.write = event_inject_write,
331 };
332