/* uprobe_apache.c — Capture HTTP depuis Apache httpd via apr_socket_recv * * Utilise uprobe sur la fonction apr_socket_recv d'Apache Portable Runtime * pour capturer les données HTTP lues depuis le socket. * * Cette approche fonctionne sur tous les kernels car elle utilise des * uprobes au lieu de dépendre de syscalls. * * ============================================================================ */ #include "vmlinux.h" #include #include #include "bpf_types.h" /* Structure pour stocker les arguments entre entry et return */ struct apr_socket_recv_args { __u64 buf_ptr; /* pointeur vers le buffer de réception */ __u32 len; /* longueur demandée */ }; /* Map temporaire pour stocker les arguments entre entry et return */ struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 10240); __type(key, __u64); __type(value, struct apr_socket_recv_args); } apr_socket_recv_args_map SEC(".maps"); /* ============================================================================ * uprobe_apr_socket_recv_entry — Entrée de la fonction apr_socket_recv * * Signature: apr_status_t apr_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len) * * Capture le pointeur vers le buffer qui recevra les données. * ============================================================================ */ SEC("uprobe/apr_socket_recv") int uprobe_apr_socket_recv_entry(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_http_pid_map */ __u8 *enabled = bpf_map_lookup_elem(&apache_http_pid_map, &pid); if (!enabled || *enabled == 0) { return 0; } /* Récupérer les arguments depuis pt_regs (x86_64) * rdi = sock, rsi = buf, rdx = len */ struct apr_socket_recv_args args = {}; args.buf_ptr = PT_REGS_PARM2(ctx); /* deuxième paramètre = buf */ /* Le troisième paramètre est un pointeur vers size_t, * on doit lire la valeur pointée pour obtenir la longueur */ __u64 len_ptr = PT_REGS_PARM3(ctx); __u32 len_value = 0; bpf_probe_read_user(&len_value, sizeof(len_value), (void *)len_ptr); args.len = len_value; if (args.buf_ptr && args.len > 0) { bpf_map_update_elem(&apr_socket_recv_args_map, &pid_tgid, &args, BPF_ANY); } return 0; } /* ============================================================================ * uretprobe_apr_socket_recv — Sortie de la fonction apr_socket_recv * * La valeur de retour indique le succès, et le pointeur len a été mis à jour * avec le nombre d'octets réellement lus. * ============================================================================ */ SEC("uretprobe/apr_socket_recv") int uretprobe_apr_socket_recv(struct pt_regs *ctx) { __u64 pid_tgid = bpf_get_current_pid_tgid(); __u32 pid = pid_tgid >> 32; __u8 *enabled = bpf_map_lookup_elem(&apache_http_pid_map, &pid); if (!enabled || *enabled == 0) { return 0; } struct apr_socket_recv_args *args = bpf_map_lookup_elem(&apr_socket_recv_args_map, &pid_tgid); if (!args) { return 0; } /* La valeur de retour est apr_status_t (0 = succès) */ long retval = PT_REGS_RC(ctx); /* APR_SUCCESS est 0, toute autre valeur indique une erreur */ if (retval != 0) { bpf_map_delete_elem(&apr_socket_recv_args_map, &pid_tgid); return 0; } /* Buffer pour l'événement */ __u32 zero = 0; struct apache_http_event *e = bpf_map_lookup_elem(&__apache_buf, &zero); if (!e) { bpf_map_delete_elem(&apr_socket_recv_args_map, &pid_tgid); return 0; } /* Initialiser l'événement */ e->pid_tgid = pid_tgid; e->fd = 0; e->src_ip = 0; e->src_port = 0; e->timestamp_ns = bpf_ktime_get_ns(); e->method_len = 0; e->uri_len = 0; e->query_len = 0; e->body_len = 0; e->data_len = 0; /* Lire les données depuis le buffer utilisateur */ __u32 data_len = args->len; __u64 buf_ptr = args->buf_ptr; /* Vérifier que data_len est dans des limites raisonnables */ if (data_len > 0 && data_len <= 4096 && buf_ptr != 0) { /* Limiter la lecture pour éviter les accès hors limites */ __u32 copy_len = data_len; if (copy_len > sizeof(e->data)) { copy_len = sizeof(e->data); } bpf_probe_read_user(e->data, copy_len, (void *)buf_ptr); e->data_len = copy_len; } /* Envoyer vers userspace */ bpf_perf_event_output(ctx, &pb_apache_http, BPF_F_CURRENT_CPU, e, sizeof(*e)); bpf_map_delete_elem(&apr_socket_recv_args_map, &pid_tgid); return 0; } char LICENSE[] SEC("license") = "GPL";