From c496b01d663d087278038bf26802488969441078 Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Tue, 21 May 2024 01:34:34 +0900
Subject: [PATCH 0663/1160] btrfs-util: check current offset before read

Fixes #32936.

(cherry picked from commit 125cca1b51e19d9209a229fca4fb9d94d34c3e78)
---
 src/shared/btrfs-util.c | 49 +++++++++++++++++++++++++++++++----------
 1 file changed, 37 insertions(+), 12 deletions(-)

diff --git a/src/shared/btrfs-util.c b/src/shared/btrfs-util.c
index 2ed6bf24a2..42d21ad118 100644
--- a/src/shared/btrfs-util.c
+++ b/src/shared/btrfs-util.c
@@ -262,24 +262,49 @@ static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args
 }
 
 typedef struct BtrfsForeachIterator {
-        const void *p;
-        size_t i;
+        const struct btrfs_ioctl_search_args *args;
+        size_t offset;
+        unsigned index;
+        struct btrfs_ioctl_search_header *header;
+        const void **body;
 } BtrfsForeachIterator;
 
+static int btrfs_iterate(BtrfsForeachIterator *i) {
+        assert(i);
+        assert(i->args);
+        assert(i->header);
+        assert(i->body);
+
+        if (i->index >= i->args->key.nr_items)
+                return 0; /* end */
+
+        assert_cc(BTRFS_SEARCH_ARGS_BUFSIZE >= sizeof(struct btrfs_ioctl_search_header));
+        if (i->offset > BTRFS_SEARCH_ARGS_BUFSIZE - sizeof(struct btrfs_ioctl_search_header))
+                return -EBADMSG;
+
+        struct btrfs_ioctl_search_header h;
+        memcpy(&h, (const uint8_t*) i->args->buf + i->offset, sizeof(struct btrfs_ioctl_search_header));
+
+        if (i->offset > BTRFS_SEARCH_ARGS_BUFSIZE - sizeof(struct btrfs_ioctl_search_header) - h.len)
+                return -EBADMSG;
+
+        *i->body = (const uint8_t*) i->args->buf + i->offset + sizeof(struct btrfs_ioctl_search_header);
+        *i->header = h;
+        i->offset += sizeof(struct btrfs_ioctl_search_header) + h.len;
+        i->index++;
+
+        return 1;
+}
+
 /* Iterates through a series of struct btrfs_file_extent_item elements. They are unfortunately not aligned,
  * hence we copy out the header from them */
-#define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(sh, body, args)               \
+#define FOREACH_BTRFS_IOCTL_SEARCH_HEADER(_sh, _body, _args)            \
         for (BtrfsForeachIterator iterator = {                          \
-                        .p = ({                                         \
-                               memcpy(&(sh), (args).buf, sizeof(struct btrfs_ioctl_search_header)); \
-                               (body) = (const void*) ((const uint8_t*) (args).buf + sizeof(struct btrfs_ioctl_search_header)); \
-                               (args).buf;                              \
-                        }),                                             \
+                        .args = &(_args),                               \
+                        .header = &(_sh),                               \
+                        .body = &(_body),                               \
              };                                                         \
-             iterator.i < (args).key.nr_items;                          \
-             iterator.i++,                                              \
-             memcpy(&(sh), iterator.p = (const uint8_t*) iterator.p + sizeof(struct btrfs_ioctl_search_header) + (sh).len, sizeof(struct btrfs_ioctl_search_header)), \
-             (body) = (const void*) ((const uint8_t*) iterator.p + sizeof(struct btrfs_ioctl_search_header)))
+             btrfs_iterate(&iterator) > 0; )
 
 int btrfs_subvol_get_info_fd(int fd, uint64_t subvol_id, BtrfsSubvolInfo *ret) {
         struct btrfs_ioctl_search_args args = {
-- 
2.33.0