lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Fri, 24 May 2019 09:23:04 -0700
From:   Stephen Hemminger <stephen@...workplumber.org>
To:     John Hurley <john.hurley@...ronome.com>
Cc:     netdev@...r.kernel.org, jiri@...lanox.com, davem@...emloft.net,
        xiyou.wangcong@...il.com, simon.horman@...ronome.com,
        jakub.kicinski@...ronome.com, oss-drivers@...ronome.com
Subject: Re: [RFC net-next 1/1] net: sched: protect against loops in TC
 filter hooks

On Fri, 24 May 2019 17:05:46 +0100
John Hurley <john.hurley@...ronome.com> wrote:

> TC hooks allow the application of filters and actions to packets at both
> ingress and egress of the network stack. It is possible, with poor
> configuration, that this can produce loops whereby an ingress hook calls
> a mirred egress action that has an egress hook that redirects back to
> the first ingress etc. The TC core classifier protects against loops when
> doing reclassifies but, as yet, there is no protection against a packet
> looping between multiple hooks. This can lead to stack overflow panics.
> 
> Add a per cpu counter that tracks recursion of packets through TC hooks.
> The packet will be dropped if a recursive limit is passed and the counter
> reset for the next packet.
> 
> Signed-off-by: John Hurley <john.hurley@...ronome.com>
> Reviewed-by: Simon Horman <simon.horman@...ronome.com>
> ---
>  net/core/dev.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
>  1 file changed, 55 insertions(+), 7 deletions(-)
> 
> diff --git a/net/core/dev.c b/net/core/dev.c
> index b6b8505..a6d9ed7 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -154,6 +154,9 @@
>  /* This should be increased if a protocol with a bigger head is added. */
>  #define GRO_MAX_HEAD (MAX_HEADER + 128)
>  
> +#define SCH_RECURSION_LIMIT	4
> +static DEFINE_PER_CPU(int, sch_recursion_level);

Maybe use unsigned instead of int?

> +
>  static DEFINE_SPINLOCK(ptype_lock);
>  static DEFINE_SPINLOCK(offload_lock);
>  struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;
> @@ -3598,16 +3601,42 @@ int dev_loopback_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)
>  }
>  EXPORT_SYMBOL(dev_loopback_xmit);
>  
> +static inline int sch_check_inc_recur_level(void)
> +{
> +	int rec_level = __this_cpu_inc_return(sch_recursion_level);
> +
> +	if (rec_level >= SCH_RECURSION_LIMIT) {
unlikely here?

> +		net_warn_ratelimited("Recursion limit reached on TC datapath, probable configuration error\n");

It would be good to know which device this was on.

> +		return -ELOOP;
> +	}
> +
> +	return 0;
> +}
> +
> +static inline void sch_dec_recur_level(void)
> +{
> +	__this_cpu_dec(sch_recursion_level);

Decrement of past 0 is an error that should be trapped and logged.

> +}
> +
>  #ifdef CONFIG_NET_EGRESS
>  static struct sk_buff *
>  sch_handle_egress(struct sk_buff *skb, int *ret, struct net_device *dev)
>  {
>  	struct mini_Qdisc *miniq = rcu_dereference_bh(dev->miniq_egress);
>  	struct tcf_result cl_res;
> +	int err;
>  
>  	if (!miniq)
>  		return skb;
>  
> +	err = sch_check_inc_recur_level();
> +	if (err) {
> +		sch_dec_recur_level();

You should have sch_check_inc_recur_level do the unwind on error.
That would simplify the error paths.

> +		*ret = NET_XMIT_DROP;
> +		consume_skb(skb);
> +		return NULL;
> +	}
> +

Powered by blists - more mailing lists