linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3] Fixes: null pointer dereference in pfnmap_lockdep_assert
@ 2024-10-04 13:45 Manas via B4 Relay
  2024-10-04 13:47 ` Manas
  2024-10-04 15:17 ` Matthew Wilcox
  0 siblings, 2 replies; 6+ messages in thread
From: Manas via B4 Relay @ 2024-10-04 13:45 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Peter Xu, Shuah Khan, Anup Sharma, linux-mm, linux-kernel,
	syzbot+093d096417e7038a689b, Manas

From: Manas <manas18244@iiitd.ac.in>

syzbot has pointed to a possible null pointer dereference in
pfnmap_lockdep_assert. vm_file member of vm_area_struct is being
dereferenced without any checks.

This fix assigns mapping only if vm_file is not NULL.

Reported-by: syzbot+093d096417e7038a689b@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=093d096417e7038a689b
---
This bug[1] triggers a general protection fault in follow_pfnmap_start
function. An assertion pfnmap_lockdep_assert inside this function
dereferences vm_file member of vm_area_struct. And panic gets triggered
when vm_file is NULL.

This patch assigns mapping only if vm_file is not NULL.

[1] https://syzkaller.appspot.com/bug?extid=093d096417e7038a689b

Signed-off-by: Manas <manas18244@iiitd.ac.in>
---
Changes in v3:
- v3: use assigned var instead of accessing member again 
- Link to v2: https://lore.kernel.org/r/20241004-fix-null-deref-v2-1-23ad90999cd1@iiitd.ac.in

Changes in v2:
- v2: use ternary operator according to feedback
- Link to v1: https://lore.kernel.org/r/20241003-fix-null-deref-v1-1-0a45df9d016a@iiitd.ac.in
---
 mm/memory.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mm/memory.c b/mm/memory.c
