Message ID | 20240801024603.1865-1-songmuchun@bytedance.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | [v2] mm: list_lru: fix UAF for memory cgroup | expand |
On 8/1/24 04:46, Muchun Song wrote: > The mem_cgroup_from_slab_obj() is supposed to be called under rcu > lock or cgroup_mutex or others which could prevent returned memcg > from being freed. Fix it by adding missing rcu read lock. > > Fixes: 0a97c01cd20b ("list_lru: allow explicit memcg and NUMA node selection") > Signed-off-by: Muchun Song <songmuchun@bytedance.com> > Acked-by: Shakeel Butt <shakeel.butt@linux.dev> > Cc: <stable@vger.kernel.org> Acked-by: Vlastimil Babka <vbabka@suse.cz> > --- > v2: > Only grab rcu lock when necessary (Vlastimil Babka) > > mm/list_lru.c | 28 ++++++++++++++++++++++------ > 1 file changed, 22 insertions(+), 6 deletions(-) > > diff --git a/mm/list_lru.c b/mm/list_lru.c > index a29d96929d7c7..9b7ff06e9d326 100644 > --- a/mm/list_lru.c > +++ b/mm/list_lru.c > @@ -85,6 +85,7 @@ list_lru_from_memcg_idx(struct list_lru *lru, int nid, int idx) > } > #endif /* CONFIG_MEMCG */ > > +/* The caller must ensure the memcg lifetime. */ > bool list_lru_add(struct list_lru *lru, struct list_head *item, int nid, > struct mem_cgroup *memcg) > { > @@ -109,14 +110,22 @@ EXPORT_SYMBOL_GPL(list_lru_add); > > bool list_lru_add_obj(struct list_lru *lru, struct list_head *item) > { > + bool ret; > int nid = page_to_nid(virt_to_page(item)); > - struct mem_cgroup *memcg = list_lru_memcg_aware(lru) ? > - mem_cgroup_from_slab_obj(item) : NULL; > > - return list_lru_add(lru, item, nid, memcg); > + if (list_lru_memcg_aware(lru)) { > + rcu_read_lock(); > + ret = list_lru_add(lru, item, nid, mem_cgroup_from_slab_obj(item)); > + rcu_read_unlock(); > + } else { > + ret = list_lru_add(lru, item, nid, NULL); > + } > + > + return ret; > } > EXPORT_SYMBOL_GPL(list_lru_add_obj); > > +/* The caller must ensure the memcg lifetime. */ > bool list_lru_del(struct list_lru *lru, struct list_head *item, int nid, > struct mem_cgroup *memcg) > { > @@ -139,11 +148,18 @@ EXPORT_SYMBOL_GPL(list_lru_del); > > bool list_lru_del_obj(struct list_lru *lru, struct list_head *item) > { > + bool ret; > int nid = page_to_nid(virt_to_page(item)); > - struct mem_cgroup *memcg = list_lru_memcg_aware(lru) ? > - mem_cgroup_from_slab_obj(item) : NULL; > > - return list_lru_del(lru, item, nid, memcg); > + if (list_lru_memcg_aware(lru)) { > + rcu_read_lock(); > + ret = list_lru_del(lru, item, nid, mem_cgroup_from_slab_obj(item)); > + rcu_read_unlock(); > + } else { > + ret = list_lru_del(lru, item, nid, NULL); > + } > + > + return ret; > } > EXPORT_SYMBOL_GPL(list_lru_del_obj); >
diff --git a/mm/list_lru.c b/mm/list_lru.c index a29d96929d7c7..9b7ff06e9d326 100644 --- a/mm/list_lru.c +++ b/mm/list_lru.c @@ -85,6 +85,7 @@ list_lru_from_memcg_idx(struct list_lru *lru, int nid, int idx) } #endif /* CONFIG_MEMCG */ +/* The caller must ensure the memcg lifetime. */ bool list_lru_add(struct list_lru *lru, struct list_head *item, int nid, struct mem_cgroup *memcg) { @@ -109,14 +110,22 @@ EXPORT_SYMBOL_GPL(list_lru_add); bool list_lru_add_obj(struct list_lru *lru, struct list_head *item) { + bool ret; int nid = page_to_nid(virt_to_page(item)); - struct mem_cgroup *memcg = list_lru_memcg_aware(lru) ? - mem_cgroup_from_slab_obj(item) : NULL; - return list_lru_add(lru, item, nid, memcg); + if (list_lru_memcg_aware(lru)) { + rcu_read_lock(); + ret = list_lru_add(lru, item, nid, mem_cgroup_from_slab_obj(item)); + rcu_read_unlock(); + } else { + ret = list_lru_add(lru, item, nid, NULL); + } + + return ret; } EXPORT_SYMBOL_GPL(list_lru_add_obj); +/* The caller must ensure the memcg lifetime. */ bool list_lru_del(struct list_lru *lru, struct list_head *item, int nid, struct mem_cgroup *memcg) { @@ -139,11 +148,18 @@ EXPORT_SYMBOL_GPL(list_lru_del); bool list_lru_del_obj(struct list_lru *lru, struct list_head *item) { + bool ret; int nid = page_to_nid(virt_to_page(item)); - struct mem_cgroup *memcg = list_lru_memcg_aware(lru) ? - mem_cgroup_from_slab_obj(item) : NULL; - return list_lru_del(lru, item, nid, memcg); + if (list_lru_memcg_aware(lru)) { + rcu_read_lock(); + ret = list_lru_del(lru, item, nid, mem_cgroup_from_slab_obj(item)); + rcu_read_unlock(); + } else { + ret = list_lru_del(lru, item, nid, NULL); + } + + return ret; } EXPORT_SYMBOL_GPL(list_lru_del_obj);