* [PATCH v2 1/9] libbpf: Introduce bpf_map_get_fd_by_id_flags()
2022-06-02 14:37 [PATCH v2 0/9] bpf: Per-operation map permissions Roberto Sassu
@ 2022-06-02 14:37 ` Roberto Sassu
2022-06-03 20:58 ` Andrii Nakryiko
2022-06-02 14:37 ` [PATCH v2 2/9] libbpf: Introduce bpf_obj_get_flags() Roberto Sassu
` (8 subsequent siblings)
9 siblings, 1 reply; 15+ messages in thread
From: Roberto Sassu @ 2022-06-02 14:37 UTC (permalink / raw)
To: ast, daniel, andrii, kpsingh
Cc: bpf, netdev, linux-kselftest, linux-kernel, Roberto Sassu
Introduce bpf_map_get_fd_by_id_flags(), to let a caller specify the open
flags needed for the operation. This could make an operation succeed, if
access to a map is restricted (i.e. it allows only certain operations).
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
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 240186aac8e6..33bac2006043 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -1047,18 +1047,24 @@ int bpf_prog_get_fd_by_id(__u32 id)
return libbpf_err_errno(fd);
}
-int bpf_map_get_fd_by_id(__u32 id)
+int bpf_map_get_fd_by_id_flags(__u32 id, __u32 flags)
{
union bpf_attr attr;
int fd;
memset(&attr, 0, sizeof(attr));
attr.map_id = id;
+ attr.open_flags = flags;
fd = sys_bpf_fd(BPF_MAP_GET_FD_BY_ID, &attr, sizeof(attr));
return libbpf_err_errno(fd);
}
+int bpf_map_get_fd_by_id(__u32 id)
+{
+ return bpf_map_get_fd_by_id_flags(id, 0);
+}
+
int bpf_btf_get_fd_by_id(__u32 id)
{
union bpf_attr attr;
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index cabc03703e29..20e4c852362d 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -438,6 +438,7 @@ LIBBPF_API int bpf_map_get_next_id(__u32 start_id, __u32 *next_id);
LIBBPF_API int bpf_btf_get_next_id(__u32 start_id, __u32 *next_id);
LIBBPF_API int bpf_link_get_next_id(__u32 start_id, __u32 *next_id);
LIBBPF_API int bpf_prog_get_fd_by_id(__u32 id);
+LIBBPF_API int bpf_map_get_fd_by_id_flags(__u32 id, __u32 flags);
LIBBPF_API int bpf_map_get_fd_by_id(__u32 id);
LIBBPF_API int bpf_btf_get_fd_by_id(__u32 id);
LIBBPF_API int bpf_link_get_fd_by_id(__u32 id);
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index 38e284ff057d..019278e66836 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -466,6 +466,7 @@ LIBBPF_1.0.0 {
libbpf_bpf_link_type_str;
libbpf_bpf_map_type_str;
libbpf_bpf_prog_type_str;
+ bpf_map_get_fd_by_id_flags;
local: *;
};
--
2.25.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [PATCH v2 1/9] libbpf: Introduce bpf_map_get_fd_by_id_flags()
2022-06-02 14:37 ` [PATCH v2 1/9] libbpf: Introduce bpf_map_get_fd_by_id_flags() Roberto Sassu
@ 2022-06-03 20:58 ` Andrii Nakryiko
0 siblings, 0 replies; 15+ messages in thread
From: Andrii Nakryiko @ 2022-06-03 20:58 UTC (permalink / raw)
To: Roberto Sassu
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, KP Singh,
bpf, Networking, open list:KERNEL SELFTEST FRAMEWORK, open list
On Thu, Jun 2, 2022 at 7:38 AM Roberto Sassu <roberto.sassu@huawei.com> wrote:
>
> Introduce bpf_map_get_fd_by_id_flags(), to let a caller specify the open
> flags needed for the operation. This could make an operation succeed, if
> access to a map is restricted (i.e. it allows only certain operations).
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> ---
> 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 240186aac8e6..33bac2006043 100644
> --- a/tools/lib/bpf/bpf.c
> +++ b/tools/lib/bpf/bpf.c
> @@ -1047,18 +1047,24 @@ int bpf_prog_get_fd_by_id(__u32 id)
> return libbpf_err_errno(fd);
> }
>
> -int bpf_map_get_fd_by_id(__u32 id)
> +int bpf_map_get_fd_by_id_flags(__u32 id, __u32 flags)
let's go the OPTS route instead so that we don't have to add any more
new variants? We can probably use common bpf_get_fd_by_id_opts for
map/prog/link/btf get_fd_by_id operations (and let's add all variants
for consistency)?
> {
> union bpf_attr attr;
> int fd;
>
> memset(&attr, 0, sizeof(attr));
> attr.map_id = id;
> + attr.open_flags = flags;
>
> fd = sys_bpf_fd(BPF_MAP_GET_FD_BY_ID, &attr, sizeof(attr));
> return libbpf_err_errno(fd);
> }
>
> +int bpf_map_get_fd_by_id(__u32 id)
> +{
> + return bpf_map_get_fd_by_id_flags(id, 0);
> +}
> +
> int bpf_btf_get_fd_by_id(__u32 id)
> {
> union bpf_attr attr;
> diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
> index cabc03703e29..20e4c852362d 100644
> --- a/tools/lib/bpf/bpf.h
> +++ b/tools/lib/bpf/bpf.h
> @@ -438,6 +438,7 @@ LIBBPF_API int bpf_map_get_next_id(__u32 start_id, __u32 *next_id);
> LIBBPF_API int bpf_btf_get_next_id(__u32 start_id, __u32 *next_id);
> LIBBPF_API int bpf_link_get_next_id(__u32 start_id, __u32 *next_id);
> LIBBPF_API int bpf_prog_get_fd_by_id(__u32 id);
> +LIBBPF_API int bpf_map_get_fd_by_id_flags(__u32 id, __u32 flags);
> LIBBPF_API int bpf_map_get_fd_by_id(__u32 id);
> LIBBPF_API int bpf_btf_get_fd_by_id(__u32 id);
> LIBBPF_API int bpf_link_get_fd_by_id(__u32 id);
> diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
> index 38e284ff057d..019278e66836 100644
> --- a/tools/lib/bpf/libbpf.map
> +++ b/tools/lib/bpf/libbpf.map
> @@ -466,6 +466,7 @@ LIBBPF_1.0.0 {
> libbpf_bpf_link_type_str;
> libbpf_bpf_map_type_str;
> libbpf_bpf_prog_type_str;
> + bpf_map_get_fd_by_id_flags;
>
> local: *;
> };
> --
> 2.25.1
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2 2/9] libbpf: Introduce bpf_obj_get_flags()
2022-06-02 14:37 [PATCH v2 0/9] bpf: Per-operation map permissions Roberto Sassu
2022-06-02 14:37 ` [PATCH v2 1/9] libbpf: Introduce bpf_map_get_fd_by_id_flags() Roberto Sassu
@ 2022-06-02 14:37 ` Roberto Sassu
2022-06-03 20:59 ` Andrii Nakryiko
2022-06-02 14:37 ` [PATCH v2 3/9] bpftool: Add flags parameter to open_obj_pinned_any() and open_obj_pinned() Roberto Sassu
` (7 subsequent siblings)
9 siblings, 1 reply; 15+ messages in thread
From: Roberto Sassu @ 2022-06-02 14:37 UTC (permalink / raw)
To: ast, daniel, andrii, kpsingh
Cc: bpf, netdev, linux-kselftest, linux-kernel, Roberto Sassu
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 <roberto.sassu@huawei.com>
---
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
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [PATCH v2 2/9] libbpf: Introduce bpf_obj_get_flags()
2022-06-02 14:37 ` [PATCH v2 2/9] libbpf: Introduce bpf_obj_get_flags() Roberto Sassu
@ 2022-06-03 20:59 ` Andrii Nakryiko
0 siblings, 0 replies; 15+ messages in thread
From: Andrii Nakryiko @ 2022-06-03 20:59 UTC (permalink / raw)
To: Roberto Sassu
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, KP Singh,
bpf, Networking, open list:KERNEL SELFTEST FRAMEWORK, open list
On Thu, Jun 2, 2022 at 7:38 AM Roberto Sassu <roberto.sassu@huawei.com> 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 <roberto.sassu@huawei.com>
> ---
> 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
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2 3/9] bpftool: Add flags parameter to open_obj_pinned_any() and open_obj_pinned()
2022-06-02 14:37 [PATCH v2 0/9] bpf: Per-operation map permissions Roberto Sassu
2022-06-02 14:37 ` [PATCH v2 1/9] libbpf: Introduce bpf_map_get_fd_by_id_flags() Roberto Sassu
2022-06-02 14:37 ` [PATCH v2 2/9] libbpf: Introduce bpf_obj_get_flags() Roberto Sassu
@ 2022-06-02 14:37 ` Roberto Sassu
2022-06-02 14:37 ` [PATCH v2 4/9] bpftool: Add flags parameter to *_parse_fd() functions Roberto Sassu
` (6 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Roberto Sassu @ 2022-06-02 14:37 UTC (permalink / raw)
To: ast, daniel, andrii, kpsingh
Cc: bpf, netdev, linux-kselftest, linux-kernel, Roberto Sassu
Add the flags parameter to open_obj_pinned_any() and open_obj_pinned(), so
that it is possible to specify the right permissions when obtaining a file
descriptor from a pinned object.
By default, the value passed to those functions is zero, so that there is
no change in the current behavior.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
tools/bpf/bpftool/common.c | 15 ++++++++-------
tools/bpf/bpftool/link.c | 2 +-
tools/bpf/bpftool/main.h | 5 +++--
3 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
index a45b42ee8ab0..88e5e1900270 100644
--- a/tools/bpf/bpftool/common.c
+++ b/tools/bpf/bpftool/common.c
@@ -118,7 +118,7 @@ int mount_tracefs(const char *target)
return err;
}
-int open_obj_pinned(const char *path, bool quiet)
+int open_obj_pinned(const char *path, bool quiet, __u32 flags)
{
char *pname;
int fd = -1;
@@ -130,7 +130,7 @@ int open_obj_pinned(const char *path, bool quiet)
goto out_ret;
}
- fd = bpf_obj_get(pname);
+ fd = bpf_obj_get_flags(pname, flags);
if (fd < 0) {
if (!quiet)
p_err("bpf obj get (%s): %s", pname,
@@ -146,12 +146,13 @@ int open_obj_pinned(const char *path, bool quiet)
return fd;
}
-int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type)
+int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type,
+ __u32 flags)
{
enum bpf_obj_type type;
int fd;
- fd = open_obj_pinned(path, false);
+ fd = open_obj_pinned(path, false, flags);
if (fd < 0)
return -1;
@@ -400,7 +401,7 @@ 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);
+ fd = open_obj_pinned(fpath, true, 0);
if (fd < 0)
goto out_ret;
@@ -761,7 +762,7 @@ int prog_parse_fds(int *argc, char ***argv, int **fds)
path = **argv;
NEXT_ARGP();
- (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_PROG);
+ (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_PROG, 0);
if ((*fds)[0] < 0)
return -1;
return 1;
@@ -898,7 +899,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);
+ (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_MAP, 0);
if ((*fds)[0] < 0)
return -1;
return 1;
diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c
index 7a20931c3250..04447ad9b3b3 100644
--- a/tools/bpf/bpftool/link.c
+++ b/tools/bpf/bpftool/link.c
@@ -44,7 +44,7 @@ static int link_parse_fd(int *argc, char ***argv)
path = **argv;
NEXT_ARGP();
- return open_obj_pinned_any(path, BPF_OBJ_LINK);
+ return open_obj_pinned_any(path, BPF_OBJ_LINK, 0);
}
p_err("expected 'id' or 'pinned', got: '%s'?", **argv);
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 6c311f47147e..3f6c03afb2f8 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -141,8 +141,9 @@ void get_prog_full_name(const struct bpf_prog_info *prog_info, int prog_fd,
int get_fd_type(int fd);
const char *get_fd_type_name(enum bpf_obj_type type);
char *get_fdinfo(int fd, const char *key);
-int open_obj_pinned(const char *path, bool quiet);
-int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type);
+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_fd(int fd, const char *name);
--
2.25.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v2 4/9] bpftool: Add flags parameter to *_parse_fd() functions
2022-06-02 14:37 [PATCH v2 0/9] bpf: Per-operation map permissions Roberto Sassu
` (2 preceding siblings ...)
2022-06-02 14:37 ` [PATCH v2 3/9] bpftool: Add flags parameter to open_obj_pinned_any() and open_obj_pinned() Roberto Sassu
@ 2022-06-02 14:37 ` Roberto Sassu
2022-06-02 14:37 ` [PATCH v2 5/9] bpftool: Add flags parameter to map_parse_fds() Roberto Sassu
` (5 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Roberto Sassu @ 2022-06-02 14:37 UTC (permalink / raw)
To: ast, daniel, andrii, kpsingh
Cc: bpf, netdev, linux-kselftest, linux-kernel, Roberto Sassu
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 <roberto.sassu@huawei.com>
---
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
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v2 5/9] bpftool: Add flags parameter to map_parse_fds()
2022-06-02 14:37 [PATCH v2 0/9] bpf: Per-operation map permissions Roberto Sassu
` (3 preceding siblings ...)
2022-06-02 14:37 ` [PATCH v2 4/9] bpftool: Add flags parameter to *_parse_fd() functions Roberto Sassu
@ 2022-06-02 14:37 ` Roberto Sassu
2022-06-02 14:37 ` [PATCH v2 6/9] bpftool: Add flags parameter to map_parse_fd_and_info() Roberto Sassu
` (4 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Roberto Sassu @ 2022-06-02 14:37 UTC (permalink / raw)
To: ast, daniel, andrii, kpsingh
Cc: bpf, netdev, linux-kselftest, linux-kernel, Roberto Sassu
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 <roberto.sassu@huawei.com>
---
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
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v2 6/9] bpftool: Add flags parameter to map_parse_fd_and_info()
2022-06-02 14:37 [PATCH v2 0/9] bpf: Per-operation map permissions Roberto Sassu
` (4 preceding siblings ...)
2022-06-02 14:37 ` [PATCH v2 5/9] bpftool: Add flags parameter to map_parse_fds() Roberto Sassu
@ 2022-06-02 14:37 ` Roberto Sassu
2022-06-02 14:37 ` [PATCH v2 7/9] bpftool: Add flags parameter in struct_ops functions Roberto Sassu
` (3 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Roberto Sassu @ 2022-06-02 14:37 UTC (permalink / raw)
To: ast, daniel, andrii, kpsingh
Cc: bpf, netdev, linux-kselftest, linux-kernel, Roberto Sassu
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 <roberto.sassu@huawei.com>
---
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
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v2 7/9] bpftool: Add flags parameter in struct_ops functions
2022-06-02 14:37 [PATCH v2 0/9] bpf: Per-operation map permissions Roberto Sassu
` (5 preceding siblings ...)
2022-06-02 14:37 ` [PATCH v2 6/9] bpftool: Add flags parameter to map_parse_fd_and_info() Roberto Sassu
@ 2022-06-02 14:37 ` Roberto Sassu
2022-06-02 14:37 ` [PATCH v2 8/9] bpftool: Adjust map permissions Roberto Sassu
` (2 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Roberto Sassu @ 2022-06-02 14:37 UTC (permalink / raw)
To: ast, daniel, andrii, kpsingh
Cc: bpf, netdev, linux-kselftest, linux-kernel, Roberto Sassu
Add the flags parameter to struct_ops functions, to distinguish between
read-like and write-like operations on struct_ops maps.
Also, always perform the search with read-only permission, and eventually
obtain a new file descriptor if the requested permission is different.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
tools/bpf/bpftool/struct_ops.c | 39 +++++++++++++++++++++++-----------
1 file changed, 27 insertions(+), 12 deletions(-)
diff --git a/tools/bpf/bpftool/struct_ops.c b/tools/bpf/bpftool/struct_ops.c
index 2535f079ed67..e8252a76e115 100644
--- a/tools/bpf/bpftool/struct_ops.c
+++ b/tools/bpf/bpftool/struct_ops.c
@@ -130,7 +130,8 @@ static struct bpf_map_info *map_info_alloc(__u32 *alloc_len)
* -1: Error and the caller should abort the iteration.
*/
static int get_next_struct_ops_map(const char *name, int *res_fd,
- struct bpf_map_info *info, __u32 info_len)
+ struct bpf_map_info *info, __u32 info_len,
+ __u32 flags)
{
__u32 id = info->id;
int err, fd;
@@ -144,7 +145,7 @@ static int get_next_struct_ops_map(const char *name, int *res_fd,
return -1;
}
- 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;
@@ -162,6 +163,19 @@ static int get_next_struct_ops_map(const char *name, int *res_fd,
if (info->type == BPF_MAP_TYPE_STRUCT_OPS &&
(!name || !strcmp(name, info->name))) {
+ if (flags != BPF_F_RDONLY) {
+ close(fd);
+
+ fd = bpf_map_get_fd_by_id_flags(id, flags);
+ if (fd < 0) {
+ if (errno == ENOENT)
+ continue;
+ p_err("can't get map by id (%u): %s",
+ id, strerror(errno));
+ return -1;
+ }
+ }
+
*res_fd = fd;
return 1;
}
@@ -186,7 +200,7 @@ typedef int (*work_func)(int fd, const struct bpf_map_info *info, void *data,
* Then call "func(fd, info, data, wtr)" on each struct_ops map found.
*/
static struct res do_search(const char *name, work_func func, void *data,
- struct json_writer *wtr)
+ struct json_writer *wtr, __u32 flags)
{
struct bpf_map_info *info;
struct res res = {};
@@ -201,7 +215,8 @@ static struct res do_search(const char *name, work_func func, void *data,
if (wtr)
jsonw_start_array(wtr);
- while ((err = get_next_struct_ops_map(name, &fd, info, info_len)) == 1) {
+ while ((err = get_next_struct_ops_map(name, &fd, info, info_len,
+ flags)) == 1) {
res.nr_maps++;
err = func(fd, info, data, wtr);
if (err)
@@ -235,7 +250,7 @@ static struct res do_search(const char *name, work_func func, void *data,
}
static struct res do_one_id(const char *id_str, work_func func, void *data,
- struct json_writer *wtr)
+ struct json_writer *wtr, __u32 flags)
{
struct bpf_map_info *info;
struct res res = {};
@@ -251,7 +266,7 @@ static struct res do_one_id(const char *id_str, work_func func, void *data,
return res;
}
- fd = bpf_map_get_fd_by_id(id);
+ fd = bpf_map_get_fd_by_id_flags(id, flags);
if (fd < 0) {
p_err("can't get map by id (%lu): %s", id, strerror(errno));
res.nr_errs++;
@@ -300,16 +315,16 @@ static struct res do_one_id(const char *id_str, work_func func, void *data,
static struct res do_work_on_struct_ops(const char *search_type,
const char *search_term,
work_func func, void *data,
- struct json_writer *wtr)
+ struct json_writer *wtr, __u32 flags)
{
if (search_type) {
if (is_prefix(search_type, "id"))
- return do_one_id(search_term, func, data, wtr);
+ return do_one_id(search_term, func, data, wtr, flags);
else if (!is_prefix(search_type, "name"))
usage();
}
- return do_search(search_term, func, data, wtr);
+ return do_search(search_term, func, data, wtr, flags);
}
static int __do_show(int fd, const struct bpf_map_info *info, void *data,
@@ -344,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);
+ NULL, json_wtr, 0);
return cmd_retval(&res, !!search_term);
}
@@ -433,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);
+ wtr, 0);
if (!json_output)
jsonw_destroy(&wtr);
@@ -472,7 +487,7 @@ static int do_unregister(int argc, char **argv)
search_term = GET_ARG();
res = do_work_on_struct_ops(search_type, search_term,
- __do_unregister, NULL, NULL);
+ __do_unregister, NULL, NULL, 0);
return cmd_retval(&res, true);
}
--
2.25.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v2 8/9] bpftool: Adjust map permissions
2022-06-02 14:37 [PATCH v2 0/9] bpf: Per-operation map permissions Roberto Sassu
` (6 preceding siblings ...)
2022-06-02 14:37 ` [PATCH v2 7/9] bpftool: Add flags parameter in struct_ops functions Roberto Sassu
@ 2022-06-02 14:37 ` Roberto Sassu
2022-06-02 14:37 ` [PATCH v2 9/9] selftests/bpf: Add map access tests Roberto Sassu
2022-06-03 21:00 ` [PATCH v2 0/9] bpf: Per-operation map permissions Andrii Nakryiko
9 siblings, 0 replies; 15+ messages in thread
From: Roberto Sassu @ 2022-06-02 14:37 UTC (permalink / raw)
To: ast, daniel, andrii, kpsingh
Cc: bpf, netdev, linux-kselftest, linux-kernel, Roberto Sassu
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 <roberto.sassu@huawei.com>
---
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
^ permalink raw reply related [flat|nested] 15+ messages in thread* [PATCH v2 9/9] selftests/bpf: Add map access tests
2022-06-02 14:37 [PATCH v2 0/9] bpf: Per-operation map permissions Roberto Sassu
` (7 preceding siblings ...)
2022-06-02 14:37 ` [PATCH v2 8/9] bpftool: Adjust map permissions Roberto Sassu
@ 2022-06-02 14:37 ` Roberto Sassu
2022-06-03 20:59 ` Andrii Nakryiko
2022-06-03 21:00 ` [PATCH v2 0/9] bpf: Per-operation map permissions Andrii Nakryiko
9 siblings, 1 reply; 15+ messages in thread
From: Roberto Sassu @ 2022-06-02 14:37 UTC (permalink / raw)
To: ast, daniel, andrii, kpsingh
Cc: bpf, netdev, linux-kselftest, linux-kernel, Roberto Sassu
Add some tests to ensure that read-like operations can be performed on a
write-protected map, and that write-like operations fail with a read file
descriptor.
Do the tests programmatically, with the new functions
bpf_map_get_fd_by_id_flags() and bpf_obj_get_flags(), added to libbpf, and
with the bpftool binary.
Also ensure that map search by name works when there is a write-protected
map. Before, iteration over existing maps stopped due to not being able
to get a file descriptor with full permissions.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
.../bpf/prog_tests/test_map_check_access.c | 264 ++++++++++++++++++
.../selftests/bpf/progs/map_check_access.c | 65 +++++
2 files changed, 329 insertions(+)
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
diff --git a/tools/testing/selftests/bpf/prog_tests/test_map_check_access.c b/tools/testing/selftests/bpf/prog_tests/test_map_check_access.c
new file mode 100644
index 000000000000..20ccadcdf10f
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/test_map_check_access.c
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ */
+
+#include <test_progs.h>
+
+#include "map_check_access.skel.h"
+
+#define PINNED_MAP_PATH "/sys/fs/bpf/test_map_check_access_map"
+#define BPFTOOL_PATH "./tools/build/bpftool/bpftool"
+
+enum check_types { CHECK_NONE, CHECK_PINNED, CHECK_METADATA };
+
+static int populate_argv(char *argv[], int max_args, char *cmdline)
+{
+ char *arg;
+ int i = 0;
+
+ argv[i++] = BPFTOOL_PATH;
+
+ while ((arg = strsep(&cmdline, " "))) {
+ if (i == max_args - 1)
+ break;
+
+ argv[i++] = arg;
+ }
+
+ argv[i] = NULL;
+ return i;
+}
+
+static void restore_cmdline(char *argv[], int num_args)
+{
+ int i;
+
+ for (i = 1; i < num_args - 1; i++)
+ argv[i][strlen(argv[i])] = ' ';
+}
+
+static int _run_bpftool(char *cmdline, enum check_types check)
+{
+ char *argv[20];
+ char output[1024];
+ int ret, fd[2], num_args, child_pid, child_status;
+
+ num_args = populate_argv(argv, ARRAY_SIZE(argv), cmdline);
+
+ ret = pipe(fd);
+ if (ret < 0)
+ return ret;
+
+ child_pid = fork();
+ if (child_pid == 0) {
+ close(fd[0]);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+
+ ret = dup2(fd[1], STDOUT_FILENO);
+ if (ret < 0) {
+ close(fd[1]);
+ exit(errno);
+ }
+
+ execv(BPFTOOL_PATH, argv);
+ close(fd[1]);
+ exit(errno);
+ } else if (child_pid > 0) {
+ close(fd[1]);
+
+ restore_cmdline(argv, num_args);
+
+ waitpid(child_pid, &child_status, 0);
+ if (WEXITSTATUS(child_status)) {
+ close(fd[0]);
+ return WEXITSTATUS(child_status);
+ }
+
+ ret = read(fd[0], output, sizeof(output) - 1);
+
+ close(fd[0]);
+
+ if (ret < 0)
+ return ret;
+
+ output[ret] = '\0';
+ ret = 0;
+
+ switch (check) {
+ case CHECK_PINNED:
+ if (!strstr(output, PINNED_MAP_PATH))
+ ret = -ENOENT;
+ break;
+ case CHECK_METADATA:
+ if (!strstr(output, "test_var"))
+ ret = -ENOENT;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+ }
+
+ close(fd[0]);
+ close(fd[1]);
+
+ return -EINVAL;
+}
+
+void test_test_map_check_access(void)
+{
+ struct map_check_access *skel;
+ struct bpf_map_info info_m = { 0 };
+ struct bpf_map *map;
+ __u32 len = sizeof(info_m);
+ char cmdline[1024];
+ int ret, zero = 0, fd, duration = 0;
+
+ skel = map_check_access__open_and_load();
+ if (CHECK(!skel, "skel", "open_and_load failed\n"))
+ goto close_prog;
+
+ ret = map_check_access__attach(skel);
+ if (CHECK(ret < 0, "skel", "attach failed\n"))
+ goto close_prog;
+
+ map = bpf_object__find_map_by_name(skel->obj, "data_input");
+ if (CHECK(!map, "bpf_object__find_map_by_name", "not found\n"))
+ goto close_prog;
+
+ ret = bpf_obj_get_info_by_fd(bpf_map__fd(map), &info_m, &len);
+ if (CHECK(ret < 0, "bpf_obj_get_info_by_fd", "error: %d\n", ret))
+ goto close_prog;
+
+ fd = bpf_map_get_fd_by_id(info_m.id);
+ if (CHECK(fd >= 0, "bpf_map_get_fd_by_id",
+ "should fail (map write-protected)\n"))
+ goto close_prog;
+
+ fd = bpf_map_get_fd_by_id_flags(info_m.id, 0);
+ if (CHECK(fd >= 0, "bpf_map_get_fd_by_id_flags",
+ "should fail (map write-protected)\n"))
+ goto close_prog;
+
+ fd = bpf_map_get_fd_by_id_flags(info_m.id, BPF_F_RDONLY);
+ if (CHECK(fd < 0, "bpf_map_get_fd_by_id_flags", "error: %d\n", fd))
+ goto close_prog;
+
+ ret = bpf_map_lookup_elem(fd, &zero, &len);
+ if (CHECK(ret < 0, "bpf_map_lookup_elem", "error: %d\n", ret)) {
+ close(fd);
+ goto close_prog;
+ }
+
+ ret = bpf_map_update_elem(fd, &zero, &len, BPF_ANY);
+
+ close(fd);
+
+ if (CHECK(!ret, "bpf_map_update_elem",
+ "should fail (read-only permission)\n"))
+ goto close_prog;
+
+ ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &len, BPF_ANY);
+ if (CHECK(ret < 0, "bpf_map_update_elem", "error: %d\n", ret))
+ goto close_prog;
+
+ ret = bpf_map__pin(map, PINNED_MAP_PATH);
+ if (CHECK(ret < 0, "bpf_map__pin", "error: %d\n", ret))
+ goto close_prog;
+
+ fd = bpf_obj_get_flags(PINNED_MAP_PATH, BPF_F_RDONLY);
+ if (CHECK(fd < 0, "bpf_obj_get_flags", "error: %d\n", fd))
+ goto close_prog;
+
+ close(fd);
+
+ fd = bpf_obj_get_flags(PINNED_MAP_PATH, 0);
+ if (CHECK(fd >= 0, "bpf_obj_get_flags",
+ "should fail (read-only permission)\n")) {
+ close(fd);
+ goto close_prog;
+ }
+
+ snprintf(cmdline, sizeof(cmdline), "map list");
+ ret = _run_bpftool(cmdline, CHECK_NONE);
+ if (CHECK(ret, "bpftool", "%s - error: %d\n", cmdline, ret))
+ goto close_prog;
+
+ snprintf(cmdline, sizeof(cmdline), "map show name data_input");
+ ret = _run_bpftool(cmdline, CHECK_NONE);
+ if (CHECK(ret, "bpftool", "%s - error: %d\n", cmdline, ret))
+ goto close_prog;
+
+ snprintf(cmdline, sizeof(cmdline), "map -f show pinned %s",
+ PINNED_MAP_PATH);
+ ret = _run_bpftool(cmdline, CHECK_PINNED);
+ if (CHECK(ret, "bpftool", "%s - error: %d\n", cmdline, ret))
+ goto close_prog;
+
+ unlink(PINNED_MAP_PATH);
+
+ snprintf(cmdline, sizeof(cmdline), "map dump name data_input");
+ ret = _run_bpftool(cmdline, CHECK_NONE);
+ if (CHECK(ret, "bpftool", "%s - error: %d\n", cmdline, ret))
+ goto close_prog;
+
+ snprintf(cmdline, sizeof(cmdline),
+ "map lookup name data_input key 0 0 0 0");
+ ret = _run_bpftool(cmdline, CHECK_NONE);
+ if (CHECK(ret, "bpftool", "%s - error: %d\n", cmdline, ret))
+ goto close_prog;
+
+ snprintf(cmdline, sizeof(cmdline),
+ "map update name data_input key 0 0 0 0 value 0 0 0 0");
+ ret = _run_bpftool(cmdline, CHECK_NONE);
+ if (CHECK(!ret, "bpftool",
+ "%s - should fail (read-only permission)\n", cmdline))
+ goto close_prog;
+
+ snprintf(cmdline, sizeof(cmdline),
+ "map update name data_input_w key 0 0 0 0 value 0 0 0 0");
+ ret = _run_bpftool(cmdline, CHECK_NONE);
+ if (CHECK(ret, "bpftool", "%s - error: %d\n", cmdline, ret))
+ goto close_prog;
+
+ snprintf(cmdline, sizeof(cmdline), "prog show name check_access");
+ ret = _run_bpftool(cmdline, CHECK_METADATA);
+ if (CHECK(ret, "bpftool", "%s - error: %d\n", cmdline, ret))
+ goto close_prog;
+
+ snprintf(cmdline, sizeof(cmdline), "btf show");
+ ret = _run_bpftool(cmdline, CHECK_NONE);
+ if (CHECK(ret, "bpftool", "%s - error: %d\n", cmdline, ret))
+ goto close_prog;
+
+ snprintf(cmdline, sizeof(cmdline), "btf dump map name data_input");
+ ret = _run_bpftool(cmdline, CHECK_NONE);
+ if (CHECK(ret, "bpftool", "%s - error: %d\n", cmdline, ret))
+ goto close_prog;
+
+ snprintf(cmdline, sizeof(cmdline), "map pin name data_input %s",
+ PINNED_MAP_PATH);
+ ret = _run_bpftool(cmdline, CHECK_NONE);
+ if (CHECK(ret, "bpftool", "%s - error: %d\n", cmdline, ret))
+ goto close_prog;
+
+ snprintf(cmdline, sizeof(cmdline), "struct_ops show name dummy_2");
+ ret = _run_bpftool(cmdline, CHECK_NONE);
+ if (CHECK(ret, "bpftool", "%s - error: %d\n", cmdline, ret))
+ goto close_prog;
+
+ snprintf(cmdline, sizeof(cmdline), "struct_ops dump name dummy_2");
+ ret = _run_bpftool(cmdline, CHECK_NONE);
+
+ CHECK(ret, "_run_bpftool", "%s - error: %d\n", cmdline, ret);
+
+close_prog:
+ map_check_access__destroy(skel);
+ unlink(PINNED_MAP_PATH);
+}
diff --git a/tools/testing/selftests/bpf/progs/map_check_access.c b/tools/testing/selftests/bpf/progs/map_check_access.c
new file mode 100644
index 000000000000..3e75b1114f79
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/map_check_access.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (C) 2021. Huawei Technologies Co., Ltd
+ * Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ */
+
+#include "vmlinux.h"
+#include <errno.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+
+/* From include/linux/mm.h. */
+#define FMODE_WRITE 0x2
+
+const char bpf_metadata_test_var[] SEC(".rodata") = "test_var";
+
+struct {
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __uint(max_entries, 1);
+ __type(key, __u32);
+ __type(value, __u32);
+} data_input SEC(".maps");
+
+struct {
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __uint(max_entries, 1);
+ __type(key, __u32);
+ __type(value, __u32);
+} data_input_w SEC(".maps");
+
+char _license[] SEC("license") = "GPL";
+
+SEC("lsm/bpf_map")
+int BPF_PROG(check_access, struct bpf_map *map, fmode_t fmode)
+{
+ if (map != (struct bpf_map *)&data_input)
+ return 0;
+
+ if (fmode & FMODE_WRITE)
+ return -EACCES;
+
+ return 0;
+}
+
+SEC("struct_ops/test_1")
+int BPF_PROG(test_1, struct bpf_dummy_ops_state *state)
+{
+ return 0;
+}
+
+SEC("struct_ops/test_2")
+int BPF_PROG(test_2, struct bpf_dummy_ops_state *state, int a1,
+ unsigned short a2, char a3, unsigned long a4)
+{
+ return 0;
+}
+
+SEC(".struct_ops")
+struct bpf_dummy_ops dummy_2 = {
+ .test_1 = (void *)test_1,
+ .test_2 = (void *)test_2,
+};
--
2.25.1
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [PATCH v2 9/9] selftests/bpf: Add map access tests
2022-06-02 14:37 ` [PATCH v2 9/9] selftests/bpf: Add map access tests Roberto Sassu
@ 2022-06-03 20:59 ` Andrii Nakryiko
0 siblings, 0 replies; 15+ messages in thread
From: Andrii Nakryiko @ 2022-06-03 20:59 UTC (permalink / raw)
To: Roberto Sassu
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, KP Singh,
bpf, Networking, open list:KERNEL SELFTEST FRAMEWORK, open list
On Thu, Jun 2, 2022 at 7:39 AM Roberto Sassu <roberto.sassu@huawei.com> wrote:
>
> Add some tests to ensure that read-like operations can be performed on a
> write-protected map, and that write-like operations fail with a read file
> descriptor.
>
> Do the tests programmatically, with the new functions
> bpf_map_get_fd_by_id_flags() and bpf_obj_get_flags(), added to libbpf, and
> with the bpftool binary.
>
> Also ensure that map search by name works when there is a write-protected
> map. Before, iteration over existing maps stopped due to not being able
> to get a file descriptor with full permissions.
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> ---
> .../bpf/prog_tests/test_map_check_access.c | 264 ++++++++++++++++++
> .../selftests/bpf/progs/map_check_access.c | 65 +++++
> 2 files changed, 329 insertions(+)
> 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
general convention (not universally followed, unfortunately) is
opposite, progs/test_<something>.c and prog_tests/<something>.c. This
allows to not have weird test_test_<something> naming pattern
>
> diff --git a/tools/testing/selftests/bpf/prog_tests/test_map_check_access.c b/tools/testing/selftests/bpf/prog_tests/test_map_check_access.c
> new file mode 100644
> index 000000000000..20ccadcdf10f
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/prog_tests/test_map_check_access.c
> @@ -0,0 +1,264 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH
> + *
> + * Author: Roberto Sassu <roberto.sassu@huawei.com>
> + */
> +
> +#include <test_progs.h>
> +
> +#include "map_check_access.skel.h"
> +
> +#define PINNED_MAP_PATH "/sys/fs/bpf/test_map_check_access_map"
> +#define BPFTOOL_PATH "./tools/build/bpftool/bpftool"
> +
> +enum check_types { CHECK_NONE, CHECK_PINNED, CHECK_METADATA };
> +
> +static int populate_argv(char *argv[], int max_args, char *cmdline)
> +{
> + char *arg;
> + int i = 0;
> +
> + argv[i++] = BPFTOOL_PATH;
> +
> + while ((arg = strsep(&cmdline, " "))) {
> + if (i == max_args - 1)
> + break;
> +
> + argv[i++] = arg;
> + }
> +
> + argv[i] = NULL;
> + return i;
> +}
> +
> +static void restore_cmdline(char *argv[], int num_args)
> +{
> + int i;
> +
> + for (i = 1; i < num_args - 1; i++)
> + argv[i][strlen(argv[i])] = ' ';
> +}
I'm missing the point of this cmdline restoration?..
> +
> +static int _run_bpftool(char *cmdline, enum check_types check)
> +{
> + char *argv[20];
> + char output[1024];
> + int ret, fd[2], num_args, child_pid, child_status;
> +
> + num_args = populate_argv(argv, ARRAY_SIZE(argv), cmdline);
> +
> + ret = pipe(fd);
> + if (ret < 0)
> + return ret;
> +
and popen() doesn't work instead of all this forking/execve sequence?
> + child_pid = fork();
> + if (child_pid == 0) {
> + close(fd[0]);
> + close(STDOUT_FILENO);
> + close(STDERR_FILENO);
> +
> + ret = dup2(fd[1], STDOUT_FILENO);
> + if (ret < 0) {
> + close(fd[1]);
> + exit(errno);
> + }
> +
> + execv(BPFTOOL_PATH, argv);
> + close(fd[1]);
> + exit(errno);
> + } else if (child_pid > 0) {
> + close(fd[1]);
> +
> + restore_cmdline(argv, num_args);
> +
> + waitpid(child_pid, &child_status, 0);
> + if (WEXITSTATUS(child_status)) {
> + close(fd[0]);
> + return WEXITSTATUS(child_status);
> + }
> +
> + ret = read(fd[0], output, sizeof(output) - 1);
> +
> + close(fd[0]);
> +
> + if (ret < 0)
> + return ret;
> +
> + output[ret] = '\0';
> + ret = 0;
> +
> + switch (check) {
> + case CHECK_PINNED:
> + if (!strstr(output, PINNED_MAP_PATH))
> + ret = -ENOENT;
> + break;
> + case CHECK_METADATA:
> + if (!strstr(output, "test_var"))
> + ret = -ENOENT;
> + break;
> + default:
> + break;
> + }
> +
> + return ret;
> + }
> +
> + close(fd[0]);
> + close(fd[1]);
> +
> + return -EINVAL;
> +}
> +
> +void test_test_map_check_access(void)
> +{
> + struct map_check_access *skel;
> + struct bpf_map_info info_m = { 0 };
> + struct bpf_map *map;
> + __u32 len = sizeof(info_m);
> + char cmdline[1024];
> + int ret, zero = 0, fd, duration = 0;
> +
> + skel = map_check_access__open_and_load();
> + if (CHECK(!skel, "skel", "open_and_load failed\n"))
> + goto close_prog;
> +
> + ret = map_check_access__attach(skel);
> + if (CHECK(ret < 0, "skel", "attach failed\n"))
> + goto close_prog;
> +
please don't use CHECK(), use ASSERT_xxx() macros instead
> + map = bpf_object__find_map_by_name(skel->obj, "data_input");
> + if (CHECK(!map, "bpf_object__find_map_by_name", "not found\n"))
> + goto close_prog;
> +
> + ret = bpf_obj_get_info_by_fd(bpf_map__fd(map), &info_m, &len);
> + if (CHECK(ret < 0, "bpf_obj_get_info_by_fd", "error: %d\n", ret))
> + goto close_prog;
> +
> + fd = bpf_map_get_fd_by_id(info_m.id);
> + if (CHECK(fd >= 0, "bpf_map_get_fd_by_id",
> + "should fail (map write-protected)\n"))
> + goto close_prog;
> +
[...]
> + snprintf(cmdline, sizeof(cmdline), "btf dump map name data_input");
> + ret = _run_bpftool(cmdline, CHECK_NONE);
> + if (CHECK(ret, "bpftool", "%s - error: %d\n", cmdline, ret))
> + goto close_prog;
> +
> + snprintf(cmdline, sizeof(cmdline), "map pin name data_input %s",
> + PINNED_MAP_PATH);
> + ret = _run_bpftool(cmdline, CHECK_NONE);
> + if (CHECK(ret, "bpftool", "%s - error: %d\n", cmdline, ret))
> + goto close_prog;
> +
> + snprintf(cmdline, sizeof(cmdline), "struct_ops show name dummy_2");
> + ret = _run_bpftool(cmdline, CHECK_NONE);
if you don't have to restore anything, you don't need snprintf()'ing,
just pass arguments as a string literal directly
> + if (CHECK(ret, "bpftool", "%s - error: %d\n", cmdline, ret))
> + goto close_prog;
> +
> + snprintf(cmdline, sizeof(cmdline), "struct_ops dump name dummy_2");
> + ret = _run_bpftool(cmdline, CHECK_NONE);
> +
> + CHECK(ret, "_run_bpftool", "%s - error: %d\n", cmdline, ret);
> +
> +close_prog:
> + map_check_access__destroy(skel);
> + unlink(PINNED_MAP_PATH);
> +}
[...]
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 0/9] bpf: Per-operation map permissions
2022-06-02 14:37 [PATCH v2 0/9] bpf: Per-operation map permissions Roberto Sassu
` (8 preceding siblings ...)
2022-06-02 14:37 ` [PATCH v2 9/9] selftests/bpf: Add map access tests Roberto Sassu
@ 2022-06-03 21:00 ` Andrii Nakryiko
2022-06-09 12:55 ` Roberto Sassu
9 siblings, 1 reply; 15+ messages in thread
From: Andrii Nakryiko @ 2022-06-03 21:00 UTC (permalink / raw)
To: Roberto Sassu
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, KP Singh,
bpf, Networking, open list:KERNEL SELFTEST FRAMEWORK, open list
On Thu, Jun 2, 2022 at 7:38 AM Roberto Sassu <roberto.sassu@huawei.com> 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/20220530084514.10170-1-roberto.sassu@huawei.com/
>
> 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
^ permalink raw reply [flat|nested] 15+ messages in thread* RE: [PATCH v2 0/9] bpf: Per-operation map permissions
2022-06-03 21:00 ` [PATCH v2 0/9] bpf: Per-operation map permissions Andrii Nakryiko
@ 2022-06-09 12:55 ` Roberto Sassu
0 siblings, 0 replies; 15+ messages in thread
From: Roberto Sassu @ 2022-06-09 12:55 UTC (permalink / raw)
To: Andrii Nakryiko
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, KP Singh,
bpf, Networking, open list:KERNEL SELFTEST FRAMEWORK, open list
> From: Andrii Nakryiko [mailto:andrii.nakryiko@gmail.com]
> Sent: Friday, June 3, 2022 11:00 PM
> On Thu, Jun 2, 2022 at 7:38 AM Roberto Sassu <roberto.sassu@huawei.com>
> 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/20220530084514.10170-1-
> roberto.sassu@huawei.com/
> >
> > 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]).
Thanks for the review Andrii. Will send a new version of the
patch set soon.
Roberto
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063
Managing Director: Li Peng, Yang Xi, Li He
> 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
^ permalink raw reply [flat|nested] 15+ messages in thread