linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] mm: list_lru: Fix NULL pointer dereference in list_lru_add()
@ 2024-07-12  3:25 Youling Tang
  2024-07-12  4:07 ` Kent Overstreet
  0 siblings, 1 reply; 9+ messages in thread
From: Youling Tang @ 2024-07-12  3:25 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Kent Overstreet, linux-mm, linux-kernel, Youling Tang

From: Youling Tang <tangyouling@kylinos.cn>

Note that list_lru_from_memcg_idx() may return NULL, so it is necessary
to error handle the return value to avoid triggering NULL pointer
dereference BUG.

The issue was triggered for discussion [1],
Link [1]: https://lore.kernel.org/linux-bcachefs/84de6cb1-57bd-42f7-8029-4203820ef0b4@linux.dev/T/#m901bb26cdb1d9d4bacebf0d034f0a5a712cc93a6

Signed-off-by: Youling Tang <tangyouling@kylinos.cn>
---
 mm/list_lru.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/mm/list_lru.c b/mm/list_lru.c
index 3fd64736bc45..ee7424c3879d 100644
--- a/mm/list_lru.c
+++ b/mm/list_lru.c
@@ -94,6 +94,9 @@ bool list_lru_add(struct list_lru *lru, struct list_head *item, int nid,
 	spin_lock(&nlru->lock);
 	if (list_empty(item)) {
 		l = list_lru_from_memcg_idx(lru, nid, memcg_kmem_id(memcg));
+		if (!l)
+			goto out;
+
 		list_add_tail(item, &l->list);
 		/* Set shrinker bit if the first element was added */
 		if (!l->nr_items++)
@@ -102,6 +105,7 @@ bool list_lru_add(struct list_lru *lru, struct list_head *item, int nid,
 		spin_unlock(&nlru->lock);
 		return true;
 	}
+out:
 	spin_unlock(&nlru->lock);
 	return false;
 }
-- 
2.34.1



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

* Re: [PATCH] mm: list_lru: Fix NULL pointer dereference in list_lru_add()
  2024-07-12  3:25 [PATCH] mm: list_lru: Fix NULL pointer dereference in list_lru_add() Youling Tang
@ 2024-07-12  4:07 ` Kent Overstreet
  2024-07-12  4:28   ` Youling Tang
  2024-07-15  3:27   ` Qi Zheng
  0 siblings, 2 replies; 9+ messages in thread
From: Kent Overstreet @ 2024-07-12  4:07 UTC (permalink / raw)
  To: Youling Tang; +Cc: Andrew Morton, linux-mm, linux-kernel, Youling Tang

On Fri, Jul 12, 2024 at 11:25:54AM GMT, Youling Tang wrote:
> From: Youling Tang <tangyouling@kylinos.cn>
> 
> Note that list_lru_from_memcg_idx() may return NULL, so it is necessary
> to error handle the return value to avoid triggering NULL pointer
> dereference BUG.
> 
> The issue was triggered for discussion [1],
> Link [1]: https://lore.kernel.org/linux-bcachefs/84de6cb1-57bd-42f7-8029-4203820ef0b4@linux.dev/T/#m901bb26cdb1d9d4bacebf0d034f0a5a712cc93a6

I see no explanation for why this is the correct fix, and I doubt it is.
What's the real reason for the NULL lru_list_one, and why doesn't this
come up on other filesystems?


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

* Re: [PATCH] mm: list_lru: Fix NULL pointer dereference in list_lru_add()
  2024-07-12  4:07 ` Kent Overstreet
@ 2024-07-12  4:28   ` Youling Tang
  2024-07-12 15:49     ` Kent Overstreet
  2024-07-15  3:27   ` Qi Zheng
  1 sibling, 1 reply; 9+ messages in thread
From: Youling Tang @ 2024-07-12  4:28 UTC (permalink / raw)
  To: Kent Overstreet; +Cc: Andrew Morton, linux-mm, linux-kernel, Youling Tang

