Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

syscall: panic when syscall.ParseSocketControlMessage called #41522

Closed
blacktear23 opened this issue Sep 21, 2020 · 8 comments
Closed

syscall: panic when syscall.ParseSocketControlMessage called #41522

blacktear23 opened this issue Sep 21, 2020 · 8 comments
Milestone

Comments

@blacktear23
Copy link

@blacktear23 blacktear23 commented Sep 21, 2020

What version of Go are you using (go version)?

$ go version
go version go1.15.1 darwin/amd64

Does this issue reproduce with the latest release?

yes

What operating system and processor architecture are you using (go env)?

Running at Linux AMD64

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/rainli/Library/Caches/go-build"
GOENV="/Users/rainli/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/rainli/goprojs/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/rainli/goprojs"
GOPRIVATE=""
GOPROXY=""
GOROOT="/usr/local/Cellar/go/1.15.1/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.15.1/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/f5/f893z52n5z9gpdq4wgjpqlvc0000gp/T/go-build835697009=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

Got panic on syscall.ParseSocketControlMessage.

syscall.ParseSocketControlMessage(0xc0017b2000, 0x20, 0x100c, 0x7f41d57bb0a0, 0xc00213ea80, 0xc0002b2800, 0x7f41fc7e8e98, 0xc0010cbe58)
	syscall/sockcmsg_unix.go:43 +0x30d
...
panic: runtime error: slice bounds out of range [-5310291284149790200:]

Before line 43 h, dbuf, err := socketControlMessageHeaderAndData(b[i:]) we should check variable i is not a negative number.

What did you expect to see?

No panic

What did you see instead?

Got panic

@davecheney
Copy link
Contributor

@davecheney davecheney commented Sep 21, 2020

Thank you for your issue. To be able to investigate we will need a way to reproduce what you see. Can you please provide a stand alone program which demonstrates the panic you see. Thank you

@blacktear23
Copy link
Author

@blacktear23 blacktear23 commented Sep 21, 2020

@davecheney code snippet likes below:

func Run(listenAddr string) {
	uaddr, _ := net.ResolveUDPAddr("udp", listenAddr)
	conn, _ := net.ListenUDP("udp", uaddr)
	fds, _ := conn.File()
	defer fds.Close()
	fd := int(fds.Fd())
	syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_TRANSPARENT, 1)
	syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_RECVORIGDSTADDR, 1)
	for {
		buf := make([]byte, 4096)
		scmBuf := make([]byte, 4096)
		n, scmn, _, src, err := conn.ReadMsgUDP(buf, scmBuf)
		if err != nil {
			log.Printf("[TProxy] Read packet from UDP error: %v\n", err)
			continue
		}
		go handleTProxyUDPPacket(src, n, buf, scmBuf[0:scmn])
	}
}

func handleTProxyUDPPacket(src *net.UDPAddr, n int, buf []byte, scm []byte) {
	msgs, err := syscall.ParseSocketControlMessage(scm)
	...
}
@blacktear23
Copy link
Author

@blacktear23 blacktear23 commented Sep 21, 2020

Seems Linux Kernel or ReadMsgUDP return a bad data. But I think return an error instead of panic is better design for ParseSocketControlMessage.

@cagedmantis cagedmantis changed the title syscall: got panic when call `syscall.ParseSocketControlMessage` syscall: panic when syscall.ParseSocketControlMessage called Sep 22, 2020
@cagedmantis cagedmantis added this to the Backlog milestone Sep 22, 2020
@cagedmantis
Copy link
Contributor

@cagedmantis cagedmantis commented Sep 22, 2020

@blacktear23
Copy link
Author

@blacktear23 blacktear23 commented Sep 24, 2020

I have more information:

  • Linux Kernel Version: Linux Ubuntu 4.4.0-77-generic #98-Ubuntu SMP
  • I add recover in program and log SocketControlMessage, below is sample data.
Got Fatal Error: runtime error: slice bounds out of range [-942784121279537400:] Data: [1 31 65 55 214 142 234 242 235 176 145 153 234 178 2 177 238 111 87 28 84 157 20 223 14 118 21 61 176 39 113 172]
Got Fatal Error: runtime error: slice bounds out of range [-1835265814303145464:] Data: [1 2 11 46 119 211 135 230 134 164 122 177 135 166 111 165 131 123 58 8 57 137 121 203 99 98 120 41 221 51 28 184]
Got Fatal Error: runtime error: slice bounds out of range [-7991719146625691896:] Data: [1 15 176 48 199 181 23 145 22 211 111 200 23 209 255 210 19 12 170 127 169 254 233 188 243 21 232 94 77 68 140 207]
Got Fatal Error: runtime error: slice bounds out of range [-5423398458185798904:] Data: [1 43 111 48 214 55 188 180 189 246 163 107 188 244 84 247 184 41 1 90 2 219 66 153 88 48 67 123 230 97 39 234]
Got Fatal Error: runtime error: slice bounds out of range [-2617315282930556664:] Data: [1 33 185 7 158 109 173 219 172 153 161 4 173 155 69 152 169 70 16 53 19 180 83 246 73 95 82 20 247 14 54 133]
Got Fatal Error: runtime error: slice bounds out of range [-9043550968425791992:] Data: [1 62 215 26 79 218 126 130 127 192 142 142 126 194 150 193 122 31 195 108 192 237 128 175 154 6 129 77 36 87 229 220]
Got Fatal Error: runtime error: slice bounds out of range [-3518738449171086840:] Data: [1 2 166 7 6 238 42 207 43 141 12 220 42 143 194 140 46 82 151 33 148 160 212 226 206 75 213 0 112 26 177 145]
Got Fatal Error: runtime error: slice bounds out of range [-1252274658875404280:] Data: [1 16 130 36 213 6 159 238 158 172 179 79 159 174 119 173 155 115 34 0 33 129 97 195 123 106 96 33 197 59 4 176]
Got Fatal Error: runtime error: slice bounds out of range [-2826249855503823864:] Data: [1 12 50 4 187 36 199 216 198 154 141 105 199 152 47 155 195 69 122 54 121 183 57 245 35 92 56 23 157 13 92 134]
@tklauser
Copy link
Member

@tklauser tklauser commented Sep 24, 2020

I cannot reproduce this on linux/amd64 with go 1.15.2 using the given data using the following test:

func TestParseSocketControlMessage(t *testing.T) {
        for _, tc := range [][]byte{
                {1, 31, 65, 55, 214, 142, 234, 242, 235, 176, 145, 153, 234, 178, 2, 177, 238, 111, 87, 28, 84, 157, 20, 223, 14, 118, 21, 61, 176, 39, 113, 172},
                {1, 2, 11, 46, 119, 211, 135, 230, 134, 164, 122, 177, 135, 166, 111, 165, 131, 123, 58, 8, 57, 137, 121, 203, 99, 98, 120, 41, 221, 51, 28, 184},
                {1, 15, 176, 48, 199, 181, 23, 145, 22, 211, 111, 200, 23, 209, 255, 210, 19, 12, 170, 127, 169, 254, 233, 188, 243, 21, 232, 94, 77, 68, 140, 207},
                {1, 43, 111, 48, 214, 55, 188, 180, 189, 246, 163, 107, 188, 244, 84, 247, 184, 41, 1, 90, 2, 219, 66, 153, 88, 48, 67, 123, 230, 97, 39, 234},
                {1, 33, 185, 7, 158, 109, 173, 219, 172, 153, 161, 4, 173, 155, 69, 152, 169, 70, 16, 53, 19, 180, 83, 246, 73, 95, 82, 20, 247, 14, 54, 133},
                {1, 62, 215, 26, 79, 218, 126, 130, 127, 192, 142, 142, 126, 194, 150, 193, 122, 31, 195, 108, 192, 237, 128, 175, 154, 6, 129, 77, 36, 87, 229, 220},
                {1, 2, 166, 7, 6, 238, 42, 207, 43, 141, 12, 220, 42, 143, 194, 140, 46, 82, 151, 33, 148, 160, 212, 226, 206, 75, 213, 0, 112, 26, 177, 145},
                {1, 16, 130, 36, 213, 6, 159, 238, 158, 172, 179, 79, 159, 174, 119, 173, 155, 115, 34, 0, 33, 129, 97, 195, 123, 106, 96, 33, 197, 59, 4, 176},
                {1, 12, 50, 4, 187, 36, 199, 216, 198, 154, 141, 105, 199, 152, 47, 155, 195, 69, 122, 54, 121, 183, 57, 245, 35, 92, 56, 23, 157, 13, 92, 134},
        } {
                _, err := syscall.ParseSocketControlMessage(tc)
                if err != nil && err != syscall.EINVAL {
                        t.Errorf("ParseSocketControlMessage: %v", err)
                }
        }
}

This never panic()s and ParseSocketControlMessage always returns EINVAL as expected for an invalid socket control message. Could you please post the modified reproducer program with the recover and logging of the socket control message which you used to gather the sample data?

@blacktear23
Copy link
Author

@blacktear23 blacktear23 commented Sep 24, 2020

@tklauser I run the build at MacOS 10.15.6 and the build command is GOOS=linux go build -trimpath -ldflags "-s -w" .... Arch is amd64 and the binary is running on an Ubuntu server which kernel version is 4.4.0-77.
And when I got those log messages I try to reproduce it too, but cannot get any panic yet. I am thinking is conn.ReadMsgUDP(buf, scmBuf) will write scmBuf twice?

@blacktear23
Copy link
Author

@blacktear23 blacktear23 commented Sep 27, 2020

@tklauser Finally I found the reason. scmBuf is assigned from a MemoryPool and other code return the memory buffer to the Pool before it really not used. So the problem is caused by other goroutine rewrite the buffer when socketControlMessageHeaderAndData returned.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants
You can’t perform that action at this time.