From f0ae9bb5090ad5d874aa4d47fe0abc5696fa2f60 Mon Sep 17 00:00:00 2001 From: John Soros Date: Sun, 29 Nov 2015 04:28:05 +0100 Subject: [PATCH] handlers: check array bounds before indexing --- client/handlers.go | 5 ++++- client/line.go | 13 +++++++++++++ client/state_handlers.go | 32 +++++++++++++++++++++++++++++++- 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/client/handlers.go b/client/handlers.go index 884a9bd..b538579 100644 --- a/client/handlers.go +++ b/client/handlers.go @@ -73,6 +73,9 @@ func (conn *Conn) h_433(line *Line) { me := conn.Me() neu := conn.cfg.NewNick(line.Args[1]) conn.Nick(neu) + if !line.argslen(1) { + return + } // if this is happening before we're properly connected (i.e. the nick // we sent in the initial NICK command is in use) we will not receive // a NICK message to confirm our change of nick, so ReNick here... @@ -89,7 +92,7 @@ func (conn *Conn) h_433(line *Line) { func (conn *Conn) h_CTCP(line *Line) { if line.Args[0] == VERSION { conn.CtcpReply(line.Nick, VERSION, conn.cfg.Version) - } else if line.Args[0] == PING { + } else if line.Args[0] == PING && line.argslen(2) { conn.CtcpReply(line.Nick, PING, line.Args[2]) } } diff --git a/client/line.go b/client/line.go index 135a2e4..d0204fd 100644 --- a/client/line.go +++ b/client/line.go @@ -3,6 +3,8 @@ package client import ( "strings" "time" + "runtime" + "github.com/fluffle/goirc/logging" ) // We parse an incoming line into this struct. Line.Cmd is used as the trigger @@ -156,3 +158,14 @@ func ParseLine(s string) *Line { } return line } + + +func (line *Line) argslen(minlen int) bool { + pc, _, _, _ := runtime.Caller(1) + fn := runtime.FuncForPC(pc) + if len(line.Args) <= minlen { + logging.Warn("%s: too few arguments: %s", fn.Name(), strings.Join(line.Args, " ")) + return false + } + return true +} diff --git a/client/state_handlers.go b/client/state_handlers.go index 3c62957..847679c 100644 --- a/client/state_handlers.go +++ b/client/state_handlers.go @@ -83,6 +83,9 @@ func (conn *Conn) h_PART(line *Line) { // Handle KICKs from channels to maintain state func (conn *Conn) h_KICK(line *Line) { + if !line.argslen(1) { + return + } // XXX: this won't handle autorejoining channels on KICK // it's trivial to do this in a seperate handler... conn.st.Dissociate(line.Args[0], line.Args[1]) @@ -95,6 +98,9 @@ func (conn *Conn) h_QUIT(line *Line) { // Handle MODE changes for channels we know about (and our nick personally) func (conn *Conn) h_MODE(line *Line) { + if !line.argslen(1) { + return + } if ch := conn.st.GetChannel(line.Args[0]); ch != nil { // channel modes first conn.st.ChannelModes(line.Args[0], line.Args[1], line.Args[2:]...) @@ -114,6 +120,9 @@ func (conn *Conn) h_MODE(line *Line) { // Handle TOPIC changes for channels func (conn *Conn) h_TOPIC(line *Line) { + if !line.argslen(1) { + return + } if ch := conn.st.GetChannel(line.Args[0]); ch != nil { conn.st.Topic(line.Args[0], line.Args[1]) } else { @@ -124,7 +133,10 @@ func (conn *Conn) h_TOPIC(line *Line) { // Handle 311 whois reply func (conn *Conn) h_311(line *Line) { - if nk := conn.st.GetNick(line.Args[1]); nk != nil && !conn.Me().Equals(nk) { + if !line.argslen(5) { + return + } + if nk := conn.st.GetNick(line.Args[1]); (nk != nil) && !conn.Me().Equals(nk) { conn.st.NickInfo(line.Args[1], line.Args[2], line.Args[3], line.Args[5]) } else { logging.Warn("irc.311(): received WHOIS info for unknown nick %s", @@ -134,6 +146,9 @@ func (conn *Conn) h_311(line *Line) { // Handle 324 mode reply func (conn *Conn) h_324(line *Line) { + if !line.argslen(2) { + return + } if ch := conn.st.GetChannel(line.Args[1]); ch != nil { conn.st.ChannelModes(line.Args[1], line.Args[2], line.Args[3:]...) } else { @@ -144,6 +159,9 @@ func (conn *Conn) h_324(line *Line) { // Handle 332 topic reply on join to channel func (conn *Conn) h_332(line *Line) { + if !line.argslen(2) { + return + } if ch := conn.st.GetChannel(line.Args[1]); ch != nil { conn.st.Topic(line.Args[1], line.Args[2]) } else { @@ -154,6 +172,9 @@ func (conn *Conn) h_332(line *Line) { // Handle 352 who reply func (conn *Conn) h_352(line *Line) { + if !line.argslen(5) { + return + } nk := conn.st.GetNick(line.Args[5]) if nk == nil { logging.Warn("irc.352(): received WHO reply for unknown nick %s", @@ -168,6 +189,9 @@ func (conn *Conn) h_352(line *Line) { // last arg contains " " a := strings.SplitN(line.Args[len(line.Args)-1], " ", 2) conn.st.NickInfo(nk.Nick, line.Args[2], line.Args[3], a[1]) + if !line.argslen(6) { + return + } if idx := strings.Index(line.Args[6], "*"); idx != -1 { conn.st.NickModes(nk.Nick, "+o") } @@ -181,6 +205,9 @@ func (conn *Conn) h_352(line *Line) { // Handle 353 names reply func (conn *Conn) h_353(line *Line) { + if !line.argslen(2) { + return + } if ch := conn.st.GetChannel(line.Args[2]); ch != nil { nicks := strings.Split(line.Args[len(line.Args)-1], " ") for _, nick := range nicks { @@ -223,6 +250,9 @@ func (conn *Conn) h_353(line *Line) { // Handle 671 whois reply (nick connected via SSL) func (conn *Conn) h_671(line *Line) { + if !line.argslen(1) { + return + } if nk := conn.st.GetNick(line.Args[1]); nk != nil { conn.st.NickModes(nk.Nick, "+z") } else {