Skip to content

Commit 0014404

Browse files
committed
Merge branch 'akpm' (patches from Andrew)
Merge misc fixes from Andrew Morton: "8 patches. Subsystems affected by this patch series: mm (hugetlb, pagemap, and userfaultfd), memfd, selftests, and kconfig" * emailed patches from Andrew Morton <akpm@linux-foundation.org>: configs/debug: set CONFIG_DEBUG_INFO=y properly proc: fix documentation and description of pagemap kselftest/vm: fix tests build with old libc memfd: fix F_SEAL_WRITE after shmem huge page allocated mm: fix use-after-free when anon vma name is used after vma is freed mm: prevent vm_area_struct::anon_name refcount saturation mm: refactor vm_area_struct::anon_vma_name usage code selftests/vm: cleanup hugetlb file after mremap test
2 parents f9026e1 + d1eff16 commit 0014404

File tree

18 files changed

+194
-137
lines changed

18 files changed

+194
-137
lines changed

Documentation/admin-guide/mm/pagemap.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ There are four components to pagemap:
2323
* Bit 56 page exclusively mapped (since 4.2)
2424
* Bit 57 pte is uffd-wp write-protected (since 5.13) (see
2525
:ref:`Documentation/admin-guide/mm/userfaultfd.rst <userfaultfd>`)
26-
* Bits 57-60 zero
26+
* Bits 58-60 zero
2727
* Bit 61 page is file-page or shared-anon (since 3.5)
2828
* Bit 62 page swapped
2929
* Bit 63 page present

fs/proc/task_mmu.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
309309

310310
name = arch_vma_name(vma);
311311
if (!name) {
312-
const char *anon_name;
312+
struct anon_vma_name *anon_name;
313313

314314
if (!mm) {
315315
name = "[vdso]";
@@ -327,10 +327,10 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
327327
goto done;
328328
}
329329

330-
anon_name = vma_anon_name(vma);
330+
anon_name = anon_vma_name(vma);
331331
if (anon_name) {
332332
seq_pad(m, ' ');
333-
seq_printf(m, "[anon:%s]", anon_name);
333+
seq_printf(m, "[anon:%s]", anon_name->name);
334334
}
335335
}
336336

@@ -1597,7 +1597,8 @@ static const struct mm_walk_ops pagemap_ops = {
15971597
* Bits 5-54 swap offset if swapped
15981598
* Bit 55 pte is soft-dirty (see Documentation/admin-guide/mm/soft-dirty.rst)
15991599
* Bit 56 page exclusively mapped
1600-
* Bits 57-60 zero
1600+
* Bit 57 pte is uffd-wp write-protected
1601+
* Bits 58-60 zero
16011602
* Bit 61 page is file-page or shared-anon
16021603
* Bit 62 page swapped
16031604
* Bit 63 page present

fs/userfaultfd.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -878,7 +878,7 @@ static int userfaultfd_release(struct inode *inode, struct file *file)
878878
new_flags, vma->anon_vma,
879879
vma->vm_file, vma->vm_pgoff,
880880
vma_policy(vma),
881-
NULL_VM_UFFD_CTX, vma_anon_name(vma));
881+
NULL_VM_UFFD_CTX, anon_vma_name(vma));
882882
if (prev)
883883
vma = prev;
884884
else
@@ -1438,7 +1438,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
14381438
vma->anon_vma, vma->vm_file, vma->vm_pgoff,
14391439
vma_policy(vma),
14401440
((struct vm_userfaultfd_ctx){ ctx }),
1441-
vma_anon_name(vma));
1441+
anon_vma_name(vma));
14421442
if (prev) {
14431443
vma = prev;
14441444
goto next;
@@ -1615,7 +1615,7 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
16151615
prev = vma_merge(mm, prev, start, vma_end, new_flags,
16161616
vma->anon_vma, vma->vm_file, vma->vm_pgoff,
16171617
vma_policy(vma),
1618-
NULL_VM_UFFD_CTX, vma_anon_name(vma));
1618+
NULL_VM_UFFD_CTX, anon_vma_name(vma));
16191619
if (prev) {
16201620
vma = prev;
16211621
goto next;

include/linux/mm.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2626,7 +2626,7 @@ static inline int vma_adjust(struct vm_area_struct *vma, unsigned long start,
26262626
extern struct vm_area_struct *vma_merge(struct mm_struct *,
26272627
struct vm_area_struct *prev, unsigned long addr, unsigned long end,
26282628
unsigned long vm_flags, struct anon_vma *, struct file *, pgoff_t,
2629-
struct mempolicy *, struct vm_userfaultfd_ctx, const char *);
2629+
struct mempolicy *, struct vm_userfaultfd_ctx, struct anon_vma_name *);
26302630
extern struct anon_vma *find_mergeable_anon_vma(struct vm_area_struct *);
26312631
extern int __split_vma(struct mm_struct *, struct vm_area_struct *,
26322632
unsigned long addr, int new_below);
@@ -3372,11 +3372,12 @@ static inline int seal_check_future_write(int seals, struct vm_area_struct *vma)
33723372

33733373
#ifdef CONFIG_ANON_VMA_NAME
33743374
int madvise_set_anon_name(struct mm_struct *mm, unsigned long start,
3375-
unsigned long len_in, const char *name);
3375+
unsigned long len_in,
3376+
struct anon_vma_name *anon_name);
33763377
#else
33773378
static inline int
33783379
madvise_set_anon_name(struct mm_struct *mm, unsigned long start,
3379-
unsigned long len_in, const char *name) {
3380+
unsigned long len_in, struct anon_vma_name *anon_name) {
33803381
return 0;
33813382
}
33823383
#endif

include/linux/mm_inline.h

Lines changed: 69 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -140,50 +140,91 @@ static __always_inline void del_page_from_lru_list(struct page *page,
140140

141141
#ifdef CONFIG_ANON_VMA_NAME
142142
/*
143-
* mmap_lock should be read-locked when calling vma_anon_name() and while using
144-
* the returned pointer.
143+
* mmap_lock should be read-locked when calling anon_vma_name(). Caller should
144+
* either keep holding the lock while using the returned pointer or it should
145+
* raise anon_vma_name refcount before releasing the lock.
145146
*/
146-
extern const char *vma_anon_name(struct vm_area_struct *vma);
147+
extern struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma);
148+
extern struct anon_vma_name *anon_vma_name_alloc(const char *name);
149+
extern void anon_vma_name_free(struct kref *kref);
147150

148-
/*
149-
* mmap_lock should be read-locked for orig_vma->vm_mm.
150-
* mmap_lock should be write-locked for new_vma->vm_mm or new_vma should be
151-
* isolated.
152-
*/
153-
extern void dup_vma_anon_name(struct vm_area_struct *orig_vma,
154-
struct vm_area_struct *new_vma);
151+
/* mmap_lock should be read-locked */
152+
static inline void anon_vma_name_get(struct anon_vma_name *anon_name)
153+
{
154+
if (anon_name)
155+
kref_get(&anon_name->kref);
156+
}
155157

156-
/*
157-
* mmap_lock should be write-locked or vma should have been isolated under
158-
* write-locked mmap_lock protection.
159-
*/
160-
extern void free_vma_anon_name(struct vm_area_struct *vma);
158+
static inline void anon_vma_name_put(struct anon_vma_name *anon_name)
159+
{
160+
if (anon_name)
161+
kref_put(&anon_name->kref, anon_vma_name_free);
162+
}
161163

162-
/* mmap_lock should be read-locked */
163-
static inline bool is_same_vma_anon_name(struct vm_area_struct *vma,
164-
const char *name)
164+
static inline
165+
struct anon_vma_name *anon_vma_name_reuse(struct anon_vma_name *anon_name)
166+
{
167+
/* Prevent anon_name refcount saturation early on */
168+
if (kref_read(&anon_name->kref) < REFCOUNT_MAX) {
169+
anon_vma_name_get(anon_name);
170+
return anon_name;
171+
172+
}
173+
return anon_vma_name_alloc(anon_name->name);
174+
}
175+
176+
static inline void dup_anon_vma_name(struct vm_area_struct *orig_vma,
177+
struct vm_area_struct *new_vma)
178+
{
179+
struct anon_vma_name *anon_name = anon_vma_name(orig_vma);
180+
181+
if (anon_name)
182+
new_vma->anon_name = anon_vma_name_reuse(anon_name);
183+
}
184+
185+
static inline void free_anon_vma_name(struct vm_area_struct *vma)
165186
{
166-
const char *vma_name = vma_anon_name(vma);
187+
/*
188+
* Not using anon_vma_name because it generates a warning if mmap_lock
189+
* is not held, which might be the case here.
190+
*/
191+
if (!vma->vm_file)
192+
anon_vma_name_put(vma->anon_name);
193+
}
167194

168-
/* either both NULL, or pointers to same string */
169-
if (vma_name == name)
195+
static inline bool anon_vma_name_eq(struct anon_vma_name *anon_name1,
196+
struct anon_vma_name *anon_name2)
197+
{
198+
if (anon_name1 == anon_name2)
170199
return true;
171200

172-
return name && vma_name && !strcmp(name, vma_name);
201+
return anon_name1 && anon_name2 &&
202+
!strcmp(anon_name1->name, anon_name2->name);
173203
}
204+
174205
#else /* CONFIG_ANON_VMA_NAME */
175-
static inline const char *vma_anon_name(struct vm_area_struct *vma)
206+
static inline struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma)
176207
{
177208
return NULL;
178209
}
179-
static inline void dup_vma_anon_name(struct vm_area_struct *orig_vma,
180-
struct vm_area_struct *new_vma) {}
181-
static inline void free_vma_anon_name(struct vm_area_struct *vma) {}
182-
static inline bool is_same_vma_anon_name(struct vm_area_struct *vma,
183-
const char *name)
210+
211+
static inline struct anon_vma_name *anon_vma_name_alloc(const char *name)
212+
{
213+
return NULL;
214+
}
215+
216+
static inline void anon_vma_name_get(struct anon_vma_name *anon_name) {}
217+
static inline void anon_vma_name_put(struct anon_vma_name *anon_name) {}
218+
static inline void dup_anon_vma_name(struct vm_area_struct *orig_vma,
219+
struct vm_area_struct *new_vma) {}
220+
static inline void free_anon_vma_name(struct vm_area_struct *vma) {}
221+
222+
static inline bool anon_vma_name_eq(struct anon_vma_name *anon_name1,
223+
struct anon_vma_name *anon_name2)
184224
{
185225
return true;
186226
}
227+
187228
#endif /* CONFIG_ANON_VMA_NAME */
188229

189230
static inline void init_tlb_flush_pending(struct mm_struct *mm)

include/linux/mm_types.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,10 @@ struct vm_area_struct {
416416
struct rb_node rb;
417417
unsigned long rb_subtree_last;
418418
} shared;
419-
/* Serialized by mmap_sem. */
419+
/*
420+
* Serialized by mmap_sem. Never use directly because it is
421+
* valid only when vm_file is NULL. Use anon_vma_name instead.
422+
*/
420423
struct anon_vma_name *anon_name;
421424
};
422425

kernel/configs/debug.config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ CONFIG_SYMBOLIC_ERRNAME=y
1616
#
1717
# Compile-time checks and compiler options
1818
#
19-
CONFIG_DEBUG_INFO=y
19+
CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
2020
CONFIG_DEBUG_SECTION_MISMATCH=y
2121
CONFIG_FRAME_WARN=2048
2222
CONFIG_SECTION_MISMATCH_WARN_ONLY=y

kernel/fork.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -366,14 +366,14 @@ struct vm_area_struct *vm_area_dup(struct vm_area_struct *orig)
366366
*new = data_race(*orig);
367367
INIT_LIST_HEAD(&new->anon_vma_chain);
368368
new->vm_next = new->vm_prev = NULL;
369-
dup_vma_anon_name(orig, new);
369+
dup_anon_vma_name(orig, new);
370370
}
371371
return new;
372372
}
373373

374374
void vm_area_free(struct vm_area_struct *vma)
375375
{
376-
free_vma_anon_name(vma);
376+
free_anon_vma_name(vma);
377377
kmem_cache_free(vm_area_cachep, vma);
378378
}
379379

kernel/sys.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <linux/export.h>
99
#include <linux/mm.h>
10+
#include <linux/mm_inline.h>
1011
#include <linux/utsname.h>
1112
#include <linux/mman.h>
1213
#include <linux/reboot.h>
@@ -2286,15 +2287,16 @@ static int prctl_set_vma(unsigned long opt, unsigned long addr,
22862287
{
22872288
struct mm_struct *mm = current->mm;
22882289
const char __user *uname;
2289-
char *name, *pch;
2290+
struct anon_vma_name *anon_name = NULL;
22902291
int error;
22912292

22922293
switch (opt) {
22932294
case PR_SET_VMA_ANON_NAME:
22942295
uname = (const char __user *)arg;
22952296
if (uname) {
2296-
name = strndup_user(uname, ANON_VMA_NAME_MAX_LEN);
2297+
char *name, *pch;
22972298

2299+
name = strndup_user(uname, ANON_VMA_NAME_MAX_LEN);
22982300
if (IS_ERR(name))
22992301
return PTR_ERR(name);
23002302

@@ -2304,15 +2306,18 @@ static int prctl_set_vma(unsigned long opt, unsigned long addr,
23042306
return -EINVAL;
23052307
}
23062308
}
2307-
} else {
2308-
/* Reset the name */
2309-
name = NULL;
2309+
/* anon_vma has its own copy */
2310+
anon_name = anon_vma_name_alloc(name);
2311+
kfree(name);
2312+
if (!anon_name)
2313+
return -ENOMEM;
2314+
23102315
}
23112316

23122317
mmap_write_lock(mm);
2313-
error = madvise_set_anon_name(mm, addr, size, name);
2318+
error = madvise_set_anon_name(mm, addr, size, anon_name);
23142319
mmap_write_unlock(mm);
2315-
kfree(name);
2320+
anon_vma_name_put(anon_name);
23162321
break;
23172322
default:
23182323
error = -EINVAL;

0 commit comments

Comments
 (0)