Thursday, August 02, 2012

VSFTPD "refusing to run with writable root inside chroot" Work-around

Hey there, everyone! I've been very busy lately with a couple different projects, but I thought I'd take the time to share my latest challenge and how I worked around it. The other day, I updated my Ubuntu servers from 10.04 to 12.04. This update brings with it a new version of VSFTPD (Very Secure FTP Daemon) which boasts some security improvements. Unfortunately, one of these improvements is causing a lot of headaches for me and other server maintainers.

VSFTPD has buffed up security pertaining to chroot'ed users. The (brief) reasoning behind it is that users jailed to directories they have write access on may alter scripts in such a way that would allow them to "break out of" the jail. While I acknowledge this as something to take into consideration, I feel the compromise between security and usability currently being forced onto us is unacceptable. Many configurations that worked perfectly fine before the update now throw an error when a chroot'ed user logs in:

500 OOPS: vsftpd: refusing to run with writable root inside chroot ()

A quick Google search turns up some obvious solutions, like stripping write permissions from the user on their home directory, moving files you want the user to have access to into subfolders (where they can have write access), or using the local_root config directive to jail users to the parent directory instead. You can even replace VSFTPD with the vsftpd-ext package, which supports the allow_writeable_chroot config directive. But, these weren't viable solutions for me; I didn't want to remove write access from users on the one place on the system I feel they should be guaranteed full-run over, I didn't want to allow nosey users to see what other files and folders were outside of their own area, and I didn't want to install an alternative package just to fix one simplistic issue. So I came up with my own solution!

My configuration is set up to not jail users by default. This allows accounts like mine and my operating partners to navigate the entire system, while also allowing me to limit what is visible to specific users for simplicity or to keep them out of places they shouldn't be in.

$ nano /etc/vsftpd.conf
...
chroot_local_user=NO
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd.chroot_list
user_config_dir=/etc/vsftpd_user_conf

$ nano /etc/vsftpd.chroot_list
# List of local users to chroot() jail in their home directory when FTPing
foo
bar
foobar

Above, we can see that my config file calls for local users to not be chroot jailed by default, but to jail specific users listed in /etc/vsftpd.chroot_list, and to also find user-specific config files in the /etc/vsftpd_user_conf directory. The list file is pretty straight-forward (one username per line). This next part is where the magic comes in. The objective is to jail the users in such a directory that the only thing they could possibly see in their FTP listing would be their home directory. This directory must not have write access, and it must preserve the existing directory structure. There is a great utility for this sort of thing: links! But therein lies a problem. Directories can only be symlinked/softlinked, and FTP clients typically can't follow symlinks.

Luckily, there is another, much more powerful way to create links to directories. If you are familiar with the mount command, you know that it's used to create links between the filesystem and physical data. Did you know it can also create links between one area of the filesystem and another? The magical command uses the syntax mount --bind originalfile linkname. Now let's put it to work!

This next part will require you to know the superuser password. If you don't know it, but your account is allowed to sudo, skip the su root command and preceed each of the other lines with sudo.

$ nano /etc/vsftpd_user_conf/foo
local_root=/srv/ftp/foo

$ su root
# mkdir /srv/ftp/foo
# chown foo:foo /srv/ftp/foo
# chmod ug-w /srv/ftp/foo
 
# mkdir /srv/ftp/foo/foohome
# mount --bind /home/foo /srv/ftp/foo/foohome

In the first part, we see that we change foo's local root directory to /srv/ftp/foo instead of his typical home directory (in this example, /home/foo, though it could be anywhere). I chose to use the /srv/ftp directory to house these jails, but you can use any directory you'd like as long as it has world read-execute permissions. In the second part, we run a couple commands to create the necessary directories, set the owner and access flags, and finally link the original home directory to the new area.

That's all there is to it! Simply repeat the above process for each jailed user, giving each one their own vsftpd_user_conf entry and /srv/ftp folder. Please note that you will have to execute the mount --bind command again for each user after every system reboot. To avoid this chore, I created a script and referenced it in my /etc/rc.local file. You can find more details about writing scripts and making them execute each time your system starts on plenty of other sites. I hope this has helped!

5 comments:

Andy said...

Nice try but I couldn't reproduce this workaround. Following this on our ubuntu setup, vsftpd would read the user specific local_root folder and drop the login directly into that path - so it drops them at foo and ls would show foohome.

I think our version users local_root in preference to the home dir.

This is such a silly restriction - users not being able to write in their home dirs? What were they thinking?

Blake said...

@Andy, it sounds like you did successfully reproduce my solution. It isn't perfect in that it requires the user be entered into a directory containing the actual target (home) directory, but I felt this was an acceptable trade-off.

I agree whole-heartedly that this restriction is silly. I see it as a fix to a breach that could happen, but honestly doesn't happen very often.

Unknown said...

I am still receiving the "500 OOPS: vsftpd: refusing to run with writable root inside chroot()" error. I am using Ubuntu 12.04 and vsftpd from the latest repos. The way I am trying to access the server is with FileZilla, FireFox, and through the commandline. I receive the same error with all of those. I followed your walk-through as well as others. What else could i be missing.

Would you be able to contact me so we could discuss the exact steps to set up a VSFTPD server on Ubuntu?

Blake said...
This comment has been removed by the author.
Unknown said...

Awesome solution. Worked nicely, thank you :)