0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/ctype.h>
0010 #include <linux/mutex.h>
0011 #include <linux/slab.h>
0012 #include <linux/rculist.h>
0013
0014 #include "trace.h"
0015
0016 static int
0017 trace_inject_entry(struct trace_event_file *file, void *rec, int len)
0018 {
0019 struct trace_event_buffer fbuffer;
0020 int written = 0;
0021 void *entry;
0022
0023 rcu_read_lock_sched();
0024 entry = trace_event_buffer_reserve(&fbuffer, file, len);
0025 if (entry) {
0026 memcpy(entry, rec, len);
0027 written = len;
0028 trace_event_buffer_commit(&fbuffer);
0029 }
0030 rcu_read_unlock_sched();
0031
0032 return written;
0033 }
0034
0035 static int
0036 parse_field(char *str, struct trace_event_call *call,
0037 struct ftrace_event_field **pf, u64 *pv)
0038 {
0039 struct ftrace_event_field *field;
0040 char *field_name;
0041 int s, i = 0;
0042 int len;
0043 u64 val;
0044
0045 if (!str[i])
0046 return 0;
0047
0048 while (isspace(str[i]))
0049 i++;
0050 s = i;
0051 while (isalnum(str[i]) || str[i] == '_')
0052 i++;
0053 len = i - s;
0054 if (!len)
0055 return -EINVAL;
0056
0057 field_name = kmemdup_nul(str + s, len, GFP_KERNEL);
0058 if (!field_name)
0059 return -ENOMEM;
0060 field = trace_find_event_field(call, field_name);
0061 kfree(field_name);
0062 if (!field)
0063 return -ENOENT;
0064
0065 *pf = field;
0066 while (isspace(str[i]))
0067 i++;
0068 if (str[i] != '=')
0069 return -EINVAL;
0070 i++;
0071 while (isspace(str[i]))
0072 i++;
0073 s = i;
0074 if (isdigit(str[i]) || str[i] == '-') {
0075 char *num, c;
0076 int ret;
0077
0078
0079 if (is_string_field(field))
0080 return -EINVAL;
0081
0082 if (str[i] == '-')
0083 i++;
0084
0085
0086 while (isalnum(str[i]))
0087 i++;
0088 num = str + s;
0089 c = str[i];
0090 if (c != '\0' && !isspace(c))
0091 return -EINVAL;
0092 str[i] = '\0';
0093
0094 if (field->is_signed)
0095 ret = kstrtoll(num, 0, &val);
0096 else
0097 ret = kstrtoull(num, 0, &val);
0098 str[i] = c;
0099 if (ret)
0100 return ret;
0101
0102 *pv = val;
0103 return i;
0104 } else if (str[i] == '\'' || str[i] == '"') {
0105 char q = str[i];
0106
0107
0108 if (!is_string_field(field))
0109 return -EINVAL;
0110
0111 for (i++; str[i]; i++) {
0112 if (str[i] == '\\' && str[i + 1]) {
0113 i++;
0114 continue;
0115 }
0116 if (str[i] == q)
0117 break;
0118 }
0119 if (!str[i])
0120 return -EINVAL;
0121
0122
0123 s++;
0124 len = i - s;
0125 if (len >= MAX_FILTER_STR_VAL)
0126 return -EINVAL;
0127
0128 *pv = (unsigned long)(str + s);
0129 str[i] = 0;
0130
0131 i++;
0132 return i;
0133 }
0134
0135 return -EINVAL;
0136 }
0137
0138 static int trace_get_entry_size(struct trace_event_call *call)
0139 {
0140 struct ftrace_event_field *field;
0141 struct list_head *head;
0142 int size = 0;
0143
0144 head = trace_get_fields(call);
0145 list_for_each_entry(field, head, link) {
0146 if (field->size + field->offset > size)
0147 size = field->size + field->offset;
0148 }
0149
0150 return size;
0151 }
0152
0153 static void *trace_alloc_entry(struct trace_event_call *call, int *size)
0154 {
0155 int entry_size = trace_get_entry_size(call);
0156 struct ftrace_event_field *field;
0157 struct list_head *head;
0158 void *entry = NULL;
0159
0160
0161 entry = kzalloc(entry_size + 1, GFP_KERNEL);
0162 if (!entry)
0163 return NULL;
0164
0165 head = trace_get_fields(call);
0166 list_for_each_entry(field, head, link) {
0167 if (!is_string_field(field))
0168 continue;
0169 if (field->filter_type == FILTER_STATIC_STRING)
0170 continue;
0171 if (field->filter_type == FILTER_DYN_STRING ||
0172 field->filter_type == FILTER_RDYN_STRING) {
0173 u32 *str_item;
0174 int str_loc = entry_size & 0xffff;
0175
0176 if (field->filter_type == FILTER_RDYN_STRING)
0177 str_loc -= field->offset + field->size;
0178
0179 str_item = (u32 *)(entry + field->offset);
0180 *str_item = str_loc;
0181 } else {
0182 char **paddr;
0183
0184 paddr = (char **)(entry + field->offset);
0185 *paddr = "";
0186 }
0187 }
0188
0189 *size = entry_size + 1;
0190 return entry;
0191 }
0192
0193 #define INJECT_STRING "STATIC STRING CAN NOT BE INJECTED"
0194
0195
0196 static int parse_entry(char *str, struct trace_event_call *call, void **pentry)
0197 {
0198 struct ftrace_event_field *field;
0199 void *entry = NULL;
0200 int entry_size;
0201 u64 val = 0;
0202 int len;
0203
0204 entry = trace_alloc_entry(call, &entry_size);
0205 *pentry = entry;
0206 if (!entry)
0207 return -ENOMEM;
0208
0209 tracing_generic_entry_update(entry, call->event.type,
0210 tracing_gen_ctx());
0211
0212 while ((len = parse_field(str, call, &field, &val)) > 0) {
0213 if (is_function_field(field))
0214 return -EINVAL;
0215
0216 if (is_string_field(field)) {
0217 char *addr = (char *)(unsigned long) val;
0218
0219 if (field->filter_type == FILTER_STATIC_STRING) {
0220 strlcpy(entry + field->offset, addr, field->size);
0221 } else if (field->filter_type == FILTER_DYN_STRING ||
0222 field->filter_type == FILTER_RDYN_STRING) {
0223 int str_len = strlen(addr) + 1;
0224 int str_loc = entry_size & 0xffff;
0225 u32 *str_item;
0226
0227 entry_size += str_len;
0228 *pentry = krealloc(entry, entry_size, GFP_KERNEL);
0229 if (!*pentry) {
0230 kfree(entry);
0231 return -ENOMEM;
0232 }
0233 entry = *pentry;
0234
0235 strlcpy(entry + (entry_size - str_len), addr, str_len);
0236 str_item = (u32 *)(entry + field->offset);
0237 if (field->filter_type == FILTER_RDYN_STRING)
0238 str_loc -= field->offset + field->size;
0239 *str_item = (str_len << 16) | str_loc;
0240 } else {
0241 char **paddr;
0242
0243 paddr = (char **)(entry + field->offset);
0244 *paddr = INJECT_STRING;
0245 }
0246 } else {
0247 switch (field->size) {
0248 case 1: {
0249 u8 tmp = (u8) val;
0250
0251 memcpy(entry + field->offset, &tmp, 1);
0252 break;
0253 }
0254 case 2: {
0255 u16 tmp = (u16) val;
0256
0257 memcpy(entry + field->offset, &tmp, 2);
0258 break;
0259 }
0260 case 4: {
0261 u32 tmp = (u32) val;
0262
0263 memcpy(entry + field->offset, &tmp, 4);
0264 break;
0265 }
0266 case 8:
0267 memcpy(entry + field->offset, &val, 8);
0268 break;
0269 default:
0270 return -EINVAL;
0271 }
0272 }
0273
0274 str += len;
0275 }
0276
0277 if (len < 0)
0278 return len;
0279
0280 return entry_size;
0281 }
0282
0283 static ssize_t
0284 event_inject_write(struct file *filp, const char __user *ubuf, size_t cnt,
0285 loff_t *ppos)
0286 {
0287 struct trace_event_call *call;
0288 struct trace_event_file *file;
0289 int err = -ENODEV, size;
0290 void *entry = NULL;
0291 char *buf;
0292
0293 if (cnt >= PAGE_SIZE)
0294 return -EINVAL;
0295
0296 buf = memdup_user_nul(ubuf, cnt);
0297 if (IS_ERR(buf))
0298 return PTR_ERR(buf);
0299 strim(buf);
0300
0301 mutex_lock(&event_mutex);
0302 file = event_file_data(filp);
0303 if (file) {
0304 call = file->event_call;
0305 size = parse_entry(buf, call, &entry);
0306 if (size < 0)
0307 err = size;
0308 else
0309 err = trace_inject_entry(file, entry, size);
0310 }
0311 mutex_unlock(&event_mutex);
0312
0313 kfree(entry);
0314 kfree(buf);
0315
0316 if (err < 0)
0317 return err;
0318
0319 *ppos += err;
0320 return cnt;
0321 }
0322
0323 static ssize_t
0324 event_inject_read(struct file *file, char __user *buf, size_t size,
0325 loff_t *ppos)
0326 {
0327 return -EPERM;
0328 }
0329
0330 const struct file_operations event_inject_fops = {
0331 .open = tracing_open_generic,
0332 .read = event_inject_read,
0333 .write = event_inject_write,
0334 };