mm: prevent vm_area_struct::anon_name refcount saturation
A deep process chain with many vmas could grow really high. With default sysctl_max_map_count (64k) and default pid_max (32k) the max number of vmas in the system is 2147450880 and the refcounter has headroom of 1073774592 before it reaches REFCOUNT_SATURATED (3221225472). Therefore it's unlikely that an anonymous name refcounter will overflow with these defaults. Currently the max for pid_max is PID_MAX_LIMIT (4194304) and for sysctl_max_map_count it's INT_MAX (2147483647). In this configuration anon_vma_name refcount overflow becomes theoretically possible (that still require heavy sharing of that anon_vma_name between processes). kref refcounting interface used in anon_vma_name structure will detect a counter overflow when it reaches REFCOUNT_SATURATED value but will only generate a warning and freeze the ref counter. This would lead to the refcounted object never being freed. A determined attacker could leak memory like that but it would be rather expensive and inefficient way to do so. To ensure anon_vma_name refcount does not overflow, stop anon_vma_name sharing when the refcount reaches REFCOUNT_MAX (2147483647), which still leaves INT_MAX/2 (1073741823) values before the counter reaches REFCOUNT_SATURATED. This should provide enough headroom for raising the refcounts temporarily. Link: https://lkml.kernel.org/r/20220223153613.835563-2-surenb@google.com Signed-off-by: Suren Baghdasaryan <surenb@google.com> Suggested-by: Michal Hocko <mhocko@suse.com> Acked-by: Michal Hocko <mhocko@suse.com> Cc: Alexey Gladkov <legion@kernel.org> Cc: Chris Hyser <chris.hyser@oracle.com> Cc: Christian Brauner <brauner@kernel.org> Cc: Colin Cross <ccross@google.com> Cc: Cyrill Gorcunov <gorcunov@gmail.com> Cc: Dave Hansen <dave.hansen@intel.com> Cc: David Hildenbrand <david@redhat.com> Cc: Davidlohr Bueso <dave@stgolabs.net> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Kees Cook <keescook@chromium.org> Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> Cc: Matthew Wilcox <willy@infradead.org> Cc: Peter Collingbourne <pcc@google.com> Cc: Sasha Levin <sashal@kernel.org> Cc: Sumit Semwal <sumit.semwal@linaro.org> Cc: Vlastimil Babka <vbabka@suse.cz> Cc: Xiaofeng Cao <caoxiaofeng@yulong.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
5c26f6ac94
commit
96403e1128
@ -161,15 +161,25 @@ static inline void anon_vma_name_put(struct anon_vma_name *anon_name)
|
||||
kref_put(&anon_name->kref, anon_vma_name_free);
|
||||
}
|
||||
|
||||
static inline
|
||||
struct anon_vma_name *anon_vma_name_reuse(struct anon_vma_name *anon_name)
|
||||
{
|
||||
/* Prevent anon_name refcount saturation early on */
|
||||
if (kref_read(&anon_name->kref) < REFCOUNT_MAX) {
|
||||
anon_vma_name_get(anon_name);
|
||||
return anon_name;
|
||||
|
||||
}
|
||||
return anon_vma_name_alloc(anon_name->name);
|
||||
}
|
||||
|
||||
static inline void dup_anon_vma_name(struct vm_area_struct *orig_vma,
|
||||
struct vm_area_struct *new_vma)
|
||||
{
|
||||
struct anon_vma_name *anon_name = anon_vma_name(orig_vma);
|
||||
|
||||
if (anon_name) {
|
||||
anon_vma_name_get(anon_name);
|
||||
new_vma->anon_name = anon_name;
|
||||
}
|
||||
if (anon_name)
|
||||
new_vma->anon_name = anon_vma_name_reuse(anon_name);
|
||||
}
|
||||
|
||||
static inline void free_anon_vma_name(struct vm_area_struct *vma)
|
||||
|
@ -113,8 +113,7 @@ static int replace_anon_vma_name(struct vm_area_struct *vma,
|
||||
if (anon_vma_name_eq(orig_name, anon_name))
|
||||
return 0;
|
||||
|
||||
anon_vma_name_get(anon_name);
|
||||
vma->anon_name = anon_name;
|
||||
vma->anon_name = anon_vma_name_reuse(anon_name);
|
||||
anon_vma_name_put(orig_name);
|
||||
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user