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
[](<>)
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