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