diff options
author | Vladimir Kobal <vlad@prokk.net> | 2020-08-04 22:54:15 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-08-04 22:54:15 +0300 |
commit | 63258aa524f3c876a5a9c8524af9d0989788086b (patch) | |
tree | 1e7272f8ddee40a9baa0428874a8550ce23e881d /libnetdata/ebpf | |
parent | 01c220b90e45ff05b418984647bf4a69aa147155 (diff) |
Detect a buggy Ubuntu kernel (#9648)
Diffstat (limited to 'libnetdata/ebpf')
-rw-r--r-- | libnetdata/ebpf/ebpf.c | 80 | ||||
-rw-r--r-- | libnetdata/ebpf/ebpf.h | 3 |
2 files changed, 80 insertions, 3 deletions
diff --git a/libnetdata/ebpf/ebpf.c b/libnetdata/ebpf/ebpf.c index 0d7af7068a..50454c77d2 100644 --- a/libnetdata/ebpf/ebpf.c +++ b/libnetdata/ebpf/ebpf.c @@ -4,6 +4,7 @@ #include <sys/stat.h> #include <fcntl.h> #include <dlfcn.h> +#include <sys/utsname.h> #include "../libnetdata.h" @@ -61,7 +62,7 @@ int clean_kprobe_events(FILE *out, int pid, netdata_ebpf_events_t *ptr) int get_kernel_version(char *out, int size) { char major[16], minor[16], patch[16]; - char ver[256]; + char ver[VERSION_STRING_LEN]; char *version = ver; out[0] = '\0'; @@ -107,14 +108,14 @@ int get_kernel_version(char *out, int size) int get_redhat_release() { - char buffer[256]; + char buffer[VERSION_STRING_LEN + 1]; int major, minor; FILE *fp = fopen("/etc/redhat-release", "r"); if (fp) { major = 0; minor = -1; - size_t length = fread(buffer, sizeof(char), 255, fp); + size_t length = fread(buffer, sizeof(char), VERSION_STRING_LEN, fp); if (length > 4) { buffer[length] = '\0'; char *end = strchr(buffer, '.'); @@ -146,8 +147,81 @@ int get_redhat_release() } } +/** + * Check if the kernel is in a list of rejected ones + * + * @return Returns 1 if the kernel is rejected, 0 otherwise. + */ +static int kernel_is_rejected() +{ + // Get kernel version from system + char version_string[VERSION_STRING_LEN + 1]; + int version_string_len = 0; + + if (read_file("/proc/version_signature", version_string, VERSION_STRING_LEN)) { + if (read_file("/proc/version", version_string, VERSION_STRING_LEN)) { + struct utsname uname_buf; + if (!uname(&uname_buf)) { + info("Cannot check kernel version"); + return 0; + } + version_string_len = + snprintfz(version_string, VERSION_STRING_LEN, "%s %s", uname_buf.release, uname_buf.version); + } + } + + if (!version_string_len) + version_string_len = strlen(version_string); + + // Open a file with a list of rejected kernels + char *config_dir = getenv("NETDATA_USER_CONFIG_DIR"); + if (config_dir == NULL) { + config_dir = CONFIG_DIR; + } + + char filename[FILENAME_MAX + 1]; + snprintfz(filename, FILENAME_MAX, "%s/%s", config_dir, EBPF_KERNEL_REJECT_LIST_FILE); + FILE *kernel_reject_list = fopen(filename, "r"); + + if (!kernel_reject_list) { + config_dir = getenv("NETDATA_STOCK_CONFIG_DIR"); + if (config_dir == NULL) { + config_dir = LIBCONFIG_DIR; + } + + snprintfz(filename, FILENAME_MAX, "%s/%s", config_dir, EBPF_KERNEL_REJECT_LIST_FILE); + kernel_reject_list = fopen(filename, "r"); + + if (!kernel_reject_list) + return 0; + } + + // Find if the kernel is in the reject list + char *reject_string = NULL; + size_t buf_len = 0; + ssize_t reject_string_len; + while ((reject_string_len = getline(&reject_string, &buf_len, kernel_reject_list) - 1) > 0) { + if (version_string_len >= reject_string_len) { + if (!strncmp(version_string, reject_string, reject_string_len)) { + info("A buggy kernel is detected"); + fclose(kernel_reject_list); + freez(reject_string); + return 1; + } + } + } + + fclose(kernel_reject_list); + freez(reject_string); + + return 0; +} + static int has_ebpf_kernel_version(int version) { + if (kernel_is_rejected()) + return 0; + // Kernel 4.11.0 or RH > 7.5 return (version >= NETDATA_MINIMUM_EBPF_KERNEL || get_redhat_release() >= NETDATA_MINIMUM_RH_VERSION); } diff --git a/libnetdata/ebpf/ebpf.h b/libnetdata/ebpf/ebpf.h index 1003f9eda3..029175dcb3 100644 --- a/libnetdata/ebpf/ebpf.h +++ b/libnetdata/ebpf/ebpf.h @@ -52,6 +52,9 @@ */ #define NETDATA_EBPF_KERNEL_4_11 264960 +#define VERSION_STRING_LEN 256 +#define EBPF_KERNEL_REJECT_LIST_FILE "ebpf_kernel_reject_list.txt" + typedef struct netdata_ebpf_events { char type; char *name; |