diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2008-12-05 22:44:42 +0100 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2009-03-24 20:56:37 +0100 |
commit | 1f3125af8ed7410cc0ebcc0acd59bbfc1ae0057a (patch) | |
tree | 3e0cd754d86b8780b164bd507564fd2355c7db29 /drivers/firewire | |
parent | bf8e3355ec8f4e472f9841e94203cd759b45226e (diff) |
firewire: cdev: tcodes input validation
The behaviour of fw-transaction.c::fw_send_request is ill-defined for
any other tcodes than read/ write/ lock request tcodes. Therefore
prevent requests with wrong tcodes from entering the transaction layer.
Maybe fw_send_request should check them itself, but I am not inclined to
change it and fw_fill_request from void-valued functions to ones which
return error codes and pass those up. Besides, maybe fw_send_request is
going to support one more tcode than ioctl_send_request in the future
(TCODE_STREAM_DATA).
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire')
-rw-r--r-- | drivers/firewire/fw-cdev.c | 27 |
1 files changed, 25 insertions, 2 deletions
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c index 75bbd66f852..a320ab48edd 100644 --- a/drivers/firewire/fw-cdev.c +++ b/drivers/firewire/fw-cdev.c @@ -398,6 +398,7 @@ static int ioctl_send_request(struct client *client, void *buffer) struct fw_device *device = client->device; struct fw_cdev_send_request *request = buffer; struct response *response; + int ret; /* What is the biggest size we'll accept, really? */ if (request->length > 4096) @@ -414,8 +415,26 @@ static int ioctl_send_request(struct client *client, void *buffer) if (request->data && copy_from_user(response->response.data, u64_to_uptr(request->data), request->length)) { - kfree(response); - return -EFAULT; + ret = -EFAULT; + goto err; + } + + switch (request->tcode) { + case TCODE_WRITE_QUADLET_REQUEST: + case TCODE_WRITE_BLOCK_REQUEST: + case TCODE_READ_QUADLET_REQUEST: + case TCODE_READ_BLOCK_REQUEST: + case TCODE_LOCK_MASK_SWAP: + case TCODE_LOCK_COMPARE_SWAP: + case TCODE_LOCK_FETCH_ADD: + case TCODE_LOCK_LITTLE_ADD: + case TCODE_LOCK_BOUNDED_ADD: + case TCODE_LOCK_WRAP_ADD: + case TCODE_LOCK_VENDOR_DEPENDENT: + break; + default: + ret = -EINVAL; + goto err; } response->resource.release = release_transaction; @@ -434,6 +453,10 @@ static int ioctl_send_request(struct client *client, void *buffer) return sizeof(request) + request->length; else return sizeof(request); + err: + kfree(response); + + return ret; } struct address_handler { |