linux/tools/testing/selftests/bpf/test_tag.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <stdint.h>
   3#include <stdio.h>
   4#include <stdlib.h>
   5#include <ctype.h>
   6#include <time.h>
   7#include <errno.h>
   8#include <unistd.h>
   9#include <string.h>
  10#include <sched.h>
  11#include <limits.h>
  12#include <assert.h>
  13
  14#include <sys/socket.h>
  15
  16#include <linux/filter.h>
  17#include <linux/bpf.h>
  18#include <linux/if_alg.h>
  19
  20#include <bpf/bpf.h>
  21
  22#include "../../../include/linux/filter.h"
  23#include "bpf_rlimit.h"
  24#include "testing_helpers.h"
  25
  26static struct bpf_insn prog[BPF_MAXINSNS];
  27
  28static void bpf_gen_imm_prog(unsigned int insns, int fd_map)
  29{
  30        int i;
  31
  32        srand(time(NULL));
  33        for (i = 0; i < insns; i++)
  34                prog[i] = BPF_ALU64_IMM(BPF_MOV, i % BPF_REG_10, rand());
  35        prog[i - 1] = BPF_EXIT_INSN();
  36}
  37
  38static void bpf_gen_map_prog(unsigned int insns, int fd_map)
  39{
  40        int i, j = 0;
  41
  42        for (i = 0; i + 1 < insns; i += 2) {
  43                struct bpf_insn tmp[] = {
  44                        BPF_LD_MAP_FD(j++ % BPF_REG_10, fd_map)
  45                };
  46
  47                memcpy(&prog[i], tmp, sizeof(tmp));
  48        }
  49        if (insns % 2 == 0)
  50                prog[insns - 2] = BPF_ALU64_IMM(BPF_MOV, i % BPF_REG_10, 42);
  51        prog[insns - 1] = BPF_EXIT_INSN();
  52}
  53
  54static int bpf_try_load_prog(int insns, int fd_map,
  55                             void (*bpf_filler)(unsigned int insns,
  56                                                int fd_map))
  57{
  58        int fd_prog;
  59
  60        bpf_filler(insns, fd_map);
  61        fd_prog = bpf_test_load_program(BPF_PROG_TYPE_SCHED_CLS, prog, insns, "", 0,
  62                                   NULL, 0);
  63        assert(fd_prog > 0);
  64        if (fd_map > 0)
  65                bpf_filler(insns, 0);
  66        return fd_prog;
  67}
  68
  69static int __hex2bin(char ch)
  70{
  71        if ((ch >= '0') && (ch <= '9'))
  72                return ch - '0';
  73        ch = tolower(ch);
  74        if ((ch >= 'a') && (ch <= 'f'))
  75                return ch - 'a' + 10;
  76        return -1;
  77}
  78
  79static int hex2bin(uint8_t *dst, const char *src, size_t count)
  80{
  81        while (count--) {
  82                int hi = __hex2bin(*src++);
  83                int lo = __hex2bin(*src++);
  84
  85                if ((hi < 0) || (lo < 0))
  86                        return -1;
  87                *dst++ = (hi << 4) | lo;
  88        }
  89        return 0;
  90}
  91
  92static void tag_from_fdinfo(int fd_prog, uint8_t *tag, uint32_t len)
  93{
  94        const int prefix_len = sizeof("prog_tag:\t") - 1;
  95        char buff[256];
  96        int ret = -1;
  97        FILE *fp;
  98
  99        snprintf(buff, sizeof(buff), "/proc/%d/fdinfo/%d", getpid(),
 100                 fd_prog);
 101        fp = fopen(buff, "r");
 102        assert(fp);
 103
 104        while (fgets(buff, sizeof(buff), fp)) {
 105                if (strncmp(buff, "prog_tag:\t", prefix_len))
 106                        continue;
 107                ret = hex2bin(tag, buff + prefix_len, len);
 108                break;
 109        }
 110
 111        fclose(fp);
 112        assert(!ret);
 113}
 114
 115static void tag_from_alg(int insns, uint8_t *tag, uint32_t len)
 116{
 117        static const struct sockaddr_alg alg = {
 118                .salg_family    = AF_ALG,
 119                .salg_type      = "hash",
 120                .salg_name      = "sha1",
 121        };
 122        int fd_base, fd_alg, ret;
 123        ssize_t size;
 124
 125        fd_base = socket(AF_ALG, SOCK_SEQPACKET, 0);
 126        assert(fd_base > 0);
 127
 128        ret = bind(fd_base, (struct sockaddr *)&alg, sizeof(alg));
 129        assert(!ret);
 130
 131        fd_alg = accept(fd_base, NULL, 0);
 132        assert(fd_alg > 0);
 133
 134        insns *= sizeof(struct bpf_insn);
 135        size = write(fd_alg, prog, insns);
 136        assert(size == insns);
 137
 138        size = read(fd_alg, tag, len);
 139        assert(size == len);
 140
 141        close(fd_alg);
 142        close(fd_base);
 143}
 144
 145static void tag_dump(const char *prefix, uint8_t *tag, uint32_t len)
 146{
 147        int i;
 148
 149        printf("%s", prefix);
 150        for (i = 0; i < len; i++)
 151                printf("%02x", tag[i]);
 152        printf("\n");
 153}
 154
 155static void tag_exit_report(int insns, int fd_map, uint8_t *ftag,
 156                            uint8_t *atag, uint32_t len)
 157{
 158        printf("Program tag mismatch for %d insns%s!\n", insns,
 159               fd_map < 0 ? "" : " with map");
 160
 161        tag_dump("  fdinfo result: ", ftag, len);
 162        tag_dump("  af_alg result: ", atag, len);
 163        exit(1);
 164}
 165
 166static void do_test(uint32_t *tests, int start_insns, int fd_map,
 167                    void (*bpf_filler)(unsigned int insns, int fd))
 168{
 169        int i, fd_prog;
 170
 171        for (i = start_insns; i <= BPF_MAXINSNS; i++) {
 172                uint8_t ftag[8], atag[sizeof(ftag)];
 173
 174                fd_prog = bpf_try_load_prog(i, fd_map, bpf_filler);
 175                tag_from_fdinfo(fd_prog, ftag, sizeof(ftag));
 176                tag_from_alg(i, atag, sizeof(atag));
 177                if (memcmp(ftag, atag, sizeof(ftag)))
 178                        tag_exit_report(i, fd_map, ftag, atag, sizeof(ftag));
 179
 180                close(fd_prog);
 181                sched_yield();
 182                (*tests)++;
 183        }
 184}
 185
 186int main(void)
 187{
 188        LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_NO_PREALLOC);
 189        uint32_t tests = 0;
 190        int i, fd_map;
 191
 192        fd_map = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(int),
 193                                sizeof(int), 1, &opts);
 194        assert(fd_map > 0);
 195
 196        for (i = 0; i < 5; i++) {
 197                do_test(&tests, 2, -1,     bpf_gen_imm_prog);
 198                do_test(&tests, 3, fd_map, bpf_gen_map_prog);
 199        }
 200
 201        printf("test_tag: OK (%u tests)\n", tests);
 202        close(fd_map);
 203        return 0;
 204}
 205