Commit 2832ef81 authored by Ian Rogers's avatar Ian Rogers Committed by Arnaldo Carvalho de Melo

perf map: Add reference count checking

There's no strict get/put policy with map that leads to leaks or use
after free. Reference count checking identifies correct pairing of gets
and puts.

Committer notes:

Extracted from a larger patch removing bits that were covered by the use
of pre-existing map__ accessors (e.g. maps__nr_maps()) and new ones
added (map__refcnt() and the maps__set_ ones) to reduce
RC_CHK_ACCESS(maps)-> source code pollution.
Signed-off-by: default avatarIan Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexey Bayduraev <alexey.v.bayduraev@linux.intel.com>
Cc: Dmitriy Vyukov <dvyukov@google.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Riccardo Mancini <rickyman7@gmail.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Stephen Brennan <stephen.s.brennan@oracle.com>
Link: https://lore.kernel.org/lkml/20230407230405.2931830-6-irogers@google.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent e6a9efce
...@@ -145,7 +145,7 @@ static int find_sample(struct sample *samples, size_t nr_samples, ...@@ -145,7 +145,7 @@ static int find_sample(struct sample *samples, size_t nr_samples,
{ {
while (nr_samples--) { while (nr_samples--) {
if (samples->thread == t && if (samples->thread == t &&
samples->map == m && RC_CHK_ACCESS(samples->map) == RC_CHK_ACCESS(m) &&
samples->sym == s) samples->sym == s)
return 1; return 1;
samples++; samples++;
......
...@@ -953,7 +953,7 @@ static int machine__process_ksymbol_unregister(struct machine *machine, ...@@ -953,7 +953,7 @@ static int machine__process_ksymbol_unregister(struct machine *machine,
if (!map) if (!map)
return 0; return 0;
if (map != machine->vmlinux_map) if (RC_CHK_ACCESS(map) != RC_CHK_ACCESS(machine->vmlinux_map))
maps__remove(machine__kernel_maps(machine), map); maps__remove(machine__kernel_maps(machine), map);
else { else {
struct dso *dso = map__dso(map); struct dso *dso = map__dso(map);
......
...@@ -120,11 +120,13 @@ struct map *map__new(struct machine *machine, u64 start, u64 len, ...@@ -120,11 +120,13 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
u32 prot, u32 flags, struct build_id *bid, u32 prot, u32 flags, struct build_id *bid,
char *filename, struct thread *thread) char *filename, struct thread *thread)
{ {
struct map *map = malloc(sizeof(*map)); struct map *result;
RC_STRUCT(map) *map;
struct nsinfo *nsi = NULL; struct nsinfo *nsi = NULL;
struct nsinfo *nnsi; struct nsinfo *nnsi;
if (map != NULL) { map = malloc(sizeof(*map));
if (ADD_RC_CHK(result, map)) {
char newfilename[PATH_MAX]; char newfilename[PATH_MAX];
struct dso *dso, *header_bid_dso; struct dso *dso, *header_bid_dso;
int anon, no_dso, vdso, android; int anon, no_dso, vdso, android;
...@@ -167,7 +169,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len, ...@@ -167,7 +169,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
if (dso == NULL) if (dso == NULL)
goto out_delete; goto out_delete;
map__init(map, start, start + len, pgoff, dso); map__init(result, start, start + len, pgoff, dso);
if (anon || no_dso) { if (anon || no_dso) {
map->map_ip = map->unmap_ip = identity__map_ip; map->map_ip = map->unmap_ip = identity__map_ip;
...@@ -204,10 +206,10 @@ struct map *map__new(struct machine *machine, u64 start, u64 len, ...@@ -204,10 +206,10 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
} }
dso__put(dso); dso__put(dso);
} }
return map; return result;
out_delete: out_delete:
nsinfo__put(nsi); nsinfo__put(nsi);
free(map); RC_CHK_FREE(result);
return NULL; return NULL;
} }
...@@ -218,16 +220,18 @@ struct map *map__new(struct machine *machine, u64 start, u64 len, ...@@ -218,16 +220,18 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
*/ */
struct map *map__new2(u64 start, struct dso *dso) struct map *map__new2(u64 start, struct dso *dso)
{ {
struct map *map = calloc(1, (sizeof(*map) + struct map *result;
(dso->kernel ? sizeof(struct kmap) : 0))); RC_STRUCT(map) *map;
if (map != NULL) {
map = calloc(1, sizeof(*map) + (dso->kernel ? sizeof(struct kmap) : 0));
if (ADD_RC_CHK(result, map)) {
/* /*
* ->end will be filled after we load all the symbols * ->end will be filled after we load all the symbols
*/ */
map__init(map, start, 0, 0, dso); map__init(result, start, 0, 0, dso);
} }
return map; return result;
} }
bool __map__is_kernel(const struct map *map) bool __map__is_kernel(const struct map *map)
...@@ -293,19 +297,21 @@ bool map__has_symbols(const struct map *map) ...@@ -293,19 +297,21 @@ bool map__has_symbols(const struct map *map)
static void map__exit(struct map *map) static void map__exit(struct map *map)
{ {
BUG_ON(refcount_read(map__refcnt(map)) != 0); BUG_ON(refcount_read(map__refcnt(map)) != 0);
dso__zput(map->dso); dso__zput(RC_CHK_ACCESS(map)->dso);
} }
void map__delete(struct map *map) void map__delete(struct map *map)
{ {
map__exit(map); map__exit(map);
free(map); RC_CHK_FREE(map);
} }
void map__put(struct map *map) void map__put(struct map *map)
{ {
if (map && refcount_dec_and_test(map__refcnt(map))) if (map && refcount_dec_and_test(map__refcnt(map)))
map__delete(map); map__delete(map);
else
RC_CHK_PUT(map);
} }
void map__fixup_start(struct map *map) void map__fixup_start(struct map *map)
...@@ -400,20 +406,21 @@ struct symbol *map__find_symbol_by_name(struct map *map, const char *name) ...@@ -400,20 +406,21 @@ struct symbol *map__find_symbol_by_name(struct map *map, const char *name)
struct map *map__clone(struct map *from) struct map *map__clone(struct map *from)
{ {
size_t size = sizeof(struct map); struct map *result;
struct map *map; RC_STRUCT(map) *map;
size_t size = sizeof(RC_STRUCT(map));
struct dso *dso = map__dso(from); struct dso *dso = map__dso(from);
if (dso && dso->kernel) if (dso && dso->kernel)
size += sizeof(struct kmap); size += sizeof(struct kmap);
map = memdup(from, size); map = memdup(RC_CHK_ACCESS(from), size);
if (map != NULL) { if (ADD_RC_CHK(result, map)) {
refcount_set(&map->refcnt, 1); refcount_set(&map->refcnt, 1);
map->dso = dso__get(dso); map->dso = dso__get(dso);
} }
return map; return result;
} }
size_t map__fprintf(struct map *map, FILE *fp) size_t map__fprintf(struct map *map, FILE *fp)
...@@ -567,7 +574,7 @@ struct kmap *__map__kmap(struct map *map) ...@@ -567,7 +574,7 @@ struct kmap *__map__kmap(struct map *map)
if (!dso || !dso->kernel) if (!dso || !dso->kernel)
return NULL; return NULL;
return (struct kmap *)(map + 1); return (struct kmap *)(&RC_CHK_ACCESS(map)[1]);
} }
struct kmap *map__kmap(struct map *map) struct kmap *map__kmap(struct map *map)
......
...@@ -10,12 +10,13 @@ ...@@ -10,12 +10,13 @@
#include <string.h> #include <string.h>
#include <stdbool.h> #include <stdbool.h>
#include <linux/types.h> #include <linux/types.h>
#include <internal/rc_check.h>
struct dso; struct dso;
struct maps; struct maps;
struct machine; struct machine;
struct map { DECLARE_RC_STRUCT(map) {
u64 start; u64 start;
u64 end; u64 end;
bool erange_warned:1; bool erange_warned:1;
...@@ -49,72 +50,72 @@ u64 identity__map_ip(const struct map *map __maybe_unused, u64 ip); ...@@ -49,72 +50,72 @@ u64 identity__map_ip(const struct map *map __maybe_unused, u64 ip);
static inline struct dso *map__dso(const struct map *map) static inline struct dso *map__dso(const struct map *map)
{ {
return map->dso; return RC_CHK_ACCESS(map)->dso;
} }
static inline u64 map__map_ip(const struct map *map, u64 ip) static inline u64 map__map_ip(const struct map *map, u64 ip)
{ {
return map->map_ip(map, ip); return RC_CHK_ACCESS(map)->map_ip(map, ip);
} }
static inline u64 map__unmap_ip(const struct map *map, u64 ip) static inline u64 map__unmap_ip(const struct map *map, u64 ip)
{ {
return map->unmap_ip(map, ip); return RC_CHK_ACCESS(map)->unmap_ip(map, ip);
} }
static inline void *map__map_ip_ptr(struct map *map) static inline void *map__map_ip_ptr(struct map *map)
{ {
return map->map_ip; return RC_CHK_ACCESS(map)->map_ip;
} }
static inline void* map__unmap_ip_ptr(struct map *map) static inline void* map__unmap_ip_ptr(struct map *map)
{ {
return map->unmap_ip; return RC_CHK_ACCESS(map)->unmap_ip;
} }
static inline u64 map__start(const struct map *map) static inline u64 map__start(const struct map *map)
{ {
return map->start; return RC_CHK_ACCESS(map)->start;
} }
static inline u64 map__end(const struct map *map) static inline u64 map__end(const struct map *map)
{ {
return map->end; return RC_CHK_ACCESS(map)->end;
} }
static inline u64 map__pgoff(const struct map *map) static inline u64 map__pgoff(const struct map *map)
{ {
return map->pgoff; return RC_CHK_ACCESS(map)->pgoff;
} }
static inline u64 map__reloc(const struct map *map) static inline u64 map__reloc(const struct map *map)
{ {
return map->reloc; return RC_CHK_ACCESS(map)->reloc;
} }
static inline u32 map__flags(const struct map *map) static inline u32 map__flags(const struct map *map)
{ {
return map->flags; return RC_CHK_ACCESS(map)->flags;
} }
static inline u32 map__prot(const struct map *map) static inline u32 map__prot(const struct map *map)
{ {
return map->prot; return RC_CHK_ACCESS(map)->prot;
} }
static inline bool map__priv(const struct map *map) static inline bool map__priv(const struct map *map)
{ {
return map->priv; return RC_CHK_ACCESS(map)->priv;
} }
static inline refcount_t *map__refcnt(struct map *map) static inline refcount_t *map__refcnt(struct map *map)
{ {
return &map->refcnt; return &RC_CHK_ACCESS(map)->refcnt;
} }
static inline bool map__erange_warned(struct map *map) static inline bool map__erange_warned(struct map *map)
{ {
return map->erange_warned; return RC_CHK_ACCESS(map)->erange_warned;
} }
static inline size_t map__size(const struct map *map) static inline size_t map__size(const struct map *map)
...@@ -173,9 +174,12 @@ struct map *map__clone(struct map *map); ...@@ -173,9 +174,12 @@ struct map *map__clone(struct map *map);
static inline struct map *map__get(struct map *map) static inline struct map *map__get(struct map *map)
{ {
if (map) struct map *result;
if (RC_CHK_GET(result, map))
refcount_inc(map__refcnt(map)); refcount_inc(map__refcnt(map));
return map;
return result;
} }
void map__put(struct map *map); void map__put(struct map *map);
...@@ -249,51 +253,51 @@ static inline int is_no_dso_memory(const char *filename) ...@@ -249,51 +253,51 @@ static inline int is_no_dso_memory(const char *filename)
static inline void map__set_start(struct map *map, u64 start) static inline void map__set_start(struct map *map, u64 start)
{ {
map->start = start; RC_CHK_ACCESS(map)->start = start;
} }
static inline void map__set_end(struct map *map, u64 end) static inline void map__set_end(struct map *map, u64 end)
{ {
map->end = end; RC_CHK_ACCESS(map)->end = end;
} }
static inline void map__set_pgoff(struct map *map, u64 pgoff) static inline void map__set_pgoff(struct map *map, u64 pgoff)
{ {
map->pgoff = pgoff; RC_CHK_ACCESS(map)->pgoff = pgoff;
} }
static inline void map__add_pgoff(struct map *map, u64 inc) static inline void map__add_pgoff(struct map *map, u64 inc)
{ {
map->pgoff += inc; RC_CHK_ACCESS(map)->pgoff += inc;
} }
static inline void map__set_reloc(struct map *map, u64 reloc) static inline void map__set_reloc(struct map *map, u64 reloc)
{ {
map->reloc = reloc; RC_CHK_ACCESS(map)->reloc = reloc;
} }
static inline void map__set_priv(struct map *map, int priv) static inline void map__set_priv(struct map *map, int priv)
{ {
map->priv = priv; RC_CHK_ACCESS(map)->priv = priv;
} }
static inline void map__set_erange_warned(struct map *map, bool erange_warned) static inline void map__set_erange_warned(struct map *map, bool erange_warned)
{ {
map->erange_warned = erange_warned; RC_CHK_ACCESS(map)->erange_warned = erange_warned;
} }
static inline void map__set_dso(struct map *map, struct dso *dso) static inline void map__set_dso(struct map *map, struct dso *dso)
{ {
map->dso = dso; RC_CHK_ACCESS(map)->dso = dso;
} }
static inline void map__set_map_ip(struct map *map, u64 (*map_ip)(const struct map *map, u64 ip)) static inline void map__set_map_ip(struct map *map, u64 (*map_ip)(const struct map *map, u64 ip))
{ {
map->map_ip = map_ip; RC_CHK_ACCESS(map)->map_ip = map_ip;
} }
static inline void map__set_unmap_ip(struct map *map, u64 (*unmap_ip)(const struct map *map, u64 rip)) static inline void map__set_unmap_ip(struct map *map, u64 (*unmap_ip)(const struct map *map, u64 rip))
{ {
map->unmap_ip = unmap_ip; RC_CHK_ACCESS(map)->unmap_ip = unmap_ip;
} }
#endif /* __PERF_MAP_H */ #endif /* __PERF_MAP_H */
...@@ -126,7 +126,7 @@ void maps__remove(struct maps *maps, struct map *map) ...@@ -126,7 +126,7 @@ void maps__remove(struct maps *maps, struct map *map)
RC_CHK_ACCESS(maps)->last_search_by_name = NULL; RC_CHK_ACCESS(maps)->last_search_by_name = NULL;
rb_node = maps__find_node(maps, map); rb_node = maps__find_node(maps, map);
assert(rb_node->map == map); assert(rb_node->RC_CHK_ACCESS(map) == RC_CHK_ACCESS(map));
__maps__remove(maps, rb_node); __maps__remove(maps, rb_node);
if (maps__maps_by_name(maps)) if (maps__maps_by_name(maps))
__maps__free_maps_by_name(maps); __maps__free_maps_by_name(maps);
...@@ -420,7 +420,7 @@ struct map_rb_node *maps__find_node(struct maps *maps, struct map *map) ...@@ -420,7 +420,7 @@ struct map_rb_node *maps__find_node(struct maps *maps, struct map *map)
struct map_rb_node *rb_node; struct map_rb_node *rb_node;
maps__for_each_entry(maps, rb_node) { maps__for_each_entry(maps, rb_node) {
if (rb_node->map == map) if (rb_node->RC_CHK_ACCESS(map) == RC_CHK_ACCESS(map))
return rb_node; return rb_node;
} }
return NULL; return NULL;
......
...@@ -865,7 +865,7 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta, ...@@ -865,7 +865,7 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta,
*module++ = '\0'; *module++ = '\0';
curr_map_dso = map__dso(curr_map); curr_map_dso = map__dso(curr_map);
if (strcmp(curr_map_dso->short_name, module)) { if (strcmp(curr_map_dso->short_name, module)) {
if (curr_map != initial_map && if (RC_CHK_ACCESS(curr_map) != RC_CHK_ACCESS(initial_map) &&
dso->kernel == DSO_SPACE__KERNEL_GUEST && dso->kernel == DSO_SPACE__KERNEL_GUEST &&
machine__is_default_guest(machine)) { machine__is_default_guest(machine)) {
/* /*
...@@ -1457,7 +1457,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map, ...@@ -1457,7 +1457,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
list_del_init(&new_node->node); list_del_init(&new_node->node);
if (new_map == replacement_map) { if (RC_CHK_ACCESS(new_map) == RC_CHK_ACCESS(replacement_map)) {
map__set_start(map, map__start(new_map)); map__set_start(map, map__start(new_map));
map__set_end(map, map__end(new_map)); map__set_end(map, map__end(new_map));
map__set_pgoff(map, map__pgoff(new_map)); map__set_pgoff(map, map__pgoff(new_map));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment