]> git.ipfire.org Git - thirdparty/dbus.git/commitdiff
DBusCredentials: add support for PID FDs via SO_PEERPIDFD
authorLuca Boccassi <bluca@debian.org>
Mon, 20 Mar 2023 02:00:51 +0000 (02:00 +0000)
committerLuca Boccassi <bluca@debian.org>
Tue, 8 Aug 2023 11:24:20 +0000 (12:24 +0100)
The new socket option SO_PEERPIDFD allows to pin the process on the
other side of the socket by file descriptor, which closes a race
condition where a PID can be reused before we can pin it manually.
Available since Linux v6.5.

When storing credentials, pin the process by FD from the PID.
When querying the PID, if the PID FD is available, resolve
it from there first if possible.

Ensure the DBusCredentials object only returns the PID FD if it was
obtained by this call, so that we know for sure we can rely on it
being safe against PID reuse attacks.

Signed-off-by: Luca Boccassi <bluca@debian.org>
cmake/ConfigureChecks.cmake
cmake/config.h.cmake
configure.ac
dbus/dbus-auth.c
dbus/dbus-credentials.c
dbus/dbus-credentials.h
dbus/dbus-sysdeps-unix.c
dbus/dbus-sysdeps.h
meson.build
test/internals/dbus-credentials-util.c

index 4e0c9ce6c473f014f542c1f2798e3affb0e4af97..737913bac431c729a7f5b283c7b6f1d0461eef0d 100644 (file)
@@ -42,6 +42,7 @@ set(HAVE_BACKTRACE ${Backtrace_FOUND})
 check_symbol_exists(LOG_PERROR   "syslog.h"                  HAVE_DECL_LOG_PERROR)
 check_symbol_exists(MSG_NOSIGNAL "sys/socket.h"              HAVE_DECL_MSG_NOSIGNAL)
 check_symbol_exists(SCM_RIGHTS    "sys/types.h;sys/socket.h;sys/un.h" HAVE_UNIX_FD_PASSING)
+check_symbol_exists(SYS_pidfd_open "sys/syscall.h"  HAVE_DECL_SYS_PIDFD_OPEN) #  dbus-sysdeps-unix.c
 check_symbol_exists(accept4      "sys/socket.h"             HAVE_ACCEPT4)
 check_symbol_exists(clearenv     "stdlib.h"         HAVE_CLEARENV)           #  dbus-sysdeps.c
 check_symbol_exists(close_range  "unistd.h"         HAVE_CLOSE_RANGE)        #  dbus-sysdeps-unix.c
index a4811b540f9fb893e9649da51b63f58466383207..e16d2247d2721827c99eeca8c5d55694b9faeb0a 100644 (file)
 #cmakedefine01 HAVE_DECL_ENVIRON
 #cmakedefine01 HAVE_DECL_LOG_PERROR
 #cmakedefine01 HAVE_DECL_MSG_NOSIGNAL
+#cmakedefine01 HAVE_DECL_SYS_PIDFD_OPEN
 
 #endif  // _DBUS_CONFIG_H
index f6ce9e6cb727b6022a9c3cb58413e4702e1e7d8f..b1809e7551087f5d1df4e9ee5874e67b08d7f8fb 100644 (file)
@@ -1029,6 +1029,8 @@ fi
 AC_CHECK_HEADERS(sys/vfs.h, [AC_CHECK_FUNCS(fstatfs)])
 AC_CHECK_HEADERS([linux/magic.h])
 
