]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
pidfd-util: preferably acquire pidfd inode id through name_to_handle_at()
authorMike Yuan <me@yhndnzj.com>
Wed, 22 Jan 2025 02:00:32 +0000 (03:00 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 22 Jan 2025 20:41:44 +0000 (21:41 +0100)
See rationales described in kernel commit:
https://github.com/torvalds/linux/commit/b3caba8f7a34a2bbaf45ffc6ff3a49b70afeb192

man/sd_notify.xml
src/basic/pidfd-util.c

index cf19ba01da76db34dc5b25cd9de71b6078c30b09..c017f484870f4b7167917250fc93ca2ae173960e 100644 (file)
 
         <listitem><para>The pidfd inode number of the new main process (specified through <varname>MAINPID=</varname>).
         This information can be acquired through
-        <citerefentry project='man-pages'><refentrytitle>fstat</refentrytitle><manvolnum>2</manvolnum></citerefentry>
+        <citerefentry project='man-pages'><refentrytitle>name_to_handle_at</refentrytitle><manvolnum>2</manvolnum></citerefentry>
+        or <citerefentry project='man-pages'><refentrytitle>fstat</refentrytitle><manvolnum>2</manvolnum></citerefentry>
         on the pidfd and is used to identify the process in a race-free fashion. Alternatively,
         a pidfd can be sent directly to the service manager (see <varname>MAINPIDFD=1</varname> below).</para>
 
index 36fe224324aa03d4e8531044206f707a888f1855..82064e162a58a65cf5c613179fe1b5e323cadeb6 100644 (file)
@@ -8,8 +8,10 @@
 #include "fileio.h"
 #include "macro.h"
 #include "memory-util.h"
+#include "missing_fs.h"
 #include "missing_magic.h"
 #include "missing_threads.h"
+#include "mountpoint-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "pidfd-util.h"
@@ -226,6 +228,7 @@ int pidfd_get_cgroupid(int fd, uint64_t *ret) {
 }
 
 int pidfd_get_inode_id(int fd, uint64_t *ret) {
+        static bool file_handle_supported = true;
         int r;
 
         assert(fd >= 0);
@@ -236,6 +239,30 @@ int pidfd_get_inode_id(int fd, uint64_t *ret) {
         if (r == 0)
                 return -EOPNOTSUPP;
 
+        if (file_handle_supported) {
+                union {
+                        struct file_handle file_handle;
+                        uint8_t space[offsetof(struct file_handle, f_handle) + sizeof(uint64_t)];
+                } fh = {
+                        .file_handle.handle_bytes = sizeof(uint64_t),
+                        .file_handle.handle_type = FILEID_KERNFS,
+                };
+                int mnt_id;
+
+                r = RET_NERRNO(name_to_handle_at(fd, "", &fh.file_handle, &mnt_id, AT_EMPTY_PATH));
+                if (r >= 0) {
+                        if (ret)
+                                *ret = *(uint64_t*) fh.file_handle.f_handle;
+                        return 0;
+                }
+                assert(r != -EOVERFLOW);
+                if (is_name_to_handle_at_fatal_error(r))
+                        return r;
+
+                file_handle_supported = false;
+        }
+
+#if SIZEOF_INO_T == 8
         struct stat st;
         if (fstat(fd, &st) < 0)
                 return -errno;
@@ -243,6 +270,16 @@ int pidfd_get_inode_id(int fd, uint64_t *ret) {
         if (ret)
                 *ret = (uint64_t) st.st_ino;
         return 0;
+
+#elif SIZEOF_INO_T == 4
+        /* On 32-bit systems (where sizeof(ino_t) == 4), the inode id returned by fstat() cannot be used to
+         * reliably identify the process, nor can we communicate the origin of the id with the clients.
+         * Hence let's just refuse to acquire pidfdid through fstat() here. All clients shall also insist on
+         * the 64-bit id from name_to_handle_at(). */
+        return -EOPNOTSUPP;
+#else
+#  error Unsupported ino_t size
+#endif
 }
 
 int pidfd_get_inode_id_self_cached(uint64_t *ret) {