1 // SPDX-License-Identifier: GPL-2.0 2 #include <trace/syscall.h> 3 #include <trace/events/syscalls.h> 4 #include <linux/syscalls.h> 5 #include <linux/slab.h> 6 #include <linux/kernel.h> 7 #include <linux/module.h> /* for MODULE_NAME_LEN via KSYM_SYMBOL_LEN */ 8 #include <linux/ftrace.h> 9 #include <linux/perf_event.h> 10 #include <linux/xarray.h> 11 #include <asm/syscall.h> 12 13 #include "trace_output.h" 14 #include "trace.h" 15 16 static DEFINE_MUTEX(syscall_trace_lock); 17 18 static int syscall_enter_register(struct trace_event_call *event, 19 enum trace_reg type, void *data); 20 static int syscall_exit_register(struct trace_event_call *event, 21 enum trace_reg type, void *data); 22 23 static struct list_head * 24 syscall_get_enter_fields(struct trace_event_call *call) 25 { 26 struct syscall_metadata *entry = call->data; 27 28 return &entry->enter_fields; 29 } 30 31 extern struct syscall_metadata *__start_syscalls_metadata[]; 32 extern struct syscall_metadata *__stop_syscalls_metadata[]; 33 34 static DEFINE_XARRAY(syscalls_metadata_sparse); 35 static struct syscall_metadata **syscalls_metadata; 36 37 #ifndef ARCH_HAS_SYSCALL_MATCH_SYM_NAME 38 static inline bool arch_syscall_match_sym_name(const char *sym, const char *name) 39 { 40 /* 41 * Only compare after the "sys" prefix. Archs that use 42 * syscall wrappers may have syscalls symbols aliases prefixed 43 * with ".SyS" or ".sys" instead of "sys", leading to an unwanted 44 * mismatch. 45 */ 46 return !strcmp(sym + 3, name + 3); 47 } 48 #endif 49 50 #ifdef ARCH_TRACE_IGNORE_COMPAT_SYSCALLS 51 /* 52 * Some architectures that allow for 32bit applications 53 * to run on a 64bit kernel, do not map the syscalls for 54 * the 32bit tasks the same as they do for 64bit tasks. 55 * 56 * *cough*x86*cough* 57 * 58 * In such a case, instead of reporting the wrong syscalls, 59 * simply ignore them. 60 * 61 * For an arch to ignore the compat syscalls it needs to 62 * define ARCH_TRACE_IGNORE_COMPAT_SYSCALLS as well as 63 * define the function arch_trace_is_compat_syscall() to let 64 * the tracing system know that it should ignore it. 65 */ 66 static int 67 trace_get_syscall_nr(struct task_struct *task, struct pt_regs *regs) 68 { 69 if (unlikely(arch_trace_is_compat_syscall(regs))) 70 return -1; 71 72 return syscall_get_nr(task, regs); 73 } 74 #else 75 static inline int 76 trace_get_syscall_nr(struct task_struct *task, struct pt_regs *regs) 77 { 78 return syscall_get_nr(task, regs); 79 } 80 #endif /* ARCH_TRACE_IGNORE_COMPAT_SYSCALLS */ 81 82 static __init struct syscall_metadata * 83 find_syscall_meta(unsigned long syscall) 84 { 85 struct syscall_metadata **start; 86 struct syscall_metadata **stop; 87 char str[KSYM_SYMBOL_LEN]; 88 89 90 start = __start_syscalls_metadata; 91 stop = __stop_syscalls_metadata; 92 kallsyms_lookup(syscall, NULL, NULL, NULL, str); 93 94 if (arch_syscall_match_sym_name(str, "sys_ni_syscall")) 95 return NULL; 96 97 for ( ; start < stop; start++) { 98 if ((*start)->name && arch_syscall_match_sym_name(str, (*start)->name)) 99 return *start; 100 } 101 return NULL; 102 } 103 104 static struct syscall_metadata *syscall_nr_to_meta(int nr) 105 { 106 if (IS_ENABLED(CONFIG_HAVE_SPARSE_SYSCALL_NR)) 107 return xa_load(&syscalls_metadata_sparse, (unsigned long)nr); 108 109 if (!syscalls_metadata || nr >= NR_syscalls || nr < 0) 110 return NULL; 111 112 return syscalls_metadata[nr]; 113 } 114 115 const char *get_syscall_name(int syscall) 116 { 117 struct syscall_metadata *entry; 118 119 entry = syscall_nr_to_meta(syscall); 120 if (!entry) 121 return NULL; 122 123 return entry->name; 124 } 125 126 static enum print_line_t 127 print_syscall_enter(struct trace_iterator *iter, int flags, 128 struct trace_event *event) 129 { 130 struct trace_array *tr = iter->tr; 131 struct trace_seq *s = &iter->seq; 132 struct trace_entry *ent = iter->ent; 133 struct syscall_trace_enter *trace; 134 struct syscall_metadata *entry; 135 int i, syscall; 136 137 trace = (typeof(trace))ent; 138 syscall = trace->nr; 139 entry = syscall_nr_to_meta(syscall); 140 141 if (!entry) 142 goto end; 143 144 if (entry->enter_event->event.type != ent->type) { 145 WARN_ON_ONCE(1); 146 goto end; 147 } 148 149 trace_seq_printf(s, "%s(", entry->name); 150 151 for (i = 0; i < entry->nb_args; i++) { 152 153 if (trace_seq_has_overflowed(s)) 154 goto end; 155 156 /* parameter types */ 157 if (tr->trace_flags & TRACE_ITER_VERBOSE) 158 trace_seq_printf(s, "%s ", entry->types[i]); 159 160 /* parameter values */ 161 trace_seq_printf(s, "%s: %lx%s", entry->args[i], 162 trace->args[i], 163 i == entry->nb_args - 1 ? "" : ", "); 164 } 165 166 trace_seq_putc(s, ')'); 167 end: 168 trace_seq_putc(s, '\n'); 169 170 return trace_handle_return(s); 171 } 172 173 static enum print_line_t 174 print_syscall_exit(struct trace_iterator *iter, int flags, 175 struct trace_event *event) 176 { 177 struct trace_seq *s = &iter->seq; 178 struct trace_entry *ent = iter->ent; 179 struct syscall_trace_exit *trace; 180 int syscall; 181 struct syscall_metadata *entry; 182 183 trace = (typeof(trace))ent; 184 syscall = trace->nr; 185 entry = syscall_nr_to_meta(syscall); 186 187 if (!entry) { 188 trace_seq_putc(s, '\n'); 189 goto out; 190 } 191 192 if (entry->exit_event->event.type != ent->type) { 193 WARN_ON_ONCE(1); 194 return TRACE_TYPE_UNHANDLED; 195 } 196 197 trace_seq_printf(s, "%s -> 0x%lx\n", entry->name, 198 trace->ret); 199 200 out: 201 return trace_handle_return(s); 202 } 203 204 extern char *__bad_type_size(void); 205 206 #define SYSCALL_FIELD(_type, _name) { \ 207 .type = #_type, .name = #_name, \ 208 .size = sizeof(_type), .align = __alignof__(_type), \ 209 .is_signed = is_signed_type(_type), .filter_type = FILTER_OTHER } 210 211 static int __init 212 __set_enter_print_fmt(struct syscall_metadata *entry, char *buf, int len) 213 { 214 int i; 215 int pos = 0; 216 217 /* When len=0, we just calculate the needed length */ 218 #define LEN_OR_ZERO (len ? len - pos : 0) 219 220 pos += snprintf(buf + pos, LEN_OR_ZERO, "\""); 221 for (i = 0; i < entry->nb_args; i++) { 222 pos += snprintf(buf + pos, LEN_OR_ZERO, "%s: 0x%%0%zulx%s", 223 entry->args[i], sizeof(unsigned long), 224 i == entry->nb_args - 1 ? "" : ", "); 225 } 226 pos += snprintf(buf + pos, LEN_OR_ZERO, "\""); 227 228 for (i = 0; i < entry->nb_args; i++) { 229 pos += snprintf(buf + pos, LEN_OR_ZERO, 230 ", ((unsigned long)(REC->%s))", entry->args[i]); 231 } 232 233 #undef LEN_OR_ZERO 234 235 /* return the length of print_fmt */ 236 return pos; 237 } 238 239 static int __init set_syscall_print_fmt(struct trace_event_call *call) 240 { 241 char *print_fmt; 242 int len; 243 struct syscall_metadata *entry = call->data; 244 245 if (entry->enter_event != call) { 246 call->print_fmt = "\"0x%lx\", REC->ret"; 247 return 0; 248 } 249 250 /* First: called with 0 length to calculate the needed length */ 251 len = __set_enter_print_fmt(entry, NULL, 0); 252 253 print_fmt = kmalloc(len + 1, GFP_KERNEL); 254 if (!print_fmt) 255 return -ENOMEM; 256 257 /* Second: actually write the @print_fmt */ 258 __set_enter_print_fmt(entry, print_fmt, len + 1); 259 call->print_fmt = print_fmt; 260 261 return 0; 262 } 263 264 static void __init free_syscall_print_fmt(struct trace_event_call *call) 265 { 266 struct syscall_metadata *entry = call->data; 267 268 if (entry->enter_event == call) 269 kfree(call->print_fmt); 270 } 271 272 static int __init syscall_enter_define_fields(struct trace_event_call *call) 273 { 274 struct syscall_trace_enter trace; 275 struct syscall_metadata *meta = call->data; 276 int offset = offsetof(typeof(trace), args); 277 int ret, i; 278 279 for (i = 0; i < meta->nb_args; i++) { 280 ret = trace_define_field(call, meta->types[i], 281 meta->args[i], offset, 282 sizeof(unsigned long), 0, 283 FILTER_OTHER); 284 if (ret) 285 break; 286 offset += sizeof(unsigned long); 287 } 288 289 return ret; 290 } 291 292 static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id) 293 { 294 struct trace_array *tr = data; 295 struct trace_event_file *trace_file; 296 struct syscall_trace_enter *entry; 297 struct syscall_metadata *sys_data; 298 struct ring_buffer_event *event; 299 struct ring_buffer *buffer; 300 unsigned long irq_flags; 301 unsigned long args[6]; 302 int pc; 303 int syscall_nr; 304 int size; 305 306 syscall_nr = trace_get_syscall_nr(current, regs); 307 if (syscall_nr < 0 || syscall_nr >= NR_syscalls) 308 return; 309 310 /* Here we're inside tp handler's rcu_read_lock_sched (__DO_TRACE) */ 311 trace_file = rcu_dereference_sched(tr->enter_syscall_files[syscall_nr]); 312 if (!trace_file) 313 return; 314 315 if (trace_trigger_soft_disabled(trace_file)) 316 return; 317 318 sys_data = syscall_nr_to_meta(syscall_nr); 319 if (!sys_data) 320 return; 321 322 size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args; 323 324 local_save_flags(irq_flags); 325 pc = preempt_count(); 326 327 buffer = tr->trace_buffer.buffer; 328 event = trace_buffer_lock_reserve(buffer, 329 sys_data->enter_event->event.type, size, irq_flags, pc); 330 if (!event) 331 return; 332 333 entry = ring_buffer_event_data(event); 334 entry->nr = syscall_nr; 335 syscall_get_arguments(current, regs, args); 336 memcpy(entry->args, args, sizeof(unsigned long) * sys_data->nb_args); 337 338 event_trigger_unlock_commit(trace_file, buffer, event, entry, 339 irq_flags, pc); 340 } 341 342 static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret) 343 { 344 struct trace_array *tr = data; 345 struct trace_event_file *trace_file; 346 struct syscall_trace_exit *entry; 347 struct syscall_metadata *sys_data; 348 struct ring_buffer_event *event; 349 struct ring_buffer *buffer; 350 unsigned long irq_flags; 351 int pc; 352 int syscall_nr; 353 354 syscall_nr = trace_get_syscall_nr(current, regs); 355 if (syscall_nr < 0 || syscall_nr >= NR_syscalls) 356 return; 357 358 /* Here we're inside tp handler's rcu_read_lock_sched (__DO_TRACE()) */ 359 trace_file = rcu_dereference_sched(tr->exit_syscall_files[syscall_nr]); 360 if (!trace_file) 361 return; 362 363 if (trace_trigger_soft_disabled(trace_file)) 364 return; 365 366 sys_data = syscall_nr_to_meta(syscall_nr); 367 if (!sys_data) 368 return; 369 370 local_save_flags(irq_flags); 371 pc = preempt_count(); 372 373 buffer = tr->trace_buffer.buffer; 374 event = trace_buffer_lock_reserve(buffer, 375 sys_data->exit_event->event.type, sizeof(*entry), 376 irq_flags, pc); 377 if (!event) 378 return; 379 380 entry = ring_buffer_event_data(event); 381 entry->nr = syscall_nr; 382 entry->ret = syscall_get_return_value(current, regs); 383 384 event_trigger_unlock_commit(trace_file, buffer, event, entry, 385 irq_flags, pc); 386 } 387 388 static int reg_event_syscall_enter(struct trace_event_file *file, 389 struct trace_event_call *call) 390 { 391 struct trace_array *tr = file->tr; 392 int ret = 0; 393 int num; 394 395 num = ((struct syscall_metadata *)call->data)->syscall_nr; 396 if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls)) 397 return -ENOSYS; 398 mutex_lock(&syscall_trace_lock); 399 if (!tr->sys_refcount_enter) 400 ret = register_trace_sys_enter(ftrace_syscall_enter, tr); 401 if (!ret) { 402 rcu_assign_pointer(tr->enter_syscall_files[num], file); 403 tr->sys_refcount_enter++; 404 } 405 mutex_unlock(&syscall_trace_lock); 406 return ret; 407 } 408 409 static void unreg_event_syscall_enter(struct trace_event_file *file, 410 struct trace_event_call *call) 411 { 412 struct trace_array *tr = file->tr; 413 int num; 414 415 num = ((struct syscall_metadata *)call->data)->syscall_nr; 416 if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls)) 417 return; 418 mutex_lock(&syscall_trace_lock); 419 tr->sys_refcount_enter--; 420 RCU_INIT_POINTER(tr->enter_syscall_files[num], NULL); 421 if (!tr->sys_refcount_enter) 422 unregister_trace_sys_enter(ftrace_syscall_enter, tr); 423 mutex_unlock(&syscall_trace_lock); 424 } 425 426 static int reg_event_syscall_exit(struct trace_event_file *file, 427 struct trace_event_call *call) 428 { 429 struct trace_array *tr = file->tr; 430 int ret = 0; 431 int num; 432 433 num = ((struct syscall_metadata *)call->data)->syscall_nr; 434 if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls)) 435 return -ENOSYS; 436 mutex_lock(&syscall_trace_lock); 437 if (!tr->sys_refcount_exit) 438 ret = register_trace_sys_exit(ftrace_syscall_exit, tr); 439 if (!ret) { 440 rcu_assign_pointer(tr->exit_syscall_files[num], file); 441 tr->sys_refcount_exit++; 442 } 443 mutex_unlock(&syscall_trace_lock); 444 return ret; 445 } 446 447 static void unreg_event_syscall_exit(struct trace_event_file *file, 448 struct trace_event_call *call) 449 { 450 struct trace_array *tr = file->tr; 451 int num; 452 453 num = ((struct syscall_metadata *)call->data)->syscall_nr; 454 if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls)) 455 return; 456 mutex_lock(&syscall_trace_lock); 457 tr->sys_refcount_exit--; 458 RCU_INIT_POINTER(tr->exit_syscall_files[num], NULL); 459 if (!tr->sys_refcount_exit) 460 unregister_trace_sys_exit(ftrace_syscall_exit, tr); 461 mutex_unlock(&syscall_trace_lock); 462 } 463 464 static int __init init_syscall_trace(struct trace_event_call *call) 465 { 466 int id; 467 int num; 468 469 num = ((struct syscall_metadata *)call->data)->syscall_nr; 470 if (num < 0 || num >= NR_syscalls) { 471 pr_debug("syscall %s metadata not mapped, disabling ftrace event\n", 472 ((struct syscall_metadata *)call->data)->name); 473 return -ENOSYS; 474 } 475 476 if (set_syscall_print_fmt(call) < 0) 477 return -ENOMEM; 478 479 id = trace_event_raw_init(call); 480 481 if (id < 0) { 482 free_syscall_print_fmt(call); 483 return id; 484 } 485 486 return id; 487 } 488 489 static struct trace_event_fields __refdata syscall_enter_fields_array[] = { 490 SYSCALL_FIELD(int, __syscall_nr), 491 { .type = TRACE_FUNCTION_TYPE, 492 .define_fields = syscall_enter_define_fields }, 493 {} 494 }; 495 496 struct trace_event_functions enter_syscall_print_funcs = { 497 .trace = print_syscall_enter, 498 }; 499 500 struct trace_event_functions exit_syscall_print_funcs = { 501 .trace = print_syscall_exit, 502 }; 503 504 struct trace_event_class __refdata event_class_syscall_enter = { 505 .system = "syscalls", 506 .reg = syscall_enter_register, 507 .fields_array = syscall_enter_fields_array, 508 .get_fields = syscall_get_enter_fields, 509 .raw_init = init_syscall_trace, 510 }; 511 512 struct trace_event_class __refdata event_class_syscall_exit = { 513 .system = "syscalls", 514 .reg = syscall_exit_register, 515 .fields_array = (struct trace_event_fields[]){ 516 SYSCALL_FIELD(int, __syscall_nr), 517 SYSCALL_FIELD(long, ret), 518 {} 519 }, 520 .fields = LIST_HEAD_INIT(event_class_syscall_exit.fields), 521 .raw_init = init_syscall_trace, 522 }; 523 524 unsigned long __init __weak arch_syscall_addr(int nr) 525 { 526 return (unsigned long)sys_call_table[nr]; 527 } 528 529 void __init init_ftrace_syscalls(void) 530 { 531 struct syscall_metadata *meta; 532 unsigned long addr; 533 int i; 534 void *ret; 535 536 if (!IS_ENABLED(CONFIG_HAVE_SPARSE_SYSCALL_NR)) { 537 syscalls_metadata = kcalloc(NR_syscalls, 538 sizeof(*syscalls_metadata), 539 GFP_KERNEL); 540 if (!syscalls_metadata) { 541 WARN_ON(1); 542 return; 543 } 544 } 545 546 for (i = 0; i < NR_syscalls; i++) { 547 addr = arch_syscall_addr(i); 548 meta = find_syscall_meta(addr); 549 if (!meta) 550 continue; 551 552 meta->syscall_nr = i; 553 554 if (!IS_ENABLED(CONFIG_HAVE_SPARSE_SYSCALL_NR)) { 555 syscalls_metadata[i] = meta; 556 } else { 557 ret = xa_store(&syscalls_metadata_sparse, i, meta, 558 GFP_KERNEL); 559 WARN(xa_is_err(ret), 560 "Syscall memory allocation failed\n"); 561 } 562 563 } 564 } 565 566 #ifdef CONFIG_PERF_EVENTS 567 568 static DECLARE_BITMAP(enabled_perf_enter_syscalls, NR_syscalls); 569 static DECLARE_BITMAP(enabled_perf_exit_syscalls, NR_syscalls); 570 static int sys_perf_refcount_enter; 571 static int sys_perf_refcount_exit; 572 573 static int perf_call_bpf_enter(struct trace_event_call *call, struct pt_regs *regs, 574 struct syscall_metadata *sys_data, 575 struct syscall_trace_enter *rec) 576 { 577 struct syscall_tp_t { 578 unsigned long long regs; 579 unsigned long syscall_nr; 580 unsigned long args[SYSCALL_DEFINE_MAXARGS]; 581 } param; 582 int i; 583 584 *(struct pt_regs **)¶m = regs; 585 param.syscall_nr = rec->nr; 586 for (i = 0; i < sys_data->nb_args; i++) 587 param.args[i] = rec->args[i]; 588 return trace_call_bpf(call, ¶m); 589 } 590 591 static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id) 592 { 593 struct syscall_metadata *sys_data; 594 struct syscall_trace_enter *rec; 595 struct hlist_head *head; 596 unsigned long args[6]; 597 bool valid_prog_array; 598 int syscall_nr; 599 int rctx; 600 int size; 601 602 syscall_nr = trace_get_syscall_nr(current, regs); 603 if (syscall_nr < 0 || syscall_nr >= NR_syscalls) 604 return; 605 if (!test_bit(syscall_nr, enabled_perf_enter_syscalls)) 606 return; 607 608 sys_data = syscall_nr_to_meta(syscall_nr); 609 if (!sys_data) 610 return; 611 612 head = this_cpu_ptr(sys_data->enter_event->perf_events); 613 valid_prog_array = bpf_prog_array_valid(sys_data->enter_event); 614 if (!valid_prog_array && hlist_empty(head)) 615 return; 616 617 /* get the size after alignment with the u32 buffer size field */ 618 size = sizeof(unsigned long) * sys_data->nb_args + sizeof(*rec); 619 size = ALIGN(size + sizeof(u32), sizeof(u64)); 620 size -= sizeof(u32); 621 622 rec = perf_trace_buf_alloc(size, NULL, &rctx); 623 if (!rec) 624 return; 625 626 rec->nr = syscall_nr; 627 syscall_get_arguments(current, regs, args); 628 memcpy(&rec->args, args, sizeof(unsigned long) * sys_data->nb_args); 629 630 if ((valid_prog_array && 631 !perf_call_bpf_enter(sys_data->enter_event, regs, sys_data, rec)) || 632 hlist_empty(head)) { 633 perf_swevent_put_recursion_context(rctx); 634 return; 635 } 636 637 perf_trace_buf_submit(rec, size, rctx, 638 sys_data->enter_event->event.type, 1, regs, 639 head, NULL); 640 } 641 642 static int perf_sysenter_enable(struct trace_event_call *call) 643 { 644 int ret = 0; 645 int num; 646 647 num = ((struct syscall_metadata *)call->data)->syscall_nr; 648 649 mutex_lock(&syscall_trace_lock); 650 if (!sys_perf_refcount_enter) 651 ret = register_trace_sys_enter(perf_syscall_enter, NULL); 652 if (ret) { 653 pr_info("event trace: Could not activate syscall entry trace point"); 654 } else { 655 set_bit(num, enabled_perf_enter_syscalls); 656 sys_perf_refcount_enter++; 657 } 658 mutex_unlock(&syscall_trace_lock); 659 return ret; 660 } 661 662 static void perf_sysenter_disable(struct trace_event_call *call) 663 { 664 int num; 665 666 num = ((struct syscall_metadata *)call->data)->syscall_nr; 667 668 mutex_lock(&syscall_trace_lock); 669 sys_perf_refcount_enter--; 670 clear_bit(num, enabled_perf_enter_syscalls); 671 if (!sys_perf_refcount_enter) 672 unregister_trace_sys_enter(perf_syscall_enter, NULL); 673 mutex_unlock(&syscall_trace_lock); 674 } 675 676 static int perf_call_bpf_exit(struct trace_event_call *call, struct pt_regs *regs, 677 struct syscall_trace_exit *rec) 678 { 679 struct syscall_tp_t { 680 unsigned long long regs; 681 unsigned long syscall_nr; 682 unsigned long ret; 683 } param; 684 685 *(struct pt_regs **)¶m = regs; 686 param.syscall_nr = rec->nr; 687 param.ret = rec->ret; 688 return trace_call_bpf(call, ¶m); 689 } 690 691 static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret) 692 { 693 struct syscall_metadata *sys_data; 694 struct syscall_trace_exit *rec; 695 struct hlist_head *head; 696 bool valid_prog_array; 697 int syscall_nr; 698 int rctx; 699 int size; 700 701 syscall_nr = trace_get_syscall_nr(current, regs); 702 if (syscall_nr < 0 || syscall_nr >= NR_syscalls) 703 return; 704 if (!test_bit(syscall_nr, enabled_perf_exit_syscalls)) 705 return; 706 707 sys_data = syscall_nr_to_meta(syscall_nr); 708 if (!sys_data) 709 return; 710 711 head = this_cpu_ptr(sys_data->exit_event->perf_events); 712 valid_prog_array = bpf_prog_array_valid(sys_data->exit_event); 713 if (!valid_prog_array && hlist_empty(head)) 714 return; 715 716 /* We can probably do that at build time */ 717 size = ALIGN(sizeof(*rec) + sizeof(u32), sizeof(u64)); 718 size -= sizeof(u32); 719 720 rec = perf_trace_buf_alloc(size, NULL, &rctx); 721 if (!rec) 722 return; 723 724 rec->nr = syscall_nr; 725 rec->ret = syscall_get_return_value(current, regs); 726 727 if ((valid_prog_array && 728 !perf_call_bpf_exit(sys_data->exit_event, regs, rec)) || 729 hlist_empty(head)) { 730 perf_swevent_put_recursion_context(rctx); 731 return; 732 } 733 734 perf_trace_buf_submit(rec, size, rctx, sys_data->exit_event->event.type, 735 1, regs, head, NULL); 736 } 737 738 static int perf_sysexit_enable(struct trace_event_call *call) 739 { 740 int ret = 0; 741 int num; 742 743 num = ((struct syscall_metadata *)call->data)->syscall_nr; 744 745 mutex_lock(&syscall_trace_lock); 746 if (!sys_perf_refcount_exit) 747 ret = register_trace_sys_exit(perf_syscall_exit, NULL); 748 if (ret) { 749 pr_info("event trace: Could not activate syscall exit trace point"); 750 } else { 751 set_bit(num, enabled_perf_exit_syscalls); 752 sys_perf_refcount_exit++; 753 } 754 mutex_unlock(&syscall_trace_lock); 755 return ret; 756 } 757 758 static void perf_sysexit_disable(struct trace_event_call *call) 759 { 760 int num; 761 762 num = ((struct syscall_metadata *)call->data)->syscall_nr; 763 764 mutex_lock(&syscall_trace_lock); 765 sys_perf_refcount_exit--; 766 clear_bit(num, enabled_perf_exit_syscalls); 767 if (!sys_perf_refcount_exit) 768 unregister_trace_sys_exit(perf_syscall_exit, NULL); 769 mutex_unlock(&syscall_trace_lock); 770 } 771 772 #endif /* CONFIG_PERF_EVENTS */ 773 774 static int syscall_enter_register(struct trace_event_call *event, 775 enum trace_reg type, void *data) 776 { 777 struct trace_event_file *file = data; 778 779 switch (type) { 780 case TRACE_REG_REGISTER: 781 return reg_event_syscall_enter(file, event); 782 case TRACE_REG_UNREGISTER: 783 unreg_event_syscall_enter(file, event); 784 return 0; 785 786 #ifdef CONFIG_PERF_EVENTS 787 case TRACE_REG_PERF_REGISTER: 788 return perf_sysenter_enable(event); 789 case TRACE_REG_PERF_UNREGISTER: 790 perf_sysenter_disable(event); 791 return 0; 792 case TRACE_REG_PERF_OPEN: 793 case TRACE_REG_PERF_CLOSE: 794 case TRACE_REG_PERF_ADD: 795 case TRACE_REG_PERF_DEL: 796 return 0; 797 #endif 798 } 799 return 0; 800 } 801 802 static int syscall_exit_register(struct trace_event_call *event, 803 enum trace_reg type, void *data) 804 { 805 struct trace_event_file *file = data; 806 807 switch (type) { 808 case TRACE_REG_REGISTER: 809 return reg_event_syscall_exit(file, event); 810 case TRACE_REG_UNREGISTER: 811 unreg_event_syscall_exit(file, event); 812 return 0; 813 814 #ifdef CONFIG_PERF_EVENTS 815 case TRACE_REG_PERF_REGISTER: 816 return perf_sysexit_enable(event); 817 case TRACE_REG_PERF_UNREGISTER: 818 perf_sysexit_disable(event); 819 return 0; 820 case TRACE_REG_PERF_OPEN: 821 case TRACE_REG_PERF_CLOSE: 822 case TRACE_REG_PERF_ADD: 823 case TRACE_REG_PERF_DEL: 824 return 0; 825 #endif 826 } 827 return 0; 828 } 829