3636#include <errno.h>
3737
3838#include "attr-lookup-metrics.h"
39+ #include "decision-context.h"
3940#include "event.h"
4041#include "database.h"
4142#include "decision-timing.h"
6162 (SUBJECT_BUILDING_STALE_MS * NSEC_PER_MSEC)
6263#define SUBJECT_BUILDING_LOG_INTERVAL 60
6364
64- static Queue * subj_cache = NULL ;
65- static Queue * obj_cache = NULL ;
66- static bool obj_cache_warned = false;
67- static unsigned int early_subj_cache_evictions = 0 ;
68- static unsigned int building_tracer_evictions = 0 ;
69- static unsigned int building_stale_evictions = 0 ;
70- static struct message_rate_limit building_tracer_log =
71- MESSAGE_RATE_LIMIT_INIT (SUBJECT_BUILDING_LOG_INTERVAL );
72- static struct message_rate_limit building_stale_log =
73- MESSAGE_RATE_LIMIT_INIT (SUBJECT_BUILDING_LOG_INTERVAL );
65+ static struct decision_context default_decision_context = {
66+ .building_tracer_rate_limit =
67+ MESSAGE_RATE_LIMIT_INIT (SUBJECT_BUILDING_LOG_INTERVAL ),
68+ .building_stale_rate_limit =
69+ MESSAGE_RATE_LIMIT_INIT (SUBJECT_BUILDING_LOG_INTERVAL ),
70+ };
71+ static struct decision_context * current_decision_context =
72+ & default_decision_context ;
73+
74+ #define subj_cache (current_decision_context->subject_cache)
75+ #define obj_cache (current_decision_context->object_cache)
76+ #define obj_cache_warned (current_decision_context->object_cache_warned)
77+ #define early_subj_cache_evictions \
78+ (current_decision_context->early_subject_cache_evictions)
79+ #define building_tracer_evictions \
80+ (current_decision_context->building_tracer_evict_count)
81+ #define building_stale_evictions \
82+ (current_decision_context->building_stale_evict_count)
83+ #define building_tracer_log \
84+ (current_decision_context->building_tracer_rate_limit)
85+ #define building_stale_log \
86+ (current_decision_context->building_stale_rate_limit)
7487
7588atomic_bool needs_flush = false;
7689
@@ -88,6 +101,68 @@ struct building_evict_context {
88101 unsigned int event_count ;
89102};
90103
104+ /*
105+ * decision_context_current - return active mutable decision state.
106+ *
107+ * A default empty context is available before the daemon initializes the real
108+ * caches so policy-only tests can still use the logging buffer.
109+ */
110+ struct decision_context * decision_context_current (void )
111+ {
112+ return current_decision_context ;
113+ }
114+
115+ /*
116+ * decision_context_set_current - publish the active decision context.
117+ * @ctx: context to use, or NULL to restore the default empty context.
118+ * Returns nothing.
119+ */
120+ void decision_context_set_current (struct decision_context * ctx )
121+ {
122+ if (ctx == NULL )
123+ current_decision_context = & default_decision_context ;
124+ else
125+ current_decision_context = ctx ;
126+ }
127+
128+ /*
129+ * decision_context_init_rate_limits - initialize per-context log throttles.
130+ * @ctx: context to initialize.
131+ * Returns nothing.
132+ */
133+ static void decision_context_init_rate_limits (struct decision_context * ctx )
134+ {
135+ atomic_init (& ctx -> building_tracer_rate_limit .last_log , 0 );
136+ ctx -> building_tracer_rate_limit .interval =
137+ SUBJECT_BUILDING_LOG_INTERVAL ;
138+ atomic_init (& ctx -> building_stale_rate_limit .last_log , 0 );
139+ ctx -> building_stale_rate_limit .interval = SUBJECT_BUILDING_LOG_INTERVAL ;
140+ }
141+
142+ /*
143+ * decision_context_init_policy_counters - initialize policy metric counters.
144+ * @counters: policy counter block to initialize.
145+ * Returns nothing.
146+ */
147+ static void decision_context_init_policy_counters (
148+ struct decision_policy_counters * counters )
149+ {
150+ atomic_init (& counters -> allowed , 0 );
151+ atomic_init (& counters -> denied , 0 );
152+ atomic_init (& counters -> allowed_by_rule , 0 );
153+ atomic_init (& counters -> allowed_by_fallthrough , 0 );
154+ atomic_init (& counters -> fallthrough_open , 0 );
155+ atomic_init (& counters -> fallthrough_execute , 0 );
156+ atomic_init (& counters -> fallthrough_trusted , 0 );
157+ atomic_init (& counters -> fallthrough_untrusted , 0 );
158+ atomic_init (& counters -> fallthrough_trust_unknown , 0 );
159+ atomic_init (& counters -> fallthrough_executable , 0 );
160+ atomic_init (& counters -> fallthrough_programmatic , 0 );
161+ atomic_init (& counters -> fallthrough_sharedlib , 0 );
162+ atomic_init (& counters -> fallthrough_unknown_ftype , 0 );
163+ atomic_init (& counters -> fallthrough_other_ftype , 0 );
164+ }
165+
91166/*
92167 * event_now_ns - read monotonic time for BUILDING age checks.
93168 *
@@ -302,27 +377,47 @@ static void obj_evict_warn(void *unused)
302377// Return 0 on success and 1 on error
303378int init_event_system (const conf_t * config )
304379{
380+ struct decision_context * ctx ;
381+
382+ ctx = calloc (1 , sizeof (* ctx ));
383+ if (ctx == NULL )
384+ return 1 ;
385+ decision_context_init_rate_limits (ctx );
386+ decision_context_init_policy_counters (& ctx -> policy_counters );
387+
305388 /*
306389 * Attach subject_evict_warn so we can see when fast PID turnover
307390 * drops a subject before classification completes. Without all the
308391 * paths collected ld.so can report spurious access denials. A larger
309392 * subj_cache_size lengthens the window and avoids this condition.
310393 */
311- subj_cache = init_lru (config -> subj_cache_size ,
394+ ctx -> subject_cache = init_lru (config -> subj_cache_size ,
312395 (void (* )(void * ))subject_clear , "Subject" ,
313396 (void (* )(void * ))subject_evict_warn );
314- if (!subj_cache )
397+ if (!ctx -> subject_cache ) {
398+ free (ctx );
315399 return 1 ;
400+ }
316401
317- obj_cache = init_lru (config -> obj_cache_size ,
402+ ctx -> object_cache = init_lru (config -> obj_cache_size ,
318403 (void (* )(void * ))object_clear , "Object" ,
319404 obj_evict_warn );
320- if (!obj_cache ) {
321- destroy_lru (subj_cache );
322- subj_cache = NULL ;
405+ if (!ctx -> object_cache ) {
406+ destroy_lru (ctx -> subject_cache );
407+ free ( ctx ) ;
323408 return 1 ;
324409 }
325410
411+ if (decision_defer_init (& ctx -> defer_queue , config -> subj_cache_size )) {
412+ destroy_lru (ctx -> subject_cache );
413+ destroy_lru (ctx -> object_cache );
414+ free (ctx );
415+ return 1 ;
416+ }
417+ decision_defer_metrics_snapshot_reset (& ctx -> defer_queue ,
418+ & ctx -> last_defer_metrics , 0 );
419+
420+ decision_context_set_current (ctx );
326421 return 0 ;
327422}
328423
@@ -350,23 +445,31 @@ static int flush_cache(void)
350445
351446void destroy_event_system (void )
352447{
448+ struct decision_context * ctx = current_decision_context ;
449+
450+ if (ctx == & default_decision_context )
451+ return ;
452+
353453 /* We're intentionally clearing the caches; disable warnings */
354- if (subj_cache )
355- subj_cache -> evict_cb = NULL ;
356- if (early_subj_cache_evictions )
454+ if (ctx -> subject_cache )
455+ ctx -> subject_cache -> evict_cb = NULL ;
456+ if (ctx -> early_subject_cache_evictions )
357457 msg (LOG_WARNING ,
358458 "Processes are being evicted from the subject cache before "
359459 "pattern detection completes: increase subj_cache_size "
360- "(total early evictions: %u)" , early_subj_cache_evictions );
361- if (obj_cache )
362- obj_cache -> evict_cb = NULL ;
363- if (obj_cache_warned )
460+ "(total early evictions: %u)" ,
461+ ctx -> early_subject_cache_evictions );
462+ if (ctx -> object_cache )
463+ ctx -> object_cache -> evict_cb = NULL ;
464+ if (ctx -> object_cache_warned )
364465 msg (LOG_WARNING ,
365466 "object cache eviction ratios high: increase obj_cache_size" );
366- destroy_lru (subj_cache );
367- destroy_lru (obj_cache );
368- subj_cache = NULL ;
369- obj_cache = NULL ;
467+ destroy_lru (ctx -> subject_cache );
468+ destroy_lru (ctx -> object_cache );
469+ decision_defer_destroy (& ctx -> defer_queue );
470+ free (ctx -> working_buffer );
471+ decision_context_set_current (NULL );
472+ free (ctx );
370473}
371474
372475static inline void reset_subject_attributes (s_array * s )
0 commit comments