diff options
Diffstat (limited to 'net/xfrm/xfrm_user.c')
| -rw-r--r-- | net/xfrm/xfrm_user.c | 15 | 
1 files changed, 10 insertions, 5 deletions
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index d720e163ae6e..c34a2a06ca94 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1770,7 +1770,7 @@ static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut,  }  static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family, -			 struct netlink_ext_ack *extack) +			 int dir, struct netlink_ext_ack *extack)  {  	u16 prev_family;  	int i; @@ -1796,6 +1796,10 @@ static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family,  		switch (ut[i].mode) {  		case XFRM_MODE_TUNNEL:  		case XFRM_MODE_BEET: +			if (ut[i].optional && dir == XFRM_POLICY_OUT) { +				NL_SET_ERR_MSG(extack, "Mode in optional template not allowed in outbound policy"); +				return -EINVAL; +			}  			break;  		default:  			if (ut[i].family != prev_family) { @@ -1833,7 +1837,7 @@ static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family,  }  static int copy_from_user_tmpl(struct xfrm_policy *pol, struct nlattr **attrs, -			       struct netlink_ext_ack *extack) +			       int dir, struct netlink_ext_ack *extack)  {  	struct nlattr *rt = attrs[XFRMA_TMPL]; @@ -1844,7 +1848,7 @@ static int copy_from_user_tmpl(struct xfrm_policy *pol, struct nlattr **attrs,  		int nr = nla_len(rt) / sizeof(*utmpl);  		int err; -		err = validate_tmpl(nr, utmpl, pol->family, extack); +		err = validate_tmpl(nr, utmpl, pol->family, dir, extack);  		if (err)  			return err; @@ -1921,7 +1925,7 @@ static struct xfrm_policy *xfrm_policy_construct(struct net *net,  	if (err)  		goto error; -	if (!(err = copy_from_user_tmpl(xp, attrs, extack))) +	if (!(err = copy_from_user_tmpl(xp, attrs, p->dir, extack)))  		err = copy_from_user_sec_ctx(xp, attrs);  	if (err)  		goto error; @@ -1980,6 +1984,7 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh,  	if (err) {  		xfrm_dev_policy_delete(xp); +		xfrm_dev_policy_free(xp);  		security_xfrm_policy_free(xp->security);  		kfree(xp);  		return err; @@ -3499,7 +3504,7 @@ static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt,  		return NULL;  	nr = ((len - sizeof(*p)) / sizeof(*ut)); -	if (validate_tmpl(nr, ut, p->sel.family, NULL)) +	if (validate_tmpl(nr, ut, p->sel.family, p->dir, NULL))  		return NULL;  	if (p->dir > XFRM_POLICY_OUT)  | 
