2022-06-02 22:36:48

by Roberto Sassu

[permalink] [raw]
Subject: [PATCH v2 0/9] bpf: Per-operation map permissions

With the bpf_map security hook, an eBPF program is able to restrict access
to a map. For example, it might allow only read accesses and deny write
accesses.

Unfortunately, permissions are not accurately specified by libbpf and
bpftool. As a consequence, even if they are requested to perform a
read-like operation, such as a map lookup, that operation fails even if the
caller has the right to do so.

Even worse, the iteration over existing maps stops as soon as a
write-protected one is encountered. Maps after the write-protected one are
not accessible, even if the user has the right to perform operations on
them.

At low level, the problem is that open_flags and file_flags, respectively
in the bpf_map_get_fd_by_id() and bpf_obj_get(), are set to zero. The
kernel interprets this as a request to obtain a file descriptor with full
permissions.

For some operations, like show or dump, a read file descriptor is enough.
Those operations could be still performed even in a write-protected map.

Also for searching a map by name, which requires getting the map info, a
read file descriptor is enough. If an operation requires more permissions,
they could still be requested later, after the search.

First, solve both problems by extending libbpf with two new functions,
bpf_map_get_fd_by_id_flags() and bpf_obj_get_flags(), which unlike their
counterparts bpf_map_get_fd_by_id() and bpf_obj_get(), have the additional
parameter flags to specify the needed permissions for an operation.

Then, propagate the flags in bpftool from the functions implementing the
subcommands down to the functions calling bpf_map_get_fd_by_id() and
bpf_obj_get(), and replace the latter functions with their new variant.
Initially, set the flags to zero, so that the current behavior does not
change.

The only exception is for map search by name, where a read-only permission
is requested, regardless of the operation, to get the map info. In this
case, request a new file descriptor if a write-like operation needs to be
performed after the search.

Finally, identify other read-like operations in bpftool and for those
replace the zero value for flags with BPF_F_RDONLY.

The patch set is organized as follows.

Patches 1-2 introduce the two new variants of bpf_map_get_fd_by_id() and
bpf_obj_get() in libbpf, named respectively bpf_map_get_fd_by_id_flags()
and bpf_obj_get_flags().

Patches 3-7 propagate the flags in bpftool from the functions implementing
the subcommands to the two new libbpf functions, and always set flags to
BPF_F_RDONLY for the map search operation.

Patch 8 adjusts permissions depending on the map operation performed.

Patch 9 ensures that read-only accesses to a write-protected map succeed
and write accesses still fail. Also ensure that map search is always
successful even if there are write-protected maps.

Changelog

v1:
- Define per-operation permissions rather than retrying access with
read-only permission (suggested by Daniel)
https://lore.kernel.org/bpf/[email protected]/

Roberto Sassu (9):
libbpf: Introduce bpf_map_get_fd_by_id_flags()
libbpf: Introduce bpf_obj_get_flags()
bpftool: Add flags parameter to open_obj_pinned_any() and
open_obj_pinned()
bpftool: Add flags parameter to *_parse_fd() functions
bpftool: Add flags parameter to map_parse_fds()
bpftool: Add flags parameter to map_parse_fd_and_info()
bpftool: Add flags parameter in struct_ops functions
bpftool: Adjust map permissions
selftests/bpf: Add map access tests

tools/bpf/bpftool/btf.c | 11 +-
tools/bpf/bpftool/cgroup.c | 4 +-
tools/bpf/bpftool/common.c | 52 ++--
tools/bpf/bpftool/iter.c | 2 +-
tools/bpf/bpftool/link.c | 9 +-
tools/bpf/bpftool/main.h | 17 +-
tools/bpf/bpftool/map.c | 24 +-
tools/bpf/bpftool/map_perf_ring.c | 3 +-
tools/bpf/bpftool/net.c | 2 +-
tools/bpf/bpftool/prog.c | 12 +-
tools/bpf/bpftool/struct_ops.c | 39 ++-
tools/lib/bpf/bpf.c | 16 +-
tools/lib/bpf/bpf.h | 2 +
tools/lib/bpf/libbpf.map | 2 +
.../bpf/prog_tests/test_map_check_access.c | 264 ++++++++++++++++++
.../selftests/bpf/progs/map_check_access.c | 65 +++++
16 files changed, 452 insertions(+), 72 deletions(-)
create mode 100644 tools/testing/selftests/bpf/prog_tests/test_map_check_access.c
create mode 100644 tools/testing/selftests/bpf/progs/map_check_access.c

--
2.25.1



2022-06-03 09:48:21

by Roberto Sassu

[permalink] [raw]
Subject: [PATCH v2 2/9] libbpf: Introduce bpf_obj_get_flags()

Introduce the bpf_obj_get_flags() function, so that it is possible to
specify the needed permissions for obtaining a file descriptor from a
pinned object.

Signed-off-by: Roberto Sassu <[email protected]>
---
tools/lib/bpf/bpf.c | 8 +++++++-
tools/lib/bpf/bpf.h | 1 +
tools/lib/bpf/libbpf.map | 1 +
3 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 33bac2006043..a5fc40f6ce13 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -670,18 +670,24 @@ int bpf_obj_pin(int fd, const char *pathname)
return libbpf_err_errno(ret);
}

-int bpf_obj_get(const char *pathname)
+int bpf_obj_get_flags(const char *pathname, __u32 flags)
{
union bpf_attr attr;
int fd;

memset(&attr, 0, sizeof(attr));
attr.pathname = ptr_to_u64((void *)pathname);
+ attr.file_flags = flags;

fd = sys_bpf_fd(BPF_OBJ_GET, &attr, sizeof(attr));
return libbpf_err_errno(fd);
}

+int bpf_obj_get(const char *pathname)
+{
+ return bpf_obj_get_flags(pathname, 0);
+}
+
int bpf_prog_attach(int prog_fd, int target_fd, enum bpf_attach_type type,
unsigned int flags)
{
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index 20e4c852362d..6d0ceb2e90c4 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -339,6 +339,7 @@ LIBBPF_API int bpf_map_update_batch(int fd, const void *keys, const void *values
const struct bpf_map_batch_opts *opts);

LIBBPF_API int bpf_obj_pin(int fd, const char *pathname);
+LIBBPF_API int bpf_obj_get_flags(const char *pathname, __u32 flags);
LIBBPF_API int bpf_obj_get(const char *pathname);

struct bpf_prog_attach_opts {
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index 019278e66836..6c3ace12b27b 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -467,6 +467,7 @@ LIBBPF_1.0.0 {
libbpf_bpf_map_type_str;
libbpf_bpf_prog_type_str;
bpf_map_get_fd_by_id_flags;
+ bpf_obj_get_flags;

local: *;
};
--
2.25.1


2022-06-03 18:59:55

by Roberto Sassu

[permalink] [raw]
Subject: [PATCH v2 6/9] bpftool: Add flags parameter to map_parse_fd_and_info()

Add the flags parameter to map_parse_fd_and_info(), as this function is
called directly by the functions implementing bpftool subcommands, so that
it is possible to specify the right permissions for accessing a map.

Still pass zero as value for flags, and adjust permissions in a later
patch.

Signed-off-by: Roberto Sassu <[email protected]>
---
tools/bpf/bpftool/btf.c | 2 +-
tools/bpf/bpftool/common.c | 5 +++--
tools/bpf/bpftool/main.h | 3 ++-
tools/bpf/bpftool/map.c | 12 ++++++------
tools/bpf/bpftool/map_perf_ring.c | 3 ++-
5 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/tools/bpf/bpftool/btf.c b/tools/bpf/bpftool/btf.c
index 98569252ef4a..69a7695030f9 100644
--- a/tools/bpf/bpftool/btf.c
+++ b/tools/bpf/bpftool/btf.c
@@ -529,7 +529,7 @@ static int do_dump(int argc, char **argv)
return -1;
}

- fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
+ fd = map_parse_fd_and_info(&argc, &argv, &info, &len, 0);
if (fd < 0)
return -1;

diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
index 641810b78581..0816ea2f0be1 100644
--- a/tools/bpf/bpftool/common.c
+++ b/tools/bpf/bpftool/common.c
@@ -947,12 +947,13 @@ int map_parse_fd(int *argc, char ***argv, __u32 flags)
return fd;
}

-int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len)
+int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len,
+ __u32 flags)
{
int err;
int fd;

- fd = map_parse_fd(argc, argv, 0);
+ fd = map_parse_fd(argc, argv, flags);
if (fd < 0)
return -1;

diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 70b0ad6245b9..46c2f24f66fd 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -171,7 +171,8 @@ int prog_parse_fd(int *argc, char ***argv, __u32 flags);
int prog_parse_fds(int *argc, char ***argv, int **fds);
int map_parse_fd(int *argc, char ***argv, __u32 flags);
int map_parse_fds(int *argc, char ***argv, int **fds, __u32 flags);
-int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len);
+int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len,
+ __u32 flags);

struct bpf_prog_linfo;
#ifdef HAVE_LIBBFD_SUPPORT
diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
index 9a747918882e..f253f69879a9 100644
--- a/tools/bpf/bpftool/map.c
+++ b/tools/bpf/bpftool/map.c
@@ -998,7 +998,7 @@ static int do_update(int argc, char **argv)
if (argc < 2)
usage();

- fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
+ fd = map_parse_fd_and_info(&argc, &argv, &info, &len, 0);
if (fd < 0)
return -1;

@@ -1077,7 +1077,7 @@ static int do_lookup(int argc, char **argv)
if (argc < 2)
usage();

- fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
+ fd = map_parse_fd_and_info(&argc, &argv, &info, &len, 0);
if (fd < 0)
return -1;

@@ -1128,7 +1128,7 @@ static int do_getnext(int argc, char **argv)
if (argc < 2)
usage();

- fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
+ fd = map_parse_fd_and_info(&argc, &argv, &info, &len, 0);
if (fd < 0)
return -1;

@@ -1199,7 +1199,7 @@ static int do_delete(int argc, char **argv)
if (argc < 2)
usage();

- fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
+ fd = map_parse_fd_and_info(&argc, &argv, &info, &len, 0);
if (fd < 0)
return -1;

@@ -1311,7 +1311,7 @@ static int do_create(int argc, char **argv)
if (!REQ_ARGS(2))
usage();
inner_map_fd = map_parse_fd_and_info(&argc, &argv,
- &info, &len);
+ &info, &len, 0);
if (inner_map_fd < 0)
return -1;
attr.inner_map_fd = inner_map_fd;
@@ -1358,7 +1358,7 @@ static int do_pop_dequeue(int argc, char **argv)
if (argc < 2)
usage();

- fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
+ fd = map_parse_fd_and_info(&argc, &argv, &info, &len, 0);
if (fd < 0)
return -1;

diff --git a/tools/bpf/bpftool/map_perf_ring.c b/tools/bpf/bpftool/map_perf_ring.c
index 6b0c410152de..dcfc4724cd8d 100644
--- a/tools/bpf/bpftool/map_perf_ring.c
+++ b/tools/bpf/bpftool/map_perf_ring.c
@@ -135,7 +135,8 @@ int do_event_pipe(int argc, char **argv)
int err, map_fd;

map_info_len = sizeof(map_info);
- map_fd = map_parse_fd_and_info(&argc, &argv, &map_info, &map_info_len);
+ map_fd = map_parse_fd_and_info(&argc, &argv, &map_info, &map_info_len,
+ 0);
if (map_fd < 0)
return -1;

--
2.25.1

2022-06-04 14:57:20

by Andrii Nakryiko

[permalink] [raw]
Subject: Re: [PATCH v2 0/9] bpf: Per-operation map permissions

On Thu, Jun 2, 2022 at 7:38 AM Roberto Sassu <[email protected]> wrote:
>
> With the bpf_map security hook, an eBPF program is able to restrict access
> to a map. For example, it might allow only read accesses and deny write
> accesses.
>
> Unfortunately, permissions are not accurately specified by libbpf and
> bpftool. As a consequence, even if they are requested to perform a
> read-like operation, such as a map lookup, that operation fails even if the
> caller has the right to do so.
>
> Even worse, the iteration over existing maps stops as soon as a
> write-protected one is encountered. Maps after the write-protected one are
> not accessible, even if the user has the right to perform operations on
> them.
>
> At low level, the problem is that open_flags and file_flags, respectively
> in the bpf_map_get_fd_by_id() and bpf_obj_get(), are set to zero. The
> kernel interprets this as a request to obtain a file descriptor with full
> permissions.
>
> For some operations, like show or dump, a read file descriptor is enough.
> Those operations could be still performed even in a write-protected map.
>
> Also for searching a map by name, which requires getting the map info, a
> read file descriptor is enough. If an operation requires more permissions,
> they could still be requested later, after the search.
>
> First, solve both problems by extending libbpf with two new functions,
> bpf_map_get_fd_by_id_flags() and bpf_obj_get_flags(), which unlike their
> counterparts bpf_map_get_fd_by_id() and bpf_obj_get(), have the additional
> parameter flags to specify the needed permissions for an operation.
>
> Then, propagate the flags in bpftool from the functions implementing the
> subcommands down to the functions calling bpf_map_get_fd_by_id() and
> bpf_obj_get(), and replace the latter functions with their new variant.
> Initially, set the flags to zero, so that the current behavior does not
> change.
>
> The only exception is for map search by name, where a read-only permission
> is requested, regardless of the operation, to get the map info. In this
> case, request a new file descriptor if a write-like operation needs to be
> performed after the search.
>
> Finally, identify other read-like operations in bpftool and for those
> replace the zero value for flags with BPF_F_RDONLY.
>
> The patch set is organized as follows.
>
> Patches 1-2 introduce the two new variants of bpf_map_get_fd_by_id() and
> bpf_obj_get() in libbpf, named respectively bpf_map_get_fd_by_id_flags()
> and bpf_obj_get_flags().
>
> Patches 3-7 propagate the flags in bpftool from the functions implementing
> the subcommands to the two new libbpf functions, and always set flags to
> BPF_F_RDONLY for the map search operation.
>
> Patch 8 adjusts permissions depending on the map operation performed.
>
> Patch 9 ensures that read-only accesses to a write-protected map succeed
> and write accesses still fail. Also ensure that map search is always
> successful even if there are write-protected maps.
>
> Changelog
>
> v1:
> - Define per-operation permissions rather than retrying access with
> read-only permission (suggested by Daniel)
> https://lore.kernel.org/bpf/[email protected]/
>
> Roberto Sassu (9):
> libbpf: Introduce bpf_map_get_fd_by_id_flags()
> libbpf: Introduce bpf_obj_get_flags()
> bpftool: Add flags parameter to open_obj_pinned_any() and
> open_obj_pinned()
> bpftool: Add flags parameter to *_parse_fd() functions
> bpftool: Add flags parameter to map_parse_fds()
> bpftool: Add flags parameter to map_parse_fd_and_info()
> bpftool: Add flags parameter in struct_ops functions
> bpftool: Adjust map permissions
> selftests/bpf: Add map access tests
>
> tools/bpf/bpftool/btf.c | 11 +-
> tools/bpf/bpftool/cgroup.c | 4 +-
> tools/bpf/bpftool/common.c | 52 ++--
> tools/bpf/bpftool/iter.c | 2 +-
> tools/bpf/bpftool/link.c | 9 +-
> tools/bpf/bpftool/main.h | 17 +-
> tools/bpf/bpftool/map.c | 24 +-
> tools/bpf/bpftool/map_perf_ring.c | 3 +-
> tools/bpf/bpftool/net.c | 2 +-
> tools/bpf/bpftool/prog.c | 12 +-
> tools/bpf/bpftool/struct_ops.c | 39 ++-
> tools/lib/bpf/bpf.c | 16 +-
> tools/lib/bpf/bpf.h | 2 +
> tools/lib/bpf/libbpf.map | 2 +
> .../bpf/prog_tests/test_map_check_access.c | 264 ++++++++++++++++++
> .../selftests/bpf/progs/map_check_access.c | 65 +++++
> 16 files changed, 452 insertions(+), 72 deletions(-)
> create mode 100644 tools/testing/selftests/bpf/prog_tests/test_map_check_access.c
> create mode 100644 tools/testing/selftests/bpf/progs/map_check_access.c
>
> --
> 2.25.1
>

