v2ray/ext

JSON 解析中处理转义字符有问题导致崩溃

dawndiy opened this issue · 1 comments

问题

在特定的 JSON 文本环境,Ext 中 encoding/json 部分对转义字符处理实现有问题,会导致 go 的标准库 encoding/json 直接崩溃。特定环境是,当 JSON 文本的第 512 个字节刚好是 \ 的时候,会造成崩溃。因为我刚好遇到了 JSON 文本刚好第 512 个字节开始是 path 部分,如:\/v2ray.com

表现

v2ray -config test.json 
V2Ray 3.14 (die Commanderin) Custom
An unified platform for anti-censorship.
panic: runtime error: slice bounds out of range

goroutine 1 [running]:
encoding/json.(*Decoder).refill(0xc4201d0000, 0x22, 0x1)
        /usr/local/go/src/encoding/json/stream.go:160 +0x23f
encoding/json.(*Decoder).readValue(0xc4201d0000, 0x0, 0x0, 0xace560)
        /usr/local/go/src/encoding/json/stream.go:134 +0x23d
encoding/json.(*Decoder).Decode(0xc4201d0000, 0xa1cae0, 0xc4201ce000, 0xd0, 0xa83840)
        /usr/local/go/src/encoding/json/stream.go:63 +0x78
v2ray.com/ext/tools/conf/serial.LoadJSONConfig(0xb704c0, 0xc4200b0000, 0xc42019a6c0,0xc42006bee8, 0x410319)
        /home/dawndiy/workspace/golang/src/v2ray.com/ext/tools/conf/serial/loader.go:18 +0xd1
v2ray.com/ext/tools/conf/command.init.0.func1(0xc4200b4000, 0x0, 0x0)
        /home/dawndiy/workspace/golang/src/v2ray.com/ext/tools/conf/command/command.go:15 +0x4b
main.main()
        src/v2ray.com/ext/tools/control/main/main.go:31 +0xeb

Main: failed to read config file: test.json > Main|Json: failed to execute v2ctl to convert config file. > exit status 2

环境

  • Go 1.10
  • Ext 库最新 commit(f43f74d)

分析

崩溃的原因是 io.Reader.Read() 返回的结果长度大于传入 []byte 的长度。

io.Reader.Read() 的注释里有如下描述:

// Read reads up to len(p) bytes into p. It returns the number of bytes
// read (0 <= n <= len(p)) and any error encountered. Even if Read
// returns n < len(p), it may use all of p as scratch space during the call.

在 Go 的 encoding/json 标准库的 decoder 中先会用长度为 512 的 []byte 来调用 io.Reader.Read() (ext 的实现) ,当第 512 字节是转义符号的时候处理是没有追加到返回中,而是跳过了。这时候 io.Reader.Reader() 返回的 n 是 511。然后如果剩下的内容还很长,第二次继续读取的时候会以 1025 长度的输入来调用函数,然而 ext 中的实现,因为上一次是标记了转义(这里导致少返回一个字节),这次会多插入一个字节(这里导致多插入一个字节,并且由于 p := b[:0] 这里会导致 p 提前后移,后面的内容就都重复了)。

简单尝试了一下在 Reader 结构中加一个 buffer []byte 来存多余的部分,但由于现在的实现 p 有的时候会一次追加 2 个字节导致循环过程修改了本身内容,不太好做,可以讨论一下有什么好的办法。

上面我应该描述清楚了,简单写了个测试用例可以来测试: dawndiy@da0a47f#diff-7d2da6197eab2fafc43d39c5180a853c

感谢测试并反馈。你的测试用例我merge到上游了,然后修复了转义时产生的问题。