Skip to content

Commit e6bbad7

Browse files
torvaldsgregkh
authored andcommitted
mm: always expand the stack with the mmap write lock held
commit 8d7071a upstream This finishes the job of always holding the mmap write lock when extending the user stack vma, and removes the 'write_locked' argument from the vm helper functions again. For some cases, we just avoid expanding the stack at all: drivers and page pinning really shouldn't be extending any stacks. Let's see if any strange users really wanted that. It's worth noting that architectures that weren't converted to the new lock_mm_and_find_vma() helper function are left using the legacy "expand_stack()" function, but it has been changed to drop the mmap_lock and take it for writing while expanding the vma. This makes it fairly straightforward to convert the remaining architectures. As a result of dropping and re-taking the lock, the calling conventions for this function have also changed, since the old vma may no longer be valid. So it will now return the new vma if successful, and NULL - and the lock dropped - if the area could not be extended. Signed-off-by: Linus Torvalds <[email protected]> [6.1: Patch drivers/iommu/io-pgfault.c instead] Signed-off-by: Samuel Mendoza-Jonas <[email protected]> Signed-off-by: David Woodhouse <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent c4b31d1 commit e6bbad7

File tree

17 files changed

+169
-116
lines changed

17 files changed

+169
-116
lines changed

arch/ia64/mm/fault.c

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,12 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
110110
* register backing store that needs to expand upwards, in
111111
* this case vma will be null, but prev_vma will ne non-null
112112
*/
113-
if (( !vma && prev_vma ) || (address < vma->vm_start) )
114-
goto check_expansion;
113+
if (( !vma && prev_vma ) || (address < vma->vm_start) ) {
114+
vma = expand_stack(mm, address);
115+
if (!vma)
116+
goto bad_area_nosemaphore;
117+
}
115118

116-
good_area:
117119
code = SEGV_ACCERR;
118120

119121
/* OK, we've got a good vm_area for this memory area. Check the access permissions: */
@@ -174,35 +176,9 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
174176
mmap_read_unlock(mm);
175177
return;
176178

177-
check_expansion:
178-
if (!(prev_vma && (prev_vma->vm_flags & VM_GROWSUP) && (address == prev_vma->vm_end))) {
179-
if (!vma)
180-
goto bad_area;
181-
if (!(vma->vm_flags & VM_GROWSDOWN))
182-
goto bad_area;
183-
if (REGION_NUMBER(address) != REGION_NUMBER(vma->vm_start)
184-
|| REGION_OFFSET(address) >= RGN_MAP_LIMIT)
185-
goto bad_area;
186-
if (expand_stack(vma, address))
187-
goto bad_area;
188-
} else {
189-
vma = prev_vma;
190-
if (REGION_NUMBER(address) != REGION_NUMBER(vma->vm_start)
191-
|| REGION_OFFSET(address) >= RGN_MAP_LIMIT)
192-
goto bad_area;
193-
/*
194-
* Since the register backing store is accessed sequentially,
195-
* we disallow growing it by more than a page at a time.
196-
*/
197-
if (address > vma->vm_end + PAGE_SIZE - sizeof(long))
198-
goto bad_area;
199-
if (expand_upwards(vma, address))
200-
goto bad_area;
201-
}
202-
goto good_area;
203-
204179
bad_area:
205180
mmap_read_unlock(mm);
181+
bad_area_nosemaphore:
206182
if ((isr & IA64_ISR_SP)
207183
|| ((isr & IA64_ISR_NA) && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH))
208184
{

arch/m68k/mm/fault.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,9 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
105105
if (address + 256 < rdusp())
106106
goto map_err;
107107
}
108-
if (expand_stack(vma, address))
109-
goto map_err;
108+
vma = expand_stack(mm, address);
109+
if (!vma)
110+
goto map_err_nosemaphore;
110111

111112
/*
112113
* Ok, we have a good vm_area for this memory access, so
@@ -193,10 +194,12 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
193194
goto send_sig;
194195

195196
map_err:
197+
mmap_read_unlock(mm);
198+
map_err_nosemaphore:
196199
current->thread.signo = SIGSEGV;
197200
current->thread.code = SEGV_MAPERR;
198201
current->thread.faddr = address;
199-
goto send_sig;
202+
return send_fault_sig(regs);
200203

201204
acc_err:
202205
current->thread.signo = SIGSEGV;

arch/microblaze/mm/fault.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,9 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
192192
&& (kernel_mode(regs) || !store_updates_sp(regs)))
193193
goto bad_area;
194194
}
195-
if (expand_stack(vma, address))
196-
goto bad_area;
195+
vma = expand_stack(mm, address);
196+
if (!vma)
197+
goto bad_area_nosemaphore;
197198

198199
good_area:
199200
code = SEGV_ACCERR;

arch/openrisc/mm/fault.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,9 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long address,
127127
if (address + PAGE_SIZE < regs->sp)
128128
goto bad_area;
129129
}
130-
if (expand_stack(vma, address))
131-
goto bad_area;
130+
vma = expand_stack(mm, address);
131+
if (!vma)
132+
goto bad_area_nosemaphore;
132133

133134
/*
134135
* Ok, we have a good vm_area for this memory access, so

arch/parisc/mm/fault.c

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -288,15 +288,19 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,
288288
retry:
289289
mmap_read_lock(mm);
290290
vma = find_vma_prev(mm, address, &prev_vma);
291-
if (!vma || address < vma->vm_start)
292-
goto check_expansion;
291+
if (!vma || address < vma->vm_start) {
292+
if (!prev || !(prev->vm_flags & VM_GROWSUP))
293+
goto bad_area;
294+
vma = expand_stack(mm, address);
295+
if (!vma)
296+
goto bad_area_nosemaphore;
297+
}
298+
293299
/*
294300
* Ok, we have a good vm_area for this memory access. We still need to
295301
* check the access permissions.
296302
*/
297303

