aboutsummaryrefslogtreecommitdiffstats
path: root/fs/exec.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2017-06-24 08:57:20 +0200
committerIngo Molnar <mingo@kernel.org>2017-06-24 08:57:20 +0200
commit1bc3cd4dfa9f2f5385ee15de2301d25e51cf43f0 (patch)
treecd38acbcaeea1520a598cf8978002a07c2a5993b /fs/exec.c
parent8887cd99038bf242fb47f2d07fa0cf9371efa643 (diff)
parent94a6df251dd08c6436ebd6d10c68f03659148ce1 (diff)
downloadnet-1bc3cd4dfa9f2f5385ee15de2301d25e51cf43f0.tar.gz
Merge branch 'linus' into sched/core, to pick up fixes
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'fs/exec.c')
-rw-r--r--fs/exec.c28
1 files changed, 24 insertions, 4 deletions
diff --git a/fs/exec.c b/fs/exec.c
index 72934df6847150..904199086490d5 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -220,8 +220,26 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
if (write) {
unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start;
+ unsigned long ptr_size;
struct rlimit *rlim;
+ /*
+ * Since the stack will hold pointers to the strings, we
+ * must account for them as well.
+ *
+ * The size calculation is the entire vma while each arg page is
+ * built, so each time we get here it's calculating how far it
+ * is currently (rather than each call being just the newly
+ * added size from the arg page). As a result, we need to
+ * always add the entire size of the pointers, so that on the
+ * last call to get_arg_page() we'll actually have the entire
+ * correct size.
+ */
+ ptr_size = (bprm->argc + bprm->envc) * sizeof(void *);
+ if (ptr_size > ULONG_MAX - size)
+ goto fail;
+ size += ptr_size;
+
acct_arg_size(bprm, size / PAGE_SIZE);
/*
@@ -239,13 +257,15 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
* to work from.
*/
rlim = current->signal->rlim;
- if (size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur) / 4) {
- put_page(page);
- return NULL;
- }
+ if (size > READ_ONCE(rlim[RLIMIT_STACK].rlim_cur) / 4)
+ goto fail;
}
return page;
+
+fail:
+ put_page(page);
+ return NULL;
}
static void put_arg_page(struct page *page)