Cover | Table of Contents
for (i=1; i < 1; i++) {
printf("Hello World\n");
}
for (i=1; i < 100; i++) {
printf("Hello to a vast collection of worlds!\n");
}It was the best of protocols, it was the worst of protocols, it was the age of monopoly, it was the age of Free Software, it was the epoch of openness, it was the epoch of proprietary lock-in, it was the season of GNU, it was the season of Microsoft, it was the spring of Linux, it was the winter of Windows....
Standard: (noun) A flag, banner, or ensign, especially. An emblem or flag of an army, raised on a pole to indicate the rallying point in battle.
fcntl()
call, a
sort of jack-of-all-trades for manipulating files (hence
"fcntl
→ file
control"). It's not important to
know exactly how to program this call. Suffice it to say that a code
fragment to set up such a byte range lock looks something like this:int fd = open("/path/to/file", O_RDWR);
struct
flock
structure to describe the kind of byte range lock we need:int ret = fcntl(fd, F_SETLKW, &flock_struct);
ret is zero, we got the lock. Looks simple,
right? The byte range lock we got on the region of the file is
advisory. This means that other processes can ignore it and are not
restricted in terms of reading or writing the byte range covered by
the region (that's a difference from the Win32 way
of doing things, in which locks are mandatory; if a lock is in place
on a region, no other process can write to that region, even if it
doesn't test for locks). An existing lock can be
detected by another process doing its own fcntl()
call, asking to lock its own region of interest. Another useful
feature is that once the file descriptor open on the file
(int
fd in the previous
example) is closed, the lock is silently removed. This is perfectly
acceptable and a rational way of specifying a file locking primitive;
just what you'd want.unsigned
int, but as the type
off_t. What is
off_t? The answer depends completely on the system
implementation. On small or older systems, it is usually defined as a
signed 32-bit integer (it's used as a seek position
so that it can have a negative value), and on newer systems (Linux,
for example) it's defined as a signed 64-bit
integer. As long as applications are careful to cast integer types
only to the correct off_t type and use these for
file-size manipulation, the same application will work on both small
and large POSIX systems.
open() call is very simple. It
takes a pathname to open, the way in which you want to access or
create the file (read, write, or both with various create types), and
a permission mask that gets applied to files you do create. Under
Win32, the equivalent
call,
CreateFile(), takes seven parameters, and the
interactions among them can be ferociously complex. The parameter
that causes all the trouble is the ShareMode
parameter, which can take values of
any of the following constants
OR'ed together:FILE_SHARE_READ
FILE_SHARE_WRITE
FILE_SHARE_NONE
FILE_SHARE_DELETE
#define
of
-DUNICODE (it also helps if you own the compiler
market for Windows, as Microsoft does, as you can standardize tricks
like this). The older code-page-based applications call Win32
libraries that internally convert any string arguments to 16-bit
Unicode and then call the real Win32 library
interface, which, like the Windows NT kernel, is Unicode only.June and July were bad months for free software. First Apache chunked encoding vulnerability, and just when we'd finished patching that, we get the OpenSSH hole. Both of these are pretty scary—the first making every single web server potentially exploitable, and the second makes every remotely managed machine vulnerable.But we survived that, only to be hit just days later with the BIND resolver problems. Would it ever end? Well, there was a brief respite, but then, at the end of July, we had the OpenSSL buffer overflows.All of these were pretty agonising, but it seems we got through it mostly unscathed, by releasing patches widely as soon as possible. Of course, this is painful for users and vendors alike, having to scramble to patch systems before exploits become available. I know that pain only too well: at The Bunker, we had to use every available sysadmin for days on end to fix the problems, which seemed to be arriving before we'd had time to catch our breath from the previous one.But I also know the pain suffered by the discoverer of such problems, so I thought I'd tell you a bit about that. First, I was involved in the Apache chunked encoding problem. That was pretty straightforward, because the vulnerability was released without any consultation with the Apache Software Foundation, a move I consider most ill advised, but it did at least simplify our options: we had to get a patch out as fast as possible. Even so, we thought we could take a little bit of time to produce a fix, since all we were looking at was a denial-of-service attack, and let's face it, Apache doesn't need bugs to suffer denial of service—all this did was make it a little cheaper for the attacker to consume your resources.That is, until Gobbles came out with the exploit for the problem. Now, this really is the worst possible position to be in. Not only is there an exploitable problem, but the first you know of it is when you see the exploit code. Then we really had to scramble. First we had to figure out how the exploit worked. I figured that out by attacking myself and running Apache under gdb. I have to say that the attack was rather marvelously cunning, and for a while I forgot the urgency of the problem while I unravelled its inner workings. Having worked that out, we were in a position to finally fix the problem, and also, perhaps more importantly, more generically prevent the problem from occurring again through a different route. Once we had done that, it was just a matter of writing the advisory, releasing the patches, and posting the advisory to the usual places.