perf trace: Mark which syscall arguments go from user space to kernel space
authorArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 9 Sep 2024 19:29:44 +0000 (16:29 -0300)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 9 Sep 2024 22:23:03 +0000 (19:23 -0300)
We need to know where to collect it in the BPF augmenters, if in the
sys_enter hook or in the sys_exit hook.

Start with the SCA_FILENAME one, that is just from user to kernel space.

The alternative, better, but takes a bit more time than I have now, is
to use the __user information that is already in the syscall args and
encoded in BTF via a tag, do it later.

Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Howard Chu <howardchu95@gmail.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/builtin-trace.c

index 53690bbb143ed1adc502a0dbc6147765788223f2..64f0aefeba3b53c7dabbc9d96374a3a624868228 100644 (file)
 
 /*
  * strtoul: Go from a string to a value, i.e. for msr: MSR_FS_BASE to 0xc0000100
+ *
+ * We have to explicitely mark the direction of the flow of data, if from the
+ * kernel to user space or the other way around, since the BPF collector we
+ * have so far copies only from user to kernel space, mark the arguments that
+ * go that direction, so that we donĀ“t end up collecting the previous contents
+ * for syscall args that goes from kernel to user space.
  */
 struct syscall_arg_fmt {
        size_t     (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
@@ -110,6 +116,7 @@ struct syscall_arg_fmt {
        void       *parm;
        const char *name;
        u16        nr_entries; // for arrays
+       bool       from_user;
        bool       show_zero;
 #ifdef HAVE_LIBBPF_SUPPORT
        const struct btf_type *type;
@@ -851,6 +858,11 @@ static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
 
 #define SCA_FILENAME syscall_arg__scnprintf_filename
 
+// 'argname' is just documentational at this point, to remove the previous comment with that info
+#define SCA_FILENAME_FROM_USER(argname) \
+         { .scnprintf  = SCA_FILENAME, \
+           .from_user  = true, }
+
 static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
                                                struct syscall_arg *arg)
 {
@@ -1091,11 +1103,11 @@ static const struct syscall_fmt syscall_fmts[] = {
          .arg = { [1] = { .scnprintf = SCA_EFD_FLAGS, /* flags */ }, }, },
        { .name     = "faccessat",
          .arg = { [0] = { .scnprintf = SCA_FDAT,         /* dirfd */ },
-                  [1] = { .scnprintf = SCA_FILENAME,     /* pathname */ },
+                  [1] = SCA_FILENAME_FROM_USER(pathname),
                   [2] = { .scnprintf = SCA_ACCMODE,      /* mode */ }, }, },
        { .name     = "faccessat2",
          .arg = { [0] = { .scnprintf = SCA_FDAT,         /* dirfd */ },
-                  [1] = { .scnprintf = SCA_FILENAME,     /* pathname */ },
+                  [1] = SCA_FILENAME_FROM_USER(pathname),
                   [2] = { .scnprintf = SCA_ACCMODE,      /* mode */ },
                   [3] = { .scnprintf = SCA_FACCESSAT2_FLAGS, /* flags */ }, }, },
        { .name     = "fchmodat",
@@ -1117,7 +1129,7 @@ static const struct syscall_fmt syscall_fmts[] = {
                   [2] = { .scnprintf = SCA_FSMOUNT_ATTR_FLAGS, /* attr_flags */ }, }, },
        { .name     = "fspick",
          .arg = { [0] = { .scnprintf = SCA_FDAT,         /* dfd */ },
-                  [1] = { .scnprintf = SCA_FILENAME,     /* path */ },
+                  [1] = SCA_FILENAME_FROM_USER(path),
                   [2] = { .scnprintf = SCA_FSPICK_FLAGS, /* flags */ }, }, },
        { .name     = "fstat", .alias = "newfstat", },
        { .name     = "futex",
@@ -1181,20 +1193,20 @@ static const struct syscall_fmt syscall_fmts[] = {
                           .parm      = &strarray__mmap_flags, },
                   [5] = { .scnprintf = SCA_HEX,        /* offset */ }, }, },
        { .name     = "mount",
-         .arg = { [0] = { .scnprintf = SCA_FILENAME, /* dev_name */ },
+         .arg = { [0] = SCA_FILENAME_FROM_USER(devname),
                   [3] = { .scnprintf = SCA_MOUNT_FLAGS, /* flags */
                           .mask_val  = SCAMV_MOUNT_FLAGS, /* flags */ }, }, },
        { .name     = "move_mount",
          .arg = { [0] = { .scnprintf = SCA_FDAT,       /* from_dfd */ },
-                  [1] = { .scnprintf = SCA_FILENAME, /* from_pathname */ },
+                  [1] = SCA_FILENAME_FROM_USER(pathname),
                   [2] = { .scnprintf = SCA_FDAT,       /* to_dfd */ },
-                  [3] = { .scnprintf = SCA_FILENAME, /* to_pathname */ },
+                  [3] = SCA_FILENAME_FROM_USER(pathname),
                   [4] = { .scnprintf = SCA_MOVE_MOUNT_FLAGS, /* flags */ }, }, },
        { .name     = "mprotect",
          .arg = { [0] = { .scnprintf = SCA_HEX,        /* start */ },
                   [2] = { .scnprintf = SCA_MMAP_PROT, .show_zero = true, /* prot */ }, }, },
        { .name     = "mq_unlink",
-         .arg = { [0] = { .scnprintf = SCA_FILENAME, /* u_name */ }, }, },
+         .arg = { [0] = SCA_FILENAME_FROM_USER(u_name), }, },
        { .name     = "mremap",     .hexret = true,
          .arg = { [3] = { .scnprintf = SCA_MREMAP_FLAGS, /* flags */ }, }, },
        { .name     = "name_to_handle_at",
@@ -1203,7 +1215,7 @@ static const struct syscall_fmt syscall_fmts[] = {
          .arg = { [0] = { .scnprintf = SCA_TIMESPEC,  /* req */ }, }, },
        { .name     = "newfstatat", .alias = "fstatat",
          .arg = { [0] = { .scnprintf = SCA_FDAT,         /* dirfd */ },
-                  [1] = { .scnprintf = SCA_FILENAME,     /* pathname */ },
+                  [1] = SCA_FILENAME_FROM_USER(pathname),
                   [3] = { .scnprintf = SCA_FS_AT_FLAGS, /* flags */ }, }, },
        { .name     = "open",
          .arg = { [1] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
@@ -1299,9 +1311,9 @@ static const struct syscall_fmt syscall_fmts[] = {
                   [2] = { .scnprintf = SCA_FS_AT_FLAGS, /* flags */ } ,
                   [3] = { .scnprintf = SCA_STATX_MASK,  /* mask */ }, }, },
        { .name     = "swapoff",
-         .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
+         .arg = { [0] = SCA_FILENAME_FROM_USER(specialfile), }, },
        { .name     = "swapon",
-         .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
+         .arg = { [0] = SCA_FILENAME_FROM_USER(specialfile), }, },
        { .name     = "symlinkat",
          .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
        { .name     = "sync_file_range",
@@ -1311,11 +1323,11 @@ static const struct syscall_fmt syscall_fmts[] = {
        { .name     = "tkill",
          .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
        { .name     = "umount2", .alias = "umount",
-         .arg = { [0] = { .scnprintf = SCA_FILENAME, /* name */ }, }, },
+         .arg = { [0] = SCA_FILENAME_FROM_USER(name), }, },
        { .name     = "uname", .alias = "newuname", },
        { .name     = "unlinkat",
          .arg = { [0] = { .scnprintf = SCA_FDAT,         /* dfd */ },
-                  [1] = { .scnprintf = SCA_FILENAME,     /* pathname */ },
+                  [1] = SCA_FILENAME_FROM_USER(pathname),
                   [2] = { .scnprintf = SCA_FS_AT_FLAGS,  /* flags */ }, }, },
        { .name     = "utimensat",
          .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, }, },
@@ -1903,9 +1915,10 @@ syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field
 
                if (strcmp(field->type, "const char *") == 0 &&
                    ((len >= 4 && strcmp(field->name + len - 4, "name") == 0) ||
-                    strstr(field->name, "path") != NULL))
+                    strstr(field->name, "path") != NULL)) {
                        arg->scnprintf = SCA_FILENAME;
-               else if ((field->flags & TEP_FIELD_IS_POINTER) || strstr(field->name, "addr"))
+                       arg->from_user = true;
+               } else if ((field->flags & TEP_FIELD_IS_POINTER) || strstr(field->name, "addr"))
                        arg->scnprintf = SCA_PTR;
                else if (strcmp(field->type, "pid_t") == 0)
                        arg->scnprintf = SCA_PID;