Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Augment syscalls with the contents of the pointer arguments.
0004  *
0005  * Test it with:
0006  *
0007  * perf trace -e tools/perf/examples/bpf/augmented_syscalls.c cat /etc/passwd > /dev/null
0008  *
0009  * It'll catch some openat syscalls related to the dynamic linked and
0010  * the last one should be the one for '/etc/passwd'.
0011  *
0012  * This matches what is marshalled into the raw_syscall:sys_enter payload
0013  * expected by the 'perf trace' beautifiers, and can be used by them, that will
0014  * check if perf_sample->raw_data is more than what is expected for each
0015  * syscalls:sys_{enter,exit}_SYSCALL tracepoint, uing the extra data as the
0016  * contents of pointer arguments.
0017  */
0018 
0019 #include <stdio.h>
0020 #include <linux/socket.h>
0021 
0022 /* bpf-output associated map */
0023 bpf_map(__augmented_syscalls__, PERF_EVENT_ARRAY, int, u32, __NR_CPUS__);
0024 
0025 struct syscall_exit_args {
0026     unsigned long long common_tp_fields;
0027     long           syscall_nr;
0028     long           ret;
0029 };
0030 
0031 struct augmented_filename {
0032     unsigned int    size;
0033     int     reserved;
0034     char        value[256];
0035 };
0036 
0037 #define augmented_filename_syscall(syscall)                         \
0038 struct augmented_enter_##syscall##_args {                           \
0039     struct syscall_enter_##syscall##_args   args;                       \
0040     struct augmented_filename       filename;                   \
0041 };                                              \
0042 int syscall_enter(syscall)(struct syscall_enter_##syscall##_args *args)             \
0043 {                                               \
0044     struct augmented_enter_##syscall##_args augmented_args = { .filename.reserved = 0, };   \
0045     unsigned int len = sizeof(augmented_args);                      \
0046     probe_read(&augmented_args.args, sizeof(augmented_args.args), args);            \
0047     augmented_args.filename.size = probe_read_str(&augmented_args.filename.value,       \
0048                               sizeof(augmented_args.filename.value),    \
0049                               args->filename_ptr);          \
0050     if (augmented_args.filename.size < sizeof(augmented_args.filename.value)) {     \
0051         len -= sizeof(augmented_args.filename.value) - augmented_args.filename.size;    \
0052         len &= sizeof(augmented_args.filename.value) - 1;               \
0053     }                                           \
0054     /* If perf_event_output fails, return non-zero so that it gets recorded unaugmented */  \
0055     return perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU,      \
0056                  &augmented_args, len);                     \
0057 }                                               \
0058 int syscall_exit(syscall)(struct syscall_exit_args *args)                   \
0059 {                                               \
0060        return 1; /* 0 as soon as we start copying data returned by the kernel, e.g. 'read' */   \
0061 }
0062 
0063 struct syscall_enter_openat_args {
0064     unsigned long long common_tp_fields;
0065     long           syscall_nr;
0066     long           dfd;
0067     char           *filename_ptr;
0068     long           flags;
0069     long           mode;
0070 };
0071 
0072 augmented_filename_syscall(openat);
0073 
0074 struct syscall_enter_open_args {
0075     unsigned long long common_tp_fields;
0076     long           syscall_nr;
0077     char           *filename_ptr;
0078     long           flags;
0079     long           mode;
0080 };
0081 
0082 augmented_filename_syscall(open);
0083 
0084 struct syscall_enter_inotify_add_watch_args {
0085     unsigned long long common_tp_fields;
0086     long           syscall_nr;
0087     long           fd;
0088     char           *filename_ptr;
0089     long           mask;
0090 };
0091 
0092 augmented_filename_syscall(inotify_add_watch);
0093 
0094 struct statbuf;
0095 
0096 struct syscall_enter_newstat_args {
0097     unsigned long long common_tp_fields;
0098     long           syscall_nr;
0099     char           *filename_ptr;
0100     struct stat    *statbuf;
0101 };
0102 
0103 augmented_filename_syscall(newstat);
0104 
0105 #ifndef _K_SS_MAXSIZE
0106 #define _K_SS_MAXSIZE 128
0107 #endif
0108 
0109 #define augmented_sockaddr_syscall(syscall)                     \
0110 struct augmented_enter_##syscall##_args {                           \
0111     struct syscall_enter_##syscall##_args   args;                       \
0112     struct sockaddr_storage         addr;                       \
0113 };                                              \
0114 int syscall_enter(syscall)(struct syscall_enter_##syscall##_args *args)             \
0115 {                                               \
0116     struct augmented_enter_##syscall##_args augmented_args;                 \
0117     unsigned long addrlen = sizeof(augmented_args.addr);                    \
0118     probe_read(&augmented_args.args, sizeof(augmented_args.args), args);            \
0119 /* FIXME_CLANG_OPTIMIZATION_THAT_ACCESSES_USER_CONTROLLED_ADDRLEN_DESPITE_THIS_CHECK */     \
0120 /*  if (addrlen > augmented_args.args.addrlen)                   */     \
0121 /*      addrlen = augmented_args.args.addrlen;                   */     \
0122 /*                                           */     \
0123     probe_read(&augmented_args.addr, addrlen, args->addr_ptr);              \
0124     /* If perf_event_output fails, return non-zero so that it gets recorded unaugmented */  \
0125     return perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU,      \
0126                  &augmented_args,                       \
0127                 sizeof(augmented_args) - sizeof(augmented_args.addr) + addrlen);\
0128 }                                               \
0129 int syscall_exit(syscall)(struct syscall_exit_args *args)                   \
0130 {                                               \
0131        return 1; /* 0 as soon as we start copying data returned by the kernel, e.g. 'read' */   \
0132 }
0133 
0134 struct sockaddr;
0135 
0136 struct syscall_enter_bind_args {
0137     unsigned long long common_tp_fields;
0138     long           syscall_nr;
0139     long           fd;
0140     struct sockaddr    *addr_ptr;
0141     unsigned long      addrlen;
0142 };
0143 
0144 augmented_sockaddr_syscall(bind);
0145 
0146 struct syscall_enter_connect_args {
0147     unsigned long long common_tp_fields;
0148     long           syscall_nr;
0149     long           fd;
0150     struct sockaddr    *addr_ptr;
0151     unsigned long      addrlen;
0152 };
0153 
0154 augmented_sockaddr_syscall(connect);
0155 
0156 struct syscall_enter_sendto_args {
0157     unsigned long long common_tp_fields;
0158     long           syscall_nr;
0159     long           fd;
0160     void           *buff;
0161     long           len;
0162     unsigned long      flags;
0163     struct sockaddr    *addr_ptr;
0164     long           addr_len;
0165 };
0166 
0167 augmented_sockaddr_syscall(sendto);
0168 
0169 license(GPL);