test_verifier_log.c 3.8 KB

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