I was looking at some Linux Kernel code today when I came across this piece of code implementing the write operation in a device driver.
if (copy_from_user(writebuf, buffer + writecount, transfer_length) ...
buffer is user controlled. writecount is derived from the user controlled count parameter that is used the write(…,const char __user *buffer,size_t count,…) operation.
This type of code of pointer indexing as in buffer + writecount is not uncommon and found in a number of places with the Linux kernel, and presumably many other kernels including NetBSD, OpenBSD, FreeBSD, and perhaps even non Unix Kernels.
There is an explicit check in the Linux file system layer that validates the count parameter, so that it is not greater than INT_MAX. The reason for this validation, amongst eliminating a number of kernel bugs when passing large values of count, is that the return value on the read and write operations is of type ssize_t.
ssize_t is a signed integral type and is in the range of INT_MIN and INT_MAX. Therefore if the return value, which indicates the number of bytes read or written is to fit into size_t, the count parameter must be less than INT_MAX. The unused bit between INT_MAX and UINT_MAX is used in the return vaue, and indicates the sign.
Back to the Linux Kernel code..
An interesting thing occurs when we start using buffer + count with large values of count. It is possible to have pointer overflows and wraparounds.
In Linux (default build), the userland stack begins at 0xbfffffff and the kernel begins at 0xc0000000. The largest address that a 32 bit pointer can hold is 0xffffffff. 0xffffffff – 0xc0000000 is 0x40000000. In cases where we use a user supplied count from a read or write operation to index either a kernel buffer or a buffer controlled by userland (at or below 0xbfffffff), count must be less than INT_MAX.
But 0x40000000 is much less than INT_MAX, and we can have a pointer overflow or wraparound when we use this to index a buffer.
This means that there are number of pointer overflows within the Kernel. buffer + count can overflow and wraparound when count is greater than 0x40000000.
Is code like this exploitable?
There is no doubt that code like this is exploitable in the sense that pointer overflows can occur. But are they exploitable from a malicious attacker’s point of view? I’m not sure of this, and will have to audit and investigate each case individually. I suspect that it may be hard to trigger such code without being caught out by memory access concerns.