[CHANGED] Enforce max_control_line for client connections only

Only check limit for CLIENT connection types, however, the check
is done for CLIENT in all conditions, not only in the case of a
split buffer as it was the case so far.

Signed-off-by: Ivan Kozlovic <ivan@synadia.com>
This commit is contained in:
Ivan Kozlovic
2021-01-26 15:33:39 -07:00
parent 9716aa8b4c
commit dce814009b
5 changed files with 120 additions and 24 deletions

View File

@@ -259,6 +259,9 @@ func (c *client) parse(buf []byte) error {
} else {
arg = buf[c.as : i-c.drop]
}
if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
return err
}
if trace {
c.traceInOp("HPUB", arg)
}
@@ -319,6 +322,9 @@ func (c *client) parse(buf []byte) error {
} else {
arg = buf[c.as : i-c.drop]
}
if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
return err
}
var err error
if c.kind == ROUTER || c.kind == GATEWAY {
if trace {
@@ -391,6 +397,9 @@ func (c *client) parse(buf []byte) error {
} else {
arg = buf[c.as : i-c.drop]
}
if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
return err
}
if trace {
c.traceInOp("PUB", arg)
}
@@ -508,6 +517,9 @@ func (c *client) parse(buf []byte) error {
} else {
arg = buf[c.as : i-c.drop]
}
if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
return err
}
if trace {
c.traceInOp("A+", arg)
}
@@ -547,6 +559,9 @@ func (c *client) parse(buf []byte) error {
} else {
arg = buf[c.as : i-c.drop]
}
if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
return err
}
if trace {
c.traceInOp("A-", arg)
}
@@ -598,6 +613,9 @@ func (c *client) parse(buf []byte) error {
} else {
arg = buf[c.as : i-c.drop]
}
if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
return err
}
var err error
switch c.kind {
@@ -730,6 +748,9 @@ func (c *client) parse(buf []byte) error {
} else {
arg = buf[c.as : i-c.drop]
}
if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
return err
}
var err error
switch c.kind {
@@ -876,6 +897,9 @@ func (c *client) parse(buf []byte) error {
} else {
arg = buf[c.as : i-c.drop]
}
if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
return err
}
if trace {
c.traceInOp("CONNECT", removePassFromTrace(arg))
}
@@ -934,6 +958,9 @@ func (c *client) parse(buf []byte) error {
} else {
arg = buf[c.as : i-c.drop]
}
if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
return err
}
var err error
if c.kind == ROUTER || c.kind == GATEWAY {
switch c.op {
@@ -1010,6 +1037,9 @@ func (c *client) parse(buf []byte) error {
} else {
arg = buf[c.as : i-c.drop]
}
if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
return err
}
if err := c.processInfo(arg); err != nil {
return err
}
@@ -1086,6 +1116,9 @@ func (c *client) parse(buf []byte) error {
} else {
arg = buf[c.as : i-c.drop]
}
if err := c.overMaxControlLineLimit(arg, mcl); err != nil {
return err
}
c.processErr(string(arg))
c.drop, c.as, c.state = 0, i+1, OP_START
default:
@@ -1113,11 +1146,7 @@ func (c *client) parse(buf []byte) error {
// Check for violations of control line length here. Note that this is not
// exact at all but the performance hit is too great to be precise, and
// catching here should prevent memory exhaustion attacks.
if len(c.argBuf) > int(mcl) {
err := NewErrorCtx(ErrMaxControlLine, "State %d, max_control_line %d, Buffer len %d",
c.state, int(mcl), len(c.argBuf))
c.sendErr(err.Error())
c.closeConnection(MaxControlLineExceeded)
if err := c.overMaxControlLineLimit(c.argBuf, mcl); err != nil {
return err
}
}
@@ -1160,13 +1189,13 @@ authErr:
parseErr:
c.sendErr("Unknown Protocol Operation")
snip := protoSnippet(i, buf)
snip := protoSnippet(i, PROTO_SNIPPET_SIZE, buf)
err := fmt.Errorf("%s parser ERROR, state=%d, i=%d: proto='%s...'", c.typeString(), c.state, i, snip)
return err
}
func protoSnippet(start int, buf []byte) string {
stop := start + PROTO_SNIPPET_SIZE
func protoSnippet(start, max int, buf []byte) string {
stop := start + max
bufSize := len(buf)
if start >= bufSize {
return `""`
@@ -1177,6 +1206,23 @@ func protoSnippet(start int, buf []byte) string {
return fmt.Sprintf("%q", buf[start:stop])
}
// Check if the length of buffer `arg` is over the max control line limit `mcl`.
// If so, an error is sent to the client and the connection is closed.
// The error ErrMaxControlLine is returned.
func (c *client) overMaxControlLineLimit(arg []byte, mcl int32) error {
if c.kind != CLIENT {
return nil
}
if len(arg) > int(mcl) {
err := NewErrorCtx(ErrMaxControlLine, "State %d, max_control_line %d, Buffer len %d (snip: %s...)",
c.state, int(mcl), len(c.argBuf), protoSnippet(0, MAX_CONTOL_LINE_SNIPPET_SIZE, arg))
c.sendErr(err.Error())
c.closeConnection(MaxControlLineExceeded)
return err
}
return nil
}
// clonePubArg is used when the split buffer scenario has the pubArg in the existing read buffer, but
// we need to hold onto it into the next read.
func (c *client) clonePubArg(lmsg bool) error {