Ilk eBPF Programi ve Tracepoint'ler
Reading event data
Önceki alıştırmada, “Kim çalışıyor?” sorusunu sormak için bir helper kullandık.
Şimdi tracepoint’e sunulan verileri sorgulayarak çalışan process hakkında soruları yanıtlayalım.
sched_process_exec için kernel, Process ID (PID) ve filename gibi özel event verileri içeren bir structure sağlar.
Kernel’in sağladığı context’in formatını herhangi bir Linux bilgisayarında şu komutu çalıştırarak bulabilirsiniz:
$ cat /sys/kernel/tracing/events/sched/sched_process_exec/format
format:
unsigned short common_type; offset:0; size:2;
unsigned char common_flags; offset:2; size:1;
unsigned char common_preempt_count; offset:3; size:1;
int common_pid; offset:4; size:4;
__data_loc char[] filename; offset:8; size:4;
pid_t pid; offset:12; size:4;
pid_t old_pid; offset:16; size:4;
Alternatif olarak, tanımı görmek için editörde trace_event_raw_sched_process_exec üzerine Ctrl+Click yapın.
Görev
Çalıştırılan programın PID ve filename bilgilerini doğrudan event verisinden çıkartın.
PID’yi almak bu durumda basit, doğrudan okuyabiliriz:
int pid = ctx->pid;
DEBUG_NUM("PID", pid);
Ancak filename’i okumak daha fazla işlem gerektirir. Yukarıdaki tip bildiriminde gördüğünüz gibi,
tipi __data_loc char[] şeklindedir.
Bu normal bir pointer değildir; __data_loc ön eki, alanın string’in kendisini değil, string’in kodlanmış konumunu içerdiğini belirtir.
Temel olarak, filename alanı iki bilgiyi paketleyen 32-bit bir integer içerir:
- Alt 16 bit: Offset (String’in structure’ın başından ne kadar uzakta olduğu)
- Üst 16 bit: Length (String’in ne kadar uzun olduğu)
Gerçek string’e ulaşmak için konumunu çözümlememiz gerekiyor:
__data_loc_filenamealanını okuyun- Offset’i elde etmek için alt 16 bit’i maskeleyin (
val & 0xFFFF) - Length’i elde etmek için üst bit’leri sağa kaydırın (
val >> 16) - Bu offset’i
ctxpointer’ına ekleyin
Ancak hesaplanan adresten veriyi doğrudan okuyamayız:
char* fname = (void *)ctx + off;
DEBUG_STR("Filename", fname);
Neden?
Giriş bölümünde gördüğümüz gibi, eBPF programları bir sandbox içinde çalışır. Bunun gibi hesaplanan adresler (ctx + off), kernel memory’ye işaret eder (programın stack’ine değil).
DEBUG_STR’yi yerel olmayan bir adresle çağırdığımızda, kernel helper’ları o bellek aralığını okumayı reddeder ve “DEBUG” belleği başlatılmamış olarak kalır.
Yine de deneyebilirsiniz! Kernel’ı çökertmez, bunun yerine şu şekilde bir şey döndürür: �����.
Bunu çözmek için, bpf_probe_read_kernel_str helper’ını kullanarak o veriyi “yerel bellek” (stack) alanına kopyalamamız gerekir.
char fname[32];
bpf_probe_read_kernel_str(fname, sizeof(fname), (void *)ctx + off);
Bundan sonra fname buffer’ı doldurulmuş olacak ve üzerinde DEBUG_STR çağırabilirsiniz.
Göreviniz
Yukarıda açıklandığı gibi DEBUG_STR/DEBUG_NUM eklediyseniz, birden fazla standart program göreceksiniz, ancak bir tanesi dikkat çekiyor. Göndermek için SUBMIT_STR_LEN(buff, len) kullanın.
Compare two strings for equality
- Args:
char* bufdynamic buffer to compareu32 buf_szlength of dynamic bufferconst char* buf2literal string to compare against