From e4c4685fd6e4afd3e9b6818c96fded371f350a3f Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Thu, 19 Sep 2019 19:04:47 -0700 Subject: [PATCH] bpf: Fix race condition with map pinning If two processes attempt to invoke bpf_map_attach() at the same time, then they will both create maps, then the first will successfully pin the map to the filesystem and the second will not pin the map, but will continue operating with a reference to its own copy of the map. As a result, the sharing of the same map will be broken from the two programs that were concurrently loaded via loaders using this library. Fix this by adding a retry in the case where the pinning fails because the map already exists on the filesystem. In that case, re-attempt opening a fd to the map on the filesystem as it shows that another program already created and pinned a map at that location. Signed-off-by: Joe Stringer Signed-off-by: Stephen Hemminger --- lib/bpf.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/bpf.c b/lib/bpf.c index 7d2a322f..23cb0d96 100644 --- a/lib/bpf.c +++ b/lib/bpf.c @@ -1625,7 +1625,9 @@ static int bpf_map_attach(const char *name, struct bpf_elf_ctx *ctx, int *have_map_in_map) { int fd, ifindex, ret, map_inner_fd = 0; + bool retried = false; +probe: fd = bpf_probe_pinned(name, ctx, map->pinning); if (fd > 0) { ret = bpf_map_selfcheck_pinned(fd, map, ext, @@ -1674,10 +1676,14 @@ static int bpf_map_attach(const char *name, struct bpf_elf_ctx *ctx, } ret = bpf_place_pinned(fd, name, ctx, map->pinning); - if (ret < 0 && errno != EEXIST) { + if (ret < 0) { + close(fd); + if (!retried && errno == EEXIST) { + retried = true; + goto probe; + } fprintf(stderr, "Could not pin %s map: %s\n", name, strerror(errno)); - close(fd); return ret; }