[HN Gopher] Don't abuse su for dropping user privileges (2015)
       ___________________________________________________________________
        
       Don't abuse su for dropping user privileges (2015)
        
       Author : aargh_aargh
       Score  : 43 points
       Date   : 2023-05-26 10:49 UTC (12 hours ago)
        
 (HTM) web link (jdebp.uk)
 (TXT) w3m dump (jdebp.uk)
        
       | chasil wrote:
       | I still have some SysV init and I use it to respawn Oracle
       | clients in runlevel 4.
       | 
       | I use this C to knock down the privilege from root to the app
       | client account before I execve() the target:
       | setfsgid(g);       setfsuid(u);       if(setgroups(NULL) ||
       | setresgid(g,g,g) || setresuid(u,u,u))       {
       | fprintf(stderr, "permissions error\n");         exit(1);       }
       | 
       | I hope that I did this correctly. Even if incorrect, it's worked
       | since 2013.
       | 
       | Interesting that the post's linked article does not even mention
       | real, effective, and saved user/groupIDs.
        
         | st_goliath wrote:
         | > Interesting that the post's linked article does not even
         | mention real, effective, and saved user/groupIDs.
         | 
         | Even worse, the article doesn't even mention TIOCSTI, which is
         | another big reason, you should not use `su` this way (see e.g.
         | https://www.errno.fr/TTYPushback.html).
         | 
         | The program run under su keeps the same TTY and can use the
         | TIOCSTI ioctl to push data back into the TTY input buffer. When
         | the program exits and the parent reads from stdin, it receives
         | those bytes. If the parent happens to be a root shell from
         | which you dropped privileges using su, you have a problem.
        
           | JdeBP wrote:
           | TIOCSTI is irrelevant. When one is _dropping_ privileges, in
           | a system cron job or in a process supervised by one 's
           | favourite service management system, there is no terminal
           | involved. TIOCSTI simply doesn't enter into the picture at
           | all.
           | 
           | Only when one is in a terminal login session and using su to
           | _elevate_ / _add_ privileges, does TIOCSTI become relevant.
           | But no-one here is saying not to use su to _add_ privileges.
           | 
           | People blame su, sudo, and (as the person at
           | https://github.com/slicer69/doas/issues/110 did) doas for
           | this feature of operating system kernels. The right thing to
           | do with TIOCSTI it to just eliminate it from the kernel.
           | OpenBSD did back in version 6.
           | 
           | Sadly, the argument from Alan Cox, Linux developer, when this
           | was proposed years ago was that it should stay in Linux, and
           | all of the programs like su, sudo, and doas should have _even
           | more_ things to do in the parent process that sticks around,
           | namely pump I /O to and from a controlling pseudo-terminal
           | that su/sudo/doas sets up for the shell subprocess, breaking
           | (as the maintainer of OpenDoas pointed out) the long-standing
           | notion that the child processes belong to the same terminal
           | session and share things like a single getlogname() with the
           | login shell.
           | 
           | 6 years after https://www.openwall.com/lists/kernel-
           | hardening/2017/05/10/3... and
           | https://www.openwall.com/lists/oss-security/2017/06/03/9,
           | there is no sign of anyone doing anything of the sort in any
           | su or doas implementation. (It was briefly in one su
           | implementation, but taken out in 2017 for being a "stupid
           | hack": https://github.com/util-linux/util-
           | linux/commit/23f75093264a...)
           | 
           | Fortunately, some six months ago Linux developers finally
           | made TIOCSTI removable and the right course of action is
           | available to those that want it: https://lore.kernel.org/lkml
           | /20221228205726.rfevry7ud6gmttg5...
        
           | ptx wrote:
           | The linked page also describes how this problem is solved by
           | using "su -P" or the "use_pty" option with sudo, but says
           | that is disabled by default. Any idea why the security fix
           | isn't enabled by default?
        
       | RjQoLCOSwiIKfpm wrote:
       | The article seems quite unclear about potential consequences of
       | using su this way.
       | 
       | I typically use su to run some program in its own user account to
       | ensure:
       | 
       | - it has its own homedir and doesn't fill mine with garbage.
       | 
       | - there is some level of isolation from the rest of the system
       | for security, a basic "jail". I'm not trying to protect against
       | targeted attacks from extremely competent threat actors here, but
       | rather trying to stick software into its own user account so it
       | can only access that account, with isolation of the same level as
       | if I had manually logged in to a secondary account.
       | 
       | Can such programs break out of their "jail" when using su?
       | 
       | Or is the author of the article just angry for other reasons?
        
         | jacobvosmaer wrote:
         | The article does not talk about security problems. It's about
         | whether your daemon works correctly.
         | 
         | 1. Depending on the environment, process supervision can break
         | if there is an unexpected process sitting between the
         | supervisor and the supervisee. The article describes how the
         | switch to PAM forced the introduction of an in-the-middle
         | process responsible for closing the PAM session. The old su
         | used exec, which avoids an in-the-middle process.
         | 
         | 2. Su uses the shell of the target user, and will outright not
         | work if the target user has a "nologin" shell.
         | 
         | The article goes on to mention correct workarounds for this
         | like daemontools setuidguid, Runit chpst or just rolling your
         | own exec wrapper.
        
         | jjnoakes wrote:
         | > angry
         | 
         | Seems like an unnecessary assumption.
        
         | AstralStorm wrote:
         | Yes, the program can likely setuid to the original user with
         | su, as the session is the parent session and still active.
         | 
         | This is not a behavior you want of a jail. Use chroot, LXC or
         | your own setuid wrapper that removes the privilege.
        
           | kazinator wrote:
           | Every process in your system either still has an ancestor
           | that is still running and has superuser privileges. Either
           | because that was the real ancestor, or else because that
           | ancestor is PID 1 due to reparenting.
           | 
           | A process cannot use its existing ancestral sessions to gain
           | control of their account.
        
           | ptx wrote:
           | Well, os.setuid and os.seteuid in Python give me
           | "PermissionError: [Errno 1] Operation not permitted". Do you
           | have an example of how this could be done?
        
       | Tuna-Fish wrote:
       | So, what is the correct default (nothing self-built, please)
       | command to start a shell using the privilege level of some less
       | privileged user? Setuigid doesn't seem to be included by default
       | in distributions.
        
         | klodolph wrote:
         | The su command is correct for that purpose, as is sudo.
         | 
         | This is kind of a subtle point that the article makes--the
         | problem is that "su" is not good for dropping user privileges
         | _in general_ , but it does work if you are a user trying to
         | spawn an interactive shell as another user.
         | 
         | Keep in mind that you are giving control of your terminal to
         | that less-privileged account, and that this is a potential
         | point of privilege escalation.
        
         | tkhattra wrote:
         | check out the setpriv command - https://man7.org/linux/man-
         | pages/man1/setpriv.1.html
        
         | cwillu wrote:
         | According to man su(1):
         | 
         | "su is mostly designed for unprivileged users, the recommended
         | solution for privileged users (e.g. scripts executed by root)
         | is to use non-set-user-ID command runuser(1) that does not
         | require authentication and provide separate PAM configuration.
         | If the PAM session is not required at all then the recommend
         | solution is to use command setpriv(1)."
        
       | tinus_hn wrote:
       | Writing daemon instead of daemon is not cute and not clever.
        
         | LanternLight83 wrote:
         | i think its cute
        
       | justin_oaks wrote:
       | I assume that is why I see gosu [1] used so often for dropping
       | privileges in Docker containers.
       | 
       | It's good to have some explanation as to why su is unsuitable for
       | this.
       | 
       | [1] https://github.com/tianon/gosu
        
       | kazinator wrote:
       | This article is nonsense. I'm afraid.
       | 
       | Firstly, the su program isn't standardized by POSIX, so
       | everything we say about it is system-dependent.
       | 
       | On the systems where that trick is used, su is documented as
       | having that feature.
       | 
       | When su is executed by root (so that its setuid bit is moot), it
       | knows this, and allows a credentials change to a specified
       | account without prompting for a password. This is a feature and
       | the example cron jobs are using it correctly to obtain their
       | desired effect of impersonating that user.
       | 
       | su is not "dropping privileges"; it's impersonating a specific
       | user, in a command dispatched from a root cron job or other
       | script.
       | 
       | Thus all that might be wrong is the _rhetoric_ used to describe
       | the scripts, not what the scripts are actually doing, and only if
       | we are nitpicky.
       | 
       | "Dropping privileges" has a strict meaning, referring to the
       | situation that some user _bob_ invoked a setuid root executable,
       | which then disrobes itself of the root privilege, changing its
       | effective-root uid to just _bob_ again.
       | 
       | When root changes to another account that is unrelated to the
       | real user ID, nevertheless, that situation fits the description
       | of "dropping privileges" because that account is strictly less
       | privileged than root.
       | 
       | > The right way ... Create a small wrapper binary with C
       | 
       | That's a silly nonstarter.
       | 
       | > _The new implementation called fork() and only dropped
       | privileges in the child, retaining a privileged account parent
       | process that could call the PAM "user session" cleanup function
       | once the child exited._
       | 
       | Privileged parents waiting for unprivileged children to terminate
       | is an established pattern in Unix-like systems.
       | 
       | E.g. PID 1 (init or systemd) is privileged and handles the
       | termination of everything that has no parent.
       | 
       | The author is not connecting the dots here: reporting some actual
       | privilege escalation bug in the use of "su bob command ...".
       | 
       | Interactively, when you are root, you can do this:
       | root # su bob       /home/bob$ exit       root #
       | 
       | This exit back to root is not a security hole, and it is not
       | relevant to the scripted scenario at all. Bob has not actually
       | gained root access. The order of messages on the TTY isn't what
       | determines the security context semantics.
        
         | TacticalCoder wrote:
         | > This exit back to root is not a security hole
         | 
         | Wait... Doing just "su bob" is vulnerable to a known decades
         | old exploit. You should do either "exec su bob" or "su -P bob"
         | or you just gave bob root rights on every Linux kernel older
         | than 6.2 (and I think on 6.2 and more recent the default is
         | still insecure?).
         | 
         | It's explained here with a simple PoC exploit (I tried the
         | exploit and it works/worked) and it's been frontpage on HN in
         | the past I think:
         | 
         | https://www.errno.fr/TTYPushback.html
        
           | hulitu wrote:
           | > Consider this python sample and assume it's automatically
           | being run at logon from the .bashrc of a technical account,
           | such as postgres, to which the root user changes by typing su
           | - postgres
           | 
           | From su man page: "su is mostly designed for unprivileged
           | users, the recommended solution for privileged users (e.g.,
           | scripts executed by root) is to use non-set-user-ID command
           | runuser(1) that does not require authentication and provides
           | separate PAM configuration. If the PAM session is not
           | required at all then the recommended solution is to use
           | command setpriv(1)."
        
       ___________________________________________________________________
       (page generated 2023-05-26 23:01 UTC)