Straightening out ioctl() size confusion
The Linux kernel takes things a little further by encoding some useful information in the command codes. Along with driver-specific "magic" and command numbers, the ioctl() command code includes the direction of data movement (if any) between kernel and user space and the size of the data to be moved. The kernel itself does not do anything with those values, but their presence does enable a driver to perform some checks. If, for example, the size of a structure used as an ioctl() argument changes, the driver can use the size field in the command code to determine whether the application is using the older version or not. Some kernel code actually does check the sizes to be sure that things match up.
The command codes are created using some macros in <asm/ioctl.h>. A driver defining codes would use one of these macros:
_IOR(type, number, size)
_IOW(type, number, size)
_IORW(type, number, size)
The macro used specifies whether the ioctl() operation reads or writes kernel-space data (or both); type is the driver's "magic" code, and number is the command-specific code. The confusion comes in with the argument called size; it is supposed to be the type of the data to be passed between kernel and user space. So, for example, the "get tape position" code is defined as:
#define MTIOCPOS _IOR('m', 3, struct mtpos)
The problem is that a number of hackers saw the size argument and assumed that they were expected to pass the size of the expected data transfer. The result was a number of definitions like:
#define CIOC_KERNEL_VERSION _IOWR('c', 10, sizeof (int))
As a result, the actual size value, as encoded within the command, was the size of the size value, or, on most architectures, four bytes. Since most code never looks at that size value, things worked, but the values defined were not as intended. Another problem that occasionally came up was that some code used very large size values, overflowing the space allotted in the command word, thus corrupting the rest of the command code. Once again, things worked, but not quite in the way people expected.
One of the themes of 2.6 development has been the addition of type checking anywhere that the compiler can be coerced into doing it. So the obvious thing to do was to add checking to the generation of command codes; Arnd Bergmann submitted a patch which does exactly that. It adds a bit of preprocessor magic in the form of this macro:
#define _IOC_TYPECHECK(t) \
((sizeof(t) == sizeof(t[1]) && \
sizeof(t) < (1 << _IOC_SIZEBITS)) ? \
sizeof(t) : __invalid_size_argument_for_IOC)
The first test ensures that an actual type (as opposed to a simple size) has been passed in; the second makes sure it is not too large.
All that remains is the inconvenient fact that the old, erroneous codes
have found their way into a number of application programs. Changing those
codes would break those applications, and that's something the kernel hackers
try never to do. So, for these cases, a new set of macros (with names like
_IOW_BAD() has been introduced, and the erroneous uses have been
moved over to the new macros. The command codes remain unchanged, but the
mistake is noted so that it is not replicated when somebody copies the code
in question.
