sftp-server: add a flag to call unveil on starting directory

Chris Rapier rapier at psc.edu
Thu Jan 29 08:27:01 AEDT 2026


The main objection I can see to this is that it might require no small 
amount work on the portable branch to have this in other OSes as unveil 
seems to be limited to OpenBSD.

Chris

On 1/28/2026 15:54, s-k2 at caipora.net wrote:
> Dear list,
> 
> I would like to discuss whether it is possible to add an optional flag
> to sftp-server that uses unveil to restrict filesystem access to the
> starting directory and paths beneath it. Greping the mailing list
> surprisingly revealed no discussion about unveil usage so far, thus I'll
> try my luck here.
> 
> Such a flag would make it possible to apply restrictions for specific
> SSH keys, for example by using them for just a specific file access
> task. With the patch below, I can restrict the SFTP access of my music
> player, while other keys retain normal access permissions, using an
> authorized_keys file like this:
> 
> restrict="/usr/libexec/sftp-server -d /home/sk/music -U" MUSIC-DEV-KEY
> ssh-ed25519 UNRESTRICTED-ACCESS-KEY
> 
> Would it be possible to add that feature? I know that this could also be
> accomplished with an additional user and appropriate group permissions.
> However, using different keys seems much easier to me and encourages
> narrowing down restrictions to specific use cases.
> 
> While reading through the code, I noticed three extension commands that
> are affected when a user activates that flag. All of them fail because
> /etc/passwd is no longer accessible:
> 
> - "users-groups-by-id at openssh.com"
> - "expand-path at openssh.com" (only when ~user is used)
> - "home-directory"
> 
> In my oppinion that is not a real problem, as the user explicitly adds a
> flag to limit filesystem access. I would argue against calling unveil
> for the passwd file as well, because a user would not expect this to be
> accessible anymore. Instead, I mention that in the man page.
> 
> I would be glad if you could share your opinions about that flag!
> 
> Kind regards,
> Stefan
> 
> 
> diff -u -r ssh-10.2/sftp-server.8 ssh/sftp-server.8
> --- ssh-10.2/sftp-server.8	Tue Jul 27 16:14:25 2021
> +++ ssh/sftp-server.8	Mon Jan 26 03:51:04 2026
> @@ -31,7 +31,7 @@
>   .Sh SYNOPSIS
>   .Nm sftp-server
>   .Bk -words
> -.Op Fl ehR
> +.Op Fl ehRU
>   .Op Fl d Ar start_directory
>   .Op Fl f Ar log_facility
>   .Op Fl l Ar log_level
> @@ -138,6 +138,13 @@
>   .Xr umask 2
>   to be applied to newly-created files and directories, instead of the
>   user's default mask.
> +.It Fl U
> +Restrict filesystem access to the starting directory and all paths beneath
> +it using the
> +.Xr unveil 2
> +system call. Extended SFTP commands that read the
> +.Xr passwd 5
> +file may fail.
>   .El
>   .Pp
>   On some systems,
> diff -u -r ssh-10.2/sftp-server.c ssh/sftp-server.c
> --- ssh-10.2/sftp-server.c	Tue Sep  2 11:26:21 2025
> +++ ssh/sftp-server.c	Mon Jan 26 03:57:27 2026
> @@ -1859,7 +1859,7 @@
>   	extern char *__progname;
>   
>   	fprintf(stderr,
> -	    "usage: %s [-ehR] [-d start_directory] [-f log_facility] "
> +	    "usage: %s [-ehRU] [-d start_directory] [-f log_facility] "
>   	    "[-l log_level]\n\t[-P denied_requests] "
>   	    "[-p allowed_requests] [-u umask]\n"
>   	    "       %s -Q protocol_feature\n",
> @@ -1870,7 +1870,7 @@
>   int
>   sftp_server_main(int argc, char **argv, struct passwd *user_pw)
>   {
> -	int i, r, in, out, ch, skipargs = 0, log_stderr = 0;
> +	int i, r, in, out, ch, skipargs = 0, log_stderr = 0, unveil_cwd = 0;
>   	ssize_t len, olen;
>   	SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
>   	char *cp, *homedir = NULL, uidstr[32], buf[4*4096];
> @@ -1884,7 +1884,7 @@
>   	pw = pwcopy(user_pw);
>   
>   	while (!skipargs && (ch = getopt(argc, argv,
> -	    "d:f:l:P:p:Q:u:cehR")) != -1) {
> +	    "d:f:l:P:p:Q:u:cehRU")) != -1) {
>   		switch (ch) {
>   		case 'Q':
>   			if (strcasecmp(optarg, "requests") != 0) {
> @@ -1946,6 +1946,9 @@
>   				fatal("Invalid umask \"%s\"", optarg);
>   			(void)umask((mode_t)mask);
>   			break;
> +		case 'U':
> +			unveil_cwd = 1;
> +			break;
>   		case 'h':
>   		default:
>   			sftp_server_usage();
> @@ -1981,6 +1984,13 @@
>   			error("chdir to \"%s\" failed: %s", homedir,
>   			    strerror(errno));
>   		}
> +	}
> +
> +	if (unveil_cwd) {
> +		if (unveil(".", "rwc") != 0)
> +			error("unveil cwd failed: %s", strerror(errno));
> +		if (unveil(NULL, NULL) != 0)
> +			error("blocking unveil failed: %s", strerror(errno));
>   	}
>   
>   	for (;;) {
> _______________________________________________
> openssh-unix-dev mailing list
> openssh-unix-dev at mindrot.org
> https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev



More information about the openssh-unix-dev mailing list