lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Fri, 3 Jun 2022 13:59:05 -0700
From:   Andrii Nakryiko <andrii.nakryiko@...il.com>
To:     Roberto Sassu <roberto.sassu@...wei.com>
Cc:     Alexei Starovoitov <ast@...nel.org>,
        Daniel Borkmann <daniel@...earbox.net>,
        Andrii Nakryiko <andrii@...nel.org>,
        KP Singh <kpsingh@...nel.org>, bpf <bpf@...r.kernel.org>,
        Networking <netdev@...r.kernel.org>,
        "open list:KERNEL SELFTEST FRAMEWORK" 
        <linux-kselftest@...r.kernel.org>,
        open list <linux-kernel@...r.kernel.org>
Subject: Re: [PATCH v2 9/9] selftests/bpf: Add map access tests

On Thu, Jun 2, 2022 at 7:39 AM Roberto Sassu <roberto.sassu@...wei.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@...wei.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@...wei.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);
> +}

[...]

Powered by blists - more mailing lists