[Toybox] Upgrades to su command.

Rob Landley rob at landley.net
Wed Feb 20 10:54:15 PST 2019


This came up recently:

  https://github.com/landley/toybox/issues/117#issuecomment-465610332

And it's been on my todo list forever: if you want to run a command as an
arbitrary UID/GID, it's kinda awkward to do so with sudo or su because both
conventionally want to look up a name out of /etc/passwd, and will error out on
a uid with no passwd entry even for root. But these days with things like
containers, there's lots of interesting UIDs and GIDs that aren't active in
/etc/passwd. (And then there's the whole android thing of not having an
/etc/passwd and using their version of the Windows Registry instead, because
keeping system information in human readable text files is too unixy or
something....)

So anyway, I want su -u UID and su -g GID[,gid,gid...] to work, at least for
root. And I want to be able to run an arbitrary command line without necessarily
having to wash it through a random command shell. And _implementing this is
fairly straightforward. No the hard part is writing the help text to explain it,
especially if I've kept compatibility with the original su behavior.

A word on the legacy su behavior: way back when setting a user's shell in
/etc/passwd to /bin/false or /dev/null was a way of preventing anybody from
running commands as that user. Then su grew -s to override which shell you were
running as, so this stopped working from a security standpoint. (Besides, if you
were running as root you could whip up a trivial C program to do it anyway, but
the point was _su_ no longer enforced it.) And it let you specify -c to pass a
command line to that shell so su could "run a command as a user" instead of
being interactive, so this ability is already _there_ for most users, just
awkward to use.

Here's the new help text I've got so far. Is it intelligible?

  usage: su [-lmp] [-u UID] [-g GID,...] [-s SHELL] [-c CMD] [USER [COMMAND...]]

  Switch user, prompting for password of new user when not run as root.

  With one argument, switch to USER and run user's shell from /etc/passwd.
  With no arguments, USER is root. If COMMAND line provided after USER,
  exec() it as new USER (bypasing shell). If -u or -g specified, first
  argument (if any) isn't USER (it's COMMAND).

  first argument is USER name to switch to (which must exist).
  Non-root users are prompted for new user's password.

  -s  Shell to use (default is user's shell from /etc/passwd)
  -c  Command line to pass to -s shell (ala sh -c "CMD")
  -l  Reset environment as if new login.
  -u  Switch to UID instead of USER
  -g  Switch to GID (only root allowed, can be comma separated list)
  -p  Preserve environment

One other thing... I've been pondering a "contain" command for a long time that
combines unshare, nsenter, chroot (really pivot_root because
http://lkml.iu.edu/hypermail/linux/kernel/1310.0/02823.html), uid/gid range
remapping, su, and possibly oneit or similar. (How you marshall
stdin/stdout/stderr out of the container and into something the host can see is
sort of a pty problem requiring a host daemon to monitor the container. And what
_does_ happen to dmesg, anyway? I forget...)

It's probably still worth upgrading su anyway, but there _is_ no
contain-equivalent pipeline that doesn't have circular dependencies in the order
the commands need to run, and then your init binary needs to do setup _in_ the
new namespace which with chroot means you need a binary in the new chroot that's
really all about the host, not the chroot. Static qemu application mode that
can't do it's own chroot had this problem too, which is why I submitted a patch
to it many moons ago...

Rob

P.S. https://twitter.com/__apf__/status/1098265272782184448


More information about the Toybox mailing list