Skip to content

fix(ngap): add nil guards for missing mandatory NGAP-ID IEs in handlers#731

Merged
gab-arrobo merged 5 commits into
omec-project:mainfrom
donivtech:fix/ngap-missing-ie-nil-guards
Jul 9, 2026
Merged

fix(ngap): add nil guards for missing mandatory NGAP-ID IEs in handlers#731
gab-arrobo merged 5 commits into
omec-project:mainfrom
donivtech:fix/ngap-missing-ie-nil-guards

Conversation

@donivtech

@donivtech donivtech commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Description

Several NGAP handlers dereference a mandatory NGAP-ID IE's .Value right after the IE-decoding loop. The in-loop checks only catch the "IE present but value is nil" case — an IE that is entirely absent from the ProtocolIEs list leaves the pointer nil, so a malformed/non-conformant peer can panic the AMF by omitting it.

The panic occurs in two places per handler: the lookup RanUeFind…(id.Value), and the No UE Context[…: %d] error log immediately after it (which re-derefs the same ID and is reached precisely when the lookup returns nil).

This adds a post-loop if <id> == nil { return } guard before the first dereference in each affected handler.

Note: simply swapping the lookup for the findRanUeBy{Ran,Amf}NgapID helper (as done in #732 for FetchRanUeContext) is not sufficient for the handlers — the helper returns nil, but the subsequent No UE Context log still derefs the ID and panics. The guard is needed because it returns before both the lookup and the log. (FetchRanUeContext is different: it returns the possibly-nil ranUe without logging the ID, so the helper is correct there.)

Handlers guarded (10)

Handler ID
HandleInitialUEMessage (also return after the criticality-diagnostics ErrorIndication) RANUENGAPID
HandleInitialContextSetupResponse RANUENGAPID
HandleInitialContextSetupFailure RANUENGAPID
HandleUEContextReleaseRequest (nil-safe dual AMFUENGAPID/RANUENGAPID lookup + drop nil-deref from its log) both
HandleUplinkNasTransport RANUENGAPID
HandleUEContextReleaseComplete AMFUENGAPID
HandlePDUSessionResourceReleaseResponse RANUENGAPID
HandleHandoverCancel RANUENGAPID
HandleNasNonDeliveryIndication RANUENGAPID
HandleUERadioCapabilityInfoIndication RANUENGAPID

The remaining handlers already guard their mandatory IDs (post-loop == nil guard, inline if id != nil wrapper, or the criticality-diagnostics if len > 0 { return } pattern), so they're left unchanged.

Testing

  • go build ./..., go vet ./..., go test ./... all pass
  • golangci-lint run --new-from-rev=main0 issues.
  • gofmt clean

@donivtech donivtech requested a review from a team June 25, 2026 08:59
@gab-arrobo gab-arrobo requested a review from Copilot June 25, 2026 15:10

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens several NGAP handlers against malformed/non-conformant peers by preventing nil-pointer dereferences when mandatory IEs are absent from ProtocolIEs, avoiding AMF panics/crashes during message handling.

Changes:

  • HandleInitialUEMessage: return immediately after sending ErrorIndication for reject/missing IEs; add explicit guard for missing RANUENGAPID before UE lookup/creation.
  • HandleInitialContextSetupResponse / HandleInitialContextSetupFailure: add explicit guard for missing RANUENGAPID before UE lookup.
  • HandleUEContextReleaseRequest: make AMF/RAN UE ID lookup nil-safe and remove a nil-deref from the “no context” error log path.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ngap/handler.go Outdated
@donivtech donivtech force-pushed the fix/ngap-missing-ie-nil-guards branch from 0d4080d to 6ddd2f0 Compare June 25, 2026 21:16
@donivtech donivtech changed the title fix(ngap): add nil guards for missing mandatory IEs in 4 handlers fix(ngap): add nil guards for missing mandatory NGAP-ID IEs in handlers Jun 25, 2026
@gab-arrobo gab-arrobo requested a review from Copilot June 25, 2026 21:48

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.

Comment thread ngap/handler.go
Comment thread ngap/handler.go

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 3 comments.

Comment thread ngap/handler.go
Comment thread ngap/handler.go
Comment thread ngap/handler.go
@donivtech

Copy link
Copy Markdown
Contributor Author

Good catch. Fixed in c689af4. Added a post-loop nASPDU == nil guard in HandleUplinkNasTransport, HandleInitialUEMessage, and HandleNasNonDeliveryIndication. I also swept all the handlers touched in this PR for any other post-loop IE dereference and found none remaining.

@gab-arrobo gab-arrobo force-pushed the fix/ngap-missing-ie-nil-guards branch from c689af4 to 343ba49 Compare June 26, 2026 17:12

@gab-arrobo gab-arrobo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@donivtech, thanks for your contribution. Please see a few comments below but those comments are applicable across the proposed changes. Let me know what you think. Thanks!

Comment thread ngap/handler.go Outdated
Comment thread ngap/handler.go Outdated
Comment thread ngap/handler.go Outdated
@donivtech

donivtech commented Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

Switched these to the helpers as suggested (44fe599): findRanUeByRanNgapID / findRanUeByAmfNgapID for the lookups in UplinkNasTransport, UEContextReleaseComplete, PDUSessionResourceReleaseResponse, InitialContextSetupResponse/Failure, HandoverCancel, NasNonDeliveryIndication, and UERadioCapabilityInfoIndication.

In each of these the No UE Context[…: %d] log right after the lookup dereferences the same ID, and with the helper that line is now reached when the ID is nil — so I wrapped it in if id != nil to stay panic-safe (the helper already logs the nil-ID case).

Happy to instead expand the helpers to take a caller label (your "from X" idea) if you'd prefer that over the generic nil-ID log - just say

@gab-arrobo

gab-arrobo commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Switched these to the helpers as suggested (44fe599): findRanUeByRanNgapID / findRanUeByAmfNgapID for the lookups in UplinkNasTransport, UEContextReleaseComplete, PDUSessionResourceReleaseResponse, InitialContextSetupResponse/Failure, HandoverCancel, NasNonDeliveryIndication, and UERadioCapabilityInfoIndication.

In each of these the No UE Context[…: %d] log right after the lookup dereferences the same ID, and with the helper that line is now reached when the ID is nil — so I wrapped it in if id != nil to stay panic-safe (the helper already logs the nil-ID case).

Happy to instead expand the helpers to take a caller label (your "from X" idea) if you'd prefer that over the generic nil-ID log - just say

Hi @donivtech,
Sorry, I got confused why you needed to check rANUENGAPID == nil. based on your latest changes, I see that you still need to check that because of the log inside if ranUe == nil.

	if rANUENGAPID == nil {
		ran.Log.Errorln("RANUENGAPID IE missing from UplinkNasTransport")
		return
	}

I think a better approach would be to keep the following check(s) and remove the if statements from inside if ranUe == nil. What do you think?

	if rANUENGAPID == nil {
		ran.Log.Errorln("RANUENGAPID IE missing from UplinkNasTransport")
		return
	}

That is, something like this in all places where rANUENGAPID.Value is used inside a if ranUe == nil

diff --git a/ngap/handler.go b/ngap/handler.go
index ed83f62..4b7599e 100644
--- a/ngap/handler.go
+++ b/ngap/handler.go
@@ -789,6 +789,11 @@ func HandleUplinkNasTransport(ctx ctxt.Context, ran *context.AmfRan, message *ng
                }
        }

