linux/tools/testing/selftests/bpf/prog_tests/d_path.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#define _GNU_SOURCE
   3#include <test_progs.h>
   4#include <sys/stat.h>
   5#include <linux/sched.h>
   6#include <sys/syscall.h>
   7
   8#define MAX_PATH_LEN            128
   9#define MAX_FILES               7
  10
  11#include "test_d_path.skel.h"
  12
  13static int duration;
  14
  15static struct {
  16        __u32 cnt;
  17        char paths[MAX_FILES][MAX_PATH_LEN];
  18} src;
  19
  20static int set_pathname(int fd, pid_t pid)
  21{
  22        char buf[MAX_PATH_LEN];
  23
  24        snprintf(buf, MAX_PATH_LEN, "/proc/%d/fd/%d", pid, fd);
  25        return readlink(buf, src.paths[src.cnt++], MAX_PATH_LEN);
  26}
  27
  28static int trigger_fstat_events(pid_t pid)
  29{
  30        int sockfd = -1, procfd = -1, devfd = -1;
  31        int localfd = -1, indicatorfd = -1;
  32        int pipefd[2] = { -1, -1 };
  33        struct stat fileStat;
  34        int ret = -1;
  35
  36        /* unmountable pseudo-filesystems */
  37        if (CHECK(pipe(pipefd) < 0, "trigger", "pipe failed\n"))
  38                return ret;
  39        /* unmountable pseudo-filesystems */
  40        sockfd = socket(AF_INET, SOCK_STREAM, 0);
  41        if (CHECK(sockfd < 0, "trigger", "socket failed\n"))
  42                goto out_close;
  43        /* mountable pseudo-filesystems */
  44        procfd = open("/proc/self/comm", O_RDONLY);
  45        if (CHECK(procfd < 0, "trigger", "open /proc/self/comm failed\n"))
  46                goto out_close;
  47        devfd = open("/dev/urandom", O_RDONLY);
  48        if (CHECK(devfd < 0, "trigger", "open /dev/urandom failed\n"))
  49                goto out_close;
  50        localfd = open("/tmp/d_path_loadgen.txt", O_CREAT | O_RDONLY, 0644);
  51        if (CHECK(localfd < 0, "trigger", "open /tmp/d_path_loadgen.txt failed\n"))
  52                goto out_close;
  53        /* bpf_d_path will return path with (deleted) */
  54        remove("/tmp/d_path_loadgen.txt");
  55        indicatorfd = open("/tmp/", O_PATH);
  56        if (CHECK(indicatorfd < 0, "trigger", "open /tmp/ failed\n"))
  57                goto out_close;
  58
  59        ret = set_pathname(pipefd[0], pid);
  60        if (CHECK(ret < 0, "trigger", "set_pathname failed for pipe[0]\n"))
  61                goto out_close;
  62        ret = set_pathname(pipefd[1], pid);
  63        if (CHECK(ret < 0, "trigger", "set_pathname failed for pipe[1]\n"))
  64                goto out_close;
  65        ret = set_pathname(sockfd, pid);
  66        if (CHECK(ret < 0, "trigger", "set_pathname failed for socket\n"))
  67                goto out_close;
  68        ret = set_pathname(procfd, pid);
  69        if (CHECK(ret < 0, "trigger", "set_pathname failed for proc\n"))
  70                goto out_close;
  71        ret = set_pathname(devfd, pid);
  72        if (CHECK(ret < 0, "trigger", "set_pathname failed for dev\n"))
  73                goto out_close;
  74        ret = set_pathname(localfd, pid);
  75        if (CHECK(ret < 0, "trigger", "set_pathname failed for file\n"))
  76                goto out_close;
  77        ret = set_pathname(indicatorfd, pid);
  78        if (CHECK(ret < 0, "trigger", "set_pathname failed for dir\n"))
  79                goto out_close;
  80
  81        /* triggers vfs_getattr */
  82        fstat(pipefd[0], &fileStat);
  83        fstat(pipefd[1], &fileStat);
  84        fstat(sockfd, &fileStat);
  85        fstat(procfd, &fileStat);
  86        fstat(devfd, &fileStat);
  87        fstat(localfd, &fileStat);
  88        fstat(indicatorfd, &fileStat);
  89
  90out_close:
  91        /* triggers filp_close */
  92        close(pipefd[0]);
  93        close(pipefd[1]);
  94        close(sockfd);
  95        close(procfd);
  96        close(devfd);
  97        close(localfd);
  98        close(indicatorfd);
  99        return ret;
 100}
 101
 102void test_d_path(void)
 103{
 104        struct test_d_path__bss *bss;
 105        struct test_d_path *skel;
 106        int err;
 107
 108        skel = test_d_path__open_and_load();
 109        if (CHECK(!skel, "setup", "d_path skeleton failed\n"))
 110                goto cleanup;
 111
 112        err = test_d_path__attach(skel);
 113        if (CHECK(err, "setup", "attach failed: %d\n", err))
 114                goto cleanup;
 115
 116        bss = skel->bss;
 117        bss->my_pid = getpid();
 118
 119        err = trigger_fstat_events(bss->my_pid);
 120        if (err < 0)
 121                goto cleanup;
 122
 123        if (CHECK(!bss->called_stat,
 124                  "stat",
 125                  "trampoline for security_inode_getattr was not called\n"))
 126                goto cleanup;
 127
 128        if (CHECK(!bss->called_close,
 129                  "close",
 130                  "trampoline for filp_close was not called\n"))
 131                goto cleanup;
 132
 133        for (int i = 0; i < MAX_FILES; i++) {
 134                CHECK(strncmp(src.paths[i], bss->paths_stat[i], MAX_PATH_LEN),
 135                      "check",
 136                      "failed to get stat path[%d]: %s vs %s\n",
 137                      i, src.paths[i], bss->paths_stat[i]);
 138                CHECK(strncmp(src.paths[i], bss->paths_close[i], MAX_PATH_LEN),
 139                      "check",
 140                      "failed to get close path[%d]: %s vs %s\n",
 141                      i, src.paths[i], bss->paths_close[i]);
 142                /* The d_path helper returns size plus NUL char, hence + 1 */
 143                CHECK(bss->rets_stat[i] != strlen(bss->paths_stat[i]) + 1,
 144                      "check",
 145                      "failed to match stat return [%d]: %d vs %zd [%s]\n",
 146                      i, bss->rets_stat[i], strlen(bss->paths_stat[i]) + 1,
 147                      bss->paths_stat[i]);
 148                CHECK(bss->rets_close[i] != strlen(bss->paths_stat[i]) + 1,
 149                      "check",
 150                      "failed to match stat return [%d]: %d vs %zd [%s]\n",
 151                      i, bss->rets_close[i], strlen(bss->paths_close[i]) + 1,
 152                      bss->paths_stat[i]);
 153        }
 154
 155cleanup:
 156        test_d_path__destroy(skel);
 157}
 158