Also check CI failures ([0]).

test_test_map_check_access:PASS:skel 0 nsec
test_test_map_check_access:PASS:skel 0 nsec
test_test_map_check_access:PASS:bpf_object__find_map_by_name 0 nsec
test_test_map_check_access:PASS:bpf_obj_get_info_by_fd 0 nsec
test_test_map_check_access:PASS:bpf_map_get_fd_by_id 0 nsec
test_test_map_check_access:PASS:bpf_map_get_fd_by_id_flags 0 nsec
test_test_map_check_access:PASS:bpf_map_get_fd_by_id_flags 0 nsec
test_test_map_check_access:PASS:bpf_map_lookup_elem 0 nsec
test_test_map_check_access:PASS:bpf_map_update_elem 0 nsec
test_test_map_check_access:PASS:bpf_map_update_elem 0 nsec
test_test_map_check_access:PASS:bpf_map__pin 0 nsec
test_test_map_check_access:PASS:bpf_obj_get_flags 0 nsec
test_test_map_check_access:PASS:bpf_obj_get_flags 0 nsec
test_test_map_check_access:FAIL:bpftool map list - error: 127
#189 test_map_check_access:FAIL

[0] https://github.com/kernel-patches/bpf/runs/6730796689?check_suite_focus=true

2022-06-04 15:37:33

by Roberto Sassu

[permalink] [raw]
Subject: [PATCH v2 5/9] bpftool: Add flags parameter to map_parse_fds()

Add the flags parameter to map_parse_fds(), and the static function
map_fd_by_name() called by it. In the latter function, request the read
permission for the map search, and obtain a new file descriptor if the
flags variable has a different value.

Also pass the flags to the new functions bpf_map_get_fd_by_id_flags() and
the modified function open_obj_pinned_any().

At this point, there is still no change in the current behavior, as the
flags argument passed is always zero or the requested permission is a
subset (in map_fd_by_name()).

Signed-off-by: Roberto Sassu <[email protected]>
---
tools/bpf/bpftool/common.c | 25 ++++++++++++++++++-------
tools/bpf/bpftool/main.h | 2 +-
tools/bpf/bpftool/map.c | 4 ++--
3 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
index 54246109516f..641810b78581 100644
--- a/tools/bpf/bpftool/common.c
+++ b/tools/bpf/bpftool/common.c
@@ -799,7 +799,7 @@ int prog_parse_fd(int *argc, char ***argv, __u32 flags)
return fd;
}

-static int map_fd_by_name(char *name, int **fds)
+static int map_fd_by_name(char *name, int **fds, __u32 flags)
{
unsigned int id = 0;
int fd, nb_fds = 0;
@@ -819,7 +819,7 @@ static int map_fd_by_name(char *name, int **fds)
return nb_fds;
}

- fd = bpf_map_get_fd_by_id(id);
+ fd = bpf_map_get_fd_by_id_flags(id, BPF_F_RDONLY);
if (fd < 0) {
p_err("can't get map by id (%u): %s",
id, strerror(errno));
@@ -838,6 +838,17 @@ static int map_fd_by_name(char *name, int **fds)
continue;
}

+ if (flags != BPF_F_RDONLY) {
+ close(fd);
+
+ fd = bpf_map_get_fd_by_id_flags(id, flags);
+ if (fd < 0) {
+ p_err("can't get map by id (%u): %s",
+ id, strerror(errno));
+ goto err_close_fds;
+ }
+ }
+
if (nb_fds > 0) {
tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
if (!tmp) {
@@ -857,7 +868,7 @@ static int map_fd_by_name(char *name, int **fds)
return -1;
}

-int map_parse_fds(int *argc, char ***argv, int **fds)
+int map_parse_fds(int *argc, char ***argv, int **fds, __u32 flags)
{
if (is_prefix(**argv, "id")) {
unsigned int id;
@@ -872,7 +883,7 @@ int map_parse_fds(int *argc, char ***argv, int **fds)
}
NEXT_ARGP();

- (*fds)[0] = bpf_map_get_fd_by_id(id);
+ (*fds)[0] = bpf_map_get_fd_by_id_flags(id, flags);
if ((*fds)[0] < 0) {
p_err("get map by id (%u): %s", id, strerror(errno));
return -1;
@@ -890,7 +901,7 @@ int map_parse_fds(int *argc, char ***argv, int **fds)
}
NEXT_ARGP();

- return map_fd_by_name(name, fds);
+ return map_fd_by_name(name, fds, flags);
} else if (is_prefix(**argv, "pinned")) {
char *path;

@@ -899,7 +910,7 @@ int map_parse_fds(int *argc, char ***argv, int **fds)
path = **argv;
NEXT_ARGP();

- (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_MAP, 0);
+ (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_MAP, flags);
if ((*fds)[0] < 0)
return -1;
return 1;
@@ -919,7 +930,7 @@ int map_parse_fd(int *argc, char ***argv, __u32 flags)
p_err("mem alloc failed");
return -1;
}
- nb_fds = map_parse_fds(argc, argv, &fds);
+ nb_fds = map_parse_fds(argc, argv, &fds, flags);
if (nb_fds != 1) {
if (nb_fds > 1) {
p_err("several maps match this handle");
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index f342b2da4d8d..70b0ad6245b9 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -170,7 +170,7 @@ int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what);
int prog_parse_fd(int *argc, char ***argv, __u32 flags);
int prog_parse_fds(int *argc, char ***argv, int **fds);
int map_parse_fd(int *argc, char ***argv, __u32 flags);
-int map_parse_fds(int *argc, char ***argv, int **fds);
+int map_parse_fds(int *argc, char ***argv, int **fds, __u32 flags);
int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len);

struct bpf_prog_linfo;
diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
index d1231dce7183..9a747918882e 100644
--- a/tools/bpf/bpftool/map.c
+++ b/tools/bpf/bpftool/map.c
@@ -634,7 +634,7 @@ static int do_show_subset(int argc, char **argv)
p_err("mem alloc failed");
return -1;
}
- nb_fds = map_parse_fds(&argc, &argv, &fds);
+ nb_fds = map_parse_fds(&argc, &argv, &fds, 0);
if (nb_fds < 1)
goto exit_free;

