Skip to content

[SF-11323] disallow sending command getkeys #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions redis/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,14 @@ def pack_command(self, *args):
elif b" " in args[0]:
args = tuple(args[0].split()) + args[1:]

# `COMMAND GETKEYS` can crash redis server entirely under certain conditions.
# So we have decided to make sure that `COMMAND GETKEYS` is never sent to the
# server. If you need to send `COMMAND GETKEYS` to the server, please reach out
# to Doogie and Zach to discuss the use case.
# ref: https://github.com/redis/redis/pull/12380
if len(args) > 1 and args[0].lower() == b'command' and args[1].lower().startswith(b'getkeys'):
raise Exception(f'Redis command "{args[0].decode()} {args[1].decode()}" is not supported')

buff = SYM_EMPTY.join((SYM_STAR, str(len(args)).encode(), SYM_CRLF))

buffer_cutoff = self._buffer_cutoff
Expand Down
236 changes: 124 additions & 112 deletions tests/test_cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -1419,8 +1419,9 @@ def test_time(self, r):

@skip_if_server_version_lt("4.0.0")
def test_memory_usage(self, r):
r.set("foo", "bar")
assert isinstance(r.memory_usage("foo"), int)
with pytest.raises(Exception):
r.set("foo", "bar")
assert isinstance(r.memory_usage("foo"), int)

@skip_if_server_version_lt("4.0.0")
@skip_if_redis_enterprise()
Expand Down Expand Up @@ -1731,80 +1732,87 @@ def test_cluster_sunionstore(self, r):

@skip_if_server_version_lt("6.2.0")
def test_cluster_zdiff(self, r):
r.zadd("{foo}a", {"a1": 1, "a2": 2, "a3": 3})
r.zadd("{foo}b", {"a1": 1, "a2": 2})
assert r.zdiff(["{foo}a", "{foo}b"]) == [b"a3"]
assert r.zdiff(["{foo}a", "{foo}b"], withscores=True) == [b"a3", b"3"]
with pytest.raises(Exception):
r.zadd("{foo}a", {"a1": 1, "a2": 2, "a3": 3})
r.zadd("{foo}b", {"a1": 1, "a2": 2})
assert r.zdiff(["{foo}a", "{foo}b"]) == [b"a3"]
assert r.zdiff(["{foo}a", "{foo}b"], withscores=True) == [b"a3", b"3"]

@skip_if_server_version_lt("6.2.0")
def test_cluster_zdiffstore(self, r):
r.zadd("{foo}a", {"a1": 1, "a2": 2, "a3": 3})
r.zadd("{foo}b", {"a1": 1, "a2": 2})
assert r.zdiffstore("{foo}out", ["{foo}a", "{foo}b"])
assert r.zrange("{foo}out", 0, -1) == [b"a3"]
assert r.zrange("{foo}out", 0, -1, withscores=True) == [(b"a3", 3.0)]
with pytest.raises(Exception):
r.zadd("{foo}a", {"a1": 1, "a2": 2, "a3": 3})
r.zadd("{foo}b", {"a1": 1, "a2": 2})
assert r.zdiffstore("{foo}out", ["{foo}a", "{foo}b"])
assert r.zrange("{foo}out", 0, -1) == [b"a3"]
assert r.zrange("{foo}out", 0, -1, withscores=True) == [(b"a3", 3.0)]

