From 5e3b4c497c54e9d31517b1873cca745ad8b86bfd Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 23 Sep 2025 16:46:41 +0200 Subject: [PATCH] Refactor handover context cleanup and fix memory leak in N2 handover source gNB path - Add missing handover context cleanup in rrc_CU_process_ue_context_release_complete - Fix 16-byte handover context leak in N2 handover source gNB trigger path AddressSanitizer backtrace: Direct leak of 16 byte(s) in 1 object(s) allocated from: /#0 0x7fee67cb4a57 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154 /#1 0x58059e33454b in calloc_or_fail /home/guido/repo/openairinterface5g/develop/common/utils/utils.h:74 /#2 0x58059e33454b in alloc_ho_ctx /home/guido/repo/openairinterface5g/develop/openair2/RRC/NR/rrc_gNB_mobility.c:47 /#3 0x58059e339e4d in nr_rrc_trigger_n2_ho /home/guido/repo/openairinterface5g/develop/openair2/RRC/NR/rrc_gNB_mobility.c:556 /#4 0x58059e33ae93 in nr_HO_N2_trigger_telnet /home/guido/repo/openairinterface5g/develop/openair2/RRC/NR/rrc_gNB_mobility.c:611 Root cause: Handover context allocated in N2 handover source gNB trigger path (nr_rrc_trigger_n2_ho) for any successful N2 handover but not properly freed in all handover completion scenarios. The UE context release complete handler was missing cleanup for handover context. Solution: refactor handover context cleanup - Move nr_rrc_finalize_ho() call to rrc_delete_ue_data() for centralized cleanup - Remove redundant nr_rrc_finalize_ho() calls from handover failure paths: * rrc_CU_process_ue_context_release_request() - UE not deleted yet * invalidate_du_connections() - UE will be deleted later - Keep nr_rrc_finalize_ho() calls in handover success paths where UE continues operating - Ensures handover context is cleaned up exactly once when UE is actually deleted - Prevents potential double-free and use-after-free issues in handover cleanup This centralizes all UE data cleanup in rrc_delete_ue_data() and ensures handover context is properly managed throughout the UE lifecycle and cleaned up when UE delete happens. --- openair2/RRC/NR/rrc_gNB.c | 3 +++ openair2/RRC/NR/rrc_gNB_du.c | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 2661531c27..aea6fb9259 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2338,6 +2338,9 @@ static void rrc_CU_process_ue_context_release_request(MessageDef *msg_p, sctp_as static void rrc_delete_ue_data(gNB_RRC_UE_t *UE) { + /* Clean up handover context if it exists */ + if (UE->ho_context) + nr_rrc_finalize_ho(UE); ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability, UE->UE_Capability_nr); ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->masterCellGroup); ASN_STRUCT_FREE(asn_DEF_NR_MeasResults, UE->measResults); diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index e104641edc..edf6f19164 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -453,10 +453,8 @@ static int invalidate_du_connections(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id) RB_FOREACH(ue_context_p, rrc_nr_ue_tree_s, &rrc->rrc_ue_head) { gNB_RRC_UE_t *UE = &ue_context_p->ue_context; uint32_t ue_id = UE->rrc_ue_id; - if (UE->ho_context != NULL) { + if (UE->ho_context != NULL) LOG_W(NR_RRC, "DU disconnected while handover for UE %d active\n", ue_id); - nr_rrc_finalize_ho(UE); - } f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_id); if (ue_data.du_assoc_id != assoc_id) continue; /* this UE is on another DU */