linux/tools/perf/examples/bpf/augmented_syscalls.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Augment syscalls with the contents of the pointer arguments.
   4 *
   5 * Test it with:
   6 *
   7 * perf trace -e tools/perf/examples/bpf/augmented_syscalls.c cat /etc/passwd > /dev/null
   8 *
   9 * It'll catch some openat syscalls related to the dynamic linked and
  10 * the last one should be the one for '/etc/passwd'.
  11 *
  12 * This matches what is marshalled into the raw_syscall:sys_enter payload
  13 * expected by the 'perf trace' beautifiers, and can be used by them, that will
  14 * check if perf_sample->raw_data is more than what is expected for each
  15 * syscalls:sys_{enter,exit}_SYSCALL tracepoint, uing the extra data as the
  16 * contents of pointer arguments.
  17 */
  18
  19#include <stdio.h>
  20#include <linux/socket.h>
  21
  22/* bpf-output associated map */
  23bpf_map(__augmented_syscalls__, PERF_EVENT_ARRAY, int, u32, __NR_CPUS__);
  24
  25struct syscall_exit_args {
  26        unsigned long long common_tp_fields;
  27        long               syscall_nr;
  28        long               ret;
  29};
  30
  31struct augmented_filename {
  32        unsigned int    size;
  33        int             reserved;
  34        char            value[256];
  35};
  36
  37#define augmented_filename_syscall(syscall)                                                     \
  38struct augmented_enter_##syscall##_args {                                                       \
  39        struct syscall_enter_##syscall##_args   args;                                           \
  40        struct augmented_filename               filename;                                       \
  41};                                                                                              \
  42int syscall_enter(syscall)(struct syscall_enter_##syscall##_args *args)                         \
  43{                                                                                               \
  44        struct augmented_enter_##syscall##_args augmented_args = { .filename.reserved = 0, };   \
  45        unsigned int len = sizeof(augmented_args);                                              \
  46        probe_read(&augmented_args.args, sizeof(augmented_args.args), args);                    \
  47        augmented_args.filename.size = probe_read_str(&augmented_args.filename.value,           \
  48                                                      sizeof(augmented_args.filename.value),    \
  49                                                      args->filename_ptr);                      \
  50        if (augmented_args.filename.size < sizeof(augmented_args.filename.value)) {             \
  51                len -= sizeof(augmented_args.filename.value) - augmented_args.filename.size;    \
  52                len &= sizeof(augmented_args.filename.value) - 1;                               \
  53        }                                                                                       \
  54        /* If perf_event_output fails, return non-zero so that it gets recorded unaugmented */  \
  55        return perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU,              \
  56                                 &augmented_args, len);                                         \
  57}                                                                                               \
  58int syscall_exit(syscall)(struct syscall_exit_args *args)                                       \
  59{                                                                                               \
  60       return 1; /* 0 as soon as we start copying data returned by the kernel, e.g. 'read' */   \
  61}
  62
  63struct syscall_enter_openat_args {
  64        unsigned long long common_tp_fields;
  65        long               syscall_nr;
  66        long               dfd;
  67        char               *filename_ptr;
  68        long               flags;
  69        long               mode;
  70};
  71
  72augmented_filename_syscall(openat);
  73
  74struct syscall_enter_open_args {
  75        unsigned long long common_tp_fields;
  76        long               syscall_nr;
  77        char               *filename_ptr;
  78        long               flags;
  79        long               mode;
  80};
  81
  82augmented_filename_syscall(open);
  83
  84struct syscall_enter_inotify_add_watch_args {
  85        unsigned long long common_tp_fields;
  86        long               syscall_nr;
  87        long               fd;
  88        char               *filename_ptr;
  89        long               mask;
  90};
  91
  92augmented_filename_syscall(inotify_add_watch);
  93
  94struct statbuf;
  95
  96struct syscall_enter_newstat_args {
  97        unsigned long long common_tp_fields;
  98        long               syscall_nr;
  99        char               *filename_ptr;
 100        struct stat        *statbuf;
 101};
 102
 103augmented_filename_syscall(newstat);
 104
 105#ifndef _K_SS_MAXSIZE
 106#define _K_SS_MAXSIZE 128
 107#endif
 108
 109#define augmented_sockaddr_syscall(syscall)                                             \
 110struct augmented_enter_##syscall##_args {                                                       \
 111        struct syscall_enter_##syscall##_args   args;                                           \
 112        struct sockaddr_storage                 addr;                                           \
 113};                                                                                              \
 114int syscall_enter(syscall)(struct syscall_enter_##syscall##_args *args)                         \
 115{                                                                                               \
 116        struct augmented_enter_##syscall##_args augmented_args;                                 \
 117        unsigned long addrlen = sizeof(augmented_args.addr);                                    \
 118        probe_read(&augmented_args.args, sizeof(augmented_args.args), args);                    \
 119/* FIXME_CLANG_OPTIMIZATION_THAT_ACCESSES_USER_CONTROLLED_ADDRLEN_DESPITE_THIS_CHECK */         \
 120/*      if (addrlen > augmented_args.args.addrlen)                                   */         \
 121/*              addrlen = augmented_args.args.addrlen;                               */         \
 122/*                                                                                   */         \
 123        probe_read(&augmented_args.addr, addrlen, args->addr_ptr);                              \
 124        /* If perf_event_output fails, return non-zero so that it gets recorded unaugmented */  \
 125        return perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU,              \
 126                                 &augmented_args,                                               \
 127                                sizeof(augmented_args) - sizeof(augmented_args.addr) + addrlen);\
 128}                                                                                               \
 129int syscall_exit(syscall)(struct syscall_exit_args *args)                                       \
 130{                                                                                               \
 131       return 1; /* 0 as soon as we start copying data returned by the kernel, e.g. 'read' */   \
 132}
 133
 134struct sockaddr;
 135
 136struct syscall_enter_bind_args {
 137        unsigned long long common_tp_fields;
 138        long               syscall_nr;
 139        long               fd;
 140        struct sockaddr    *addr_ptr;
 141        unsigned long      addrlen;
 142};
 143
 144augmented_sockaddr_syscall(bind);
 145
 146struct syscall_enter_connect_args {
 147        unsigned long long common_tp_fields;
 148        long               syscall_nr;
 149        long               fd;
 150        struct sockaddr    *addr_ptr;
 151        unsigned long      addrlen;
 152};
 153
 154augmented_sockaddr_syscall(connect);
 155
 156struct syscall_enter_sendto_args {
 157        unsigned long long common_tp_fields;
 158        long               syscall_nr;
 159        long               fd;
 160        void               *buff;
 161        long               len;
 162        unsigned long      flags;
 163        struct sockaddr    *addr_ptr;
 164        long               addr_len;
 165};
 166
 167augmented_sockaddr_syscall(sendto);
 168
 169license(GPL);
 170