libbtrfs: fix potentially unaligned access

Same fix a previous commit, unaligned access on strict alignment hosts
could produce wrong results (reported on send/receive and arm5). As
libbtrfs has own copy of the code fix it here too, replacing leXX_to_cpu
with get_unaligned_leXX where appropriate. This means any access to raw
buffers that get cast to a structure.

Issue: #770
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
David Sterba 2024-05-25 00:29:31 +02:00
parent 09a5fe669f
commit 5fa48a03c5
2 changed files with 12 additions and 11 deletions

View File

@ -1615,7 +1615,7 @@ void write_extent_buffer(struct extent_buffer *eb, const void *src,
static inline u##bits btrfs_##name(const struct extent_buffer *eb) \ static inline u##bits btrfs_##name(const struct extent_buffer *eb) \
{ \ { \
const struct btrfs_header *h = (struct btrfs_header *)eb->data; \ const struct btrfs_header *h = (struct btrfs_header *)eb->data; \
return le##bits##_to_cpu(h->member); \ return get_unaligned_le##bits(&h->member); \
} \ } \
static inline void btrfs_set_##name(struct extent_buffer *eb, \ static inline void btrfs_set_##name(struct extent_buffer *eb, \
u##bits val) \ u##bits val) \
@ -1643,7 +1643,7 @@ static inline void btrfs_set_##name(struct extent_buffer *eb, \
#define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits) \ #define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits) \
static inline u##bits btrfs_##name(const type *s) \ static inline u##bits btrfs_##name(const type *s) \
{ \ { \
return le##bits##_to_cpu(s->member); \ return get_unaligned_le##bits(&s->member); \
} \ } \
static inline void btrfs_set_##name(type *s, u##bits val) \ static inline void btrfs_set_##name(type *s, u##bits val) \
{ \ { \

View File

@ -119,9 +119,10 @@ static int read_cmd(struct btrfs_send_stream *sctx)
goto out; goto out;
} }
/* No data alignment is guaranteed. */
sctx->cmd_hdr = (struct btrfs_cmd_header *)sctx->read_buf; sctx->cmd_hdr = (struct btrfs_cmd_header *)sctx->read_buf;
cmd = le16_to_cpu(sctx->cmd_hdr->cmd); cmd = get_unaligned_le16(&sctx->cmd_hdr->cmd);
cmd_len = le32_to_cpu(sctx->cmd_hdr->len); cmd_len = get_unaligned_le32(&sctx->cmd_hdr->len);
if (cmd_len + sizeof(*sctx->cmd_hdr) >= sizeof(sctx->read_buf)) { if (cmd_len + sizeof(*sctx->cmd_hdr) >= sizeof(sctx->read_buf)) {
ret = -EINVAL; ret = -EINVAL;
@ -140,8 +141,8 @@ static int read_cmd(struct btrfs_send_stream *sctx)
goto out; goto out;
} }
crc = le32_to_cpu(sctx->cmd_hdr->crc); crc = get_unaligned_le32(&sctx->cmd_hdr->crc);
sctx->cmd_hdr->crc = 0; put_unaligned_le32(0, &sctx->cmd_hdr->crc);
crc2 = crc32c(0, (unsigned char*)sctx->read_buf, crc2 = crc32c(0, (unsigned char*)sctx->read_buf,
sizeof(*sctx->cmd_hdr) + cmd_len); sizeof(*sctx->cmd_hdr) + cmd_len);
@ -159,8 +160,8 @@ static int read_cmd(struct btrfs_send_stream *sctx)
u16 tlv_len; u16 tlv_len;
tlv_hdr = (struct btrfs_tlv_header *)data; tlv_hdr = (struct btrfs_tlv_header *)data;
tlv_type = le16_to_cpu(tlv_hdr->tlv_type); tlv_type = get_unaligned_le16(&tlv_hdr->tlv_type);
tlv_len = le16_to_cpu(tlv_hdr->tlv_len); tlv_len = get_unaligned_le16(&tlv_hdr->tlv_len);
if (tlv_type == 0 || tlv_type > BTRFS_SEND_A_MAX) { if (tlv_type == 0 || tlv_type > BTRFS_SEND_A_MAX) {
fprintf(stderr, fprintf(stderr,
@ -203,7 +204,7 @@ static int tlv_get(struct btrfs_send_stream *sctx, int attr, void **data, int *l
goto out; goto out;
} }
*len = le16_to_cpu(hdr->tlv_len); *len = get_unaligned_le16(&hdr->tlv_len);
*data = hdr + 1; *data = hdr + 1;
ret = 0; ret = 0;
@ -282,8 +283,8 @@ static int tlv_get_timespec(struct btrfs_send_stream *sctx,
TLV_GET(sctx, attr, (void**)&bts, &len); TLV_GET(sctx, attr, (void**)&bts, &len);
TLV_CHECK_LEN(sizeof(*bts), len); TLV_CHECK_LEN(sizeof(*bts), len);
ts->tv_sec = le64_to_cpu(bts->sec); ts->tv_sec = get_unaligned_le64(&bts->sec);
ts->tv_nsec = le32_to_cpu(bts->nsec); ts->tv_nsec = get_unaligned_le32(&bts->nsec);
ret = 0; ret = 0;
tlv_get_failed: tlv_get_failed: