[gmail] Re: realpath bug

Denis Vlasenko vda.linux at googlemail.com
Sat Feb 10 18:35:37 UTC 2007


On Friday 09 February 2007 09:36, Marc Leeman wrote:
> Cc to busybox ML.
> 
> > > > could you be more specific as to what is breaking ?  "syslogd breaks on
> > > > read only filesystems" does not translate well into actual test cases for
> > > > inclusion into uClibc testsuite ...
> > >
> > > cf. busybox discussion of yesterday:
> > >
> > > http://www.busybox.net/lists/busybox/2007-February/026252.html
> > 
> > ok, looking again and i see your setup is:
> >  - /dev is mounted RO
> >  - /tmp is mounted RW
> >  - /dev/log is a symlink to ../tmp/log
> > 
> > busybox launches sysklogd which does:
> >  - dev_log_name = xmalloc_realpath(/dev/log)
> >  - unlink(dev_log_name)
> > 
> > on your system, dev_log_name should be resolving to /tmp/log but it seems to 
> > return NULL ... on my system, it works:
> > # ls -l /dev/log /tmp/log 
> > lrwxrwxrwx 1 root root 10 2007-02-08 23:58 /dev/log -> ../tmp/log
> > -rw-r--r-- 1 root root  0 2007-02-08 23:58 /tmp/log
> > # ./busybox syslogd -n
> > running xmalloc_realpath(/dev/log)
> > got back /tmp/log
> > dev_log_name is now /tmp/log
> > unlinking(/tmp/log)
> > exiting now
> > # ./busybox syslogd -n
> > running xmalloc_realpath(/dev/log)
> > got back (null)
> > dev_log_name is now /dev/log
> > unlinking(/dev/log)
> > exiting now
> > 
> > this behavior is correct ... since /tmp/log was removed in the first run, the 
> > second run should actually return NULL ...
> 
> The system is using an empty /tmp fs (tmpfs), so the socket or any other
> file is not present in /tmp when xmallok_realpath("/dev/log") is called.
> 
> The old syslogd implementation correctly de-referenced the pointer in
> /dev/log to /tmp/log and created a /tmp/log socket. the new syslogd
> implementation tries to delete /dev/log on the RO filesystem and tries
> to create the log socket there, what obviously fails on a RO fs.

rev 16000:

        /* Create the syslog file so realpath() can work. */
        if (realpath(_PATH_LOG, lfile) != NULL) {
                unlink(lfile);
        }

        memset(&sunx, 0, sizeof(sunx));
        sunx.sun_family = AF_UNIX;
        strncpy(sunx.sun_path, lfile, sizeof(sunx.sun_path));
        sock_fd = xsocket(AF_UNIX, SOCK_DGRAM, 0);
        addrLength = sizeof(sunx.sun_family) + strlen(sunx.sun_path);
        if (bind(sock_fd, (struct sockaddr *) &sunx, addrLength) < 0) {
                bb_perror_msg_and_die("Could not connect to socket " _PATH_LOG);
        }

if realpath fails, lfile is undefined.
strncpy above will pass possibly bogus lfile as socket name to bind().
it happens so on glibc realpath() returns resolved link and
uclibc returns NULL but fills lfile with resolved link.

New code is:

        dev_log_name = xmalloc_realpath(_PATH_LOG);
        if (!dev_log_name)
                dev_log_name = _PATH_LOG;

        /* Unlink old /dev/log (or object it points to) */
        unlink(dev_log_name);

        memset(&sunx, 0, sizeof(sunx));
        sunx.sun_family = AF_UNIX;
        strncpy(sunx.sun_path, dev_log_name, sizeof(sunx.sun_path));
        sock_fd = xsocket(AF_UNIX, SOCK_DGRAM, 0);
        addr_len = sizeof(sunx.sun_family) + strlen(sunx.sun_path);
        xbind(sock_fd, (struct sockaddr *) &sunx, addr_len);

which looks more sane to me.

Apparently the problem is that realpath may fail to resolve
dangling links (e.g. uclibc).

Patch which replaces realpath with readlink, anyone?
--
vda



More information about the uClibc mailing list