@@ -168,28 +168,44 @@ static int read_cmd(struct btrfs_send_stream *sctx)
pos = 0;
while (pos < cmd_len) {
- struct btrfs_tlv_header *tlv_hdr;
u16 tlv_type;
- u16 tlv_len;
struct btrfs_send_attribute *send_attr;
- tlv_hdr = (struct btrfs_tlv_header *)data;
- tlv_type = le16_to_cpu(tlv_hdr->tlv_type);
- tlv_len = le16_to_cpu(tlv_hdr->tlv_len);
+ if (cmd_len - pos < sizeof(__le16)) {
+ error("send stream is truncated");
+ ret = -EINVAL;
+ goto out;
+ }
+ tlv_type = le16_to_cpu(*(__le16 *)data);
if (tlv_type == 0 || tlv_type > BTRFS_SEND_A_MAX) {
- error("invalid tlv in cmd tlv_type = %hu, tlv_len = %hu",
- tlv_type, tlv_len);
+ error("invalid tlv in cmd tlv_type = %hu", tlv_type);
ret = -EINVAL;
goto out;
}
send_attr = &sctx->cmd_attrs[tlv_type];
send_attr->tlv_type = tlv_type;
- send_attr->tlv_len = tlv_len;
- pos += sizeof(*tlv_hdr);
- data += sizeof(*tlv_hdr);
+ pos += sizeof(tlv_type);
+ data += sizeof(tlv_type);
+ if (sctx->version == 2 && tlv_type == BTRFS_SEND_A_DATA) {
+ send_attr->tlv_len = cmd_len - pos;
+ } else {
+ if (cmd_len - pos < sizeof(__le16)) {
+ error("send stream is truncated");
+ ret = -EINVAL;
+ goto out;
+ }
+ send_attr->tlv_len = le16_to_cpu(*(__le16 *)data);
+ pos += sizeof(__le16);
+ data += sizeof(__le16);
+ }
+ if (cmd_len - pos < send_attr->tlv_len) {
+ error("send stream is truncated");
+ ret = -EINVAL;
+ goto out;
+ }
send_attr->data = data;
pos += send_attr->tlv_len;
data += send_attr->tlv_len;