64

In Ubuntu releases prior to Ubuntu 19.10 Eoan Ermine, when I run a command with sudo, that command receives my home directory in the $HOME environment variable. This is the behavior I have long expected and warned other people about. If I want sudo to reset the $HOME environment variable, so that it refers to the target user's home directory instead of my own, I have to pass the -H option (or -i, though that does more).

ek@Kip:~$ lsb_release -d
Description:    Ubuntu 18.04.3 LTS
ek@Kip:~$ sudo printenv HOME  # Shows ek's home, not root's.
/home/ek
ek@Kip:~$ sudo -u as printenv HOME  # Shows ek's home, not as's.
/home/ek
ek@Kip:~$ sudo -H printenv HOME  # Shows root's home.
/root
ek@Kip:~$ sudo -Hu as printenv HOME  # Shows as's home.
/home/as

When I first upgraded to Ubuntu 19.10, I was surprised to discover that sudo seems to reset $HOME no matter what! I continue to observe this now that 19.10 is released and I've installed updates--both on newly installed systems and one I upgraded to 19.10.

ek@Cord:~$ lsb_release -d
Description:    Ubuntu 19.10
ek@Cord:~$ sudo printenv HOME  # Shows root's home, even without -H or -i.
/root
ek@Cord:~$ sudo -u as printenv HOME  # Shows as's home, even without -H or -i.
/home/as
ek@Cord:~$ sudo -H printenv HOME  # Also shows root's home.
/root
ek@Cord:~$ sudo -Hu as printenv HOME  # Also shows as's home.
/home/as

I thought this might be due to updated configuration files. But I checked, and always_set_home does not appear in any Defaults line in my 19.10 /etc/sudoers file.

What makes sudo treat $HOME differently starting in 19.10, and why was this change made? Does this make it safe to use plain sudo in cases where I would previously have used sudo -H?

83

For years, Ubuntu has shipped a patched version of sudo that preserves $HOME by default. Besides Ubuntu and its derivatives, very few other operating systems (perhaps no others) do this. It has been decided that this causes more problems than it solves, and starting in Ubuntu 19.10, $HOME is no longer one of the few environment variables sudo preserves.

In terms of what the change is and how it affects users, the key points are:

  • As of Ubuntu 19.10, sudo command does what sudo -H command does in previous releases. It can indeed be used in cases that would have previously advised sudo -H, including to run GUI applications as root or another user. Running graphical programs as root at all remains controversial. But in 19.10 you can run sudo gedit with the exact same effect as sudo -H gedit. In 19.10, commands like sudo gedit no longer create annoying file ownership problems in your home directory.
  • This applies even on systems upgraded to 19.10 from an earlier release, even when the upgrade doesn't change your /etc/sudoers file. The change is in the source code of the sudo program itself, not in its default configuration files. (It can be overridden in a sudoers file, but you'd probably know if you did this.)
  • It doesn't--and won't--apply to releases prior to 19.10. Before 19.10, sudo preserves $HOME by default, and future updates to sudo won't change that. For example, 18.04 LTS will always have the old behavior, even in future point releases.
  • sudo -H command still works fine. If you're in the habit of using that, no problem. You just don't have to, on a 19.10 system.
  • Most commands you run with sudo won't behave differently. In the overwhelming majority of situations where you would not have passed -H, you could have. Some users do rely on or otherwise prefer the old behavior of preserving $HOME. But that often had unintended effects. So if you were relying on this, you still might not want to override the change in a sudoers file.

See also WinEunuuchs2Unix's answer to Why should users never use normal sudo to start graphical applications?


Why The Change

As the changelog puts it (under "sudo (1.8.27-1ubuntu2) eoan"):

This restores sudo handling of $HOME to what everyone else does

"Everyone else" refers to the upstream sudo project (hosted here) and also seemingly all other operating systems that contain sudo, except those that derive from Ubuntu.

There's more to it, though. This is also considered to fix a security bug, as described in Ubuntu patch to add HOME to env_keep makes custom commands vulnerable by default. The history was concisely summarized in this comment there by Steve Langasek (whom you may have heard of), which I quote in full:

This change was originally introduced in response to bug #760140.

The upstream change in sudo was never accompanied by a CVE, and the behavior change was never applied to previous releases of Ubuntu, so it didn't seem security sensitive at the time.

I am not opposed to changing this to behave the way Simon describes, but I defer to the Security Team here.

Todd C. Miller, who maintains the upstream sudo project (very actively, and for many years now), was also asked for input on the issue. He explained the reason sudo resets (i.e., does not preserve) $HOME:

On Thu, 16 May 2019 07:48:40 -0400, Dan Streetman wrote:

I've cc'ed sudo-users, so the question to the upstream sudo list can be summarized as:
How likely would it be for upstream sudo to add HOME to env_keep by default?

Extremely unlikely. Prior to sudo 1.7.4 the HOME and MAIL environment variables were preserved in the environment by default. This can lead to programs using config files the original user's home directory, which has security implications, so the default was changed in 1.7.4.

In the old days, sudo did little more than change the uid. These days sudo tries to run the command in an environment that closely matches what you would get by logging in as that user. This has proven to be safer as it more closely matches the assumptions other programs make.

We ask because Ubuntu carries a patch that adds HOME to env_keep, unlike the default upstream, or any other Linux/Unix. We are considering removing that patch, to match upstream defaults, of not including HOME in env_keep.

I would be supportive of that. I believe that resetting HOME is the safer default.

- todd

(I have altered the formatting from the original message to display properly in this medium.)

As of 19.10, the downstream sudo in Ubuntu behaves as the upstream sudo (and sudo in other operating systems, including Debian) have behaved for many years. For more detailed information on the history of this change and the developments that preceded it, including numerous links for further reading, see the "sudo and $HOME: The Last 20 Years" section below.

Huh? a.k.a. Why it (sometimes) matters what sudo does with $HOME

Programs you run that need the location of your home directory often examine the value of the $HOME environment variable. One important case is when a program tries to store and access configuration files in the home directory of the user running it. Programs typically go by the value of $HOME. Sometimes when you run a program as a substitute user--for example, as the root account--it is appealing to have that program use your settings. But this can also get messy, in two ways:

  1. Usually when you run a command as another user, you want it to work mostly the same way as if that user had run it. But if it is a command whose behavior can be radically altered by the fact that you ran it--which happens if its behavior is heavily customized by data read from files found inside the directory named in $HOME--then this goal is not achieved.

    When you're permitted to perform any action you choose as any user including root (which in Ubuntu is conferred by membership in the sudo group), the issue is mostly one of accident. However, if you are a limited user and you have been permitted to run only specific commands with sudo, then being able to manipulate what those commands do has serious security implications. The bug report that led to the change in 19.10 was specifically motivated by that problem (and includes a compelling example of it).

  2. If you run a command as another user and the command makes changes to its configuration in the directory named in $HOME, an attempt is made to write the changes to files in that location. When the substitute user is not root, as in sudo -u username command, this typically fails and produces error messages, which is mildly annoying but not serious.

    But in the common case that the substitute user is root, as in sudo command, this succeeds, but if any new files are created, they are owned by root, and your user account no longer has full access to all its own configuration files. This can be fixed by chowning the files back, so the problem is most severe in the case of graphical applications, whose complexity can make it so more files, in more places, are involved (and where it has been reported to sometimes make login difficult, though usually the problem is less severe than that).

What changed, and why all 19.10 systems have the change

A short whitelist of environment variables that are not reset by default is hard-coded in sudo itself. In Ubuntu releases prior to 19.10, an Ubuntu-specific patch adds $HOME to this whitelist. It is compiled into a binary file used by sudo, so upgrading to a version of sudo that does not have the patch removes it from the whitelist.

The patch was removed in 19.10. So upgrading to 19.10 or higher will always apply the change, even when no configuration files associated with sudo are modified.

It is still possible to configure any version of sudo to preserve $HOME (see below). In the extremely unusual case that you did this before 19.10--when such a configuration would have made no difference--and kept that configuration across an upgrade, $HOME would still be preserved. But you would presumably remember having done this strange thing.

If your upgrade to 19.10 (or later) failed and gave you an only partially upgraded system with a version of sudo from before 19.10, then sudo on that system still preserves $HOME by default. This is almost the only case where sudo would preserve $HOME in 19.10 (or later) without you knowing about it--though you would still have been informed, during the release upgrade, that not all packages could be upgraded.

The easiest way to see directly that the patch is gone in the source code of sudo in Ubuntu 19.10 is to compare https://git.launchpad.net/ubuntu/+source/sudo/tree/debian/patches?h=ubuntu/disco-security to https://git.launchpad.net/ubuntu/+source/sudo/tree/debian/patches?h=ubuntu/eoan.

Still, if you are not sure how your system is configured, you can run sudo printenv HOME to find out.

Resetting $HOME in Ubuntu 19.04 and earlier

Although updates to sudo in Ubuntu 19.04 and earlier may include changes to the documentation to explain the situation, the way sudo treats $HOME in those releases has not been and will not be changed by any updates. Most users will not want to bother manually changing how sudo works on systems where they are already using it without problems. However, if you like, you can make sudo reset $HOME on those systems, even without upgrading them.

Any particular time you run sudo, you can use the -H/--set-home option to reset $HOME:

sudo -H command

Or you can use -i. This does more than reset $HOME. sudo -i command behaves as if you logged in as root, ran command, and logged out; sudo -i by itself behaves as if you logged in as root and places you in an interactive root shell. This differs from sudo -s, which starts an interactive shell that is not a login shell. Before Ubuntu 19.10, sudo -s preserves $HOME; that is, regardless of version, the -s option does not carry any behavior that affects how $HOME is treated. It is meaningful to use -H and -s together. You can also use any of -H, -i, and -s with -u user to become user rather than root. Finally, using sudo via the graphical frontends gksu or gksudo (still available in 16.04 LTS, though you may need to install the gksu package) resets $HOME.

If you want to reconfigure sudo so that it always resets $HOME, you can enable the always_set_home option in a sudoers file:

Defaults    always_set_home

You would add that line to /etc/sudoers or, better, to a new file in /etc/sudoers.d/. Either way, you should use visudo to edit the file, so you get the benefit of syntax checking. (A syntax error in any sudoers file causes sudo to refuse to work at all. This is a hassle, though it can be fixed.)

For example, on some of my pre-19.10 systems, I created and edited /etc/sudoers.d/always_set_home by running:

sudo visudo -f /etc/sudoers.d/always_set_home

In the file, I wrote the above Defaults line. The filename need not be always_set_home--it can be whatever you like, so long as it contains no . or ~ character. The word on the Defaults line does, of course, need to be exactly always_set_home.

(One reason to prefer making a new file in /etc/sudoers.d/ to modifying the existing /etc/sudoers file is that, if a future update ever does change the default /etc/sudoers file, you can accept the new file without losing your customizations. Another reason is that it is immediately clear that you have changed the configuration, and where your changes may be found.)

If you do this and later wish to run an individual sudo command that preserves $HOME, you can do that the same way you would do it in 19.10 (see below).

Preserving $HOME in Ubuntu 19.10 and later

The way sudo treats $HOME has been changed for a reason. (See the above sections, as well as the detailed history section below.) But if you really want to make sudo continue to preserve $HOME, even in 19.10 and later, you can configure this behavior in a sudoers file.

Any particular time you run sudo, you can tell it to preserve $HOME with --preserve-env=HOME:

sudo --preserve-env=HOME command

This is the form of --preserve-env that is documented as --preserve-env=list in the sudo manpage. It is also possible to use --preserve-env with no list operand, which is the same as -E; that preserves all environment variables. But there's rarely a good reason to do that, especially if your goal is just to preserve $HOME. If you don't like typing --preserve-env=HOME, you could define a shell alias or shell function or write a script that lets you run a shorter command to do it. Even better would be to seldom preserve $HOME (see the section below on alternatives to doing so).

More generally, you can make sudo preserve any particular environment variable varname with --preserve-env=varname. (You may also see code that effectively preserves $HOME by setting it explicitly in the command sudo runs, such as with sudo HOME="$HOME" command. This also works. It is quite different from HOME="$HOME" sudo command, which would not keep sudo from resetting $HOME.)

Or if you really want to make sudo always preserve $HOME, you can do this by adding $HOME to env_keep in a sudoers file:

Defaults    env_keep += "HOME"

That can go in /etc/sudoers or a file in /etc/sudoers.d/. Although I stress I don't recommend doing this at all, if you decide to do it then I'd suggest creating and editing /etc/sudoers.d/keep-home (call the file what you like, so long as the name doesn't contain . or ~) by running:

sudo visudo -f /etc/sudoers.d/keep-home

Then you can put that Defaults line in the file.

The reason to use += instead of merely = is that there are a handful of other environment variables, hard-coded into sudo itself, that are preserved by default, and that you probably want preserved. If you used =, then only the environment variables you listed explicitly in the file would be preserved. In this case, that would be just $HOME. More information about the grammar of sudoers files is available in sudoers(5).

As for why I suggest making a file in /etc/sudoers.d/ instead of editing /etc/sudoers--and why you should definitely use visudo either way--see my comments in the "Resetting $HOME in Ubuntu 19.04 and earlier" section above.

Alternatives to Preserving $HOME

Most of the time you use sudo, the best alternative to preserving $HOME is to do nothing. Most sudo commands have the same effect (and some work slightly better) without $HOME preserved. However, I am aware of two popular use cases for preserving $HOME.

Using your text editor configuration and/or plugins to edit files owned by root or another user. sudoedit, or equivalently sudo -e, is an ideal alternative for this. It runs the editor as you, you edit a temporary copy of the file, and the file is updated when you quit the editor. Since the editor runs as you, it uses your configuration and plugins automatically, and does so without any risk of failing in opaque and unexpected ways with permission denied errors or making files in your home directory inaccessible to you. To edit file:

sudoedit file

To edit file with editor instead of the default editor:

SUDO_EDITOR=editor sudoedit file

For example, SUDO_EDITOR=vim sudoedit /etc/apt/sources.list edits /etc/apt/sources.list with vim.

To decide what editor to use, sudoedit consults the environment variable $SUDO_EDITOR; if that's unset, it consults $VISUAL; if that's unset, it consults $EDITOR; if that's unset, it tries editor commands from a hard-coded list, which in practice in Ubuntu means it uses editor. Typically that resolves to /usr/bin/editor, which is a symlink. If you want to change the default editor systemwide then you can change what /usr/bin/editor points to by running sudo update-alternatives --config editor. You can also set one of those three environment variables, which is a good way to change what sudoedit edits with for just one user.

Making programs you only run as root use specific configuration files. If a program you run as root looks in $HOME for its configuration, then you can just put that configuration in (or move that configuration to) root's home directory, /root.

Resetting $HOME when you don't know what release you're using

You may sometimes write a command and not know what release of Ubuntu (or what operating systems besides Ubuntu) it will run on. For example, you may be writing a script that you will run on multiple machines.

sudo continues to accept the -H option, with the same effect it always had. It just happens that, starting on 19.10, sudo without -H does the same thing (unless you have configured it to do otherwise) as sudo -H.

To write portable sudo commands that reset $HOME, you can continue using:

sudo -H command

(Also as before, if all the actions performed in your script need to be done as root, it's probably better not to use sudo in your script and just run the script as root with sudo.)

sudo and $HOME: The Last 20 Years

Around the turn of the century, the upstream sudo project introduced the env_reset option, which makes sudo reset most environment variables. This option is enabled unless disabled explicitly in a sudoers file. (It is possible to enable it explicitly, which Defaults env_reset in Debian and Ubuntu's /etc/sudoers file does, but this is not actually necessary.) Before sudo had env_reset, all environment variables were preserved unchanged. With env_reset, only a handful of variables were preserved. This included $HOME.

In July of 2010, $HOME was removed from that small whitelist and thus no longer preserved by default.

In September of 2010, a bug report about documenting that in the sudo package in Debian was filed. As far as I can tell, there was no controversy about, or objection to, the change itself, from Debian developers. (But see below.)

In February of 2011, the change had come further downstream from Debian to Ubuntu and Ubuntu developers discussed whether or not it was desirable.

In April of 2011, the change was reported as a bug, referencing that discussion. (Some behavior resulting from the change had been reported as a bug the day before that.) At least at the time, this was considered to be a regression ("the Debian maintainer already tried to fix this once but it appears the fix was incomplete"). I haven't found any such Debian bug report, but that doesn't mean there wasn't one; furthermore, a change could have been made without one. I suspect, though, that it may have been an erroneous reference to that documentation bug.

The next day, the development release of Ubuntu was updated with a downstream, Ubuntu-only patch, to re-add $HOME to the list of environment variables sudo preserved by default. I believe this was done quickly so as to make it into the release of Ubuntu 11.04. The effect was that sudo in 11.04, as in previous Ubuntu releases, preserved $HOME by default.

In November of 2011, a bug was reported about how the documentation for sudo in Ubuntu said $HOME was reset. That is, the manpage in Ubuntu correctly described the behavior of upstream sudo but not the patched behavior in Ubuntu.

In September of 2014, a bug was reported pointing out some of the problems with having sudo preserve $HOME by default and arguing that the problem with running graphical programs with normal sudo is not that it's inherently dangerous (often cited to this wiki page) but that sudo's unusual handling of $HOME in Ubuntu makes it dangerous and should be considered a bug. It appears there was significant interest in this bug report, including from Ubuntu developers, even though it would be some time before it would be fixed.

In March of 2016, the bug that would later become the main reference for the problems with sudo preserving $HOME was reported. Initially, this bug report focused specifically on the security problem that users who are not administrators (i.e., cannot run arbitrary commands as root), but who have been permitted to run specific commands with sudo, can maliciously alter the behavior of some programs, and in some cases even gain full control of the system. It recommended a narrow change that would attempt to address that case specifically, while still having $HOME preserved when members of the sudo group run commands as root or another user.

In April of 2019, a bug was reported objecting to the behavior of sudo preserving $HOME by default, even when sudo -s is used.

Later that month, discussion resumed on the March 2016 bug, toward the possible resolution of removing the Ubuntu-specific patch altogether. This broadened the focus of that bug report beyond the specific security vulnerability it described. The goal of making sudo in Ubuntu treat $HOME the same way upstream sudo (and sudo in other operating systems) treats it, starting in Ubuntu 19.10, was articulated.

In May of 2019, a bug was reported about how programs (including non-graphical programs) that use launchpadlib suffer configuration file ownership problems because sudo preserves $HOME.

A week later, another mailing list discussion on "how sudo handles $HOME" took place (see also this archive page), showcasing a range of views on how sudo ought to treat $HOME. One preference that was uncontroversial was that if a change were to be made, it should only be to 19.10 and later, and not be made in any updates for previous releases. The question arose of whether upstream sudo would continue resetting $HOME in future versions.

The upstream sudo maintainer, when consulted about this, made clear that no such upstream change is planned and supported the view that the downstream version of sudo in Ubuntu should also reset $HOME by default. That message, posted originally on the sudo-users mailing list, was quoted in a comment on the March 2016 bug report.

In June 2019, Ubuntu developers made plans to remove the patch that makes sudo in Ubuntu preserve $HOME.

About a week later, the change was made in Ubuntu's repositories. This change applies starting in 19.10. The only change that will be made to sudo in earlier releases is to update the documentation so it clearly and correctly describes the behavior of sudo in those releases.

Acknowledgements

  • 9
    +1's for your excellent Q&A. I don't really deserve first answer kudos because my answer was inspired by your comments about sudo changes in the Ask Ubuntu general chatroom. – WinEunuuchs2Unix Nov 8 at 1:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.