Hi, Kent

On 12/07/2024 12:07, Kent Overstreet wrote:
> On Fri, Jul 12, 2024 at 11:25:54AM GMT, Youling Tang wrote:
>> From: Youling Tang <tangyouling@kylinos.cn>
>>
>> Note that list_lru_from_memcg_idx() may return NULL, so it is necessary
>> to error handle the return value to avoid triggering NULL pointer
>> dereference BUG.
>>
>> The issue was triggered for discussion [1],
>> Link [1]: https://lore.kernel.org/linux-bcachefs/84de6cb1-57bd-42f7-8029-4203820ef0b4@linux.dev/T/#m901bb26cdb1d9d4bacebf0d034f0a5a712cc93a6
> I see no explanation for why this is the correct fix, and I doubt it is.
> What's the real reason for the NULL lru_list_one, and why doesn't this
> come up on other filesystems?
We can break it down into two questions (independent of each other):
1) Error handling is necessary when l (lru_list_one) is NULL here.
2) Why does marking SLAB_ACCOUNT in bcachefs cause lru_list_one
    to be NULL?

This patch only fixes the first issue, and the real cause of the
second issue still needs to be analyzed.

Thanks,
Youling.


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

* Re: [PATCH] mm: list_lru: Fix NULL pointer dereference in list_lru_add()
  2024-07-12  4:28   ` Youling Tang
@ 2024-07-12 15:49     ` Kent Overstreet
  2024-07-16  2:28       ` Youling Tang
  0 siblings, 1 reply; 9+ messages in thread
From: Kent Overstreet @ 2024-07-12 15:49 UTC (permalink / raw)
  To: Youling Tang; +Cc: Andrew Morton, linux-mm, linux-kernel, Youling Tang

On Fri, Jul 12, 2024 at 12:28:57PM GMT, Youling Tang wrote:
> Hi, Kent
> 
> On 12/07/2024 12:07, Kent Overstreet wrote:
> > On Fri, Jul 12, 2024 at 11:25:54AM GMT, Youling Tang wrote:
> > > From: Youling Tang <tangyouling@kylinos.cn>
> > > 
> > > Note that list_lru_from_memcg_idx() may return NULL, so it is necessary
> > > to error handle the return value to avoid triggering NULL pointer
> > > dereference BUG.
> > > 
> > > The issue was triggered for discussion [1],
> > > Link [1]: https://lore.kernel.org/linux-bcachefs/84de6cb1-57bd-42f7-8029-4203820ef0b4@linux.dev/T/#m901bb26cdb1d9d4bacebf0d034f0a5a712cc93a6
> > I see no explanation for why this is the correct fix, and I doubt it is.
> > What's the real reason for the NULL lru_list_one, and why doesn't this
> > come up on other filesystems?
> We can break it down into two questions (independent of each other):
> 1) Error handling is necessary when l (lru_list_one) is NULL here.

No, you're just hiding the actual bug - since I wasn't clear, I'm naking
this patch.


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

* Re: [PATCH] mm: list_lru: Fix NULL pointer dereference in list_lru_add()
  2024-07-12  4:07 ` Kent Overstreet
  2024-07-12  4:28   ` Youling Tang
@ 2024-07-15  3:27   ` Qi Zheng
  2024-07-17  2:25     ` Youling Tang
  1 sibling, 1 reply; 9+ messages in thread
From: Qi Zheng @ 2024-07-15  3:27 UTC (permalink / raw)
  To: Kent Overstreet
  Cc: Youling Tang, Andrew Morton, linux-mm, linux-kernel, Youling Tang



On 2024/7/12 12:07, Kent Overstreet wrote:
> On Fri, Jul 12, 2024 at 11:25:54AM GMT, Youling Tang wrote:
>> From: Youling Tang <tangyouling@kylinos.cn>
>>
>> Note that list_lru_from_memcg_idx() may return NULL, so it is necessary
>> to error handle the return value to avoid triggering NULL pointer
>> dereference BUG.
>>
>> The issue was triggered for discussion [1],
>> Link [1]: https://lore.kernel.org/linux-bcachefs/84de6cb1-57bd-42f7-8029-4203820ef0b4@linux.dev/T/#m901bb26cdb1d9d4bacebf0d034f0a5a712cc93a6
> 
> I see no explanation for why this is the correct fix, and I doubt it is.
> What's the real reason for the NULL lru_list_one, and why doesn't this
> come up on other filesystems?

Agree, IIRC, the list_lru_one will be pre-allocated in the allocation
path of inode/dentry etc.


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

* Re: [PATCH] mm: list_lru: Fix NULL pointer dereference in list_lru_add()
  2024-07-12 15:49     ` Kent Overstreet
