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