security: add peer credential validation to macOS ovpnagent - #442
security: add peer credential validation to macOS ovpnagent#442shaggyinsomniac wants to merge 2 commits into
Conversation
…d access The macOS ovpnagent listens on a Unix domain socket with mode 0777 and accepts all connections without verifying the peer's identity. Any local process can connect and issue privileged commands including: - POST /tun-setup: configure system routing and DNS as root, receive the tun file descriptor via SCM_RIGHTS - POST /add-bypass-route: modify the kernel routing table - GET /tun-destroy: tear down active VPN tunnels This change: 1. Validates the connecting process's UID via LOCAL_PEERCRED in allow_client(), rejecting connections that are not from root or the same user the agent runs as 2. Restricts the Unix socket mode from 0777 to 0600 The peercreds() and root_or_self_uid() infrastructure already exists in openvpn/common/peercred.hpp but was not being used by the macOS agent.
|
I agree that this is something we need to fix but I think the fix completely misunderstand the purpose of ovpnagent. This is done to allow privilege separation to allow an unprivileged user space OpenVPN process to do these commands. Having this open for everyone is not a good idea as that allows everyone to mess with the network configuration. But this fix will restrict ovpnagent to root only which defeats the purpose as well.: |
Restores socket mode to 0666 so unprivileged clients can connect again. allow_client() now accepts root unconditionally, and non-root peers only when their UID is listed in /etc/openvpn/ovpnagent.allowed_uids (numeric UID or username, one per line). The special entry "all" restores the legacy unrestricted behaviour for deployments that want it. Missing or unreadable allowlist file means root-only access.
|
Fair point, you're right — restricting the agent to root-only defeats the whole reason it exists. Sorry about that, I was too focused on closing the open access and broke the actual use case. I've pushed a rework (ee20602) that keeps unprivileged clients working:
One thing I'd like your input on: the default. I went with root-only until the admin opts users in via the allowlist file, since that's the safe failure mode. But I can see an argument for auto-allowing the current console user (the agent is really only ever talking to the logged-in user's client on a desktop). Happy to switch to whichever you think fits the project better — or a different config mechanism entirely if a file in /etc/openvpn isn't the right place for this. Built and ran the unit test suite locally on this revision (CoreTests passes, agent_macos target builds clean). |
|
Your answer reads like it was completely AI generated.
You are propsoing to fix a security problem and then also propose to keep the security in the program at the same time? That sounds like either the behaviour is fine and can kept as is or it is not fine because it is a security problem and needs to be fixed. This is a contradiction in my opinion. |
|
A side note, I just tested on Tahoe 26.6.2, and noticed the .socket files no longer are created in /var/run, not sure if they are but hidden from all users including root while I tried to list using sudo prefix but no difference? is this intended behaviour? Anyhow, the ovpnagent still works, and thanks for the PR. |
Summary
The macOS
ovpnagentdaemon runs as root and listens on a Unix domain socket(
/var/run/agent_ovpnconnect.sock) with mode0777. Theallow_client()method returns
trueunconditionally, meaning any local process —regardless of user or code signature — can connect and issue privileged
commands.
Impact
An unprivileged local process can:
POST /tun-setupPOST /add-bypass-routeGET /tun-destroyRoot Cause
Fix
Peer credential check in
allow_client()using the existingpeercreds()androot_or_self_uid()helpers fromopenvpn/common/peercred.hpp— these were already available but unused.Socket mode restricted from
0777to0600.Testing
Verified on macOS 27.0 (Apple Silicon):
POST /add-bypass-routereturns200 OK, kernel routing table modified (verified vianetstat -rn)Notes
This does not affect the Linux agent, which uses a different socket permission
model. The fix uses only infrastructure already present in the codebase.