From 4bea2e96e2c479fac90553af3d73f432981eabdd Mon Sep 17 00:00:00 2001 From: deraadt Date: Sat, 7 Mar 2026 18:35:43 +0000 Subject: [PATCH] With it's own daemonization / fd cleaning code, ssh-agent opens /dev/null O_RDWR after a pledge without "wpath". This is allowed in current pledge because "/dev/null" is implicitly allowed to be opened even with the most restrictive pledges or unveils. This is a design decision in pledge made at the very beginning, to satisfy libc requirements. We've finally had enough experience and know how to fix that in the near-future, but need to review and fix all code which opens these implicit paths. The fix is to add "wpath", so that "/dev/null" can be opened O_RDWR. But that is uncomfortable, so we add unveil() allowing "/" with "r", 4 unveil "x" for the potential askpass and helpers to be execve'd, and "/dev/null" with "wr". As a result filesystem access is substantially more restricted than before, and ssh-agent is ready for the future pledge change. ok djm dtucker --- usr.bin/ssh/ssh-agent.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/usr.bin/ssh/ssh-agent.c b/usr.bin/ssh/ssh-agent.c index 93b5d399b41..be4b7a689f6 100644 --- a/usr.bin/ssh/ssh-agent.c +++ b/usr.bin/ssh/ssh-agent.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-agent.c,v 1.320 2026/03/05 05:35:44 djm Exp $ */ +/* $OpenBSD: ssh-agent.c,v 1.321 2026/03/07 18:35:43 deraadt Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -2521,7 +2521,25 @@ skip: sigaddset(&nsigset, SIGTERM); sigaddset(&nsigset, SIGUSR1); - if (pledge("stdio rpath cpath unix id proc exec", NULL) == -1) + if (unveil("/", "r") == -1) + fatal("%s: unveil /: %s", __progname, strerror(errno)); + if (getenv("SSH_SK_HELPER")) + if (unveil(getenv("SSH_SK_HELPER"), "x") == -1) + fatal("%s: unveil %s: %s", __progname, + getenv("SSH_SK_HELPER"), strerror(errno)); + if (unveil(_PATH_SSH_SK_HELPER, "x") == -1) + fatal("%s: unveil %s: %s", __progname, + _PATH_SSH_SK_HELPER, strerror(errno)); + if (getenv("SSH_ASKPASS")) + if (unveil(getenv("SSH_ASKPASS"), "x") == -1) + fatal("%s: unveil %s: %s", __progname, + getenv("SSH_ASKPASS"), strerror(errno)); + if (unveil(_PATH_SSH_ASKPASS_DEFAULT, "x") == -1) + fatal("%s: unveil %s: %s", __progname, + _PATH_SSH_ASKPASS_DEFAULT, strerror(errno)); + if (unveil("/dev/null", "rw") == -1) + fatal("%s: unveil /dev/null: %s", __progname, strerror(errno)); + if (pledge("stdio rpath cpath wpath unix id proc exec", NULL) == -1) fatal("%s: pledge: %s", __progname, strerror(errno)); while (1) {