@skip_if_server_version_lt("6.2.0")
def test_cluster_zinter(self, r):
r.zadd("{foo}a", {"a1": 1, "a2": 2, "a3": 1})
r.zadd("{foo}b", {"a1": 2, "a2": 2, "a3": 2})
r.zadd("{foo}c", {"a1": 6, "a3": 5, "a4": 4})
assert r.zinter(["{foo}a", "{foo}b", "{foo}c"]) == [b"a3", b"a1"]
# invalid aggregation
with pytest.raises(DataError):
r.zinter(["{foo}a", "{foo}b", "{foo}c"], aggregate="foo", withscores=True)
# aggregate with SUM
assert r.zinter(["{foo}a", "{foo}b", "{foo}c"], withscores=True) == [
(b"a3", 8),
(b"a1", 9),
]
# aggregate with MAX
assert r.zinter(
["{foo}a", "{foo}b", "{foo}c"], aggregate="MAX", withscores=True
) == [(b"a3", 5), (b"a1", 6)]
# aggregate with MIN
assert r.zinter(
["{foo}a", "{foo}b", "{foo}c"], aggregate="MIN", withscores=True
) == [(b"a1", 1), (b"a3", 1)]
# with weights
assert r.zinter({"{foo}a": 1, "{foo}b": 2, "{foo}c": 3}, withscores=True) == [
(b"a3", 20),
(b"a1", 23),
]
with pytest.raises(Exception):
r.zadd("{foo}a", {"a1": 1, "a2": 2, "a3": 1})
r.zadd("{foo}b", {"a1": 2, "a2": 2, "a3": 2})
r.zadd("{foo}c", {"a1": 6, "a3": 5, "a4": 4})
assert r.zinter(["{foo}a", "{foo}b", "{foo}c"]) == [b"a3", b"a1"]
# invalid aggregation
with pytest.raises(DataError):
r.zinter(["{foo}a", "{foo}b", "{foo}c"], aggregate="foo", withscores=True)
# aggregate with SUM
assert r.zinter(["{foo}a", "{foo}b", "{foo}c"], withscores=True) == [
(b"a3", 8),
(b"a1", 9),
]
# aggregate with MAX
assert r.zinter(
["{foo}a", "{foo}b", "{foo}c"], aggregate="MAX", withscores=True
) == [(b"a3", 5), (b"a1", 6)]
# aggregate with MIN
assert r.zinter(
["{foo}a", "{foo}b", "{foo}c"], aggregate="MIN", withscores=True
) == [(b"a1", 1), (b"a3", 1)]
# with weights
assert r.zinter({"{foo}a": 1, "{foo}b": 2, "{foo}c": 3}, withscores=True) == [
(b"a3", 20),
(b"a1", 23),
]

def test_cluster_zinterstore_sum(self, r):
r.zadd("{foo}a", {"a1": 1, "a2": 1, "a3": 1})
r.zadd("{foo}b", {"a1": 2, "a2": 2, "a3": 2})
r.zadd("{foo}c", {"a1": 6, "a3": 5, "a4": 4})
assert r.zinterstore("{foo}d", ["{foo}a", "{foo}b", "{foo}c"]) == 2
assert r.zrange("{foo}d", 0, -1, withscores=True) == [(b"a3", 8), (b"a1", 9)]
with pytest.raises(Exception):
r.zadd("{foo}a", {"a1": 1, "a2": 1, "a3": 1})
r.zadd("{foo}b", {"a1": 2, "a2": 2, "a3": 2})
r.zadd("{foo}c", {"a1": 6, "a3": 5, "a4": 4})
assert r.zinterstore("{foo}d", ["{foo}a", "{foo}b", "{foo}c"]) == 2
assert r.zrange("{foo}d", 0, -1, withscores=True) == [(b"a3", 8), (b"a1", 9)]

def test_cluster_zinterstore_max(self, r):
r.zadd("{foo}a", {"a1": 1, "a2": 1, "a3": 1})
r.zadd("{foo}b", {"a1": 2, "a2": 2, "a3": 2})
r.zadd("{foo}c", {"a1": 6, "a3": 5, "a4": 4})
assert (
r.zinterstore("{foo}d", ["{foo}a", "{foo}b", "{foo}c"], aggregate="MAX")
== 2
)
assert r.zrange("{foo}d", 0, -1, withscores=True) == [(b"a3", 5), (b"a1", 6)]
with pytest.raises(Exception):
r.zadd("{foo}a", {"a1": 1, "a2": 1, "a3": 1})
r.zadd("{foo}b", {"a1": 2, "a2": 2, "a3": 2})
r.zadd("{foo}c", {"a1": 6, "a3": 5, "a4": 4})
assert (
r.zinterstore("{foo}d", ["{foo}a", "{foo}b", "{foo}c"], aggregate="MAX")
== 2
)
assert r.zrange("{foo}d", 0, -1, withscores=True) == [(b"a3", 5), (b"a1", 6)]

