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