Skip to content

Commit 3fb4cd5

Browse files
committed
auditd: make TLS ACL reload transactional
SIGHUP reconfiguration updated tls_allowed_clients in the active config before the replacement ACL had been parsed and validated. A bad reload could therefore leave auditd reporting the new ACL path while continuing to use the previous in-memory ACL, and removing tls_allowed_clients could clear the only active PSK authorization source without rebuilding the live TLS context. Load replacement ACLs into a temporary table and only publish the new path and table together after validation succeeds. Failed reloads and single-PSK ACL cardinality errors now keep the old live ACL, and ACL removal is rejected when the live PSK listener has no tls_psk_identity fallback. The new path string is freed when it is not published so the existing reconfigure ownership model does not leak it. Add listener reconfiguration coverage to format_event_test for invalid ACL replacement, ACL-only removal on a live PSK listener, and successful ACL removal when a fallback identity is active.
1 parent 2957f07 commit 3fb4cd5

3 files changed

Lines changed: 343 additions & 47 deletions

File tree

src/auditd-listen.c

Lines changed: 185 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,113 @@ static struct ev_tcp *handshake_chain = NULL;
119119
static unsigned int handshake_count = 0;
120120
#define MAX_HANDSHAKE_PENDING 32
121121
static struct autls_acl_table *acl_table = NULL;
122+
static unsigned char *server_psk_key = NULL;
123+
static size_t server_psk_key_len = 0;
124+
static char *expected_psk_identity = NULL;
122125
static int ssl_ex_idx_identity = -1;
123126
static int ssl_ex_idx_reason = -1;
124127
#endif
125128

129+
#if defined(HAVE_TLS) && defined(AUDITD_LISTEN_TEST)
130+
/*
131+
* auditd_tls_test_set_transport - set listener transport for unit tests
132+
* @value: transport value to install
133+
*
134+
* Returns: None.
135+
*/
136+
void auditd_tls_test_set_transport(int value)
137+
{
138+
transport = value;
139+
}
140+
141+
/*
142+
* auditd_tls_test_set_acl_table - install a test ACL table
143+
* @table: ACL table to install; ownership transfers to the listener
144+
*
145+
* Returns: None.
146+
*/
147+
void auditd_tls_test_set_acl_table(struct autls_acl_table *table)
148+
{
149+
autls_acl_free(acl_table);
150+
acl_table = table;
151+
}
152+
153+
/*
154+
* auditd_tls_test_acl_check - check a test identity against live ACL state
155+
* @identity: identity string to check
156+
*
157+
* Returns: autls_acl_check() result, or -2 when no ACL is installed.
158+
*/
159+
int auditd_tls_test_acl_check(const char *identity)
160+
{
161+
if (acl_table == NULL)
162+
return -2;
163+
return autls_acl_check(acl_table, (const unsigned char *)identity,
164+
strlen(identity));
165+
}
166+
167+
/*
168+
* auditd_tls_test_set_psk_state - install minimal live PSK state for tests
169+
* @active: non-zero to install a PSK marker
170+
* @identity: optional fallback PSK identity
171+
*
172+
* Returns: 0 on success, -1 on allocation failure.
173+
*/
174+
int auditd_tls_test_set_psk_state(int active, const char *identity)
175+
{
176+
if (server_psk_key) {
177+
OPENSSL_cleanse(server_psk_key, server_psk_key_len);
178+
OPENSSL_free(server_psk_key);
179+
}
180+
server_psk_key = NULL;
181+
server_psk_key_len = 0;
182+
free(expected_psk_identity);
183+
expected_psk_identity = NULL;
184+
185+
if (active) {
186+
server_psk_key = OPENSSL_malloc(1);
187+
if (server_psk_key == NULL)
188+
return -1;
189+
server_psk_key[0] = 0;
190+
server_psk_key_len = 1;
191+
}
192+
if (identity) {
193+
expected_psk_identity = strdup(identity);
194+
if (expected_psk_identity == NULL) {
195+
if (server_psk_key) {
196+
OPENSSL_cleanse(server_psk_key,
197+
server_psk_key_len);
198+
OPENSSL_free(server_psk_key);
199+
}
200+
server_psk_key = NULL;
201+
server_psk_key_len = 0;
202+
return -1;
203+
}
204+
}
205+
return 0;
206+
}
207+
208+
/*
209+
* auditd_tls_test_clear - clear listener TLS state used by unit tests
210+
*
211+
* Returns: None.
212+
*/
213+
void auditd_tls_test_clear(void)
214+
{
215+
transport = T_TCP;
216+
autls_acl_free(acl_table);
217+
acl_table = NULL;
218+
if (server_psk_key) {
219+
OPENSSL_cleanse(server_psk_key, server_psk_key_len);
220+
OPENSSL_free(server_psk_key);
221+
}
222+
server_psk_key = NULL;
223+
server_psk_key_len = 0;
224+
free(expected_psk_identity);
225+
expected_psk_identity = NULL;
226+
}
227+
#endif
228+
126229
/*
127230
* sockaddr_to_string_buf - format an address into a caller buffer
128231
* @addr: socket address
@@ -1765,11 +1868,6 @@ static void periodic_handler(struct ev_loop *loop, struct ev_periodic *per,
17651868
}
17661869

17671870
#ifdef HAVE_TLS
1768-
static unsigned char *server_psk_key = NULL;
1769-
static size_t server_psk_key_len = 0;
1770-
1771-
static char *expected_psk_identity = NULL;
1772-
17731871
/* Store a failure reason in SSL ex-data for audit records */
17741872
static void set_psk_failure_reason(SSL *ssl, const char *reason)
17751873
{
@@ -2386,6 +2484,87 @@ static void periodic_reconfigure(const struct daemon_conf *config)
23862484
}
23872485
}
23882486

2487+
#ifdef HAVE_TLS
2488+
/*
2489+
* reload_tls_client_acl - reload live TLS PSK client authorization
2490+
* @nconf: newly parsed daemon configuration
2491+
* @oconf: active daemon configuration
2492+
*
2493+
* Returns: None.
2494+
*
2495+
* SIGHUP must not partially publish authorization state. Parse and
2496+
* validate the new ACL into temporary storage first, then replace the
2497+
* live path and table together only after all checks pass. If the ACL
2498+
* is the only active PSK authorization source, removing it would make
2499+
* connection attempts fail closed and could create an avoidable denial
2500+
* of service, so keep the old ACL until restart or a replacement ACL.
2501+
*/
2502+
static void reload_tls_client_acl(const struct daemon_conf *nconf,
2503+
struct daemon_conf *oconf)
2504+
{
2505+
struct autls_acl_table *new_acl = NULL;
2506+
int old_enabled;
2507+
2508+
if (!USE_TLS) {
2509+
free((void *)oconf->tls_allowed_clients);
2510+
oconf->tls_allowed_clients = nconf->tls_allowed_clients;
2511+
return;
2512+
}
2513+
2514+
if (nconf->tls_allowed_clients == NULL) {
2515+
if (oconf->tls_allowed_clients == NULL)
2516+
return;
2517+
2518+
if (server_psk_key && expected_psk_identity == NULL) {
2519+
audit_msg(LOG_ERR,
2520+
"tls_allowed_clients removal ignored; "
2521+
"live TLS PSK listener has no "
2522+
"tls_psk_identity fallback");
2523+
return;
2524+
}
2525+
2526+
free((void *)oconf->tls_allowed_clients);
2527+
oconf->tls_allowed_clients = NULL;
2528+
if (acl_table) {
2529+
audit_msg(LOG_NOTICE,
2530+
"tls_allowed_clients removed; "
2531+
"clearing ACL");
2532+
autls_acl_free(acl_table);
2533+
acl_table = NULL;
2534+
}
2535+
return;
2536+
}
2537+
2538+
if (autls_acl_load(nconf->tls_allowed_clients, &new_acl,
2539+
audit_msg) != 0) {
2540+
audit_msg(LOG_ERR,
2541+
"Failed to reload TLS client ACL; "
2542+
"keeping current ACL");
2543+
free((void *)nconf->tls_allowed_clients);
2544+
return;
2545+
}
2546+
2547+
if (server_psk_key && new_acl->enabled_count > 1) {
2548+
audit_msg(LOG_ERR,
2549+
"Reloaded ACL has %d enabled identities but "
2550+
"single-PSK mode allows at most 1; "
2551+
"keeping current ACL", new_acl->enabled_count);
2552+
autls_acl_free(new_acl);
2553+
free((void *)nconf->tls_allowed_clients);
2554+
return;
2555+
}
2556+
2557+
old_enabled = acl_table ? acl_table->enabled_count : 0;
2558+
autls_acl_free(acl_table);
2559+
acl_table = new_acl;
2560+
free((void *)oconf->tls_allowed_clients);
2561+
oconf->tls_allowed_clients = nconf->tls_allowed_clients;
2562+
audit_msg(LOG_NOTICE,
2563+
"TLS client ACL reloaded (%d->%d enabled)",
2564+
old_enabled, new_acl->enabled_count);
2565+
}
2566+
#endif
2567+
23892568
void auditd_tcp_listen_reconfigure(const struct daemon_conf *nconf,
23902569
struct daemon_conf *oconf)
23912570
{
@@ -2472,6 +2651,7 @@ void auditd_tcp_listen_reconfigure(const struct daemon_conf *nconf,
24722651
audit_msg(LOG_NOTICE,
24732652
"TLS context not reloaded; restart auditd "
24742653
"to apply cert/key/PSK config changes");
2654+
reload_tls_client_acl(nconf, oconf);
24752655
free((void *)oconf->tls_cert_file);
24762656
oconf->tls_cert_file = nconf->tls_cert_file;
24772657
free((void *)oconf->tls_key_file);
@@ -2489,46 +2669,5 @@ void auditd_tcp_listen_reconfigure(const struct daemon_conf *nconf,
24892669
/* Integer fields that must match the live SSL_CTX are NOT
24902670
* updated here — they only change on restart when
24912671
* init_tls_server_context rebuilds the context. */
2492-
free((void *)oconf->tls_allowed_clients);
2493-
oconf->tls_allowed_clients = nconf->tls_allowed_clients;
2494-
2495-
/* Reload ACL table on SIGHUP — independent of SSL_CTX */
2496-
if (USE_TLS && oconf->tls_allowed_clients) {
2497-
struct autls_acl_table *new_acl = NULL;
2498-
if (autls_acl_load(oconf->tls_allowed_clients,
2499-
&new_acl, audit_msg) == 0) {
2500-
if (server_psk_key &&
2501-
new_acl->enabled_count > 1) {
2502-
audit_msg(LOG_ERR,
2503-
"Reloaded ACL has %d enabled "
2504-
"identities but single-PSK "
2505-
"mode allows at most 1; "
2506-
"keeping current ACL",
2507-
new_acl->enabled_count);
2508-
autls_acl_free(new_acl);
2509-
} else {
2510-
int old_enabled = acl_table ?
2511-
acl_table->enabled_count : 0;
2512-
autls_acl_free(acl_table);
2513-
acl_table = new_acl;
2514-
audit_msg(LOG_NOTICE,
2515-
"TLS client ACL reloaded "
2516-
"(%d->%d enabled)",
2517-
old_enabled,
2518-
new_acl->enabled_count);
2519-
}
2520-
} else {
2521-
audit_msg(LOG_ERR,
2522-
"Failed to reload TLS client ACL; "
2523-
"keeping current ACL");
2524-
}
2525-
} else if (USE_TLS && !oconf->tls_allowed_clients
2526-
&& acl_table) {
2527-
audit_msg(LOG_NOTICE,
2528-
"tls_allowed_clients removed; "
2529-
"clearing ACL");
2530-
autls_acl_free(acl_table);
2531-
acl_table = NULL;
2532-
}
25332672
#endif
25342673
}

src/test/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ format_event_test_SOURCES += \
5454
if ENABLE_TLS
5555
format_event_test_CFLAGS += -I${top_srcdir}/autls $(OPENSSL_CFLAGS)
5656
format_event_test_CFLAGS += -DAUDITD_EXE=\"$(sbindir)/auditd\"
57+
format_event_test_CFLAGS += -DAUDITD_LISTEN_TEST
5758
format_event_test_LDADD += ${top_builddir}/autls/libautls.la
5859
endif
5960
endif

0 commit comments

Comments
 (0)