mirror of
https://github.com/golang/go
synced 2024-11-24 22:57:57 -07:00
exp/ssh: fix length header leaking into channel data streams.
The payload of a data message is defined as an SSH string type, which uses the first four bytes to encode its length. When channelData and channelExtendedData were added I defined Payload as []byte to be able to use it directly without a string to []byte conversion. This resulted in the length data leaking into the payload data. This CL fixes the bug, and restores agl's original fast path code. Additionally, a bug whereby s.lock was not released if a packet arrived for an invalid channel has been fixed. Finally, as they were no longer used, I have removed the channelData and channelExtedendData structs. R=agl, rsc CC=golang-dev https://golang.org/cl/5330053
This commit is contained in:
parent
604e10c34d
commit
0f6b80c694
@ -258,17 +258,45 @@ func (c *ClientConn) openChan(typ string) (*clientChan, os.Error) {
|
||||
// mainloop reads incoming messages and routes channel messages
|
||||
// to their respective ClientChans.
|
||||
func (c *ClientConn) mainLoop() {
|
||||
// TODO(dfc) signal the underlying close to all channels
|
||||
defer c.Close()
|
||||
for {
|
||||
packet, err := c.readPacket()
|
||||
if err != nil {
|
||||
// TODO(dfc) signal the underlying close to all channels
|
||||
c.Close()
|
||||
return
|
||||
break
|
||||
}
|
||||
// TODO(dfc) A note on blocking channel use.
|
||||
// The msg, win, data and dataExt channels of a clientChan can
|
||||
// cause this loop to block indefinately if the consumer does
|
||||
// not service them.
|
||||
switch packet[0] {
|
||||
case msgChannelData:
|
||||
if len(packet) < 9 {
|
||||
// malformed data packet
|
||||
break
|
||||
}
|
||||
peersId := uint32(packet[1])<<24 | uint32(packet[2])<<16 | uint32(packet[3])<<8 | uint32(packet[4])
|
||||
if length := int(packet[5])<<24 | int(packet[6])<<16 | int(packet[7])<<8 | int(packet[8]); length > 0 {
|
||||
packet = packet[9:]
|
||||
c.getChan(peersId).data <- packet[:length]
|
||||
}
|
||||
case msgChannelExtendedData:
|
||||
if len(packet) < 13 {
|
||||
// malformed data packet
|
||||
break
|
||||
}
|
||||
peersId := uint32(packet[1])<<24 | uint32(packet[2])<<16 | uint32(packet[3])<<8 | uint32(packet[4])
|
||||
datatype := uint32(packet[5])<<24 | uint32(packet[6])<<16 | uint32(packet[7])<<8 | uint32(packet[8])
|
||||
if length := int(packet[9])<<24 | int(packet[10])<<16 | int(packet[11])<<8 | int(packet[12]); length > 0 {
|
||||
packet = packet[13:]
|
||||
// RFC 4254 5.2 defines data_type_code 1 to be data destined
|
||||
// for stderr on interactive sessions. Other data types are
|
||||
// silently discarded.
|
||||
if datatype == 1 {
|
||||
c.getChan(peersId).dataExt <- packet[:length]
|
||||
}
|
||||
}
|
||||
default:
|
||||
switch msg := decode(packet).(type) {
|
||||
case *channelOpenMsg:
|
||||
c.getChan(msg.PeersId).msg <- msg
|
||||
@ -292,20 +320,12 @@ func (c *ClientConn) mainLoop() {
|
||||
c.getChan(msg.PeersId).msg <- msg
|
||||
case *windowAdjustMsg:
|
||||
c.getChan(msg.PeersId).win <- int(msg.AdditionalBytes)
|
||||
case *channelData:
|
||||
c.getChan(msg.PeersId).data <- msg.Payload
|
||||
case *channelExtendedData:
|
||||
// RFC 4254 5.2 defines data_type_code 1 to be data destined
|
||||
// for stderr on interactive sessions. Other data types are
|
||||
// silently discarded.
|
||||
if msg.Datatype == 1 {
|
||||
c.getChan(msg.PeersId).dataExt <- msg.Payload
|
||||
}
|
||||
default:
|
||||
fmt.Printf("mainLoop: unhandled %#v\n", msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dial connects to the given network address using net.Dial and
|
||||
// then initiates a SSH handshake, returning the resulting client connection.
|
||||
|
@ -144,19 +144,6 @@ type channelOpenFailureMsg struct {
|
||||
Language string
|
||||
}
|
||||
|
||||
// See RFC 4254, section 5.2.
|
||||
type channelData struct {
|
||||
PeersId uint32
|
||||
Payload []byte `ssh:"rest"`
|
||||
}
|
||||
|
||||
// See RFC 4254, section 5.2.
|
||||
type channelExtendedData struct {
|
||||
PeersId uint32
|
||||
Datatype uint32
|
||||
Payload []byte `ssh:"rest"`
|
||||
}
|
||||
|
||||
type channelRequestMsg struct {
|
||||
PeersId uint32
|
||||
Request string
|
||||
@ -612,10 +599,6 @@ func decode(packet []byte) interface{} {
|
||||
msg = new(channelOpenFailureMsg)
|
||||
case msgChannelWindowAdjust:
|
||||
msg = new(windowAdjustMsg)
|
||||
case msgChannelData:
|
||||
msg = new(channelData)
|
||||
case msgChannelExtendedData:
|
||||
msg = new(channelExtendedData)
|
||||
case msgChannelEOF:
|
||||
msg = new(channelEOFMsg)
|
||||
case msgChannelClose:
|
||||
|
@ -581,6 +581,25 @@ func (s *ServerConn) Accept() (Channel, os.Error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch packet[0] {
|
||||
case msgChannelData:
|
||||
if len(packet) < 9 {
|
||||
// malformed data packet
|
||||
return nil, ParseError{msgChannelData}
|
||||
}
|
||||
peersId := uint32(packet[1])<<24 | uint32(packet[2])<<16 | uint32(packet[3])<<8 | uint32(packet[4])
|
||||
s.lock.Lock()
|
||||
c, ok := s.channels[peersId]
|
||||
if !ok {
|
||||
s.lock.Unlock()
|
||||
continue
|
||||
}
|
||||
if length := int(packet[5])<<24 | int(packet[6])<<16 | int(packet[7])<<8 | int(packet[8]); length > 0 {
|
||||
packet = packet[9:]
|
||||
c.handleData(packet[:length])
|
||||
}
|
||||
s.lock.Unlock()
|
||||
default:
|
||||
switch msg := decode(packet).(type) {
|
||||
case *channelOpenMsg:
|
||||
c := new(channel)
|
||||
@ -605,24 +624,17 @@ func (s *ServerConn) Accept() (Channel, os.Error) {
|
||||
s.lock.Lock()
|
||||
c, ok := s.channels[msg.PeersId]
|
||||
if !ok {
|
||||
s.lock.Unlock()
|
||||
continue
|
||||
}
|
||||
c.handlePacket(msg)
|
||||
s.lock.Unlock()
|
||||
|
||||
case *channelData:
|
||||
s.lock.Lock()
|
||||
c, ok := s.channels[msg.PeersId]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
c.handleData(msg.Payload)
|
||||
s.lock.Unlock()
|
||||
|
||||
case *channelEOFMsg:
|
||||
s.lock.Lock()
|
||||
c, ok := s.channels[msg.PeersId]
|
||||
if !ok {
|
||||
s.lock.Unlock()
|
||||
continue
|
||||
}
|
||||
c.handlePacket(msg)
|
||||
@ -632,6 +644,7 @@ func (s *ServerConn) Accept() (Channel, os.Error) {
|
||||
s.lock.Lock()
|
||||
c, ok := s.channels[msg.PeersId]
|
||||
if !ok {
|
||||
s.lock.Unlock()
|
||||
continue
|
||||
}
|
||||
c.handlePacket(msg)
|
||||
@ -652,6 +665,7 @@ func (s *ServerConn) Accept() (Channel, os.Error) {
|
||||
// Unknown message. Ignore.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
panic("unreachable")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user