Prevent unauthenticated client from easily consuming lots of memory (CVE-2021-32675)
This change sets a low limit for multibulk and bulk length in the protocol for unauthenticated connections, so that they can't easily cause redis to allocate massive amounts of memory by sending just a few characters on the network. The new limits are 10 arguments of 16kb each (instead of 1m of 512mb)
This commit is contained in:
parent
7cd645a043
commit
c34f970be5
@ -107,6 +107,15 @@ static void clientSetDefaultAuth(client *c) {
|
|||||||
!(c->user->flags & USER_FLAG_DISABLED);
|
!(c->user->flags & USER_FLAG_DISABLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int authRequired(client *c) {
|
||||||
|
/* Check if the user is authenticated. This check is skipped in case
|
||||||
|
* the default user is flagged as "nopass" and is active. */
|
||||||
|
int auth_required = (!(DefaultUser->flags & USER_FLAG_NOPASS) ||
|
||||||
|
(DefaultUser->flags & USER_FLAG_DISABLED)) &&
|
||||||
|
!c->authenticated;
|
||||||
|
return auth_required;
|
||||||
|
}
|
||||||
|
|
||||||
client *createClient(connection *conn) {
|
client *createClient(connection *conn) {
|
||||||
client *c = zmalloc(sizeof(client));
|
client *c = zmalloc(sizeof(client));
|
||||||
|
|
||||||
@ -1860,6 +1869,10 @@ int processMultibulkBuffer(client *c) {
|
|||||||
addReplyError(c,"Protocol error: invalid multibulk length");
|
addReplyError(c,"Protocol error: invalid multibulk length");
|
||||||
setProtocolError("invalid mbulk count",c);
|
setProtocolError("invalid mbulk count",c);
|
||||||
return C_ERR;
|
return C_ERR;
|
||||||
|
} else if (ll > 10 && authRequired(c)) {
|
||||||
|
addReplyError(c, "Protocol error: unauthenticated multibulk length");
|
||||||
|
setProtocolError("unauth mbulk count", c);
|
||||||
|
return C_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
c->qb_pos = (newline-c->querybuf)+2;
|
c->qb_pos = (newline-c->querybuf)+2;
|
||||||
@ -1907,6 +1920,10 @@ int processMultibulkBuffer(client *c) {
|
|||||||
addReplyError(c,"Protocol error: invalid bulk length");
|
addReplyError(c,"Protocol error: invalid bulk length");
|
||||||
setProtocolError("invalid bulk length",c);
|
setProtocolError("invalid bulk length",c);
|
||||||
return C_ERR;
|
return C_ERR;
|
||||||
|
} else if (ll > 16384 && authRequired(c)) {
|
||||||
|
addReplyError(c, "Protocol error: unauthenticated bulk length");
|
||||||
|
setProtocolError("unauth bulk length", c);
|
||||||
|
return C_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
c->qb_pos = newline-c->querybuf+2;
|
c->qb_pos = newline-c->querybuf+2;
|
||||||
|
@ -4001,13 +4001,8 @@ int processCommand(client *c) {
|
|||||||
int is_may_replicate_command = (c->cmd->flags & (CMD_WRITE | CMD_MAY_REPLICATE)) ||
|
int is_may_replicate_command = (c->cmd->flags & (CMD_WRITE | CMD_MAY_REPLICATE)) ||
|
||||||
(c->cmd->proc == execCommand && (c->mstate.cmd_flags & (CMD_WRITE | CMD_MAY_REPLICATE)));
|
(c->cmd->proc == execCommand && (c->mstate.cmd_flags & (CMD_WRITE | CMD_MAY_REPLICATE)));
|
||||||
|
|
||||||
/* Check if the user is authenticated. This check is skipped in case
|
if (authRequired(c)) {
|
||||||
* the default user is flagged as "nopass" and is active. */
|
/* AUTH and HELLO and no auth commands are valid even in
|
||||||
int auth_required = (!(DefaultUser->flags & USER_FLAG_NOPASS) ||
|
|
||||||
(DefaultUser->flags & USER_FLAG_DISABLED)) &&
|
|
||||||
!c->authenticated;
|
|
||||||
if (auth_required) {
|
|
||||||
/* AUTH and HELLO and no auth modules are valid even in
|
|
||||||
* non-authenticated state. */
|
* non-authenticated state. */
|
||||||
if (!(c->cmd->flags & CMD_NO_AUTH)) {
|
if (!(c->cmd->flags & CMD_NO_AUTH)) {
|
||||||
rejectCommand(c,shared.noautherr);
|
rejectCommand(c,shared.noautherr);
|
||||||
|
@ -1897,6 +1897,7 @@ void protectClient(client *c);
|
|||||||
void unprotectClient(client *c);
|
void unprotectClient(client *c);
|
||||||
void initThreadedIO(void);
|
void initThreadedIO(void);
|
||||||
client *lookupClientByID(uint64_t id);
|
client *lookupClientByID(uint64_t id);
|
||||||
|
int authRequired(client *c);
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
void addReplyErrorFormat(client *c, const char *fmt, ...)
|
void addReplyErrorFormat(client *c, const char *fmt, ...)
|
||||||
|
@ -24,6 +24,22 @@ start_server {tags {"auth"} overrides {requirepass foobar}} {
|
|||||||
r set foo 100
|
r set foo 100
|
||||||
r incr foo
|
r incr foo
|
||||||
} {101}
|
} {101}
|
||||||
|
|
||||||
|
test {For unauthenticated clients multibulk and bulk length are limited} {
|
||||||
|
set rr [redis [srv "host"] [srv "port"] 0 $::tls]
|
||||||
|
$rr write "*100\r\n"
|
||||||
|
$rr flush
|
||||||
|
catch {[$rr read]} e
|
||||||
|
assert_match {*unauthenticated multibulk length*} $e
|
||||||
|
$rr close
|
||||||
|
|
||||||
|
set rr [redis [srv "host"] [srv "port"] 0 $::tls]
|
||||||
|
$rr write "*1\r\n\$100000000\r\n"
|
||||||
|
$rr flush
|
||||||
|
catch {[$rr read]} e
|
||||||
|
assert_match {*unauthenticated bulk length*} $e
|
||||||
|
$rr close
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start_server {tags {"auth_binary_password"}} {
|
start_server {tags {"auth_binary_password"}} {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user