lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <1461580708-15169-1-git-send-email-ravi.bangoria@linux.vnet.ibm.com>
Date:	Mon, 25 Apr 2016 16:08:27 +0530
From:	Ravi Bangoria <ravi.bangoria@...ux.vnet.ibm.com>
To:	linux-kernel@...r.kernel.org
Cc:	acme@...nel.org, peterz@...radead.org, mingo@...hat.com,
	alexander.shishkin@...ux.intel.com,
	masami.hiramatsu.pt@...achi.com, wangnan0@...wei.com,
	namhyung@...nel.org, srikar@...ux.vnet.ibm.com,
	naveen.n.rao@...ux.vnet.ibm.com,
	Ravi Bangoria <ravi.bangoria@...ux.vnet.ibm.com>
Subject: [RFC] perf probe: Fix offline module name missmatch issue

Perf can add a probe on kernel module which has not been loaded yet.
Current implementation finds module name from path. But if filename
is different from actual module name then perf fails to register
probe while loading module because of mismatch in names. For example,
samples/kobject/kobject-example.ko is loaded as kobject_example.

Before applying patch:

  $ sudo ./perf probe -m /linux/samples/kobject/kobject-example.ko foo_show
    Added new event:
      probe:foo_show       (on foo_show in kobject-example)

    You can now use it in all perf tools, such as:

    perf record -e probe:foo_show -aR sleep 1

  $ cat /sys/kernel/debug/tracing/kprobe_events
    p:probe/foo_show kobject-example:foo_show

  $ insmod kobject-example.ko

  $ lsmod
    Module                  Size  Used by
    kobject_example        16384  0

  Generate read to /sys/kernel/kobject_example/foo while recording data
  with below command
  $ sudo ./perf record -e probe:foo_show -a
    [ perf record: Woken up 1 times to write data ]
    [ perf record: Captured and wrote 0.093 MB perf.data ]

  $./perf report --stdio -F overhead,comm,dso,sym
    Error:
    The perf.data.old file has no samples!

After applying patch:

  $ sudo ./perf probe -m /linux/samples/kobject/kobject-example.ko foo_show
    Added new event:
      probe:foo_show       (on foo_show in kobject_example)

    You can now use it in all perf tools, such as:

    perf record -e probe:foo_show -aR sleep 1

  $ sudo cat /sys/kernel/debug/tracing/kprobe_events
    p:probe/foo_show kobject_example:foo_show

  $ insmod kobject-example.ko

  $ lsmod
    Module                  Size  Used by
    kobject_example        16384  0

  Generate read to /sys/kernel/kobject_example/foo while recording data
  with below command
  $ sudo ./perf record -e probe:foo_show -a
    [ perf record: Woken up 1 times to write data ]
    [ perf record: Captured and wrote 0.097 MB perf.data (8 samples) ]

  $ sudo ./perf report  --stdio -F overhead,comm,dso,sym
    ...
    # Samples: 8  of event 'probe:foo_show'
    # Event count (approx.): 8
    #
    # Overhead  Command  Shared Object      Symbol
    # ........  .......  .................  ............
    #
       100.00%  cat      [kobject_example]  [k] foo_show

Signed-off-by: Ravi Bangoria <ravi.bangoria@...ux.vnet.ibm.com>
---
 tools/perf/util/probe-event.c | 78 +++++++++++++++++++++++++++++++++++--------
 tools/perf/util/probe-event.h |  2 ++
 2 files changed, 66 insertions(+), 14 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 8319fbb..05d0905 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -265,6 +265,65 @@ static bool kprobe_warn_out_range(const char *symbol, unsigned long address)
 	return true;
 }
 
+/*
+ * NOTE:
+ * '.gnu.linkonce.this_module' section of kernel module elf directly
+ * maps to 'struct module' from linux/module.h. This section contains
+ * actual module name which will be used by kernel after loading it.
+ * But, we cannot use 'struct module' here since linux/module.h is not
+ * exposed to user-space. Offset of 'name' has remained same from long
+ * time, so hardcoding it here.
+ */
+#ifdef __LP64__
+#define MOD_NAME_OFFSET 24
+#else
+#define MOD_NAME_OFFSET 12
+#endif
+
+/*
+ * @module can be module name of module file path. In case of path,
+ * inspect elf and find out what is actual module name.
+ * Caller has to free mod_name after using it.
+ */
+char *find_module_name(const char *module)
+{
+	int fd;
+	Elf *elf;
+	GElf_Ehdr ehdr;
+	GElf_Shdr shdr;
+	Elf_Data *data;
+	Elf_Scn *sec;
+	char *mod_name = NULL;
+
+	fd = open(module, O_RDONLY);
+	if (fd < 0)
+		return NULL;
+
+	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+	if (elf == NULL)
+		goto elf_err;
+
+	if (gelf_getehdr(elf, &ehdr) == NULL)
+		goto ret_err;
+
+	sec = elf_section_by_name(elf, &ehdr, &shdr,
+			".gnu.linkonce.this_module", NULL);
+	if (!sec)
+		goto ret_err;
+
+	data = elf_getdata(sec, NULL);
+	if (!data || !data->d_buf)
+		goto ret_err;
+
+	mod_name = strdup((char *)data->d_buf + MOD_NAME_OFFSET);
+
+ret_err:
+	elf_end(elf);
+elf_err:
+	close(fd);
+	return mod_name;
+}
+
 #ifdef HAVE_DWARF_SUPPORT
 
 static int kernel_get_module_dso(const char *module, struct dso **pdso)
@@ -583,32 +642,23 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
 					    int ntevs, const char *module)
 {
 	int i, ret = 0;
-	char *tmp;
+	char *mod_name;
 
 	if (!module)
 		return 0;
 
-	tmp = strrchr(module, '/');
-	if (tmp) {
-		/* This is a module path -- get the module name */
-		module = strdup(tmp + 1);
-		if (!module)
-			return -ENOMEM;
-		tmp = strchr(module, '.');
-		if (tmp)
-			*tmp = '\0';
-		tmp = (char *)module;	/* For free() */
-	}
+	mod_name = find_module_name(module);
 
 	for (i = 0; i < ntevs; i++) {
-		tevs[i].point.module = strdup(module);
+		tevs[i].point.module =
+			strdup(mod_name ? mod_name : module);
 		if (!tevs[i].point.module) {
 			ret = -ENOMEM;
 			break;
 		}
 	}
 
-	free(tmp);
+	free(mod_name);
 	return ret;
 }
 
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index e54e7b0..0468fa3 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -166,4 +166,6 @@ int e_snprintf(char *str, size_t size, const char *format, ...)
 int copy_to_probe_trace_arg(struct probe_trace_arg *tvar,
 			    struct perf_probe_arg *pvar);
 
+char *find_module_name(const char *module);
+
 #endif /*_PROBE_EVENT_H */
-- 
2.1.4

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