]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
xattr-util: merge various getxattr()/listxattr() helpers into getxattr_at_malloc...
authorLennart Poettering <lennart@poettering.net>
Wed, 6 Oct 2021 14:31:49 +0000 (16:31 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 7 Oct 2021 09:49:22 +0000 (11:49 +0200)
Unfortunately fgetxattr() and flistxattr() don't work via O_PATH fds.
Let's thus add fallbacks to go via /proc/self/fd/ in these cases.

Also, let's merge all the various flavours we have here into singular
implementations that can do everything we need:

1. malloc() loop handling
2. by fd, by path, or combination (i.e. a proper openat() like API)
3. work on O_PATH

src/basic/cgroup-util.c
src/basic/os-util.c
src/basic/xattr-util.c
src/basic/xattr-util.h
src/libsystemd/sd-journal/journal-vacuum.c
src/shared/cgroup-show.c
src/shared/discover-image.c
src/shared/dissect-image.c
src/shared/smack-util.c
src/test/test-copy.c
src/test/test-xattr-util.c

index 221157d57aaa8225f9d65310cdde0ab4f725bcf8..1d577a24eca6b7fb88be9d6b76877fd871336d01 100644 (file)
@@ -669,7 +669,7 @@ int cg_get_xattr_malloc(const char *controller, const char *path, const char *na
         if (r < 0)
                 return r;
 
-        r = getxattr_malloc(fs, name, ret, false);
+        r = lgetxattr_malloc(fs, name, ret);
         if (r < 0)
                 return r;
 
index d161f8d33c4b358101a3629a7b9495c42db57628..2a218ad1451bcce301cbb9ecdf734a458c16d931 100644 (file)
@@ -118,7 +118,7 @@ int open_extension_release(const char *root, const char *extension, char **ret_p
 
                                 /* No xattr or cannot parse it? Then skip this. */
                                 _cleanup_free_ char *extension_release_xattr = NULL;
-                                k = fgetxattrat_fake_malloc(extension_release_fd, NULL, "user.extension-release.strict", AT_EMPTY_PATH, &extension_release_xattr);
+                                k = fgetxattr_malloc(extension_release_fd, "user.extension-release.strict", &extension_release_xattr);
                                 if (k < 0 && !ERRNO_IS_NOT_SUPPORTED(k) && k != -ENODATA)
                                         log_debug_errno(k,
                                                         "Failed to read 'user.extension-release.strict' extended attribute from extension-release file %s/%s: %m",
index 5ae6cf8772b8f3bf1d77186dd8945afcbedfbd1a..7bb5b3f6df7c61baa9a96afd119931c170be1560 100644 (file)
 #include "time-util.h"
 #include "xattr-util.h"
 
-int getxattr_malloc(
+int getxattr_at_malloc(
+                int fd,
                 const char *path,
                 const char *name,
-                char **ret,
-                bool allow_symlink) {
+                int flags,
+                char **ret) {
 
+        _cleanup_close_ int opened_fd = -1;
+        unsigned n_attempts = 7;
+        bool by_procfs = false;
         size_t l = 100;
 
-        assert(path);
+        assert(fd >= 0 || fd == AT_FDCWD);
         assert(name);
+        assert((flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0);
         assert(ret);
 
-        for(;;) {
-                _cleanup_free_ char *v = NULL;
-                ssize_t n;
-
-                v = new0(char, l+1);
-                if (!v)
-                        return -ENOMEM;
+        /* So, this is single function that does what getxattr()/lgetxattr()/fgetxattr() does, but in one go,
+         * and with additional bells and whistles. Specifically:
+         *
+         * 1. This works on O_PATH fds (which fgetxattr() does not)
+         * 2. Provides full openat()-style semantics, i.e. by-fd, by-path and combination thereof
+         * 3. As extension to openat()-style semantics implies AT_EMPTY_PATH if path is NULL.
+         * 4. Does a malloc() loop, automatically sizing the allocation
+         * 5. NUL-terminates the returned buffer (for safety)
+         */
+
+        if (!path) /* If path is NULL, imply AT_EMPTY_PATH. – But if it's "", don't — for safety reasons. */
+                flags |= AT_EMPTY_PATH;
+
+        if (isempty(path)) {
+                if (!FLAGS_SET(flags, AT_EMPTY_PATH))
+                        return -EINVAL;
 
-                if (allow_symlink)
-                        n = lgetxattr(path, name, v, l);
+                if (fd == AT_FDCWD) /* Both unspecified? Then operate on current working directory */
+                        path = ".";
                 else
-                        n = getxattr(path, name, v, l);
-                if (n < 0) {
-                        if (errno != ERANGE)
-                                return -errno;
-                } else {
-                        v[n] = 0; /* NUL terminate */
-                        *ret = TAKE_PTR(v);
-                        return (int) n;
-                }
+                        path = NULL;
 
-                if (allow_symlink)
-                        n = lgetxattr(path, name, NULL, 0);
-                else
-                        n = getxattr(path, name, NULL, 0);
-                if (n < 0)
+        } else if (fd != AT_FDCWD) {
+
+                /* If both have been specified, then we go via O_PATH */
+                opened_fd = openat(fd, path, O_PATH|O_CLOEXEC|(FLAGS_SET(flags, AT_SYMLINK_FOLLOW) ? 0 : O_NOFOLLOW));
+                if (opened_fd < 0)
                         return -errno;
-                if (n > INT_MAX) /* We couldn't return this as 'int' anymore */
-                        return -E2BIG;
 
-                l = (size_t) n;
+                fd = opened_fd;
+                path = NULL;
+                by_procfs = true; /* fgetxattr() is not going to work, go via /proc/ link right-away */
         }
-}
 
-int fgetxattr_malloc(
-                int fd,
-                const char *name,
-                char **ret) {
-
-        size_t l = 100;
-
-        assert(fd >= 0);
-        assert(name);
-        assert(ret);
-
-        for (;;) {
+        for(;;) {
                 _cleanup_free_ char *v = NULL;
                 ssize_t n;
 
-                v = new(char, l+1);
+                if (n_attempts == 0) /* If someone is racing against us, give up eventually */
+                        return -EBUSY;
+                n_attempts--;
+
+                v = new0(char, l+1);
                 if (!v)
                         return -ENOMEM;
 
-                n = fgetxattr(fd, name, v, l);
+                l = MALLOC_ELEMENTSOF(v) - 1;
+
+                if (path)
+                        n = FLAGS_SET(flags, AT_SYMLINK_FOLLOW) ? getxattr(path, name, v, l) : lgetxattr(path, name, v, l);
+                else
+                        n = by_procfs ? getxattr(FORMAT_PROC_FD_PATH(fd), name, v, l) : fgetxattr(fd, name, v, l);
                 if (n < 0) {
+                        if (errno == EBADF) {
+                                if (by_procfs || path)
+                                        return -EBADF;
+
+                                by_procfs = true; /* Might be an O_PATH fd, try again via /proc/ link */
+                                continue;
+                        }
+
                         if (errno != ERANGE)
                                 return -errno;
                 } else {
@@ -93,7 +104,10 @@ int fgetxattr_malloc(
                         return (int) n;
                 }
 
-                n = fgetxattr(fd, name, NULL, 0);
+                if (path)
+                        n = FLAGS_SET(flags, AT_SYMLINK_FOLLOW) ? getxattr(path, name, NULL, 0) : lgetxattr(path, name, NULL, 0);
+                else
+                        n = by_procfs ? getxattr(FORMAT_PROC_FD_PATH(fd), name, NULL, 0) : fgetxattr(fd, name, NULL, 0);
                 if (n < 0)
                         return -errno;
                 if (n > INT_MAX) /* We couldn't return this as 'int' anymore */
@@ -103,87 +117,6 @@ int fgetxattr_malloc(
         }
 }
 
-/* Note: ret_fn should already be allocated for the usual xsprintf and /proc/self/fd/%i pattern. */
-static int getxattrat_fake_prepare(
-                int dirfd,
-                const char *filename,
-                int flags,
-                char ret_fn[static PROC_FD_PATH_MAX],
-                int *ret_fd) {
-
-        _cleanup_close_ int fd = -1;
-        assert(ret_fn);
-        assert(ret_fd);
-
-        /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */
-
-        if (flags & ~(AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH))
-                return -EINVAL;
-
-        if (isempty(filename)) {
-                if (!(flags & AT_EMPTY_PATH))
-                        return -EINVAL;
-
-                assert(dirfd >= 0);
-
-                format_proc_fd_path(ret_fn, dirfd);
-        } else {
-                fd = openat(dirfd, filename, O_CLOEXEC|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
-                if (fd < 0)
-                        return -errno;
-
-                format_proc_fd_path(ret_fn, fd);
-        }
-
-        /* Pass the FD to the caller, since in case we do openat() the filename depends on it. */
-        *ret_fd = TAKE_FD(fd);
-
-        return 0;
-}
-
-int fgetxattrat_fake(
-                int dirfd,
-                const char *filename,
-                const char *attribute,
-                void *value, size_t size,
-                int flags,
-                size_t *ret_size) {
-
-        _cleanup_close_ int fd = -1;
-        char fn[PROC_FD_PATH_MAX];
-        ssize_t l;
-        int r;
-
-        r = getxattrat_fake_prepare(dirfd, filename, flags, fn, &fd);
-        if (r < 0)
-                return r;
-
-        l = getxattr(fn, attribute, value, size);
-        if (l < 0)
-                return -errno;
-
-        *ret_size = l;
-        return 0;
-}
-
-int fgetxattrat_fake_malloc(
-                int dirfd,
-                const char *filename,
-                const char *attribute,
-                int flags,
-                char **value) {
-
-        _cleanup_close_ int fd = -1;
-        char fn[PROC_FD_PATH_MAX];
-        int r;
-
-        r = getxattrat_fake_prepare(dirfd, filename, flags, fn, &fd);
-        if (r < 0)
-                return r;
-
-        return getxattr_malloc(fn, attribute, value, false);
-}
-
 static int parse_crtime(le64_t le, usec_t *usec) {
         uint64_t u;
 
@@ -197,17 +130,23 @@ static int parse_crtime(le64_t le, usec_t *usec) {
         return 0;
 }
 
-int fd_getcrtime_at(int dirfd, const char *name, usec_t *ret, int flags) {
+int fd_getcrtime_at(
+                int fd,
+                const char *path,
+                int flags,
+                usec_t *ret) {
+
+        _cleanup_free_ le64_t *le = NULL;
         STRUCT_STATX_DEFINE(sx);
         usec_t a, b;
-        le64_t le;
-        size_t n;
         int r;
 
+        assert(fd >= 0 || fd == AT_FDCWD);
+        assert((flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0);
         assert(ret);
 
-        if (flags & ~(AT_EMPTY_PATH|AT_SYMLINK_NOFOLLOW))
-                return -EINVAL;
+        if (!path)
+                flags |= AT_EMPTY_PATH;
 
         /* So here's the deal: the creation/birth time (crtime/btime) of a file is a relatively newly supported concept
          * on Linux (or more strictly speaking: a concept that only recently got supported in the API, it was
@@ -219,7 +158,10 @@ int fd_getcrtime_at(int dirfd, const char *name, usec_t *ret, int flags) {
          * concept is useful for determining how "old" a file really is, and hence using the older of the two makes
          * most sense. */
 
-        if (statx(dirfd, strempty(name), flags|AT_STATX_DONT_SYNC, STATX_BTIME, &sx) >= 0 &&
+        if (statx(fd, strempty(path),
+                  (flags & ~AT_SYMLINK_FOLLOW)|(FLAGS_SET(flags, AT_SYMLINK_FOLLOW) ? 0 : AT_SYMLINK_NOFOLLOW)|AT_STATX_DONT_SYNC,
+                  STATX_BTIME,
+                  &sx) >= 0 &&
             (sx.stx_mask & STATX_BTIME) &&
             sx.stx_btime.tv_sec != 0)
                 a = (usec_t) sx.stx_btime.tv_sec * USEC_PER_SEC +
@@ -227,12 +169,12 @@ int fd_getcrtime_at(int dirfd, const char *name, usec_t *ret, int flags) {
         else
                 a = USEC_INFINITY;
 
-        r = fgetxattrat_fake(dirfd, name, "user.crtime_usec", &le, sizeof(le), flags, &n);
+        r = getxattr_at_malloc(fd, path, "user.crtime_usec", flags, (char**) &le);
         if (r >= 0) {
-                if (n != sizeof(le))
+                if (r != sizeof(*le))
                         r = -EIO;
                 else
-                        r = parse_crtime(le, &b);
+                        r = parse_crtime(*le, &b);
         }
         if (r < 0) {
                 if (a != USEC_INFINITY) {
@@ -251,10 +193,6 @@ int fd_getcrtime_at(int dirfd, const char *name, usec_t *ret, int flags) {
         return 0;
 }
 
-int fd_getcrtime(int fd, usec_t *ret) {
-        return fd_getcrtime_at(fd, NULL, ret, AT_EMPTY_PATH);
-}
-
 int fd_setcrtime(int fd, usec_t usec) {
         le64_t le;
 
@@ -270,22 +208,73 @@ int fd_setcrtime(int fd, usec_t usec) {
         return 0;
 }
 
-int flistxattr_malloc(int fd, char **ret) {
+int listxattr_at_malloc(
+                int fd,
+                const char *path,
+                int flags,
+                char **ret) {
+
+        _cleanup_close_ int opened_fd = -1;
+        bool by_procfs = false;
+        unsigned n_attempts = 7;
         size_t l = 100;
 
-        assert(fd >= 0);
+        assert(fd >= 0 || fd == AT_FDCWD);
+        assert((flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0);
         assert(ret);
 
+        /* This is to listxattr()/llistattr()/flistattr() what getxattr_at_malloc() is to getxattr()/… */
+
+        if (!path) /* If path is NULL, imply AT_EMPTY_PATH. – But if it's "", don't. */
+                flags |= AT_EMPTY_PATH;
+
+        if (isempty(path)) {
+                if (!FLAGS_SET(flags, AT_EMPTY_PATH))
+                        return -EINVAL;
+
+                if (fd == AT_FDCWD) /* Both unspecified? Then operate on current working directory */
+                        path = ".";
+                else
+                        path = NULL;
+
+        } else if (fd != AT_FDCWD) {
+                /* If both have been specified, then we go via O_PATH */
+                opened_fd = openat(fd, path, O_PATH|O_CLOEXEC|(FLAGS_SET(flags, AT_SYMLINK_FOLLOW) ? 0 : O_NOFOLLOW));
+                if (opened_fd < 0)
+                        return -errno;
+
+                fd = opened_fd;
+                path = NULL;
+                by_procfs = true;
+        }
+
         for (;;) {
                 _cleanup_free_ char *v = NULL;
                 ssize_t n;
 
+                if (n_attempts == 0) /* If someone is racing against us, give up eventually */
+                        return -EBUSY;
+                n_attempts--;
+
                 v = new(char, l+1);
                 if (!v)
                         return -ENOMEM;
 
-                n = flistxattr(fd, v, l);
+                l = MALLOC_ELEMENTSOF(v) - 1;
+
+                if (path)
+                        n = FLAGS_SET(flags, AT_SYMLINK_FOLLOW) ? listxattr(path, v, l) : llistxattr(path, v, l);
+                else
+                        n = by_procfs ? listxattr(FORMAT_PROC_FD_PATH(fd), v, l) : flistxattr(fd, v, l);
                 if (n < 0) {
+                        if (errno == EBADF) {
+                                if (by_procfs || path)
+                                        return -EBADF;
+
+                                by_procfs = true; /* Might be an O_PATH fd, try again via /proc/ link */
+                                continue;
+                        }
+
                         if (errno != ERANGE)
                                 return -errno;
                 } else {
@@ -294,7 +283,10 @@ int flistxattr_malloc(int fd, char **ret) {
                         return (int) n;
                 }
 
-                n = flistxattr(fd, NULL, 0);
+                if (path)
+                        n = FLAGS_SET(flags, AT_SYMLINK_FOLLOW) ? listxattr(path, NULL, 0) : llistxattr(path, NULL, 0);
+                else
+                        n = by_procfs ? listxattr(FORMAT_PROC_FD_PATH(fd), NULL, 0) : flistxattr(fd, NULL, 0);
                 if (n < 0)
                         return -errno;
                 if (n > INT_MAX) /* We couldn't return this as 'int' anymore */
index 87caec980086b0c3dd327aad80bb5c623a8e021b..0eb745a7a3bd84bb61081b912a94b88ade35ad21 100644 (file)
@@ -7,26 +7,32 @@
 
 #include "time-util.h"
 
-int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink);
-int fgetxattr_malloc(int fd, const char *name, char **value);
-
-int fgetxattrat_fake(
-                int dirfd,
-                const char *filename,
-                const char *attribute,
-                void *value, size_t size,
-                int flags,
-                size_t *ret_size);
-int fgetxattrat_fake_malloc(
-                int dirfd,
-                const char *filename,
-                const char *attribute,
-                int flags,
-                char **value);
+int getxattr_at_malloc(int fd, const char *path, const char *name, int flags, char **ret);
+static inline int getxattr_malloc(const char *path, const char *name, char **ret) {
+        return getxattr_at_malloc(AT_FDCWD, path, name, AT_SYMLINK_FOLLOW, ret);
+}
+static inline int lgetxattr_malloc(const char *path, const char *name, char **ret) {
+        return getxattr_at_malloc(AT_FDCWD, path, name, 0, ret);
+}
+static inline int fgetxattr_malloc(int fd, const char *name, char **ret) {
+        return getxattr_at_malloc(fd, NULL, name, AT_EMPTY_PATH, ret);
+}
 
 int fd_setcrtime(int fd, usec_t usec);
 
-int fd_getcrtime(int fd, usec_t *usec);
-int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags);
+int fd_getcrtime_at(int fd, const char *name, int flags, usec_t *ret);
+static inline int fd_getcrtime(int fd, usec_t *ret) {
+        return fd_getcrtime_at(fd, NULL, 0, ret);
+}
+
 
-int flistxattr_malloc(int fd, char **ret);
+int listxattr_at_malloc(int fd, const char *path, int flags, char **ret);
+static inline int listxattr_malloc(const char *path, char **ret) {
+        return listxattr_at_malloc(AT_FDCWD, path, AT_SYMLINK_FOLLOW, ret);
+}
+static inline int llistxattr_malloc(const char *path, char **ret) {
+        return listxattr_at_malloc(AT_FDCWD, path, 0, ret);
+}
+static inline int flistxattr_malloc(int fd, char **ret) {
+        return listxattr_at_malloc(fd, NULL, AT_EMPTY_PATH, ret);
+}
index 6d761b78ebd45653cc17b4c216d6c47a66c8d74f..889caa19056232743bd030faab82327a0bd6c309 100644 (file)
@@ -53,11 +53,10 @@ static void patch_realtime(
                 const struct stat *st,
                 unsigned long long *realtime) {
 
-        usec_t x, crtime = 0;
+        usec_t x;
 
-        /* The timestamp was determined by the file name, but let's
-         * see if the file might actually be older than the file name
-         * suggested... */
+        /* The timestamp was determined by the file name, but let's see if the file might actually be older
+         * than the file name suggested... */
 
         assert(fd >= 0);
         assert(fn);
@@ -76,15 +75,12 @@ static void patch_realtime(
         if (x > 0 && x != USEC_INFINITY && x < *realtime)
                 *realtime = x;
 
-        /* Let's read the original creation time, if possible. Ideally
-         * we'd just query the creation time the FS might provide, but
-         * unfortunately there's currently no sane API to query
-         * it. Hence let's implement this manually... */
+        /* Let's read the original creation time, if possible. Ideally we'd just query the creation time the
+         * FS might provide, but unfortunately there's currently no sane API to query it. Hence let's
+         * implement this manually... */
 
-        if (fd_getcrtime_at(fd, fn, &crtime, 0) >= 0) {
-                if (crtime < *realtime)
-                        *realtime = crtime;
-        }
+        if (fd_getcrtime_at(fd, fn, AT_SYMLINK_FOLLOW, &x) >= 0 && x < *realtime)
+                *realtime = x;
 }
 
 static int journal_file_empty(int dir_fd, const char *name) {
index c7e63be5080693d80ac9f7548823d496f7f65659..bdc35492d03e60c56aac196ebca70fef04bcc5a3 100644 (file)
@@ -127,7 +127,7 @@ static int show_cgroup_name(
         bool delegate = false;
         int r;
 
-        r = getxattr_malloc(path, "trusted.delegate", &b, false);
+        r = lgetxattr_malloc(path, "trusted.delegate", &b);
         if (r < 0) {
                 if (r != -ENODATA)
                         log_debug_errno(r, "Failed to read trusted.delegate extended attribute: %m");
index 129db21eb0e05afc390c409b884c89096c041b5d..60833cec4551e2ef33be9f71b08d1ce4cc8713f8 100644 (file)
@@ -334,7 +334,7 @@ static int image_make(
                 if (!ret)
                         return 0;
 
-                (void) fd_getcrtime_at(dfd, filename, &crtime, 0);
+                (void) fd_getcrtime_at(dfd, filename, AT_SYMLINK_FOLLOW, &crtime);
 
                 if (!pretty) {
                         r = extract_pretty(filename, ".raw", &pretty_buffer);
index ccbe1aced4141fa29502bc082997e3c908fc8cfe..c734b9609a639966b689b4bf82c03812114d6365 100644 (file)
@@ -2765,7 +2765,7 @@ int verity_settings_load(
                          * that doesn't exist for /usr */
 
                         if (designator < 0 || designator == PARTITION_ROOT) {
-                                r = getxattr_malloc(image, "user.verity.roothash", &text, true);
+                                r = getxattr_malloc(image, "user.verity.roothash", &text);
                                 if (r < 0) {
                                         _cleanup_free_ char *p = NULL;
 
@@ -2794,7 +2794,7 @@ int verity_settings_load(
                                  * `usrhash`, because `usrroothash` or `rootusrhash` would just be too
                                  * confusing. We thus drop the reference to the root of the Merkle tree, and
                                  * just indicate which file system it's about. */
-                                r = getxattr_malloc(image, "user.verity.usrhash", &text, true);
+                                r = getxattr_malloc(image, "user.verity.usrhash", &text);
                                 if (r < 0) {
                                         _cleanup_free_ char *p = NULL;
 
index 1d040200278dad71a5ff1484f89489003c629547..d7fbbdc913aa1784fff46bdd060dc73dbc8270d8 100644 (file)
@@ -52,7 +52,7 @@ int mac_smack_read(const char *path, SmackAttr attr, char **label) {
         if (!mac_smack_use())
                 return 0;
 
-        return getxattr_malloc(path, smack_attr_to_string(attr), label, true);
+        return getxattr_malloc(path, smack_attr_to_string(attr), label);
 }
 
 int mac_smack_read_fd(int fd, SmackAttr attr, char **label) {
@@ -166,7 +166,7 @@ static int smack_fix_fd(int fd, const char *abspath, LabelFixFlags flags) {
                         return 0;
 
                 /* If the old label is identical to the new one, suppress any kind of error */
-                if (getxattr_malloc(FORMAT_PROC_FD_PATH(fd), "security.SMACK64", &old_label, false) >= 0 &&
+                if (lgetxattr_malloc(FORMAT_PROC_FD_PATH(fd), "security.SMACK64", &old_label) >= 0 &&
                     streq(old_label, label))
                         return 0;
 
index 362f210e6a65771d5ef8209f97e407cedbbf3034..445a4b2a6e3c2968f8894dc7f95572038e1a2880 100644 (file)
@@ -149,7 +149,7 @@ static void test_copy_tree(void) {
                 assert_se(read_full_file(f, &buf, &sz) == 0);
                 assert_se(streq(buf, "file\n"));
 
-                k = getxattr_malloc(f, "user.testxattr", &c, false);
+                k = lgetxattr_malloc(f, "user.testxattr", &c);
                 assert_se(xattr_worked < 0 || ((k >= 0) == !!xattr_worked));
 
                 if (k >= 0) {
index 3fbae5738fe2ff334df406d8cb30ad845abc913d..b30a639ff3d299a03e7bdcef612c525de163a5f9 100644 (file)
 #include "tmpfile-util.h"
 #include "xattr-util.h"
 
-static void test_fgetxattrat_fake(void) {
+static void test_getxattr_at_malloc(void) {
         char t[] = "/var/tmp/xattrtestXXXXXX";
         _cleanup_free_ char *value = NULL;
         _cleanup_close_ int fd = -1;
         const char *x;
-        char v[3];
         int r;
-        size_t size;
 
         log_info("/* %s */", __func__);
 
@@ -38,21 +36,24 @@ static void test_fgetxattrat_fake(void) {
         fd = open(t, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY);
         assert_se(fd >= 0);
 
-        assert_se(fgetxattrat_fake(fd, "test", "user.foo", v, 3, 0, &size) >= 0);
-        assert_se(size == 3);
-        assert_se(memcmp(v, "bar", 3) == 0);
+        assert_se(getxattr_at_malloc(fd, "test", "user.foo", 0, &value) == 3);
+        assert_se(memcmp(value, "bar", 3) == 0);
+        value = mfree(value);
+
+        assert_se(getxattr_at_malloc(AT_FDCWD, x, "user.foo", 0, &value) == 3);
+        assert_se(memcmp(value, "bar", 3) == 0);
+        value = mfree(value);
 
         safe_close(fd);
         fd = open("/", O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY);
         assert_se(fd >= 0);
-        r = fgetxattrat_fake(fd, "usr", "user.idontexist", v, 3, 0, &size);
+        r = getxattr_at_malloc(fd, "usr", "user.idontexist", 0, &value);
         assert_se(r == -ENODATA || ERRNO_IS_NOT_SUPPORTED(r));
 
         safe_close(fd);
         fd = open(x, O_PATH|O_CLOEXEC);
         assert_se(fd >= 0);
-        r = fgetxattrat_fake_malloc(fd, NULL, "user.foo", AT_EMPTY_PATH, &value);
-        assert_se(r == 3);
+        assert_se(getxattr_at_malloc(fd, NULL, "user.foo", 0, &value) == 3);
         assert_se(streq(value, "bar"));
 
 cleanup:
@@ -68,7 +69,7 @@ static void test_getcrtime(void) {
 
         log_info("/* %s */", __func__);
 
-        assert_se(tmp_dir(&vt) >= 0);
+        assert_se(var_tmp_dir(&vt) >= 0);
 
         fd = open_tmpfile_unlinkable(vt, O_RDWR);
         assert_se(fd >= 0);
@@ -92,7 +93,7 @@ static void test_getcrtime(void) {
 int main(void) {
         test_setup_logging(LOG_DEBUG);
 
-        test_fgetxattrat_fake();
+        test_getxattr_at_malloc();
         test_getcrtime();
 
         return 0;