@@ -910,7 +910,7 @@ static int do_dump(int argc, char **argv)
p_err("mem alloc failed");
return -1;
}
- nb_fds = map_parse_fds(&argc, &argv, &fds);
+ nb_fds = map_parse_fds(&argc, &argv, &fds, 0);
if (nb_fds < 1)
goto exit_free;

--
2.25.1

2022-06-06 04:12:49

by Roberto Sassu

[permalink] [raw]
Subject: [PATCH v2 4/9] bpftool: Add flags parameter to *_parse_fd() functions

Add the flags parameter to map_parse_fd(), prog_parse_fd(), link_parse_fd()
and btf_parse_fd() at the same time, as those functions are passed to
do_pin_any().

Pass zero to those functions, so that the current behavior does not change,
and adjust permissions in a later patch.

Signed-off-by: Roberto Sassu <[email protected]>
---
tools/bpf/bpftool/btf.c | 6 +++---
tools/bpf/bpftool/cgroup.c | 4 ++--
tools/bpf/bpftool/common.c | 10 +++++-----
tools/bpf/bpftool/iter.c | 2 +-
tools/bpf/bpftool/link.c | 7 ++++---
tools/bpf/bpftool/main.h | 7 ++++---
tools/bpf/bpftool/map.c | 6 +++---
tools/bpf/bpftool/net.c | 2 +-
tools/bpf/bpftool/prog.c | 10 +++++-----
9 files changed, 28 insertions(+), 26 deletions(-)

diff --git a/tools/bpf/bpftool/btf.c b/tools/bpf/bpftool/btf.c
index 7e6accb9d9f7..98569252ef4a 100644
--- a/tools/bpf/bpftool/btf.c
+++ b/tools/bpf/bpftool/btf.c
@@ -559,7 +559,7 @@ static int do_dump(int argc, char **argv)
return -1;
}

- fd = prog_parse_fd(&argc, &argv);
+ fd = prog_parse_fd(&argc, &argv, 0);
if (fd < 0)
return -1;

@@ -661,7 +661,7 @@ static int do_dump(int argc, char **argv)
return err;
}

-static int btf_parse_fd(int *argc, char ***argv)
+static int btf_parse_fd(int *argc, char ***argv, __u32 flags)
{
unsigned int id;
char *endptr;
@@ -931,7 +931,7 @@ static int do_show(int argc, char **argv)
__u32 id = 0;

if (argc == 2) {
- fd = btf_parse_fd(&argc, &argv);
+ fd = btf_parse_fd(&argc, &argv, 0);
if (fd < 0)
return -1;
}
diff --git a/tools/bpf/bpftool/cgroup.c b/tools/bpf/bpftool/cgroup.c
index 42421fe47a58..516d410a3218 100644
--- a/tools/bpf/bpftool/cgroup.c
+++ b/tools/bpf/bpftool/cgroup.c
@@ -425,7 +425,7 @@ static int do_attach(int argc, char **argv)

argc -= 2;
argv = &argv[2];
- prog_fd = prog_parse_fd(&argc, &argv);
+ prog_fd = prog_parse_fd(&argc, &argv, 0);
if (prog_fd < 0)
goto exit_cgroup;

@@ -483,7 +483,7 @@ static int do_detach(int argc, char **argv)

argc -= 2;
argv = &argv[2];
- prog_fd = prog_parse_fd(&argc, &argv);
+ prog_fd = prog_parse_fd(&argc, &argv, 0);
if (prog_fd < 0)
goto exit_cgroup;

diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
index 88e5e1900270..54246109516f 100644
--- a/tools/bpf/bpftool/common.c
+++ b/tools/bpf/bpftool/common.c
@@ -223,12 +223,12 @@ int do_pin_fd(int fd, const char *name)
return err;
}

-int do_pin_any(int argc, char **argv, int (*get_fd)(int *, char ***))
+int do_pin_any(int argc, char **argv, int (*get_fd)(int *, char ***, __u32))
{
int err;
int fd;

- fd = get_fd(&argc, &argv);
+ fd = get_fd(&argc, &argv, 0);
if (fd < 0)
return fd;

@@ -772,7 +772,7 @@ int prog_parse_fds(int *argc, char ***argv, int **fds)
return -1;
}

