After authentication is complete, unveil login.conf "r" (to discover
authorderaadt <deraadt@openbsd.org>
Wed, 8 Aug 2018 18:32:51 +0000 (18:32 +0000)
committerderaadt <deraadt@openbsd.org>
Wed, 8 Aug 2018 18:32:51 +0000 (18:32 +0000)
login tweaks), and walk the path (would could be $PATH, or not) adding
an unveil "x" to each possible executable which execvpe() could later
be tried by execvpe.
It would be great if we could do some unveil before authentication, but
I failed to determine all the possibilities.
Some problem reports by bluhm, tb, florian, and others during development
In snaps for about 3 weeks.
ok florian

usr.bin/doas/doas.c

index 9ec4257..f20f5d3 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: doas.c,v 1.72 2017/05/27 09:51:07 tedu Exp $ */
+/* $OpenBSD: doas.c,v 1.73 2018/08/08 18:32:51 deraadt Exp $ */
 /*
  * Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
  *
@@ -239,6 +239,44 @@ good:
        }
 }
 
+int
+unveilcommands(const char *ipath, const char *cmd)
+{
+       char *path = NULL, *p;
+       int unveils = 0;
+
+       if (strchr(cmd, '/') != NULL) {
+               if (unveil(cmd, "x") != -1)
+                       unveils++;
+               goto done;
+       }
+
+       if (!ipath) {
+               errno = ENOENT;
+               goto done;
+       }
+       path = strdup(ipath);
+       if (!path) {
+               errno = ENOENT;
+               goto done;
+       }
+       for (p = path; p && *p; ) {
+               char buf[PATH_MAX];
+               char *cp = strsep(&p, ":");
+
+               if (cp) {
+                       int r = snprintf(buf, sizeof buf, "%s/%s", cp, cmd);
+                       if (r != -1 && r < sizeof buf) {
+                               if (unveil(buf, "x") != -1)
+                                       unveils++;
+                       }
+               }
+       }
+done:
+       free(path);
+       return (unveils);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -364,6 +402,15 @@ main(int argc, char **argv)
                authuser(myname, login_style, rule->options & PERSIST);
        }
 
+       if (unveil(_PATH_LOGIN_CONF, "r") == -1)
+               err(1, "unveil");
+       if (rule->cmd) {
+               if (setenv("PATH", safepath, 1) == -1)
+                       err(1, "failed to set PATH '%s'", safepath);
+       }
+       if (unveilcommands(getenv("PATH"), cmd) == 0)
+               goto fail;
+
        if (pledge("stdio rpath getpw exec id", NULL) == -1)
                err(1, "pledge");
 
@@ -392,11 +439,8 @@ main(int argc, char **argv)
 
        envp = prepenv(rule);
 
-       if (rule->cmd) {
-               if (setenv("PATH", safepath, 1) == -1)
-                       err(1, "failed to set PATH '%s'", safepath);
-       }
        execvpe(cmd, argv, envp);
+fail:
        if (errno == ENOENT)
                errx(1, "%s: command not found", cmd);
        err(1, "%s", cmd);