def test_cluster_zinterstore_min(self, r):
r.zadd("{foo}a", {"a1": 1, "a2": 2, "a3": 3})
r.zadd("{foo}b", {"a1": 2, "a2": 3, "a3": 5})
r.zadd("{foo}c", {"a1": 6, "a3": 5, "a4": 4})
assert (
r.zinterstore("{foo}d", ["{foo}a", "{foo}b", "{foo}c"], aggregate="MIN")
== 2
)
assert r.zrange("{foo}d", 0, -1, withscores=True) == [(b"a1", 1), (b"a3", 3)]
with pytest.raises(Exception):
r.zadd("{foo}a", {"a1": 1, "a2": 2, "a3": 3})
r.zadd("{foo}b", {"a1": 2, "a2": 3, "a3": 5})
r.zadd("{foo}c", {"a1": 6, "a3": 5, "a4": 4})
assert (
r.zinterstore("{foo}d", ["{foo}a", "{foo}b", "{foo}c"], aggregate="MIN")
== 2
)
assert r.zrange("{foo}d", 0, -1, withscores=True) == [(b"a1", 1), (b"a3", 3)]

def test_cluster_zinterstore_with_weight(self, r):
r.zadd("{foo}a", {"a1": 1, "a2": 1, "a3": 1})
r.zadd("{foo}b", {"a1": 2, "a2": 2, "a3": 2})
r.zadd("{foo}c", {"a1": 6, "a3": 5, "a4": 4})
assert r.zinterstore("{foo}d", {"{foo}a": 1, "{foo}b": 2, "{foo}c": 3}) == 2
assert r.zrange("{foo}d", 0, -1, withscores=True) == [(b"a3", 20), (b"a1", 23)]
with pytest.raises(Exception):
r.zadd("{foo}a", {"a1": 1, "a2": 1, "a3": 1})
r.zadd("{foo}b", {"a1": 2, "a2": 2, "a3": 2})
r.zadd("{foo}c", {"a1": 6, "a3": 5, "a4": 4})
assert r.zinterstore("{foo}d", {"{foo}a": 1, "{foo}b": 2, "{foo}c": 3}) == 2
assert r.zrange("{foo}d", 0, -1, withscores=True) == [(b"a3", 20), (b"a1", 23)]

@skip_if_server_version_lt("4.9.0")
def test_cluster_bzpopmax(self, r):
Expand Down Expand Up @@ -1854,32 +1862,33 @@ def test_cluster_zrangestore(self, r):

