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 void *entry = NULL; 196 int entry_size; 197 u64 val = 0; 198 int len; 199 200 entry = trace_alloc_entry(call, &entry_size); 201 *pentry = entry; 202 if (!entry) 203 return -ENOMEM; 204 205 tracing_generic_entry_update(entry, call->event.type, 206 tracing_gen_ctx()); 207 208 while ((len = parse_field(str, call, &field, &val)) > 0) { 209 if (is_function_field(field)) 210 return -EINVAL; 211 212 if (is_string_field(field)) { 213 char *addr = (char *)(unsigned long) val; 214 215 if (field->filter_type == FILTER_STATIC_STRING) { 216 strlcpy(entry + field->offset, addr, field->size); 217 } else if (field->filter_type == FILTER_DYN_STRING) { 218 int str_len = strlen(addr) + 1; 219 int str_loc = entry_size & 0xffff; 220 u32 *str_item; 221 222 entry_size += str_len; 223 *pentry = krealloc(entry, entry_size, GFP_KERNEL); 224 if (!*pentry) { 225 kfree(entry); 226 return -ENOMEM; 227 } 228 entry = *pentry; 229 230 strlcpy(entry + (entry_size - str_len), addr, str_len); 231 str_item = (u32 *)(entry + field->offset); 232 *str_item = (str_len << 16) | str_loc; 233 } else { 234 char **paddr; 235 236 paddr = (char **)(entry + field->offset); 237 *paddr = INJECT_STRING; 238 } 239 } else { 240 switch (field->size) { 241 case 1: { 242 u8 tmp = (u8) val; 243 244 memcpy(entry + field->offset, &tmp, 1); 245 break; 246 } 247 case 2: { 248 u16 tmp = (u16) val; 249 250 memcpy(entry + field->offset, &tmp, 2); 251 break; 252 } 253 case 4: { 254 u32 tmp = (u32) val; 255 256 memcpy(entry + field->offset, &tmp, 4); 257 break; 258 } 259 case 8: 260 memcpy(entry + field->offset, &val, 8); 261 break; 262 default: 263 return -EINVAL; 264 } 265 } 266 267 str += len; 268 } 269 270 if (len < 0) 271 return len; 272 273 return entry_size; 274 } 275 276 static ssize_t 277 event_inject_write(struct file *filp, const char __user *ubuf, size_t cnt, 278 loff_t *ppos) 279 { 280 struct trace_event_call *call; 281 struct trace_event_file *file; 282 int err = -ENODEV, size; 283 void *entry = NULL; 284 char *buf; 285 286 if (cnt >= PAGE_SIZE) 287 return -EINVAL; 288 289 buf = memdup_user_nul(ubuf, cnt); 290 if (IS_ERR(buf)) 291 return PTR_ERR(buf); 292 strim(buf); 293 294 mutex_lock(&event_mutex); 295 file = event_file_data(filp); 296 if (file) { 297 call = file->event_call; 298 size = parse_entry(buf, call, &entry); 299 if (size < 0) 300 err = size; 301 else 302 err = trace_inject_entry(file, entry, size); 303 } 304 mutex_unlock(&event_mutex); 305 306 kfree(entry); 307 kfree(buf); 308 309 if (err < 0) 310 return err; 311 312 *ppos += err; 313 return cnt; 314 } 315 316 static ssize_t 317 event_inject_read(struct file *file, char __user *buf, size_t size, 318 loff_t *ppos) 319 { 320 return -EPERM; 321 } 322 323 const struct file_operations event_inject_fops = { 324 .open = tracing_open_generic, 325 .read = event_inject_read, 326 .write = event_inject_write, 327 }; 328