+AC_CHECK_DECLS([SYS_pidfd_open], [], [], [[ #include <sys/syscall.h> ]])
+
 #### Set up final flags
 LIBDBUS_LIBS="$THREAD_LIBS $NETWORK_libs $SYSTEMD_LIBS"
 AC_SUBST([LIBDBUS_LIBS])
index bcb612a8c8f336c7062727b2a310ca4fd6c9ede0..09942f801897c2e75553169f41aedf66c95a4b22 100644 (file)
@@ -803,8 +803,12 @@ sha1_handle_second_client_response (DBusAuth         *auth,
                                           auth->desired_identity))
     goto out_3;
 
-  /* Copy process ID from the socket credentials if it's there
+  /* Copy process ID (and PID FD) from the socket credentials if it's there
    */
+  if (!_dbus_credentials_add_credential (auth->authorized_identity,
+                                         DBUS_CREDENTIAL_UNIX_PROCESS_FD,
+                                         auth->credentials))
+    goto out_3;
   if (!_dbus_credentials_add_credential (auth->authorized_identity,
                                          DBUS_CREDENTIAL_UNIX_PROCESS_ID,
                                          auth->credentials))
@@ -1187,6 +1191,11 @@ handle_server_data_external_mech (DBusAuth         *auth,
 
       /* also copy misc process info from the socket credentials
        */
+      if (!_dbus_credentials_add_credential (auth->authorized_identity,
+                                             DBUS_CREDENTIAL_UNIX_PROCESS_FD,
+                                             auth->credentials))
+        return FALSE;
+
       if (!_dbus_credentials_add_credential (auth->authorized_identity,
                                              DBUS_CREDENTIAL_UNIX_PROCESS_ID,
                                              auth->credentials))
@@ -1304,8 +1313,13 @@ handle_server_data_anonymous_mech (DBusAuth         *auth,
   /* We want to be anonymous (clear in case some other protocol got midway through I guess) */
   _dbus_credentials_clear (auth->desired_identity);
 
-  /* Copy process ID from the socket credentials
+  /* Copy process ID (and PID FD) from the socket credentials
    */
+  if (!_dbus_credentials_add_credential (auth->authorized_identity,
+                                         DBUS_CREDENTIAL_UNIX_PROCESS_FD,
+                                         auth->credentials))
+    return FALSE;
+
   if (!_dbus_credentials_add_credential (auth->authorized_identity,
                                          DBUS_CREDENTIAL_UNIX_PROCESS_ID,
                                          auth->credentials))
index d932865e336d75f910ff4aa427c60520d60f2313..44cd40bfccacc361914fac3a2082fe28e48cd961 100644 (file)
 #include <config.h>
 #include <stdlib.h>
 #include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_SYSCALL_H
+#include <sys/syscall.h>
+#endif
 #include "dbus-credentials.h"
 #include "dbus-internals.h"
+#ifdef DBUS_UNIX
+#include "dbus-sysdeps-unix.h"
+#endif
 
 /**
  * @defgroup DBusCredentials Credentials provable through authentication
@@ -54,6 +63,7 @@ struct DBusCredentials {
   dbus_gid_t *unix_gids;
   size_t n_unix_gids;
   dbus_pid_t pid;
+  int pid_fd;
   char *windows_sid;
   char *linux_security_label;
   void *adt_audit_data;
@@ -86,6 +96,7 @@ _dbus_credentials_new (void)
   creds->unix_gids = NULL;
   creds->n_unix_gids = 0;
   creds->pid = DBUS_PID_UNSET;
+  creds->pid_fd = -1;
   creds->windows_sid = NULL;
   creds->linux_security_label = NULL;
   creds->adt_audit_data = NULL;
@@ -145,12 +156,22 @@ _dbus_credentials_unref (DBusCredentials    *credentials)
       dbus_free (credentials->windows_sid);
       dbus_free (credentials->linux_security_label);
       dbus_free (credentials->adt_audit_data);
+#ifdef DBUS_UNIX
+      if (credentials->pid_fd >= 0)
+        {
+          close (credentials->pid_fd);
+          credentials->pid_fd = -1;
+        }
+#endif
       dbus_free (credentials);
     }
 }
 
 /**
- * Add a UNIX process ID to the credentials.
+ * Add a UNIX process ID to the credentials. If the
+ * process ID FD is set, it will always take
+ * precendence when querying the PID of this
+ * credential.
  *
  * @param credentials the object
  * @param pid the process ID
@@ -164,6 +185,30 @@ _dbus_credentials_add_pid (DBusCredentials    *credentials,
   return TRUE;
 }
 
+/**
+ * Add a UNIX process ID FD to the credentials. The
+ * FD is now owned by the credentials object.
+ *
+ * @param credentials the object
+ * @param pid_fd the process ID FD
+ * @returns #FALSE if no memory
+ */
+#ifndef DBUS_UNIX
+_DBUS_GNUC_NORETURN
+#endif
+void
+_dbus_credentials_take_pid_fd (DBusCredentials    *credentials,
+                              int                 pid_fd)
+{
+#ifdef DBUS_UNIX
+  if (credentials->pid_fd >= 0)
+    close (credentials->pid_fd);
+  credentials->pid_fd = pid_fd;
+#else
+  _dbus_assert_not_reached ("pidfd never set on non-Unix");
+#endif
+}
+
 /**
  * Add a UNIX user ID to the credentials.
  *
@@ -323,7 +368,10 @@ _dbus_credentials_include (DBusCredentials    *credentials,
   switch (type)
     {
     case DBUS_CREDENTIAL_UNIX_PROCESS_ID:
-      return credentials->pid != DBUS_PID_UNSET;
+      return credentials->pid != DBUS_PID_UNSET ||
+             credentials->pid_fd >= 0;
+    case DBUS_CREDENTIAL_UNIX_PROCESS_FD:
+      return credentials->pid_fd >= 0;
     case DBUS_CREDENTIAL_UNIX_USER_ID:
       return credentials->unix_uid != DBUS_UID_UNSET;
     case DBUS_CREDENTIAL_UNIX_GROUP_IDS:
@@ -343,6 +391,8 @@ _dbus_credentials_include (DBusCredentials    *credentials,
 /**
  * Gets the UNIX process ID in the credentials, or #DBUS_PID_UNSET if
  * the credentials object doesn't contain a process ID.
+ * If the PID FD is set, it will first try to resolve from it, and
+ * only return the stored PID if that fails.
  *
  * @param credentials the object
  * @returns UNIX process ID
@@ -350,9 +400,35 @@ _dbus_credentials_include (DBusCredentials    *credentials,
 dbus_pid_t
 _dbus_credentials_get_pid (DBusCredentials    *credentials)
 {
+#ifdef DBUS_UNIX
+  dbus_pid_t pid;
+
+  if (credentials->pid_fd >= 0)
+    {
+      pid = _dbus_resolve_pid_fd (credentials->pid_fd);
+      if (pid > 0)
+        return pid;
+    }
+#endif
+
   return credentials->pid;
 }
 
+/**
+ * Gets the UNIX process ID FD in the credentials as obtained by 'safe'
+ * means (e.g.: Linux's SO_PEERPIDFD), or -1 if the credentials object
+ * doesn't contain a process ID FD. The file FD is owned by the credentials
+ * object and must not be closed by the caller.
+ *
+ * @param credentials the object
+ * @returns UNIX process ID FD
+ */
+int
+_dbus_credentials_get_pid_fd (DBusCredentials    *credentials)
+{
+  return credentials->pid_fd;
+}
+
 /**
  * Gets the UNIX user ID in the credentials, or #DBUS_UID_UNSET if
  * the credentials object doesn't contain a user ID.
@@ -463,6 +539,7 @@ _dbus_credentials_are_empty (DBusCredentials    *credentials)
 {
   return
     credentials->pid == DBUS_PID_UNSET &&
+    credentials->pid_fd == -1 &&
     credentials->unix_uid == DBUS_UID_UNSET &&
     credentials->unix_gids == NULL &&
     credentials->n_unix_gids == 0 &&
@@ -498,6 +575,9 @@ _dbus_credentials_add_credentials (DBusCredentials    *credentials,
                                    DBusCredentials    *other_credentials)
 {
   return
+    _dbus_credentials_add_credential (credentials,
+                                      DBUS_CREDENTIAL_UNIX_PROCESS_FD,
+                                      other_credentials) &&
     _dbus_credentials_add_credential (credentials,
                                       DBUS_CREDENTIAL_UNIX_PROCESS_ID,
                                       other_credentials) &&
@@ -582,6 +662,19 @@ _dbus_credentials_add_credential (DBusCredentials    *credentials,
       if (!_dbus_credentials_add_adt_audit_data (credentials, other_credentials->adt_audit_data, other_credentials->adt_audit_data_size))
         return FALSE;
     }
+  /* _dbus_dup() is only available on UNIX platforms. */
+#ifdef DBUS_UNIX
+  else if (which == DBUS_CREDENTIAL_UNIX_PROCESS_FD &&
+      other_credentials->pid_fd >= 0)
+    {
+      int pid_fd = _dbus_dup (other_credentials->pid_fd, NULL);
+
+      if (pid_fd < 0)
+        return FALSE;
+
+      _dbus_credentials_take_pid_fd (credentials, pid_fd);
+    }
+#endif
 
   return TRUE;
 }
@@ -595,6 +688,13 @@ void
 _dbus_credentials_clear (DBusCredentials    *credentials)
 {
   credentials->pid = DBUS_PID_UNSET;
+#ifdef DBUS_UNIX
+  if (credentials->pid_fd >= 0)
+    {
+      close (credentials->pid_fd);
+      credentials->pid_fd = -1;
+    }
+#endif
   credentials->unix_uid = DBUS_UID_UNSET;
   dbus_free (credentials->unix_gids);
   credentials->unix_gids = NULL;
@@ -677,9 +777,12 @@ _dbus_credentials_to_string_append (DBusCredentials    *credentials,
         goto oom;
       join = TRUE;
     }
-  if (credentials->pid != DBUS_PID_UNSET)
+  if (credentials->pid != DBUS_PID_UNSET || credentials->pid_fd >= 0)
     {
-      if (!_dbus_string_append_printf (string, "%spid=" DBUS_PID_FORMAT, join ? " " : "", credentials->pid))
+      if (!_dbus_string_append_printf (string,
+                                       "%spid=" DBUS_PID_FORMAT,
+                                       join ? " " : "",
+                                       _dbus_credentials_get_pid (credentials)))
         goto oom;
       join = TRUE;
     }
@@ -715,6 +818,13 @@ _dbus_credentials_to_string_append (DBusCredentials    *credentials,
       join = TRUE;
     }
 
+  if (credentials->pid_fd >= 0)
+    {
+      if (!_dbus_string_append_printf (string, "%spidfd=%d", join ? " " : "", credentials->pid_fd))
+        goto oom;
+      join = TRUE;
+    }
+
   return TRUE;
 oom:
   return FALSE;
index 6da0d1ae8b2f38b6ea285f7b06b8c2cec93c7488..407d5cb5222839bcb5cb527e39aacadedc807c96 100644 (file)
@@ -38,7 +38,8 @@ typedef enum {
   DBUS_CREDENTIAL_UNIX_GROUP_IDS,
   DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
   DBUS_CREDENTIAL_LINUX_SECURITY_LABEL,
-  DBUS_CREDENTIAL_WINDOWS_SID
+  DBUS_CREDENTIAL_WINDOWS_SID,
+  DBUS_CREDENTIAL_UNIX_PROCESS_FD,
 } DBusCredentialType;
 
 DBUS_PRIVATE_EXPORT
@@ -53,6 +54,9 @@ DBUS_PRIVATE_EXPORT
 dbus_bool_t      _dbus_credentials_add_pid                  (DBusCredentials    *credentials,
                                                              dbus_pid_t          pid);
 DBUS_PRIVATE_EXPORT
+void             _dbus_credentials_take_pid_fd               (DBusCredentials    *credentials,
+                                                             int                 pid_fd);
+DBUS_PRIVATE_EXPORT
 dbus_bool_t      _dbus_credentials_add_unix_uid             (DBusCredentials    *credentials,
                                                              dbus_uid_t          uid);
 DBUS_PRIVATE_EXPORT
@@ -73,6 +77,8 @@ dbus_bool_t      _dbus_credentials_include                  (DBusCredentials
 DBUS_PRIVATE_EXPORT
 dbus_pid_t       _dbus_credentials_get_pid                  (DBusCredentials    *credentials);
 DBUS_PRIVATE_EXPORT
+int              _dbus_credentials_get_pid_fd               (DBusCredentials    *credentials);
+DBUS_PRIVATE_EXPORT
 dbus_uid_t       _dbus_credentials_get_unix_uid             (DBusCredentials    *credentials);
 DBUS_PRIVATE_EXPORT
 dbus_bool_t      _dbus_credentials_get_unix_gids            (DBusCredentials    *credentials,
index 6962b07716c3914398770f61db3796d2cc20791f..c66096e076e62ac17b32c06a0a7d784eded490d7 100644 (file)
@@ -2217,6 +2217,7 @@ _dbus_read_credentials_socket  (DBusSocket       client_fd,
   dbus_gid_t primary_gid_read;
   dbus_pid_t pid_read;
   int bytes_read;
+  int pid_fd_read;
 
 #ifdef HAVE_CMSGCRED
   union {
@@ -2236,6 +2237,7 @@ _dbus_read_credentials_socket  (DBusSocket       client_fd,
   uid_read = DBUS_UID_UNSET;
   primary_gid_read = DBUS_GID_UNSET;
   pid_read = DBUS_PID_UNSET;
+  pid_fd_read = -1;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
@@ -2328,6 +2330,24 @@ _dbus_read_credentials_socket  (DBusSocket       client_fd,
         primary_gid_read = cr.gid;
 #endif
       }
+
+#ifdef SO_PEERPIDFD
+    /* If we have SO_PEERCRED we might also have SO_PEERPIDFD, which
+     * allows to pin the process ID, and is available on Linux since v6.5. */
+    cr_len = sizeof (int);
+
+    if (getsockopt (client_fd.fd, SOL_SOCKET, SO_PEERPIDFD, &pid_fd_read, &cr_len) != 0)
+      {
+        _dbus_verbose ("Failed to getsockopt(SO_PEERPIDFD): %s\n",
+                       _dbus_strerror (errno));
+      }
+    else if (cr_len != sizeof (int))
+      {
+        _dbus_verbose ("Failed to getsockopt(SO_PEERPIDFD), returned %d bytes, expected %d\n",
+                       cr_len, (int) sizeof (int));
+      }
+#endif
+
 #elif defined(HAVE_UNPCBID) && defined(LOCAL_PEEREID)
     /* Another variant of the above - used on NetBSD
      */
@@ -2483,6 +2503,11 @@ _dbus_read_credentials_socket  (DBusSocket       client_fd,
                 pid_read,
                 uid_read);
 
+  /* Assign this first, so we don't have to close it manually in case one of
+   * the next steps fails. */
+  if (pid_fd_read >= 0)
+    _dbus_credentials_take_pid_fd (credentials, pid_fd_read);
+
   if (pid_read != DBUS_PID_UNSET)
     {
       if (!_dbus_credentials_add_pid (credentials, pid_read))
@@ -2960,6 +2985,8 @@ _dbus_user_info_fill_uid (DBusUserInfo *info,
 dbus_bool_t
 _dbus_credentials_add_from_current_process (DBusCredentials *credentials)
 {
+  dbus_pid_t pid = _dbus_getpid ();
+
   /* The POSIX spec certainly doesn't promise this, but
    * we need these assertions to fail as soon as we're wrong about
    * it so we can do the porting fixups
@@ -2968,7 +2995,14 @@ _dbus_credentials_add_from_current_process (DBusCredentials *credentials)
   _DBUS_STATIC_ASSERT (sizeof (uid_t) <= sizeof (dbus_uid_t));
   _DBUS_STATIC_ASSERT (sizeof (gid_t) <= sizeof (dbus_gid_t));
 
-  if (!_dbus_credentials_add_pid(credentials, _dbus_getpid()))
+#if HAVE_DECL_SYS_PIDFD_OPEN
+  /* Normally this syscall would have a race condition, but we can trust
+   * that our own process isn't going to exit, so the pid won't get reused. */
+  int pid_fd = (int) syscall (SYS_pidfd_open, pid, 0);
+  if (pid_fd >= 0)
+    _dbus_credentials_take_pid_fd (credentials, pid_fd);
+#endif
+  if (!_dbus_credentials_add_pid (credentials, pid))
     return FALSE;
   if (!_dbus_credentials_add_unix_uid(credentials, _dbus_geteuid()))
     return FALSE;
@@ -2976,6 +3010,79 @@ _dbus_credentials_add_from_current_process (DBusCredentials *credentials)
   return TRUE;
 }
 
+/**
+ * Resolve the PID from the PID FD, if any. This allows us to avoid
+ * PID reuse attacks. Returns DBUS_PID_UNSET if the PID could not be resolved.
+ * Note that this requires being able to read /proc/self/fdinfo/<FD>,
+ * which is created as 600 and owned by the original UID that the
+ * process started as. So it cannot work when the start as root and
+ * drop privileges mechanism is in use (the systemd unit no longer
+ * does this, but third-party init-scripts might).
+ *
+ * @param pid_fd the PID FD
+ * @returns the resolved PID if found, DBUS_PID_UNSET otherwise
+ */
+dbus_pid_t
+_dbus_resolve_pid_fd (int pid_fd)
+{
+#ifdef __linux__
+  DBusError error = DBUS_ERROR_INIT;
+  DBusString content = _DBUS_STRING_INIT_INVALID;
+  DBusString filename = _DBUS_STRING_INIT_INVALID;
+  dbus_pid_t result = DBUS_PID_UNSET;
+  int pid_index;
+
+  if (pid_fd < 0)
+    goto out;
+
+  if (!_dbus_string_init (&content))
+    goto out;
+
+  if (!_dbus_string_init (&filename))
+    goto out;
+
+  if (!_dbus_string_append_printf (&filename, "/proc/self/fdinfo/%d", pid_fd))
+    goto out;
+
+  if (!_dbus_file_get_contents (&content, &filename, &error))
+    {
+      _dbus_verbose ("Cannot read '/proc/self/fdinfo/%d', unable to resolve PID, %s: %s\n",
+                     pid_fd, error.name, error.message);
+      goto out;
+    }
+
+  /* Ensure we are not reading PPid, either it's the first line of the file or
+   * there's a newline before it. */
+  if (!_dbus_string_find (&content, 0, "Pid:", &pid_index) ||
+      (pid_index > 0 && _dbus_string_get_byte (&content, pid_index - 1) != '\n'))
+    {
+      _dbus_verbose ("Cannot find 'Pid:' in '/proc/self/fdinfo/%d', unable to resolve PID\n",
+                     pid_fd);
+      goto out;
+    }
+
+  if (!_dbus_string_parse_uint (&content, pid_index + strlen ("Pid:"), &result, NULL))
+    {
+      _dbus_verbose ("Cannot parse 'Pid:' from '/proc/self/fdinfo/%d', unable to resolve PID\n",
+                     pid_fd);
+      goto out;
+    }
+
+out:
+  _dbus_string_free (&content);
+  _dbus_string_free (&filename);
+  dbus_error_free (&error);
+
+  if (result <= 0)
+    return DBUS_PID_UNSET;
+
+  return result;
+#else
+  return DBUS_PID_UNSET;
+#endif
+
+}
+
 /**
  * Append to the string the identity we would like to have when we
  * authenticate, on UNIX this is the current process UID and on
index 36ababdb5e2f3a2ef3ec4f596526fcdaf9a162b2..e97371790924d4e79a8d4614b342ba33aa41ac0d 100644 (file)
@@ -311,6 +311,18 @@ dbus_bool_t _dbus_daemon_unpublish_session_bus_address (void);
 
 dbus_bool_t _dbus_socket_can_pass_unix_fd(DBusSocket fd);
 
+/* PID FDs are Linux-specific. */
+#ifdef DBUS_WIN
+static inline dbus_pid_t _dbus_resolve_pid_fd (int pid_fd)
+{
+  return DBUS_PID_UNSET;
+}
+
+#else
+DBUS_PRIVATE_EXPORT
+dbus_pid_t _dbus_resolve_pid_fd (int pid_fd);
+#endif
+
 /** Opaque type representing an atomically-modifiable integer
  * that can be used from multiple threads.
  */
index 5438b1843cafa3ae3e3d72935321bf166d744c88..9bfcb4a894ee60e000ce00ecd5ec81c5a17d2902 100644 (file)
@@ -769,6 +769,14 @@ config.set('HAVE_FSTATFS',
     )
 )
 
+config.set10('HAVE_DECL_SYS_PIDFD_OPEN',
+    cc.has_header_symbol(
+        'sys/syscall.h',
+        'SYS_pidfd_open',
+        args: compile_args_c,
+    )
+)
+
 ###############################################################################
 # Project options
 
index 06400925ae2dee184a5c3bd07319f4e2c0fbf6a0..6fada30294feea6f79dd2fc03bd74ffd11f55d92 100644 (file)
@@ -129,13 +129,15 @@ _dbus_credentials_test (const char *test_data_dir)
   DBusCredentials *creds;
   DBusCredentials *creds2;
   DBusString str;
+  DBusString str2;
   const dbus_gid_t *gids;
   size_t n;
+  dbus_pid_t pid = _dbus_getpid();
 
   if (test_data_dir == NULL)
     return TRUE;
 
-  creds = make_credentials (12, 511, 1, SAMPLE_SID);
+  creds = make_credentials (12, pid, 1, SAMPLE_SID);
   if (creds == NULL)
     _dbus_test_fatal ("oom");
 
@@ -149,7 +151,7 @@ _dbus_credentials_test (const char *test_data_dir)
   _dbus_assert (_dbus_credentials_include (creds, DBUS_CREDENTIAL_WINDOWS_SID));
 
   _dbus_assert (_dbus_credentials_get_unix_uid (creds) == 12);
-  _dbus_assert (_dbus_credentials_get_pid (creds) == 511);
+  _dbus_assert (_dbus_credentials_get_pid (creds) == pid);
   _dbus_assert (strcmp (_dbus_credentials_get_windows_sid (creds), SAMPLE_SID) == 0);
   _dbus_assert (_dbus_credentials_get_unix_gids (creds, &gids, &n));
   _dbus_assert (n == 4);
@@ -172,7 +174,7 @@ _dbus_credentials_test (const char *test_data_dir)
   _dbus_assert (_dbus_credentials_include (creds2, DBUS_CREDENTIAL_WINDOWS_SID));
 
   _dbus_assert (_dbus_credentials_get_unix_uid (creds2) == 12);
-  _dbus_assert (_dbus_credentials_get_pid (creds2) == 511);
+  _dbus_assert (_dbus_credentials_get_pid (creds2) == pid);
   _dbus_assert (strcmp (_dbus_credentials_get_windows_sid (creds2), SAMPLE_SID) == 0);
   _dbus_assert (_dbus_credentials_get_unix_gids (creds2, &gids, &n));
   _dbus_assert (n == 4);
@@ -245,7 +247,7 @@ _dbus_credentials_test (const char *test_data_dir)
   _dbus_credentials_unref (creds2);
 
   /* Same user, but not a superset, if groups are different */
-  creds2 = make_credentials (12, 511, 2, SAMPLE_SID);
+  creds2 = make_credentials (12, pid, 2, SAMPLE_SID);
   if (creds2 == NULL)
     _dbus_test_fatal ("oom");
 
@@ -255,7 +257,7 @@ _dbus_credentials_test (const char *test_data_dir)
   _dbus_credentials_unref (creds2);
 
   /* Groups being in the same order make no difference */
-  creds2 = make_credentials (12, 511, 3, SAMPLE_SID);
+  creds2 = make_credentials (12, pid, 3, SAMPLE_SID);
   if (creds2 == NULL)
     _dbus_test_fatal ("oom");
 
@@ -282,7 +284,7 @@ _dbus_credentials_test (const char *test_data_dir)
   _dbus_credentials_unref (creds);
 
   /* Make some more realistic credentials blobs to test stringification */
-  if (!_dbus_string_init (&str))
+  if (!_dbus_string_init (&str) || !_dbus_string_init (&str2))
     _dbus_test_fatal ("oom");
 
   creds = make_credentials (12, DBUS_PID_UNSET, 0, NULL);
@@ -298,7 +300,7 @@ _dbus_credentials_test (const char *test_data_dir)
 
   _dbus_credentials_unref (creds);
 
-  creds = make_credentials (12, 511, 1, NULL);
+  creds = make_credentials (12, pid, 1, NULL);
   if (creds == NULL)
     _dbus_test_fatal ("oom");
 
@@ -308,9 +310,11 @@ _dbus_credentials_test (const char *test_data_dir)
   if (!_dbus_credentials_to_string_append (creds, &str))
     _dbus_test_fatal ("oom");
 
+  if (!_dbus_string_append_printf(&str2, "uid=12 pid=" DBUS_PID_FORMAT " gid=42 gid=123 gid=1000 gid=5678", pid))
+    _dbus_test_fatal ("oom");
+
   _dbus_test_diag ("Unix complete set: %s", _dbus_string_get_const_data (&str));
-  _dbus_assert (strcmp (_dbus_string_get_const_data (&str),
-                        "uid=12 pid=511 gid=42 gid=123 gid=1000 gid=5678") == 0);
+  _dbus_assert (strcmp (_dbus_string_get_const_data (&str), _dbus_string_get_const_data (&str2)) == 0);
 
   _dbus_credentials_unref (creds);
 
@@ -330,23 +334,26 @@ _dbus_credentials_test (const char *test_data_dir)
 
   _dbus_credentials_unref (creds);
 
-  creds = make_credentials (DBUS_UID_UNSET, 511, 0, SAMPLE_SID);
+  creds = make_credentials (DBUS_UID_UNSET, pid, 0, SAMPLE_SID);
   if (creds == NULL)
     _dbus_test_fatal ("oom");
 
-  if (!_dbus_string_set_length (&str, 0))
+  if (!_dbus_string_set_length (&str, 0) || !_dbus_string_set_length (&str2, 0))
     _dbus_test_fatal ("oom");
 
   if (!_dbus_credentials_to_string_append (creds, &str))
     _dbus_test_fatal ("oom");
 
+  if (!_dbus_string_append_printf(&str2, "pid=" DBUS_PID_FORMAT " sid=" SAMPLE_SID, pid))
+    _dbus_test_fatal ("oom");
+
   _dbus_test_diag ("Windows complete set: %s", _dbus_string_get_const_data (&str));
-  _dbus_assert (strcmp (_dbus_string_get_const_data (&str),
-                        "pid=511 sid=" SAMPLE_SID) == 0);
+  _dbus_assert (strcmp (_dbus_string_get_const_data (&str), _dbus_string_get_const_data (&str2)) == 0);
 
   _dbus_credentials_unref (creds);
 
   _dbus_string_free (&str);
+  _dbus_string_free (&str2);
 
   return TRUE;
 }