diff mbox

[Zesty,v2,0/2] net sched actions: allocate act cookie early

Message ID 1493043999-19860-3-git-send-email-f.gruenbichler@proxmox.com
State New
Headers show

Commit Message

Fabian Grünbichler April 24, 2017, 2:26 p.m. UTC
From: Wolfgang Bumiller <w.bumiller@proxmox.com>

https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1682368

Policing filters do not use the TCA_ACT_* enum and the tb[]
nlattr array in tcf_action_init_1() doesn't get filled for
them so we should not try to look for a TCA_ACT_COOKIE
attribute in the then uninitialized array.
The error handling in cookie allocation then calls
tcf_hash_release() leading to invalid memory access later
on.
Additionally, if cookie allocation fails after an already
existing non-policing filter has successfully been changed,
tcf_action_release() should not be called, also we would
have to roll back the changes in the error handling, so
instead we now allocate the cookie early and assign it on
success at the end.

CVE-2017-7979
Fixes: 1045ba77a596 ("net sched actions: Add support for user cookies")
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit e0535ce58b92d7baf0b33284a6c4f8f0338f943e)
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
---
 net/sched/act_api.c | 55 +++++++++++++++++++++++++++++++----------------------
 1 file changed, 32 insertions(+), 23 deletions(-)

Comments

Fabian Grünbichler April 24, 2017, 2:29 p.m. UTC | #1
that should have been [PATCH 2/2] in the subject, sorry for the
confusion.

