|
|
dbfe2d |
From 734b41ff166263c364e89518eb46e52310eb070b Mon Sep 17 00:00:00 2001
|
|
|
dbfe2d |
From: Boris Burkov <borisb@fb.com>
|
|
|
dbfe2d |
Date: Fri, 21 Aug 2020 00:40:02 -0700
|
|
|
dbfe2d |
Subject: [PATCH] btrfs-progs: receive: support v2 send stream DATA tlv format
|
|
|
dbfe2d |
|
|
|
dbfe2d |
The new format privileges the BTRFS_SEND_A_DATA attribute by
|
|
|
dbfe2d |
guaranteeing it will always be the last attribute in any command that
|
|
|
dbfe2d |
needs it, and by implicitly encoding the data length as the difference
|
|
|
dbfe2d |
between the total command length in the command header and the sizes of
|
|
|
dbfe2d |
the rest of the attributes (and of course the tlv_type identifying the
|
|
|
dbfe2d |
DATA attribute). To parse the new stream, we must read the tlv_type and
|
|
|
dbfe2d |
if it is not DATA, we proceed normally, but if it is DATA, we don't
|
|
|
dbfe2d |
parse a tlv_len but simply compute the length.
|
|
|
dbfe2d |
|
|
|
dbfe2d |
In addition, we add some bounds checking when parsing each chunk of
|
|
|
dbfe2d |
data, as well as for the tlv_len itself.
|
|
|
dbfe2d |
|
|
|
dbfe2d |
Reviewed-by: Nikolay Borisov <nborisov@suse.com>
|
|
|
dbfe2d |
Signed-off-by: Boris Burkov <boris@bur.io>
|
|
|
dbfe2d |
---
|
|
|
dbfe2d |
common/send-stream.c | 36 ++++++++++++++++++++++++++----------
|
|
|
dbfe2d |
1 file changed, 26 insertions(+), 10 deletions(-)
|
|
|
dbfe2d |
|
|
|
dbfe2d |
diff --git a/common/send-stream.c b/common/send-stream.c
|
|
|
dbfe2d |
index 421cd1bb..81a830d9 100644
|
|
|
dbfe2d |
--- a/common/send-stream.c
|
|
|
dbfe2d |
+++ b/common/send-stream.c
|
|
|
dbfe2d |
@@ -168,28 +168,44 @@ static int read_cmd(struct btrfs_send_stream *sctx)
|
|
|
dbfe2d |
|
|
|
dbfe2d |
pos = 0;
|
|
|
dbfe2d |
while (pos < cmd_len) {
|
|
|
dbfe2d |
- struct btrfs_tlv_header *tlv_hdr;
|
|
|
dbfe2d |
u16 tlv_type;
|
|
|
dbfe2d |
- u16 tlv_len;
|
|
|
dbfe2d |
struct btrfs_send_attribute *send_attr;
|
|
|
dbfe2d |
|
|
|
dbfe2d |
- tlv_hdr = (struct btrfs_tlv_header *)data;
|
|
|
dbfe2d |
- tlv_type = le16_to_cpu(tlv_hdr->tlv_type);
|
|
|
dbfe2d |
- tlv_len = le16_to_cpu(tlv_hdr->tlv_len);
|
|
|
dbfe2d |
+ if (cmd_len - pos < sizeof(__le16)) {
|
|
|
dbfe2d |
+ error("send stream is truncated");
|
|
|
dbfe2d |
+ ret = -EINVAL;
|
|
|
dbfe2d |
+ goto out;
|
|
|
dbfe2d |
+ }
|
|
|
dbfe2d |
+ tlv_type = le16_to_cpu(*(__le16 *)data);
|
|
|
dbfe2d |
|
|
|
dbfe2d |
if (tlv_type == 0 || tlv_type > BTRFS_SEND_A_MAX) {
|
|
|
dbfe2d |
- error("invalid tlv in cmd tlv_type = %hu, tlv_len = %hu",
|
|
|
dbfe2d |
- tlv_type, tlv_len);
|
|
|
dbfe2d |
+ error("invalid tlv in cmd tlv_type = %hu", tlv_type);
|
|
|
dbfe2d |
ret = -EINVAL;
|
|
|
dbfe2d |
goto out;
|
|
|
dbfe2d |
}
|
|
|
dbfe2d |
|
|
|
dbfe2d |
send_attr = &sctx->cmd_attrs[tlv_type];
|
|
|
dbfe2d |
send_attr->tlv_type = tlv_type;
|
|
|
dbfe2d |
- send_attr->tlv_len = tlv_len;
|
|
|
dbfe2d |
- pos += sizeof(*tlv_hdr);
|
|
|
dbfe2d |
- data += sizeof(*tlv_hdr);
|
|
|
dbfe2d |
|
|
|
dbfe2d |
+ pos += sizeof(tlv_type);
|
|
|
dbfe2d |
+ data += sizeof(tlv_type);
|
|
|
dbfe2d |
+ if (sctx->version >= 2 && tlv_type == BTRFS_SEND_A_DATA) {
|
|
|
dbfe2d |
+ send_attr->tlv_len = cmd_len - pos;
|
|
|
dbfe2d |
+ } else {
|
|
|
dbfe2d |
+ if (cmd_len - pos < sizeof(__le16)) {
|
|
|
dbfe2d |
+ error("send stream is truncated");
|
|
|
dbfe2d |
+ ret = -EINVAL;
|
|
|
dbfe2d |
+ goto out;
|
|
|
dbfe2d |
+ }
|
|
|
dbfe2d |
+ send_attr->tlv_len = le16_to_cpu(*(__le16 *)data);
|
|
|
dbfe2d |
+ pos += sizeof(__le16);
|
|
|
dbfe2d |
+ data += sizeof(__le16);
|
|
|
dbfe2d |
+ }
|
|
|
dbfe2d |
+ if (cmd_len - pos < send_attr->tlv_len) {
|
|
|
dbfe2d |
+ error("send stream is truncated");
|
|
|
dbfe2d |
+ ret = -EINVAL;
|
|
|
dbfe2d |
+ goto out;
|
|
|
dbfe2d |
+ }
|
|
|
dbfe2d |
send_attr->data = data;
|
|
|
dbfe2d |
pos += send_attr->tlv_len;
|
|
|
dbfe2d |
data += send_attr->tlv_len;
|
|
|
dbfe2d |
--
|
|
|
dbfe2d |
2.35.1
|
|
|
dbfe2d |
|