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