diff options
Diffstat (limited to 'fs/exec.c')
| -rw-r--r-- | fs/exec.c | 28 |
1 files changed, 24 insertions, 4 deletions
| @@ -220,8 +220,26 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, | |||
| 220 | 220 | ||
| 221 | if (write) { | 221 | if (write) { |
| 222 | unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start; | 222 | unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start; |
| 223 | unsigned long ptr_size; | ||
| 223 | struct rlimit *rlim; | 224 | struct rlimit *rlim; |
| 224 | 225 | ||
| 226 | /* | ||
| 227 | * Since the stack will hold pointers to the strings, we | ||
| 228 | * must account for them as well. | ||
| 229 | * | ||
| 230 | * The size calculation is the entire vma while each arg page is | ||
| 231 | * built, so each time we get here it's calculating how far it | ||
| 232 | * is currently (rather than each call being just the newly | ||
| 233 | * added size from the arg page). As a result, we need to | ||
| 234 | * always add the entire size of the pointers, so that on the | ||
| 235 | * last call to get_arg_page() we'll actually have the entire | ||
| 236 | * correct size. | ||
| 237 | */ | ||
| 238 | ptr_size = (bprm->argc + bprm->envc) * sizeof(void *); | ||
| 239 | if (ptr_size > ULONG_MAX - size) | ||
| 240 | goto fail; | ||
| 241 | size += ptr_size; | ||
| 242 | |||
| 225 | acct_arg_size(bprm, size / PAGE_SIZE); | 243 | acct_arg_size(bprm, size / PAGE_SIZE); |
| 226 | 244 | ||
| 227 | /* | 245 | /* |
| @@ -239,13 +257,15 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, | |||
| 239 | * to work from. | 257 | * to work from. |
| 240 | */ | 258 | */ |
| 241 | rlim = current->signal->rlim; | 259 | rlim = current->signal->rlim; |
| 242 | if (size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur) / 4) { | 260 | if (size > READ_ONCE(rlim[RLIMIT_STACK].rlim_cur) / 4) |
| 243 | put_page(page); | 261 | goto fail; |
| 244 | return NULL; | ||
| 245 | } | ||
| 246 | } | 262 | } |
| 247 | 263 | ||
| 248 | return page; | 264 | return page; |
| 265 | |||
| 266 | fail: | ||
| 267 | put_page(page); | ||
| 268 | return NULL; | ||
| 249 | } | 269 | } |
| 250 | 270 | ||
| 251 | static void put_arg_page(struct page *page) | 271 | static void put_arg_page(struct page *page) |
