mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-10-13 17:44:00 +00:00
Fix unbounded allocations when reading untrusted binary data
This commit is contained in:
+25
-47
@@ -77,13 +77,14 @@ func Read(reader io.Reader, recover bool) (ruleSetCompat option.PlainRuleSetComp
|
||||
return
|
||||
}
|
||||
ruleSetCompat.Version = version
|
||||
ruleSetCompat.Options.Rules = make([]option.HeadlessRule, length)
|
||||
for i := range length {
|
||||
ruleSetCompat.Options.Rules[i], err = readRule(bReader, recover)
|
||||
var rule option.HeadlessRule
|
||||
rule, err = readRule(bReader, recover, 0)
|
||||
if err != nil {
|
||||
err = E.Cause(err, "read rule[", i, "]")
|
||||
return
|
||||
}
|
||||
ruleSetCompat.Options.Rules = append(ruleSetCompat.Options.Rules, rule)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -119,7 +120,13 @@ func Write(writer io.Writer, ruleSet option.PlainRuleSet, generateVersion uint8)
|
||||
return compressWriter.Close()
|
||||
}
|
||||
|
||||
func readRule(reader varbin.Reader, recover bool) (rule option.HeadlessRule, err error) {
|
||||
const maxLogicalRuleDepth = 100
|
||||
|
||||
func readRule(reader varbin.Reader, recover bool, depth int) (rule option.HeadlessRule, err error) {
|
||||
if depth > maxLogicalRuleDepth {
|
||||
err = E.New("logical rule nested too deep")
|
||||
return
|
||||
}
|
||||
var ruleType uint8
|
||||
err = binary.Read(reader, binary.BigEndian, &ruleType)
|
||||
if err != nil {
|
||||
@@ -131,7 +138,7 @@ func readRule(reader varbin.Reader, recover bool) (rule option.HeadlessRule, err
|
||||
rule.DefaultOptions, err = readDefaultRule(reader, recover)
|
||||
case 1:
|
||||
rule.Type = C.RuleTypeLogical
|
||||
rule.LogicalOptions, err = readLogicalRule(reader, recover)
|
||||
rule.LogicalOptions, err = readLogicalRule(reader, recover, depth)
|
||||
default:
|
||||
err = E.New("unknown rule type: ", ruleType)
|
||||
}
|
||||
@@ -160,7 +167,7 @@ func readDefaultRule(reader varbin.Reader, recover bool) (rule option.DefaultHea
|
||||
switch itemType {
|
||||
case ruleItemQueryType:
|
||||
var rawQueryType []uint16
|
||||
rawQueryType, err = readRuleItemUint16(reader)
|
||||
rawQueryType, err = varbin.ReadSlice[uint16](reader, binary.BigEndian)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -200,11 +207,11 @@ func readDefaultRule(reader varbin.Reader, recover bool) (rule option.DefaultHea
|
||||
rule.IPCIDR = common.Map(rule.IPSet.Prefixes(), netip.Prefix.String)
|
||||
}
|
||||
case ruleItemSourcePort:
|
||||
rule.SourcePort, err = readRuleItemUint16(reader)
|
||||
rule.SourcePort, err = varbin.ReadSlice[uint16](reader, binary.BigEndian)
|
||||
case ruleItemSourcePortRange:
|
||||
rule.SourcePortRange, err = readRuleItemString(reader)
|
||||
case ruleItemPort:
|
||||
rule.Port, err = readRuleItemUint16(reader)
|
||||
rule.Port, err = varbin.ReadSlice[uint16](reader, binary.BigEndian)
|
||||
case ruleItemPortRange:
|
||||
rule.PortRange, err = readRuleItemString(reader)
|
||||
case ruleItemProcessName:
|
||||
@@ -230,7 +237,7 @@ func readDefaultRule(reader varbin.Reader, recover bool) (rule option.DefaultHea
|
||||
rule.AdGuardDomain = matcher.Dump()
|
||||
}
|
||||
case ruleItemNetworkType:
|
||||
rule.NetworkType, err = readRuleItemUint8[option.InterfaceType](reader)
|
||||
rule.NetworkType, err = varbin.ReadSlice[option.InterfaceType](reader, binary.BigEndian)
|
||||
case ruleItemNetworkIsExpensive:
|
||||
rule.NetworkIsExpensive = true
|
||||
case ruleItemNetworkIsConstrained:
|
||||
@@ -242,7 +249,7 @@ func readDefaultRule(reader varbin.Reader, recover bool) (rule option.DefaultHea
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for i := uint64(0); i < size; i++ {
|
||||
for range size {
|
||||
var key uint8
|
||||
err = binary.Read(reader, binary.BigEndian, &key)
|
||||
if err != nil {
|
||||
@@ -510,18 +517,14 @@ func readRuleItemString(reader varbin.Reader) ([]string, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make([]string, length)
|
||||
for i := range result {
|
||||
strLen, err := binary.ReadUvarint(reader)
|
||||
var result []string
|
||||
for range length {
|
||||
var value []byte
|
||||
value, err = varbin.ReadSlice[byte](reader, binary.BigEndian)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf := make([]byte, strLen)
|
||||
_, err = io.ReadFull(reader, buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result[i] = string(buf)
|
||||
result = append(result, string(value))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@@ -548,19 +551,6 @@ func writeRuleItemString(writer varbin.Writer, itemType uint8, value []string) e
|
||||
return nil
|
||||
}
|
||||
|
||||
func readRuleItemUint8[E ~uint8](reader varbin.Reader) ([]E, error) {
|
||||
length, err := binary.ReadUvarint(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make([]E, length)
|
||||
_, err = io.ReadFull(reader, *(*[]byte)(unsafe.Pointer(&result)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func writeRuleItemUint8[E ~uint8](writer varbin.Writer, itemType uint8, value []E) error {
|
||||
err := writer.WriteByte(itemType)
|
||||
if err != nil {
|
||||
@@ -574,19 +564,6 @@ func writeRuleItemUint8[E ~uint8](writer varbin.Writer, itemType uint8, value []
|
||||
return err
|
||||
}
|
||||
|
||||
func readRuleItemUint16(reader varbin.Reader) ([]uint16, error) {
|
||||
length, err := binary.ReadUvarint(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make([]uint16, length)
|
||||
err = binary.Read(reader, binary.BigEndian, result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func writeRuleItemUint16(writer varbin.Writer, itemType uint8, value []uint16) error {
|
||||
err := writer.WriteByte(itemType)
|
||||
if err != nil {
|
||||
@@ -625,7 +602,7 @@ func writeRuleItemCIDR(writer varbin.Writer, itemType uint8, value []string) err
|
||||
return writeIPSet(writer, ipSet)
|
||||
}
|
||||
|
||||
func readLogicalRule(reader varbin.Reader, recovery bool) (logicalRule option.LogicalHeadlessRule, err error) {
|
||||
func readLogicalRule(reader varbin.Reader, recovery bool, depth int) (logicalRule option.LogicalHeadlessRule, err error) {
|
||||
mode, err := reader.ReadByte()
|
||||
if err != nil {
|
||||
return
|
||||
@@ -643,13 +620,14 @@ func readLogicalRule(reader varbin.Reader, recovery bool) (logicalRule option.Lo
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
logicalRule.Rules = make([]option.HeadlessRule, length)
|
||||
for i := range length {
|
||||
logicalRule.Rules[i], err = readRule(reader, recovery)
|
||||
var rule option.HeadlessRule
|
||||
rule, err = readRule(reader, recovery, depth+1)
|
||||
if err != nil {
|
||||
err = E.Cause(err, "read logical rule [", i, "]")
|
||||
return
|
||||
}
|
||||
logicalRule.Rules = append(logicalRule.Rules, rule)
|
||||
}
|
||||
err = binary.Read(reader, binary.BigEndian, &logicalRule.Invert)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user