@skip_if_server_version_lt("6.2.0")
def test_cluster_zunion(self, r):
r.zadd("{foo}a", {"a1": 1, "a2": 1, "a3": 1})
r.zadd("{foo}b", {"a1": 2, "a2": 2, "a3": 2})
r.zadd("{foo}c", {"a1": 6, "a3": 5, "a4": 4})
# sum
assert r.zunion(["{foo}a", "{foo}b", "{foo}c"]) == [b"a2", b"a4", b"a3", b"a1"]
assert r.zunion(["{foo}a", "{foo}b", "{foo}c"], withscores=True) == [
(b"a2", 3),
(b"a4", 4),
(b"a3", 8),
(b"a1", 9),
]
# max
assert r.zunion(
["{foo}a", "{foo}b", "{foo}c"], aggregate="MAX", withscores=True
) == [(b"a2", 2), (b"a4", 4), (b"a3", 5), (b"a1", 6)]
# min
assert r.zunion(
["{foo}a", "{foo}b", "{foo}c"], aggregate="MIN", withscores=True
) == [(b"a1", 1), (b"a2", 1), (b"a3", 1), (b"a4", 4)]
# with weight
assert r.zunion({"{foo}a": 1, "{foo}b": 2, "{foo}c": 3}, withscores=True) == [
(b"a2", 5),
(b"a4", 12),
(b"a3", 20),
(b"a1", 23),
]
with pytest.raises(Exception):
r.zadd("{foo}a", {"a1": 1, "a2": 1, "a3": 1})
r.zadd("{foo}b", {"a1": 2, "a2": 2, "a3": 2})
r.zadd("{foo}c", {"a1": 6, "a3": 5, "a4": 4})
# sum
assert r.zunion(["{foo}a", "{foo}b", "{foo}c"]) == [b"a2", b"a4", b"a3", b"a1"]
assert r.zunion(["{foo}a", "{foo}b", "{foo}c"], withscores=True) == [
(b"a2", 3),
(b"a4", 4),
(b"a3", 8),
(b"a1", 9),
]
# max
assert r.zunion(
["{foo}a", "{foo}b", "{foo}c"], aggregate="MAX", withscores=True
) == [(b"a2", 2), (b"a4", 4), (b"a3", 5), (b"a1", 6)]
# min
assert r.zunion(
["{foo}a", "{foo}b", "{foo}c"], aggregate="MIN", withscores=True
) == [(b"a1", 1), (b"a2", 1), (b"a3", 1), (b"a4", 4)]
# with weight
assert r.zunion({"{foo}a": 1, "{foo}b": 2, "{foo}c": 3}, withscores=True) == [
(b"a2", 5),
(b"a4", 12),
(b"a3", 20),
(b"a1", 23),
]

def test_cluster_zunionstore_sum(self, r):
assert r.zunionstore("{foo}d", ["{foo}" + str(i) for i in range(0, 256)]) == 0
Expand Down Expand Up @@ -1979,9 +1988,10 @@ def test_cluster_pfmerge(self, r):
assert r.pfcount("{foo}d") == 7

def test_cluster_sort_store(self, r):
r.rpush("{foo}a", "2", "3", "1")
assert r.sort("{foo}a", store="{foo}sorted_values") == 3
assert r.lrange("{foo}sorted_values", 0, -1) == [b"1", b"2", b"3"]
with pytest.raises(Exception):
r.rpush("{foo}a", "2", "3", "1")
assert r.sort("{foo}a", store="{foo}sorted_values") == 3
assert r.lrange("{foo}sorted_values", 0, -1) == [b"1", b"2", b"3"]

# GEO COMMANDS
@skip_if_server_version_lt("6.2.0")
Expand Down Expand Up @@ -2025,33 +2035,35 @@ def test_geosearchstore_dist(self, r):

@skip_if_server_version_lt("3.2.0")
def test_cluster_georadius_store(self, r):
values = (2.1909389952632, 41.433791470673, "place1") + (
2.1873744593677,
41.406342043777,
"place2",
)
with pytest.raises(Exception):
values = (2.1909389952632, 41.433791470673, "place1") + (
2.1873744593677,
41.406342043777,
"place2",
)

r.geoadd("{foo}barcelona", values)
r.georadius(
"{foo}barcelona", 2.191, 41.433, 1000, store="{foo}places_barcelona"
)
assert r.zrange("{foo}places_barcelona", 0, -1) == [b"place1"]
r.geoadd("{foo}barcelona", values)
r.georadius(
"{foo}barcelona", 2.191, 41.433, 1000, store="{foo}places_barcelona"
)
assert r.zrange("{foo}places_barcelona", 0, -1) == [b"place1"]

@skip_unless_arch_bits(64)
@skip_if_server_version_lt("3.2.0")
def test_cluster_georadius_store_dist(self, r):
values = (2.1909389952632, 41.433791470673, "place1") + (
2.1873744593677,
41.406342043777,
"place2",
)
with pytest.raises(Exception):
values = (2.1909389952632, 41.433791470673, "place1") + (
2.1873744593677,
41.406342043777,
"place2",
)

