Simon Ruderich wrote:
> Hello,
>
> I stumbled upon unexpected behavior on OpenBSD 6.0 (all patches)
> which seems to allow running commands as the original user when
> using su and doas interactively because the controlling terminal
> is the same.
> Is this behavior expected and if so, how do I run commands from
> root as an untrusted user? It's not mentioned in the man page
> that using su/doas as root might allow other users to run code as
> root.
Oh, interesting. The main design of doas is to escalate privileges, allowing
users to run commands as root. But it certainly looks appealing to use it to
drop privileges as well.
It's easy to add an option to disassociate from the controlling tty. I'm not
sure if this solves every problem, but it certainly blocks direct tty
injection. (You also pick up some privileges from being in a session or
process group, but those privileges are less powerful.)
Certain commands require a controlling tty, but that seems to be mostly
shells. Even vi and mg work ok.
Index: doas.1
===================================================================
RCS file: /cvs/src/usr.bin/doas/doas.1,v
retrieving revision 1.19
diff -u -p -r1.19 doas.1
--- doas.1 4 Sep 2016 15:20:37 -0000 1.19
+++ doas.1 3 Oct 2016 16:16:07 -0000
@@ -21,7 +21,7 @@
.Nd execute commands as another user
.Sh SYNOPSIS
.Nm doas
-.Op Fl Lns
+.Op Fl DLns
.Op Fl a Ar style
.Op Fl C Ar config
.Op Fl u Ar user
@@ -68,6 +68,9 @@ or
will be printed on standard output, depending on command
matching results.
No command is executed.
+.It Fl D
+Detach from controlling terminal.
+This can be useful when attempting to deescalate privileges.
.It Fl L
Clear any persisted authorizations from previous invocations,
then immediately exit.
Index: doas.c
===================================================================
RCS file: /cvs/src/usr.bin/doas/doas.c,v
retrieving revision 1.64
diff -u -p -r1.64 doas.c
--- doas.c 3 Sep 2016 11:03:18 -0000 1.64
+++ doas.c 3 Oct 2016 16:24:08 -0000
@@ -271,6 +271,7 @@ main(int argc, char **argv)
int i, ch;
int sflag = 0;
int nflag = 0;
+ int droptty = 0;
char cwdpath[PATH_MAX];
const char *cwd;
char *login_style = NULL;
@@ -282,7 +283,7 @@ main(int argc, char **argv)
uid = getuid();
- while ((ch = getopt(argc, argv, "a:C:Lnsu:")) != -1) {
+ while ((ch = getopt(argc, argv, "a:C:DLnsu:")) != -1) {
switch (ch) {
case 'a':
login_style = optarg;
@@ -290,6 +291,9 @@ main(int argc, char **argv)
case 'C':
confpath = optarg;
break;
+ case 'D':
+ droptty = 1;
+ break;
case 'L':
i = open("/dev/tty", O_RDWR);
if (i != -1)
@@ -371,6 +375,15 @@ main(int argc, char **argv)
errx(1, "Authorization required");
authuser(myname, login_style, rule->options & PERSIST);
+ }
+
+ if (droptty) {
+ i = open("/dev/tty", O_RDWR);
+ if (i == -1)
+ err(1, "can't open tty");
+ if (ioctl(i, TIOCNOTTY) != 0)
+ err(1, "can't drop controlling tty");
+ close(i);
}
if (pledge("stdio rpath getpw exec id", NULL) == -1)