Blame SOURCES/1104-btrfs-progs-receive-support-v2-send-stream-DATA-tlv-.patch

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