+       if rANUENGAPID == nil {
+               ran.Log.Errorln("RANUENGAPID IE missing from UplinkNasTransport")
+               return
+       }
+
        if aMFUENGAPID == nil {
                ran.Log.Errorln("AMFUENGAPID IE missing from UplinkNasTransport")
                return
@@ -800,9 +805,7 @@ func HandleUplinkNasTransport(ctx ctxt.Context, ran *context.AmfRan, message *ng

        ranUe := findRanUeByRanNgapID(ran, rANUENGAPID)
        if ranUe == nil {
-               if rANUENGAPID != nil {
-                       ran.Log.Errorf("No UE Context[RanUeNgapID: %d]", rANUENGAPID.Value)
-               }
+               ran.Log.Errorf("No UE Context[RanUeNgapID: %d]", rANUENGAPID.Value)
                return
        }

Thanks!

@donivtech

Copy link
Copy Markdown
Contributor Author

Yes, that is better— applied your suggestion in the latest push. Kept the explicit if id == nil { … return } guard before each lookup and removed the if id != nil wrapper from inside if ranUe == nil, while keeping the findRanUeBy*NgapID helper for the lookup itself. So it reads guard → helper → clean No UE Context[…: %d] log (the guard guarantees the ID is non-nil by that point). Also merged latest main in.

Applied across all eight: UplinkNasTransport, UEContextReleaseComplete, PDUSessionResourceReleaseResponse, InitialContextSetupResponse/Failure, HandoverCancel, NasNonDeliveryIndication, UERadioCapabilityInfoIndication.

@gab-arrobo gab-arrobo force-pushed the fix/ngap-missing-ie-nil-guards branch from 194d1af to ce4f60b Compare July 6, 2026 21:07
Comment thread ngap/handler.go Outdated
@donivtech

Copy link
Copy Markdown
Contributor Author

Good point , done. HandleUEContextReleaseRequest now uses findRanUeByAmfNgapID(ran, aMFUENGAPID) for the primary lookup (and findRanUeByRanNgapID(ran, rANUENGAPID) for the RAN-ID fallback), dropping the != nil wrappers since the helpers nil-check internally.

Vinod Patmanathan added 5 commits July 9, 2026 11:06
Several NGAP handlers dereference a mandatory NGAP-ID IE's .Value
immediately after the IE-decoding loop. The in-loop checks only catch
"IE present but value nil"; an IE entirely absent from the ProtocolIEs
list leaves the pointer nil, so the post-loop dereference (and the
"No UE Context[... %d]" error log that follows it) panics.

Add a post-loop nil guard before the first dereference in each affected
handler. Note the findRanUeBy*NgapID helper alone is not sufficient
here: the following "No UE Context" log re-derefs the same ID and is
reached exactly when it is nil, so the guard must return before the
lookup.

Handlers guarded:
- HandleInitialUEMessage (also return after the criticality-diagnostics
  ErrorIndication)
- HandleInitialContextSetupResponse
- HandleInitialContextSetupFailure
- HandleUEContextReleaseRequest (nil-safe AMFUENGAPID/RANUENGAPID lookup
  + drop the nil-deref from its "no context" log)
- HandleUplinkNasTransport
- HandleUEContextReleaseComplete
- HandlePDUSessionResourceReleaseResponse
- HandleHandoverCancel
- HandleNasNonDeliveryIndication
- HandleUERadioCapabilityInfoIndication

Signed-off-by: Vinod Patmanathan <vinod.patmanathan@forsway.com>
Address review feedback on the handler nil-guards:

- HandleUplinkNasTransport and HandleHandoverCancel also dereference
  aMFUENGAPID.Value later (in a "No UE Context" log and an
  AmfUeNgapId conflict check respectively), which the RANUENGAPID guard
  alone did not cover. Add a symmetric AMFUENGAPID nil guard so an
  absent AMFUENGAPID IE can't trigger a nil-pointer panic.

- HandleUEContextReleaseRequest: instead of a generic message, log
  whichever of AMFUENGAPID / RANUENGAPID is present (the dual lookup
  may have either), keeping the identifiers available for debugging
  without dereferencing a nil pointer.

Signed-off-by: Vinod Patmanathan <vinod.patmanathan@forsway.com>
Address review feedback: HandleUplinkNasTransport, HandleInitialUEMessage
and HandleNasNonDeliveryIndication pass nASPDU.Value to nas.HandleNAS()
after the IE loop. The in-loop check only catches a present-but-nil
NASPDU; an entirely-absent NASPDU IE leaves nASPDU nil and panics there.

Add a post-loop NASPDU nil guard in each (NASPDU is a mandatory IE in
these messages per TS 38.413).

Signed-off-by: Vinod Patmanathan <vinod.patmanathan@forsway.com>
Per review: keep the explicit `if id == nil { return }` guard before the
lookup (so the ID is guaranteed non-nil for the following "No UE Context"
log) and use the findRanUeByRanNgapID / findRanUeByAmfNgapID helpers for
the lookup itself. This removes the `if id != nil` wrappers from inside
`if ranUe == nil` used in the previous revision while staying panic-safe.

Handlers: HandleUplinkNasTransport, HandleUEContextReleaseComplete,
HandlePDUSessionResourceReleaseResponse, HandleInitialContextSetupResponse,
HandleInitialContextSetupFailure, HandleHandoverCancel,
HandleNasNonDeliveryIndication, HandleUERadioCapabilityInfoIndication.

Signed-off-by: Vinod Patmanathan <vinod.patmanathan@forsway.com>
Per review: route the AMF/RAN UE lookup in HandleUEContextReleaseRequest
through findRanUeByAmfNgapID / findRanUeByRanNgapID instead of the raw
context.AMF_Self().RanUeFindByAmfUeNgapID / ran.RanUeFindByRanUeNgapID
calls with explicit `!= nil` wrappers. The helpers already nil-check the
IDs, and the `if ranUe == nil` conditional log below remains nil-safe.

Signed-off-by: Vinod Patmanathan <vinod.patmanathan@forsway.com>
@gab-arrobo gab-arrobo force-pushed the fix/ngap-missing-ie-nil-guards branch from fc76f7b to 7f127f3 Compare July 9, 2026 18:06
@gab-arrobo gab-arrobo merged commit ec0bc40 into omec-project:main Jul 9, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants