diff --git a/src/basic/errno-util.h b/src/basic/errno-util.h index eb2941253d..195d13208b 100644 --- a/src/basic/errno-util.h +++ b/src/basic/errno-util.h @@ -218,10 +218,13 @@ static inline bool ERRNO_IS_NEG_DEVICE_ABSENT_OR_EMPTY(intmax_t r) { } _DEFINE_ABS_WRAPPER(DEVICE_ABSENT_OR_EMPTY); -/* Quite often we want to handle cases where the backing FS doesn't support extended attributes at all and - * where it simply doesn't have the requested xattr the same way */ +/* Quite often we want to handle cases where the backing FS doesn't support extended attributes at all, + * where the path component carrying the xattr is missing, and where it simply doesn't have the requested + * xattr the same way. Note that getxattr(2) does not enumerate -ENOENT in its own error list, but inherits + * it via stat(2) (see ERRORS in getxattr(2)) for the path-component-missing case. */ static inline bool ERRNO_IS_NEG_XATTR_ABSENT(intmax_t r) { return r == -ENODATA || + r == -ENOENT || ERRNO_IS_NEG_NOT_SUPPORTED(r); } _DEFINE_ABS_WRAPPER(XATTR_ABSENT); diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 23f804bd65..c5bb52b2af 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -3820,7 +3820,7 @@ int verity_settings_load( if (r < 0) { _cleanup_free_ char *p = NULL; - if (r != -ENOENT && !ERRNO_IS_XATTR_ABSENT(r)) + if (!ERRNO_IS_XATTR_ABSENT(r)) return r; p = build_auxiliary_path(image, ".roothash"); @@ -3849,7 +3849,7 @@ int verity_settings_load( if (r < 0) { _cleanup_free_ char *p = NULL; - if (r != -ENOENT && !ERRNO_IS_XATTR_ABSENT(r)) + if (!ERRNO_IS_XATTR_ABSENT(r)) return r; p = build_auxiliary_path(image, ".usrhash"); diff --git a/src/test/test-xattr-util.c b/src/test/test-xattr-util.c index eeb0d8a8af..4d39a0a1f1 100644 --- a/src/test/test-xattr-util.c +++ b/src/test/test-xattr-util.c @@ -46,6 +46,16 @@ TEST(getxattr_at_malloc) { r = getxattr_at_malloc(fd, "usr", "user.idontexist", 0, &value, /* ret_size= */ NULL); ASSERT_TRUE(ERRNO_IS_NEG_XATTR_ABSENT(r)); + /* A non-existent path component must also be treated as xattr-absent. The kernel + * returns -ENOENT in this case, which is inherited from stat(2)'s error list + * (see ERRORS in getxattr(2)). Without this, callers that semantically just want + * to know "is the xattr there?" end up logging spurious errors for paths that + * are simply gone — e.g. journald reading a unit's cgroup xattr after the + * cgroup directory has been torn down. */ + r = getxattr_at_malloc(fd, "this-path-does-not-exist-XXXXXX", "user.idontexist", + 0, &value, /* ret_size= */ NULL); + ASSERT_TRUE(ERRNO_IS_NEG_XATTR_ABSENT(r)); + safe_close(fd); ASSERT_OK_ERRNO(fd = open(x, O_PATH|O_CLOEXEC)); ASSERT_OK(getxattr_at_malloc(fd, NULL, "user.foo", 0, &value, /* ret_size= */ NULL));