index 2366578015ad..828967a13596 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -6346,10 +6346,10 @@ static inline void pfnmap_args_setup(struct follow_pfnmap_args *args,
 static inline void pfnmap_lockdep_assert(struct vm_area_struct *vma)
 {
 #ifdef CONFIG_LOCKDEP
-	struct address_space *mapping = vma->vm_file->f_mapping;
+	struct address_space *mapping = vma->vm_file ? vma->vm_file->f_mapping : NULL;
 
 	if (mapping)
-		lockdep_assert(lockdep_is_held(&vma->vm_file->f_mapping->i_mmap_rwsem) ||
+		lockdep_assert(lockdep_is_held(&mapping->i_mmap_rwsem) ||
 			       lockdep_is_held(&vma->vm_mm->mmap_lock));
 	else
 		lockdep_assert(lockdep_is_held(&vma->vm_mm->mmap_lock));

---
base-commit: 9852d85ec9d492ebef56dc5f229416c925758edc
change-id: 20241003-fix-null-deref-6bfa0337efc3

Best regards,
-- 
Manas <manas18244@iiitd.ac.in>




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3] Fixes: null pointer dereference in pfnmap_lockdep_assert
  2024-10-04 13:45 [PATCH v3] Fixes: null pointer dereference in pfnmap_lockdep_assert Manas via B4 Relay
@ 2024-10-04 13:47 ` Manas
  2024-10-04 15:17 ` Matthew Wilcox
  1 sibling, 0 replies; 6+ messages in thread
From: Manas @ 2024-10-04 13:47 UTC (permalink / raw)
  To: Andrew Morton, Peter Xu, Shuah Khan, Anup Sharma, linux-mm,
	linux-kernel, syzbot+093d096417e7038a689b

On 04.10.2024 19:15, Manas via B4 Relay wrote:
>From: Manas <manas18244@iiitd.ac.in>
>
>syzbot has pointed to a possible null pointer dereference in
>pfnmap_lockdep_assert. vm_file member of vm_area_struct is being
>dereferenced without any checks.
>
>This fix assigns mapping only if vm_file is not NULL.
I also edited the commit message (and cover letter) slightly to tell about the
newer fix, instead of the v1 fix of returning.

I hope this is okay.

-- 
Manas


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3] Fixes: null pointer dereference in pfnmap_lockdep_assert
  2024-10-04 13:45 [PATCH v3] Fixes: null pointer dereference in pfnmap_lockdep_assert Manas via B4 Relay
  2024-10-04 13:47 ` Manas
@ 2024-10-04 15:17 ` Matthew Wilcox
  2024-10-04 17:40   ` Manas
  2024-10-07 13:23   ` Peter Xu
  1 sibling, 2 replies; 6+ messages in thread
From: Matthew Wilcox @ 2024-10-04 15:17 UTC (permalink / raw)
  To: manas18244
  Cc: Andrew Morton, Peter Xu, Shuah Khan, Anup Sharma, linux-mm,
	linux-kernel, syzbot+093d096417e7038a689b

On Fri, Oct 04, 2024 at 07:15:48PM +0530, Manas via B4 Relay wrote:
> +++ b/mm/memory.c
> @@ -6346,10 +6346,10 @@ static inline void pfnmap_args_setup(struct follow_pfnmap_args *args,
>  static inline void pfnmap_lockdep_assert(struct vm_area_struct *vma)
>  {
>  #ifdef CONFIG_LOCKDEP
> -	struct address_space *mapping = vma->vm_file->f_mapping;
> +	struct address_space *mapping = vma->vm_file ? vma->vm_file->f_mapping : NULL;

Overly long and complex line.  Much simpler to write:

	struct address_space *mapping = NULL;

	if (vma->vm_file)
		mapping = vma->vm_file->f_mapping;

>  	if (mapping)
> -		lockdep_assert(lockdep_is_held(&vma->vm_file->f_mapping->i_mmap_rwsem) ||
> +		lockdep_assert(lockdep_is_held(&mapping->i_mmap_rwsem) ||
>  			       lockdep_is_held(&vma->vm_mm->mmap_lock));
>  	else
>  		lockdep_assert(lockdep_is_held(&vma->vm_mm->mmap_lock));

This one should have been lockdep_assert_held(&vma->vm_mm->mmap_lock).

I'm not sure that the previous one is correct.  The
lockdep_assert_held() macro is pretty careful about checking
LOCK_STATE_NOT_HELD to avoid the LOCK_STATE_UNKNOWN possibility.
But I'll leave that for Peter to fix.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3] Fixes: null pointer dereference in pfnmap_lockdep_assert
  2024-10-04 15:17 ` Matthew Wilcox
@ 2024-10-04 17:40   ` Manas
  2024-10-07 13:23   ` Peter Xu
  1 sibling, 0 replies; 6+ messages in thread
From: Manas @ 2024-10-04 17:40 UTC (permalink / raw)
  To: Matthew Wilcox
  Cc: Andrew Morton, Peter Xu, Shuah Khan, Anup Sharma, linux-mm,
	linux-kernel, syzbot+093d096417e7038a689b

Hi Matthew,

On 04.10.2024 16:17, Matthew Wilcox wrote:
>On Fri, Oct 04, 2024 at 07:15:48PM +0530, Manas via B4 Relay wrote:
>> +++ b/mm/memory.c
>> @@ -6346,10 +6346,10 @@ static inline void pfnmap_args_setup(struct follow_pfnmap_args *args,
>>  static inline void pfnmap_lockdep_assert(struct vm_area_struct *vma)
>>  {
>>  #ifdef CONFIG_LOCKDEP
>> -	struct address_space *mapping = vma->vm_file->f_mapping;
>> +	struct address_space *mapping = vma->vm_file ? vma->vm_file->f_mapping : NULL;
>
>Overly long and complex line.  Much simpler to write:
>
>	struct address_space *mapping = NULL;
>
>	if (vma->vm_file)
>		mapping = vma->vm_file->f_mapping;
>
Thank you for reviewing! I am sending v4.

>>  	if (mapping)
>> -		lockdep_assert(lockdep_is_held(&vma->vm_file->f_mapping->i_mmap_rwsem) ||
>> +		lockdep_assert(lockdep_is_held(&mapping->i_mmap_rwsem) ||
>>  			       lockdep_is_held(&vma->vm_mm->mmap_lock));
>>  	else
>>  		lockdep_assert(lockdep_is_held(&vma->vm_mm->mmap_lock));
>
>This one should have been lockdep_assert_held(&vma->vm_mm->mmap_lock).
>
>I'm not sure that the previous one is correct.  The
>lockdep_assert_held() macro is pretty careful about checking
>LOCK_STATE_NOT_HELD to avoid the LOCK_STATE_UNKNOWN possibility.
>But I'll leave that for Peter to fix.

-- 
Manas


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3] Fixes: null pointer dereference in pfnmap_lockdep_assert
  2024-10-04 15:17 ` Matthew Wilcox
  2024-10-04 17:40   ` Manas
@ 2024-10-07 13:23   ` Peter Xu
  2024-10-08 19:27     ` Peter Xu
  1 sibling, 1 reply; 6+ messages in thread
From: Peter Xu @ 2024-10-07 13:23 UTC (permalink / raw)
  To: Matthew Wilcox
  Cc: manas18244, Andrew Morton, Shuah Khan, Anup Sharma, linux-mm,
	linux-kernel, syzbot+093d096417e7038a689b

On Fri, Oct 04, 2024 at 04:17:42PM +0100, Matthew Wilcox wrote:
> On Fri, Oct 04, 2024 at 07:15:48PM +0530, Manas via B4 Relay wrote:
> > +++ b/mm/memory.c
> > @@ -6346,10 +6346,10 @@ static inline void pfnmap_args_setup(struct follow_pfnmap_args *args,
> >  static inline void pfnmap_lockdep_assert(struct vm_area_struct *vma)
> >  {
> >  #ifdef CONFIG_LOCKDEP
> > -	struct address_space *mapping = vma->vm_file->f_mapping;
> > +	struct address_space *mapping = vma->vm_file ? vma->vm_file->f_mapping : NULL;
> 
> Overly long and complex line.  Much simpler to write:
> 
> 	struct address_space *mapping = NULL;
> 
> 	if (vma->vm_file)
> 		mapping = vma->vm_file->f_mapping;
> 
> >  	if (mapping)
> > -		lockdep_assert(lockdep_is_held(&vma->vm_file->f_mapping->i_mmap_rwsem) ||
> > +		lockdep_assert(lockdep_is_held(&mapping->i_mmap_rwsem) ||
> >  			       lockdep_is_held(&vma->vm_mm->mmap_lock));
> >  	else
> >  		lockdep_assert(lockdep_is_held(&vma->vm_mm->mmap_lock));
> 
> This one should have been lockdep_assert_held(&vma->vm_mm->mmap_lock).
> 
> I'm not sure that the previous one is correct.  The
> lockdep_assert_held() macro is pretty careful about checking
> LOCK_STATE_NOT_HELD to avoid the LOCK_STATE_UNKNOWN possibility.
> But I'll leave that for Peter to fix.

Indeed..

Then looks like we could have quite a few other places in Linux that can
have used this wrong.. when the assert wants to check against either of the
two locks (one mutex or rcu read lock, for example) is held.

I'll send a patch after this one lands.

Thanks,

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3] Fixes: null pointer dereference in pfnmap_lockdep_assert
  2024-10-07 13:23   ` Peter Xu
@ 2024-10-08 19:27     ` Peter Xu
  0 siblings, 0 replies; 6+ messages in thread
From: Peter Xu @ 2024-10-08 19:27 UTC (permalink / raw)
  To: Matthew Wilcox
  Cc: manas18244, Andrew Morton, Shuah Khan, Anup Sharma, linux-mm,
	linux-kernel, syzbot+093d096417e7038a689b

On Mon, Oct 07, 2024 at 09:23:47AM -0400, Peter Xu wrote:
> On Fri, Oct 04, 2024 at 04:17:42PM +0100, Matthew Wilcox wrote:
> > On Fri, Oct 04, 2024 at 07:15:48PM +0530, Manas via B4 Relay wrote:
> > > +++ b/mm/memory.c
> > > @@ -6346,10 +6346,10 @@ static inline void pfnmap_args_setup(struct follow_pfnmap_args *args,
> > >  static inline void pfnmap_lockdep_assert(struct vm_area_struct *vma)
> > >  {
> > >  #ifdef CONFIG_LOCKDEP
> > > -	struct address_space *mapping = vma->vm_file->f_mapping;
> > > +	struct address_space *mapping = vma->vm_file ? vma->vm_file->f_mapping : NULL;
> > 
> > Overly long and complex line.  Much simpler to write:
> > 
> > 	struct address_space *mapping = NULL;
> > 
> > 	if (vma->vm_file)
> > 		mapping = vma->vm_file->f_mapping;
> > 
> > >  	if (mapping)
> > > -		lockdep_assert(lockdep_is_held(&vma->vm_file->f_mapping->i_mmap_rwsem) ||
> > > +		lockdep_assert(lockdep_is_held(&mapping->i_mmap_rwsem) ||
> > >  			       lockdep_is_held(&vma->vm_mm->mmap_lock));
> > >  	else
> > >  		lockdep_assert(lockdep_is_held(&vma->vm_mm->mmap_lock));
> > 
> > This one should have been lockdep_assert_held(&vma->vm_mm->mmap_lock).
> > 
> > I'm not sure that the previous one is correct.  The
> > lockdep_assert_held() macro is pretty careful about checking
> > LOCK_STATE_NOT_HELD to avoid the LOCK_STATE_UNKNOWN possibility.
> > But I'll leave that for Peter to fix.
> 
> Indeed..
> 
> Then looks like we could have quite a few other places in Linux that can
> have used this wrong.. when the assert wants to check against either of the
> two locks (one mutex or rcu read lock, for example) is held.
> 
> I'll send a patch after this one lands.

Just to follow this up and leave a record: I had a closer look today and
then quickly I found above should be all fine (similar to all kernel usages
like this, for example, rcu_dereference_check()).

The trick is LOCK_STATE_NOT_HELD is defined as 0:

#define LOCK_STATE_UNKNOWN	-1
#define LOCK_STATE_NOT_HELD	0
#define LOCK_STATE_HELD		1

So this:

#define lockdep_assert_held(l)		\
	lockdep_assert(lockdep_is_held(l) != LOCK_STATE_NOT_HELD)

Is the same to:

#define lockdep_assert_held(l)		\
	lockdep_assert(lockdep_is_held(l))

The lockdep_assert() was introduced exactly for such >1 lock assertion use
cases, in this commit:

commit d19c81378829e5d774c951219c5a973965b9202c
Author: Peter Zijlstra <peterz@infradead.org>
Date:   Mon Aug 2 18:59:56 2021 +0800

    locking/lockdep: Provide lockdep_assert{,_once}() helpers

    Extract lockdep_assert{,_once}() helpers to more easily write composite
    assertions like, for example:

            lockdep_assert(lockdep_is_held(&drm_device.master_mutex) ||
                           lockdep_is_held(&drm_file.master_lookup_lock));

Thanks,

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2024-12-05 15:20 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-10-04 13:45 [PATCH v3] Fixes: null pointer dereference in pfnmap_lockdep_assert Manas via B4 Relay
2024-10-04 13:47 ` Manas
2024-10-04 15:17 ` Matthew Wilcox
2024-10-04 17:40   ` Manas
2024-10-07 13:23   ` Peter Xu
2024-10-08 19:27     ` Peter Xu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox