@cryptotaxi247 / netdata-1 / commits / 664d180dc

Fix potential memory leak in ebpf.plugin (#9484)

Fix reported bugs with ebpf.plugin.

thiagoftsm committed Jul 14, 2020 at 16:42 UTC 664d180dc7a5e34334a4f94399e5663eb5c0be8a
13 files changed +60 -34
.gitignore
+1
@@ -67,6 +67,7 @@ cgroup-network
67 !cgroup-network/
68
69 ebpf.plugin
70 +collectors/ebpf.plugin/reset_netdata_trace.sh
71 !ebpf.plugin/
72
73 # protoc generated files
collectors/ebpf.plugin/Makefile.am
+12 -1
@@ -3,11 +3,22 @@
3 AUTOMAKE_OPTIONS = subdir-objects
4 MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
5
6 +CLEANFILES = \
7 + reset_netdata_trace.sh \
8 + $(NULL)
9 +
10 +include $(top_srcdir)/build/subst.inc
11 +SUFFIXES = .in
12 +
13 +dist_plugins_SCRIPTS = \
14 + reset_netdata_trace.sh \
15 + $(NULL)
16 +
17 dist_noinst_DATA = \
18 + reset_netdata_trace.sh.in \
19 README.md \
20 $(NULL)
21
22 dist_libconfig_DATA = \
23 ebpf.conf \
24 $(NULL)
13 -
collectors/ebpf.plugin/README.md
+5
@@ -338,4 +338,9 @@ shows how the lockdown module impacts `ebpf.plugin` based on the selected option
338 If you or your distribution compiled the kernel with the last combination, your system cannot load shared libraries
339 required to run `ebpf.plugin`.
340
341 +## Cleaning `kprobe_events`
342 +The eBPF collector adds entries to the file `/sys/kernel/debug/tracing/kprobe_events`, and cleans them on exit, unless
343 +another process prevents it. If you need to clean the eBPF entries safely, you can manually run the script
344 +`/usr/libexec/netdata/plugins.d/reset_netdata_trace.sh`.
345 +
346 [![analytics](https://www.google-analytics.com/collect?v=1&aip=1&t=pageview&_s=1&ds=github&dr=https%3A%2F%2Fgithub.com%2Fnetdata%2Fnetdata&dl=https%3A%2F%2Fmy-netdata.io%2Fgithub%2Fcollectors%2Febpf.plugin%2FREADME&_u=MAC~&cid=5792dfd7-8dc4-476b-af31-da2fdb9f93d2&tid=UA-64295674-3)](<>)
collectors/ebpf.plugin/ebpf.c
+15 -4
@@ -86,13 +86,14 @@ netdata_ebpf_events_t process_probes[] = {
86 };
87
88 netdata_ebpf_events_t socket_probes[] = {
89 - { .type = 'r', .name = "tcp_sendmsg" },
89 { .type = 'p', .name = "tcp_cleanup_rbuf" },
90 { .type = 'p', .name = "tcp_close" },
91 { .type = 'p', .name = "udp_recvmsg" },
92 { .type = 'r', .name = "udp_recvmsg" },
93 { .type = 'r', .name = "udp_sendmsg" },
94 { .type = 'p', .name = "do_exit" },
95 + { .type = 'p', .name = "tcp_sendmsg" },
96 + { .type = 'r', .name = "tcp_sendmsg" },
97 { .type = 0, .name = NULL }
98 };
99
@@ -115,6 +116,15 @@ ebpf_process_stat_t *global_process_stat = NULL;
116 *
117 *****************************************************************/
118
119 +static void change_events()
120 +{
121 + if (ebpf_modules[0].mode == MODE_ENTRY)
122 + change_process_event();
123 +
124 + if (ebpf_modules[1].mode == MODE_ENTRY)
125 + change_socket_event();
126 +}
127 +
128 /**
129 * Clean Loaded Events
130 *
@@ -166,8 +176,8 @@ static void ebpf_exit(int sig)
176
177 int sid = setsid();
178 if(sid >= 0) {
169 - sleep(1);
179 debug(D_EXIT, "Wait for father %d die", getpid());
180 + sleep_usec(200000); //Sleep 200 miliseconds to father dies.
181 clean_loaded_events();
182 } else {
183 error("Cannot become session id leader, so I won't try to clean kprobe_events.\n");
@@ -816,10 +826,10 @@ static void parse_args(int argc, char **argv)
826 }
827
828 if (load_collector_config(ebpf_user_config_dir, &disable_apps)) {
819 - error("Does not have a configuration file inside `%s/ebpf.conf. It will try to load stock file.",
829 + info("Does not have a configuration file inside `%s/ebpf.conf. It will try to load stock file.",
830 ebpf_user_config_dir);
831 if (load_collector_config(ebpf_stock_config_dir, &disable_apps)) {
822 - error("Does not have a stock file. It is starting with default options.");
832 + info("Does not have a stock file. It is starting with default options.");
833 } else {
834 enabled = 1;
835 }
@@ -920,6 +930,7 @@ int main(int argc, char **argv)
930 {NULL, NULL, NULL, 0, NULL, NULL, NULL}
931 };
932
933 + change_events();
934 clean_loaded_events();
935
936 int i;
collectors/ebpf.plugin/ebpf.h
+4
@@ -202,4 +202,8 @@ extern int update_every;
202
203 # define EBPF_MAX_SYNCHRONIZATION_TIME 300
204
205 +//External functions
206 +extern void change_socket_event();
207 +extern void change_process_event();
208 +
209 #endif
collectors/ebpf.plugin/ebpf_apps.c
+1 -1
@@ -764,7 +764,7 @@ static inline void link_all_processes_to_their_parents(void) {
764 }
765 else {
766 p->parent = NULL;
767 - error("pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid);
767 + debug_log("pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid);
768 }
769 }
770 }
collectors/ebpf.plugin/ebpf_process.c
+3 -20
@@ -876,18 +876,6 @@ static void process_collector(usec_t step, ebpf_module_t *em)
876 *
877 *****************************************************************/
878
879 -/**
880 - * Clean the allocated process stat structure
881 - */
882 -static void clean_process_stat()
883 -{
884 - size_t i;
885 - for (i = 0 ; i < all_pids_count ; i++) {
886 - ebpf_process_stat_t *w = local_process_stats[pid_index[i]];
887 - freez(w);
888 - }
889 -}
890 -
879 /**
880 * Clean up the main thread.
881 *
@@ -901,7 +889,6 @@ static void ebpf_process_cleanup(void *ptr)
889 freez(process_publish_aggregated);
890 freez(process_hash_values);
891
904 - clean_process_stat();
892 freez(local_process_stats);
893
894 if (process_functions.libnetdata) {
@@ -936,7 +923,7 @@ static void ebpf_process_allocate_global_vectors(size_t length) {
923 prev_apps_data = callocz((size_t)pid_max, sizeof(ebpf_process_publish_apps_t *));
924 }
925
939 -static void change_collector_event() {
926 +void change_process_event() {
927 int i;
928 if (running_on_kernel < NETDATA_KERNEL_V5_3)
929 process_probes[EBPF_SYS_CLONE_IDX].name = NULL;
@@ -956,7 +943,7 @@ static void change_syscalls() {
943 * Set local variables
944 *
945 */
959 -static void set_local_pointers(ebpf_module_t *em) {
946 +static void set_local_pointers() {
947 #ifndef STATIC
948 bpf_map_lookup_elem = process_functions.bpf_map_lookup_elem;
949
@@ -965,10 +952,6 @@ static void set_local_pointers(ebpf_module_t *em) {
952
953 map_fd = process_functions.map_fd;
954
968 - if (em->mode == MODE_ENTRY) {
969 - change_collector_event();
970 - }
971 -
955 if (process_functions.isrh >= NETDATA_MINIMUM_RH_VERSION && process_functions.isrh < NETDATA_RH_8)
956 change_syscalls();
957 }
@@ -1032,7 +1015,7 @@ void *ebpf_process_thread(void *ptr)
1015 goto endprocess;
1016 }
1017
1035 - set_local_pointers(em);
1018 + set_local_pointers();
1019 if (ebpf_load_program(ebpf_plugin_dir, em->thread_id, em->mode, kernel_string,
1020 em->thread_name, process_functions.map_fd, process_functions.load_bpf_file) ) {
1021 pthread_mutex_unlock(&lock);
collectors/ebpf.plugin/ebpf_socket.c
+4 -2
@@ -515,9 +515,11 @@ static void ebpf_socket_allocate_global_vectors(size_t length) {
515 bandwidth_vector = callocz((size_t) ebpf_nprocs, sizeof(ebpf_bandwidth_t));
516 }
517
518 -static void change_collector_event() {
518 +void change_socket_event() {
519 socket_probes[0].type = 'p';
520 + socket_probes[4].type = 'p';
521 socket_probes[5].type = 'p';
522 + socket_probes[7].name = NULL;
523 }
524
525 /**
@@ -533,7 +535,7 @@ static void set_local_pointers(ebpf_module_t *em) {
535 map_fd = socket_functions.map_fd;
536
537 if (em->mode == MODE_ENTRY) {
536 - change_collector_event();
538 + change_socket_event();
539 }
540 }
541
collectors/ebpf.plugin/reset_netdata_trace.sh.in new
+9
@@ -0,0 +1,9 @@
1 +#!/bin/bash
2 +
3 +KPROBE_FILE="/sys/kernel/debug/tracing/kprobe_events"
4 +
5 +DATA="$(grep _netdata_ $KPROBE_FILE| cut -d' ' -f1 | cut -d: -f2)"
6 +
7 +for I in $DATA; do
8 + echo "-:$I" > $KPROBE_FILE 2>/dev/null;
9 +done
libnetdata/ebpf/ebpf.c
+1 -1
@@ -262,7 +262,7 @@ int ebpf_load_program(char *plugins_dir,
262
263 snprintf(lpath, 4096, "%s/%s", plugins_dir, lname);
264 if (load_bpf_file(map_fd, lpath, event_id)) {
265 - error("Cannot load program: %s", lpath);
265 + info("Cannot load program: %s", lpath);
266 return -1;
267 } else {
268 info("The eBPF program %s was loaded with success.", name);
packaging/ebpf.checksums
+3 -3
@@ -1,3 +1,3 @@
1 -fbee50759ebede5f8b6d4cb43ed28f4877ab813b2700f25f560a854186cc53af netdata-kernel-collector-glibc-v0.4.3.tar.xz
2 -2f9eea8821fac1324b634edb6ef973096ffb20c8f959675887885844068f5461 netdata-kernel-collector-musl-v0.4.3.tar.xz
3 -2fc3dfdcf6efd4c75a3fee0c9e4898bf596cf6e2d58adf3933b3ed519ef8c287 netdata-kernel-collector-static-v0.4.3.tar.xz
1 +d36bfbc727f639b0db8d1525b4e1a0bf5caab61a6a78b40a85581a1f4c1523c8 netdata-kernel-collector-glibc-v0.4.5.tar.xz
2 +9903cebfbf3846810287aa755186000a7badfca5ea49703c836ee788b775466b netdata-kernel-collector-musl-v0.4.5.tar.xz
3 +558ccce60b28cabe8759ec43b3ee519a0fdd5b1aaa9e44d75ac511e5de874261 netdata-kernel-collector-static-v0.4.5.tar.xz
packaging/ebpf.version
+1 -1
@@ -1 +1 @@
1 -v0.4.3
1 +v0.4.5
system/netdata.service.in
+1 -1
@@ -17,7 +17,7 @@ ExecStartPre=/bin/mkdir -p @localstatedir_POST@/cache/netdata
17 ExecStartPre=/bin/chown -R netdata:netdata @localstatedir_POST@/cache/netdata
18 ExecStartPre=/bin/mkdir -p @localstatedir_POST@/run/netdata
19 ExecStartPre=/bin/chown -R netdata:netdata @localstatedir_POST@/run/netdata
20 -#ExecStopPost=/bin/rm @localstatedir_POST@/run/netdata/netdata.pid
20 +ExecStopPost=@pluginsdir_POST@/reset_netdata_trace.sh
21 PermissionsStartOnly=true
22
23 # saving a big db on slow disks may need some time