aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_user.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm/xfrm_user.c')
-rw-r--r--net/xfrm/xfrm_user.c147
1 files changed, 131 insertions, 16 deletions
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index b95a2d64eb59..1ada6186933c 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -62,6 +62,22 @@ static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
62 return 0; 62 return 0;
63} 63}
64 64
65static int verify_auth_trunc(struct nlattr **attrs)
66{
67 struct nlattr *rt = attrs[XFRMA_ALG_AUTH_TRUNC];
68 struct xfrm_algo_auth *algp;
69
70 if (!rt)
71 return 0;
72
73 algp = nla_data(rt);
74 if (nla_len(rt) < xfrm_alg_auth_len(algp))
75 return -EINVAL;
76
77 algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0';
78 return 0;
79}
80
65static int verify_aead(struct nlattr **attrs) 81static int verify_aead(struct nlattr **attrs)
66{ 82{
67 struct nlattr *rt = attrs[XFRMA_ALG_AEAD]; 83 struct nlattr *rt = attrs[XFRMA_ALG_AEAD];
@@ -128,7 +144,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
128 err = -EINVAL; 144 err = -EINVAL;
129 switch (p->id.proto) { 145 switch (p->id.proto) {
130 case IPPROTO_AH: 146 case IPPROTO_AH:
131 if (!attrs[XFRMA_ALG_AUTH] || 147 if ((!attrs[XFRMA_ALG_AUTH] &&
148 !attrs[XFRMA_ALG_AUTH_TRUNC]) ||
132 attrs[XFRMA_ALG_AEAD] || 149 attrs[XFRMA_ALG_AEAD] ||
133 attrs[XFRMA_ALG_CRYPT] || 150 attrs[XFRMA_ALG_CRYPT] ||
134 attrs[XFRMA_ALG_COMP]) 151 attrs[XFRMA_ALG_COMP])
@@ -139,10 +156,12 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
139 if (attrs[XFRMA_ALG_COMP]) 156 if (attrs[XFRMA_ALG_COMP])
140 goto out; 157 goto out;
141 if (!attrs[XFRMA_ALG_AUTH] && 158 if (!attrs[XFRMA_ALG_AUTH] &&
159 !attrs[XFRMA_ALG_AUTH_TRUNC] &&
142 !attrs[XFRMA_ALG_CRYPT] && 160 !attrs[XFRMA_ALG_CRYPT] &&
143 !attrs[XFRMA_ALG_AEAD]) 161 !attrs[XFRMA_ALG_AEAD])
144 goto out; 162 goto out;
145 if ((attrs[XFRMA_ALG_AUTH] || 163 if ((attrs[XFRMA_ALG_AUTH] ||
164 attrs[XFRMA_ALG_AUTH_TRUNC] ||
146 attrs[XFRMA_ALG_CRYPT]) && 165 attrs[XFRMA_ALG_CRYPT]) &&
147 attrs[XFRMA_ALG_AEAD]) 166 attrs[XFRMA_ALG_AEAD])
148 goto out; 167 goto out;
@@ -152,6 +171,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
152 if (!attrs[XFRMA_ALG_COMP] || 171 if (!attrs[XFRMA_ALG_COMP] ||
153 attrs[XFRMA_ALG_AEAD] || 172 attrs[XFRMA_ALG_AEAD] ||
154 attrs[XFRMA_ALG_AUTH] || 173 attrs[XFRMA_ALG_AUTH] ||
174 attrs[XFRMA_ALG_AUTH_TRUNC] ||
155 attrs[XFRMA_ALG_CRYPT]) 175 attrs[XFRMA_ALG_CRYPT])
156 goto out; 176 goto out;
157 break; 177 break;
@@ -161,6 +181,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
161 case IPPROTO_ROUTING: 181 case IPPROTO_ROUTING:
162 if (attrs[XFRMA_ALG_COMP] || 182 if (attrs[XFRMA_ALG_COMP] ||
163 attrs[XFRMA_ALG_AUTH] || 183 attrs[XFRMA_ALG_AUTH] ||
184 attrs[XFRMA_ALG_AUTH_TRUNC] ||
164 attrs[XFRMA_ALG_AEAD] || 185 attrs[XFRMA_ALG_AEAD] ||
165 attrs[XFRMA_ALG_CRYPT] || 186 attrs[XFRMA_ALG_CRYPT] ||
166 attrs[XFRMA_ENCAP] || 187 attrs[XFRMA_ENCAP] ||
@@ -176,6 +197,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
176 197
177 if ((err = verify_aead(attrs))) 198 if ((err = verify_aead(attrs)))
178 goto out; 199 goto out;
200 if ((err = verify_auth_trunc(attrs)))
201 goto out;
179 if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH))) 202 if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH)))
180 goto out; 203 goto out;
181 if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT))) 204 if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT)))
@@ -229,6 +252,66 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props,
229 return 0; 252 return 0;
230} 253}
231 254
255static int attach_auth(struct xfrm_algo_auth **algpp, u8 *props,
256 struct nlattr *rta)
257{
258 struct xfrm_algo *ualg;
259 struct xfrm_algo_auth *p;
260 struct xfrm_algo_desc *algo;
261
262 if (!rta)
263 return 0;
264
265 ualg = nla_data(rta);
266
267 algo = xfrm_aalg_get_byname(ualg->alg_name, 1);
268 if (!algo)
269 return -ENOSYS;
270 *props = algo->desc.sadb_alg_id;
271
272 p = kmalloc(sizeof(*p) + (ualg->alg_key_len + 7) / 8, GFP_KERNEL);
273 if (!p)
274 return -ENOMEM;
275
276 strcpy(p->alg_name, algo->name);
277 p->alg_key_len = ualg->alg_key_len;
278 p->alg_trunc_len = algo->uinfo.auth.icv_truncbits;
279 memcpy(p->alg_key, ualg->alg_key, (ualg->alg_key_len + 7) / 8);
280
281 *algpp = p;
282 return 0;
283}
284
285static int attach_auth_trunc(struct xfrm_algo_auth **algpp, u8 *props,
286 struct nlattr *rta)
287{
288 struct xfrm_algo_auth *p, *ualg;
289 struct xfrm_algo_desc *algo;
290
291 if (!rta)
292 return 0;
293
294 ualg = nla_data(rta);
295
296 algo = xfrm_aalg_get_byname(ualg->alg_name, 1);
297 if (!algo)
298 return -ENOSYS;
299 if (ualg->alg_trunc_len > algo->uinfo.auth.icv_fullbits)
300 return -EINVAL;
301 *props = algo->desc.sadb_alg_id;
302
303 p = kmemdup(ualg, xfrm_alg_auth_len(ualg), GFP_KERNEL);
304 if (!p)
305 return -ENOMEM;
306
307 strcpy(p->alg_name, algo->name);
308 if (!p->alg_trunc_len)
309 p->alg_trunc_len = algo->uinfo.auth.icv_truncbits;
310
311 *algpp = p;
312 return 0;
313}
314
232static int attach_aead(struct xfrm_algo_aead **algpp, u8 *props, 315static int attach_aead(struct xfrm_algo_aead **algpp, u8 *props,
233 struct nlattr *rta) 316 struct nlattr *rta)
234{ 317{
@@ -332,10 +415,14 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
332 if ((err = attach_aead(&x->aead, &x->props.ealgo, 415 if ((err = attach_aead(&x->aead, &x->props.ealgo,
333 attrs[XFRMA_ALG_AEAD]))) 416 attrs[XFRMA_ALG_AEAD])))
334 goto error; 417 goto error;
335 if ((err = attach_one_algo(&x->aalg, &x->props.aalgo, 418 if ((err = attach_auth_trunc(&x->aalg, &x->props.aalgo,
336 xfrm_aalg_get_byname, 419 attrs[XFRMA_ALG_AUTH_TRUNC])))
337 attrs[XFRMA_ALG_AUTH])))
338 goto error; 420 goto error;
421 if (!x->props.aalgo) {
422 if ((err = attach_auth(&x->aalg, &x->props.aalgo,
423 attrs[XFRMA_ALG_AUTH])))
424 goto error;
425 }
339 if ((err = attach_one_algo(&x->ealg, &x->props.ealgo, 426 if ((err = attach_one_algo(&x->ealg, &x->props.ealgo,
340 xfrm_ealg_get_byname, 427 xfrm_ealg_get_byname,
341 attrs[XFRMA_ALG_CRYPT]))) 428 attrs[XFRMA_ALG_CRYPT])))
@@ -548,6 +635,24 @@ static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb)
548 return 0; 635 return 0;
549} 636}
550 637
638static int copy_to_user_auth(struct xfrm_algo_auth *auth, struct sk_buff *skb)
639{
640 struct xfrm_algo *algo;
641 struct nlattr *nla;
642
643 nla = nla_reserve(skb, XFRMA_ALG_AUTH,
644 sizeof(*algo) + (auth->alg_key_len + 7) / 8);
645 if (!nla)
646 return -EMSGSIZE;
647
648 algo = nla_data(nla);
649 strcpy(algo->alg_name, auth->alg_name);
650 memcpy(algo->alg_key, auth->alg_key, (auth->alg_key_len + 7) / 8);
651 algo->alg_key_len = auth->alg_key_len;
652
653 return 0;
654}
655
551/* Don't change this without updating xfrm_sa_len! */ 656/* Don't change this without updating xfrm_sa_len! */
552static int copy_to_user_state_extra(struct xfrm_state *x, 657static int copy_to_user_state_extra(struct xfrm_state *x,
553 struct xfrm_usersa_info *p, 658 struct xfrm_usersa_info *p,
@@ -563,8 +668,13 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
563 668
564 if (x->aead) 669 if (x->aead)
565 NLA_PUT(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead); 670 NLA_PUT(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead);
566 if (x->aalg) 671 if (x->aalg) {
567 NLA_PUT(skb, XFRMA_ALG_AUTH, xfrm_alg_len(x->aalg), x->aalg); 672 if (copy_to_user_auth(x->aalg, skb))
673 goto nla_put_failure;
674
675 NLA_PUT(skb, XFRMA_ALG_AUTH_TRUNC,
676 xfrm_alg_auth_len(x->aalg), x->aalg);
677 }
568 if (x->ealg) 678 if (x->ealg)
569 NLA_PUT(skb, XFRMA_ALG_CRYPT, xfrm_alg_len(x->ealg), x->ealg); 679 NLA_PUT(skb, XFRMA_ALG_CRYPT, xfrm_alg_len(x->ealg), x->ealg);
570 if (x->calg) 680 if (x->calg)
@@ -2117,8 +2227,11 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x)
2117 size_t l = 0; 2227 size_t l = 0;
2118 if (x->aead) 2228 if (x->aead)
2119 l += nla_total_size(aead_len(x->aead)); 2229 l += nla_total_size(aead_len(x->aead));
2120 if (x->aalg) 2230 if (x->aalg) {
2121 l += nla_total_size(xfrm_alg_len(x->aalg)); 2231 l += nla_total_size(sizeof(struct xfrm_algo) +
2232 (x->aalg->alg_key_len + 7) / 8);
2233 l += nla_total_size(xfrm_alg_auth_len(x->aalg));
2234 }
2122 if (x->ealg) 2235 if (x->ealg)
2123 l += nla_total_size(xfrm_alg_len(x->ealg)); 2236 l += nla_total_size(xfrm_alg_len(x->ealg));
2124 if (x->calg) 2237 if (x->calg)
@@ -2608,22 +2721,24 @@ static int __net_init xfrm_user_net_init(struct net *net)
2608 xfrm_netlink_rcv, NULL, THIS_MODULE); 2721 xfrm_netlink_rcv, NULL, THIS_MODULE);
2609 if (nlsk == NULL) 2722 if (nlsk == NULL)
2610 return -ENOMEM; 2723 return -ENOMEM;
2724 net->xfrm.nlsk_stash = nlsk; /* Don't set to NULL */
2611 rcu_assign_pointer(net->xfrm.nlsk, nlsk); 2725 rcu_assign_pointer(net->xfrm.nlsk, nlsk);
2612 return 0; 2726 return 0;
2613} 2727}
2614 2728
2615static void __net_exit xfrm_user_net_exit(struct net *net) 2729static void __net_exit xfrm_user_net_exit(struct list_head *net_exit_list)
2616{ 2730{
2617 struct sock *nlsk = net->xfrm.nlsk; 2731 struct net *net;
2618 2732 list_for_each_entry(net, net_exit_list, exit_list)
2619 rcu_assign_pointer(net->xfrm.nlsk, NULL); 2733 rcu_assign_pointer(net->xfrm.nlsk, NULL);
2620 synchronize_rcu(); 2734 synchronize_net();
2621 netlink_kernel_release(nlsk); 2735 list_for_each_entry(net, net_exit_list, exit_list)
2736 netlink_kernel_release(net->xfrm.nlsk_stash);
2622} 2737}
2623 2738
2624static struct pernet_operations xfrm_user_net_ops = { 2739static struct pernet_operations xfrm_user_net_ops = {
2625 .init = xfrm_user_net_init, 2740 .init = xfrm_user_net_init,
2626 .exit = xfrm_user_net_exit, 2741 .exit_batch = xfrm_user_net_exit,
2627}; 2742};
2628 2743
2629static int __init xfrm_user_init(void) 2744static int __init xfrm_user_init(void)