Reputation: 487
I have a device driver that allows a user-space app to perform various operations using the ioctl mechanism. Returned as part of an initial ioctl call is a handle that is supposed to be opaque to the user-space app which the app provides in other ioctl calls.
Internally in the driver, the handle is the address of some control/context block in kernel space. If the app could be trusted to pass back faithfully the handle returned, all is well. Concern is what if the app is malicious and passes back some aribitrary handle which the driver then casts to appropriate pointer type and de-references it.
One sanity check I was thinking of is to compare with PAGE_OFFSET and reject if less than (to ensure address at-least points to kernel memory). What if it page faults which I believe is not legal in kernel space? A simple scheme could be to check whether the handle was previously returned to user-space but overhead to search could be high (since there can be a lot of these handles).
Is there a robust and efficient way to validate the handle? Any help is appreciated.
Thanks.
Upvotes: 0
Views: 1216
Reputation: 2720
Why do you even need a handle? The open file is a handle, and you can stash your own private data in there, eg:
static long your_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
{
struct your_struct *p = f->private_data;
...
Upvotes: 0
Reputation: 16441
Never accept a pointer from an untrusted program.
There's no end to the attacks this enables, on your code and on other (e.g. using you to peek into memory the process must not access).
There are ways to do validate it, but they're complicated or expensive. For example:
1. Place all the handles in a single array. Verify that the pointer is within the array, and properly aligned. But then you could use the array index as handle.
2. Scan your handle database and compare pointers to the one given from the user. Don't dereference the handle until you find it in the database. But again, using some ID for the lookup, instead of the pointer, can simplify it.
There are more things you may need to validate:
1. As Alex commented, if there are several possible handle types, verify that you get the right type (i.e. prevent h = get_handle_typeA(); use_handle_typeB(h)
).
2. Make sure each process uses only handles it created. So a process won't be able to guess handle values and hope to catch a valid one.
Upvotes: 2