Skip to content

Commit 5674b00

Browse files
committed
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)
1 parent bb7597f commit 5674b00

File tree

4 files changed

+36
-7
lines changed

4 files changed

+36
-7
lines changed

Diff for: src/networking.c

+17
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,15 @@ void linkClient(client *c) {
9797
raxInsert(server.clients_index,(unsigned char*)&id,sizeof(id),c,NULL);
9898
}
9999

100+
int authRequired(client *c) {
101+
/* Check if the user is authenticated. This check is skipped in case
102+
* the default user is flagged as "nopass" and is active. */
103+
int auth_required = (!(DefaultUser->flags & USER_FLAG_NOPASS) ||
104+
(DefaultUser->flags & USER_FLAG_DISABLED)) &&
105+
!c->authenticated;
106+
return auth_required;
107+
}
108+
100109
client *createClient(connection *conn) {
101110
client *c = zmalloc(sizeof(client));
102111

@@ -1744,6 +1753,10 @@ int processMultibulkBuffer(client *c) {
17441753
addReplyError(c,"Protocol error: invalid multibulk length");
17451754
setProtocolError("invalid mbulk count",c);
17461755
return C_ERR;
1756+
} else if (ll > 10 && authRequired(c)) {
1757+
addReplyError(c, "Protocol error: unauthenticated multibulk length");
1758+
setProtocolError("unauth mbulk count", c);
1759+
return C_ERR;
17471760
}
17481761

17491762
c->qb_pos = (newline-c->querybuf)+2;
@@ -1791,6 +1804,10 @@ int processMultibulkBuffer(client *c) {
17911804
addReplyError(c,"Protocol error: invalid bulk length");
17921805
setProtocolError("invalid bulk length",c);
17931806
return C_ERR;
1807+
} else if (ll > 16384 && authRequired(c)) {
1808+
addReplyError(c, "Protocol error: unauthenticated bulk length");
1809+
setProtocolError("unauth bulk length", c);
1810+
return C_ERR;
17941811
}
17951812

17961813
c->qb_pos = newline-c->querybuf+2;

Diff for: src/server.c

+2-7
Original file line numberDiff line numberDiff line change
@@ -3590,13 +3590,8 @@ int processCommand(client *c) {
35903590
int is_denyloading_command = !(c->cmd->flags & CMD_LOADING) ||
35913591
(c->cmd->proc == execCommand && (c->mstate.cmd_inv_flags & CMD_LOADING));
35923592

3593-
/* Check if the user is authenticated. This check is skipped in case
3594-
* the default user is flagged as "nopass" and is active. */
3595-
int auth_required = (!(DefaultUser->flags & USER_FLAG_NOPASS) ||
3596-
(DefaultUser->flags & USER_FLAG_DISABLED)) &&
3597-
!c->authenticated;
3598-
if (auth_required) {
3599-
/* AUTH and HELLO and no auth modules are valid even in
3593+
if (authRequired(c)) {
3594+
/* AUTH and HELLO and no auth commands are valid even in
36003595
* non-authenticated state. */
36013596
if (!(c->cmd->flags & CMD_NO_AUTH)) {
36023597
rejectCommand(c,shared.noautherr);

Diff for: src/server.h

+1
Original file line numberDiff line numberDiff line change
@@ -1743,6 +1743,7 @@ void protectClient(client *c);
17431743
void unprotectClient(client *c);
17441744
void initThreadedIO(void);
17451745
client *lookupClientByID(uint64_t id);
1746+
int authRequired(client *c);
17461747

17471748
#ifdef __GNUC__
17481749
void addReplyErrorFormat(client *c, const char *fmt, ...)

Diff for: tests/unit/auth.tcl

+16
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,20 @@ start_server {tags {"auth"} overrides {requirepass foobar}} {
2424
r set foo 100
2525
r incr foo
2626
} {101}
27+
28+
test {For unauthenticated clients multibulk and bulk length are limited} {
29+
set rr [redis [srv "host"] [srv "port"] 0 $::tls]
30+
$rr write "*100\r\n"
31+
$rr flush
32+
catch {[$rr read]} e
33+
assert_match {*unauthenticated multibulk length*} $e
34+
$rr close
35+
36+
set rr [redis [srv "host"] [srv "port"] 0 $::tls]
37+
$rr write "*1\r\n\$100000000\r\n"
38+
$rr flush
39+
catch {[$rr read]} e
40+
assert_match {*unauthenticated bulk length*} $e
41+
$rr close
42+
}
2743
}

0 commit comments

Comments
 (0)