public inbox for linux-btrfs@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] btrfs: test setting the same received UUID to a lot of subvolumes
@ 2026-02-27  0:12 fdmanana
  2026-02-27 23:27 ` Anand Jain
  0 siblings, 1 reply; 2+ messages in thread
From: fdmanana @ 2026-02-27  0:12 UTC (permalink / raw)
  To: fstests; +Cc: linux-btrfs, Filipe Manana

From: Filipe Manana <fdmanana@suse.com>

Test that using the received subvol ioctl to set a received UUID on a root
does not trigger a transaction abort (and turn the filesystem to RO mode)
if a user abuses by assigning the same received UUID to a large number of
subvolumes.

This exercises a bug fixed by the following kernel patch:

 "btrfs: fix transaction abort on set received ioctl due to item overflow"

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 .gitignore                        |  1 +
 configure.ac                      |  4 ++
 src/Makefile                      |  4 ++
 src/t_btrfs_received_uuid_ioctl.c | 50 +++++++++++++++++++++++
 tests/btrfs/347                   | 66 +++++++++++++++++++++++++++++++
 tests/btrfs/347.out               |  3 ++
 6 files changed, 128 insertions(+)
 create mode 100644 src/t_btrfs_received_uuid_ioctl.c
 create mode 100755 tests/btrfs/347
 create mode 100644 tests/btrfs/347.out

diff --git a/.gitignore b/.gitignore
index 2b5bedd5..0819d3c5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -213,6 +213,7 @@ tags
 /src/unlink-fsync
 /src/file_attr
 /src/truncate
+/src/t_btrfs_received_uuid_ioctl
 
 # Symlinked files
 /tests/generic/035.out
diff --git a/configure.ac b/configure.ac
index f7519fa9..441f543c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -106,6 +106,10 @@ AC_CHECK_TYPES([struct btrfs_ioctl_get_subvol_rootref_args], [], [], [[
 #include <stddef.h>
 #include <linux/btrfs.h>
 ]])
+AC_CHECK_TYPES([struct btrfs_ioctl_received_subvol_args], [], [], [[
+#include <stddef.h>
+#include <linux/btrfs.h>
+]])
 AC_CHECK_HEADERS([linux/btrfs.h linux/btrfs_tree.h])
 AC_CHECK_MEMBERS([struct btrfs_ioctl_vol_args_v2.subvolid], [], [], [[
 #include <stddef.h>
diff --git a/src/Makefile b/src/Makefile
index 577d816a..cc4efad4 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -107,6 +107,10 @@ ifeq ($(HAVE_FICLONE),yes)
      TARGETS += t_reflink_read_race
 endif
 
+ifeq ($(HAVE_LIBBTRFSUTIL), true)
+     LINUX_TARGETS += t_btrfs_received_uuid_ioctl
+endif
+
 ifeq ($(NEED_INTERNAL_XFS_IOC_EXCHANGE_RANGE),yes)
 LCFLAGS += -DNEED_INTERNAL_XFS_IOC_EXCHANGE_RANGE
 endif
diff --git a/src/t_btrfs_received_uuid_ioctl.c b/src/t_btrfs_received_uuid_ioctl.c
new file mode 100644
index 00000000..bd058278
--- /dev/null
+++ b/src/t_btrfs_received_uuid_ioctl.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Program to set a received UUID on a btrfs subvolume.
+ */
+
+#include <sys/ioctl.h>
+#include <btrfs/ioctl.h>
+#include <uuid/uuid.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+int main(int argc, char **argv)
+{
+	struct btrfs_ioctl_received_subvol_args args;
+	uuid_t uuid;
+	int ret;
+	int fd;
+
+	if (argc != 3) {
+		fprintf(stderr, "Use: %s <uuid> <subvolume path>\n", argv[0]);
+		return 1;
+	}
+
+	ret = uuid_parse(argv[1], uuid);
+	if (ret == -1) {
+		fprintf(stderr,
+	"Invalid UUID. Example: 8c628557-6987-42b2-ba16-b7cc79ddfb43\n");
+		return 2;
+	}
+
+	fd = open(argv[2], O_RDONLY | O_DIRECTORY, 0666);
+	if (fd == -1) {
+		perror("Failed to open fd");
+		return 3;
+	}
+
+	memset(&args, 0, sizeof(args));
+	memcpy(args.uuid, uuid, BTRFS_UUID_SIZE);
+
+	ret = ioctl(fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &args);
+	if (ret == -1) {
+		perror("Failed to set received subvol");
+		return 4;
+	}
+
+	return 0;
+}
diff --git a/tests/btrfs/347 b/tests/btrfs/347
new file mode 100755
index 00000000..ebd53d97
--- /dev/null
+++ b/tests/btrfs/347
@@ -0,0 +1,66 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2026 SUSE S.A.  All Rights Reserved.
+#
+# FS QA Test 347
+#
+# Test that using the received subvol ioctl to set a received UUID on a root
+# does not trigger a transaction abort (and turn the filesystem to RO mode) if
+# a user abuses by assigning the same received UUID to a large number of
+# subvolumes.
+#
+. ./common/preamble
+_begin_fstest auto quick subvol
+
+_require_test_program t_btrfs_received_uuid_ioctl
+_require_scratch
+_require_btrfs_support_sectorsize 4096
+
+_fixed_by_kernel_commit xxxxxxxxxxxx \
+	"btrfs: fix transaction abort on set received ioctl due to item overflow"
+
+# Use a 4K node/leaf size to make the test faster.
+_scratch_mkfs -n 4K >> $seqres.full 2>&1 || _fail "mkfs failed"
+_scratch_mount
+
+# With a leaf size of 4K, we can get a BTRFS_UUID_KEY_RECEIVED_SUBVOL key with
+# maximum number of 496 root IDs (u64 values).
+#
+# We have:
+#
+#  total item size = sizeof(struct btrfs_item) + sizeof(u64) * 496
+#                  = 25 + 8 * 496 = 3993
+#
+#  BTRFS_LEAF_DATA_SIZE = leafsize - sizeof(struct btrfs_header)
+#                       = 4096 - 101 = 3995
+#
+# So 497 root IDs would be 3993 + 8 = 4001 which is > BTRFS_LEAF_DATA_SIZE.
+num_subvols=496
+
+for ((i = 1; i <= $num_subvols; i++)); do
+	_btrfs subvolume create $SCRATCH_MNT/sv_$i
+done
+
+for ((i = 1; i <= $num_subvols; i++)); do
+	$here/src/t_btrfs_received_uuid_ioctl \
+		8c628557-6987-42b2-ba16-b7cc79ddfb43 $SCRATCH_MNT/sv_$i
+done
+
+# Add one more subvolume and try to set its received UUID to the same UUID.
+# This should fail due to item overflow.
+_btrfs subvolume create $SCRATCH_MNT/sv_last
+$here/src/t_btrfs_received_uuid_ioctl \
+	8c628557-6987-42b2-ba16-b7cc79ddfb43 $SCRATCH_MNT/sv_last
+
+# The failure to set the received uuid on this last subvolume should not cause
+# in a transaction abort and turn the filesystem to RO mode - otherwise a
+# malicious user could disrupt a system. So check this by seeing if we can
+# create a file.
+echo -n "hello world" > $SCRATCH_MNT/foobar
+
+# Unmount and mount again, verify file foobar exists and with the right content.
+_scratch_cycle_mount
+echo "File foobar content: $(cat $SCRATCH_MNT/foobar)"
+
+# success, all done
+_exit 0
diff --git a/tests/btrfs/347.out b/tests/btrfs/347.out
new file mode 100644
index 00000000..b98b6cec
--- /dev/null
+++ b/tests/btrfs/347.out
@@ -0,0 +1,3 @@
+QA output created by 347
+Failed to set received subvol: Value too large for defined data type
+File foobar content: hello world
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-02-27 23:28 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-27  0:12 [PATCH] btrfs: test setting the same received UUID to a lot of subvolumes fdmanana
2026-02-27 23:27 ` Anand Jain

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox