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-prev] [thread-next>] [day] [month] [year] [list]
Date:   Wed, 5 Jul 2017 13:45:03 -0700
From:   Krister Johansen <kjlx@...pleofstupid.com>
To:     Arnaldo Carvalho de Melo <acme@...nel.org>
Cc:     Krister Johansen <kjlx@...pleofstupid.com>,
        Peter Zijlstra <peterz@...radead.org>,
        Ingo Molnar <mingo@...hat.com>,
        Alexander Shishkin <alexander.shishkin@...ux.intel.com>,
        linux-kernel@...r.kernel.org
Subject: Re: [PATCH tip/perf/core 3/7] perf probe: allow placing uprobes in
 alternate namespaces.

On Mon, Jul 03, 2017 at 03:46:41PM -0300, Arnaldo Carvalho de Melo wrote:
> Em Fri, Jun 30, 2017 at 07:18:55PM -0700, Krister Johansen escreveu:
> > Teaches perf how to place a uprobe on a file that's in a different mount
> > namespace.  The user must add the probe using the --target-ns argument
> > to perf probe.  Once it has been placed, it may be recorded against
> > without further namespace-specific commands.
> > 
> > Signed-off-by: Krister Johansen <kjlx@...pleofstupid.com>
> > ---
> >  tools/perf/builtin-probe.c    | 44 ++++++++++++++++++++++--
> >  tools/perf/util/probe-event.c | 79 +++++++++++++++++++++++++++++--------------
> >  tools/perf/util/probe-event.h | 10 ++++--
> >  3 files changed, 101 insertions(+), 32 deletions(-)
> > 
> > diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
> > index cf9f9e9..5ab2e00 100644
> > --- a/tools/perf/builtin-probe.c
> > +++ b/tools/perf/builtin-probe.c
> > @@ -58,6 +58,7 @@ static struct {
> >  	struct line_range line_range;
> >  	char *target;
> >  	struct strfilter *filter;
> > +	struct nsinfo *nsi;
> >  } params;
> >  
> >  /* Parse an event definition. Note that any error must die. */
> > @@ -80,6 +81,9 @@ static int parse_probe_event(const char *str)
> >  		params.target_used = true;
> >  	}
> >  
> > +	if (params.nsi)
> > +		pev->nsi = nsinfo__get(params.nsi);
> > +
> >  	/* Parse a perf-probe command into event */
> >  	ret = parse_perf_probe_command(str, pev);
> >  	pr_debug("%d arguments\n", pev->nargs);
> > @@ -178,6 +182,7 @@ static int opt_set_target(const struct option *opt, const char *str,
> >  {
> >  	int ret = -ENOENT;
> >  	char *tmp;
> > +	struct nscookie nsc;
> >  
> >  	if  (str) {
> >  		if (!strcmp(opt->long_name, "exec"))
> > @@ -189,7 +194,9 @@ static int opt_set_target(const struct option *opt, const char *str,
> >  
> >  		/* Expand given path to absolute path, except for modulename */
> >  		if (params.uprobes || strchr(str, '/')) {
> > +			nsinfo__mountns_enter(params.nsi, &nsc);
> >  			tmp = realpath(str, NULL);
> > +			nsinfo__mountns_exit(&nsc);
> 
> Perhaps have a nsinfo__realpath()? Don't know if this will be used
> elsewhere, but looks shorter.

Sure.  I think I do this in a few different places.  I'd be happy to
pull this into its own function and re-use instead.

> >  			if (!tmp) {
> >  				pr_warning("Failed to get the absolute path of %s: %m\n", str);
> >  				return ret;
> > @@ -208,6 +215,34 @@ static int opt_set_target(const struct option *opt, const char *str,
> >  	return ret;
> >  }
> >  
> > +static int opt_set_target_ns(const struct option *opt __maybe_unused,
> > +			     const char *str, int unset __maybe_unused)
> > +{
> > +	int ret = -ENOENT;
> > +	pid_t ns_pid;
> > +	struct nsinfo *nsip;
> > +
> > +	if (str) {
> > +		errno = 0;
> > +		ns_pid = (pid_t)strtol(str, NULL, 10);
> > +		if (errno != 0) {
> > +			ret = -errno;
> > +			pr_warning("Failed to parse %s as a pid: %s\n", str,
> > +				   strerror(errno));
> > +			return ret;
> > +		}
> > +		nsip = nsinfo__new(ns_pid);
> > +		if (nsip && nsip->need_setns)
> > +			params.nsi = nsinfo__get(nsip);
> > +		nsinfo__put(nsip);
> > +
> > +		ret = 0;
> > +	}
> > +
> > +	return ret;
> > +}
> > +
> > +
> >  /* Command option callbacks */
> >  
> >  #ifdef HAVE_DWARF_SUPPORT
> > @@ -299,6 +334,7 @@ static void cleanup_params(void)
> >  	line_range__clear(&params.line_range);
> >  	free(params.target);
> >  	strfilter__delete(params.filter);
> > +	nsinfo__put(params.nsi);
> >  	memset(&params, 0, sizeof(params));
> >  }
> >  
> > @@ -554,6 +590,8 @@ __cmd_probe(int argc, const char **argv)
> >  	OPT_BOOLEAN(0, "cache", &probe_conf.cache, "Manipulate probe cache"),
> >  	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
> >  		   "Look for files with symbols relative to this directory"),
> > +	OPT_CALLBACK(0, "target-ns", NULL, "pid",
> > +		     "target pid for namespace information", opt_set_target_ns),
> >  	OPT_END()
> >  	};
> >  	int ret;
> > @@ -634,15 +672,15 @@ __cmd_probe(int argc, const char **argv)
> >  			pr_err_with_code("  Error: Failed to show event list.", ret);
> >  		return ret;
> >  	case 'F':
> > -		ret = show_available_funcs(params.target, params.filter,
> > -					params.uprobes);
> > +		ret = show_available_funcs(params.target, params.nsi,
> > +					   params.filter, params.uprobes);
> >  		if (ret < 0)
> >  			pr_err_with_code("  Error: Failed to show functions.", ret);
> >  		return ret;
> >  #ifdef HAVE_DWARF_SUPPORT
> >  	case 'L':
> >  		ret = show_line_range(&params.line_range, params.target,
> > -				      params.uprobes);
> > +				      params.nsi, params.uprobes);
> >  		if (ret < 0)
> >  			pr_err_with_code("  Error: Failed to show lines.", ret);
> >  		return ret;
> > diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
> > index 84e7e69..dce4f12 100644
> > --- a/tools/perf/util/probe-event.c
> > +++ b/tools/perf/util/probe-event.c
> > @@ -184,13 +184,19 @@ static struct map *kernel_get_module_map(const char *module)
> >  	return NULL;
> >  }
> >  
> > -struct map *get_target_map(const char *target, bool user)
> > +struct map *get_target_map(const char *target, struct nsinfo *nsi, bool user)
> >  {
> >  	/* Init maps of given executable or kernel */
> > -	if (user)
> > -		return dso__new_map(target);
> > -	else
> > +	if (user) {
> > +		struct map *map;
> > +
> > +		map = dso__new_map(target);
> > +		if (map && map->dso)
> > +			map->dso->nsinfo = nsinfo__get(nsi);
> > +		return map;
> > +	} else {
> >  		return kernel_get_module_map(target);
> > +	}
> >  }
> >  
> >  static int convert_exec_to_group(const char *exec, char **result)
> > @@ -366,7 +372,8 @@ static int kernel_get_module_dso(const char *module, struct dso **pdso)
> >  static int find_alternative_probe_point(struct debuginfo *dinfo,
> >  					struct perf_probe_point *pp,
> >  					struct perf_probe_point *result,
> > -					const char *target, bool uprobes)
> > +					const char *target, struct nsinfo *nsi,
> > +					bool uprobes)
> >  {
> >  	struct map *map = NULL;
> >  	struct symbol *sym;
> > @@ -377,7 +384,7 @@ static int find_alternative_probe_point(struct debuginfo *dinfo,
> >  	if (!pp->function || pp->file)
> >  		return -ENOTSUP;
> >  
> > -	map = get_target_map(target, uprobes);
> > +	map = get_target_map(target, nsi, uprobes);
> >  	if (!map)
> >  		return -EINVAL;
> >  
> > @@ -421,8 +428,8 @@ static int get_alternative_probe_event(struct debuginfo *dinfo,
> >  
> >  	memcpy(tmp, &pev->point, sizeof(*tmp));
> >  	memset(&pev->point, 0, sizeof(pev->point));
> > -	ret = find_alternative_probe_point(dinfo, tmp, &pev->point,
> > -					   pev->target, pev->uprobes);
> > +	ret = find_alternative_probe_point(dinfo, tmp, &pev->point, pev->target,
> > +					   pev->nsi, pev->uprobes);
> >  	if (ret < 0)
> >  		memcpy(&pev->point, tmp, sizeof(*tmp));
> >  
> > @@ -444,7 +451,7 @@ static int get_alternative_line_range(struct debuginfo *dinfo,
> >  	if (lr->end != INT_MAX)
> >  		len = lr->end - lr->start;
> >  	ret = find_alternative_probe_point(dinfo, &pp, &result,
> > -					   target, user);
> > +					   target, NULL, user);
> >  	if (!ret) {
> >  		lr->function = result.function;
> >  		lr->file = result.file;
> > @@ -457,12 +464,14 @@ static int get_alternative_line_range(struct debuginfo *dinfo,
> >  }
> >  
> >  /* Open new debuginfo of given module */
> > -static struct debuginfo *open_debuginfo(const char *module, bool silent)
> > +static struct debuginfo *open_debuginfo(const char *module, struct nsinfo *nsi,
> > +					bool silent)
> >  {
> >  	const char *path = module;
> >  	char reason[STRERR_BUFSIZE];
> >  	struct debuginfo *ret = NULL;
> >  	struct dso *dso = NULL;
> > +	struct nscookie nsc;
> >  	int err;
> >  
> >  	if (!module || !strchr(module, '/')) {
> > @@ -480,6 +489,7 @@ static struct debuginfo *open_debuginfo(const char *module, bool silent)
> >  		}
> >  		path = dso->long_name;
> >  	}
> > +	nsinfo__mountns_enter(nsi, &nsc);
> >  	ret = debuginfo__new(path);
> >  	if (!ret && !silent) {
> >  		pr_warning("The %s file has no debug information.\n", path);
> > @@ -489,6 +499,7 @@ static struct debuginfo *open_debuginfo(const char *module, bool silent)
> >  			pr_warning("Rebuild with -g, ");
> >  		pr_warning("or install an appropriate debuginfo package.\n");
> >  	}
> > +	nsinfo__mountns_exit(&nsc);
> >  	return ret;
> >  }
> >  
> > @@ -516,7 +527,7 @@ static struct debuginfo *debuginfo_cache__open(const char *module, bool silent)
> >  		goto out;
> >  	}
> >  
> > -	debuginfo_cache = open_debuginfo(module, silent);
> > +	debuginfo_cache = open_debuginfo(module, NULL, silent);
> >  	if (!debuginfo_cache)
> >  		zfree(&debuginfo_cache_path);
> >  out:
> > @@ -531,14 +542,18 @@ static void debuginfo_cache__exit(void)
> >  }
> >  
> >  
> > -static int get_text_start_address(const char *exec, unsigned long *address)
> > +static int get_text_start_address(const char *exec, unsigned long *address,
> > +				  struct nsinfo *nsi)
> >  {
> >  	Elf *elf;
> >  	GElf_Ehdr ehdr;
> >  	GElf_Shdr shdr;
> >  	int fd, ret = -ENOENT;
> > +	struct nscookie nsc;
> >  
> > +	nsinfo__mountns_enter(nsi, &nsc);
> >  	fd = open(exec, O_RDONLY);
> > +	nsinfo__mountns_exit(&nsc);
> >  	if (fd < 0)
> >  		return -errno;
> >  
> > @@ -582,7 +597,7 @@ static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp,
> >  			ret = -EINVAL;
> >  			goto error;
> >  		}
> > -		ret = get_text_start_address(tp->module, &stext);
> > +		ret = get_text_start_address(tp->module, &stext, NULL);
> >  		if (ret < 0)
> >  			goto error;
> >  		addr += stext;
> > @@ -659,7 +674,7 @@ post_process_offline_probe_trace_events(struct probe_trace_event *tevs,
> >  
> >  	/* Prepare a map for offline binary */
> >  	map = dso__new_map(pathname);
> > -	if (!map || get_text_start_address(pathname, &stext) < 0) {
> > +	if (!map || get_text_start_address(pathname, &stext, NULL) < 0) {
> >  		pr_warning("Failed to get ELF symbols for %s\n", pathname);
> >  		return -EINVAL;
> >  	}
> > @@ -676,7 +691,8 @@ post_process_offline_probe_trace_events(struct probe_trace_event *tevs,
> >  }
> >  
> >  static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
> > -					  int ntevs, const char *exec)
> > +					  int ntevs, const char *exec,
> > +					  struct nsinfo *nsi)
> >  {
> >  	int i, ret = 0;
> >  	unsigned long stext = 0;
> > @@ -684,7 +700,7 @@ static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
> >  	if (!exec)
> >  		return 0;
> >  
> > -	ret = get_text_start_address(exec, &stext);
> > +	ret = get_text_start_address(exec, &stext, nsi);
> >  	if (ret < 0)
> >  		return ret;
> >  
> > @@ -715,7 +731,7 @@ post_process_module_probe_trace_events(struct probe_trace_event *tevs,
> >  	if (!module)
> >  		return 0;
> >  
> > -	map = get_target_map(module, false);
> > +	map = get_target_map(module, NULL, false);
> >  	if (!map || debuginfo__get_text_offset(dinfo, &text_offs, true) < 0) {
> >  		pr_warning("Failed to get ELF symbols for %s\n", module);
> >  		return -EINVAL;
> > @@ -802,7 +818,8 @@ static int post_process_probe_trace_events(struct perf_probe_event *pev,
> >  	int ret;
> >  
> >  	if (uprobe)
> > -		ret = add_exec_to_probe_trace_events(tevs, ntevs, module);
> > +		ret = add_exec_to_probe_trace_events(tevs, ntevs, module,
> > +						     pev->nsi);
> >  	else if (module)
> >  		/* Currently ref_reloc_sym based probe is not for drivers */
> >  		ret = post_process_module_probe_trace_events(tevs, ntevs,
> > @@ -825,7 +842,7 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
> >  	struct debuginfo *dinfo;
> >  	int ntevs, ret = 0;
> >  
> > -	dinfo = open_debuginfo(pev->target, !need_dwarf);
> > +	dinfo = open_debuginfo(pev->target, pev->nsi, !need_dwarf);
> >  	if (!dinfo) {
> >  		if (need_dwarf)
> >  			return -ENOENT;
> > @@ -945,7 +962,7 @@ static int __show_line_range(struct line_range *lr, const char *module,
> >  	char sbuf[STRERR_BUFSIZE];
> >  
> >  	/* Search a line range */
> > -	dinfo = open_debuginfo(module, false);
> > +	dinfo = open_debuginfo(module, NULL, false);
> >  	if (!dinfo)
> >  		return -ENOENT;
> >  
> > @@ -1021,14 +1038,18 @@ static int __show_line_range(struct line_range *lr, const char *module,
> >  	return ret;
> >  }
> >  
> > -int show_line_range(struct line_range *lr, const char *module, bool user)
> > +int show_line_range(struct line_range *lr, const char *module,
> > +		    struct nsinfo *nsi, bool user)
> >  {
> >  	int ret;
> > +	struct nscookie nsc;
> >  
> >  	ret = init_probe_symbol_maps(user);
> >  	if (ret < 0)
> >  		return ret;
> > +	nsinfo__mountns_enter(nsi, &nsc);
> >  	ret = __show_line_range(lr, module, user);
> > +	nsinfo__mountns_exit(&nsc);
> >  	exit_probe_symbol_maps();
> >  
> >  	return ret;
> > @@ -1111,7 +1132,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
> >  	if (ret < 0)
> >  		return ret;
> >  
> > -	dinfo = open_debuginfo(pevs->target, false);
> > +	dinfo = open_debuginfo(pevs->target, pevs->nsi, false);
> >  	if (!dinfo) {
> >  		ret = -ENOENT;
> >  		goto out;
> > @@ -2703,6 +2724,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
> >  	struct probe_trace_event *tev = NULL;
> >  	struct probe_cache *cache = NULL;
> >  	struct strlist *namelist[2] = {NULL, NULL};
> > +	struct nscookie nsc;
> >  
> >  	up = pev->uprobes ? 1 : 0;
> >  	fd[up] = __open_probe_file_and_namelist(up, &namelist[up]);
> > @@ -2729,7 +2751,9 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
> >  		if (ret < 0)
> >  			break;
> >  
> > +		nsinfo__mountns_enter(pev->nsi, &nsc);
> >  		ret = probe_file__add_event(fd[up], tev);
> > +		nsinfo__mountns_exit(&nsc);
> >  		if (ret < 0)
> >  			break;
> >  
> > @@ -2805,7 +2829,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
> >  	int ret, i, j, skipped = 0;
> >  	char *mod_name;
> >  
> > -	map = get_target_map(pev->target, pev->uprobes);
> > +	map = get_target_map(pev->target, pev->nsi, pev->uprobes);
> >  	if (!map) {
> >  		ret = -EINVAL;
> >  		goto out;
> > @@ -3345,13 +3369,16 @@ int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs)
> >  void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs)
> >  {
> >  	int i, j;
> > +	struct perf_probe_event *pev;
> >  
> >  	/* Loop 3: cleanup and free trace events  */
> >  	for (i = 0; i < npevs; i++) {
> > +		pev = &pevs[i];
> >  		for (j = 0; j < pevs[i].ntevs; j++)
> >  			clear_probe_trace_event(&pevs[i].tevs[j]);
> >  		zfree(&pevs[i].tevs);
> >  		pevs[i].ntevs = 0;
> > +		nsinfo__zput(pev->nsi);
> >  		clear_perf_probe_event(&pevs[i]);
> >  	}
> >  }
> > @@ -3409,8 +3436,8 @@ int del_perf_probe_events(struct strfilter *filter)
> >  	return ret;
> >  }
> >  
> > -int show_available_funcs(const char *target, struct strfilter *_filter,
> > -					bool user)
> > +int show_available_funcs(const char *target, struct nsinfo *nsi,
> > +			 struct strfilter *_filter, bool user)
> >  {
> >          struct rb_node *nd;
> >  	struct map *map;
> > @@ -3421,7 +3448,7 @@ int show_available_funcs(const char *target, struct strfilter *_filter,
> >  		return ret;
> >  
> >  	/* Get a symbol map */
> > -	map = get_target_map(target, user);
> > +	map = get_target_map(target, nsi, user);
> >  	if (!map) {
> >  		pr_err("Failed to get a map for %s\n", (target) ? : "kernel");
> >  		return -EINVAL;
> > diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
> > index 5812947..078681d 100644
> > --- a/tools/perf/util/probe-event.h
> > +++ b/tools/perf/util/probe-event.h
> > @@ -4,6 +4,7 @@
> >  #include <linux/compiler.h>
> >  #include <stdbool.h>
> >  #include "intlist.h"
> > +#include "namespaces.h"
> >  
> >  /* Probe related configurations */
> >  struct probe_conf {
> > @@ -92,6 +93,7 @@ struct perf_probe_event {
> >  	struct perf_probe_arg	*args;	/* Arguments */
> >  	struct probe_trace_event *tevs;
> >  	int			ntevs;
> > +	struct nsinfo		*nsi;	/* Target namespace */
> >  };
> >  
> >  /* Line range */
> > @@ -163,10 +165,12 @@ int show_perf_probe_event(const char *group, const char *event,
> >  			  struct perf_probe_event *pev,
> >  			  const char *module, bool use_stdout);
> >  int show_perf_probe_events(struct strfilter *filter);
> > -int show_line_range(struct line_range *lr, const char *module, bool user);
> > +int show_line_range(struct line_range *lr, const char *module,
> > +		    struct nsinfo *nsi, bool user);
> >  int show_available_vars(struct perf_probe_event *pevs, int npevs,
> >  			struct strfilter *filter);
> > -int show_available_funcs(const char *module, struct strfilter *filter, bool user);
> > +int show_available_funcs(const char *module, struct nsinfo *nsi,
> > +			 struct strfilter *filter, bool user);
> >  void arch__fix_tev_from_maps(struct perf_probe_event *pev,
> >  			     struct probe_trace_event *tev, struct map *map,
> >  			     struct symbol *sym);
> > @@ -180,7 +184,7 @@ int e_snprintf(char *str, size_t size, const char *format, ...) __printf(3, 4);
> >  int copy_to_probe_trace_arg(struct probe_trace_arg *tvar,
> >  			    struct perf_probe_arg *pvar);
> >  
> > -struct map *get_target_map(const char *target, bool user);
> > +struct map *get_target_map(const char *target, struct nsinfo *nsi, bool user);
> >  
> >  void arch__post_process_probe_trace_events(struct perf_probe_event *pev,
> >  					   int ntevs);
> > -- 
> > 2.7.4

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