298-
good_area:
299-
300304
if ((vma->vm_flags & acc_type) != acc_type)
301305
goto bad_area;
302306

@@ -342,17 +346,13 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,
342346
mmap_read_unlock(mm);
343347
return;
344348

345-
check_expansion:
346-
vma = prev_vma;
347-
if (vma && (expand_stack(vma, address) == 0))
348-
goto good_area;
349-
350349
/*
351350
* Something tried to access memory that isn't in our memory map..
352351
*/
353352
bad_area:
354353
mmap_read_unlock(mm);
355354

355+
bad_area_nosemaphore:
356356
if (user_mode(regs)) {
357357
int signo, si_code;
358358

@@ -444,7 +444,7 @@ handle_nadtlb_fault(struct pt_regs *regs)
444444
{
445445
unsigned long insn = regs->iir;
446446
int breg, treg, xreg, val = 0;
447-
struct vm_area_struct *vma, *prev_vma;
447+
struct vm_area_struct *vma;
448448
struct task_struct *tsk;
449449
struct mm_struct *mm;
450450
unsigned long address;
@@ -480,7 +480,7 @@ handle_nadtlb_fault(struct pt_regs *regs)
480480
/* Search for VMA */
481481
address = regs->ior;
482482
mmap_read_lock(mm);
483-
vma = find_vma_prev(mm, address, &prev_vma);
483+
vma = vma_lookup(mm, address);
484484
mmap_read_unlock(mm);
485485

486486
/*
@@ -489,7 +489,6 @@ handle_nadtlb_fault(struct pt_regs *regs)
489489
*/
490490
acc_type = (insn & 0x40) ? VM_WRITE : VM_READ;
491491
if (vma
492-
&& address >= vma->vm_start
493492
&& (vma->vm_flags & acc_type) == acc_type)
494493
val = 1;
495494
}

arch/s390/mm/fault.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -429,8 +429,9 @@ static inline vm_fault_t do_exception(struct pt_regs *regs, int access)
429429
if (unlikely(vma->vm_start > address)) {
430430
if (!(vma->vm_flags & VM_GROWSDOWN))
431431
goto out_up;
432-
if (expand_stack(vma, address))
433-
goto out_up;
432+
vma = expand_stack(mm, address);
433+
if (!vma)
434+
goto out;
434435
}
435436

436437
/*

arch/sparc/mm/fault_64.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -383,8 +383,9 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
383383
goto bad_area;
384384
}
385385
}
386-
if (expand_stack(vma, address))
387-
goto bad_area;
386+
vma = expand_stack(mm, address);
387+
if (!vma)
388+
goto bad_area_nosemaphore;
388389
/*
389390
* Ok, we have a good vm_area for this memory access, so
390391
* we can handle it..
@@ -482,8 +483,9 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
482483
* Fix it, but check if it's kernel or user first..
483484
*/
484485
bad_area:
485-
insn = get_fault_insn(regs, insn);
486486
mmap_read_unlock(mm);
487+
bad_area_nosemaphore:
488+
insn = get_fault_insn(regs, insn);
487489

488490
handle_kernel_fault:
489491
do_kernel_fault(regs, si_code, fault_code, insn, address);

arch/um/kernel/trap.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,15 @@ int handle_page_fault(unsigned long address, unsigned long ip,
4747
vma = find_vma(mm, address);
4848
if (!vma)
4949
goto out;
50-
else if (vma->vm_start <= address)
50+
if (vma->vm_start <= address)
5151
goto good_area;
52-
else if (!(vma->vm_flags & VM_GROWSDOWN))
52+
if (!(vma->vm_flags & VM_GROWSDOWN))
5353
goto out;
54-
else if (is_user && !ARCH_IS_STACKGROW(address))
55-
goto out;
56-
else if (expand_stack(vma, address))
54+
if (is_user && !ARCH_IS_STACKGROW(address))
5755
goto out;
56+
vma = expand_stack(mm, address);
57+
if (!vma)
58+
goto out_nosemaphore;
5859

5960
good_area:
6061
*code_out = SEGV_ACCERR;

drivers/iommu/amd/iommu_v2.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -485,8 +485,8 @@ static void do_fault(struct work_struct *work)
485485
flags |= FAULT_FLAG_REMOTE;
486486

487487
mmap_read_lock(mm);
488-
vma = find_extend_vma(mm, address);
489-
if (!vma || address < vma->vm_start)
488+
vma = vma_lookup(mm, address);
489+
if (!vma)
490490
/* failed to get a vma in the right range */
491491
goto out;
492492

drivers/iommu/io-pgfault.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ iopf_handle_single(struct iopf_fault *iopf)
8989

9090
mmap_read_lock(mm);
9191

92-
vma = find_extend_vma(mm, prm->addr);
92+
vma = vma_lookup(mm, prm->addr);
9393
if (!vma)
9494
/* Unmapped area */
9595
goto out_put_mm;

0 commit comments

Comments
 (0)