From: Michal Hocko <mhocko@kernel.org>
To: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>, Hugh Dickins <hughd@google.com>,
Andrew Morton <akpm@linux-foundation.org>,
Larry Woodman <lwoodman@redhat.com>,
Linux Kernel Mailing List <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH 0/1] expand_downwards: don't require the gap if !vm_prev
Date: Mon, 3 Jul 2017 17:49:25 +0200 [thread overview]
Message-ID: <20170703154925.GD11848@dhcp22.suse.cz> (raw)
In-Reply-To: <CA+55aFwaOBdp-ETuLxh=uxTjjGB5VKAh3ST=O0Se8R5NMumCwA@mail.gmail.com>
On Fri 30-06-17 10:48:15, Linus Torvalds wrote:
> On Fri, Jun 30, 2017 at 10:26 AM, Michal Hocko <mhocko@kernel.org> wrote:
> >
> > Ohh, you misunderstood I guess. They wanted that only for internal
> > testing (e.g. make sure that everything that matters blows up if it is
> > doing something wrong). Absolutely nothing to base any compilator
> > decistion on.
>
> Oh, good.
>
> If that's the case, I really think we should try to add some code that
> checks that the stack grows strictly one page at a time, and have a
> way to enable SIGSEGV if that is ever not the case.
>
> That should be trivial to add in expand_downwards/expand_upwards.
yes, but I would be worried to have this hardcoded. People very often do
run 3rd party code compiled with a non-default distribution compiler. I
also expect there are sensible usecases where probing on the stack could
lead to a performance degradation so people might want to explicitely
disable it.
> We could make a "warn once" thing unconditional for distro testing,
> but since compiler people would presumably want to test this before
> the rest of the distro is clean, they'd need some rlimit or something
> like that to enable it for particular processes.
yes, WARN_ONCE is not very practical to identify offenders..
> Would that be ok for them?
>
> Some prctl to get/set that "max I'm allowed to extend the stack"?
prctl would be less code than proc interface I've had and quite
straightforward as well. Below is what I have ended up with for them. I
doesn't warn by default because I thought it would be too noisy without
stack probing used more widely.
If you think this is worth pursuing in upstream, just let me know and I
can polish it, add a patch for the man page and other things.
---
diff --git a/fs/exec.c b/fs/exec.c
index 904199086490..7589fb701fca 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -320,6 +320,13 @@ static int __bprm_mm_init(struct linux_binprm *bprm)
arch_bprm_mm_init(mm, vma);
up_write(&mm->mmap_sem);
bprm->p = vma->vm_end - sizeof(void *);
+
+ /*
+ * We cannot set the stack expand limit now because we will do manual
+ * stack expansions which might be larger. See setup_arg_pages
+ */
+ if (current->mm)
+ bprm->expand_stack_limit = current->mm->expand_stack_limit;
return 0;
err:
up_write(&mm->mmap_sem);
@@ -786,6 +793,14 @@ int setup_arg_pages(struct linux_binprm *bprm,
if (ret)
ret = -EFAULT;
+ /*
+ * Stack is finilized now and so all later expansions have
+ * to comply with the inherited limit.
+ *
+ * TODO: Do we want to allow non-privileged task to set
+ * the limit for privileged ones?
+ */
+ vma->vm_mm->expand_stack_limit = bprm->expand_stack_limit;
out_unlock:
up_write(&mm->mmap_sem);
return ret;
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index 05488da3aee9..2d3d7fff4811 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -17,6 +17,7 @@ struct linux_binprm {
char buf[BINPRM_BUF_SIZE];
#ifdef CONFIG_MMU
struct vm_area_struct *vma;
+ unsigned long expand_stack_limit;
unsigned long vma_pages;
#else
# define MAX_ARG_PAGES 32
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 45cdb27791a3..24ee38a45a9e 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -425,6 +425,7 @@ struct mm_struct {
unsigned long start_brk, brk, start_stack;
unsigned long arg_start, arg_end, env_start, env_end;
+ unsigned long expand_stack_limit; /* how much we can grow stack at once */
unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */
/*
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index a8d0759a9e40..6f3c65530c71 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -197,4 +197,7 @@ struct prctl_mm_map {
# define PR_CAP_AMBIENT_LOWER 3
# define PR_CAP_AMBIENT_CLEAR_ALL 4
+#define PR_SET_STACK_EXPAND_LIMIT 48
+#define PR_GET_STACK_EXPAND_LIMIT 49
+
#endif /* _LINUX_PRCTL_H */
diff --git a/kernel/sys.c b/kernel/sys.c
index 4111d584ff4a..05bdcdeda98f 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -2290,6 +2290,17 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
case PR_GET_FP_MODE:
error = GET_FP_MODE(me);
break;
+ case PR_SET_STACK_EXPAND_LIMIT:
+ if (arg3 || arg4 || arg5)
+ return -EINVAL;
+ if (down_write_killable(&me->mm->mmap_sem))
+ return -EINTR;
+ me->mm->expand_stack_limit = arg2;
+ up_write(&me->mm->mmap_sem);
+ break;
+ case PR_GET_STACK_EXPAND_LIMIT:
+ error = me->mm->expand_stack_limit;
+ break;
default:
error = -EINVAL;
break;
diff --git a/mm/mmap.c b/mm/mmap.c
index 5a0ba9788cdd..ff2a5981ee92 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2266,7 +2266,16 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
unsigned long size, grow;
size = address - vma->vm_start;
- grow = (address - vma->vm_end) >> PAGE_SHIFT;
+ grow = address - vma->vm_end;
+
+ if (mm->expand_stack_limit && grow > mm->expand_stack_limit) {
+ pr_warn("%s[%d]: disallowed stack expansion %lu with limit %lu\n",
+ current->comm, task_pid_nr(current),
+ grow, mm->expand_stack_limit);
+ anon_vma_unlock_write(vma->anon_vma);
+ return -ENOMEM;
+ }
+ grow >>= PAGE_SHIFT;
error = -ENOMEM;
if (vma->vm_pgoff + (size >> PAGE_SHIFT) >= vma->vm_pgoff) {
@@ -2350,7 +2359,20 @@ int expand_downwards(struct vm_area_struct *vma,
unsigned long size, grow;
size = vma->vm_end - address;
- grow = (vma->vm_start - address) >> PAGE_SHIFT;
+ grow = vma->vm_start - address;
+
+ /*
+ * Make sure that a single stack expansion doesn't exceed the
+ * configured limit.
+ */
+ if (mm->expand_stack_limit && grow > mm->expand_stack_limit) {
+ pr_warn("%s[%d]: disallowed stack expansion %lu with limit %lu\n",
+ current->comm, task_pid_nr(current),
+ grow, mm->expand_stack_limit);
+ anon_vma_unlock_write(vma->anon_vma);
+ return -ENOMEM;
+ }
+ grow >>= PAGE_SHIFT;
error = -ENOMEM;
if (grow <= vma->vm_pgoff) {
--
Michal Hocko
SUSE Labs
next prev parent reply other threads:[~2017-07-03 15:49 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-06-28 17:52 Oleg Nesterov
2017-06-28 17:52 ` [PATCH 1/1] " Oleg Nesterov
2017-06-30 13:16 ` Michal Hocko
2017-06-28 23:26 ` [PATCH 0/1] " Linus Torvalds
2017-06-29 15:19 ` Oleg Nesterov
2017-06-29 18:21 ` Linus Torvalds
2017-06-29 18:55 ` Oleg Nesterov
2017-06-29 19:00 ` Linus Torvalds
2017-06-30 13:24 ` Michal Hocko
2017-06-30 17:08 ` Linus Torvalds
2017-06-30 17:26 ` Michal Hocko
2017-06-30 17:48 ` Linus Torvalds
2017-07-03 15:49 ` Michal Hocko [this message]
2017-07-03 16:30 ` Linus Torvalds
2017-07-03 16:54 ` Michal Hocko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170703154925.GD11848@dhcp22.suse.cz \
--to=mhocko@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=hughd@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lwoodman@redhat.com \
--cc=oleg@redhat.com \
--cc=torvalds@linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®