Add Linux audit subsystem monitoring (#22077)
Costa Tsaousis committed
May 1, 2026 at 16:30 UTC
b64ef16360030719f85395a1a7cbb7ea6d40d10c
11 files changed
+483
-7
CMakeLists.txt
+1
@@ -2631,6 +2631,7 @@ if(ENABLE_PLUGIN_DEBUGFS)
2631
src/collectors/debugfs.plugin/module-zswap.c
2632
src/collectors/debugfs.plugin/module-devices-powercap.c
2633
src/collectors/debugfs.plugin/module-libsensors.c
2634
+ src/collectors/debugfs.plugin/module-audit.c
2635
)
2636
2637
# Add executable for debugfs.plugin
netdata-installer.sh
+1
-1
@@ -830,7 +830,7 @@ if [ "$(id -u)" -eq 0 ]; then
830
capabilities=0
831
if ! iscontainer && command -v setcap 1> /dev/null 2>&1; then
832
run chmod 0750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/debugfs.plugin"
833
- if run setcap cap_dac_read_search+ep "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/debugfs.plugin"; then
833
+ if run setcap cap_dac_read_search,cap_audit_control+ep "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/debugfs.plugin"; then
834
# if we managed to setcap, but we fail to execute debugfs.plugin setuid to root
835
"${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/debugfs.plugin" -t > /dev/null 2>&1 && capabilities=1 || capabilities=0
836
fi
netdata.spec.in
+2
-2
@@ -3171,8 +3171,8 @@ Requires(pre): %{name}-user >= %{version}
3171
3172
%files plugin-debugfs
3173
%defattr(0750,root,netdata,0750)
3174
-# CAP_DAC_READ_SEARCH required for data collection.
3175
-%caps(cap_dac_read_search=ep) %attr(0750,root,netdata) %{_libexecdir}/%{name}/plugins.d/debugfs.plugin
3174
+# CAP_DAC_READ_SEARCH for debugfs data collection, CAP_AUDIT_CONTROL for audit subsystem monitoring.
3175
+%caps(cap_dac_read_search,cap_audit_control=ep) %attr(0750,root,netdata) %{_libexecdir}/%{name}/plugins.d/debugfs.plugin
3176
3177
%package plugin-journal-viewer
3178
Summary: Transitional dummy package
packaging/cmake/pkg-files/deb/plugin-debugfs/postinst
+1
-1
@@ -6,7 +6,7 @@ case "$1" in
6
configure|reconfigure)
7
chown root:netdata /usr/libexec/netdata/plugins.d/debugfs.plugin
8
chmod 0750 /usr/libexec/netdata/plugins.d/debugfs.plugin
9
- if ! setcap "cap_dac_read_search=eip" /usr/libexec/netdata/plugins.d/debugfs.plugin; then
9
+ if ! setcap "cap_dac_read_search,cap_audit_control=eip" /usr/libexec/netdata/plugins.d/debugfs.plugin; then
10
chmod -f 4750 /usr/libexec/netdata/plugins.d/debugfs.plugin
11
fi
12
;;
packaging/makeself/install-or-update.sh
+1
-1
@@ -194,7 +194,7 @@ if command -v setcap >/dev/null 2>&1; then
194
if ! run setcap "cap_dac_read_search=ep" "usr/libexec/netdata/plugins.d/slabinfo.plugin"; then
195
run chmod 4750 "usr/libexec/netdata/plugins.d/slabinfo.plugin"
196
fi
197
- if ! run setcap "cap_dac_read_search=ep" "usr/libexec/netdata/plugins.d/debugfs.plugin"; then
197
+ if ! run setcap "cap_dac_read_search,cap_audit_control=ep" "usr/libexec/netdata/plugins.d/debugfs.plugin"; then
198
run chmod 4750 "usr/libexec/netdata/plugins.d/debugfs.plugin"
199
fi
200
if ! run setcap "cap_dac_read_search+epi cap_net_admin+epi cap_net_raw=eip" "usr/libexec/netdata/plugins.d/go.d.plugin"; then
src/collectors/all.h
+8
@@ -166,6 +166,14 @@
166
#define NETDATA_CHART_PRIO_MEM_KSM_SAVINGS 1301
167
#define NETDATA_CHART_PRIO_MEM_KSM_RATIOS 1302
168
#define NETDATA_CHART_PRIO_MEM_KSM_COW 1303
169
+// Audit
170
+
171
+#define NETDATA_CHART_PRIO_AUDIT_BACKLOG 1340
172
+#define NETDATA_CHART_PRIO_AUDIT_BACKLOG_UTIL 1341
173
+#define NETDATA_CHART_PRIO_AUDIT_LOST 1342
174
+#define NETDATA_CHART_PRIO_AUDIT_ENABLED 1343
175
+#define NETDATA_CHART_PRIO_AUDIT_FAILURE 1344
176
+
177
#define NETDATA_CHART_PRIO_MEM_BALLOON 1350
178
#define NETDATA_CHART_PRIO_MEM_NUMA 1400
179
#define NETDATA_CHART_PRIO_MEM_NUMA_NODES_NUMASTAT 1410
src/collectors/debugfs.plugin/debugfs_plugin.c
+8
-2
@@ -45,6 +45,12 @@ static struct debugfs_module {
45
.enabled = CONFIG_BOOLEAN_YES,
46
.func = do_module_libsensors
47
},
48
+ {
49
+ // Linux audit subsystem status via netlink
50
+ .name = "audit",
51
+ .enabled = CONFIG_BOOLEAN_YES,
52
+ .func = do_module_audit
53
+ },
54
55
// The terminator
56
{.name = NULL, .enabled = CONFIG_BOOLEAN_NO, .func = NULL}
@@ -207,8 +213,8 @@ int main(int argc, char **argv)
213
#ifdef HAVE_CAPABILITY
214
netdata_log_error(
215
"debugfs.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities. "
210
- "Without these, debugfs.plugin cannot access /sys/kernel/debug. "
211
- "To enable capabilities run: sudo setcap cap_dac_read_search,cap_sys_ptrace+ep %s; "
216
+ "cap_dac_read_search is needed for /sys/kernel/debug access, cap_audit_control for audit subsystem monitoring. "
217
+ "To enable capabilities run: sudo setcap cap_dac_read_search,cap_audit_control+ep %s; "
218
"To enable setuid to root run: sudo chown root:netdata %s; sudo chmod 4750 %s; ",
219
uid,
220
euid,
src/collectors/debugfs.plugin/debugfs_plugin.h
+1
@@ -15,6 +15,7 @@ int do_module_numa_extfrag(int update_every, const char *name);
15
int do_module_zswap(int update_every, const char *name);
16
int do_module_devices_powercap(int update_every, const char *name);
17
int do_module_libsensors(int update_every, const char *name);
18
+int do_module_audit(int update_every, const char *name);
19
20
void module_libsensors_cleanup(void);
21
src/collectors/debugfs.plugin/metadata.yaml
+143
@@ -390,3 +390,146 @@ modules:
390
- name: dram
391
- name: core
392
- name: uncore
393
+ - meta:
394
+ plugin_name: debugfs.plugin
395
+ module_name: audit
396
+ monitored_instance:
397
+ name: Linux Audit Subsystem
398
+ link: 'https://man7.org/linux/man-pages/man8/auditd.8.html'
399
+ categories:
400
+ - data-collection.operating-systems
401
+ icon_filename: 'linux.svg'
402
+ related_resources:
403
+ integrations:
404
+ list: []
405
+ info_provided_to_referring_integrations:
406
+ description: ''
407
+ keywords:
408
+ - audit
409
+ - auditd
410
+ - backlog
411
+ - security
412
+ - kernel panic
413
+ - compliance
414
+ overview:
415
+ data_collection:
416
+ metrics_description: >
417
+ Monitors Linux kernel audit subsystem status via NETLINK_AUDIT.
418
+ Tracks audit backlog depth, backlog utilization, lost events,
419
+ and configuration (failure mode, enabled state).
420
+ Critical for detecting audit backlog overflow conditions that
421
+ cause kernel panics when failure mode is set to 2 (panic).
422
+ method_description: 'Query kernel audit status via NETLINK_AUDIT socket (AUDIT_GET)'
423
+ supported_platforms:
424
+ include:
425
+ - Linux
426
+ exclude: []
427
+ multi_instance: false
428
+ additional_permissions:
429
+ description: >
430
+ This integration requires root privileges or CAP_AUDIT_CONTROL capability
431
+ to query the kernel audit subsystem via netlink. The Netdata installer
432
+ grants this capability to debugfs.plugin automatically. The module
433
+ detects missing privileges and disables itself gracefully.
434
+ default_behavior:
435
+ auto_detection:
436
+ description: >
437
+ Automatically detects and monitors the Linux audit subsystem when
438
+ the kernel supports NETLINK_AUDIT. Gracefully disables itself if
439
+ audit is not available.
440
+ limits:
441
+ description: ''
442
+ performance_impact:
443
+ description: >
444
+ Minimal. Performs a single netlink query per collection cycle.
445
+ No file I/O, no process forking.
446
+ setup:
447
+ prerequisites:
448
+ list:
449
+ - title: 'Linux kernel with audit support'
450
+ description: >
451
+ The Linux kernel must have audit support enabled (CONFIG_AUDIT=y).
452
+ Most distribution kernels include this by default.
453
+ configuration:
454
+ file:
455
+ name: 'netdata.conf'
456
+ section_name: '[plugin:debugfs]'
457
+ description: 'This is netdata main configuration file.'
458
+ options:
459
+ description: ''
460
+ folding:
461
+ title: 'Config options'
462
+ enabled: true
463
+ list:
464
+ - name: update every
465
+ description: Data collection frequency.
466
+ default_value: 1
467
+ required: false
468
+ examples:
469
+ folding:
470
+ enabled: true
471
+ title: ''
472
+ list: []
473
+ troubleshooting:
474
+ problems:
475
+ list: []
476
+ alerts:
477
+ - name: audit_backlog_utilization
478
+ link: https://github.com/netdata/netdata/blob/master/src/health/health.d/audit.conf
479
+ metric: audit.backlog_utilization
480
+ info: >
481
+ Linux audit backlog utilization has exceeded the warning threshold
482
+ while failure mode is set to panic. Kernel panic is imminent if
483
+ backlog overflows.
484
+ - name: audit_lost_events
485
+ link: https://github.com/netdata/netdata/blob/master/src/health/health.d/audit.conf
486
+ metric: audit.lost
487
+ info: >
488
+ Linux audit subsystem is losing events (backlog overflow, rate
489
+ limiting, or memory pressure).
490
+ metrics:
491
+ folding:
492
+ title: Metrics
493
+ enabled: false
494
+ description: "Monitor the Linux kernel audit subsystem status and backlog health."
495
+ availability: []
496
+ scopes:
497
+ - name: global
498
+ description: "Audit subsystem status for the entire system."
499
+ labels: []
500
+ metrics:
501
+ - name: audit.backlog
502
+ description: Audit Backlog
503
+ unit: "events"
504
+ chart_type: stacked
505
+ dimensions:
506
+ - name: used
507
+ - name: free
508
+ - name: audit.backlog_utilization
509
+ description: Audit Backlog Utilization
510
+ unit: "%"
511
+ chart_type: area
512
+ dimensions:
513
+ - name: utilization
514
+ - name: audit.lost
515
+ description: Audit Lost Events
516
+ unit: "events/s"
517
+ chart_type: area
518
+ dimensions:
519
+ - name: lost
520
+ - name: audit.enabled
521
+ description: Audit Enabled State
522
+ unit: "state"
523
+ chart_type: line
524
+ dimensions:
525
+ - name: disabled
526
+ - name: enabled
527
+ - name: immutable
528
+ - name: audit.failure
529
+ description: Audit Failure Mode
530
+ unit: "state"
531
+ chart_type: line
532
+ dimensions:
533
+ - name: silent
534
+ - name: printk
535
+ - name: panic
src/collectors/debugfs.plugin/module-audit.c
new
+277
@@ -0,0 +1,277 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+// Linux audit subsystem status collector.
4
+// Queries the kernel audit status via NETLINK_AUDIT socket (AUDIT_GET)
5
+// and exposes backlog depth, lost events, configuration, and failure mode.
6
+
7
+#include "debugfs_plugin.h"
8
+
9
+#include <linux/audit.h>
10
+#include <linux/netlink.h>
11
+#include <sys/socket.h>
12
+#include <sys/time.h>
13
+#include <string.h>
14
+#include <unistd.h>
15
+#include <errno.h>
16
+
17
+#define AUDIT_STATUS_MIN_PAYLOAD 32 // 8 fields (mask through backlog) = 32 bytes
18
+#define AUDIT_RECV_TIMEOUT_MS 500 // netlink receive timeout in milliseconds
19
+#define AUDIT_RECV_MAX_ATTEMPTS 5 // max recvfrom attempts per query
20
+#define AUDIT_STARTUP_RETRIES 3 // startup failures before permanent disable
21
+
22
+// -----------------------------------------------------------------------
23
+// netlink audit query
24
+
25
+struct audit_reply {
26
+ int valid; // whether the query succeeded
27
+ uint32_t enabled; // 0=disabled, 1=enabled, 2=immutable
28
+ uint32_t failure; // 0=silent, 1=printk, 2=panic
29
+ uint32_t pid; // audit daemon pid (0=no daemon)
30
+ uint32_t rate_limit; // max events/s (0=unlimited)
31
+ uint32_t backlog_limit;
32
+ uint32_t lost; // cumulative lost events
33
+ uint32_t backlog; // current queue depth
34
+};
35
+
36
+// query the kernel audit status via netlink
37
+// returns 0 on success, -1 on failure
38
+static int audit_netlink_query(struct audit_reply *reply) {
39
+ memset(reply, 0, sizeof(*reply));
40
+
41
+ int fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_AUDIT);
42
+ if (fd < 0)
43
+ return -1;
44
+
45
+ // bind to the netlink socket (nl_pid=0 lets kernel auto-assign a unique port ID)
46
+ struct sockaddr_nl addr = {
47
+ .nl_family = AF_NETLINK,
48
+ .nl_pid = 0,
49
+ .nl_groups = 0,
50
+ };
51
+ if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
52
+ close(fd);
53
+ return -1;
54
+ }
55
+
56
+ // send AUDIT_GET request
57
+ struct {
58
+ struct nlmsghdr nlh;
59
+ struct audit_status s;
60
+ } req = {
61
+ .nlh = {
62
+ .nlmsg_len = NLMSG_LENGTH(sizeof(struct audit_status)),
63
+ .nlmsg_type = AUDIT_GET,
64
+ .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
65
+ .nlmsg_seq = 1,
66
+ .nlmsg_pid = 0,
67
+ },
68
+ .s = { 0 },
69
+ };
70
+
71
+ // send to kernel (nl_pid=0)
72
+ struct sockaddr_nl kernel_addr = {
73
+ .nl_family = AF_NETLINK,
74
+ .nl_pid = 0,
75
+ .nl_groups = 0,
76
+ };
77
+ if (sendto(fd, &req, req.nlh.nlmsg_len, 0,
78
+ (struct sockaddr *)&kernel_addr, sizeof(kernel_addr)) < 0) {
79
+ close(fd);
80
+ return -1;
81
+ }
82
+
83
+ // receive response
84
+ char buf[8192];
85
+
86
+ // set a timeout to avoid blocking the plugin's collection loop
87
+ struct timeval tv = { .tv_sec = 0, .tv_usec = AUDIT_RECV_TIMEOUT_MS * 1000 };
88
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
89
+ close(fd);
90
+ return -1;
91
+ }
92
+
93
+ for (int attempts = 0; attempts < AUDIT_RECV_MAX_ATTEMPTS; attempts++) {
94
+ struct sockaddr_nl from;
95
+ socklen_t fromlen = sizeof(from);
96
+
97
+ ssize_t len = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&from, &fromlen);
98
+ if (len < 0) {
99
+ if (errno == EINTR)
100
+ continue;
101
+ close(fd);
102
+ return -1;
103
+ }
104
+
105
+ // only accept messages from the kernel
106
+ if (from.nl_pid != 0)
107
+ continue;
108
+
109
+ // iterate all messages in the received buffer
110
+ int msg_len = (int)len;
111
+ for (struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
112
+ NLMSG_OK(nlh, msg_len);
113
+ nlh = NLMSG_NEXT(nlh, msg_len)) {
114
+
115
+ if (nlh->nlmsg_type == AUDIT_GET) {
116
+ if (nlh->nlmsg_len < NLMSG_LENGTH(AUDIT_STATUS_MIN_PAYLOAD))
117
+ continue;
118
+
119
+ struct audit_status *s = NLMSG_DATA(nlh);
120
+ reply->valid = 1;
121
+ reply->enabled = s->enabled;
122
+ reply->failure = s->failure;
123
+ reply->pid = s->pid;
124
+ reply->rate_limit = s->rate_limit;
125
+ reply->backlog_limit = s->backlog_limit;
126
+ reply->lost = s->lost;
127
+ reply->backlog = s->backlog;
128
+ close(fd);
129
+ return 0;
130
+ }
131
+
132
+ if (nlh->nlmsg_type == NLMSG_ERROR) {
133
+ if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
134
+ continue;
135
+ struct nlmsgerr *err = NLMSG_DATA(nlh);
136
+ if (err->error == 0)
137
+ continue; // ACK, keep looking for AUDIT_GET
138
+ close(fd);
139
+ return -1;
140
+ }
141
+ }
142
+ }
143
+
144
+ close(fd);
145
+ return -1;
146
+}
147
+
148
+// -----------------------------------------------------------------------
149
+// charts
150
+
151
+static int charts_created = 0;
152
+
153
+static void audit_send_charts(int update_every, const char *name) {
154
+ if (charts_created)
155
+ return;
156
+
157
+ charts_created = 1;
158
+
159
+ netdata_mutex_lock(&stdout_mutex);
160
+
161
+ // chart: audit backlog (stacked: used + free = backlog_limit)
162
+ printf(PLUGINSD_KEYWORD_CHART
163
+ " audit.backlog '' 'Audit Backlog' 'events' 'audit' 'audit.backlog' %s %d %d '' 'debugfs.plugin' '%s'\n",
164
+ debugfs_rrdset_type_name(RRDSET_TYPE_STACKED), NETDATA_CHART_PRIO_AUDIT_BACKLOG, update_every, name);
165
+ printf(PLUGINSD_KEYWORD_DIMENSION " 'used' 'used' %s 1 1 ''\n",
166
+ RRD_ALGORITHM_ABSOLUTE_NAME);
167
+ printf(PLUGINSD_KEYWORD_DIMENSION " 'free' 'free' %s 1 1 'hidden'\n",
168
+ RRD_ALGORITHM_ABSOLUTE_NAME);
169
+
170
+ // chart: audit backlog utilization (percentage)
171
+ printf(PLUGINSD_KEYWORD_CHART
172
+ " audit.backlog_utilization '' 'Audit Backlog Utilization' '%%' 'audit' 'audit.backlog_utilization' %s %d %d '' 'debugfs.plugin' '%s'\n",
173
+ debugfs_rrdset_type_name(RRDSET_TYPE_AREA), NETDATA_CHART_PRIO_AUDIT_BACKLOG_UTIL, update_every, name);
174
+ printf(PLUGINSD_KEYWORD_DIMENSION " 'utilization' 'utilization' %s 1 100 ''\n",
175
+ RRD_ALGORITHM_ABSOLUTE_NAME);
176
+
177
+ // chart: audit lost events
178
+ printf(PLUGINSD_KEYWORD_CHART
179
+ " audit.lost '' 'Audit Lost Events' 'events/s' 'audit' 'audit.lost' %s %d %d '' 'debugfs.plugin' '%s'\n",
180
+ debugfs_rrdset_type_name(RRDSET_TYPE_AREA), NETDATA_CHART_PRIO_AUDIT_LOST, update_every, name);
181
+ printf(PLUGINSD_KEYWORD_DIMENSION " 'lost' 'lost' %s 1 1 ''\n",
182
+ RRD_ALGORITHM_INCREMENTAL_NAME);
183
+
184
+ // chart: audit enabled state (exactly one dimension is 1 at any time)
185
+ printf(PLUGINSD_KEYWORD_CHART
186
+ " audit.enabled '' 'Audit Enabled State' 'state' 'audit' 'audit.enabled' %s %d %d '' 'debugfs.plugin' '%s'\n",
187
+ debugfs_rrdset_type_name(RRDSET_TYPE_LINE), NETDATA_CHART_PRIO_AUDIT_ENABLED, update_every, name);
188
+ printf(PLUGINSD_KEYWORD_DIMENSION " 'disabled' 'disabled' %s 1 1 ''\n",
189
+ RRD_ALGORITHM_ABSOLUTE_NAME);
190
+ printf(PLUGINSD_KEYWORD_DIMENSION " 'enabled' 'enabled' %s 1 1 ''\n",
191
+ RRD_ALGORITHM_ABSOLUTE_NAME);
192
+ printf(PLUGINSD_KEYWORD_DIMENSION " 'immutable' 'immutable' %s 1 1 ''\n",
193
+ RRD_ALGORITHM_ABSOLUTE_NAME);
194
+
195
+ // chart: audit failure mode (exactly one dimension is 1 at any time)
196
+ printf(PLUGINSD_KEYWORD_CHART
197
+ " audit.failure '' 'Audit Failure Mode' 'state' 'audit' 'audit.failure' %s %d %d '' 'debugfs.plugin' '%s'\n",
198
+ debugfs_rrdset_type_name(RRDSET_TYPE_LINE), NETDATA_CHART_PRIO_AUDIT_FAILURE, update_every, name);
199
+ printf(PLUGINSD_KEYWORD_DIMENSION " 'silent' 'silent' %s 1 1 ''\n",
200
+ RRD_ALGORITHM_ABSOLUTE_NAME);
201
+ printf(PLUGINSD_KEYWORD_DIMENSION " 'printk' 'printk' %s 1 1 ''\n",
202
+ RRD_ALGORITHM_ABSOLUTE_NAME);
203
+ printf(PLUGINSD_KEYWORD_DIMENSION " 'panic' 'panic' %s 1 1 ''\n",
204
+ RRD_ALGORITHM_ABSOLUTE_NAME);
205
+
206
+ fflush(stdout);
207
+ netdata_mutex_unlock(&stdout_mutex);
208
+}
209
+
210
+static void audit_send_data(struct audit_reply *r) {
211
+ netdata_mutex_lock(&stdout_mutex);
212
+
213
+ // backlog (stacked: used + free = backlog_limit)
214
+ uint32_t free_backlog = (r->backlog_limit > r->backlog) ? r->backlog_limit - r->backlog : 0;
215
+ printf(PLUGINSD_KEYWORD_BEGIN " audit.backlog\n");
216
+ printf(PLUGINSD_KEYWORD_SET " used = %u\n", r->backlog);
217
+ printf(PLUGINSD_KEYWORD_SET " free = %u\n", free_backlog);
218
+ printf(PLUGINSD_KEYWORD_END "\n");
219
+
220
+ // backlog utilization (percentage)
221
+ collected_number utilization = 0;
222
+ if (r->backlog_limit > 0)
223
+ utilization = (collected_number)r->backlog * 10000 / (collected_number)r->backlog_limit;
224
+ printf(PLUGINSD_KEYWORD_BEGIN " audit.backlog_utilization\n");
225
+ printf(PLUGINSD_KEYWORD_SET " utilization = %lld\n", utilization);
226
+ printf(PLUGINSD_KEYWORD_END "\n");
227
+
228
+ // lost events (incremental)
229
+ printf(PLUGINSD_KEYWORD_BEGIN " audit.lost\n");
230
+ printf(PLUGINSD_KEYWORD_SET " lost = %u\n", r->lost);
231
+ printf(PLUGINSD_KEYWORD_END "\n");
232
+
233
+ // enabled state
234
+ printf(PLUGINSD_KEYWORD_BEGIN " audit.enabled\n");
235
+ printf(PLUGINSD_KEYWORD_SET " disabled = %d\n", r->enabled == 0 ? 1 : 0);
236
+ printf(PLUGINSD_KEYWORD_SET " enabled = %d\n", r->enabled == 1 ? 1 : 0);
237
+ printf(PLUGINSD_KEYWORD_SET " immutable = %d\n", r->enabled == 2 ? 1 : 0);
238
+ printf(PLUGINSD_KEYWORD_END "\n");
239
+
240
+ // failure mode
241
+ printf(PLUGINSD_KEYWORD_BEGIN " audit.failure\n");
242
+ printf(PLUGINSD_KEYWORD_SET " silent = %d\n", r->failure == 0 ? 1 : 0);
243
+ printf(PLUGINSD_KEYWORD_SET " printk = %d\n", r->failure == 1 ? 1 : 0);
244
+ printf(PLUGINSD_KEYWORD_SET " panic = %d\n", r->failure == 2 ? 1 : 0);
245
+ printf(PLUGINSD_KEYWORD_END "\n");
246
+
247
+ fflush(stdout);
248
+ netdata_mutex_unlock(&stdout_mutex);
249
+}
250
+
251
+// -----------------------------------------------------------------------
252
+// module entry point
253
+
254
+int do_module_audit(int update_every, const char *name) {
255
+ static int startup_retries = AUDIT_STARTUP_RETRIES;
256
+
257
+ struct audit_reply reply;
258
+ if (audit_netlink_query(&reply) < 0 || !reply.valid) {
259
+ if (startup_retries > 0) {
260
+ startup_retries--;
261
+ if (startup_retries == 0) {
262
+ netdata_log_info("audit: netlink AUDIT_GET query failed, audit module disabled");
263
+ return 1; // permanently disable after exhausting retries
264
+ }
265
+ return 0; // retry next cycle
266
+ }
267
+ return 0; // transient failure after startup, keep module enabled
268
+ }
269
+
270
+ // mark startup as successful
271
+ startup_retries = 0;
272
+
273
+ audit_send_charts(update_every, name);
274
+ audit_send_data(&reply);
275
+
276
+ return 0;
277
+}
src/health/health.d/audit.conf
new
+40
@@ -0,0 +1,40 @@
1
+# Alerts for the Linux audit subsystem.
2
+# Monitors audit backlog utilization relative to failure mode,
3
+# and detects audit event loss.
4
+
5
+# Alert when audit backlog is filling up AND failure mode is panic (2).
6
+# This combination means the system will kernel panic if the backlog overflows.
7
+# Only fires when failure=2 (panic mode) — for other failure modes,
8
+# audit_lost_events covers actual event loss.
9
+
10
+ template: audit_backlog_utilization
11
+ on: audit.backlog_utilization
12
+ class: Utilization
13
+ type: System
14
+component: Audit
15
+ lookup: max -1m unaligned of utilization
16
+ units: %
17
+ every: 10s
18
+ warn: $this > 50 AND $audit.failure.panic == 1
19
+ crit: $this > 80 AND $audit.failure.panic == 1
20
+ delay: down 5m multiplier 1.5 max 1h
21
+ summary: Audit backlog utilization (kernel panic risk)
22
+ info: Linux audit backlog is filling up while failure mode is set to panic — kernel panic is imminent if backlog overflows
23
+ to: sysadmin
24
+
25
+# Alert when audit events are being lost (dropped).
26
+# This indicates the audit subsystem cannot keep up with event volume.
27
+
28
+ template: audit_lost_events
29
+ on: audit.lost
30
+ class: Errors
31
+ type: System
32
+component: Audit
33
+ lookup: max -1m unaligned of lost
34
+ units: events/s
35
+ every: 10s
36
+ warn: $this > 0
37
+ delay: down 5m multiplier 1.5 max 1h
38
+ summary: Audit subsystem losing events
39
+ info: Linux audit subsystem is losing events (backlog overflow, rate limiting, or memory pressure)
40
+ to: sysadmin