aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm
diff options
context:
space:
mode:
authorMartin Willi <martin@strongswan.org>2009-11-24 19:29:52 -0500
committerDavid S. Miller <davem@davemloft.net>2009-11-25 18:48:38 -0500
commit4447bb33f09444920a8f1d89e1540137429351b6 (patch)
tree0aeadd5f09b412380974d3155255ba8db27dd1ed /net/xfrm
parent4e242d1616781f9f1f0b01abf878700b259cd8b5 (diff)
xfrm: Store aalg in xfrm_state with a user specified truncation length
Adding a xfrm_state requires an authentication algorithm specified either as xfrm_algo or as xfrm_algo_auth with a specific truncation length. For compatibility, both attributes are dumped to userspace, and we also accept both attributes, but prefer the new syntax. If no truncation length is specified, or the authentication algorithm is specified using xfrm_algo, the truncation length from the algorithm description in the kernel is used. Signed-off-by: Martin Willi <martin@strongswan.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/xfrm')
-rw-r--r--net/xfrm/xfrm_state.c2
-rw-r--r--net/xfrm/xfrm_user.c129
2 files changed, 122 insertions, 9 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index e9ac0cec0877..d847f1a52b44 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -1114,7 +1114,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
1114 x->props.saddr = orig->props.saddr; 1114 x->props.saddr = orig->props.saddr;
1115 1115
1116 if (orig->aalg) { 1116 if (orig->aalg) {
1117 x->aalg = xfrm_algo_clone(orig->aalg); 1117 x->aalg = xfrm_algo_auth_clone(orig->aalg);
1118 if (!x->aalg) 1118 if (!x->aalg)
1119 goto error; 1119 goto error;
1120 } 1120 }
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index b95a2d64eb59..fb42d778d278 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)