Improve dbid range check for SELECT, MOVE, COPY (#8085)

SELECT used to read the index into a `long` variable, and then pass it to a function
that takes an `int`, possibly causing an overflow before the range check.

Now all these commands use better and cleaner range check, and that also results in
a slight change of the error response in case of an invalid database index.

SELECT:
in the past it would have returned either `-ERR invalid DB index` (if not a number),
or `-ERR DB index is out of range` (if not between 1..16 or alike).
now it'll return either `-ERR value is out of range` (if not a number), or
`-ERR value is out of range, value must between -2147483648 and 2147483647`
(if not in the range for an int), or `-ERR DB index is out of range`
(if not between 0..16 or alike)


MOVE:
in the past it would only fail with `-ERR index out of range` no matter the reason.
now return the same errors as the new ones for SELECT mentioned above.
(i.e. unlike for SELECT even for a value like 17 we changed the error message)

COPY:
doesn't really matter how it behaved in the past (new command), new behavior is
like the above two.
This commit is contained in:
sundb 2020-12-02 03:41:26 +08:00 committed by GitHub
parent c1b1e8c329
commit 3ba2281f96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 29 additions and 19 deletions

View File

@ -600,10 +600,9 @@ void existsCommand(client *c) {
} }
void selectCommand(client *c) { void selectCommand(client *c) {
long id; int id;
if (getLongFromObjectOrReply(c, c->argv[1], &id, if (getIntFromObjectOrReply(c, c->argv[1], &id, NULL) != C_OK)
"invalid DB index") != C_OK)
return; return;
if (server.cluster_enabled && id != 0) { if (server.cluster_enabled && id != 0) {
@ -1022,8 +1021,8 @@ void renamenxCommand(client *c) {
void moveCommand(client *c) { void moveCommand(client *c) {
robj *o; robj *o;
redisDb *src, *dst; redisDb *src, *dst;
int srcid; int srcid, dbid;
long long dbid, expire; long long expire;
if (server.cluster_enabled) { if (server.cluster_enabled) {
addReplyError(c,"MOVE is not allowed in cluster mode"); addReplyError(c,"MOVE is not allowed in cluster mode");
@ -1034,11 +1033,11 @@ void moveCommand(client *c) {
src = c->db; src = c->db;
srcid = c->db->id; srcid = c->db->id;
if (getLongLongFromObject(c->argv[2],&dbid) == C_ERR || if (getIntFromObjectOrReply(c, c->argv[2], &dbid, NULL) != C_OK)
dbid < INT_MIN || dbid > INT_MAX || return;
selectDb(c,dbid) == C_ERR)
{ if (selectDb(c,dbid) == C_ERR) {
addReply(c,shared.outofrangeerr); addReplyError(c,"DB index is out of range");
return; return;
} }
dst = c->db; dst = c->db;
@ -1084,8 +1083,8 @@ void moveCommand(client *c) {
void copyCommand(client *c) { void copyCommand(client *c) {
robj *o; robj *o;
redisDb *src, *dst; redisDb *src, *dst;
int srcid; int srcid, dbid;
long long dbid, expire; long long expire;
int j, replace = 0, delete = 0; int j, replace = 0, delete = 0;
/* Obtain source and target DB pointers /* Obtain source and target DB pointers
@ -1100,11 +1099,11 @@ void copyCommand(client *c) {
if (!strcasecmp(c->argv[j]->ptr,"replace")) { if (!strcasecmp(c->argv[j]->ptr,"replace")) {
replace = 1; replace = 1;
} else if (!strcasecmp(c->argv[j]->ptr, "db") && additional >= 1) { } else if (!strcasecmp(c->argv[j]->ptr, "db") && additional >= 1) {
if (getLongLongFromObject(c->argv[j+1], &dbid) == C_ERR || if (getIntFromObjectOrReply(c, c->argv[j+1], &dbid, NULL) != C_OK)
dbid < INT_MIN || dbid > INT_MAX || return;
selectDb(c, dbid) == C_ERR)
{ if (selectDb(c, dbid) == C_ERR) {
addReplyError(c,"invalid DB index"); addReplyError(c,"DB index is out of range");
return; return;
} }
dst = c->db; dst = c->db;

View File

@ -747,6 +747,16 @@ int getPositiveLongFromObjectOrReply(client *c, robj *o, long *target, const cha
return getRangeLongFromObjectOrReply(c, o, 0, LONG_MAX, target, msg); return getRangeLongFromObjectOrReply(c, o, 0, LONG_MAX, target, msg);
} }
int getIntFromObjectOrReply(client *c, robj *o, int *target, const char *msg) {
long value;
if (getRangeLongFromObjectOrReply(c, o, INT_MIN, INT_MAX, &value, msg) != C_OK)
return C_ERR;
*target = value;
return C_OK;
}
char *strEncoding(int encoding) { char *strEncoding(int encoding) {
switch(encoding) { switch(encoding) {
case OBJ_ENCODING_RAW: return "raw"; case OBJ_ENCODING_RAW: return "raw";

View File

@ -1872,6 +1872,7 @@ int getDoubleFromObject(const robj *o, double *target);
int getLongLongFromObject(robj *o, long long *target); int getLongLongFromObject(robj *o, long long *target);
int getLongDoubleFromObject(robj *o, long double *target); int getLongDoubleFromObject(robj *o, long double *target);
int getLongDoubleFromObjectOrReply(client *c, robj *o, long double *target, const char *msg); int getLongDoubleFromObjectOrReply(client *c, robj *o, long double *target, const char *msg);
int getIntFromObjectOrReply(client *c, robj *o, int *target, const char *msg);
char *strEncoding(int encoding); char *strEncoding(int encoding);
int compareStringObjects(robj *a, robj *b); int compareStringObjects(robj *a, robj *b);
int collateStringObjects(robj *a, robj *b); int collateStringObjects(robj *a, robj *b);

View File

@ -217,7 +217,7 @@ start_server {tags {"keyspace"}} {
r set mykey foobar r set mykey foobar
catch {r copy mykey mynewkey DB notanumber} e catch {r copy mykey mynewkey DB notanumber} e
set e set e
} {*ERR*invalid DB index} } {ERR value is not an integer or out of range}
test {COPY can copy key expire metadata as well} { test {COPY can copy key expire metadata as well} {
r set mykey foobar ex 100 r set mykey foobar ex 100
@ -398,7 +398,7 @@ start_server {tags {"keyspace"}} {
r set mykey hello r set mykey hello
catch {r move mykey notanumber} e catch {r move mykey notanumber} e
set e set e
} {*ERR*index out of range} } {ERR value is not an integer or out of range}
test {MOVE can move key expire metadata as well} { test {MOVE can move key expire metadata as well} {
r select 10 r select 10