diff mbox

[net,v4] ovs: limit ovs recursions in ovs_execute_actions to not corrupt stack

Message ID 1452876675-19834-1-git-send-email-hannes@stressinduktion.org
State Changes Requested, archived
Delegated to: David Miller
Headers show

Commit Message

Hannes Frederic Sowa Jan. 15, 2016, 4:51 p.m. UTC
It was seen that defective configurations of openvswitch could overwrite
the STACK_END_MAGIC and cause a hard crash of the kernel because of too
many recursions within ovs.

This problem arises due to the high stack usage of openvswitch. The rest
of the kernel is fine with the current limit of 10 (RECURSION_LIMIT).

We use the already existing recursion counter in ovs_execute_actions to
implement an upper bound of 5 recursions.

Cc: Pravin Shelar <pshelar@ovn.org>
Cc: Simon Horman <simon.horman@netronome.com>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Reviewed-by: Simon Horman <simon.horman@netronome.com>
---
v2) added preemption guards
v3) Pravin suggested to reuse the ovs_execute_actions counter which this
    patch does. Also only allow 5 recursions as suggested by Pravin.
v4) added unlikely as suggested by Eric

Thanks to all reviewers!

 net/openvswitch/actions.c | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

Comments

Pravin Shelar Jan. 16, 2016, 5:04 p.m. UTC | #1
On Fri, Jan 15, 2016 at 8:51 AM, Hannes Frederic Sowa
<hannes@stressinduktion.org> wrote:
> It was seen that defective configurations of openvswitch could overwrite
> the STACK_END_MAGIC and cause a hard crash of the kernel because of too
> many recursions within ovs.
>
> This problem arises due to the high stack usage of openvswitch. The rest
> of the kernel is fine with the current limit of 10 (RECURSION_LIMIT).
>
> We use the already existing recursion counter in ovs_execute_actions to
> implement an upper bound of 5 recursions.
>
> Cc: Pravin Shelar <pshelar@ovn.org>
> Cc: Simon Horman <simon.horman@netronome.com>
> Cc: Eric Dumazet <eric.dumazet@gmail.com>
> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
> Reviewed-by: Simon Horman <simon.horman@netronome.com>
> ---
> v2) added preemption guards
> v3) Pravin suggested to reuse the ovs_execute_actions counter which this
>     patch does. Also only allow 5 recursions as suggested by Pravin.
> v4) added unlikely as suggested by Eric
>
> Thanks to all reviewers!
>
>  net/openvswitch/actions.c | 21 ++++++++++++++++-----
>  1 file changed, 16 insertions(+), 5 deletions(-)
>
> diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
> index c88d0f2d3e019b..da66f9e1660dbb 100644
> --- a/net/openvswitch/actions.c
> +++ b/net/openvswitch/actions.c
> @@ -1160,17 +1160,28 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb,
>                         const struct sw_flow_actions *acts,
>                         struct sw_flow_key *key)
>  {
> -       int level = this_cpu_read(exec_actions_level);
> -       int err;
> +       static const int ovs_recursion_limit = 5;
> +       int err, level;
> +
> +       preempt_disable();

This function always run in soft-irq context. Do we really need this
preempt-disable call here?
David Miller Jan. 18, 2016, 12:26 a.m. UTC | #2
From: pravin shelar <pshelar@ovn.org>
Date: Sat, 16 Jan 2016 09:04:50 -0800

> This function always run in soft-irq context. Do we really need this
> preempt-disable call here?

Hannes, please respond to this feedback.

Thanks.
Hannes Frederic Sowa Jan. 18, 2016, 11:21 a.m. UTC | #3
On 18.01.2016 01:26, David Miller wrote:
> From: pravin shelar <pshelar@ovn.org>
> Date: Sat, 16 Jan 2016 09:04:50 -0800
>
>> This function always run in soft-irq context. Do we really need this
>> preempt-disable call here?
>
> Hannes, please respond to this feedback.

Sorry, was traveling on the weekend.

Pravin, I added preempt protection because of the discussion about this 
patch: <http://www.spinics.net/lists/linux-rt-users/msg14343.html>

I didn't want to add a recursion limiter into struct task_struct for 
ovs, so I disable preemption here. On non-rt kernels this will have no 
change in behavior (besides the accesses to the preempt counter), but it 
does the right thing on -rt kernels.

I don't think that -rt kernels are important for openvswitch right now, 
so this is just a safe guard.

Bye,
Hannes
David Miller Jan. 18, 2016, 4:50 p.m. UTC | #4
From: Hannes Frederic Sowa <hannes@stressinduktion.org>
Date: Mon, 18 Jan 2016 12:21:16 +0100

> I don't think that -rt kernels are important for openvswitch right
> now, so this is just a safe guard.

Hannes, whilst I don't want to explicitly make things harder for the -rt
folks, I don't think it's appropriate to put unnecessary preemtption
disables into the main kernel like this.

Someone reading the code as-is will say this is superfluous and (correctly)
submit a patch to remove the preemption disables.

Please remove this from your patch, someone can deal with this in the
-rt kernel as needed.
Hannes Frederic Sowa Jan. 18, 2016, 4:58 p.m. UTC | #5
On 18.01.2016 17:50, David Miller wrote:
> From: Hannes Frederic Sowa <hannes@stressinduktion.org>
> Date: Mon, 18 Jan 2016 12:21:16 +0100
>
>> I don't think that -rt kernels are important for openvswitch right
>> now, so this is just a safe guard.
>
> Hannes, whilst I don't want to explicitly make things harder for the -rt
> folks, I don't think it's appropriate to put unnecessary preemtption
> disables into the main kernel like this.
>
> Someone reading the code as-is will say this is superfluous and (correctly)
> submit a patch to remove the preemption disables.
>
> Please remove this from your patch, someone can deal with this in the
> -rt kernel as needed.

I am fine with that. Actually I had the same feeling, but seeing such a 
patch being discussed and explicitly ignoring this issue in another part 
made me feel a little bit bad.

Will resend in some seconds.

Bye,
Hannes
diff mbox

Patch

diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index c88d0f2d3e019b..da66f9e1660dbb 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -1160,17 +1160,28 @@  int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb,
 			const struct sw_flow_actions *acts,
 			struct sw_flow_key *key)
 {
-	int level = this_cpu_read(exec_actions_level);
-	int err;
+	static const int ovs_recursion_limit = 5;
+	int err, level;
+
+	preempt_disable();
+	level = __this_cpu_inc_return(exec_actions_level);
+	if (unlikely(level > ovs_recursion_limit)) {
+		net_crit_ratelimited("ovs: recursion limit reached on datapath %s, probable configuration error\n",
+				     ovs_dp_name(dp));
+		kfree_skb(skb);
+		err = -ENETDOWN;
+		goto out;
+	}
 
-	this_cpu_inc(exec_actions_level);
 	err = do_execute_actions(dp, skb, key,
 				 acts->actions, acts->actions_len);
 
-	if (!level)
+	if (level == 1)
 		process_deferred_actions(dp);
 
-	this_cpu_dec(exec_actions_level);
+out:
+	__this_cpu_dec(exec_actions_level);
+	preempt_enable();
 	return err;
 }