On Thu, Jul 26, 2018 at 10:22:28AM -0600, Theo de Raadt wrote:
> This mail includes a large diff of userland which demonstrates how
> unveil() will be used in base.
>
[...]
>
> And here is the userland diff, applying to about 37 programs. There will
> be weaknesses and errors in here. This is not perfect yet.
Here, a quick review of some possible problems, unrelated diff hunks or
others comments.
I didn't check for the accuracy of the unveiled paths.
> Index: libexec/fingerd/fingerd.c
> ===================================================================
> RCS file: /cvs/src/libexec/fingerd/fingerd.c,v
> retrieving revision 1.39
> diff -u -p -u -r1.39 fingerd.c
> --- libexec/fingerd/fingerd.c 13 Nov 2015 01:26:33 -0000 1.39
> +++ libexec/fingerd/fingerd.c 12 Jul 2018 16:18:13 -0000
> @@ -68,7 +68,7 @@ main(int argc, char *argv[])
> char **ap, *av[ENTRIES + 1], line[8192], *lp, *hname;
> char hostbuf[HOST_NAME_MAX+1];
>
> - if (pledge("stdio inet dns proc exec", NULL) == -1)
> + if (pledge("stdio unveil inet dns proc exec", NULL) == -1)
> err(1, "pledge");
>
> prog = _PATH_FINGER;
> @@ -110,6 +110,9 @@ main(int argc, char *argv[])
> default:
> usage();
> }
> +
> + if (unveil(_PATH_FINGER, "x") == -1)
> + err(1, "unveil");
>
> if (logging) {
> struct sockaddr_storage ss;
unveil(2) call (with static name _PATH_FINGER) should be before
pledge(2). alternatively another call of pledge(2) without "unveil"
should be done after.
> Index: libexec/spamd-setup/spamd-setup.c
> ===================================================================
> RCS file: /cvs/src/libexec/spamd-setup/spamd-setup.c,v
> retrieving revision 1.50
> diff -u -p -u -r1.50 spamd-setup.c
> --- libexec/spamd-setup/spamd-setup.c 7 Jul 2017 00:10:15 -0000 1.50
> +++ libexec/spamd-setup/spamd-setup.c 12 Jul 2018 16:18:13 -0000
> @@ -851,13 +851,24 @@ main(int argc, char *argv[])
> spamd_uid = pw->pw_uid;
> spamd_gid = pw->pw_gid;
>
> - if (pledge("stdio rpath inet proc exec id", NULL) == -1)
> + if (pledge("stdio unveil rpath inet proc exec id", NULL) == -1)
> err(1, "pledge");
>
> if (daemonize)
> daemon(0, 0);
> else if (chdir("/") != 0)
> err(1, "chdir(\"/\")");
> +
> + if (unveil(PATH_FTP, "x") == -1)
> + err(1, "unveil");
> + if (unveil(PATH_PFCTL, "x") == -1)
> + err(1, "unveil");
> + if (unveil(PATH_SPAMD_CONF, "r") == -1)
> + err(1, "unveil");
> + if (unveil(_PATH_SERVICES, "r") == -1)
> + err(1, "unveil");
> + if (pledge("stdio rpath inet proc exec id", NULL) == -1)
> + err(1, "pledge");
>
> if ((ent = getservbyname("spamd-cfg", "tcp")) == NULL)
> errx(1, "cannot find service \"spamd-cfg\" in /etc/services");
I would perfer to see all unveil(2) calls before pledge(2), instead of
calling pledge(2) twice (here it is possible: all unveiled paths are
known in advance).
> Index: sbin/scan_ffs/scan_ffs.c
> ===================================================================
> RCS file: /cvs/src/sbin/scan_ffs/scan_ffs.c,v
> retrieving revision 1.22
> diff -u -p -u -r1.22 scan_ffs.c
> --- sbin/scan_ffs/scan_ffs.c 26 Apr 2018 15:55:14 -0000 1.22
> +++ sbin/scan_ffs/scan_ffs.c 12 Jul 2018 16:18:13 -0000
> @@ -139,7 +139,7 @@ main(int argc, char *argv[])
> daddr_t beg = 0, end = -1;
> const char *errstr;
>
> - if (pledge("stdio rpath disklabel", NULL) == -1)
> + if (pledge("stdio unveil rpath disklabel", NULL) == -1)
> err(1, "pledge");
>
> while ((ch = getopt(argc, argv, "lsvb:e:")) != -1)
hum. Makefile doesn't show it would search source code somewhere else.
The change (adding "unveil" promise without unveil(2) calls) is
suspirious.
> Index: usr.bin/doas/doas.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/doas/doas.c,v
> retrieving revision 1.72
> diff -u -p -u -r1.72 doas.c
> --- usr.bin/doas/doas.c 27 May 2017 09:51:07 -0000 1.72
> +++ usr.bin/doas/doas.c 12 Jul 2018 16:18:13 -0000
> @@ -239,6 +239,30 @@ good:
> }
> }
>
> +void
> +pledgecommands(const char *ipath, const char *cmd)
cosmetic: unveilcommands() would be a better name :)
> +{
> + char *path;
> + char buf[PATH_MAX];
> + char *p, *cp;
> +
> + path = strdup(ipath);
> + if (!path)
> + err(1, "copying path");
> +
> + for (p = path; p && *p;) {
> + cp = strsep(&p, ":");
> + if (cp) {
> + int r = snprintf(buf, sizeof buf, "%s/%s", cp, cmd);
> + if (r == -1 || r >= sizeof buf)
> + errx(1, "snprintf");
> + if (unveil(buf, "x") == -1)
> + err(1, "unveil");
> + }
> + }
> + free(path);
> +}
> +
> int
> main(int argc, char **argv)
> {
> @@ -364,6 +388,7 @@ main(int argc, char **argv)
> authuser(myname, login_style, rule->options & PERSIST);
> }
>
> + pledgecommands(safepath, cmd);
> if (pledge("stdio rpath getpw exec id", NULL) == -1)
> err(1, "pledge");
>
> Index: usr.bin/ftp/main.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/ftp/main.c,v
> retrieving revision 1.120
> diff -u -p -u -r1.120 main.c
> --- usr.bin/ftp/main.c 10 Feb 2018 06:25:16 -0000 1.120
> +++ usr.bin/ftp/main.c 12 Jul 2018 16:18:13 -0000
> @@ -273,6 +273,7 @@ main(volatile int argc, char *argv[])
> }
>
> ttyout = stdout;
> +// espie: fw_update, ^T not working. due to no TERM= while in rc script?
> if (isatty(fileno(ttyout)) && !dumb_terminal && foregroundproc())
> progress = 1; /* progress bar on if tty is usable */
>
unrelated to unveil(2)
> Index: usr.bin/top/top.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/top/top.c,v
> retrieving revision 1.89
> diff -u -p -u -r1.89 top.c
> --- usr.bin/top/top.c 15 Mar 2017 04:24:14 -0000 1.89
> +++ usr.bin/top/top.c 12 Jul 2018 16:18:13 -0000
> @@ -412,6 +412,8 @@ main(int argc, char *argv[])
> sigprocmask(SIG_BLOCK, &mask, &oldmask);
> if (interactive)
> init_screen();
> + if (pledge("stdio getpw tty proc ps vminfo", NULL) == -1)
> + err(1, "pledge");
> (void) signal(SIGINT, leave);
> siginterrupt(SIGINT, 1);
> (void) signal(SIGQUIT, leave);
unrelated to unveil(2)
> Index: usr.sbin/bgpctl/bgpctl.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v
> retrieving revision 1.209
> diff -u -p -u -r1.209 bgpctl.c
> --- usr.sbin/bgpctl/bgpctl.c 22 Jul 2018 17:07:53 -0000 1.209
> +++ usr.sbin/bgpctl/bgpctl.c 25 Jul 2018 17:04:18 -0000
> @@ -192,7 +192,9 @@ main(int argc, char *argv[])
> break;
> }
>
> - if (pledge("stdio rpath wpath unix", NULL) == -1)
> + if (unveil(sockname, "r") == -1)
> + err(1, "unveil");
> + if (pledge("stdio unix", NULL) == -1)
> err(1, "pledge");
>
> if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
suspirious change in pledge(2)
- before: "stdio rpath wpath unix"
- after: "stdio unix"
> Index: usr.sbin/portmap/portmap.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/portmap/portmap.c,v
> retrieving revision 1.48
> diff -u -p -u -r1.48 portmap.c
> --- usr.sbin/portmap/portmap.c 14 Oct 2015 13:32:44 -0000 1.48
> +++ usr.sbin/portmap/portmap.c 12 Jul 2018 16:18:13 -0000
> @@ -609,7 +609,7 @@ callit(struct svc_req *rqstp, SVCXPRT *x
> return;
> }
>
> - if (pledge("stdio rpath inet", NULL) == -1)
> + if (pledge("stdio inet", NULL) == -1)
> err(1, "pledge");
>
> port = pml->pml_map.pm_port;
suspirious change in pledge(2)
- before: "stdio rpath inet"
- after: "stdio inet"
(and diff unrelated to unveil(2))
> Index: usr.sbin/vmctl/main.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/vmctl/main.c,v
> retrieving revision 1.39
> diff -u -p -u -r1.39 main.c
> --- usr.sbin/vmctl/main.c 12 Jul 2018 14:53:37 -0000 1.39
> +++ usr.sbin/vmctl/main.c 25 Jul 2018 17:04:20 -0000
> @@ -158,9 +166,14 @@ parse(int argc, char *argv[])
> res.action = ctl->action;
> res.ctl = ctl;
>
> + if (unveil(SOCKET_NAME, "r") == -1)
> + err(1, "unveil");
> +
> if (!ctl->has_pledge) {
> /* pledge(2) default if command doesn't have its own pledge */
> - if (pledge("stdio rpath exec unix getpw", NULL) == -1)
> + if (unveil(VMCTL_CU, "x") == -1)
> + err(1, "unveil");
> + if (pledge("stdio rpath exec unix getpw paths", NULL) == -1)
> err(1, "pledge");
"paths" isn't a know promise name (it should be "unveil")
> }
> if (ctl->main(&res, argc, argv) != 0)
--
Sebastien Marie