bpf: Add selftests for local_storage
authorKP Singh <kpsingh@google.com>
Tue, 25 Aug 2020 18:29:19 +0000 (20:29 +0200)
committerAlexei Starovoitov <ast@kernel.org>
Tue, 25 Aug 2020 22:00:04 +0000 (15:00 -0700)
inode_local_storage:

* Hook to the file_open and inode_unlink LSM hooks.
* Create and unlink a temporary file.
* Store some information in the inode's bpf_local_storage during
  file_open.
* Verify that this information exists when the file is unlinked.

sk_local_storage:

* Hook to the socket_post_create and socket_bind LSM hooks.
* Open and bind a socket and set the sk_storage in the
  socket_post_create hook using the start_server helper.
* Verify if the information is set in the socket_bind hook.

Signed-off-by: KP Singh <kpsingh@google.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Andrii Nakryiko <andriin@fb.com>
Link: https://lore.kernel.org/bpf/20200825182919.1118197-8-kpsingh@chromium.org
tools/testing/selftests/bpf/prog_tests/test_local_storage.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/local_storage.c [new file with mode: 0644]

diff --git a/tools/testing/selftests/bpf/prog_tests/test_local_storage.c b/tools/testing/selftests/bpf/prog_tests/test_local_storage.c
new file mode 100644 (file)
index 0000000..91cd6f3
--- /dev/null
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (C) 2020 Google LLC.
+ */
+
+#include <test_progs.h>
+#include <linux/limits.h>
+
+#include "local_storage.skel.h"
+#include "network_helpers.h"
+
+int create_and_unlink_file(void)
+{
+       char fname[PATH_MAX] = "/tmp/fileXXXXXX";
+       int fd;
+
+       fd = mkstemp(fname);
+       if (fd < 0)
+               return fd;
+
+       close(fd);
+       unlink(fname);
+       return 0;
+}
+
+void test_test_local_storage(void)
+{
+       struct local_storage *skel = NULL;
+       int err, duration = 0, serv_sk = -1;
+
+       skel = local_storage__open_and_load();
+       if (CHECK(!skel, "skel_load", "lsm skeleton failed\n"))
+               goto close_prog;
+
+       err = local_storage__attach(skel);
+       if (CHECK(err, "attach", "lsm attach failed: %d\n", err))
+               goto close_prog;
+
+       skel->bss->monitored_pid = getpid();
+
+       err = create_and_unlink_file();
+       if (CHECK(err < 0, "exec_cmd", "err %d errno %d\n", err, errno))
+               goto close_prog;
+
+       CHECK(skel->data->inode_storage_result != 0, "inode_storage_result",
+             "inode_local_storage not set\n");
+
+       serv_sk = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0);
+       if (CHECK(serv_sk < 0, "start_server", "failed to start server\n"))
+               goto close_prog;
+
+       CHECK(skel->data->sk_storage_result != 0, "sk_storage_result",
+             "sk_local_storage not set\n");
+
+       close(serv_sk);
+
+close_prog:
+       local_storage__destroy(skel);
+}
diff --git a/tools/testing/selftests/bpf/progs/local_storage.c b/tools/testing/selftests/bpf/progs/local_storage.c
new file mode 100644 (file)
index 0000000..0758ba2
--- /dev/null
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright 2020 Google LLC.
+ */
+
+#include <errno.h>
+#include <linux/bpf.h>
+#include <stdbool.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+
+char _license[] SEC("license") = "GPL";
+
+#define DUMMY_STORAGE_VALUE 0xdeadbeef
+
+int monitored_pid = 0;
+int inode_storage_result = -1;
+int sk_storage_result = -1;
+
+struct dummy_storage {
+       __u32 value;
+};
+
+struct {
+       __uint(type, BPF_MAP_TYPE_INODE_STORAGE);
+       __uint(map_flags, BPF_F_NO_PREALLOC);
+       __type(key, int);
+       __type(value, struct dummy_storage);
+} inode_storage_map SEC(".maps");
+
+struct {
+       __uint(type, BPF_MAP_TYPE_SK_STORAGE);
+       __uint(map_flags, BPF_F_NO_PREALLOC | BPF_F_CLONE);
+       __type(key, int);
+       __type(value, struct dummy_storage);
+} sk_storage_map SEC(".maps");
+
+/* TODO Use vmlinux.h once BTF pruning for embedded types is fixed.
+ */
+struct sock {} __attribute__((preserve_access_index));
+struct sockaddr {} __attribute__((preserve_access_index));
+struct socket {
+       struct sock *sk;
+} __attribute__((preserve_access_index));
+
+struct inode {} __attribute__((preserve_access_index));
+struct dentry {
+       struct inode *d_inode;
+} __attribute__((preserve_access_index));
+struct file {
+       struct inode *f_inode;
+} __attribute__((preserve_access_index));
+
+
+SEC("lsm/inode_unlink")
+int BPF_PROG(unlink_hook, struct inode *dir, struct dentry *victim)
+{
+       __u32 pid = bpf_get_current_pid_tgid() >> 32;
+       struct dummy_storage *storage;
+
+       if (pid != monitored_pid)
+               return 0;
+
+       storage = bpf_inode_storage_get(&inode_storage_map, victim->d_inode, 0,
+                                    BPF_SK_STORAGE_GET_F_CREATE);
+       if (!storage)
+               return 0;
+
+       if (storage->value == DUMMY_STORAGE_VALUE)
+               inode_storage_result = -1;
+
+       inode_storage_result =
+               bpf_inode_storage_delete(&inode_storage_map, victim->d_inode);
+
+       return 0;
+}
+
+SEC("lsm/socket_bind")
+int BPF_PROG(socket_bind, struct socket *sock, struct sockaddr *address,
+            int addrlen)
+{
+       __u32 pid = bpf_get_current_pid_tgid() >> 32;
+       struct dummy_storage *storage;
+
+       if (pid != monitored_pid)
+               return 0;
+
+       storage = bpf_sk_storage_get(&sk_storage_map, sock->sk, 0,
+                                    BPF_SK_STORAGE_GET_F_CREATE);
+       if (!storage)
+               return 0;
+
+       if (storage->value == DUMMY_STORAGE_VALUE)
+               sk_storage_result = -1;
+
+       sk_storage_result = bpf_sk_storage_delete(&sk_storage_map, sock->sk);
+       return 0;
+}
+
+SEC("lsm/socket_post_create")
+int BPF_PROG(socket_post_create, struct socket *sock, int family, int type,
+            int protocol, int kern)
+{
+       __u32 pid = bpf_get_current_pid_tgid() >> 32;
+       struct dummy_storage *storage;
+
+       if (pid != monitored_pid)
+               return 0;
+
+       storage = bpf_sk_storage_get(&sk_storage_map, sock->sk, 0,
+                                    BPF_SK_STORAGE_GET_F_CREATE);
+       if (!storage)
+               return 0;
+
+       storage->value = DUMMY_STORAGE_VALUE;
+
+       return 0;
+}
+
+SEC("lsm/file_open")
+int BPF_PROG(file_open, struct file *file)
+{
+       __u32 pid = bpf_get_current_pid_tgid() >> 32;
+       struct dummy_storage *storage;
+
+       if (pid != monitored_pid)
+               return 0;
+
+       if (!file->f_inode)
+               return 0;
+
+       storage = bpf_inode_storage_get(&inode_storage_map, file->f_inode, 0,
+                                    BPF_LOCAL_STORAGE_GET_F_CREATE);
+       if (!storage)
+               return 0;
+
+       storage->value = DUMMY_STORAGE_VALUE;
+       return 0;
+}