diff options
author | Joel Fernandes <joelaf@google.com> | 2018-02-16 14:02:01 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-03-01 11:37:07 -0500 |
commit | cb57469c9573f6018cd1302953dd45d6e05aba7b (patch) | |
tree | 1d2aaeb2e18d0b4f398b37f1abb89d4ebf8af1b7 | |
parent | 4a3928c6f8a53fa1aed28ccba227742486e8ddcb (diff) |
staging: android: ashmem: Fix lockdep issue during llseek
ashmem_mutex create a chain of dependencies like so:
(1)
mmap syscall ->
mmap_sem -> (acquired)
ashmem_mmap
ashmem_mutex (try to acquire)
(block)
(2)
llseek syscall ->
ashmem_llseek ->
ashmem_mutex -> (acquired)
inode_lock ->
inode->i_rwsem (try to acquire)
(block)
(3)
getdents ->
iterate_dir ->
inode_lock ->
inode->i_rwsem (acquired)
copy_to_user ->
mmap_sem (try to acquire)
There is a lock ordering created between mmap_sem and inode->i_rwsem
causing a lockdep splat [2] during a syzcaller test, this patch fixes
the issue by unlocking the mutex earlier. Functionally that's Ok since
we don't need to protect vfs_llseek.
[1] https://patchwork.kernel.org/patch/10185031/
[2] https://lkml.org/lkml/2018/1/10/48
Acked-by: Todd Kjos <tkjos@google.com>
Cc: Arve Hjonnevag <arve@android.com>
Cc: stable@vger.kernel.org
Reported-by: syzbot+8ec30bb7bf1a981a2012@syzkaller.appspotmail.com
Signed-off-by: Joel Fernandes <joelaf@google.com>
Acked-by: Greg Hackmann <ghackmann@google.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/staging/android/ashmem.c | 15 |
1 files changed, 7 insertions, 8 deletions
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index 6dbba5aff191..d5450365769c 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c | |||
@@ -326,24 +326,23 @@ static loff_t ashmem_llseek(struct file *file, loff_t offset, int origin) | |||
326 | mutex_lock(&ashmem_mutex); | 326 | mutex_lock(&ashmem_mutex); |
327 | 327 | ||
328 | if (asma->size == 0) { | 328 | if (asma->size == 0) { |
329 | ret = -EINVAL; | 329 | mutex_unlock(&ashmem_mutex); |
330 | goto out; | 330 | return -EINVAL; |
331 | } | 331 | } |
332 | 332 | ||
333 | if (!asma->file) { | 333 | if (!asma->file) { |
334 | ret = -EBADF; | 334 | mutex_unlock(&ashmem_mutex); |
335 | goto out; | 335 | return -EBADF; |
336 | } | 336 | } |
337 | 337 | ||
338 | mutex_unlock(&ashmem_mutex); | ||
339 | |||
338 | ret = vfs_llseek(asma->file, offset, origin); | 340 | ret = vfs_llseek(asma->file, offset, origin); |
339 | if (ret < 0) | 341 | if (ret < 0) |
340 | goto out; | 342 | return ret; |
341 | 343 | ||
342 | /** Copy f_pos from backing file, since f_ops->llseek() sets it */ | 344 | /** Copy f_pos from backing file, since f_ops->llseek() sets it */ |
343 | file->f_pos = asma->file->f_pos; | 345 | file->f_pos = asma->file->f_pos; |
344 | |||
345 | out: | ||
346 | mutex_unlock(&ashmem_mutex); | ||
347 | return ret; | 346 | return ret; |
348 | } | 347 | } |
349 | 348 | ||