On Fri, Dec 23, 2016 at 09:35:06PM -0700, Theo de Raadt wrote:
> This is why sshd has to be started with an absolute path, to
> avoid this problem.  Path games like this worried us.

I doubt that it makes sense to require an absolute path for all our
daemons.  It would break commands like 'pkill relayd; relayd'.  So
we should keep the p in execvp(3).

sshd can be considered special as it gives shell access and has a
broader attack vector.

> By removing this, you could be adding some subtle risk...

I considered it and concluded that I reduced the risk a bit.
Currently syslogd searches the relative path from "/" with my diff
it starts from "." .  The latter is better as we know it will find
the running syslogd binary there.

The current implementation is just wrong.  Started with an relative
path it fails silently.  Only -d gives the reason.

root@q70:.../sbin# ./syslogd -d        
CAfile /etc/ssl/cert.pem
off & running....
syslogd: init
exec priv './syslogd' failed: No such file or directory

But I found another issue.  When the parent process receives a
SIGHUP, it does an execvp(3) on itself.  This still fails with my
diff.  We could remove chdir("/") in the parent completely, but I
think this is too dangerous.

As a compromise between convenience and security I suggest to forbid
relative paths.  PATH search and absolute paths are still possible.

ok?

bluhm

Index: usr.sbin/syslogd/syslogd.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/usr.sbin/syslogd/syslogd.c,v
retrieving revision 1.224
diff -u -p -r1.224 syslogd.c
--- usr.sbin/syslogd/syslogd.c  23 Dec 2016 23:01:48 -0000      1.224
+++ usr.sbin/syslogd/syslogd.c  25 Dec 2016 14:31:34 -0000
@@ -361,6 +361,9 @@ main(int argc, char *argv[])
        int              fd_ctlsock, fd_klog, fd_sendsys, fd_bind, fd_listen;
        int             *fd_unix;
 
+       if (argv[0][0] != '/' && strchr(argv[0], '/'))
+               errx(1, "Cannot execute with relative path: %s", argv[0]);
+
        if ((path_unix = malloc(sizeof(*path_unix))) == NULL)
                err(1, "malloc %s", _PATH_LOG);
        path_unix[0] = _PATH_LOG;

Reply via email to