@ 2024-07-16  2:28       ` Youling Tang
  2024-07-16  2:30         ` Kent Overstreet
  0 siblings, 1 reply; 9+ messages in thread
From: Youling Tang @ 2024-07-16  2:28 UTC (permalink / raw)
  To: Kent Overstreet
  Cc: Andrew Morton, linux-mm, linux-kernel, Youling Tang, Qi Zheng

Hi, Kent

On 12/07/2024 23:49, Kent Overstreet wrote:
> On Fri, Jul 12, 2024 at 12:28:57PM GMT, Youling Tang wrote:
>> Hi, Kent
>>
>> On 12/07/2024 12:07, Kent Overstreet wrote:
>>> On Fri, Jul 12, 2024 at 11:25:54AM GMT, Youling Tang wrote:
>>>> From: Youling Tang <tangyouling@kylinos.cn>
>>>>
>>>> Note that list_lru_from_memcg_idx() may return NULL, so it is necessary
>>>> to error handle the return value to avoid triggering NULL pointer
>>>> dereference BUG.
>>>>
>>>> The issue was triggered for discussion [1],
>>>> Link [1]: https://lore.kernel.org/linux-bcachefs/84de6cb1-57bd-42f7-8029-4203820ef0b4@linux.dev/T/#m901bb26cdb1d9d4bacebf0d034f0a5a712cc93a6
>>> I see no explanation for why this is the correct fix, and I doubt it is.
>>> What's the real reason for the NULL lru_list_one, and why doesn't this
>>> come up on other filesystems?
>> We can break it down into two questions (independent of each other):
>> 1) Error handling is necessary when l (lru_list_one) is NULL here.
> No, you're just hiding the actual bug - since I wasn't clear, I'm naking
> this patch.
We should use kmem_cache_alloc_lru() instead of kmem_cache_alloc(),
similar to the [1] modification.

Apply the following patch to fix the problem:

diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c
index f9c9a95d7d4c..79a580dfb5e1 100644
--- a/fs/bcachefs/fs.c
+++ b/fs/bcachefs/fs.c
@@ -227,7 +227,8 @@ static struct inode *bch2_alloc_inode(struct 
super_block *sb)

  static struct bch_inode_info *__bch2_new_inode(struct bch_fs *c)
  {
-       struct bch_inode_info *inode = 
kmem_cache_alloc(bch2_inode_cache, GFP_NOFS);
+       struct bch_inode_info *inode = alloc_inode_sb(c->vfs_sb, 
bch2_inode_cache, GFP_NOFS);
         if (!inode)
                 return NULL;

Link [1]: 
https://lwn.net/ml/linux-kernel/20220228122126.37293-5-songmuchun@bytedance.com/

Thanks,
Youling.


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

* Re: [PATCH] mm: list_lru: Fix NULL pointer dereference in list_lru_add()
  2024-07-16  2:28       ` Youling Tang
@ 2024-07-16  2:30         ` Kent Overstreet
  0 siblings, 0 replies; 9+ messages in thread
From: Kent Overstreet @ 2024-07-16  2:30 UTC (permalink / raw)
  To: Youling Tang
  Cc: Andrew Morton, linux-mm, linux-kernel, Youling Tang, Qi Zheng

On Tue, Jul 16, 2024 at 10:28:33AM GMT, Youling Tang wrote:
> Hi, Kent
> 
> On 12/07/2024 23:49, Kent Overstreet wrote:
> > On Fri, Jul 12, 2024 at 12:28:57PM GMT, Youling Tang wrote:
> > > Hi, Kent
> > > 
> > > On 12/07/2024 12:07, Kent Overstreet wrote:
> > > > On Fri, Jul 12, 2024 at 11:25:54AM GMT, Youling Tang wrote:
> > > > > From: Youling Tang <tangyouling@kylinos.cn>
> > > > > 
> > > > > Note that list_lru_from_memcg_idx() may return NULL, so it is necessary
> > > > > to error handle the return value to avoid triggering NULL pointer
> > > > > dereference BUG.
> > > > > 
> > > > > The issue was triggered for discussion [1],
> > > > > Link [1]: https://lore.kernel.org/linux-bcachefs/84de6cb1-57bd-42f7-8029-4203820ef0b4@linux.dev/T/#m901bb26cdb1d9d4bacebf0d034f0a5a712cc93a6
> > > > I see no explanation for why this is the correct fix, and I doubt it is.
> > > > What's the real reason for the NULL lru_list_one, and why doesn't this
> > > > come up on other filesystems?
> > > We can break it down into two questions (independent of each other):
> > > 1) Error handling is necessary when l (lru_list_one) is NULL here.
> > No, you're just hiding the actual bug - since I wasn't clear, I'm naking
> > this patch.
> We should use kmem_cache_alloc_lru() instead of kmem_cache_alloc(),
> similar to the [1] modification.
> 
> Apply the following patch to fix the problem:

Thanks, send it as a proper patch and I'll apply it

