Writing

Feed Software, technology, sysadmin war stories, and more.

Wednesday, March 14, 2012

When in doubt, twiddle bytes in libc.so.5

Back in the fall of 2000, there was a nasty little security advisory in the klogd/syslogd pair which ran on every one of my machines. It seemed that data supplied by a user could work its way directly into the second argument of a *printf call and thus take over its format string. From there, any number of bad things could happen.

Within a day or two, there was a patched Slackware package:

----------------------------
Mon Sep 18 11:13:56 PDT 2000
a1/sysklogd.tgz:  Upgraded to sysklogd-1.4.  This fixes the
   "klogd format bug" announced this morning on BugTraq.
   (* Security fix *)
----------------------------

This patch was great, but it opened up a new problem for me. Slackware itself had recently switched to being based around glibc 2.1, and I still had a number of systems which were entirely or partially based on the older libc5 versions. I was able to install the glibc packages and then upgraded sysklogd, but then other things broke on me.

Somewhere along the way, /dev/log had changed from a SOCK_STREAM style to SOCK_DGRAM. This was probably done to avoid a denial of service attack. That was also a good thing, but it meant that all of my older programs which were still linked against libc5 had a syslog() call which no longer functioned. This was unacceptable.

I figured it would be possible to write something which would create a stream listening socket and would then translate things to datagrams and sling them at syslogd. It didn't take too much work, and now I had something which would do the conversion. It was the usual thing: set up a listener, run select(), keep track of client connections and disconnections, read() on activity, and write it to upstream.

Still, there was a big problem: the old programs still opened /dev/log, and the new programs did it too! I couldn't have it both ways on the same socket. Ultimately, I wound up doing something really evil to fix this problem. I opened up libc.so.5 and changed /dev/log to /dev/LOG with a quick call to sed. Then I made my program listen on /dev/LOG and write to /dev/log, and restarted everything which needed to use this interface.

It worked. Granted, it just moved the denial-of-service possibility to my converter, but that was an acceptable situation during the transition. Later, once everything had been upgraded and/or recompiled around glibc, I shut it down and removed the lingering cruft.

This was just one of a bunch of crazy things I had to write over the years to keep my fleet of mismatched machines running properly.