mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
fput: task_work_add() can fail if the caller has passed exit_task_work()
fput() assumes that it can't be called after exit_task_work() but
this is not true, for example free_ipc_ns()->shm_destroy() can do
this. In this case fput() silently leaks the file.
Change it to fallback to delayed_fput_work if task_work_add() fails.
The patch looks complicated but it is not, it changes the code from
if (PF_KTHREAD) {
schedule_work(...);
return;
}
task_work_add(...)
to
if (!PF_KTHREAD) {
if (!task_work_add(...))
return;
/* fallback */
}
schedule_work(...);
As for shm_destroy() in particular, we could make another fix but I
think this change makes sense anyway. There could be another similar
user, it is not safe to assume that task_work_add() can't fail.
Reported-by: Andrey Vagin <[email protected]>
Signed-off-by: Oleg Nesterov <[email protected]>
Signed-off-by: Al Viro <[email protected]>
This commit is contained in:
parent
698b822363
commit
e7b2c40692
1 changed files with 10 additions and 9 deletions
|
|
@ -306,17 +306,18 @@ void fput(struct file *file)
|
|||
{
|
||||
if (atomic_long_dec_and_test(&file->f_count)) {
|
||||
struct task_struct *task = current;
|
||||
unsigned long flags;
|
||||
|
||||
file_sb_list_del(file);
|
||||
if (unlikely(in_interrupt() || task->flags & PF_KTHREAD)) {
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&delayed_fput_lock, flags);
|
||||
list_add(&file->f_u.fu_list, &delayed_fput_list);
|
||||
schedule_work(&delayed_fput_work);
|
||||
spin_unlock_irqrestore(&delayed_fput_lock, flags);
|
||||
return;
|
||||
if (likely(!in_interrupt() && !(task->flags & PF_KTHREAD))) {
|
||||
init_task_work(&file->f_u.fu_rcuhead, ____fput);
|
||||
if (!task_work_add(task, &file->f_u.fu_rcuhead, true))
|
||||
return;
|
||||
}
|
||||
init_task_work(&file->f_u.fu_rcuhead, ____fput);
|
||||
task_work_add(task, &file->f_u.fu_rcuhead, true);
|
||||
spin_lock_irqsave(&delayed_fput_lock, flags);
|
||||
list_add(&file->f_u.fu_list, &delayed_fput_list);
|
||||
schedule_work(&delayed_fput_work);
|
||||
spin_unlock_irqrestore(&delayed_fput_lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue