^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* Copyright (c) 2019 Netronome Systems, Inc. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <ctype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <net/if.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #ifdef USE_LIBCAP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <sys/capability.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <sys/utsname.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <sys/vfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/filter.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/limits.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <bpf/bpf.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <bpf/libbpf.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <zlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "main.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #ifndef PROC_SUPER_MAGIC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) # define PROC_SUPER_MAGIC 0x9fa0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) enum probe_component {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) COMPONENT_UNSPEC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) COMPONENT_KERNEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) COMPONENT_DEVICE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define BPF_HELPER_MAKE_ENTRY(name) [BPF_FUNC_ ## name] = "bpf_" # name
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static const char * const helper_name[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) __BPF_FUNC_MAPPER(BPF_HELPER_MAKE_ENTRY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #undef BPF_HELPER_MAKE_ENTRY
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static bool full_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #ifdef USE_LIBCAP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static bool run_as_unprivileged;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /* Miscellaneous utility functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static bool check_procfs(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct statfs st_fs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (statfs("/proc", &st_fs) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) if ((unsigned long)st_fs.f_type != PROC_SUPER_MAGIC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) static void uppercase(char *str, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) size_t i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) for (i = 0; i < len && str[i] != '\0'; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) str[i] = toupper(str[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) /* Printing utility functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) print_bool_feature(const char *feat_name, const char *plain_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) const char *define_name, bool res, const char *define_prefix)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (json_output)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) jsonw_bool_field(json_wtr, feat_name, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) else if (define_prefix)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) printf("#define %s%sHAVE_%s\n", define_prefix,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) res ? "" : "NO_", define_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) printf("%s is %savailable\n", plain_name, res ? "" : "NOT ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static void print_kernel_option(const char *name, const char *value,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) const char *define_prefix)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) char *endptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) int res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (json_output) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (!value) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) jsonw_null_field(json_wtr, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) errno = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) res = strtol(value, &endptr, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (!errno && *endptr == '\n')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) jsonw_int_field(json_wtr, name, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) jsonw_string_field(json_wtr, name, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) } else if (define_prefix) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if (value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) printf("#define %s%s %s\n", define_prefix,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) name, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) printf("/* %s%s is not set */\n", define_prefix, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) printf("%s is set to %s\n", name, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) printf("%s is not set\n", name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) print_start_section(const char *json_title, const char *plain_title,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) const char *define_comment, const char *define_prefix)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (json_output) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) jsonw_name(json_wtr, json_title);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) jsonw_start_object(json_wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) } else if (define_prefix) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) printf("%s\n", define_comment);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) printf("%s\n", plain_title);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static void print_end_section(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (json_output)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) jsonw_end_object(json_wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) printf("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) /* Probing functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) static int read_procfs(const char *path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) char *endptr, *line = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) size_t len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) FILE *fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) int res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) fd = fopen(path, "r");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (!fd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) res = getline(&line, &len, fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) fclose(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (res < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) errno = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) res = strtol(line, &endptr, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (errno || *line == '\0' || *endptr != '\n')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) res = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) free(line);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) static void probe_unprivileged_disabled(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) int res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) /* No support for C-style ouptut */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) res = read_procfs("/proc/sys/kernel/unprivileged_bpf_disabled");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (json_output) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) jsonw_int_field(json_wtr, "unprivileged_bpf_disabled", res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) switch (res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) printf("bpf() syscall for unprivileged users is enabled\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) printf("bpf() syscall restricted to privileged users\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) case -1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) printf("Unable to retrieve required privileges for bpf() syscall\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) printf("bpf() syscall restriction has unknown value %d\n", res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) static void probe_jit_enable(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) int res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) /* No support for C-style ouptut */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) res = read_procfs("/proc/sys/net/core/bpf_jit_enable");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) if (json_output) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) jsonw_int_field(json_wtr, "bpf_jit_enable", res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) switch (res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) printf("JIT compiler is disabled\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) printf("JIT compiler is enabled\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) printf("JIT compiler is enabled with debugging traces in kernel logs\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) case -1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) printf("Unable to retrieve JIT-compiler status\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) printf("JIT-compiler status has unknown value %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) static void probe_jit_harden(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) int res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) /* No support for C-style ouptut */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) res = read_procfs("/proc/sys/net/core/bpf_jit_harden");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (json_output) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) jsonw_int_field(json_wtr, "bpf_jit_harden", res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) switch (res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) printf("JIT compiler hardening is disabled\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) printf("JIT compiler hardening is enabled for unprivileged users\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) printf("JIT compiler hardening is enabled for all users\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) case -1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) printf("Unable to retrieve JIT hardening status\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) printf("JIT hardening status has unknown value %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) static void probe_jit_kallsyms(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) int res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) /* No support for C-style ouptut */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) res = read_procfs("/proc/sys/net/core/bpf_jit_kallsyms");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) if (json_output) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) jsonw_int_field(json_wtr, "bpf_jit_kallsyms", res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) switch (res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) printf("JIT compiler kallsyms exports are disabled\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) printf("JIT compiler kallsyms exports are enabled for root\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) case -1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) printf("Unable to retrieve JIT kallsyms export status\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) printf("JIT kallsyms exports status has unknown value %d\n", res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) static void probe_jit_limit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) int res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) /* No support for C-style ouptut */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) res = read_procfs("/proc/sys/net/core/bpf_jit_limit");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if (json_output) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) jsonw_int_field(json_wtr, "bpf_jit_limit", res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) switch (res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) case -1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) printf("Unable to retrieve global memory limit for JIT compiler for unprivileged users\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) printf("Global memory limit for JIT compiler for unprivileged users is %d bytes\n", res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) static bool read_next_kernel_config_option(gzFile file, char *buf, size_t n,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) char **value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) char *sep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) while (gzgets(file, buf, n)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) if (strncmp(buf, "CONFIG_", 7))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) sep = strchr(buf, '=');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (!sep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) /* Trim ending '\n' */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) buf[strlen(buf) - 1] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) /* Split on '=' and ensure that a value is present. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) *sep = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) if (!sep[1])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) *value = sep + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) static void probe_kernel_image_config(const char *define_prefix)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) static const struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) const char * const name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) bool macro_dump;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) } options[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) /* Enable BPF */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) { "CONFIG_BPF", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) /* Enable bpf() syscall */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) { "CONFIG_BPF_SYSCALL", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) /* Does selected architecture support eBPF JIT compiler */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) { "CONFIG_HAVE_EBPF_JIT", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) /* Compile eBPF JIT compiler */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) { "CONFIG_BPF_JIT", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) /* Avoid compiling eBPF interpreter (use JIT only) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) { "CONFIG_BPF_JIT_ALWAYS_ON", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) /* cgroups */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) { "CONFIG_CGROUPS", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) /* BPF programs attached to cgroups */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) { "CONFIG_CGROUP_BPF", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) /* bpf_get_cgroup_classid() helper */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) { "CONFIG_CGROUP_NET_CLASSID", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) /* bpf_skb_{,ancestor_}cgroup_id() helpers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) { "CONFIG_SOCK_CGROUP_DATA", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) /* Tracing: attach BPF to kprobes, tracepoints, etc. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) { "CONFIG_BPF_EVENTS", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) /* Kprobes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) { "CONFIG_KPROBE_EVENTS", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) /* Uprobes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) { "CONFIG_UPROBE_EVENTS", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) /* Tracepoints */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) { "CONFIG_TRACING", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) /* Syscall tracepoints */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) { "CONFIG_FTRACE_SYSCALLS", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) /* bpf_override_return() helper support for selected arch */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) { "CONFIG_FUNCTION_ERROR_INJECTION", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) /* bpf_override_return() helper */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) { "CONFIG_BPF_KPROBE_OVERRIDE", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) /* Network */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) { "CONFIG_NET", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) /* AF_XDP sockets */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) { "CONFIG_XDP_SOCKETS", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) /* BPF_PROG_TYPE_LWT_* and related helpers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) { "CONFIG_LWTUNNEL_BPF", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) /* BPF_PROG_TYPE_SCHED_ACT, TC (traffic control) actions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) { "CONFIG_NET_ACT_BPF", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) /* BPF_PROG_TYPE_SCHED_CLS, TC filters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) { "CONFIG_NET_CLS_BPF", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) /* TC clsact qdisc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) { "CONFIG_NET_CLS_ACT", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) /* Ingress filtering with TC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) { "CONFIG_NET_SCH_INGRESS", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) /* bpf_skb_get_xfrm_state() helper */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) { "CONFIG_XFRM", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) /* bpf_get_route_realm() helper */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) { "CONFIG_IP_ROUTE_CLASSID", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) /* BPF_PROG_TYPE_LWT_SEG6_LOCAL and related helpers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) { "CONFIG_IPV6_SEG6_BPF", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) /* BPF_PROG_TYPE_LIRC_MODE2 and related helpers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) { "CONFIG_BPF_LIRC_MODE2", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) /* BPF stream parser and BPF socket maps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) { "CONFIG_BPF_STREAM_PARSER", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) /* xt_bpf module for passing BPF programs to netfilter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) { "CONFIG_NETFILTER_XT_MATCH_BPF", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) /* bpfilter back-end for iptables */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) { "CONFIG_BPFILTER", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) /* bpftilter module with "user mode helper" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) { "CONFIG_BPFILTER_UMH", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) /* test_bpf module for BPF tests */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) { "CONFIG_TEST_BPF", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) /* Misc configs useful in BPF C programs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) /* jiffies <-> sec conversion for bpf_jiffies64() helper */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) { "CONFIG_HZ", true, }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) char *values[ARRAY_SIZE(options)] = { };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) struct utsname utsn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) char path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) gzFile file = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) char buf[4096];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) char *value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) size_t i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) if (!uname(&utsn)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) snprintf(path, sizeof(path), "/boot/config-%s", utsn.release);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) /* gzopen also accepts uncompressed files. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) file = gzopen(path, "r");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) if (!file) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) /* Some distributions build with CONFIG_IKCONFIG=y and put the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) * config file at /proc/config.gz.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) file = gzopen("/proc/config.gz", "r");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) if (!file) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) p_info("skipping kernel config, can't open file: %s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) goto end_parse;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) /* Sanity checks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) if (!gzgets(file, buf, sizeof(buf)) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) !gzgets(file, buf, sizeof(buf))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) p_info("skipping kernel config, can't read from file: %s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) goto end_parse;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) if (strcmp(buf, "# Automatically generated file; DO NOT EDIT.\n")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) p_info("skipping kernel config, can't find correct file");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) goto end_parse;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) while (read_next_kernel_config_option(file, buf, sizeof(buf), &value)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) for (i = 0; i < ARRAY_SIZE(options); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) if ((define_prefix && !options[i].macro_dump) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) values[i] || strcmp(buf, options[i].name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) values[i] = strdup(value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) end_parse:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) if (file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) gzclose(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) for (i = 0; i < ARRAY_SIZE(options); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) if (define_prefix && !options[i].macro_dump)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) print_kernel_option(options[i].name, values[i], define_prefix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) free(values[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) static bool probe_bpf_syscall(const char *define_prefix)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) bool res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) bpf_load_program(BPF_PROG_TYPE_UNSPEC, NULL, 0, NULL, 0, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) res = (errno != ENOSYS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) print_bool_feature("have_bpf_syscall",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) "bpf() syscall",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) "BPF_SYSCALL",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) res, define_prefix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) const char *define_prefix, __u32 ifindex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) char feat_name[128], plain_desc[128], define_name[128];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) const char *plain_comment = "eBPF program_type ";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) size_t maxlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) bool res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) if (ifindex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) /* Only test offload-able program types */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) switch (prog_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) case BPF_PROG_TYPE_SCHED_CLS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) case BPF_PROG_TYPE_XDP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) res = bpf_probe_prog_type(prog_type, ifindex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) #ifdef USE_LIBCAP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) /* Probe may succeed even if program load fails, for unprivileged users
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) * check that we did not fail because of insufficient permissions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) if (run_as_unprivileged && errno == EPERM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) res = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) supported_types[prog_type] |= res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) if (!prog_type_name[prog_type]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) p_info("program type name not found (type %d)", prog_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) if (strlen(prog_type_name[prog_type]) > maxlen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) p_info("program type name too long");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) sprintf(feat_name, "have_%s_prog_type", prog_type_name[prog_type]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) sprintf(define_name, "%s_prog_type", prog_type_name[prog_type]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) uppercase(define_name, sizeof(define_name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) sprintf(plain_desc, "%s%s", plain_comment, prog_type_name[prog_type]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) print_bool_feature(feat_name, plain_desc, define_name, res,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) define_prefix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) probe_map_type(enum bpf_map_type map_type, const char *define_prefix,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) __u32 ifindex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) char feat_name[128], plain_desc[128], define_name[128];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) const char *plain_comment = "eBPF map_type ";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) size_t maxlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) bool res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) res = bpf_probe_map_type(map_type, ifindex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) /* Probe result depends on the success of map creation, no additional
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) * check required for unprivileged users
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) if (!map_type_name[map_type]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) p_info("map type name not found (type %d)", map_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) if (strlen(map_type_name[map_type]) > maxlen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) p_info("map type name too long");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) sprintf(feat_name, "have_%s_map_type", map_type_name[map_type]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) sprintf(define_name, "%s_map_type", map_type_name[map_type]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) uppercase(define_name, sizeof(define_name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) sprintf(plain_desc, "%s%s", plain_comment, map_type_name[map_type]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) print_bool_feature(feat_name, plain_desc, define_name, res,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) define_prefix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) probe_helper_for_progtype(enum bpf_prog_type prog_type, bool supported_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) const char *define_prefix, unsigned int id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) const char *ptype_name, __u32 ifindex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) bool res = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) if (supported_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) res = bpf_probe_helper(id, prog_type, ifindex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) #ifdef USE_LIBCAP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) /* Probe may succeed even if program load fails, for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) * unprivileged users check that we did not fail because of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) * insufficient permissions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) if (run_as_unprivileged && errno == EPERM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) res = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) if (json_output) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) jsonw_string(json_wtr, helper_name[id]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) } else if (define_prefix) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) printf("#define %sBPF__PROG_TYPE_%s__HELPER_%s %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) define_prefix, ptype_name, helper_name[id],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) res ? "1" : "0");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) printf("\n\t- %s", helper_name[id]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) const char *define_prefix, __u32 ifindex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) const char *ptype_name = prog_type_name[prog_type];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) char feat_name[128];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) unsigned int id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) if (ifindex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) /* Only test helpers for offload-able program types */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) switch (prog_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) case BPF_PROG_TYPE_SCHED_CLS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) case BPF_PROG_TYPE_XDP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) if (json_output) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) sprintf(feat_name, "%s_available_helpers", ptype_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) jsonw_name(json_wtr, feat_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) jsonw_start_array(json_wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) } else if (!define_prefix) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) printf("eBPF helpers supported for program type %s:",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) ptype_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) for (id = 1; id < ARRAY_SIZE(helper_name); id++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) /* Skip helper functions which emit dmesg messages when not in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) * the full mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) switch (id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) case BPF_FUNC_trace_printk:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) case BPF_FUNC_probe_write_user:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) if (!full_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) /* fallthrough */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) probe_helper_for_progtype(prog_type, supported_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) define_prefix, id, ptype_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) ifindex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) if (json_output)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) jsonw_end_array(json_wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) else if (!define_prefix)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) printf("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) probe_large_insn_limit(const char *define_prefix, __u32 ifindex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) bool res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) res = bpf_probe_large_insn_limit(ifindex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) print_bool_feature("have_large_insn_limit",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) "Large program size limit",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) "LARGE_INSN_LIMIT",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) res, define_prefix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) section_system_config(enum probe_component target, const char *define_prefix)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) switch (target) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) case COMPONENT_KERNEL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) case COMPONENT_UNSPEC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) print_start_section("system_config",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) "Scanning system configuration...",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) "/*** Misc kernel config items ***/",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) define_prefix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) if (!define_prefix) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) if (check_procfs()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) probe_unprivileged_disabled();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) probe_jit_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) probe_jit_harden();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) probe_jit_kallsyms();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) probe_jit_limit();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) p_info("/* procfs not mounted, skipping related probes */");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) probe_kernel_image_config(define_prefix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) print_end_section();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) static bool section_syscall_config(const char *define_prefix)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) bool res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) print_start_section("syscall_config",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) "Scanning system call availability...",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) "/*** System call availability ***/",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) define_prefix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) res = probe_bpf_syscall(define_prefix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) print_end_section();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) section_program_types(bool *supported_types, const char *define_prefix,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) __u32 ifindex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) print_start_section("program_types",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) "Scanning eBPF program types...",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) "/*** eBPF program types ***/",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) define_prefix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) for (i = BPF_PROG_TYPE_UNSPEC + 1; i < prog_type_name_size; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) probe_prog_type(i, supported_types, define_prefix, ifindex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) print_end_section();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) static void section_map_types(const char *define_prefix, __u32 ifindex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) print_start_section("map_types",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) "Scanning eBPF map types...",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) "/*** eBPF map types ***/",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) define_prefix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) for (i = BPF_MAP_TYPE_UNSPEC + 1; i < map_type_name_size; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) probe_map_type(i, define_prefix, ifindex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) print_end_section();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) section_helpers(bool *supported_types, const char *define_prefix, __u32 ifindex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) print_start_section("helpers",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) "Scanning eBPF helper functions...",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) "/*** eBPF helper functions ***/",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) define_prefix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) if (define_prefix)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) printf("/*\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) " * Use %sHAVE_PROG_TYPE_HELPER(prog_type_name, helper_name)\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) " * to determine if <helper_name> is available for <prog_type_name>,\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) " * e.g.\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) " * #if %sHAVE_PROG_TYPE_HELPER(xdp, bpf_redirect)\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) " * // do stuff with this helper\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) " * #elif\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) " * // use a workaround\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) " * #endif\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) " */\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) "#define %sHAVE_PROG_TYPE_HELPER(prog_type, helper) \\\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) " %sBPF__PROG_TYPE_ ## prog_type ## __HELPER_ ## helper\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) define_prefix, define_prefix, define_prefix,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) define_prefix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) for (i = BPF_PROG_TYPE_UNSPEC + 1; i < prog_type_name_size; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) probe_helpers_for_progtype(i, supported_types[i], define_prefix,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) ifindex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) print_end_section();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) static void section_misc(const char *define_prefix, __u32 ifindex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) print_start_section("misc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) "Scanning miscellaneous eBPF features...",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) "/*** eBPF misc features ***/",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) define_prefix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) probe_large_insn_limit(define_prefix, ifindex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) print_end_section();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) #ifdef USE_LIBCAP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) #define capability(c) { c, false, #c }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) #define capability_msg(a, i) a[i].set ? "" : a[i].name, a[i].set ? "" : ", "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) static int handle_perms(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) #ifdef USE_LIBCAP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) cap_value_t cap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) bool set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) char name[14]; /* strlen("CAP_SYS_ADMIN") */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) } bpf_caps[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) capability(CAP_SYS_ADMIN),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) #ifdef CAP_BPF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) capability(CAP_BPF),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) capability(CAP_NET_ADMIN),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) capability(CAP_PERFMON),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) cap_value_t cap_list[ARRAY_SIZE(bpf_caps)];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) unsigned int i, nb_bpf_caps = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) bool cap_sys_admin_only = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) cap_flag_value_t val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) int res = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) cap_t caps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) caps = cap_get_proc();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) if (!caps) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) p_err("failed to get capabilities for process: %s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) #ifdef CAP_BPF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) if (CAP_IS_SUPPORTED(CAP_BPF))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) cap_sys_admin_only = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) for (i = 0; i < ARRAY_SIZE(bpf_caps); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) const char *cap_name = bpf_caps[i].name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) cap_value_t cap = bpf_caps[i].cap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) if (cap_get_flag(caps, cap, CAP_EFFECTIVE, &val)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) p_err("bug: failed to retrieve %s status: %s", cap_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) goto exit_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) if (val == CAP_SET) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) bpf_caps[i].set = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) cap_list[nb_bpf_caps++] = cap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) if (cap_sys_admin_only)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) /* System does not know about CAP_BPF, meaning that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) * CAP_SYS_ADMIN is the only capability required. We
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) * just checked it, break.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) if ((run_as_unprivileged && !nb_bpf_caps) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) (!run_as_unprivileged && nb_bpf_caps == ARRAY_SIZE(bpf_caps)) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) (!run_as_unprivileged && cap_sys_admin_only && nb_bpf_caps)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) /* We are all good, exit now */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) res = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) goto exit_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) if (!run_as_unprivileged) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) if (cap_sys_admin_only)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) p_err("missing %s, required for full feature probing; run as root or use 'unprivileged'",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) bpf_caps[0].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) p_err("missing %s%s%s%s%s%s%s%srequired for full feature probing; run as root or use 'unprivileged'",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) capability_msg(bpf_caps, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) #ifdef CAP_BPF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) capability_msg(bpf_caps, 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) capability_msg(bpf_caps, 2),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) capability_msg(bpf_caps, 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) "", "", "", "", "", ""
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) #endif /* CAP_BPF */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) goto exit_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) /* if (run_as_unprivileged && nb_bpf_caps > 0), drop capabilities. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) if (cap_set_flag(caps, CAP_EFFECTIVE, nb_bpf_caps, cap_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) CAP_CLEAR)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) p_err("bug: failed to clear capabilities: %s", strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) goto exit_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) if (cap_set_proc(caps)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) p_err("failed to drop capabilities: %s", strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) goto exit_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) res = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) exit_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) if (cap_free(caps) && !res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) p_err("failed to clear storage object for capabilities: %s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) res = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) /* Detection assumes user has specific privileges.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) * We do not use libpcap so let's approximate, and restrict usage to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) * root user only.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) if (geteuid()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) p_err("full feature probing requires root privileges");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) #endif /* USE_LIBCAP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) static int do_probe(int argc, char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) enum probe_component target = COMPONENT_UNSPEC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) const char *define_prefix = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) bool supported_types[128] = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) __u32 ifindex = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) char *ifname;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) set_max_rlimit();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) while (argc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) if (is_prefix(*argv, "kernel")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) if (target != COMPONENT_UNSPEC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) p_err("component to probe already specified");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) target = COMPONENT_KERNEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) NEXT_ARG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) } else if (is_prefix(*argv, "dev")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) NEXT_ARG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) if (target != COMPONENT_UNSPEC || ifindex) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) p_err("component to probe already specified");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) if (!REQ_ARGS(1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) target = COMPONENT_DEVICE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) ifname = GET_ARG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) ifindex = if_nametoindex(ifname);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) if (!ifindex) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) p_err("unrecognized netdevice '%s': %s", ifname,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) } else if (is_prefix(*argv, "full")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) full_mode = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) NEXT_ARG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) } else if (is_prefix(*argv, "macros") && !define_prefix) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) define_prefix = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) NEXT_ARG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) } else if (is_prefix(*argv, "prefix")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) if (!define_prefix) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) p_err("'prefix' argument can only be use after 'macros'");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) if (strcmp(define_prefix, "")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) p_err("'prefix' already defined");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) NEXT_ARG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) if (!REQ_ARGS(1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) define_prefix = GET_ARG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) } else if (is_prefix(*argv, "unprivileged")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) #ifdef USE_LIBCAP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) run_as_unprivileged = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) NEXT_ARG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) p_err("unprivileged run not supported, recompile bpftool with libcap");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) p_err("expected no more arguments, 'kernel', 'dev', 'macros' or 'prefix', got: '%s'?",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) *argv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) /* Full feature detection requires specific privileges.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) * Let's approximate, and warn if user is not root.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) if (handle_perms())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) if (json_output) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) define_prefix = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) jsonw_start_object(json_wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) section_system_config(target, define_prefix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) if (!section_syscall_config(define_prefix))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) /* bpf() syscall unavailable, don't probe other BPF features */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) goto exit_close_json;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) section_program_types(supported_types, define_prefix, ifindex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) section_map_types(define_prefix, ifindex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) section_helpers(supported_types, define_prefix, ifindex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) section_misc(define_prefix, ifindex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) exit_close_json:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) if (json_output)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) /* End root object */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) jsonw_end_object(json_wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) static int do_help(int argc, char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) if (json_output) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) jsonw_null(json_wtr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) fprintf(stderr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) "Usage: %1$s %2$s probe [COMPONENT] [full] [unprivileged] [macros [prefix PREFIX]]\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) " %1$s %2$s help\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) "\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) " COMPONENT := { kernel | dev NAME }\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) "",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) bin_name, argv[-2]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) static const struct cmd cmds[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) { "probe", do_probe },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) { "help", do_help },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) { 0 }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) int do_feature(int argc, char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) return cmd_select(cmds, argc, argv, do_help);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) }