A privileged local daemon accepts a request over an AF_UNIX socket and needs to decide whether the sender may perform an operation. Trusting a UID, PID, or account name encoded inside the request merely trusts data supplied by the client. Linux provides a different identity channel: the kernel can expose credentials associated with the peer or with an individual message.
SO_PEERCRED and SCM_CREDENTIALS both carry a struct ucred, but they describe different moments in an IPC relationship. Treating them as interchangeable can turn a sound local authorization boundary into a stale-identity assumption.
SO_PEERCRED captures credentials at connection establishment
For a connected UNIX stream socket, getsockopt(fd, SOL_SOCKET, SO_PEERCRED, ...) returns the credentials of the peer. Linux records the returned credentials from the relevant connection establishment point: connect(), listen(), or socketpair() according to the socket arrangement.
The structure contains a PID, UID, and GID. Those values come through the kernel socket interface rather than from application payload bytes. This makes SO_PEERCRED suitable for a daemon that assigns an authorization context to a newly accepted local connection.
struct ucred cred;
socklen_t len = sizeof(cred);
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) == -1)
/* reject connection */;The snapshot is not a continuous credential monitor. If the peer later changes credentials, the value obtained through SO_PEERCRED does not become a live view of that later state. A protocol that authorizes the entire connection based on the initial peer identity is therefore making an explicit session policy decision.
SCM_CREDENTIALS attaches identity to received messages
Linux can also deliver credentials as ancillary data. When SO_PASSCRED is enabled on a receiving UNIX socket, subsequently received messages carry an SCM_CREDENTIALS control message. If the sender does not explicitly supply credentials, the kernel supplies defaults containing the sender’s PID, real UID, and real GID.
This message-oriented model is useful when authorization belongs to individual datagrams or messages rather than to a long-lived connection. The receiver must use recvmsg() and inspect the control-message chain; a plain recv() call does not expose ancillary credentials to application code.
A sender may explicitly provide SCM_CREDENTIALS, but the fields are not arbitrary untrusted claims. Linux checks supplied values. Without the relevant capabilities, the sender is constrained to permitted PID, UID, and GID values derived from its own process credentials. Privileged senders have broader substitution rules, so a receiver’s threat model still needs to account for privileged local processes.
Connection identity and message identity answer different questions
SO_PEERCRED is naturally aligned with a stream-session boundary: the daemon accepts a peer, obtains a kernel-provided credential snapshot, and associates policy state with that connection. SCM_CREDENTIALS is aligned with message provenance: each received message can carry credentials checked or supplied by the kernel.
The distinction matters for credential transitions. A service that intentionally permits a connected peer to change UID after connection may still want authorization fixed to the identity present when the session was established. In that case, SO_PEERCRED matches the policy. A datagram broker that receives messages from multiple processes needs per-message provenance instead; a connection-time snapshot cannot represent all senders.
Neither mechanism defines the authorization rule. They provide identity inputs. The daemon still decides whether a UID, GID, PID, security label, socket path, or another property is relevant to the requested operation.
Socket pathname permissions and peer credentials protect different boundaries
Filesystem permissions on a pathname-backed UNIX socket can restrict which processes can reach the endpoint under Linux filesystem rules. Peer credentials answer a separate question after communication exists: which process identity is associated with this connection or message.
Relying only on socket-file permissions can be insufficient when several principals legitimately share access to the endpoint but receive different privileges inside the protocol. Conversely, checking peer credentials does not make endpoint placement irrelevant. Directory and socket permissions can reduce who can initiate traffic at all, while credential checks can refine authorization after acceptance.
Abstract-namespace UNIX sockets do not use filesystem pathname permissions in the same manner. Designs using that namespace should not transfer assumptions from pathname ownership and mode bits to the abstract endpoint.
PID values remain namespace-scoped identifiers
The PID inside struct ucred is useful for correlation, but it should not automatically become a durable process handle. Numeric PIDs can be recycled after process exit, and PID namespace relationships affect the value visible across process boundaries.
If a daemon needs to perform a later authority-bearing operation on the same process, a numeric PID copied from credentials is not equivalent to a stable kernel process reference. The credential record establishes provenance for the socket event; it does not freeze process lifetime or turn the PID into a permanent capability.
UID and GID values also need policy context. A numeric UID can be interpreted through user namespaces, and authorization based on host identity may require explicit assumptions about the namespace arrangement of the daemon and client. Kernel delivery prevents payload forgery within the documented rules, but it does not choose the policy domain in which the number should be interpreted.
Credential truncation is a parsing failure, not an anonymous peer
Ancillary data has buffer requirements. If the control buffer passed to recvmsg() is too small, control messages can be truncated and MSG_CTRUNC is reported. A security-sensitive receiver should treat missing or truncated expected credentials as a failed identity acquisition rather than silently continuing with a less privileged parsing path that still performs sensitive work.
The same principle applies to malformed control-message traversal. The application has to verify message type, level, and expected payload size before using a struct ucred. Kernel-originated metadata still arrives through a userspace parsing boundary.
Kernel-observed identity is a narrow local authentication primitive
Peer credentials remove a specific ambiguity from local IPC: the client does not need to assert its own process identity in ordinary request data. The kernel can bind identity metadata to connection establishment or message receipt and enforce the documented substitution rules.
That property does not authenticate application intent, executable provenance, account ownership beyond the represented credentials, or the correctness of the request itself. It also does not replace discretionary or mandatory access controls surrounding the processes and socket.
A robust local protocol therefore keeps the boundary explicit. SO_PEERCRED can establish a connection-scoped identity snapshot; SCM_CREDENTIALS can provide message-scoped provenance; endpoint permissions can constrain reachability; and application policy can map those kernel-observed facts to allowed operations. The security value comes from keeping those roles separate rather than treating any single credential field as complete local authentication.