@cryptotaxi247 / netdata-1 / commits / b64ef1636

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