summaryrefslogtreecommitdiffstats
path: root/libnetdata
diff options
context:
space:
mode:
authorVladimir Kobal <vlad@prokk.net>2020-08-04 22:54:15 +0300
committerGitHub <noreply@github.com>2020-08-04 22:54:15 +0300
commit63258aa524f3c876a5a9c8524af9d0989788086b (patch)
tree1e7272f8ddee40a9baa0428874a8550ce23e881d /libnetdata
parent01c220b90e45ff05b418984647bf4a69aa147155 (diff)
Detect a buggy Ubuntu kernel (#9648)
Diffstat (limited to 'libnetdata')
-rw-r--r--libnetdata/ebpf/ebpf.c80
-rw-r--r--libnetdata/ebpf/ebpf.h3
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;