diff --git a/services/ja4ebpf/bpf/bpf_types.h b/services/ja4ebpf/bpf/bpf_types.h index 0136f45..e6822b7 100644 --- a/services/ja4ebpf/bpf/bpf_types.h +++ b/services/ja4ebpf/bpf/bpf_types.h @@ -320,7 +320,7 @@ struct { __uint(max_entries, 16); __type(key, __u32); __type(value, __u8); -} apache_pid_map SEC(".maps"); +} apache_http_pid_map SEC(".maps"); /* Hash map : pid_tgid → read_args (arguments read entry pour Apache) */ struct { @@ -328,7 +328,7 @@ struct { __uint(max_entries, 10240); __type(key, __u64); __type(value, struct read_args); -} apache_read_args_map SEC(".maps"); +} apache_http_recv_args_map SEC(".maps"); /* PERCPU_ARRAY temporaire pour apache_http_event (taille ~4KB) */ struct { diff --git a/services/ja4ebpf/bpf/uprobe_apache.c b/services/ja4ebpf/bpf/uprobe_apache.c index 05cf610..6e18ec2 100644 --- a/services/ja4ebpf/bpf/uprobe_apache.c +++ b/services/ja4ebpf/bpf/uprobe_apache.c @@ -1,8 +1,7 @@ -/* uprobe_apache.c — Tracepoints syscall pour capturer le trafic HTTP depuis Apache httpd +/* uprobe_apache.c — Kretprobe pour capturer le trafic HTTP depuis Apache httpd * - * Cette version utilise kretprobe sur __x64_sys_recvfrom pour capturer les appels - * système recvfrom() du serveur Apache httpd (identique à nginx). - * Le filtrage par PID Apache permet de capturer uniquement le trafic HTTP du serveur. + * Cette version utilise kretprobe sur __x64_sys_recvfrom (identique à nginx) + * pour capturer les appels système recvfrom() du serveur Apache httpd. * * ============================================================================ */ @@ -19,8 +18,7 @@ * kretprobe_sys_exit_recvfrom — Sortie du syscall recvfrom * * Capture les données reçues et les envoie vers pb_apache_http. - * Signature: ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, - * struct sockaddr *src_addr, socklen_t *addrlen); + * Utilise kretprobe pour contourner les limitations de tracepoint exit. * ============================================================================ */ SEC("kretprobe/__x64_sys_recvfrom") @@ -29,17 +27,18 @@ int kretprobe_sys_exit_recvfrom(struct pt_regs *ctx) __u64 pid_tgid = bpf_get_current_pid_tgid(); __u32 pid = pid_tgid >> 32; - /* Vérifier si ce PID est dans la map apache_pid_map */ + /* Vérifier si ce PID est dans la map apache_http_pid_map */ __u32 pid_key = pid; - __u8 *enabled = bpf_map_lookup_elem(&apache_pid_map, &pid_key); + __u8 *enabled = bpf_map_lookup_elem(&apache_http_pid_map, &pid_key); if (!enabled || *enabled == 0) { return 0; /* Pas un PID Apache, ignore */ } /* Obtenir la valeur de retour (nombre d'octets reçus) */ long retval = PT_REGS_RC(ctx); - if (retval <= 0 || retval > MAX_RECV_SIZE) { - return 0; /* Erreur, EOF, ou trop de données */ + if (retval < 0 || retval > MAX_RECV_SIZE) { + /* Erreur ou trop de données */ + return 0; } /* Préparer l'événement Apache HTTP */ @@ -50,8 +49,8 @@ int kretprobe_sys_exit_recvfrom(struct pt_regs *ctx) /* Initialiser l'événement */ e->pid_tgid = pid_tgid; - e->fd = 0; /* sockfd n'est pas disponible en kretprobe sans arguments sauvegardés */ - e->src_ip = 0; /* Sera rempli via corrélation TC si disponible */ + e->fd = 0; + e->src_ip = 0; e->src_port = 0; e->timestamp_ns = bpf_ktime_get_ns(); e->method_len = 0; @@ -60,18 +59,17 @@ int kretprobe_sys_exit_recvfrom(struct pt_regs *ctx) e->body_len = 0; e->data_len = 0; - /* Copier les données brutes depuis la stack (recvfrom buffer) - * Note: Comme nous n'avons pas sauvegardé les arguments à l'entrée, - * nous ne pouvons pas accéder au buffer utilisateur directement. - * Pour Apache, nous utilisons une approche simplifiée qui capture - * les données depuis le contexte BPF disponible. - */ - if (retval > 0 && retval < sizeof(e->data)) { - /* Lire depuis le premier argument de la stack (buf pointer) - * Sur x86_64, les arguments sont dans: RDI=sockfd, RSI=buf, RDX=len, R10=flags - */ - __u64 buf_ptr = PT_REGS_PARM2(ctx); - __u64 bytes_read = bpf_probe_read_user_str(e->data, sizeof(e->data), (void *)buf_ptr); + /* Copier les données depuis le buffer utilisateur (2ème argument: RSI) */ + __u64 buf_ptr = PT_REGS_PARM2(ctx); + + /* Limiter la copie à retval octets */ + __u64 copy_size = retval; + if (copy_size > sizeof(e->data)) { + copy_size = sizeof(e->data); + } + + if (copy_size > 0) { + __u64 bytes_read = bpf_probe_read_user_str(e->data, copy_size, (void *)buf_ptr); if (bytes_read > 0) { e->data_len = bytes_read; /* Envoyer vers l'espace utilisateur via perf buffer */ diff --git a/services/ja4ebpf/internal/loader/loader.go b/services/ja4ebpf/internal/loader/loader.go index 53394e3..2dd5629 100644 --- a/services/ja4ebpf/internal/loader/loader.go +++ b/services/ja4ebpf/internal/loader/loader.go @@ -307,7 +307,7 @@ func New() (*Loader, error) { allowedPorts: tcObjs.AllowedPorts, ignoredSrc: tcObjs.IgnoredSrc, nginxPidMap: nginxObjs.NginxPidMap, - apachePidMap: apacheObjs.ApachePidMap, + apachePidMap: apacheObjs.ApacheHttpPidMap, SynReader: synReader, TLSReader: tlsReader, SSLReader: sslReader, @@ -539,8 +539,8 @@ func findNginxPIDs() ([]uint32, error) { // kernel sys_enter_read et kretprobe __x64_sys_read. // Le PID Apache est ajouté à la map apache_pid_map pour filtrer les appels read(). func (l *Loader) AttachUprobesApache() error { - // Utilisation de Kretprobe pour __x64_sys_recvfrom - // Apache httpd utilise recvfrom() pour lire les requêtes HTTP (similaire à nginx) + // Utilisation de Kretprobe pour __x64_sys_recvfrom (identique à nginx) + // Apache httpd utilise recvfrom() pour lire les requêtes HTTP kp, err := link.Kretprobe("__x64_sys_recvfrom", l.apacheObjs.KretprobeSysExitRecvfrom, &link.KprobeOptions{}) if err != nil {