linux/tools/testing/selftests/bpf/test_verifier_log.c
<<
>>
Prefs
   1#include <errno.h>
   2#include <stdlib.h>
   3#include <stdio.h>
   4#include <string.h>
   5#include <unistd.h>
   6#include <sys/time.h>
   7
   8#include <linux/bpf.h>
   9#include <linux/filter.h>
  10#include <linux/unistd.h>
  11
  12#include <bpf/bpf.h>
  13
  14#include "bpf_rlimit.h"
  15
  16#define LOG_SIZE (1 << 20)
  17
  18#define err(str...)     printf("ERROR: " str)
  19
  20static const struct bpf_insn code_sample[] = {
  21        /* We need a few instructions to pass the min log length */
  22        BPF_MOV64_IMM(BPF_REG_0, 0),
  23        BPF_MOV64_IMM(BPF_REG_0, 0),
  24        BPF_MOV64_IMM(BPF_REG_0, 0),
  25        BPF_MOV64_IMM(BPF_REG_0, 0),
  26        BPF_MOV64_IMM(BPF_REG_0, 0),
  27        BPF_MOV64_IMM(BPF_REG_0, 0),
  28        BPF_MOV64_IMM(BPF_REG_0, 0),
  29        BPF_MOV64_IMM(BPF_REG_0, 0),
  30        BPF_MOV64_IMM(BPF_REG_0, 0),
  31        BPF_MOV64_IMM(BPF_REG_0, 0),
  32        BPF_MOV64_IMM(BPF_REG_0, 0),
  33        BPF_MOV64_IMM(BPF_REG_0, 0),
  34        BPF_MOV64_IMM(BPF_REG_0, 0),
  35        BPF_MOV64_IMM(BPF_REG_0, 0),
  36        BPF_MOV64_IMM(BPF_REG_0, 0),
  37        BPF_MOV64_IMM(BPF_REG_0, 0),
  38        BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
  39                     BPF_FUNC_map_lookup_elem),
  40        BPF_EXIT_INSN(),
  41};
  42
  43static inline __u64 ptr_to_u64(const void *ptr)
  44{
  45        return (__u64) (unsigned long) ptr;
  46}
  47
  48static int load(char *log, size_t log_len, int log_level)
  49{
  50        union bpf_attr attr;
  51
  52        bzero(&attr, sizeof(attr));
  53        attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
  54        attr.insn_cnt = (__u32)(sizeof(code_sample) / sizeof(struct bpf_insn));
  55        attr.insns = ptr_to_u64(code_sample);
  56        attr.license = ptr_to_u64("GPL");
  57        attr.log_buf = ptr_to_u64(log);
  58        attr.log_size = log_len;
  59        attr.log_level = log_level;
  60
  61        return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
  62}
  63
  64static void check_ret(int ret, int exp_errno)
  65{
  66        if (ret > 0) {
  67                close(ret);
  68                err("broken sample loaded successfully!?\n");
  69                exit(1);
  70        }
  71
  72        if (!ret || errno != exp_errno) {
  73                err("Program load returned: ret:%d/errno:%d, expected ret:%d/errno:%d\n",
  74                    ret, errno, -1, exp_errno);
  75                exit(1);
  76        }
  77}
  78
  79static void check_ones(const char *buf, size_t len, const char *msg)
  80{
  81        while (len--)
  82                if (buf[len] != 1) {
  83                        err("%s", msg);
  84                        exit(1);
  85                }
  86}
  87
  88static void test_log_good(char *log, size_t buf_len, size_t log_len,
  89                          size_t exp_len, int exp_errno, const char *full_log)
  90{
  91        size_t len;
  92        int ret;
  93
  94        memset(log, 1, buf_len);
  95
  96        ret = load(log, log_len, 1);
  97        check_ret(ret, exp_errno);
  98
  99        len = strnlen(log, buf_len);
 100        if (len == buf_len) {
 101                err("verifier did not NULL terminate the log\n");
 102                exit(1);
 103        }
 104        if (exp_len && len != exp_len) {
 105                err("incorrect log length expected:%zd have:%zd\n",
 106                    exp_len, len);
 107                exit(1);
 108        }
 109
 110        if (strchr(log, 1)) {
 111                err("verifier leaked a byte through\n");
 112                exit(1);
 113        }
 114
 115        check_ones(log + len + 1, buf_len - len - 1,
 116                   "verifier wrote bytes past NULL termination\n");
 117
 118        if (memcmp(full_log, log, LOG_SIZE)) {
 119                err("log did not match expected output\n");
 120                exit(1);
 121        }
 122}
 123
 124static void test_log_bad(char *log, size_t log_len, int log_level)
 125{
 126        int ret;
 127
 128        ret = load(log, log_len, log_level);
 129        check_ret(ret, EINVAL);
 130        if (log)
 131                check_ones(log, LOG_SIZE,
 132                           "verifier touched log with bad parameters\n");
 133}
 134
 135int main(int argc, char **argv)
 136{
 137        char full_log[LOG_SIZE];
 138        char log[LOG_SIZE];
 139        size_t want_len;
 140        int i;
 141
 142        memset(log, 1, LOG_SIZE);
 143
 144        /* Test incorrect attr */
 145        printf("Test log_level 0...\n");
 146        test_log_bad(log, LOG_SIZE, 0);
 147
 148        printf("Test log_size < 128...\n");
 149        test_log_bad(log, 15, 1);
 150
 151        printf("Test log_buff = NULL...\n");
 152        test_log_bad(NULL, LOG_SIZE, 1);
 153
 154        /* Test with log big enough */
 155        printf("Test oversized buffer...\n");
 156        test_log_good(full_log, LOG_SIZE, LOG_SIZE, 0, EACCES, full_log);
 157
 158        want_len = strlen(full_log);
 159
 160        printf("Test exact buffer...\n");
 161        test_log_good(log, LOG_SIZE, want_len + 2, want_len, EACCES, full_log);
 162
 163        printf("Test undersized buffers...\n");
 164        for (i = 0; i < 64; i++) {
 165                full_log[want_len - i + 1] = 1;
 166                full_log[want_len - i] = 0;
 167
 168                test_log_good(log, LOG_SIZE, want_len + 1 - i, want_len - i,
 169                              ENOSPC, full_log);
 170        }
 171
 172        printf("test_verifier_log: OK\n");
 173        return 0;
 174}
 175