|
Lines 2155-2161
find_vma_prev(struct mm_struct *mm, unsigned long addr,
Link Here
|
| 2155 |
* update accounting. This is shared with both the |
2155 |
* update accounting. This is shared with both the |
| 2156 |
* grow-up and grow-down cases. |
2156 |
* grow-up and grow-down cases. |
| 2157 |
*/ |
2157 |
*/ |
| 2158 |
static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, unsigned long grow) |
2158 |
static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, unsigned long grow, |
|
|
2159 |
unsigned long gap) |
| 2159 |
{ |
2160 |
{ |
| 2160 |
struct mm_struct *mm = vma->vm_mm; |
2161 |
struct mm_struct *mm = vma->vm_mm; |
| 2161 |
struct rlimit *rlim = current->signal->rlim; |
2162 |
struct rlimit *rlim = current->signal->rlim; |
|
Lines 2168-2174
static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns
Link Here
|
| 2168 |
/* Stack limit test */ |
2169 |
/* Stack limit test */ |
| 2169 |
actual_size = size; |
2170 |
actual_size = size; |
| 2170 |
if (size && (vma->vm_flags & (VM_GROWSUP | VM_GROWSDOWN))) |
2171 |
if (size && (vma->vm_flags & (VM_GROWSUP | VM_GROWSDOWN))) |
| 2171 |
actual_size -= PAGE_SIZE; |
2172 |
actual_size -= gap; |
| 2172 |
if (actual_size > READ_ONCE(rlim[RLIMIT_STACK].rlim_cur)) |
2173 |
if (actual_size > READ_ONCE(rlim[RLIMIT_STACK].rlim_cur)) |
| 2173 |
return -ENOMEM; |
2174 |
return -ENOMEM; |
| 2174 |
|
2175 |
|
|
Lines 2204-2210
static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns
Link Here
|
| 2204 |
* PA-RISC uses this for its stack; IA64 for its Register Backing Store. |
2205 |
* PA-RISC uses this for its stack; IA64 for its Register Backing Store. |
| 2205 |
* vma is the last one with address > vma->vm_end. Have to extend vma. |
2206 |
* vma is the last one with address > vma->vm_end. Have to extend vma. |
| 2206 |
*/ |
2207 |
*/ |
| 2207 |
int expand_upwards(struct vm_area_struct *vma, unsigned long address) |
2208 |
int expand_upwards(struct vm_area_struct *vma, unsigned long address, unsigned long gap) |
| 2208 |
{ |
2209 |
{ |
| 2209 |
struct mm_struct *mm = vma->vm_mm; |
2210 |
struct mm_struct *mm = vma->vm_mm; |
| 2210 |
int error = 0; |
2211 |
int error = 0; |
|
Lines 2212-2223
int expand_upwards(struct vm_area_struct *vma, unsigned long address)
Link Here
|
| 2212 |
if (!(vma->vm_flags & VM_GROWSUP)) |
2213 |
if (!(vma->vm_flags & VM_GROWSUP)) |
| 2213 |
return -EFAULT; |
2214 |
return -EFAULT; |
| 2214 |
|
2215 |
|
| 2215 |
/* Guard against wrapping around to address 0. */ |
|
|
| 2216 |
if (address < PAGE_ALIGN(address+4)) |
| 2217 |
address = PAGE_ALIGN(address+4); |
| 2218 |
else |
| 2219 |
return -ENOMEM; |
| 2220 |
|
| 2221 |
/* We must make sure the anon_vma is allocated. */ |
2216 |
/* We must make sure the anon_vma is allocated. */ |
| 2222 |
if (unlikely(anon_vma_prepare(vma))) |
2217 |
if (unlikely(anon_vma_prepare(vma))) |
| 2223 |
return -ENOMEM; |
2218 |
return -ENOMEM; |
|
Lines 2238-2244
int expand_upwards(struct vm_area_struct *vma, unsigned long address)
Link Here
|
| 2238 |
|
2233 |
|
| 2239 |
error = -ENOMEM; |
2234 |
error = -ENOMEM; |
| 2240 |
if (vma->vm_pgoff + (size >> PAGE_SHIFT) >= vma->vm_pgoff) { |
2235 |
if (vma->vm_pgoff + (size >> PAGE_SHIFT) >= vma->vm_pgoff) { |
| 2241 |
error = acct_stack_growth(vma, size, grow); |
2236 |
error = acct_stack_growth(vma, size, grow, gap); |
| 2242 |
if (!error) { |
2237 |
if (!error) { |
| 2243 |
/* |
2238 |
/* |
| 2244 |
* vma_gap_update() doesn't support concurrent |
2239 |
* vma_gap_update() doesn't support concurrent |
|
Lines 2279-2285
int expand_upwards(struct vm_area_struct *vma, unsigned long address)
Link Here
|
| 2279 |
* vma is the first one with address < vma->vm_start. Have to extend vma. |
2274 |
* vma is the first one with address < vma->vm_start. Have to extend vma. |
| 2280 |
*/ |
2275 |
*/ |
| 2281 |
int expand_downwards(struct vm_area_struct *vma, |
2276 |
int expand_downwards(struct vm_area_struct *vma, |
| 2282 |
unsigned long address) |
2277 |
unsigned long address, unsigned long gap) |
| 2283 |
{ |
2278 |
{ |
| 2284 |
struct mm_struct *mm = vma->vm_mm; |
2279 |
struct mm_struct *mm = vma->vm_mm; |
| 2285 |
int error; |
2280 |
int error; |
|
Lines 2309-2315
int expand_downwards(struct vm_area_struct *vma,
Link Here
|
| 2309 |
|
2304 |
|
| 2310 |
error = -ENOMEM; |
2305 |
error = -ENOMEM; |
| 2311 |
if (grow <= vma->vm_pgoff) { |
2306 |
if (grow <= vma->vm_pgoff) { |
| 2312 |
error = acct_stack_growth(vma, size, grow); |
2307 |
error = acct_stack_growth(vma, size, grow, gap); |
| 2313 |
if (!error) { |
2308 |
if (!error) { |
| 2314 |
/* |
2309 |
/* |
| 2315 |
* vma_gap_update() doesn't support concurrent |
2310 |
* vma_gap_update() doesn't support concurrent |
|
Lines 2343-2371
int expand_downwards(struct vm_area_struct *vma,
Link Here
|
| 2343 |
return error; |
2338 |
return error; |
| 2344 |
} |
2339 |
} |
| 2345 |
|
2340 |
|
|
|
2341 |
/* enforced gap between the expanding stack and other mappings. */ |
| 2342 |
unsigned long stack_guard_gap = 256UL<<PAGE_SHIFT; |
| 2343 |
|
| 2346 |
/* |
2344 |
/* |
| 2347 |
* Note how expand_stack() refuses to expand the stack all the way to |
2345 |
* Note how expand_stack() refuses to expand the stack all the way to |
| 2348 |
* abut the next virtual mapping, *unless* that mapping itself is also |
2346 |
* abut the next virtual mapping, *unless* that mapping itself is also |
| 2349 |
* a stack mapping. We want to leave room for a guard page, after all |
2347 |
* a stack mapping. We want to leave room for a guard area, after all |
| 2350 |
* (the guard page itself is not added here, that is done by the |
2348 |
* (the guard page itself is not added here, that is done by the |
| 2351 |
* actual page faulting logic) |
2349 |
* actual page faulting logic) |
| 2352 |
* |
|
|
| 2353 |
* This matches the behavior of the guard page logic (see mm/memory.c: |
| 2354 |
* check_stack_guard_page()), which only allows the guard page to be |
| 2355 |
* removed under these circumstances. |
| 2356 |
*/ |
2350 |
*/ |
| 2357 |
#ifdef CONFIG_STACK_GROWSUP |
2351 |
#ifdef CONFIG_STACK_GROWSUP |
|
|
2352 |
unsigned long expandable_stack_area(struct vm_area_struct *vma, |
| 2353 |
unsigned long address, unsigned long *gap) |
| 2354 |
{ |
| 2355 |
struct vm_area_struct *next = vma->vm_next; |
| 2356 |
unsigned long guard_gap = stack_guard_gap; |
| 2357 |
unsigned long guard_addr; |
| 2358 |
|
| 2359 |
address = ALIGN(address, PAGE_SIZE);; |
| 2360 |
if (!next) |
| 2361 |
goto out; |
| 2362 |
|
| 2363 |
if (next->vm_flags & VM_GROWSUP) { |
| 2364 |
guard_gap = min(guard_gap, next->vm_start - address); |
| 2365 |
goto out; |
| 2366 |
} |
| 2367 |
|
| 2368 |
if (next->vm_start - address < guard_gap) |
| 2369 |
return -ENOMEM; |
| 2370 |
out: |
| 2371 |
if (TASK_SIZE - address < guard_gap) |
| 2372 |
guard_gap = TASK_SIZE - address; |
| 2373 |
guard_addr = address + guard_gap; |
| 2374 |
*gap = guard_gap; |
| 2375 |
|
| 2376 |
return guard_addr; |
| 2377 |
} |
| 2378 |
|
| 2358 |
int expand_stack(struct vm_area_struct *vma, unsigned long address) |
2379 |
int expand_stack(struct vm_area_struct *vma, unsigned long address) |
| 2359 |
{ |
2380 |
{ |
|
|
2381 |
unsigned long gap; |
| 2382 |
|
| 2383 |
address = expandable_stack_area(vma, address, &gap); |
| 2384 |
if (IS_ERR_VALUE(address)) |
| 2385 |
return -ENOMEM; |
| 2386 |
return expand_upwards(vma, address, gap); |
| 2387 |
} |
| 2388 |
|
| 2389 |
int stack_guard_area(struct vm_area_struct *vma, unsigned long address) |
| 2390 |
{ |
| 2360 |
struct vm_area_struct *next; |
2391 |
struct vm_area_struct *next; |
| 2361 |
|
2392 |
|
| 2362 |
address &= PAGE_MASK; |
2393 |
if (!(vma->vm_flags & VM_GROWSUP)) |
|
|
2394 |
return 0; |
| 2395 |
|
| 2396 |
/* |
| 2397 |
* strictly speaking there is a guard gap between disjoint stacks |
| 2398 |
* but the gap is not canonical (it might be smaller) and it is |
| 2399 |
* reasonably safe to assume that we can ignore that gap for stack |
| 2400 |
* POPULATE or /proc/<pid>[s]maps purposes |
| 2401 |
*/ |
| 2363 |
next = vma->vm_next; |
2402 |
next = vma->vm_next; |
| 2364 |
if (next && next->vm_start == address + PAGE_SIZE) { |
2403 |
if (next && next->vm_flags & VM_GROWSUP) |
| 2365 |
if (!(next->vm_flags & VM_GROWSUP)) |
2404 |
return 0; |
| 2366 |
return -ENOMEM; |
2405 |
|
| 2367 |
} |
2406 |
return vma->vm_end - address <= stack_guard_gap; |
| 2368 |
return expand_upwards(vma, address); |
|
|
| 2369 |
} |
2407 |
} |
| 2370 |
|
2408 |
|
| 2371 |
struct vm_area_struct * |
2409 |
struct vm_area_struct * |
|
Lines 2384-2400
find_extend_vma(struct mm_struct *mm, unsigned long addr)
Link Here
|
| 2384 |
return prev; |
2422 |
return prev; |
| 2385 |
} |
2423 |
} |
| 2386 |
#else |
2424 |
#else |
|
|
2425 |
unsigned long expandable_stack_area(struct vm_area_struct *vma, |
| 2426 |
unsigned long address, unsigned long *gap) |
| 2427 |
{ |
| 2428 |
struct vm_area_struct *prev = vma->vm_prev; |
| 2429 |
unsigned long guard_gap = stack_guard_gap; |
| 2430 |
unsigned long guard_addr; |
| 2431 |
|
| 2432 |
address &= PAGE_MASK; |
| 2433 |
if (!prev) |
| 2434 |
goto out; |
| 2435 |
|
| 2436 |
/* |
| 2437 |
* Is there a mapping abutting this one below? |
| 2438 |
* |
| 2439 |
* That's only ok if it's the same stack mapping |
| 2440 |
* that has gotten split or there is sufficient gap |
| 2441 |
* between mappings |
| 2442 |
*/ |
| 2443 |
if (prev->vm_flags & VM_GROWSDOWN) { |
| 2444 |
guard_gap = min(guard_gap, address - prev->vm_end); |
| 2445 |
goto out; |
| 2446 |
} |
| 2447 |
|
| 2448 |
if (address - prev->vm_end < guard_gap) |
| 2449 |
return -ENOMEM; |
| 2450 |
|
| 2451 |
out: |
| 2452 |
/* make sure we won't underflow */ |
| 2453 |
if (address < mmap_min_addr) |
| 2454 |
return -ENOMEM; |
| 2455 |
if (address - mmap_min_addr < guard_gap) |
| 2456 |
guard_gap = address - mmap_min_addr; |
| 2457 |
|
| 2458 |
guard_addr = address - guard_gap; |
| 2459 |
*gap = guard_gap; |
| 2460 |
|
| 2461 |
return guard_addr; |
| 2462 |
} |
| 2463 |
|
| 2387 |
int expand_stack(struct vm_area_struct *vma, unsigned long address) |
2464 |
int expand_stack(struct vm_area_struct *vma, unsigned long address) |
| 2388 |
{ |
2465 |
{ |
|
|
2466 |
unsigned long gap; |
| 2467 |
|
| 2468 |
address = expandable_stack_area(vma, address, &gap); |
| 2469 |
if (IS_ERR_VALUE(address)) |
| 2470 |
return -ENOMEM; |
| 2471 |
return expand_downwards(vma, address, gap); |
| 2472 |
} |
| 2473 |
|
| 2474 |
int stack_guard_area(struct vm_area_struct *vma, unsigned long address) |
| 2475 |
{ |
| 2389 |
struct vm_area_struct *prev; |
2476 |
struct vm_area_struct *prev; |
| 2390 |
|
2477 |
|
| 2391 |
address &= PAGE_MASK; |
2478 |
if (!(vma->vm_flags & VM_GROWSDOWN)) |
|
|
2479 |
return 0; |
| 2480 |
|
| 2481 |
/* |
| 2482 |
* strictly speaking there is a guard gap between disjoint stacks |
| 2483 |
* but the gap is not canonical (it might be smaller) and it is |
| 2484 |
* reasonably safe to assume that we can ignore that gap for stack |
| 2485 |
* POPULATE or /proc/<pid>[s]maps purposes |
| 2486 |
*/ |
| 2392 |
prev = vma->vm_prev; |
2487 |
prev = vma->vm_prev; |
| 2393 |
if (prev && prev->vm_end == address) { |
2488 |
if (prev && prev->vm_flags & VM_GROWSDOWN) |
| 2394 |
if (!(prev->vm_flags & VM_GROWSDOWN)) |
2489 |
return 0; |
| 2395 |
return -ENOMEM; |
2490 |
|
| 2396 |
} |
2491 |
return address - vma->vm_start < stack_guard_gap; |
| 2397 |
return expand_downwards(vma, address); |
|
|
| 2398 |
} |
2492 |
} |
| 2399 |
|
2493 |
|
| 2400 |
struct vm_area_struct * |
2494 |
struct vm_area_struct * |
| 2401 |
- |
|
|