forked from e5l/au-linux-kernel-spring-2016
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
83 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,7 +28,7 @@ typedef struct vsd_dev { | |
} vsd_dev_t; | ||
static vsd_dev_t *vsd_dev; | ||
|
||
#define LOCAL_DEBUG 0 | ||
#define LOCAL_DEBUG 1 | ||
static void print_vsd_dev_hw_regs(vsd_dev_t *vsd_dev) | ||
{ | ||
if (!LOCAL_DEBUG) | ||
|
@@ -68,6 +68,7 @@ static void vsd_dev_dma_op_complete_tsk_func(unsigned long unused) | |
{ | ||
(void)unused; | ||
// TODO wakeup task waiting for completion of VSD cmd | ||
wake_up(&vsd_dev->dma_op_compete_wq); | ||
} | ||
|
||
static ssize_t vsd_dev_read(struct file *filp, | ||
|
@@ -76,14 +77,20 @@ static ssize_t vsd_dev_read(struct file *filp, | |
ssize_t ret = 0; | ||
void *kdma_buf = NULL; | ||
|
||
mutex_lock(&vsd_dev->dev_ops_serialization_mutex); | ||
print_vsd_dev_hw_regs(vsd_dev); | ||
|
||
/* | ||
This comment has been minimized.
Sorry, something went wrong.
eabatalov
Collaborator
|
||
if (vsd_dev->hwregs->cmd != VSD_CMD_NONE) { | ||
ret = -EBUSY; | ||
goto exit; | ||
} | ||
}*/ | ||
|
||
// TODO check not to alloc too much DMA memory (easy DDOS) | ||
|
||
if (read_size > vsd_dev->hwregs->dev_size) { | ||
read_size = vsd_dev->hwregs->dev_size; | ||
} | ||
|
||
kdma_buf = kzalloc(read_size, GFP_KERNEL); | ||
if (!kdma_buf) { | ||
ret = -ENOMEM; | ||
|
@@ -104,10 +111,21 @@ static ssize_t vsd_dev_read(struct file *filp, | |
* wait_event call to wait_event_interruptible call. | ||
* Describe sequence of events (step by step) that lead to | ||
* write to freed kernel buffer in vsd_* kernel code. | ||
* 1. TODO | ||
* 2. TODO | ||
* 3. TODO | ||
* ... | ||
* | ||
* Consider device size actually changes if we use SET_SIZE function | ||
* i.e. device literally frees memory (for example) when we shrinke the size and allocates new | ||
* as far as it fits into it's available size (2 pages). | ||
* Now consider the following situation | ||
* 1. user decided to change vsd size; we wait in vsd_ioctl_set_size. Meanwhile the state | ||
* of device is being changed (allocation + sizes reassignment) | ||
* 2. the signal awakens us, not condition; device is still in inconsistent state, but it | ||
* turns out it has already increased own size (probably, that's stupid, but still) | ||
* 3. by chance ret = vsd_dev->hwregs->result; is still 0 (why not, if last operation was | ||
* successful) | ||
* 4. we happily exit vsd_ioctl_set_size | ||
* 5. we enter vsd_dev_write with a big amount of data to write, but since we "enlarged" | ||
* device, it should be fine | ||
* 6. vsd_dev_write in vsd_device/module.c writes too much data and fails | ||
This comment has been minimized.
Sorry, something went wrong.
eabatalov
Collaborator
|
||
*/ | ||
wait_event(vsd_dev->dma_op_compete_wq, | ||
vsd_dev->hwregs->cmd == VSD_CMD_NONE); | ||
|
@@ -128,7 +146,7 @@ static ssize_t vsd_dev_read(struct file *filp, | |
kfree(kdma_buf); | ||
exit: | ||
print_vsd_dev_hw_regs(vsd_dev); | ||
|
||
mutex_unlock(&vsd_dev->dev_ops_serialization_mutex); | ||
return ret; | ||
} | ||
|
||
|
@@ -138,13 +156,18 @@ static ssize_t vsd_dev_write(struct file *filp, | |
ssize_t ret = 0; | ||
void *kdma_buf = NULL; | ||
|
||
mutex_lock(&vsd_dev->dev_ops_serialization_mutex); | ||
print_vsd_dev_hw_regs(vsd_dev); | ||
/* | ||
if (vsd_dev->hwregs->cmd != VSD_CMD_NONE) { | ||
ret = -EBUSY; | ||
goto exit; | ||
} | ||
}*/ | ||
|
||
// TODO check not to alloc too much DMA memory (easy DDOS) | ||
if (write_size > vsd_dev->hwregs->dev_size) { | ||
write_size = vsd_dev->hwregs->dev_size; | ||
} | ||
kdma_buf = kzalloc(write_size, GFP_KERNEL); | ||
if (!kdma_buf) { | ||
ret = -ENOMEM; | ||
|
@@ -179,7 +202,7 @@ static ssize_t vsd_dev_write(struct file *filp, | |
kfree(kdma_buf); | ||
exit: | ||
print_vsd_dev_hw_regs(vsd_dev); | ||
|
||
mutex_unlock(&vsd_dev->dev_ops_serialization_mutex); | ||
return ret; | ||
} | ||
|
||
|
@@ -223,8 +246,42 @@ static long vsd_ioctl_get_size(vsd_ioctl_get_size_arg_t __user *uarg) | |
|
||
static long vsd_ioctl_set_size(vsd_ioctl_set_size_arg_t __user *uarg) | ||
{ | ||
ssize_t ret = 0; | ||
vsd_ioctl_set_size_arg_t arg; | ||
|
||
// TODO implement | ||
return 0; | ||
mutex_lock(&vsd_dev->dev_ops_serialization_mutex); | ||
print_vsd_dev_hw_regs(vsd_dev); | ||
/*if (vsd_dev->hwregs->cmd != VSD_CMD_NONE) { | ||
ret = -EBUSY; | ||
goto exit; | ||
}*/ | ||
|
||
if (copy_from_user(&arg, uarg, sizeof(arg))) { | ||
ret = -EFAULT; | ||
goto exit; | ||
} | ||
|
||
vsd_dev->hwregs->result = 0; | ||
vsd_dev->hwregs->tasklet_vaddr = | ||
(uint64_t)&vsd_dev->dma_op_complete_tsk; | ||
vsd_dev->hwregs->dma_paddr = 0; // unused | ||
vsd_dev->hwregs->dma_size = 0; | ||
vsd_dev->hwregs->dev_offset = arg.size; // unused | ||
wmb(); | ||
vsd_dev->hwregs->cmd = VSD_CMD_SET_SIZE; | ||
|
||
wait_event(vsd_dev->dma_op_compete_wq, | ||
vsd_dev->hwregs->cmd == VSD_CMD_NONE); | ||
|
||
ret = vsd_dev->hwregs->result; | ||
if (ret) | ||
This comment has been minimized.
Sorry, something went wrong.
Aspirisha
Author
Owner
|
||
goto exit; | ||
|
||
exit: | ||
print_vsd_dev_hw_regs(vsd_dev); | ||
mutex_unlock(&vsd_dev->dev_ops_serialization_mutex); | ||
return ret; | ||
} | ||
|
||
static long vsd_dev_ioctl(struct file *filp, unsigned int cmd, | ||
|
X-D