-int prog_parse_fd(int *argc, char ***argv)
+int prog_parse_fd(int *argc, char ***argv, __u32 flags)
{
int *fds = NULL;
int nb_fds, fd;
@@ -909,7 +909,7 @@ int map_parse_fds(int *argc, char ***argv, int **fds)
return -1;
}

-int map_parse_fd(int *argc, char ***argv)
+int map_parse_fd(int *argc, char ***argv, __u32 flags)
{
int *fds = NULL;
int nb_fds, fd;
@@ -941,7 +941,7 @@ int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len)
int err;
int fd;

- fd = map_parse_fd(argc, argv);
+ fd = map_parse_fd(argc, argv, 0);
if (fd < 0)
return -1;

diff --git a/tools/bpf/bpftool/iter.c b/tools/bpf/bpftool/iter.c
index f88fdc820d23..f7a35947f4f6 100644
--- a/tools/bpf/bpftool/iter.c
+++ b/tools/bpf/bpftool/iter.c
@@ -34,7 +34,7 @@ static int do_pin(int argc, char **argv)
return -1;
}

- map_fd = map_parse_fd(&argc, &argv);
+ map_fd = map_parse_fd(&argc, &argv, 0);
if (map_fd < 0)
return -1;

diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c
index 04447ad9b3b3..61bc6f1473ed 100644
--- a/tools/bpf/bpftool/link.c
+++ b/tools/bpf/bpftool/link.c
@@ -15,7 +15,7 @@

static struct hashmap *link_table;

-static int link_parse_fd(int *argc, char ***argv)
+static int link_parse_fd(int *argc, char ***argv, __u32 flags)
{
int fd;

@@ -44,6 +44,7 @@ static int link_parse_fd(int *argc, char ***argv)
path = **argv;
NEXT_ARGP();

+ /* WARNING: flags not passed for links (no security hook). */
return open_obj_pinned_any(path, BPF_OBJ_LINK, 0);
}

@@ -321,7 +322,7 @@ static int do_show(int argc, char **argv)
build_obj_refs_table(&refs_table, BPF_OBJ_LINK);

if (argc == 2) {
- fd = link_parse_fd(&argc, &argv);
+ fd = link_parse_fd(&argc, &argv, 0);
if (fd < 0)
return fd;
return do_show_link(fd);
@@ -385,7 +386,7 @@ static int do_detach(int argc, char **argv)
return 1;
}

- fd = link_parse_fd(&argc, &argv);
+ fd = link_parse_fd(&argc, &argv, 0);
if (fd < 0)
return 1;

diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 3f6c03afb2f8..f342b2da4d8d 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -145,7 +145,8 @@ int open_obj_pinned(const char *path, bool quiet, __u32 flags);
int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type,
__u32 flags);
int mount_bpffs_for_pin(const char *name);
-int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(int *, char ***));
+int do_pin_any(int argc, char **argv,
+ int (*get_fd_by_id)(int *, char ***, __u32));
int do_pin_fd(int fd, const char *name);

/* commands available in bootstrap mode */
@@ -166,9 +167,9 @@ int do_struct_ops(int argc, char **argv) __weak;
int do_iter(int argc, char **argv) __weak;

int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what);
-int prog_parse_fd(int *argc, char ***argv);
+int prog_parse_fd(int *argc, char ***argv, __u32 flags);
int prog_parse_fds(int *argc, char ***argv, int **fds);
-int map_parse_fd(int *argc, char ***argv);
+int map_parse_fd(int *argc, char ***argv, __u32 flags);
int map_parse_fds(int *argc, char ***argv, int **fds);
int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len);

diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
index 800834be1bcb..d1231dce7183 100644
--- a/tools/bpf/bpftool/map.c
+++ b/tools/bpf/bpftool/map.c
@@ -381,7 +381,7 @@ static int parse_elem(char **argv, struct bpf_map_info *info,
return -1;
}

- fd = map_parse_fd(&argc, &argv);
+ fd = map_parse_fd(&argc, &argv, 0);
if (fd < 0)
return -1;

@@ -402,7 +402,7 @@ static int parse_elem(char **argv, struct bpf_map_info *info,
p_info("Warning: updating program array via MAP_ID, make sure this map is kept open\n"
" by some process or pinned otherwise update will be lost");

- fd = prog_parse_fd(&argc, &argv);
+ fd = prog_parse_fd(&argc, &argv, 0);
if (fd < 0)
return -1;

@@ -1397,7 +1397,7 @@ static int do_freeze(int argc, char **argv)
if (!REQ_ARGS(2))
return -1;

- fd = map_parse_fd(&argc, &argv);
+ fd = map_parse_fd(&argc, &argv, 0);
if (fd < 0)
return -1;

diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
index 526a332c48e6..32360e07a6fa 100644
--- a/tools/bpf/bpftool/net.c
+++ b/tools/bpf/bpftool/net.c
@@ -571,7 +571,7 @@ static int do_attach(int argc, char **argv)
}
NEXT_ARG();

- progfd = prog_parse_fd(&argc, &argv);
+ progfd = prog_parse_fd(&argc, &argv, 0);
if (progfd < 0)
return -EINVAL;

diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index e71f0b2da50b..05480bf26a00 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -1027,7 +1027,7 @@ static int parse_attach_detach_args(int argc, char **argv, int *progfd,
if (!REQ_ARGS(3))
return -EINVAL;

- *progfd = prog_parse_fd(&argc, &argv);
+ *progfd = prog_parse_fd(&argc, &argv, 0);
if (*progfd < 0)
return *progfd;

@@ -1046,7 +1046,7 @@ static int parse_attach_detach_args(int argc, char **argv, int *progfd,
if (!REQ_ARGS(2))
return -EINVAL;

- *mapfd = map_parse_fd(&argc, &argv);
+ *mapfd = map_parse_fd(&argc, &argv, 0);
if (*mapfd < 0)
return *mapfd;

@@ -1270,7 +1270,7 @@ static int do_run(int argc, char **argv)
if (!REQ_ARGS(4))
return -1;

- fd = prog_parse_fd(&argc, &argv);
+ fd = prog_parse_fd(&argc, &argv, 0);
if (fd < 0)
return -1;

@@ -1542,7 +1542,7 @@ static int load_with_options(int argc, char **argv, bool first_prog_only)
}
NEXT_ARG();

- fd = map_parse_fd(&argc, &argv);
+ fd = map_parse_fd(&argc, &argv, 0);
if (fd < 0)
goto err_free_reuse_maps;

@@ -2231,7 +2231,7 @@ static int do_profile(int argc, char **argv)
return -EINVAL;

/* parse target fd */
- profile_tgt_fd = prog_parse_fd(&argc, &argv);
+ profile_tgt_fd = prog_parse_fd(&argc, &argv, 0);
if (profile_tgt_fd < 0) {
p_err("failed to parse fd");
return -1;
--
2.25.1

2022-06-06 05:04:02

by Andrii Nakryiko

[permalink] [raw]
Subject: Re: [PATCH v2 2/9] libbpf: Introduce bpf_obj_get_flags()

On Thu, Jun 2, 2022 at 7:38 AM Roberto Sassu <[email protected]> wrote:
>
> Introduce the bpf_obj_get_flags() function, so that it is possible to
> specify the needed permissions for obtaining a file descriptor from a
> pinned object.
>
> Signed-off-by: Roberto Sassu <[email protected]>
> ---
> tools/lib/bpf/bpf.c | 8 +++++++-
> tools/lib/bpf/bpf.h | 1 +
> tools/lib/bpf/libbpf.map | 1 +
> 3 files changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
> index 33bac2006043..a5fc40f6ce13 100644
> --- a/tools/lib/bpf/bpf.c
> +++ b/tools/lib/bpf/bpf.c
> @@ -670,18 +670,24 @@ int bpf_obj_pin(int fd, const char *pathname)
> return libbpf_err_errno(ret);
> }
>
> -int bpf_obj_get(const char *pathname)
> +int bpf_obj_get_flags(const char *pathname, __u32 flags)

same note about bpf_obj_get_opts() instead


> {
> union bpf_attr attr;
> int fd;
>
> memset(&attr, 0, sizeof(attr));
> attr.pathname = ptr_to_u64((void *)pathname);
> + attr.file_flags = flags;
>
> fd = sys_bpf_fd(BPF_OBJ_GET, &attr, sizeof(attr));
> return libbpf_err_errno(fd);
> }
>
> +int bpf_obj_get(const char *pathname)
> +{
> + return bpf_obj_get_flags(pathname, 0);
> +}
> +
> int bpf_prog_attach(int prog_fd, int target_fd, enum bpf_attach_type type,
> unsigned int flags)
> {
> diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
> index 20e4c852362d..6d0ceb2e90c4 100644
> --- a/tools/lib/bpf/bpf.h
> +++ b/tools/lib/bpf/bpf.h
> @@ -339,6 +339,7 @@ LIBBPF_API int bpf_map_update_batch(int fd, const void *keys, const void *values
> const struct bpf_map_batch_opts *opts);
>
> LIBBPF_API int bpf_obj_pin(int fd, const char *pathname);
> +LIBBPF_API int bpf_obj_get_flags(const char *pathname, __u32 flags);
> LIBBPF_API int bpf_obj_get(const char *pathname);
>
> struct bpf_prog_attach_opts {
> diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
> index 019278e66836..6c3ace12b27b 100644
> --- a/tools/lib/bpf/libbpf.map
> +++ b/tools/lib/bpf/libbpf.map
> @@ -467,6 +467,7 @@ LIBBPF_1.0.0 {
> libbpf_bpf_map_type_str;
> libbpf_bpf_prog_type_str;
> bpf_map_get_fd_by_id_flags;
> + bpf_obj_get_flags;
>
> local: *;
> };
> --
> 2.25.1
>

2022-06-06 05:06:17

by Roberto Sassu

[permalink] [raw]
Subject: [PATCH v2 8/9] bpftool: Adjust map permissions

Request a read file descriptor for:
- map subcommands: show_subset, show, dump, lookup, getnext and pin;
- btf subcommand: dump;
- prog subcommand: show (metadata);
- struct_ops subcommands: show and dump;
- do_build_table_cb(), to show the path of a pinned map.

Signed-off-by: Roberto Sassu <[email protected]>
---
tools/bpf/bpftool/btf.c | 5 +++--
tools/bpf/bpftool/common.c | 5 +++--
tools/bpf/bpftool/map.c | 10 +++++-----
tools/bpf/bpftool/prog.c | 2 +-
tools/bpf/bpftool/struct_ops.c | 4 ++--
5 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/tools/bpf/bpftool/btf.c b/tools/bpf/bpftool/btf.c
index 69a7695030f9..a36710903549 100644
--- a/tools/bpf/bpftool/btf.c
+++ b/tools/bpf/bpftool/btf.c
@@ -529,7 +529,8 @@ static int do_dump(int argc, char **argv)
return -1;
}

- fd = map_parse_fd_and_info(&argc, &argv, &info, &len, 0);
+ fd = map_parse_fd_and_info(&argc, &argv, &info, &len,
+ BPF_F_RDONLY);
if (fd < 0)
return -1;

@@ -730,7 +731,7 @@ build_btf_type_table(struct hashmap *tab, enum bpf_obj_type type,
fd = bpf_prog_get_fd_by_id(id);
break;
case BPF_OBJ_MAP:
- fd = bpf_map_get_fd_by_id(id);
+ fd = bpf_map_get_fd_by_id_flags(id, BPF_F_RDONLY);
break;
default:
err = -1;
diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
index 0816ea2f0be1..d20e1fa8a5fd 100644
--- a/tools/bpf/bpftool/common.c
+++ b/tools/bpf/bpftool/common.c
@@ -228,7 +228,7 @@ int do_pin_any(int argc, char **argv, int (*get_fd)(int *, char ***, __u32))
int err;
int fd;

- fd = get_fd(&argc, &argv, 0);
+ fd = get_fd(&argc, &argv, BPF_F_RDONLY);
if (fd < 0)
return fd;

@@ -401,7 +401,8 @@ static int do_build_table_cb(const char *fpath, const struct stat *sb,
if (typeflag != FTW_F)
goto out_ret;

- fd = open_obj_pinned(fpath, true, 0);
+ /* WARNING: setting flags to BPF_F_RDONLY has effect only for maps. */
+ fd = open_obj_pinned(fpath, true, BPF_F_RDONLY);
if (fd < 0)
goto out_ret;

diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
index f253f69879a9..e4346c834e07 100644
--- a/tools/bpf/bpftool/map.c
+++ b/tools/bpf/bpftool/map.c
@@ -634,7 +634,7 @@ static int do_show_subset(int argc, char **argv)
p_err("mem alloc failed");
return -1;
}
- nb_fds = map_parse_fds(&argc, &argv, &fds, 0);
+ nb_fds = map_parse_fds(&argc, &argv, &fds, BPF_F_RDONLY);
if (nb_fds < 1)
goto exit_free;

@@ -702,7 +702,7 @@ static int do_show(int argc, char **argv)
break;
}

- fd = bpf_map_get_fd_by_id(id);
+ fd = bpf_map_get_fd_by_id_flags(id, BPF_F_RDONLY);
if (fd < 0) {
if (errno == ENOENT)
continue;
@@ -910,7 +910,7 @@ static int do_dump(int argc, char **argv)
p_err("mem alloc failed");
return -1;
}
- nb_fds = map_parse_fds(&argc, &argv, &fds, 0);
+ nb_fds = map_parse_fds(&argc, &argv, &fds, BPF_F_RDONLY);
if (nb_fds < 1)
goto exit_free;

@@ -1077,7 +1077,7 @@ static int do_lookup(int argc, char **argv)
if (argc < 2)
usage();

- fd = map_parse_fd_and_info(&argc, &argv, &info, &len, 0);
+ fd = map_parse_fd_and_info(&argc, &argv, &info, &len, BPF_F_RDONLY);
if (fd < 0)
return -1;

@@ -1128,7 +1128,7 @@ static int do_getnext(int argc, char **argv)
if (argc < 2)
usage();

- fd = map_parse_fd_and_info(&argc, &argv, &info, &len, 0);
+ fd = map_parse_fd_and_info(&argc, &argv, &info, &len, BPF_F_RDONLY);
if (fd < 0)
return -1;

diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index 05480bf26a00..58d573badcb4 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -251,7 +251,7 @@ static void *find_metadata(int prog_fd, struct bpf_map_info *map_info)
goto free_map_ids;

for (i = 0; i < prog_info.nr_map_ids; i++) {
- map_fd = bpf_map_get_fd_by_id(map_ids[i]);
+ map_fd = bpf_map_get_fd_by_id_flags(map_ids[i], BPF_F_RDONLY);
if (map_fd < 0)
goto free_map_ids;

diff --git a/tools/bpf/bpftool/struct_ops.c b/tools/bpf/bpftool/struct_ops.c
index e8252a76e115..ced5fe62b1d7 100644
--- a/tools/bpf/bpftool/struct_ops.c
+++ b/tools/bpf/bpftool/struct_ops.c
@@ -359,7 +359,7 @@ static int do_show(int argc, char **argv)
}

res = do_work_on_struct_ops(search_type, search_term, __do_show,
- NULL, json_wtr, 0);
+ NULL, json_wtr, BPF_F_RDONLY);

return cmd_retval(&res, !!search_term);
}
@@ -448,7 +448,7 @@ static int do_dump(int argc, char **argv)
d.prog_id_as_func_ptr = true;

res = do_work_on_struct_ops(search_type, search_term, __do_dump, &d,
- wtr, 0);
+ wtr, BPF_F_RDONLY);

if (!json_output)
jsonw_destroy(&wtr);
--
2.25.1