@@ -97,12 +97,15 @@ impl EbpfLoader {
9797 if _bytes. is_empty ( ) {
9898 return Err ( LoadError :: LoadFailed ( "Empty program bytes" . to_string ( ) ) ) ;
9999 }
100-
101- // TODO: Implement actual loading when eBPF programs are ready
102- // For now, this is a stub that will be implemented in TASK-004
100+
101+ let bpf = aya:: Bpf :: load ( _bytes)
102+ . map_err ( |e| LoadError :: LoadFailed ( e. to_string ( ) ) ) ?;
103+ self . bpf = Some ( bpf) ;
104+
105+ log:: info!( "eBPF program loaded ({} bytes)" , _bytes. len( ) ) ;
103106 Ok ( ( ) )
104107 }
105-
108+
106109 #[ cfg( not( all( target_os = "linux" , feature = "ebpf" ) ) ) ]
107110 {
108111 Err ( LoadError :: NotLinux )
@@ -132,23 +135,80 @@ impl EbpfLoader {
132135 pub fn attach_program ( & mut self , _program_name : & str ) -> Result < ( ) , LoadError > {
133136 #[ cfg( all( target_os = "linux" , feature = "ebpf" ) ) ]
134137 {
135- // TODO: Implement actual attachment
136- // For now, just mark as attached
138+ let ( category, tp_name) = program_to_tracepoint ( _program_name)
139+ . ok_or_else ( || LoadError :: ProgramNotFound (
140+ format ! ( "No tracepoint mapping for '{}'" , _program_name)
141+ ) ) ?;
142+
143+ let bpf = self . bpf . as_mut ( )
144+ . ok_or_else ( || LoadError :: LoadFailed (
145+ "No eBPF program loaded; call load_program_from_bytes first" . to_string ( )
146+ ) ) ?;
147+
148+ let prog: & mut aya:: programs:: TracePoint = bpf
149+ . program_mut ( _program_name)
150+ . ok_or_else ( || LoadError :: ProgramNotFound ( _program_name. to_string ( ) ) ) ?
151+ . try_into ( )
152+ . map_err ( |e : aya:: programs:: ProgramError | LoadError :: AttachFailed ( e. to_string ( ) ) ) ?;
153+
154+ prog. load ( )
155+ . map_err ( |e| LoadError :: AttachFailed ( format ! ( "load '{}': {}" , _program_name, e) ) ) ?;
156+
157+ prog. attach ( category, tp_name)
158+ . map_err ( |e| LoadError :: AttachFailed (
159+ format ! ( "attach '{}/{}': {}" , category, tp_name, e)
160+ ) ) ?;
161+
137162 self . loaded_programs . insert (
138163 _program_name. to_string ( ) ,
139- ProgramInfo {
140- name : _program_name. to_string ( ) ,
141- attached : true ,
142- } ,
164+ ProgramInfo { name : _program_name. to_string ( ) , attached : true } ,
143165 ) ;
166+
167+ log:: info!( "eBPF program '{}' attached to {}/{}" , _program_name, category, tp_name) ;
144168 Ok ( ( ) )
145169 }
146-
170+
171+ #[ cfg( not( all( target_os = "linux" , feature = "ebpf" ) ) ) ]
172+ {
173+ Err ( LoadError :: NotLinux )
174+ }
175+ }
176+
177+ /// Attach all known syscall tracepoint programs
178+ pub fn attach_all_programs ( & mut self ) -> Result < ( ) , LoadError > {
179+ #[ cfg( all( target_os = "linux" , feature = "ebpf" ) ) ]
180+ {
181+ for name in & [ "trace_execve" , "trace_connect" , "trace_openat" , "trace_ptrace" ] {
182+ if let Err ( e) = self . attach_program ( name) {
183+ log:: warn!( "Failed to attach '{}': {}" , name, e) ;
184+ }
185+ }
186+ Ok ( ( ) )
187+ }
188+
147189 #[ cfg( not( all( target_os = "linux" , feature = "ebpf" ) ) ) ]
148190 {
149191 Err ( LoadError :: NotLinux )
150192 }
151193 }
194+
195+ /// Extract the EVENTS ring buffer map from the loaded eBPF program.
196+ /// Must be called after load_program_from_bytes and before the Bpf object is dropped.
197+ #[ cfg( all( target_os = "linux" , feature = "ebpf" ) ) ]
198+ pub fn take_ring_buf ( & mut self ) -> Result < aya:: maps:: RingBuf < aya:: maps:: MapData > , LoadError > {
199+ let bpf = self . bpf . as_mut ( )
200+ . ok_or_else ( || LoadError :: LoadFailed (
201+ "No eBPF program loaded" . to_string ( )
202+ ) ) ?;
203+
204+ let map = bpf. take_map ( "EVENTS" )
205+ . ok_or_else ( || LoadError :: LoadFailed (
206+ "EVENTS ring buffer map not found in eBPF program" . to_string ( )
207+ ) ) ?;
208+
209+ aya:: maps:: RingBuf :: try_from ( map)
210+ . map_err ( |e| LoadError :: LoadFailed ( format ! ( "Failed to create ring buffer: {}" , e) ) )
211+ }
152212
153213 /// Detach a program
154214 pub fn detach_program ( & mut self , program_name : & str ) -> Result < ( ) , LoadError > {
@@ -201,8 +261,24 @@ impl EbpfLoader {
201261}
202262
203263impl Default for EbpfLoader {
204- fn default ( ) -> Result < Self , LoadError > {
205- Self :: new ( )
264+ fn default ( ) -> Self {
265+ Self {
266+ #[ cfg( all( target_os = "linux" , feature = "ebpf" ) ) ]
267+ bpf : None ,
268+ loaded_programs : HashMap :: new ( ) ,
269+ kernel_version : None ,
270+ }
271+ }
272+ }
273+
274+ /// Map program name to its tracepoint (category, name) for aya attachment.
275+ fn program_to_tracepoint ( name : & str ) -> Option < ( & ' static str , & ' static str ) > {
276+ match name {
277+ "trace_execve" => Some ( ( "syscalls" , "sys_enter_execve" ) ) ,
278+ "trace_connect" => Some ( ( "syscalls" , "sys_enter_connect" ) ) ,
279+ "trace_openat" => Some ( ( "syscalls" , "sys_enter_openat" ) ) ,
280+ "trace_ptrace" => Some ( ( "syscalls" , "sys_enter_ptrace" ) ) ,
281+ _ => None ,
206282 }
207283}
208284
0 commit comments