On Mon, Apr 24, 2017 at 04:26:39PM +0200, Fabian Grünbichler wrote:
> From: Wolfgang Bumiller <w.bumiller@proxmox.com>
> 
> https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1682368
> 
> Policing filters do not use the TCA_ACT_* enum and the tb[]
> nlattr array in tcf_action_init_1() doesn't get filled for
> them so we should not try to look for a TCA_ACT_COOKIE
> attribute in the then uninitialized array.
> The error handling in cookie allocation then calls
> tcf_hash_release() leading to invalid memory access later
> on.
> Additionally, if cookie allocation fails after an already
> existing non-policing filter has successfully been changed,
> tcf_action_release() should not be called, also we would
> have to roll back the changes in the error handling, so
> instead we now allocate the cookie early and assign it on
> success at the end.
> 
> CVE-2017-7979
> Fixes: 1045ba77a596 ("net sched actions: Add support for user cookies")
> Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
> Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
> Signed-off-by: David S. Miller <davem@davemloft.net>
> (cherry picked from commit e0535ce58b92d7baf0b33284a6c4f8f0338f943e)
> Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
> ---
>  net/sched/act_api.c | 55 +++++++++++++++++++++++++++++++----------------------
>  1 file changed, 32 insertions(+), 23 deletions(-)
> 
> diff --git a/net/sched/act_api.c b/net/sched/act_api.c
> index e336f30..bdbc7a9 100644
> --- a/net/sched/act_api.c
> +++ b/net/sched/act_api.c
> @@ -532,20 +532,20 @@ int tcf_action_dump(struct sk_buff *skb, struct list_head *actions,
>  	return err;
>  }
>  
> -static int nla_memdup_cookie(struct tc_action *a, struct nlattr **tb)
> +static struct tc_cookie *nla_memdup_cookie(struct nlattr **tb)
>  {
> -	a->act_cookie = kzalloc(sizeof(*a->act_cookie), GFP_KERNEL);
> -	if (!a->act_cookie)
> -		return -ENOMEM;
> +	struct tc_cookie *c = kzalloc(sizeof(*c), GFP_KERNEL);
> +	if (!c)
> +		return NULL;
>  
> -	a->act_cookie->data = nla_memdup(tb[TCA_ACT_COOKIE], GFP_KERNEL);
> -	if (!a->act_cookie->data) {
> -		kfree(a->act_cookie);
> -		return -ENOMEM;
> +	c->data = nla_memdup(tb[TCA_ACT_COOKIE], GFP_KERNEL);
> +	if (!c->data) {
> +		kfree(c);
> +		return NULL;
>  	}
> -	a->act_cookie->len = nla_len(tb[TCA_ACT_COOKIE]);
> +	c->len = nla_len(tb[TCA_ACT_COOKIE]);
>  
> -	return 0;
> +	return c;
>  }
>  
>  struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
> @@ -554,6 +554,7 @@ struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
>  {
>  	struct tc_action *a;
>  	struct tc_action_ops *a_o;
> +	struct tc_cookie *cookie = NULL;
>  	char act_name[IFNAMSIZ];
>  	struct nlattr *tb[TCA_ACT_MAX + 1];
>  	struct nlattr *kind;
> @@ -569,6 +570,18 @@ struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
>  			goto err_out;
>  		if (nla_strlcpy(act_name, kind, IFNAMSIZ) >= IFNAMSIZ)
>  			goto err_out;
> +		if (tb[TCA_ACT_COOKIE]) {
> +			int cklen = nla_len(tb[TCA_ACT_COOKIE]);
> +
> +			if (cklen > TC_COOKIE_MAX_SIZE)
> +				goto err_out;
> +
> +			cookie = nla_memdup_cookie(tb);
> +			if (!cookie) {
> +				err = -ENOMEM;
> +				goto err_out;
> +			}
> +		}
>  	} else {
>  		err = -EINVAL;
>  		if (strlcpy(act_name, name, IFNAMSIZ) >= IFNAMSIZ)
> @@ -607,20 +620,12 @@ struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
>  	if (err < 0)
>  		goto err_mod;
>  
> -	if (tb[TCA_ACT_COOKIE]) {
> -		int cklen = nla_len(tb[TCA_ACT_COOKIE]);
> -
> -		if (cklen > TC_COOKIE_MAX_SIZE) {
> -			err = -EINVAL;
> -			tcf_hash_release(a, bind);
> -			goto err_mod;
> -		}
> -
> -		if (nla_memdup_cookie(a, tb) < 0) {
> -			err = -ENOMEM;
> -			tcf_hash_release(a, bind);
> -			goto err_mod;
> +	if (name == NULL && tb[TCA_ACT_COOKIE]) {
> +		if (a->act_cookie) {
> +			kfree(a->act_cookie->data);
> +			kfree(a->act_cookie);
>  		}
> +		a->act_cookie = cookie;
>  	}
>  
>  	/* module count goes up only when brand new policy is created
> @@ -635,6 +640,10 @@ struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
>  err_mod:
>  	module_put(a_o->owner);
>  err_out:
> +	if (cookie) {
> +		kfree(cookie->data);
> +		kfree(cookie);
> +	}
>  	return ERR_PTR(err);
>  }
>  
> -- 
> 2.1.4
> 
> 
> 
> -- 
> kernel-team mailing list
> kernel-team@lists.ubuntu.com
> https://lists.ubuntu.com/mailman/listinfo/kernel-team
diff mbox

Patch

diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index e336f30..bdbc7a9 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -532,20 +532,20 @@  int tcf_action_dump(struct sk_buff *skb, struct list_head *actions,
 	return err;
 }
 
-static int nla_memdup_cookie(struct tc_action *a, struct nlattr **tb)
+static struct tc_cookie *nla_memdup_cookie(struct nlattr **tb)
 {
-	a->act_cookie = kzalloc(sizeof(*a->act_cookie), GFP_KERNEL);
-	if (!a->act_cookie)
-		return -ENOMEM;
+	struct tc_cookie *c = kzalloc(sizeof(*c), GFP_KERNEL);
+	if (!c)
+		return NULL;
 
-	a->act_cookie->data = nla_memdup(tb[TCA_ACT_COOKIE], GFP_KERNEL);
-	if (!a->act_cookie->data) {
-		kfree(a->act_cookie);
-		return -ENOMEM;
+	c->data = nla_memdup(tb[TCA_ACT_COOKIE], GFP_KERNEL);
+	if (!c->data) {
+		kfree(c);
+		return NULL;
 	}
-	a->act_cookie->len = nla_len(tb[TCA_ACT_COOKIE]);
+	c->len = nla_len(tb[TCA_ACT_COOKIE]);
 
-	return 0;
+	return c;
 }
 
 struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
@@ -554,6 +554,7 @@  struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
 {
 	struct tc_action *a;
 	struct tc_action_ops *a_o;
+	struct tc_cookie *cookie = NULL;
 	char act_name[IFNAMSIZ];
 	struct nlattr *tb[TCA_ACT_MAX + 1];
 	struct nlattr *kind;
@@ -569,6 +570,18 @@  struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
 			goto err_out;
 		if (nla_strlcpy(act_name, kind, IFNAMSIZ) >= IFNAMSIZ)
 			goto err_out;
+		if (tb[TCA_ACT_COOKIE]) {
+			int cklen = nla_len(tb[TCA_ACT_COOKIE]);
+
+			if (cklen > TC_COOKIE_MAX_SIZE)
+				goto err_out;
+
+			cookie = nla_memdup_cookie(tb);
+			if (!cookie) {
+				err = -ENOMEM;
+				goto err_out;
+			}
+		}
 	} else {
 		err = -EINVAL;
 		if (strlcpy(act_name, name, IFNAMSIZ) >= IFNAMSIZ)
@@ -607,20 +620,12 @@  struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
 	if (err < 0)
 		goto err_mod;
 
-	if (tb[TCA_ACT_COOKIE]) {
-		int cklen = nla_len(tb[TCA_ACT_COOKIE]);
-
-		if (cklen > TC_COOKIE_MAX_SIZE) {
-			err = -EINVAL;
-			tcf_hash_release(a, bind);
-			goto err_mod;
-		}
-
-		if (nla_memdup_cookie(a, tb) < 0) {
-			err = -ENOMEM;
-			tcf_hash_release(a, bind);
-			goto err_mod;
+	if (name == NULL && tb[TCA_ACT_COOKIE]) {
+		if (a->act_cookie) {
+			kfree(a->act_cookie->data);
+			kfree(a->act_cookie);
 		}
+		a->act_cookie = cookie;
 	}
 
 	/* module count goes up only when brand new policy is created
@@ -635,6 +640,10 @@  struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
 err_mod:
 	module_put(a_o->owner);
 err_out:
+	if (cookie) {
+		kfree(cookie->data);
+		kfree(cookie);
+	}
 	return ERR_PTR(err);
 }