From 3db50f47966fc0fea599163f5452d8299b2562c9 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 6 Apr 2022 13:49:52 +0930 Subject: [PATCH] commando: limit total request size. 1MB normally, but 10MB if you have a cached rune. Signed-off-by: Rusty Russell --- commando/commando.py | 25 ++++++++++++++++++++++++- commando/test_commando.py | 7 +++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/commando/commando.py b/commando/commando.py index bdf006e..b965df6 100755 --- a/commando/commando.py +++ b/commando/commando.py @@ -51,9 +51,15 @@ class InReq: def __init__(self, idnum): self.idnum = idnum self.buf = b'' + self.discard = False def append(self, data): - self.buf += data + if not self.discard: + self.buf += data + + def start_discard(self): + self.buf = b'' + self.discard = True def split_cmd(cmdstr): @@ -204,11 +210,28 @@ def on_custommsg(peer_id, payload, plugin, request, **kwargs): if peer_id not in plugin.in_reqs or idnum != plugin.in_reqs[peer_id].idnum: plugin.in_reqs[peer_id] = InReq(idnum) plugin.in_reqs[peer_id].append(data) + + # If you have cached a rune, give 10MB, otherwise 1MB. + # We can have hundreds of these things... + max_cmdlen = 1000000 + if peer_id in plugin.peer_runes: + max_cmdlen *= 10 + + if len(plugin.in_reqs[peer_id].buf) > max_cmdlen: + plugin.in_reqs[peer_id].start_discard() elif mtype == COMMANDO_CMD_TERM: # Prepend any prior data from COMMANDO_CMD_CONTINUES: if peer_id in plugin.in_reqs: data = plugin.in_reqs[peer_id].buf + data + discard = plugin.in_reqs[peer_id].discard del plugin.in_reqs[peer_id] + # Were we ignoring this for being too long? Error out now. + if discard: + send_result(plugin, peer_id, idnum, + {'error': "Command too long"}) + request.set_result({'result': 'continue'}) + return + method, params, runestr = split_cmd(data) try_command(plugin, peer_id, idnum, method, params, runestr) elif mtype == COMMANDO_REPLY_CONTINUES: diff --git a/commando/test_commando.py b/commando/test_commando.py index e162ba8..1fad1cf 100755 --- a/commando/test_commando.py +++ b/commando/test_commando.py @@ -316,3 +316,10 @@ def test_megacmd(node_factory): 'method': 'get' + 'x' * 130000, 'rune': rrune, 'params': {}}) + + with pytest.raises(RpcError, match='Command too long'): + l1.rpc.call(method='commando', + payload={'peer_id': l2.info['id'], + 'method': 'get' + 'x' * 1100000, + 'rune': rrune, + 'params': {}})