> 
> diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c
> index f9c9a95d7d4c..79a580dfb5e1 100644
> --- a/fs/bcachefs/fs.c
> +++ b/fs/bcachefs/fs.c
> @@ -227,7 +227,8 @@ static struct inode *bch2_alloc_inode(struct super_block
> *sb)
> 
>  static struct bch_inode_info *__bch2_new_inode(struct bch_fs *c)
>  {
> -       struct bch_inode_info *inode = kmem_cache_alloc(bch2_inode_cache,
> GFP_NOFS);
> +       struct bch_inode_info *inode = alloc_inode_sb(c->vfs_sb,
> bch2_inode_cache, GFP_NOFS);
>         if (!inode)
>                 return NULL;
> 
> Link [1]: https://lwn.net/ml/linux-kernel/20220228122126.37293-5-songmuchun@bytedance.com/
> 
> Thanks,
> Youling.


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

* Re: [PATCH] mm: list_lru: Fix NULL pointer dereference in list_lru_add()
  2024-07-15  3:27   ` Qi Zheng
@ 2024-07-17  2:25     ` Youling Tang
  2024-07-17  2:37       ` Qi Zheng
  0 siblings, 1 reply; 9+ messages in thread
From: Youling Tang @ 2024-07-17  2:25 UTC (permalink / raw)
  To: Qi Zheng
  Cc: Kent Overstreet, Andrew Morton, linux-mm, linux-kernel,
	Youling Tang

On 15/07/2024 11:27, Qi Zheng wrote:
>
>
> On 2024/7/12 12:07, Kent Overstreet wrote:
>> On Fri, Jul 12, 2024 at 11:25:54AM GMT, Youling Tang wrote:
>>> From: Youling Tang <tangyouling@kylinos.cn>
>>>
>>> Note that list_lru_from_memcg_idx() may return NULL, so it is necessary
>>> to error handle the return value to avoid triggering NULL pointer
>>> dereference BUG.
>>>
>>> The issue was triggered for discussion [1],
>>> Link [1]: 
>>> https://lore.kernel.org/linux-bcachefs/84de6cb1-57bd-42f7-8029-4203820ef0b4@linux.dev/T/#m901bb26cdb1d9d4bacebf0d034f0a5a712cc93a6
>>
>> I see no explanation for why this is the correct fix, and I doubt it is.
>> What's the real reason for the NULL lru_list_one, and why doesn't this
>> come up on other filesystems?
>
> Agree, IIRC, the list_lru_one will be pre-allocated in the allocation
> path of inode/dentry etc.
Yes, this issue does not fix why lru_list_one is NULL.

lru_list_one is NULL because the inode is allocated using kmem_cache_alloc()
instead of kmem_cache_alloc_lru(), and the lru argument passed to
slab_alloc_node() is NULL. See [1] for the actual fix.

However, the return value of list_lru_from_memcg_idx() may be NULL. When
list_lru_one is NULL, the kernel will panic directly. Do we need to add
error handling when list_lru_one is NULL in list_lru_{add, del}?

To avoid hiding the actual BUG(previous changes), we might make the 
following
changes,

diff --git a/mm/list_lru.c b/mm/list_lru.c
index 3fd64736bc45..fa86d3eff90b 100644
--- a/mm/list_lru.c
+++ b/mm/list_lru.c
@@ -94,6 +94,9 @@ bool list_lru_add(struct list_lru *lru, struct 
list_head *item, int nid,
         spin_lock(&nlru->lock);
         if (list_empty(item)) {
                 l = list_lru_from_memcg_idx(lru, nid, 
memcg_kmem_id(memcg));
+               if (WARN_ON_ONCE(!l))
+                       goto out;
+
                 list_add_tail(item, &l->list);
                 /* Set shrinker bit if the first element was added */
                 if (!l->nr_items++)
@@ -102,6 +105,7 @@ bool list_lru_add(struct list_lru *lru, struct 
list_head *item, int nid,
                 spin_unlock(&nlru->lock);
                 return true;
         }
+out:
         spin_unlock(&nlru->lock);
         return false;
  }
@@ -126,12 +130,16 @@ bool list_lru_del(struct list_lru *lru, struct 
list_head *item, int nid,
         spin_lock(&nlru->lock);
         if (!list_empty(item)) {
                 l = list_lru_from_memcg_idx(lru, nid, 
memcg_kmem_id(memcg));
+               if (WARN_ON_ONCE(!l))
+                       goto out;
+
                 list_del_init(item);
                 l->nr_items--;
                 nlru->nr_items--;
                 spin_unlock(&nlru->lock);
                 return true;
         }
+out:
         spin_unlock(&nlru->lock);
         return false;
  }

Link:
[1]: 
https://lore.kernel.org/all/20240716025816.52156-1-youling.tang@linux.dev/

Thanks,
Youling.


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

* Re: [PATCH] mm: list_lru: Fix NULL pointer dereference in list_lru_add()
  2024-07-17  2:25     ` Youling Tang
@ 2024-07-17  2:37       ` Qi Zheng
  0 siblings, 0 replies; 9+ messages in thread
From: Qi Zheng @ 2024-07-17  2:37 UTC (permalink / raw)
  To: Youling Tang
  Cc: Kent Overstreet, Andrew Morton, linux-mm, linux-kernel,
	Youling Tang



On 2024/7/17 10:25, Youling Tang wrote:
> On 15/07/2024 11:27, Qi Zheng wrote:
>>
>>
>> On 2024/7/12 12:07, Kent Overstreet wrote:
>>> On Fri, Jul 12, 2024 at 11:25:54AM GMT, Youling Tang wrote:
>>>> From: Youling Tang <tangyouling@kylinos.cn>
>>>>
>>>> Note that list_lru_from_memcg_idx() may return NULL, so it is necessary
>>>> to error handle the return value to avoid triggering NULL pointer
>>>> dereference BUG.
>>>>
>>>> The issue was triggered for discussion [1],
>>>> Link [1]: 
>>>> https://lore.kernel.org/linux-bcachefs/84de6cb1-57bd-42f7-8029-4203820ef0b4@linux.dev/T/#m901bb26cdb1d9d4bacebf0d034f0a5a712cc93a6
>>>
>>> I see no explanation for why this is the correct fix, and I doubt it is.
>>> What's the real reason for the NULL lru_list_one, and why doesn't this
>>> come up on other filesystems?
>>
>> Agree, IIRC, the list_lru_one will be pre-allocated in the allocation
>> path of inode/dentry etc.
> Yes, this issue does not fix why lru_list_one is NULL.
> 
> lru_list_one is NULL because the inode is allocated using 
> kmem_cache_alloc()
> instead of kmem_cache_alloc_lru(), and the lru argument passed to
> slab_alloc_node() is NULL. See [1] for the actual fix.
> 
> However, the return value of list_lru_from_memcg_idx() may be NULL. When
> list_lru_one is NULL, the kernel will panic directly. Do we need to add
> error handling when list_lru_one is NULL in list_lru_{add, del}?

Nope, we should pre-allocated the list_lru_one before calling
list_lru_add().

> 
> To avoid hiding the actual BUG(previous changes), we might make the 
> following
> changes,

Even if you do this, you should still modify all callers
to handle this failure.

> 
> diff --git a/mm/list_lru.c b/mm/list_lru.c
> index 3fd64736bc45..fa86d3eff90b 100644
> --- a/mm/list_lru.c
> +++ b/mm/list_lru.c
> @@ -94,6 +94,9 @@ bool list_lru_add(struct list_lru *lru, struct 
> list_head *item, int nid,
>          spin_lock(&nlru->lock);
>          if (list_empty(item)) {
>                  l = list_lru_from_memcg_idx(lru, nid, 
> memcg_kmem_id(memcg));
> +               if (WARN_ON_ONCE(!l))
> +                       goto out;
> +
>                  list_add_tail(item, &l->list);
>                  /* Set shrinker bit if the first element was added */
>                  if (!l->nr_items++)
> @@ -102,6 +105,7 @@ bool list_lru_add(struct list_lru *lru, struct 
> list_head *item, int nid,
>                  spin_unlock(&nlru->lock);
>                  return true;
>          }
> +out:
>          spin_unlock(&nlru->lock);
>          return false;
>   }
> @@ -126,12 +130,16 @@ bool list_lru_del(struct list_lru *lru, struct 
> list_head *item, int nid,
>          spin_lock(&nlru->lock);
>          if (!list_empty(item)) {
>                  l = list_lru_from_memcg_idx(lru, nid, 
> memcg_kmem_id(memcg));
> +               if (WARN_ON_ONCE(!l))
> +                       goto out;
> +
>                  list_del_init(item);
>                  l->nr_items--;
>                  nlru->nr_items--;
>                  spin_unlock(&nlru->lock);
>                  return true;
>          }
> +out:
>          spin_unlock(&nlru->lock);
>          return false;
>   }
> 
> Link:
> [1]: 
> https://lore.kernel.org/all/20240716025816.52156-1-youling.tang@linux.dev/
> 
> Thanks,
> Youling.


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

end of thread, other threads:[~2024-07-17  2:37 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-07-12  3:25 [PATCH] mm: list_lru: Fix NULL pointer dereference in list_lru_add() Youling Tang
2024-07-12  4:07 ` Kent Overstreet
2024-07-12  4:28   ` Youling Tang
2024-07-12 15:49     ` Kent Overstreet
2024-07-16  2:28       ` Youling Tang
2024-07-16  2:30         ` Kent Overstreet
2024-07-15  3:27   ` Qi Zheng
2024-07-17  2:25     ` Youling Tang
2024-07-17  2:37       ` Qi Zheng

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).