From 5fa48a03c579d5430ff5174e93a825db69ba8bda Mon Sep 17 00:00:00 2001 From: David Sterba Date: Sat, 25 May 2024 00:29:31 +0200 Subject: [PATCH] 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 --- libbtrfs/ctree.h | 4 ++-- libbtrfs/send-stream.c | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/libbtrfs/ctree.h b/libbtrfs/ctree.h index 0e9c5bcd..94ea9d35 100644 --- a/libbtrfs/ctree.h +++ b/libbtrfs/ctree.h @@ -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) \ { \ 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, \ 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) \ 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) \ { \ diff --git a/libbtrfs/send-stream.c b/libbtrfs/send-stream.c index 16aef3ab..ff180886 100644 --- a/libbtrfs/send-stream.c +++ b/libbtrfs/send-stream.c @@ -119,9 +119,10 @@ static int read_cmd(struct btrfs_send_stream *sctx) goto out; } + /* No data alignment is guaranteed. */ sctx->cmd_hdr = (struct btrfs_cmd_header *)sctx->read_buf; - cmd = le16_to_cpu(sctx->cmd_hdr->cmd); - cmd_len = le32_to_cpu(sctx->cmd_hdr->len); + cmd = get_unaligned_le16(&sctx->cmd_hdr->cmd); + cmd_len = get_unaligned_le32(&sctx->cmd_hdr->len); if (cmd_len + sizeof(*sctx->cmd_hdr) >= sizeof(sctx->read_buf)) { ret = -EINVAL; @@ -140,8 +141,8 @@ static int read_cmd(struct btrfs_send_stream *sctx) goto out; } - crc = le32_to_cpu(sctx->cmd_hdr->crc); - sctx->cmd_hdr->crc = 0; + crc = get_unaligned_le32(&sctx->cmd_hdr->crc); + put_unaligned_le32(0, &sctx->cmd_hdr->crc); crc2 = crc32c(0, (unsigned char*)sctx->read_buf, sizeof(*sctx->cmd_hdr) + cmd_len); @@ -159,8 +160,8 @@ static int read_cmd(struct btrfs_send_stream *sctx) u16 tlv_len; 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); + tlv_type = get_unaligned_le16(&tlv_hdr->tlv_type); + tlv_len = get_unaligned_le16(&tlv_hdr->tlv_len); if (tlv_type == 0 || tlv_type > BTRFS_SEND_A_MAX) { fprintf(stderr, @@ -203,7 +204,7 @@ static int tlv_get(struct btrfs_send_stream *sctx, int attr, void **data, int *l goto out; } - *len = le16_to_cpu(hdr->tlv_len); + *len = get_unaligned_le16(&hdr->tlv_len); *data = hdr + 1; ret = 0; @@ -282,8 +283,8 @@ static int tlv_get_timespec(struct btrfs_send_stream *sctx, TLV_GET(sctx, attr, (void**)&bts, &len); TLV_CHECK_LEN(sizeof(*bts), len); - ts->tv_sec = le64_to_cpu(bts->sec); - ts->tv_nsec = le32_to_cpu(bts->nsec); + ts->tv_sec = get_unaligned_le64(&bts->sec); + ts->tv_nsec = get_unaligned_le32(&bts->nsec); ret = 0; tlv_get_failed: