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