From: Allison Karlitskaya Date: Thu, 20 Mar 2025 12:13:13 +0000 (+0100) Subject: copy: return immediately on fs-verity failures X-Git-Tag: v258-rc1~400 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=137a2b120842fbc2bd4b40b2eea1153d6c652534;p=thirdparty%2Fsystemd.git copy: return immediately on fs-verity failures Since 8065d02e263a ("copy: Fix error handling in fd_copy_directory()") we immediately abort recursive copy operations on ENOSPC. Let's also abort on the common case of filesystems not supporting fs-verity: if it's unsupported for one file, it's unlikely to work for the 1000s that follow it. We do this by mapping the two fs-verity "not supported" errors (ENOTTY, EOPNOTSUPP) to ESOCKTNOSUPPORT as a special "fs-verity not supported here" error. When we see that error at the top level we exit immediately. This prevents us from having to see the same error message literally thousands of time when using fsverity=copy with systemd-repart on a filesystem which lacks the proper support. Adjust the test-copy test case to expect the new errno. Previously this test case would output multiple failure lines per `copy_tree_at()` invocation (for the failing cases) but now it only outputs one. --- diff --git a/src/shared/copy.c b/src/shared/copy.c index 0c79121b68e..17268387569 100644 --- a/src/shared/copy.c +++ b/src/shared/copy.c @@ -817,7 +817,11 @@ static int copy_fs_verity(int fdf, int *fdt) { * so the correct thing to do is to do nothing at all. */ if (errno == ENODATA) return 0; - return log_error_errno(errno, "Failed to read fs-verity metadata from source file: %m"); + log_error_errno(errno, "Failed to read fs-verity metadata from source file: %m"); + /* For cases where fs-verity is unsupported we return a special error code */ + if (ERRNO_IS_NOT_SUPPORTED(errno)) + return -ESOCKTNOSUPPORT; + return -errno; } /* Make sure that the descriptor is completely initialized */ @@ -844,8 +848,13 @@ static int copy_fs_verity(int fdf, int *fdt) { .salt_ptr = (uintptr_t) &desc.salt, }; - if (ioctl(*fdt, FS_IOC_ENABLE_VERITY, &enable_arg) < 0) - return log_error_errno(errno, "Failed to set fs-verity metadata: %m"); + if (ioctl(*fdt, FS_IOC_ENABLE_VERITY, &enable_arg) < 0) { + log_error_errno(errno, "Failed to set fs-verity metadata: %m"); + /* For cases where fs-verity is unsupported we return a special error code */ + if (ERRNO_IS_NOT_SUPPORTED(errno)) + return -ESOCKTNOSUPPORT; + return -errno; + } return 0; } @@ -1222,7 +1231,8 @@ static int fd_copy_directory( denylist, subvolumes, hardlink_context, child_display_path, progress_path, progress_bytes, userdata); - if (IN_SET(r, -EINTR, -ENOSPC)) /* Propagate SIGINT/SIGTERM and ENOSPC up instantly */ + /* Propagate SIGINT/SIGTERM, ENOSPC, and fs-verity fails up instantly */ + if (IN_SET(r, -EINTR, -ENOSPC, -ESOCKTNOSUPPORT)) return r; if (r == -EEXIST && (copy_flags & COPY_MERGE)) r = 0; diff --git a/src/test/test-copy.c b/src/test/test-copy.c index 9da77786551..86de5c4b633 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -676,7 +676,7 @@ TEST_RET(copy_with_verity) { /* Copy *with* fs-verity enabled and make sure it works properly */ int r = copy_tree_at(src, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL); - if (r == -ENOTTY) + if (r == -ESOCKTNOSUPPORT) /* This can happen on some versions of btrfs, for example */ return log_tests_skipped_errno(errno, "/var/tmp: fs-verity supported, but not reading metadata"); ASSERT_OK(r); @@ -697,14 +697,14 @@ TEST_RET(copy_with_verity) { /* Copy from our non-verity filesystem into dst, requesting verity and making sure we notice that * we failed to read verity from the source. */ - ASSERT_ERROR(copy_tree_at(badsrc, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL), ENOTTY); + ASSERT_ERROR(copy_tree_at(badsrc, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL), ESOCKTNOSUPPORT); /* Copy from our verity filesystem into our baddst, requesting verity and making sure we notice that * we failed to set verity on the destination. */ - ASSERT_ERROR(copy_tree_at(src, ".", baddst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL), ENOTTY); + ASSERT_ERROR(copy_tree_at(src, ".", baddst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL), ESOCKTNOSUPPORT); /* Of course this should fail too... */ - ASSERT_ERROR(copy_tree_at(badsrc, ".", baddst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL), ENOTTY); + ASSERT_ERROR(copy_tree_at(badsrc, ".", baddst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL), ESOCKTNOSUPPORT); return 0; }