77
88#include "maps.bpf.h"
99
10+ struct {
11+ __uint (type , BPF_MAP_TYPE_PROG_ARRAY );
12+ __type (key , u32 );
13+ __type (value , u32 );
14+ __uint (max_entries , 2 );
15+ } ka_ea_process_jmp_map SEC (".maps" );
16+
1017struct {
1118 __uint (type , BPF_MAP_TYPE_HASH );
1219 __type (key , struct pattern_key );
@@ -28,121 +35,169 @@ struct {
2835 __uint (max_entries , 1 << 10 );
2936} ka_ea_process_filter_map SEC (".maps" );
3037
31- // get_task_context fills *tctx with task and event data;
32- // with latter only if it's not NULL
33- static __always_inline
34- long get_task_context (struct task_context * tctx ,
35- const struct trace_event_raw_sched_process_exec * ectx )
38+ unsigned int pid ;
39+ unsigned int tid ;
40+ unsigned int pid_ns ;
41+ unsigned int mnt_ns ;
42+ char comm [TASK_COMM_LEN ];
43+ char filename [MAX_FILENAME_LEN ];
44+ u32 pattern_id ;
45+
46+ // get_task_filename fills global variable (.bss map) with task filename
47+ static
48+ long get_task_filename (const struct trace_event_raw_sched_process_exec * ctx )
3649{
37- if (!tctx )
38- return -1 ;
50+ long ret ;
51+
52+ ret = bpf_core_read_str (filename , sizeof (filename ),
53+ get_dynamic_array (ctx , filename ));
54+ if (ret < 0 )
55+ return ret ;
56+
57+ return 0 ;
58+ }
3959
60+ // get_task_ids fills global variables (.bss map) with task ids
61+ static
62+ long get_task_ids (const struct trace_event_raw_sched_process_exec * ctx )
63+ {
4064 long ret ;
4165
42- ret = bpf_get_current_comm (& tctx -> comm , sizeof (tctx -> comm ));
66+ ret = bpf_get_current_comm (comm , sizeof (comm ));
4367 if (ret < 0 )
4468 return ret ;
4569
46- struct task_struct * task ;
4770 u64 id ;
4871
49- task = (struct task_struct * ) bpf_get_current_task ();
50- tctx -> pid_ns = BPF_CORE_READ (task , nsproxy , pid_ns_for_children , ns ).inum ;
51- tctx -> mnt_ns = BPF_CORE_READ (task , nsproxy , mnt_ns , ns ).inum ;
5272 id = bpf_get_current_pid_tgid ();
53- tctx -> pid = id >> 32 ;
54- tctx -> tid = (u32 ) id ;
73+ pid = id >> 32 ;
74+ tid = (u32 ) id ;
5575
56- if (!ectx )
57- return 0 ;
58- ret = bpf_core_read_str (& tctx -> filename , sizeof (tctx -> filename ),
59- get_dynamic_array (ectx , filename ));
60- if (ret < 0 )
61- return ret ;
76+ struct task_struct * task ;
77+
78+ task = (struct task_struct * ) bpf_get_current_task ();
79+ pid_ns = BPF_CORE_READ (task , nsproxy , pid_ns_for_children , ns ).inum ;
80+ mnt_ns = BPF_CORE_READ (task , nsproxy , mnt_ns , ns ).inum ;
6281
6382 return 0 ;
6483}
6584
66- // basename returns pointer from a filename basename if filename is a path,
67- // otherwise returns filename pointer
68- static __always_inline
69- const char * basename (const char * filename )
85+ // match was inspired by the Krauss and Kurts wildcard algorithms
86+ // https://github.com/kirkjkrauss/MatchingWildcards/blob/master/Listing1.cpp
87+ // http://dodobyte.com/wildcard.html
88+ static
89+ bool match (const char * pat , const char * str )
7090{
71- if (!filename )
72- return NULL ;
73-
74- const char * base = filename ;
75-
76- // we should iterate up to i < MAX_FILENAME_LEN,
77- // but increasing loop iterations results in "BPF program is too large"
78- for (int i = 0 ; i < 32 ; i ++ ) {
79- if (!filename [i ])
80- break ;
81- if (filename [i ] == '/' )
82- base = filename + i ;
91+ int i = 0 ;
92+ int j = 0 ;
93+ int str_track = -1 ;
94+ int pat_track = -1 ;
95+
96+ while (j < MAX_PATTERN_LEN ) {
97+ // this check makes verifier happy
98+ if (i >= MAX_FILENAME_LEN )
99+ return false;
100+ if (!pat [j ] && !str [i ])
101+ return true;
102+
103+ if (pat [j ] == '*' ) {
104+ if (!str [i ]) {
105+ while (j < MAX_PATTERN_LEN - 1 && pat [j ] == '*' )
106+ j ++ ;
107+ return !pat [j ];
108+ }
109+ str_track = i ;
110+ pat_track = j ;
111+ j ++ ;
112+ continue ;
113+ }
114+
115+ if (pat [j ] != '?' && pat [j ] != str [i ]) {
116+ if (pat_track == -1 )
117+ return false;
118+ str_track ++ ;
119+ i = str_track ;
120+ j = pat_track ;
121+ continue ;
122+ }
123+
124+ i ++ ;
125+ j ++ ;
83126 }
84127
85- if (base == filename )
86- return filename ;
128+ return false;
129+ }
130+
131+ // callback_ctx struct is used as check_hash_elem handler input/output
132+ struct callback_ctx {
133+ const char * filename ;
134+ struct pattern_value * pvalue ;
135+ };
136+
137+ // check_hash_elem is the handler required by bpf_for_each_map_elem iterator
138+ static
139+ u64 check_hash_elem (struct bpf_map * map ,
140+ struct pattern_key * key , struct pattern_value * val ,
141+ struct callback_ctx * data )
142+ {
143+ if (!key || !val || !data )
144+ return 0 ;
87145
88- base ++ ;
89- if (!* base )
90- return filename ;
146+ if (match (key -> pattern , data -> filename )) {
147+ data -> pvalue -> pattern_id = val -> pattern_id ;
148+ return 1 ; // stop the iteration
149+ }
91150
92- return base ;
151+ return 0 ;
93152}
94153
95- // task_auditable checks if task must be audited
96- static __always_inline
97- bool task_auditable ( const struct task_context * tctx )
154+ // task_auditable checks if task must be audited (phase 0)
155+ static
156+ bool task_auditable_0 ( void )
98157{
99- if (!tctx )
100- return false;
101-
102- struct pattern_value * pvalue ;
158+ struct pattern_value pvalue = {
159+ .pattern_id = 0 ,
160+ };
161+ struct callback_ctx data = {
162+ .filename = (const char * ) & filename ,
163+ .pvalue = & pvalue ,
164+ };
103165
104- // we are just checking if a plain process filename (base) is auditable,
105- // disregarding globs
106- pvalue = bpf_map_lookup_elem ( & ka_ea_pattern_map , basename ( tctx -> filename ) );
107- if (! pvalue )
166+ // https://lwn.net/Articles/846504/
167+ long elem_num = bpf_for_each_map_elem ( & ka_ea_pattern_map ,
168+ check_hash_elem , & data , 0 );
169+ if (elem_num < 0 || ! data . pvalue -> pattern_id )
108170 return false;
109171
110- struct process_spec_key pskey = {
111- .pid_ns = tctx -> pid_ns ,
112- .mnt_ns = tctx -> mnt_ns ,
113- .pattern_id = pvalue -> pattern_id ,
114- };
172+ pattern_id = data .pvalue -> pattern_id ;
115173
116- return !! bpf_map_lookup_elem ( & ka_ea_process_spec_map , & pskey ) ;
174+ return true ;
117175}
118176
119- // task_audited checks if task is being audited
120- static __always_inline
121- bool task_audited (const struct task_context * tctx )
177+ // task_auditable checks if task must be audited (phase 1)
178+ static
179+ bool task_auditable_1 (const struct trace_event_raw_sched_process_exec * ctx )
122180{
123- if (! tctx )
181+ if (get_task_ids ( ctx ) < 0 )
124182 return false;
125183
126- struct process_filter_key pfkey = {
127- .pid_ns = tctx -> pid_ns ,
128- .mnt_ns = tctx -> mnt_ns ,
129- .host_pid = tctx -> pid ,
184+ struct process_spec_key pskey = {
185+ .pid_ns = pid_ns ,
186+ .mnt_ns = mnt_ns ,
187+ .pattern_id = pattern_id ,
130188 };
131189
132- return !!bpf_map_lookup_elem (& ka_ea_process_filter_map , & pfkey );
190+ return !!bpf_map_lookup_elem (& ka_ea_process_spec_map , & pskey );
133191}
134192
135193// set_task_for_audit set task for audit updating process filter map
136- static __always_inline
137- long set_task_for_audit (const struct task_context * tctx )
194+ static
195+ long set_task_for_audit (void )
138196{
139- if (!tctx )
140- return 0 ;
141-
142197 struct process_filter_key pfkey = {
143- .pid_ns = tctx -> pid_ns ,
144- .mnt_ns = tctx -> mnt_ns ,
145- .host_pid = tctx -> pid ,
198+ .pid_ns = pid_ns ,
199+ .mnt_ns = mnt_ns ,
200+ .host_pid = pid ,
146201 };
147202
148203 struct process_filter_value pfvalue = {
@@ -152,60 +207,68 @@ long set_task_for_audit(const struct task_context *tctx)
152207 return bpf_map_update_elem (& ka_ea_process_filter_map , & pfkey , & pfvalue , BPF_ANY );
153208}
154209
155- // unset_task_for_audit unset task for audit deleting from process filter map
156- static __always_inline
157- long unset_task_for_audit (const struct task_context * tctx )
210+ SEC ("tp/sched/sched_process_exec/1" )
211+ int ka_ea_sched_process_exec_1 (struct trace_event_raw_sched_process_exec * ctx )
158212{
159- if (!tctx )
213+ if (!task_auditable_1 ( ctx ) )
160214 return 0 ;
161215
162- struct process_filter_key pfkey = {
163- .pid_ns = tctx -> pid_ns ,
164- .mnt_ns = tctx -> mnt_ns ,
165- .host_pid = tctx -> pid ,
166- };
216+ if (set_task_for_audit () < 0 )
217+ bpf_printk ("[ka-ea-process]: failure setting %s for audit" , filename );
218+ else
219+ bpf_printk ("[ka-ea-process]: %s set for audit" , filename );
167220
168- return bpf_map_delete_elem ( & ka_ea_process_filter_map , & pfkey ) ;
221+ return 0 ;
169222}
170223
171- SEC ("tp/sched/sched_process_exec" )
172- int ka_ea_sched_process_exec (struct trace_event_raw_sched_process_exec * ectx )
224+ SEC ("tp/sched/sched_process_exec/0 " )
225+ int ka_ea_sched_process_exec_0 (struct trace_event_raw_sched_process_exec * ctx )
173226{
174- struct task_context tctx = {};
175-
176- if (get_task_context (& tctx , ectx ) < 0 )
227+ if (!task_auditable_0 ())
177228 return 0 ;
178229
179- if (!task_auditable (& tctx ))
230+ bpf_tail_call (ctx , & ka_ea_process_jmp_map , 1 );
231+
232+ return 0 ;
233+ }
234+
235+ SEC ("tp/sched/sched_process_exec" )
236+ int ka_ea_sched_process_exec (struct trace_event_raw_sched_process_exec * ctx )
237+ {
238+ if (get_task_filename (ctx ) < 0 )
180239 return 0 ;
181240
182- if ( set_task_for_audit ( & tctx ) < 0 )
183- bpf_printk ( "[ka-ea]: failure setting for audit" );
184- else
185- bpf_printk ( "[ka-ea]: set for audit" );
241+ // don't access the value returned from bpf_tail_call( )
242+ // although the doc states that it is negative in case of an error,
243+ // one can get 'R0 !read_ok' when the call is successful
244+ bpf_tail_call ( ctx , & ka_ea_process_jmp_map , 0 );
186245
187246 return 0 ;
188247}
189248
190249SEC ("tp/sched/sched_process_exit" )
191- int ka_ea_sched_process_exit (struct trace_event_raw_sched_process_template * ectx )
250+ int ka_ea_sched_process_exit (struct trace_event_raw_sched_process_template * ctx )
192251{
193- struct task_context tctx = {};
194-
195- if (get_task_context (& tctx , NULL ) < 0 )
252+ if (get_task_ids (NULL ) < 0 )
196253 return 0 ;
197254
198255 // disregard threads
199- if (tctx . pid != tctx . tid )
256+ if (pid != tid )
200257 return 0 ;
201258
202- if (!task_audited (& tctx ))
259+ struct process_filter_key pfkey = {
260+ .pid_ns = pid_ns ,
261+ .mnt_ns = mnt_ns ,
262+ .host_pid = pid ,
263+ };
264+
265+ if (!bpf_map_lookup_elem (& ka_ea_process_filter_map , & pfkey ))
203266 return 0 ;
204267
205- if (unset_task_for_audit ( & tctx ) < 0 )
206- bpf_printk ("[ka-ea]: failure unsetting for audit" );
268+ if (bpf_map_delete_elem ( & ka_ea_process_filter_map , & pfkey ) < 0 )
269+ bpf_printk ("[ka-ea-process ]: failure unsetting %u for audit" , pid );
207270 else
208- bpf_printk ("[ka-ea]: unset for audit" );
271+ bpf_printk ("[ka-ea-process ]: %u unset for audit" , pid );
209272
210273 return 0 ;
211274}
0 commit comments