mirror of
https://github.com/sysprog21/lkmpg.git
synced 2024-11-22 09:52:45 +08:00
Fix potential concurrent problems in chardev2.c
After forking, Each file descriptor in the child refers to the same open file description as the parent. So when calling open() before fork(), the child can access the device file without checking by exclusive access in device_open(). It may cause race conditions in device_ioctl(). Because of that, it is unnecessary to check the multiple access in device_open(). It just needs check in device_ioctl(), since read(), write(), seek() system call are atomic [1][2]. Related discussion: - https://github.com/sysprog21/lkmpg/issues/148 [1] https://lore.kernel.org/lkml/53022DB1.4070805@gmail.com/ [2] https://www.kernel.org/doc/html/latest/filesystems/files.html Close #148
This commit is contained in:
parent
aa4b5d7421
commit
beb1ff1595
|
@ -37,10 +37,6 @@ static int device_open(struct inode *inode, struct file *file)
|
|||
{
|
||||
pr_info("device_open(%p)\n", file);
|
||||
|
||||
/* We don't want to talk to two processes at the same time. */
|
||||
if (atomic_cmpxchg(&already_open, CDEV_NOT_USED, CDEV_EXCLUSIVE_OPEN))
|
||||
return -EBUSY;
|
||||
|
||||
try_module_get(THIS_MODULE);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
@ -49,9 +45,6 @@ static int device_release(struct inode *inode, struct file *file)
|
|||
{
|
||||
pr_info("device_release(%p,%p)\n", inode, file);
|
||||
|
||||
/* We're now ready for our next caller */
|
||||
atomic_set(&already_open, CDEV_NOT_USED);
|
||||
|
||||
module_put(THIS_MODULE);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
@ -129,6 +122,11 @@ device_ioctl(struct file *file, /* ditto */
|
|||
unsigned long ioctl_param)
|
||||
{
|
||||
int i;
|
||||
long ret = SUCCESS;
|
||||
|
||||
/* We don't want to talk to two processes at the same time. */
|
||||
if (atomic_cmpxchg(&already_open, CDEV_NOT_USED, CDEV_EXCLUSIVE_OPEN))
|
||||
return -EBUSY;
|
||||
|
||||
/* Switch according to the ioctl called */
|
||||
switch (ioctl_num) {
|
||||
|
@ -166,11 +164,14 @@ device_ioctl(struct file *file, /* ditto */
|
|||
/* This ioctl is both input (ioctl_param) and output (the return
|
||||
* value of this function).
|
||||
*/
|
||||
return (long)message[ioctl_param];
|
||||
ret = (long)message[ioctl_param];
|
||||
break;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
/* We're now ready for our next caller */
|
||||
atomic_set(&already_open, CDEV_NOT_USED);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Module Declarations */
|
||||
|
|
Loading…
Reference in New Issue
Block a user