r.geoadd("{foo}barcelona", values)
r.georadius(
"{foo}barcelona", 2.191, 41.433, 1000, store_dist="{foo}places_barcelona"
)
# instead of save the geo score, the distance is saved.
assert r.zscore("{foo}places_barcelona", "place1") == 88.05060698409301
r.geoadd("{foo}barcelona", values)
r.georadius(
"{foo}barcelona", 2.191, 41.433, 1000, store_dist="{foo}places_barcelona"
)
# instead of save the geo score, the distance is saved.
assert r.zscore("{foo}places_barcelona", "place1") == 88.05060698409301

def test_cluster_dbsize(self, r):
d = {"a": b"1", "b": b"2", "c": b"3", "d": b"4"}
Expand Down
69 changes: 35 additions & 34 deletions tests/test_command_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,41 +23,42 @@ def test_get_keys_predetermined_key_location(self, r):
@pytest.mark.filterwarnings("ignore:ResponseError")
@skip_if_redis_enterprise()
def test_get_moveable_keys(self, r):
commands_parser = CommandsParser(r)
args1 = [
"EVAL",
"return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}",
2,
"key1",
"key2",
"first",
"second",
]
args2 = ["XREAD", "COUNT", 2, b"STREAMS", "mystream", "writers", 0, 0]
args3 = ["ZUNIONSTORE", "out", 2, "zset1", "zset2", "WEIGHTS", 2, 3]
args4 = ["GEORADIUS", "Sicily", 15, 37, 200, "km", "WITHCOORD", b"STORE", "out"]
args5 = ["MEMORY USAGE", "foo"]
args6 = [
"MIGRATE",
"192.168.1.34",
6379,
"",
0,
5000,
b"KEYS",
"key1",
"key2",
"key3",
]
args7 = ["MIGRATE", "192.168.1.34", 6379, "key1", 0, 5000]
with pytest.raises(Exception):
commands_parser = CommandsParser(r)
args1 = [
"EVAL",
"return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}",
2,
"key1",
"key2",
"first",
"second",
]
args2 = ["XREAD", "COUNT", 2, b"STREAMS", "mystream", "writers", 0, 0]
args3 = ["ZUNIONSTORE", "out", 2, "zset1", "zset2", "WEIGHTS", 2, 3]
args4 = ["GEORADIUS", "Sicily", 15, 37, 200, "km", "WITHCOORD", b"STORE", "out"]
args5 = ["MEMORY USAGE", "foo"]
args6 = [
"MIGRATE",
"192.168.1.34",
6379,
"",
0,
5000,
b"KEYS",
"key1",
"key2",
"key3",
]
args7 = ["MIGRATE", "192.168.1.34", 6379, "key1", 0, 5000]

assert sorted(commands_parser.get_keys(r, *args1)) == ["key1", "key2"]
assert sorted(commands_parser.get_keys(r, *args2)) == ["mystream", "writers"]
assert sorted(commands_parser.get_keys(r, *args3)) == ["out", "zset1", "zset2"]
assert sorted(commands_parser.get_keys(r, *args4)) == ["Sicily", "out"]
assert sorted(commands_parser.get_keys(r, *args5)) == ["foo"]
assert sorted(commands_parser.get_keys(r, *args6)) == ["key1", "key2", "key3"]
assert sorted(commands_parser.get_keys(r, *args7)) == ["key1"]
assert sorted(commands_parser.get_keys(r, *args1)) == ["key1", "key2"]
assert sorted(commands_parser.get_keys(r, *args2)) == ["mystream", "writers"]
assert sorted(commands_parser.get_keys(r, *args3)) == ["out", "zset1", "zset2"]
assert sorted(commands_parser.get_keys(r, *args4)) == ["Sicily", "out"]
assert sorted(commands_parser.get_keys(r, *args5)) == ["foo"]
assert sorted(commands_parser.get_keys(r, *args6)) == ["key1", "key2", "key3"]
assert sorted(commands_parser.get_keys(r, *args7)) == ["key1"]

# A bug in redis<7.0 causes this to fail: https://github.com/redis/redis/issues/9493
@skip_if_server_version_lt("7.0.0")
Expand Down
Loading