sftp-server: add a chroot option
Eloi Benoist-Vanderbeken
eloi.benoist-vanderbeken at synacktiv.com
Sat Apr 11 00:41:45 AEST 2026
vsftpd will not do the job for us (for several reasons that I won't bother you with).
Why not merge this patch?
--
Eloi Benoist-Vanderbeken
Synacktiv
+33 (0)6 67 92 63 35
-----Original Message-----
From: Nico Kadel-Garcia <nkadel at gmail.com>
To: Dirk-Willem van Gulik <dirkx at webweaving.org>
Cc: Eloi Benoist-Vanderbeken <eloi.benoist-vanderbeken at synacktiv.com>, Jochen Bern <Jochen.Bern at binect.de>, openssh-unix-dev at mindrot.org
Subject: Re: sftp-server: add a chroot option
Date: 04/09/2026 08:09:21 PM
For most uses, don't bother. The vsftpd daemon does a quite good job
of chroot caging FTPS, with far less overhead maintaining it.
On Wed, Apr 1, 2026 at 5:16 AM Dirk-Willem van Gulik
<dirkx at webweaving.org> wrote:
>
> FWIIW - would love this go in !
>
> And this works cleanly for me on 14.3-RELEASE (fairly trivial setup where there is no shell or other access).
>
> Dw
>
> > On 1 Apr 2026, at 09:01, Eloi Benoist-Vanderbeken <eloi.benoist-vanderbeken at synacktiv.com> wrote:
> >
> > Hi list,
> >
> > Any news on this? It's a pretty simple patch and it should be harmless as it is very similar to ssh ChrootDirectory option.
> > We can still think about the namespace option in the future but this implementation already offers a real security and usability advantage for most (all ?) of the platforms at almost no cost.
> >
> > Kind regards,
> > --
> > Eloi Benoist-Vanderbeken
> > Synacktiv
> > +33 (0)6 67 92 63 35
> >
> > Hi Jochen,
> >
> > > If I understand correctly, you have to create a "fully equipped" chroot
> > > tree (with copies of all used libraries, $CHROOT/etc/passwd and
> > > $CHROOT/etc/group for proper "ls -l" output, maybe a $CHROOT/dev/log
> > > with the syslogd doing an extra LISTEN on it so as to have working
> > > logging, yadda yadda), anyway.
> >
> > No, not at all, I call chroot when the process is initialized, so
> > sftp-server already had the opportunity to open whatever it needs and now
> > only sees what the sftp user should be able to access (and not the
> > sftp-server executable nor /etc).
> >
> > It's almost the same than the ChrootDirectory option with internal-sftp.
> > That's also why I proposed it.
>
> > Am 25.02.26 um 12:31 schrieb Eloi Benoist-Vanderbeken:
> > > [...] I would like to add an option to chroot the sftp-server.
> > > I am well aware that I could use ChrootDirectory with internal-sftp
> > > but that doesn't work for me. [...]
> >
> > If I understand correctly, you have to create a "fully equipped" chroot
> > tree (with copies of all used libraries, $CHROOT/etc/passwd and
> > $CHROOT/etc/group for proper "ls -l" output, maybe a $CHROOT/dev/log
> > with the syslogd doing an extra LISTEN on it so as to have working
> > logging, yadda yadda), anyway. If so, wouldn't wrapping the (unchanged)
> > sftp-server executable/process with the OS' chroot(1) command do the
> > trick already?
> diff --git a/sftp-server.c b/sftp-server.c
> index b98c3cd41..d7677d199 100644
> --- a/sftp-server.c
> +++ b/sftp-server.c
> @@ -1888,7 +1888,8 @@ sftp_server_usage(void)
> extern char *__progname;
>
> fprintf(stderr,
> - "usage: %s [-ehR] [-d start_directory] [-f log_facility] "
> + "usage: %s [-ehR] [-C chroot_directory] "
> + "[-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",
> @@ -1902,7 +1903,7 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
> int i, r, in, out, ch, skipargs = 0, log_stderr = 0;
> ssize_t len, olen;
> SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
> - char *cp, *homedir = NULL, uidstr[32], buf[4*4096];
> + char *cp, *homedir = NULL, *chrootdir = NULL, uidstr[32], buf[4*4096];
> long mask;
>
> extern char *optarg;
> @@ -1914,7 +1915,7 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
> 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:C:cehR")) != -1) {
> switch (ch) {
> case 'Q':
> if (strcasecmp(optarg, "requests") != 0) {
> @@ -1937,6 +1938,9 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
> */
> skipargs = 1;
> break;
> + case 'C':
> + chrootdir = optarg;
> + break;
> case 'e':
> log_stderr = 1;
> break;
> @@ -2022,6 +2026,16 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
> if ((oqueue = sshbuf_new()) == NULL)
> fatal_f("sshbuf_new failed");
>
> + if (chrootdir != NULL) {
> + if (chdir(chrootdir) != 0) {
> + fatal_f("chdir to \"%s\" failed: %s", chrootdir,
> + strerror(errno));
> + }
> + if (chroot(chrootdir) != 0)
> + fatal_f("chroot to \"%s\" failed: %s", chrootdir,
> + strerror(errno));
> + }
> +
> if (homedir != NULL) {
> if (chdir(homedir) != 0) {
> error("chdir to \"%s\" failed: %s", homedir,
>
> _______________________________________________
> 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