Credential Passing (SO_PEERCRED)
When D-Bus checks if your process is allowed to access a secret, it asks the kernel — not your process. SO_PEERCRED provides unforgeable identity by reading directly from the kernel’s task_struct. This is authentication without passwords, enforced at the syscall level.
Credential Passing: Kernel-Enforced Identity
Kernel Foundation
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
D-Bus is a message-passing system. The session bus (dbus-daemon or dbus-broker) listens on a Unix socket. Applications like gopass use it to talk to gnome-keyring or secret-service for credential storage.
The Kernel Primitive: SO_PEERCRED
struct ucred cred;
getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len);
// cred.uid -- kernel-verified, unforgeable
// cred.pid -- kernel-verified, unforgeable
// cred.gid -- kernel-verified, unforgeable
When a process connects to the D-Bus socket, the kernel fills in the peer credentials from the process’s task_struct — the kernel’s representation of a process (include/linux/sched.h). The D-Bus daemon uses this to enforce access policies: it knows exactly which UID/PID is making each request, and the connecting process cannot lie about this.
This is kernel-enforced identity, not userspace trust. The credentials come from the kernel’s own process table, not from anything the connecting process sends.
SO_PEERCRED vs SCM_CREDENTIALS
| Mechanism | How It Works | When to Use |
|---|---|---|
|
Kernel auto-fills from |
Simple: "who connected to me?" (D-Bus, systemd) |
|
Sender includes |
Advanced: per-message credential tagging |
With SCM_CREDENTIALS, the sender can claim a UID/GID, but the kernel overrides the values unless the sender has CAP_SYS_ADMIN. A non-root process sending SCM_CREDENTIALS with a fake UID gets its real UID stamped by the kernel. This is the "trust but verify" pattern implemented at the kernel level.
Why gopass Needs D-Bus
gopass show -c performs two IPC operations:
-
Retrieves the secret via D-Bus to the keyring daemon (
gnome-keyringorsecret-service) -
Copies to clipboard via
wl-copyto the Wayland compositor
Without DBUS_SESSION_BUS_ADDRESS, gopass cannot find the bus socket, so it cannot reach the keyring daemon. The credential check (SO_PEERCRED) happens transparently — the D-Bus daemon verifies gopass’s identity before allowing access to stored secrets.
The task_struct Connection
SO_PEERCRED reads from the process’s task_struct, which is the kernel’s central data structure for process state:
// include/linux/sched.h (simplified)
struct task_struct {
pid_t pid; // Process ID
const struct cred *cred; // Process credentials
struct mm_struct *mm; // Memory map
struct files_struct *files; // Open file descriptors
// ... hundreds more fields
};
The cred field points to a struct cred containing the process’s real/effective/saved UIDs and GIDs, capabilities, and security context. This is the same structure that the kernel checks on every file access, every signal delivery, and every syscall that requires privilege. D-Bus simply leverages the same infrastructure.
Kernel Source Map
| Source File | What It Does | Key Functions |
|---|---|---|
|
|
|
|
|
Process state, credentials, memory, files |
|
|
|
|
Credential structure |
|
|
Credential management |
|
Exploration Exercises
# See D-Bus peers and their credentials
busctl --user list
# Trace D-Bus socket operations
strace -e connect,getsockopt gopass show -c v3/test 2>&1 | grep -E 'PEER|unix'
# Inspect the D-Bus socket
ss -xlp | grep bus
# Read your own task_struct via procfs
cat /proc/self/status | grep -E '^(Pid|Uid|Gid|Cap)'