diff options
Diffstat (limited to 'net/xfrm/xfrm_user.c')
| -rw-r--r-- | net/xfrm/xfrm_user.c | 57 | 
1 files changed, 42 insertions, 15 deletions
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index e75d8e47f35..289f4bf18ff 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -123,9 +123,21 @@ static inline int verify_replay(struct xfrm_usersa_info *p,  				struct nlattr **attrs)  {  	struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL]; +	struct xfrm_replay_state_esn *rs; -	if ((p->flags & XFRM_STATE_ESN) && !rt) -		return -EINVAL; +	if (p->flags & XFRM_STATE_ESN) { +		if (!rt) +			return -EINVAL; + +		rs = nla_data(rt); + +		if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8) +			return -EINVAL; + +		if (nla_len(rt) < xfrm_replay_state_esn_len(rs) && +		    nla_len(rt) != sizeof(*rs)) +			return -EINVAL; +	}  	if (!rt)  		return 0; @@ -370,14 +382,15 @@ static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_es  					 struct nlattr *rp)  {  	struct xfrm_replay_state_esn *up; +	int ulen;  	if (!replay_esn || !rp)  		return 0;  	up = nla_data(rp); +	ulen = xfrm_replay_state_esn_len(up); -	if (xfrm_replay_state_esn_len(replay_esn) != -			xfrm_replay_state_esn_len(up)) +	if (nla_len(rp) < ulen || xfrm_replay_state_esn_len(replay_esn) != ulen)  		return -EINVAL;  	return 0; @@ -388,22 +401,28 @@ static int xfrm_alloc_replay_state_esn(struct xfrm_replay_state_esn **replay_esn  				       struct nlattr *rta)  {  	struct xfrm_replay_state_esn *p, *pp, *up; +	int klen, ulen;  	if (!rta)  		return 0;  	up = nla_data(rta); +	klen = xfrm_replay_state_esn_len(up); +	ulen = nla_len(rta) >= klen ? klen : sizeof(*up); -	p = kmemdup(up, xfrm_replay_state_esn_len(up), GFP_KERNEL); +	p = kzalloc(klen, GFP_KERNEL);  	if (!p)  		return -ENOMEM; -	pp = kmemdup(up, xfrm_replay_state_esn_len(up), GFP_KERNEL); +	pp = kzalloc(klen, GFP_KERNEL);  	if (!pp) {  		kfree(p);  		return -ENOMEM;  	} +	memcpy(p, up, ulen); +	memcpy(pp, up, ulen); +  	*replay_esn = p;  	*preplay_esn = pp; @@ -442,10 +461,11 @@ static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *   * somehow made shareable and move it to xfrm_state.c - JHS   *  */ -static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs) +static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs, +				  int update_esn)  {  	struct nlattr *rp = attrs[XFRMA_REPLAY_VAL]; -	struct nlattr *re = attrs[XFRMA_REPLAY_ESN_VAL]; +	struct nlattr *re = update_esn ? attrs[XFRMA_REPLAY_ESN_VAL] : NULL;  	struct nlattr *lt = attrs[XFRMA_LTIME_VAL];  	struct nlattr *et = attrs[XFRMA_ETIMER_THRESH];  	struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH]; @@ -555,7 +575,7 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,  		goto error;  	/* override default values from above */ -	xfrm_update_ae_params(x, attrs); +	xfrm_update_ae_params(x, attrs, 0);  	return x; @@ -689,6 +709,7 @@ out:  static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)  { +	memset(p, 0, sizeof(*p));  	memcpy(&p->id, &x->id, sizeof(p->id));  	memcpy(&p->sel, &x->sel, sizeof(p->sel));  	memcpy(&p->lft, &x->lft, sizeof(p->lft)); @@ -742,7 +763,7 @@ static int copy_to_user_auth(struct xfrm_algo_auth *auth, struct sk_buff *skb)  		return -EMSGSIZE;  	algo = nla_data(nla); -	strcpy(algo->alg_name, auth->alg_name); +	strncpy(algo->alg_name, auth->alg_name, sizeof(algo->alg_name));  	memcpy(algo->alg_key, auth->alg_key, (auth->alg_key_len + 7) / 8);  	algo->alg_key_len = auth->alg_key_len; @@ -878,6 +899,7 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb,  {  	struct xfrm_dump_info info;  	struct sk_buff *skb; +	int err;  	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);  	if (!skb) @@ -888,9 +910,10 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb,  	info.nlmsg_seq = seq;  	info.nlmsg_flags = 0; -	if (dump_one_state(x, 0, &info)) { +	err = dump_one_state(x, 0, &info); +	if (err) {  		kfree_skb(skb); -		return NULL; +		return ERR_PTR(err);  	}  	return skb; @@ -1317,6 +1340,7 @@ static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy  static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p, int dir)  { +	memset(p, 0, sizeof(*p));  	memcpy(&p->sel, &xp->selector, sizeof(p->sel));  	memcpy(&p->lft, &xp->lft, sizeof(p->lft));  	memcpy(&p->curlft, &xp->curlft, sizeof(p->curlft)); @@ -1421,6 +1445,7 @@ static int copy_to_user_tmpl(struct xfrm_policy *xp, struct sk_buff *skb)  		struct xfrm_user_tmpl *up = &vec[i];  		struct xfrm_tmpl *kp = &xp->xfrm_vec[i]; +		memset(up, 0, sizeof(*up));  		memcpy(&up->id, &kp->id, sizeof(up->id));  		up->family = kp->encap_family;  		memcpy(&up->saddr, &kp->saddr, sizeof(up->saddr)); @@ -1546,6 +1571,7 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb,  {  	struct xfrm_dump_info info;  	struct sk_buff *skb; +	int err;  	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);  	if (!skb) @@ -1556,9 +1582,10 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb,  	info.nlmsg_seq = seq;  	info.nlmsg_flags = 0; -	if (dump_one_policy(xp, dir, 0, &info) < 0) { +	err = dump_one_policy(xp, dir, 0, &info); +	if (err) {  		kfree_skb(skb); -		return NULL; +		return ERR_PTR(err);  	}  	return skb; @@ -1822,7 +1849,7 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,  		goto out;  	spin_lock_bh(&x->lock); -	xfrm_update_ae_params(x, attrs); +	xfrm_update_ae_params(x, attrs, 1);  	spin_unlock_bh(&x->lock);  	c.event = nlh->nlmsg_type;  |