From 569459c54c30b2c375bf92141488daac6c4781e1 Mon Sep 17 00:00:00 2001 From: Cocoon-Break <54054995+kuishou68@users.noreply.github.com> Date: Fri, 29 May 2026 18:47:58 +0800 Subject: [PATCH] Sudoku finalmask: Harden UDP ReadFrom() against invalid packets (#6185) https://github.com/XTLS/Xray-core/issues/6184#issuecomment-4573949756 Fixes https://github.com/XTLS/Xray-core/issues/6184 --------- Co-authored-by: LjhAUMEM --- .../internet/finalmask/sudoku/conn_udp.go | 54 ++++++++++--------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/transport/internet/finalmask/sudoku/conn_udp.go b/transport/internet/finalmask/sudoku/conn_udp.go index c2b2f4dda..4d610b50a 100644 --- a/transport/internet/finalmask/sudoku/conn_udp.go +++ b/transport/internet/finalmask/sudoku/conn_udp.go @@ -1,10 +1,12 @@ package sudoku import ( - "io" + "context" "net" "sync" "time" + + "github.com/xtls/xray-core/common/errors" ) type udpConn struct { @@ -39,26 +41,31 @@ func (c *udpConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { c.readMu.Lock() defer c.readMu.Unlock() - n, addr, err = c.conn.ReadFrom(c.readBuf) - if err != nil { - return n, addr, err - } + for { + n, addr, err = c.conn.ReadFrom(c.readBuf) + if err != nil { + return n, addr, err + } - decoded := make([]byte, 0, n/4+1) - hints := make([]byte, 0, 4) - tableIndex := 0 - hints, decoded, err = decodeBytes(c.tables, &tableIndex, c.readBuf[:n], hints, decoded) - if err != nil { - return 0, addr, err + decoded := make([]byte, 0, n/4+1) + hints := make([]byte, 0, 4) + tableIndex := 0 + hints, decoded, err = decodeBytes(c.tables, &tableIndex, c.readBuf[:n], hints, decoded) + if err != nil { + errors.LogErrorInner(context.Background(), err, "drop packet from ", addr, " with size ", n) + continue + } + if len(hints) != 0 { + errors.LogError(context.Background(), "drop packet from ", addr, " with size ", n) + continue + } + if len(p) < len(decoded) { + errors.LogError(context.Background(), "drop packet from ", addr, " with size ", n) + continue + } + copy(p, decoded) + return len(decoded), addr, nil } - if len(hints) != 0 { - return 0, addr, io.ErrUnexpectedEOF - } - if len(p) < len(decoded) { - return 0, addr, io.ErrShortBuffer - } - copy(p, decoded) - return len(decoded), addr, nil } func (c *udpConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { @@ -68,16 +75,15 @@ func (c *udpConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { // UDP decoding restarts at table 0 for every datagram, so encoding must do the same. encoded, err := newCodec(c.tables, c.pMin, c.pMax).encode(p) if err != nil { - return 0, err + errors.LogErrorInner(context.Background(), err, "drop packet to ", addr, " with size ", len(p)) + return 0, nil } - nn, err := c.conn.WriteTo(encoded, addr) + _, err = c.conn.WriteTo(encoded, addr) if err != nil { return 0, err } - if nn != len(encoded) { - return 0, io.ErrShortWrite - } + return len(p), nil }