xfrm_user.c 64.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9
/* xfrm_user.c: User interface to configure xfrm engine.
 *
 * Copyright (C) 2002 David S. Miller (davem@redhat.com)
 *
 * Changes:
 *	Mitsuru KANDA @USAGI
 * 	Kazunori MIYAZAWA @USAGI
 * 	Kunihiro Ishiguro <kunihiro@ipinfusion.com>
 * 		IPv6 support
10
 *
L
Linus Torvalds 已提交
11 12
 */

13
#include <linux/crypto.h>
L
Linus Torvalds 已提交
14 15 16 17 18 19 20 21 22 23 24 25 26 27
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/socket.h>
#include <linux/string.h>
#include <linux/net.h>
#include <linux/skbuff.h>
#include <linux/pfkeyv2.h>
#include <linux/ipsec.h>
#include <linux/init.h>
#include <linux/security.h>
#include <net/sock.h>
#include <net/xfrm.h>
28
#include <net/netlink.h>
L
Linus Torvalds 已提交
29
#include <asm/uaccess.h>
30 31 32
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#include <linux/in6.h>
#endif
L
Linus Torvalds 已提交
33

34 35 36
#define DUMMY_MARK 0
static struct xfrm_mark dummy_mark = {0, 0};

37 38 39 40 41
static inline int aead_len(struct xfrm_algo_aead *alg)
{
	return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
}

42
static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
L
Linus Torvalds 已提交
43
{
44
	struct nlattr *rt = attrs[type];
L
Linus Torvalds 已提交
45 46 47 48 49
	struct xfrm_algo *algp;

	if (!rt)
		return 0;

50
	algp = nla_data(rt);
51
	if (nla_len(rt) < xfrm_alg_len(algp))
52 53
		return -EINVAL;

L
Linus Torvalds 已提交
54 55 56 57 58 59 60 61
	switch (type) {
	case XFRMA_ALG_AUTH:
	case XFRMA_ALG_CRYPT:
	case XFRMA_ALG_COMP:
		break;

	default:
		return -EINVAL;
62
	}
L
Linus Torvalds 已提交
63 64 65 66 67

	algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0';
	return 0;
}

68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
static int verify_auth_trunc(struct nlattr **attrs)
{
	struct nlattr *rt = attrs[XFRMA_ALG_AUTH_TRUNC];
	struct xfrm_algo_auth *algp;

	if (!rt)
		return 0;

	algp = nla_data(rt);
	if (nla_len(rt) < xfrm_alg_auth_len(algp))
		return -EINVAL;

	algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0';
	return 0;
}

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
static int verify_aead(struct nlattr **attrs)
{
	struct nlattr *rt = attrs[XFRMA_ALG_AEAD];
	struct xfrm_algo_aead *algp;

	if (!rt)
		return 0;

	algp = nla_data(rt);
	if (nla_len(rt) < aead_len(algp))
		return -EINVAL;

	algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0';
	return 0;
}

100
static void verify_one_addr(struct nlattr **attrs, enum xfrm_attr_type_t type,
101 102
			   xfrm_address_t **addrp)
{
103
	struct nlattr *rt = attrs[type];
104

105
	if (rt && addrp)
106
		*addrp = nla_data(rt);
107
}
108

109
static inline int verify_sec_ctx_len(struct nlattr **attrs)
110
{
111
	struct nlattr *rt = attrs[XFRMA_SEC_CTX];
112 113 114 115 116
	struct xfrm_user_sec_ctx *uctx;

	if (!rt)
		return 0;

117
	uctx = nla_data(rt);
118
	if (uctx->len != (sizeof(struct xfrm_user_sec_ctx) + uctx->ctx_len))
119 120 121 122 123 124
		return -EINVAL;

	return 0;
}


L
Linus Torvalds 已提交
125
static int verify_newsa_info(struct xfrm_usersa_info *p,
126
			     struct nlattr **attrs)
L
Linus Torvalds 已提交
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
{
	int err;

	err = -EINVAL;
	switch (p->family) {
	case AF_INET:
		break;

	case AF_INET6:
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
		break;
#else
		err = -EAFNOSUPPORT;
		goto out;
#endif

	default:
		goto out;
145
	}
L
Linus Torvalds 已提交
146 147 148 149

	err = -EINVAL;
	switch (p->id.proto) {
	case IPPROTO_AH:
150 151
		if ((!attrs[XFRMA_ALG_AUTH]	&&
		     !attrs[XFRMA_ALG_AUTH_TRUNC]) ||
152
		    attrs[XFRMA_ALG_AEAD]	||
153 154
		    attrs[XFRMA_ALG_CRYPT]	||
		    attrs[XFRMA_ALG_COMP])
L
Linus Torvalds 已提交
155 156 157 158
			goto out;
		break;

	case IPPROTO_ESP:
159 160 161
		if (attrs[XFRMA_ALG_COMP])
			goto out;
		if (!attrs[XFRMA_ALG_AUTH] &&
162
		    !attrs[XFRMA_ALG_AUTH_TRUNC] &&
163 164 165 166
		    !attrs[XFRMA_ALG_CRYPT] &&
		    !attrs[XFRMA_ALG_AEAD])
			goto out;
		if ((attrs[XFRMA_ALG_AUTH] ||
167
		     attrs[XFRMA_ALG_AUTH_TRUNC] ||
168 169
		     attrs[XFRMA_ALG_CRYPT]) &&
		    attrs[XFRMA_ALG_AEAD])
L
Linus Torvalds 已提交
170 171 172 173
			goto out;
		break;

	case IPPROTO_COMP:
174
		if (!attrs[XFRMA_ALG_COMP]	||
175
		    attrs[XFRMA_ALG_AEAD]	||
176
		    attrs[XFRMA_ALG_AUTH]	||
177
		    attrs[XFRMA_ALG_AUTH_TRUNC]	||
178
		    attrs[XFRMA_ALG_CRYPT])
L
Linus Torvalds 已提交
179 180 181
			goto out;
		break;

182 183 184
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
	case IPPROTO_DSTOPTS:
	case IPPROTO_ROUTING:
185 186
		if (attrs[XFRMA_ALG_COMP]	||
		    attrs[XFRMA_ALG_AUTH]	||
187
		    attrs[XFRMA_ALG_AUTH_TRUNC]	||
188
		    attrs[XFRMA_ALG_AEAD]	||
189 190 191 192
		    attrs[XFRMA_ALG_CRYPT]	||
		    attrs[XFRMA_ENCAP]		||
		    attrs[XFRMA_SEC_CTX]	||
		    !attrs[XFRMA_COADDR])
193 194 195 196
			goto out;
		break;
#endif

L
Linus Torvalds 已提交
197 198
	default:
		goto out;
199
	}
L
Linus Torvalds 已提交
200

201 202
	if ((err = verify_aead(attrs)))
		goto out;
203 204
	if ((err = verify_auth_trunc(attrs)))
		goto out;
205
	if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH)))
L
Linus Torvalds 已提交
206
		goto out;
207
	if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT)))
L
Linus Torvalds 已提交
208
		goto out;
209
	if ((err = verify_one_alg(attrs, XFRMA_ALG_COMP)))
L
Linus Torvalds 已提交
210
		goto out;
211
	if ((err = verify_sec_ctx_len(attrs)))
212
		goto out;
L
Linus Torvalds 已提交
213 214 215

	err = -EINVAL;
	switch (p->mode) {
216 217
	case XFRM_MODE_TRANSPORT:
	case XFRM_MODE_TUNNEL:
218
	case XFRM_MODE_ROUTEOPTIMIZATION:
D
Diego Beltrami 已提交
219
	case XFRM_MODE_BEET:
L
Linus Torvalds 已提交
220 221 222 223
		break;

	default:
		goto out;
224
	}
L
Linus Torvalds 已提交
225 226 227 228 229 230 231 232 233

	err = 0;

out:
	return err;
}

static int attach_one_algo(struct xfrm_algo **algpp, u8 *props,
			   struct xfrm_algo_desc *(*get_byname)(char *, int),
234
			   struct nlattr *rta)
L
Linus Torvalds 已提交
235 236 237 238 239 240 241
{
	struct xfrm_algo *p, *ualg;
	struct xfrm_algo_desc *algo;

	if (!rta)
		return 0;

242
	ualg = nla_data(rta);
L
Linus Torvalds 已提交
243 244 245 246 247 248

	algo = get_byname(ualg->alg_name, 1);
	if (!algo)
		return -ENOSYS;
	*props = algo->desc.sadb_alg_id;

249
	p = kmemdup(ualg, xfrm_alg_len(ualg), GFP_KERNEL);
L
Linus Torvalds 已提交
250 251 252
	if (!p)
		return -ENOMEM;

253
	strcpy(p->alg_name, algo->name);
L
Linus Torvalds 已提交
254 255 256 257
	*algpp = p;
	return 0;
}

258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
static int attach_auth(struct xfrm_algo_auth **algpp, u8 *props,
		       struct nlattr *rta)
{
	struct xfrm_algo *ualg;
	struct xfrm_algo_auth *p;
	struct xfrm_algo_desc *algo;

	if (!rta)
		return 0;

	ualg = nla_data(rta);

	algo = xfrm_aalg_get_byname(ualg->alg_name, 1);
	if (!algo)
		return -ENOSYS;
	*props = algo->desc.sadb_alg_id;

	p = kmalloc(sizeof(*p) + (ualg->alg_key_len + 7) / 8, GFP_KERNEL);
	if (!p)
		return -ENOMEM;

	strcpy(p->alg_name, algo->name);
	p->alg_key_len = ualg->alg_key_len;
	p->alg_trunc_len = algo->uinfo.auth.icv_truncbits;
	memcpy(p->alg_key, ualg->alg_key, (ualg->alg_key_len + 7) / 8);

	*algpp = p;
	return 0;
}

static int attach_auth_trunc(struct xfrm_algo_auth **algpp, u8 *props,
			     struct nlattr *rta)
{
	struct xfrm_algo_auth *p, *ualg;
	struct xfrm_algo_desc *algo;

	if (!rta)
		return 0;

	ualg = nla_data(rta);

	algo = xfrm_aalg_get_byname(ualg->alg_name, 1);
	if (!algo)
		return -ENOSYS;
	if (ualg->alg_trunc_len > algo->uinfo.auth.icv_fullbits)
		return -EINVAL;
	*props = algo->desc.sadb_alg_id;

	p = kmemdup(ualg, xfrm_alg_auth_len(ualg), GFP_KERNEL);
	if (!p)
		return -ENOMEM;

	strcpy(p->alg_name, algo->name);
	if (!p->alg_trunc_len)
		p->alg_trunc_len = algo->uinfo.auth.icv_truncbits;

	*algpp = p;
	return 0;
}

318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
static int attach_aead(struct xfrm_algo_aead **algpp, u8 *props,
		       struct nlattr *rta)
{
	struct xfrm_algo_aead *p, *ualg;
	struct xfrm_algo_desc *algo;

	if (!rta)
		return 0;

	ualg = nla_data(rta);

	algo = xfrm_aead_get_byname(ualg->alg_name, ualg->alg_icv_len, 1);
	if (!algo)
		return -ENOSYS;
	*props = algo->desc.sadb_alg_id;

	p = kmemdup(ualg, aead_len(ualg), GFP_KERNEL);
	if (!p)
		return -ENOMEM;

	strcpy(p->alg_name, algo->name);
	*algpp = p;
	return 0;
}

343
static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx)
344 345 346 347 348 349 350 351 352 353
{
	int len = 0;

	if (xfrm_ctx) {
		len += sizeof(struct xfrm_user_sec_ctx);
		len += xfrm_ctx->ctx_len;
	}
	return len;
}

L
Linus Torvalds 已提交
354 355 356 357 358 359 360 361 362
static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)
{
	memcpy(&x->id, &p->id, sizeof(x->id));
	memcpy(&x->sel, &p->sel, sizeof(x->sel));
	memcpy(&x->lft, &p->lft, sizeof(x->lft));
	x->props.mode = p->mode;
	x->props.replay_window = p->replay_window;
	x->props.reqid = p->reqid;
	x->props.family = p->family;
363
	memcpy(&x->props.saddr, &p->saddr, sizeof(x->props.saddr));
L
Linus Torvalds 已提交
364
	x->props.flags = p->flags;
365

366
	if (!x->sel.family && !(p->flags & XFRM_STATE_AF_UNSPEC))
367
		x->sel.family = p->family;
L
Linus Torvalds 已提交
368 369
}

J
Jamal Hadi Salim 已提交
370 371 372 373 374
/*
 * someday when pfkey also has support, we could have the code
 * somehow made shareable and move it to xfrm_state.c - JHS
 *
*/
375
static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs)
J
Jamal Hadi Salim 已提交
376
{
377 378 379 380
	struct nlattr *rp = attrs[XFRMA_REPLAY_VAL];
	struct nlattr *lt = attrs[XFRMA_LTIME_VAL];
	struct nlattr *et = attrs[XFRMA_ETIMER_THRESH];
	struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH];
J
Jamal Hadi Salim 已提交
381 382 383

	if (rp) {
		struct xfrm_replay_state *replay;
384
		replay = nla_data(rp);
J
Jamal Hadi Salim 已提交
385 386 387 388 389 390
		memcpy(&x->replay, replay, sizeof(*replay));
		memcpy(&x->preplay, replay, sizeof(*replay));
	}

	if (lt) {
		struct xfrm_lifetime_cur *ltime;
391
		ltime = nla_data(lt);
J
Jamal Hadi Salim 已提交
392 393 394 395 396 397
		x->curlft.bytes = ltime->bytes;
		x->curlft.packets = ltime->packets;
		x->curlft.add_time = ltime->add_time;
		x->curlft.use_time = ltime->use_time;
	}

398
	if (et)
399
		x->replay_maxage = nla_get_u32(et);
J
Jamal Hadi Salim 已提交
400

401
	if (rt)
402
		x->replay_maxdiff = nla_get_u32(rt);
J
Jamal Hadi Salim 已提交
403 404
}

405 406
static struct xfrm_state *xfrm_state_construct(struct net *net,
					       struct xfrm_usersa_info *p,
407
					       struct nlattr **attrs,
L
Linus Torvalds 已提交
408 409
					       int *errp)
{
410
	struct xfrm_state *x = xfrm_state_alloc(net);
L
Linus Torvalds 已提交
411 412 413 414 415 416 417
	int err = -ENOMEM;

	if (!x)
		goto error_no_put;

	copy_from_user_state(x, p);

418 419 420
	if ((err = attach_aead(&x->aead, &x->props.ealgo,
			       attrs[XFRMA_ALG_AEAD])))
		goto error;
421 422
	if ((err = attach_auth_trunc(&x->aalg, &x->props.aalgo,
				     attrs[XFRMA_ALG_AUTH_TRUNC])))
L
Linus Torvalds 已提交
423
		goto error;
424 425 426 427 428
	if (!x->props.aalgo) {
		if ((err = attach_auth(&x->aalg, &x->props.aalgo,
				       attrs[XFRMA_ALG_AUTH])))
			goto error;
	}
L
Linus Torvalds 已提交
429 430
	if ((err = attach_one_algo(&x->ealg, &x->props.ealgo,
				   xfrm_ealg_get_byname,
431
				   attrs[XFRMA_ALG_CRYPT])))
L
Linus Torvalds 已提交
432 433 434
		goto error;
	if ((err = attach_one_algo(&x->calg, &x->props.calgo,
				   xfrm_calg_get_byname,
435
				   attrs[XFRMA_ALG_COMP])))
L
Linus Torvalds 已提交
436
		goto error;
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451

	if (attrs[XFRMA_ENCAP]) {
		x->encap = kmemdup(nla_data(attrs[XFRMA_ENCAP]),
				   sizeof(*x->encap), GFP_KERNEL);
		if (x->encap == NULL)
			goto error;
	}

	if (attrs[XFRMA_COADDR]) {
		x->coaddr = kmemdup(nla_data(attrs[XFRMA_COADDR]),
				    sizeof(*x->coaddr), GFP_KERNEL);
		if (x->coaddr == NULL)
			goto error;
	}

H
Herbert Xu 已提交
452
	err = xfrm_init_state(x);
L
Linus Torvalds 已提交
453 454 455
	if (err)
		goto error;

456 457
	if (attrs[XFRMA_SEC_CTX] &&
	    security_xfrm_state_alloc(x, nla_data(attrs[XFRMA_SEC_CTX])))
458 459
		goto error;

L
Linus Torvalds 已提交
460
	x->km.seq = p->seq;
A
Alexey Dobriyan 已提交
461
	x->replay_maxdiff = net->xfrm.sysctl_aevent_rseqth;
J
Jamal Hadi Salim 已提交
462
	/* sysctl_xfrm_aevent_etime is in 100ms units */
A
Alexey Dobriyan 已提交
463
	x->replay_maxage = (net->xfrm.sysctl_aevent_etime*HZ)/XFRM_AE_ETH_M;
J
Jamal Hadi Salim 已提交
464 465 466 467 468 469
	x->preplay.bitmap = 0;
	x->preplay.seq = x->replay.seq+x->replay_maxdiff;
	x->preplay.oseq = x->replay.oseq +x->replay_maxdiff;

	/* override default values from above */

470
	xfrm_update_ae_params(x, attrs);
L
Linus Torvalds 已提交
471 472 473 474 475 476 477 478 479 480 481

	return x;

error:
	x->km.state = XFRM_STATE_DEAD;
	xfrm_state_put(x);
error_no_put:
	*errp = err;
	return NULL;
}

482
static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
483
		struct nlattr **attrs)
L
Linus Torvalds 已提交
484
{
485
	struct net *net = sock_net(skb->sk);
486
	struct xfrm_usersa_info *p = nlmsg_data(nlh);
L
Linus Torvalds 已提交
487 488
	struct xfrm_state *x;
	int err;
489
	struct km_event c;
490 491 492
	uid_t loginuid = NETLINK_CB(skb).loginuid;
	u32 sessionid = NETLINK_CB(skb).sessionid;
	u32 sid = NETLINK_CB(skb).sid;
L
Linus Torvalds 已提交
493

494
	err = verify_newsa_info(p, attrs);
L
Linus Torvalds 已提交
495 496 497
	if (err)
		return err;

498
	x = xfrm_state_construct(net, p, attrs, &err);
L
Linus Torvalds 已提交
499 500 501
	if (!x)
		return err;

502
	xfrm_state_hold(x);
L
Linus Torvalds 已提交
503 504 505 506 507
	if (nlh->nlmsg_type == XFRM_MSG_NEWSA)
		err = xfrm_state_add(x);
	else
		err = xfrm_state_update(x);

508
	xfrm_audit_state_add(x, err ? 0 : 1, loginuid, sessionid, sid);
J
Joy Latten 已提交
509

L
Linus Torvalds 已提交
510 511
	if (err < 0) {
		x->km.state = XFRM_STATE_DEAD;
512
		__xfrm_state_put(x);
513
		goto out;
L
Linus Torvalds 已提交
514 515
	}

516 517
	c.seq = nlh->nlmsg_seq;
	c.pid = nlh->nlmsg_pid;
518
	c.event = nlh->nlmsg_type;
519 520

	km_state_notify(x, &c);
521
out:
522
	xfrm_state_put(x);
L
Linus Torvalds 已提交
523 524 525
	return err;
}

526 527
static struct xfrm_state *xfrm_user_state_lookup(struct net *net,
						 struct xfrm_usersa_id *p,
528
						 struct nlattr **attrs,
529 530 531 532 533 534 535
						 int *errp)
{
	struct xfrm_state *x = NULL;
	int err;

	if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) {
		err = -ESRCH;
536
		x = xfrm_state_lookup(net, DUMMY_MARK, &p->daddr, p->spi, p->proto, p->family);
537 538 539
	} else {
		xfrm_address_t *saddr = NULL;

540
		verify_one_addr(attrs, XFRMA_SRCADDR, &saddr);
541 542 543 544 545
		if (!saddr) {
			err = -EINVAL;
			goto out;
		}

546
		err = -ESRCH;
547
		x = xfrm_state_lookup_byaddr(net, DUMMY_MARK, &p->daddr, saddr,
548
					     p->proto, p->family);
549 550 551 552 553 554 555 556
	}

 out:
	if (!x && errp)
		*errp = err;
	return x;
}

557
static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
558
		struct nlattr **attrs)
L
Linus Torvalds 已提交
559
{
560
	struct net *net = sock_net(skb->sk);
L
Linus Torvalds 已提交
561
	struct xfrm_state *x;
562
	int err = -ESRCH;
563
	struct km_event c;
564
	struct xfrm_usersa_id *p = nlmsg_data(nlh);
565 566 567
	uid_t loginuid = NETLINK_CB(skb).loginuid;
	u32 sessionid = NETLINK_CB(skb).sessionid;
	u32 sid = NETLINK_CB(skb).sid;
L
Linus Torvalds 已提交
568

569
	x = xfrm_user_state_lookup(net, p, attrs, &err);
L
Linus Torvalds 已提交
570
	if (x == NULL)
571
		return err;
L
Linus Torvalds 已提交
572

573
	if ((err = security_xfrm_state_delete(x)) != 0)
C
Catherine Zhang 已提交
574 575
		goto out;

L
Linus Torvalds 已提交
576
	if (xfrm_state_kern(x)) {
C
Catherine Zhang 已提交
577 578
		err = -EPERM;
		goto out;
L
Linus Torvalds 已提交
579 580
	}

581
	err = xfrm_state_delete(x);
J
Joy Latten 已提交
582

C
Catherine Zhang 已提交
583 584
	if (err < 0)
		goto out;
585 586 587

	c.seq = nlh->nlmsg_seq;
	c.pid = nlh->nlmsg_pid;
588
	c.event = nlh->nlmsg_type;
589
	km_state_notify(x, &c);
L
Linus Torvalds 已提交
590

C
Catherine Zhang 已提交
591
out:
592
	xfrm_audit_state_delete(x, err ? 0 : 1, loginuid, sessionid, sid);
C
Catherine Zhang 已提交
593
	xfrm_state_put(x);
594
	return err;
L
Linus Torvalds 已提交
595 596 597 598 599 600 601 602 603
}

static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *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));
	memcpy(&p->curlft, &x->curlft, sizeof(p->curlft));
	memcpy(&p->stats, &x->stats, sizeof(p->stats));
604
	memcpy(&p->saddr, &x->props.saddr, sizeof(p->saddr));
L
Linus Torvalds 已提交
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
	p->mode = x->props.mode;
	p->replay_window = x->props.replay_window;
	p->reqid = x->props.reqid;
	p->family = x->props.family;
	p->flags = x->props.flags;
	p->seq = x->km.seq;
}

struct xfrm_dump_info {
	struct sk_buff *in_skb;
	struct sk_buff *out_skb;
	u32 nlmsg_seq;
	u16 nlmsg_flags;
};

620 621 622 623
static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb)
{
	struct xfrm_user_sec_ctx *uctx;
	struct nlattr *attr;
624
	int ctx_size = sizeof(*uctx) + s->ctx_len;
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640

	attr = nla_reserve(skb, XFRMA_SEC_CTX, ctx_size);
	if (attr == NULL)
		return -EMSGSIZE;

	uctx = nla_data(attr);
	uctx->exttype = XFRMA_SEC_CTX;
	uctx->len = ctx_size;
	uctx->ctx_doi = s->ctx_doi;
	uctx->ctx_alg = s->ctx_alg;
	uctx->ctx_len = s->ctx_len;
	memcpy(uctx + 1, s->ctx_str, s->ctx_len);

	return 0;
}

641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
static int copy_to_user_auth(struct xfrm_algo_auth *auth, struct sk_buff *skb)
{
	struct xfrm_algo *algo;
	struct nlattr *nla;

	nla = nla_reserve(skb, XFRMA_ALG_AUTH,
			  sizeof(*algo) + (auth->alg_key_len + 7) / 8);
	if (!nla)
		return -EMSGSIZE;

	algo = nla_data(nla);
	strcpy(algo->alg_name, auth->alg_name);
	memcpy(algo->alg_key, auth->alg_key, (auth->alg_key_len + 7) / 8);
	algo->alg_key_len = auth->alg_key_len;

	return 0;
}

659 660 661 662
/* Don't change this without updating xfrm_sa_len! */
static int copy_to_user_state_extra(struct xfrm_state *x,
				    struct xfrm_usersa_info *p,
				    struct sk_buff *skb)
L
Linus Torvalds 已提交
663 664 665
{
	copy_to_user_state(x, p);

666 667 668 669 670 671
	if (x->coaddr)
		NLA_PUT(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr);

	if (x->lastused)
		NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused);

672 673
	if (x->aead)
		NLA_PUT(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead);
674 675 676 677 678 679 680
	if (x->aalg) {
		if (copy_to_user_auth(x->aalg, skb))
			goto nla_put_failure;

		NLA_PUT(skb, XFRMA_ALG_AUTH_TRUNC,
			xfrm_alg_auth_len(x->aalg), x->aalg);
	}
L
Linus Torvalds 已提交
681
	if (x->ealg)
682
		NLA_PUT(skb, XFRMA_ALG_CRYPT, xfrm_alg_len(x->ealg), x->ealg);
L
Linus Torvalds 已提交
683
	if (x->calg)
684
		NLA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg);
L
Linus Torvalds 已提交
685 686

	if (x->encap)
687
		NLA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap);
L
Linus Torvalds 已提交
688

689 690
	if (x->security && copy_sec_ctx(x->security, skb) < 0)
		goto nla_put_failure;
691

692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717
	return 0;

nla_put_failure:
	return -EMSGSIZE;
}

static int dump_one_state(struct xfrm_state *x, int count, void *ptr)
{
	struct xfrm_dump_info *sp = ptr;
	struct sk_buff *in_skb = sp->in_skb;
	struct sk_buff *skb = sp->out_skb;
	struct xfrm_usersa_info *p;
	struct nlmsghdr *nlh;
	int err;

	nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq,
			XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags);
	if (nlh == NULL)
		return -EMSGSIZE;

	p = nlmsg_data(nlh);

	err = copy_to_user_state_extra(x, p, skb);
	if (err)
		goto nla_put_failure;

718
	nlmsg_end(skb, nlh);
L
Linus Torvalds 已提交
719 720
	return 0;

721
nla_put_failure:
722
	nlmsg_cancel(skb, nlh);
723
	return err;
L
Linus Torvalds 已提交
724 725
}

726 727 728 729 730 731 732
static int xfrm_dump_sa_done(struct netlink_callback *cb)
{
	struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
	xfrm_state_walk_done(walk);
	return 0;
}

L
Linus Torvalds 已提交
733 734
static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb)
{
735
	struct net *net = sock_net(skb->sk);
736
	struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
L
Linus Torvalds 已提交
737 738
	struct xfrm_dump_info info;

739 740 741
	BUILD_BUG_ON(sizeof(struct xfrm_state_walk) >
		     sizeof(cb->args) - sizeof(cb->args[0]));

L
Linus Torvalds 已提交
742 743 744 745
	info.in_skb = cb->skb;
	info.out_skb = skb;
	info.nlmsg_seq = cb->nlh->nlmsg_seq;
	info.nlmsg_flags = NLM_F_MULTI;
746 747 748 749 750 751

	if (!cb->args[0]) {
		cb->args[0] = 1;
		xfrm_state_walk_init(walk, 0);
	}

752
	(void) xfrm_state_walk(net, walk, dump_one_state, &info);
L
Linus Torvalds 已提交
753 754 755 756 757 758 759 760 761 762

	return skb->len;
}

static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb,
					  struct xfrm_state *x, u32 seq)
{
	struct xfrm_dump_info info;
	struct sk_buff *skb;

763
	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
L
Linus Torvalds 已提交
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779
	if (!skb)
		return ERR_PTR(-ENOMEM);

	info.in_skb = in_skb;
	info.out_skb = skb;
	info.nlmsg_seq = seq;
	info.nlmsg_flags = 0;

	if (dump_one_state(x, 0, &info)) {
		kfree_skb(skb);
		return NULL;
	}

	return skb;
}

780 781 782 783 784 785 786
static inline size_t xfrm_spdinfo_msgsize(void)
{
	return NLMSG_ALIGN(4)
	       + nla_total_size(sizeof(struct xfrmu_spdinfo))
	       + nla_total_size(sizeof(struct xfrmu_spdhinfo));
}

787 788
static int build_spdinfo(struct sk_buff *skb, struct net *net,
			 u32 pid, u32 seq, u32 flags)
J
Jamal Hadi Salim 已提交
789
{
790 791 792
	struct xfrmk_spdinfo si;
	struct xfrmu_spdinfo spc;
	struct xfrmu_spdhinfo sph;
J
Jamal Hadi Salim 已提交
793 794 795 796 797 798 799 800 801
	struct nlmsghdr *nlh;
	u32 *f;

	nlh = nlmsg_put(skb, pid, seq, XFRM_MSG_NEWSPDINFO, sizeof(u32), 0);
	if (nlh == NULL) /* shouldnt really happen ... */
		return -EMSGSIZE;

	f = nlmsg_data(nlh);
	*f = flags;
802
	xfrm_spd_getinfo(net, &si);
803 804 805 806 807 808 809 810 811 812 813
	spc.incnt = si.incnt;
	spc.outcnt = si.outcnt;
	spc.fwdcnt = si.fwdcnt;
	spc.inscnt = si.inscnt;
	spc.outscnt = si.outscnt;
	spc.fwdscnt = si.fwdscnt;
	sph.spdhcnt = si.spdhcnt;
	sph.spdhmcnt = si.spdhmcnt;

	NLA_PUT(skb, XFRMA_SPD_INFO, sizeof(spc), &spc);
	NLA_PUT(skb, XFRMA_SPD_HINFO, sizeof(sph), &sph);
J
Jamal Hadi Salim 已提交
814 815 816 817 818 819 820 821 822

	return nlmsg_end(skb, nlh);

nla_put_failure:
	nlmsg_cancel(skb, nlh);
	return -EMSGSIZE;
}

static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
823
		struct nlattr **attrs)
J
Jamal Hadi Salim 已提交
824
{
825
	struct net *net = sock_net(skb->sk);
J
Jamal Hadi Salim 已提交
826
	struct sk_buff *r_skb;
827
	u32 *flags = nlmsg_data(nlh);
J
Jamal Hadi Salim 已提交
828 829 830
	u32 spid = NETLINK_CB(skb).pid;
	u32 seq = nlh->nlmsg_seq;

831
	r_skb = nlmsg_new(xfrm_spdinfo_msgsize(), GFP_ATOMIC);
J
Jamal Hadi Salim 已提交
832 833 834
	if (r_skb == NULL)
		return -ENOMEM;

835
	if (build_spdinfo(r_skb, net, spid, seq, *flags) < 0)
J
Jamal Hadi Salim 已提交
836 837
		BUG();

838
	return nlmsg_unicast(net->xfrm.nlsk, r_skb, spid);
J
Jamal Hadi Salim 已提交
839 840
}

841 842 843 844 845 846 847
static inline size_t xfrm_sadinfo_msgsize(void)
{
	return NLMSG_ALIGN(4)
	       + nla_total_size(sizeof(struct xfrmu_sadhinfo))
	       + nla_total_size(4); /* XFRMA_SAD_CNT */
}

848 849
static int build_sadinfo(struct sk_buff *skb, struct net *net,
			 u32 pid, u32 seq, u32 flags)
J
Jamal Hadi Salim 已提交
850
{
851 852
	struct xfrmk_sadinfo si;
	struct xfrmu_sadhinfo sh;
J
Jamal Hadi Salim 已提交
853 854 855 856 857 858 859 860 861
	struct nlmsghdr *nlh;
	u32 *f;

	nlh = nlmsg_put(skb, pid, seq, XFRM_MSG_NEWSADINFO, sizeof(u32), 0);
	if (nlh == NULL) /* shouldnt really happen ... */
		return -EMSGSIZE;

	f = nlmsg_data(nlh);
	*f = flags;
862
	xfrm_sad_getinfo(net, &si);
J
Jamal Hadi Salim 已提交
863

864 865 866 867 868
	sh.sadhmcnt = si.sadhmcnt;
	sh.sadhcnt = si.sadhcnt;

	NLA_PUT_U32(skb, XFRMA_SAD_CNT, si.sadcnt);
	NLA_PUT(skb, XFRMA_SAD_HINFO, sizeof(sh), &sh);
J
Jamal Hadi Salim 已提交
869 870 871 872 873 874 875 876 877

	return nlmsg_end(skb, nlh);

nla_put_failure:
	nlmsg_cancel(skb, nlh);
	return -EMSGSIZE;
}

static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
878
		struct nlattr **attrs)
J
Jamal Hadi Salim 已提交
879
{
880
	struct net *net = sock_net(skb->sk);
J
Jamal Hadi Salim 已提交
881
	struct sk_buff *r_skb;
882
	u32 *flags = nlmsg_data(nlh);
J
Jamal Hadi Salim 已提交
883 884 885
	u32 spid = NETLINK_CB(skb).pid;
	u32 seq = nlh->nlmsg_seq;

886
	r_skb = nlmsg_new(xfrm_sadinfo_msgsize(), GFP_ATOMIC);
J
Jamal Hadi Salim 已提交
887 888 889
	if (r_skb == NULL)
		return -ENOMEM;

890
	if (build_sadinfo(r_skb, net, spid, seq, *flags) < 0)
J
Jamal Hadi Salim 已提交
891 892
		BUG();

893
	return nlmsg_unicast(net->xfrm.nlsk, r_skb, spid);
J
Jamal Hadi Salim 已提交
894 895
}

896
static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
897
		struct nlattr **attrs)
L
Linus Torvalds 已提交
898
{
899
	struct net *net = sock_net(skb->sk);
900
	struct xfrm_usersa_id *p = nlmsg_data(nlh);
L
Linus Torvalds 已提交
901 902
	struct xfrm_state *x;
	struct sk_buff *resp_skb;
903
	int err = -ESRCH;
L
Linus Torvalds 已提交
904

905
	x = xfrm_user_state_lookup(net, p, attrs, &err);
L
Linus Torvalds 已提交
906 907 908 909 910 911 912
	if (x == NULL)
		goto out_noput;

	resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq);
	if (IS_ERR(resp_skb)) {
		err = PTR_ERR(resp_skb);
	} else {
913
		err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, NETLINK_CB(skb).pid);
L
Linus Torvalds 已提交
914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934
	}
	xfrm_state_put(x);
out_noput:
	return err;
}

static int verify_userspi_info(struct xfrm_userspi_info *p)
{
	switch (p->info.id.proto) {
	case IPPROTO_AH:
	case IPPROTO_ESP:
		break;

	case IPPROTO_COMP:
		/* IPCOMP spi is 16-bits. */
		if (p->max >= 0x10000)
			return -EINVAL;
		break;

	default:
		return -EINVAL;
935
	}
L
Linus Torvalds 已提交
936 937 938 939 940 941 942

	if (p->min > p->max)
		return -EINVAL;

	return 0;
}

943
static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
944
		struct nlattr **attrs)
L
Linus Torvalds 已提交
945
{
946
	struct net *net = sock_net(skb->sk);
L
Linus Torvalds 已提交
947 948 949 950 951 952 953
	struct xfrm_state *x;
	struct xfrm_userspi_info *p;
	struct sk_buff *resp_skb;
	xfrm_address_t *daddr;
	int family;
	int err;

954
	p = nlmsg_data(nlh);
L
Linus Torvalds 已提交
955 956 957 958 959 960 961 962 963
	err = verify_userspi_info(p);
	if (err)
		goto out_noput;

	family = p->info.family;
	daddr = &p->info.id.daddr;

	x = NULL;
	if (p->info.seq) {
964
		x = xfrm_find_acq_byseq(net, DUMMY_MARK, p->info.seq);
L
Linus Torvalds 已提交
965 966 967 968 969 970 971
		if (x && xfrm_addr_cmp(&x->id.daddr, daddr, family)) {
			xfrm_state_put(x);
			x = NULL;
		}
	}

	if (!x)
972
		x = xfrm_find_acq(net, &dummy_mark, p->info.mode, p->info.reqid,
L
Linus Torvalds 已提交
973 974 975 976 977 978 979
				  p->info.id.proto, daddr,
				  &p->info.saddr, 1,
				  family);
	err = -ENOENT;
	if (x == NULL)
		goto out_noput;

980 981 982
	err = xfrm_alloc_spi(x, p->min, p->max);
	if (err)
		goto out;
L
Linus Torvalds 已提交
983

984
	resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq);
L
Linus Torvalds 已提交
985 986 987 988 989
	if (IS_ERR(resp_skb)) {
		err = PTR_ERR(resp_skb);
		goto out;
	}

990
	err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, NETLINK_CB(skb).pid);
L
Linus Torvalds 已提交
991 992 993 994 995 996 997

out:
	xfrm_state_put(x);
out_noput:
	return err;
}

998
static int verify_policy_dir(u8 dir)
L
Linus Torvalds 已提交
999 1000 1001 1002 1003 1004 1005 1006 1007
{
	switch (dir) {
	case XFRM_POLICY_IN:
	case XFRM_POLICY_OUT:
	case XFRM_POLICY_FWD:
		break;

	default:
		return -EINVAL;
1008
	}
L
Linus Torvalds 已提交
1009 1010 1011 1012

	return 0;
}

1013
static int verify_policy_type(u8 type)
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
{
	switch (type) {
	case XFRM_POLICY_TYPE_MAIN:
#ifdef CONFIG_XFRM_SUB_POLICY
	case XFRM_POLICY_TYPE_SUB:
#endif
		break;

	default:
		return -EINVAL;
1024
	}
1025 1026 1027 1028

	return 0;
}

L
Linus Torvalds 已提交
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
{
	switch (p->share) {
	case XFRM_SHARE_ANY:
	case XFRM_SHARE_SESSION:
	case XFRM_SHARE_USER:
	case XFRM_SHARE_UNIQUE:
		break;

	default:
		return -EINVAL;
1040
	}
L
Linus Torvalds 已提交
1041 1042 1043 1044 1045 1046 1047 1048

	switch (p->action) {
	case XFRM_POLICY_ALLOW:
	case XFRM_POLICY_BLOCK:
		break;

	default:
		return -EINVAL;
1049
	}
L
Linus Torvalds 已提交
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063

	switch (p->sel.family) {
	case AF_INET:
		break;

	case AF_INET6:
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
		break;
#else
		return  -EAFNOSUPPORT;
#endif

	default:
		return -EINVAL;
1064
	}
L
Linus Torvalds 已提交
1065 1066 1067 1068

	return verify_policy_dir(p->dir);
}

1069
static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs)
1070
{
1071
	struct nlattr *rt = attrs[XFRMA_SEC_CTX];
1072 1073 1074 1075 1076
	struct xfrm_user_sec_ctx *uctx;

	if (!rt)
		return 0;

1077
	uctx = nla_data(rt);
1078
	return security_xfrm_policy_alloc(&pol->security, uctx);
1079 1080
}

L
Linus Torvalds 已提交
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099
static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut,
			   int nr)
{
	int i;

	xp->xfrm_nr = nr;
	for (i = 0; i < nr; i++, ut++) {
		struct xfrm_tmpl *t = &xp->xfrm_vec[i];

		memcpy(&t->id, &ut->id, sizeof(struct xfrm_id));
		memcpy(&t->saddr, &ut->saddr,
		       sizeof(xfrm_address_t));
		t->reqid = ut->reqid;
		t->mode = ut->mode;
		t->share = ut->share;
		t->optional = ut->optional;
		t->aalgos = ut->aalgos;
		t->ealgos = ut->ealgos;
		t->calgos = ut->calgos;
1100 1101
		/* If all masks are ~0, then we allow all algorithms. */
		t->allalgs = !~(t->aalgos & t->ealgos & t->calgos);
1102
		t->encap_family = ut->family;
L
Linus Torvalds 已提交
1103 1104 1105
	}
}

1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132
static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family)
{
	int i;

	if (nr > XFRM_MAX_DEPTH)
		return -EINVAL;

	for (i = 0; i < nr; i++) {
		/* We never validated the ut->family value, so many
		 * applications simply leave it at zero.  The check was
		 * never made and ut->family was ignored because all
		 * templates could be assumed to have the same family as
		 * the policy itself.  Now that we will have ipv4-in-ipv6
		 * and ipv6-in-ipv4 tunnels, this is no longer true.
		 */
		if (!ut[i].family)
			ut[i].family = family;

		switch (ut[i].family) {
		case AF_INET:
			break;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
		case AF_INET6:
			break;
#endif
		default:
			return -EINVAL;
1133
		}
1134 1135 1136 1137 1138
	}

	return 0;
}

1139
static int copy_from_user_tmpl(struct xfrm_policy *pol, struct nlattr **attrs)
L
Linus Torvalds 已提交
1140
{
1141
	struct nlattr *rt = attrs[XFRMA_TMPL];
L
Linus Torvalds 已提交
1142 1143 1144 1145

	if (!rt) {
		pol->xfrm_nr = 0;
	} else {
1146 1147
		struct xfrm_user_tmpl *utmpl = nla_data(rt);
		int nr = nla_len(rt) / sizeof(*utmpl);
1148
		int err;
L
Linus Torvalds 已提交
1149

1150 1151 1152
		err = validate_tmpl(nr, utmpl, pol->family);
		if (err)
			return err;
L
Linus Torvalds 已提交
1153

1154
		copy_templates(pol, utmpl, nr);
L
Linus Torvalds 已提交
1155 1156 1157 1158
	}
	return 0;
}

1159
static int copy_from_user_policy_type(u8 *tp, struct nlattr **attrs)
1160
{
1161
	struct nlattr *rt = attrs[XFRMA_POLICY_TYPE];
1162
	struct xfrm_userpolicy_type *upt;
1163
	u8 type = XFRM_POLICY_TYPE_MAIN;
1164 1165 1166
	int err;

	if (rt) {
1167
		upt = nla_data(rt);
1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178
		type = upt->type;
	}

	err = verify_policy_type(type);
	if (err)
		return err;

	*tp = type;
	return 0;
}

L
Linus Torvalds 已提交
1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204
static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p)
{
	xp->priority = p->priority;
	xp->index = p->index;
	memcpy(&xp->selector, &p->sel, sizeof(xp->selector));
	memcpy(&xp->lft, &p->lft, sizeof(xp->lft));
	xp->action = p->action;
	xp->flags = p->flags;
	xp->family = p->sel.family;
	/* XXX xp->share = p->share; */
}

static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p, int dir)
{
	memcpy(&p->sel, &xp->selector, sizeof(p->sel));
	memcpy(&p->lft, &xp->lft, sizeof(p->lft));
	memcpy(&p->curlft, &xp->curlft, sizeof(p->curlft));
	p->priority = xp->priority;
	p->index = xp->index;
	p->sel.family = xp->family;
	p->dir = dir;
	p->action = xp->action;
	p->flags = xp->flags;
	p->share = XFRM_SHARE_ANY; /* XXX xp->share */
}

1205
static struct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_userpolicy_info *p, struct nlattr **attrs, int *errp)
L
Linus Torvalds 已提交
1206
{
1207
	struct xfrm_policy *xp = xfrm_policy_alloc(net, GFP_KERNEL);
L
Linus Torvalds 已提交
1208 1209 1210 1211 1212 1213 1214 1215
	int err;

	if (!xp) {
		*errp = -ENOMEM;
		return NULL;
	}

	copy_from_user_policy(xp, p);
1216

1217
	err = copy_from_user_policy_type(&xp->type, attrs);
1218 1219 1220
	if (err)
		goto error;

1221 1222
	if (!(err = copy_from_user_tmpl(xp, attrs)))
		err = copy_from_user_sec_ctx(xp, attrs);
1223 1224
	if (err)
		goto error;
L
Linus Torvalds 已提交
1225 1226

	return xp;
1227 1228
 error:
	*errp = err;
H
Herbert Xu 已提交
1229
	xp->walk.dead = 1;
1230
	xfrm_policy_destroy(xp);
1231
	return NULL;
L
Linus Torvalds 已提交
1232 1233
}

1234
static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
1235
		struct nlattr **attrs)
L
Linus Torvalds 已提交
1236
{
1237
	struct net *net = sock_net(skb->sk);
1238
	struct xfrm_userpolicy_info *p = nlmsg_data(nlh);
L
Linus Torvalds 已提交
1239
	struct xfrm_policy *xp;
1240
	struct km_event c;
L
Linus Torvalds 已提交
1241 1242
	int err;
	int excl;
1243 1244 1245
	uid_t loginuid = NETLINK_CB(skb).loginuid;
	u32 sessionid = NETLINK_CB(skb).sessionid;
	u32 sid = NETLINK_CB(skb).sid;
L
Linus Torvalds 已提交
1246 1247

	err = verify_newpolicy_info(p);
1248 1249
	if (err)
		return err;
1250
	err = verify_sec_ctx_len(attrs);
L
Linus Torvalds 已提交
1251 1252 1253
	if (err)
		return err;

1254
	xp = xfrm_policy_construct(net, p, attrs, &err);
L
Linus Torvalds 已提交
1255 1256 1257
	if (!xp)
		return err;

1258 1259 1260 1261
	/* shouldnt excl be based on nlh flags??
	 * Aha! this is anti-netlink really i.e  more pfkey derived
	 * in netlink excl is a flag and you wouldnt need
	 * a type XFRM_MSG_UPDPOLICY - JHS */
L
Linus Torvalds 已提交
1262 1263
	excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY;
	err = xfrm_policy_insert(p->dir, xp, excl);
1264
	xfrm_audit_policy_add(xp, err ? 0 : 1, loginuid, sessionid, sid);
J
Joy Latten 已提交
1265

L
Linus Torvalds 已提交
1266
	if (err) {
1267
		security_xfrm_policy_free(xp->security);
L
Linus Torvalds 已提交
1268 1269 1270 1271
		kfree(xp);
		return err;
	}

1272
	c.event = nlh->nlmsg_type;
1273 1274 1275 1276
	c.seq = nlh->nlmsg_seq;
	c.pid = nlh->nlmsg_pid;
	km_policy_notify(xp, p->dir, &c);

L
Linus Torvalds 已提交
1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294
	xfrm_pol_put(xp);

	return 0;
}

static int copy_to_user_tmpl(struct xfrm_policy *xp, struct sk_buff *skb)
{
	struct xfrm_user_tmpl vec[XFRM_MAX_DEPTH];
	int i;

	if (xp->xfrm_nr == 0)
		return 0;

	for (i = 0; i < xp->xfrm_nr; i++) {
		struct xfrm_user_tmpl *up = &vec[i];
		struct xfrm_tmpl *kp = &xp->xfrm_vec[i];

		memcpy(&up->id, &kp->id, sizeof(up->id));
1295
		up->family = kp->encap_family;
L
Linus Torvalds 已提交
1296 1297 1298 1299 1300 1301 1302 1303 1304
		memcpy(&up->saddr, &kp->saddr, sizeof(up->saddr));
		up->reqid = kp->reqid;
		up->mode = kp->mode;
		up->share = kp->share;
		up->optional = kp->optional;
		up->aalgos = kp->aalgos;
		up->ealgos = kp->ealgos;
		up->calgos = kp->calgos;
	}
1305

1306 1307
	return nla_put(skb, XFRMA_TMPL,
		       sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr, vec);
1308 1309 1310 1311 1312 1313
}

static inline int copy_to_user_state_sec_ctx(struct xfrm_state *x, struct sk_buff *skb)
{
	if (x->security) {
		return copy_sec_ctx(x->security, skb);
1314 1315
	}
	return 0;
1316
}
1317

1318 1319 1320 1321 1322 1323
static inline int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb)
{
	if (xp->security) {
		return copy_sec_ctx(xp->security, skb);
	}
	return 0;
1324
}
1325 1326 1327 1328 1329 1330 1331 1332
static inline size_t userpolicy_type_attrsize(void)
{
#ifdef CONFIG_XFRM_SUB_POLICY
	return nla_total_size(sizeof(struct xfrm_userpolicy_type));
#else
	return 0;
#endif
}
1333

1334
#ifdef CONFIG_XFRM_SUB_POLICY
1335
static int copy_to_user_policy_type(u8 type, struct sk_buff *skb)
1336
{
1337 1338 1339
	struct xfrm_userpolicy_type upt = {
		.type = type,
	};
1340

1341
	return nla_put(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt);
1342 1343 1344
}

#else
1345
static inline int copy_to_user_policy_type(u8 type, struct sk_buff *skb)
1346 1347 1348 1349 1350
{
	return 0;
}
#endif

L
Linus Torvalds 已提交
1351 1352 1353 1354 1355 1356 1357 1358
static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr)
{
	struct xfrm_dump_info *sp = ptr;
	struct xfrm_userpolicy_info *p;
	struct sk_buff *in_skb = sp->in_skb;
	struct sk_buff *skb = sp->out_skb;
	struct nlmsghdr *nlh;

1359 1360 1361 1362
	nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq,
			XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags);
	if (nlh == NULL)
		return -EMSGSIZE;
L
Linus Torvalds 已提交
1363

1364
	p = nlmsg_data(nlh);
L
Linus Torvalds 已提交
1365 1366 1367
	copy_to_user_policy(xp, p, dir);
	if (copy_to_user_tmpl(xp, skb) < 0)
		goto nlmsg_failure;
1368 1369
	if (copy_to_user_sec_ctx(xp, skb))
		goto nlmsg_failure;
1370
	if (copy_to_user_policy_type(xp->type, skb) < 0)
1371
		goto nlmsg_failure;
L
Linus Torvalds 已提交
1372

1373
	nlmsg_end(skb, nlh);
L
Linus Torvalds 已提交
1374 1375 1376
	return 0;

nlmsg_failure:
1377 1378
	nlmsg_cancel(skb, nlh);
	return -EMSGSIZE;
L
Linus Torvalds 已提交
1379 1380
}

1381 1382 1383 1384 1385 1386 1387 1388
static int xfrm_dump_policy_done(struct netlink_callback *cb)
{
	struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1];

	xfrm_policy_walk_done(walk);
	return 0;
}

L
Linus Torvalds 已提交
1389 1390
static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb)
{
1391
	struct net *net = sock_net(skb->sk);
1392
	struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1];
L
Linus Torvalds 已提交
1393 1394
	struct xfrm_dump_info info;

1395 1396 1397
	BUILD_BUG_ON(sizeof(struct xfrm_policy_walk) >
		     sizeof(cb->args) - sizeof(cb->args[0]));

L
Linus Torvalds 已提交
1398 1399 1400 1401
	info.in_skb = cb->skb;
	info.out_skb = skb;
	info.nlmsg_seq = cb->nlh->nlmsg_seq;
	info.nlmsg_flags = NLM_F_MULTI;
1402 1403 1404 1405 1406 1407

	if (!cb->args[0]) {
		cb->args[0] = 1;
		xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY);
	}

1408
	(void) xfrm_policy_walk(net, walk, dump_one_policy, &info);
L
Linus Torvalds 已提交
1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419

	return skb->len;
}

static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb,
					  struct xfrm_policy *xp,
					  int dir, u32 seq)
{
	struct xfrm_dump_info info;
	struct sk_buff *skb;

1420
	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
L
Linus Torvalds 已提交
1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436
	if (!skb)
		return ERR_PTR(-ENOMEM);

	info.in_skb = in_skb;
	info.out_skb = skb;
	info.nlmsg_seq = seq;
	info.nlmsg_flags = 0;

	if (dump_one_policy(xp, dir, 0, &info) < 0) {
		kfree_skb(skb);
		return NULL;
	}

	return skb;
}

1437
static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
1438
		struct nlattr **attrs)
L
Linus Torvalds 已提交
1439
{
1440
	struct net *net = sock_net(skb->sk);
L
Linus Torvalds 已提交
1441 1442
	struct xfrm_policy *xp;
	struct xfrm_userpolicy_id *p;
1443
	u8 type = XFRM_POLICY_TYPE_MAIN;
L
Linus Torvalds 已提交
1444
	int err;
1445
	struct km_event c;
L
Linus Torvalds 已提交
1446 1447
	int delete;

1448
	p = nlmsg_data(nlh);
L
Linus Torvalds 已提交
1449 1450
	delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY;

1451
	err = copy_from_user_policy_type(&type, attrs);
1452 1453 1454
	if (err)
		return err;

L
Linus Torvalds 已提交
1455 1456 1457 1458 1459
	err = verify_policy_dir(p->dir);
	if (err)
		return err;

	if (p->index)
1460
		xp = xfrm_policy_byid(net, type, p->dir, p->index, delete, &err);
1461
	else {
1462
		struct nlattr *rt = attrs[XFRMA_SEC_CTX];
1463
		struct xfrm_sec_ctx *ctx;
1464

1465
		err = verify_sec_ctx_len(attrs);
1466 1467 1468
		if (err)
			return err;

1469
		ctx = NULL;
1470
		if (rt) {
1471
			struct xfrm_user_sec_ctx *uctx = nla_data(rt);
1472

1473 1474
			err = security_xfrm_policy_alloc(&ctx, uctx);
			if (err)
1475
				return err;
1476
		}
1477
		xp = xfrm_policy_bysel_ctx(net, type, p->dir, &p->sel, ctx,
1478
					   delete, &err);
1479
		security_xfrm_policy_free(ctx);
1480
	}
L
Linus Torvalds 已提交
1481 1482 1483 1484 1485 1486 1487 1488 1489 1490
	if (xp == NULL)
		return -ENOENT;

	if (!delete) {
		struct sk_buff *resp_skb;

		resp_skb = xfrm_policy_netlink(skb, xp, p->dir, nlh->nlmsg_seq);
		if (IS_ERR(resp_skb)) {
			err = PTR_ERR(resp_skb);
		} else {
1491
			err = nlmsg_unicast(net->xfrm.nlsk, resp_skb,
1492
					    NETLINK_CB(skb).pid);
L
Linus Torvalds 已提交
1493
		}
1494
	} else {
1495 1496 1497 1498 1499 1500
		uid_t loginuid = NETLINK_CB(skb).loginuid;
		u32 sessionid = NETLINK_CB(skb).sessionid;
		u32 sid = NETLINK_CB(skb).sid;

		xfrm_audit_policy_delete(xp, err ? 0 : 1, loginuid, sessionid,
					 sid);
1501 1502

		if (err != 0)
C
Catherine Zhang 已提交
1503
			goto out;
1504

1505
		c.data.byid = p->index;
1506
		c.event = nlh->nlmsg_type;
1507 1508 1509
		c.seq = nlh->nlmsg_seq;
		c.pid = nlh->nlmsg_pid;
		km_policy_notify(xp, p->dir, &c);
L
Linus Torvalds 已提交
1510 1511
	}

C
Catherine Zhang 已提交
1512
out:
1513
	xfrm_pol_put(xp);
L
Linus Torvalds 已提交
1514 1515 1516
	return err;
}

1517
static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
1518
		struct nlattr **attrs)
L
Linus Torvalds 已提交
1519
{
1520
	struct net *net = sock_net(skb->sk);
1521
	struct km_event c;
1522
	struct xfrm_usersa_flush *p = nlmsg_data(nlh);
J
Joy Latten 已提交
1523
	struct xfrm_audit audit_info;
1524
	int err;
L
Linus Torvalds 已提交
1525

J
Joy Latten 已提交
1526
	audit_info.loginuid = NETLINK_CB(skb).loginuid;
1527
	audit_info.sessionid = NETLINK_CB(skb).sessionid;
J
Joy Latten 已提交
1528
	audit_info.secid = NETLINK_CB(skb).sid;
1529
	err = xfrm_state_flush(net, p->proto, &audit_info);
1530 1531 1532
	if (err) {
		if (err == -ESRCH) /* empty table */
			return 0;
1533
		return err;
1534
	}
1535
	c.data.proto = p->proto;
1536
	c.event = nlh->nlmsg_type;
1537 1538
	c.seq = nlh->nlmsg_seq;
	c.pid = nlh->nlmsg_pid;
1539
	c.net = net;
1540 1541
	km_state_notify(NULL, &c);

L
Linus Torvalds 已提交
1542 1543 1544
	return 0;
}

1545 1546 1547 1548 1549 1550 1551 1552
static inline size_t xfrm_aevent_msgsize(void)
{
	return NLMSG_ALIGN(sizeof(struct xfrm_aevent_id))
	       + nla_total_size(sizeof(struct xfrm_replay_state))
	       + nla_total_size(sizeof(struct xfrm_lifetime_cur))
	       + nla_total_size(4) /* XFRM_AE_RTHR */
	       + nla_total_size(4); /* XFRM_AE_ETHR */
}
J
Jamal Hadi Salim 已提交
1553 1554 1555 1556 1557 1558

static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c)
{
	struct xfrm_aevent_id *id;
	struct nlmsghdr *nlh;

1559 1560 1561
	nlh = nlmsg_put(skb, c->pid, c->seq, XFRM_MSG_NEWAE, sizeof(*id), 0);
	if (nlh == NULL)
		return -EMSGSIZE;
J
Jamal Hadi Salim 已提交
1562

1563
	id = nlmsg_data(nlh);
1564
	memcpy(&id->sa_id.daddr, &x->id.daddr,sizeof(x->id.daddr));
J
Jamal Hadi Salim 已提交
1565 1566 1567
	id->sa_id.spi = x->id.spi;
	id->sa_id.family = x->props.family;
	id->sa_id.proto = x->id.proto;
1568 1569
	memcpy(&id->saddr, &x->props.saddr,sizeof(x->props.saddr));
	id->reqid = x->props.reqid;
J
Jamal Hadi Salim 已提交
1570 1571
	id->flags = c->data.aevent;

1572 1573
	NLA_PUT(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), &x->replay);
	NLA_PUT(skb, XFRMA_LTIME_VAL, sizeof(x->curlft), &x->curlft);
J
Jamal Hadi Salim 已提交
1574

1575 1576
	if (id->flags & XFRM_AE_RTHR)
		NLA_PUT_U32(skb, XFRMA_REPLAY_THRESH, x->replay_maxdiff);
J
Jamal Hadi Salim 已提交
1577

1578 1579 1580
	if (id->flags & XFRM_AE_ETHR)
		NLA_PUT_U32(skb, XFRMA_ETIMER_THRESH,
			    x->replay_maxage * 10 / HZ);
J
Jamal Hadi Salim 已提交
1581

1582
	return nlmsg_end(skb, nlh);
J
Jamal Hadi Salim 已提交
1583

1584
nla_put_failure:
1585 1586
	nlmsg_cancel(skb, nlh);
	return -EMSGSIZE;
J
Jamal Hadi Salim 已提交
1587 1588
}

1589
static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
1590
		struct nlattr **attrs)
J
Jamal Hadi Salim 已提交
1591
{
1592
	struct net *net = sock_net(skb->sk);
J
Jamal Hadi Salim 已提交
1593 1594 1595 1596
	struct xfrm_state *x;
	struct sk_buff *r_skb;
	int err;
	struct km_event c;
1597
	struct xfrm_aevent_id *p = nlmsg_data(nlh);
J
Jamal Hadi Salim 已提交
1598 1599
	struct xfrm_usersa_id *id = &p->sa_id;

1600
	r_skb = nlmsg_new(xfrm_aevent_msgsize(), GFP_ATOMIC);
J
Jamal Hadi Salim 已提交
1601 1602 1603
	if (r_skb == NULL)
		return -ENOMEM;

1604
	x = xfrm_state_lookup(net, DUMMY_MARK, &id->daddr, id->spi, id->proto, id->family);
J
Jamal Hadi Salim 已提交
1605
	if (x == NULL) {
P
Patrick McHardy 已提交
1606
		kfree_skb(r_skb);
J
Jamal Hadi Salim 已提交
1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621
		return -ESRCH;
	}

	/*
	 * XXX: is this lock really needed - none of the other
	 * gets lock (the concern is things getting updated
	 * while we are still reading) - jhs
	*/
	spin_lock_bh(&x->lock);
	c.data.aevent = p->flags;
	c.seq = nlh->nlmsg_seq;
	c.pid = nlh->nlmsg_pid;

	if (build_aevent(r_skb, x, &c) < 0)
		BUG();
1622
	err = nlmsg_unicast(net->xfrm.nlsk, r_skb, NETLINK_CB(skb).pid);
J
Jamal Hadi Salim 已提交
1623 1624 1625 1626 1627
	spin_unlock_bh(&x->lock);
	xfrm_state_put(x);
	return err;
}

1628
static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
1629
		struct nlattr **attrs)
J
Jamal Hadi Salim 已提交
1630
{
1631
	struct net *net = sock_net(skb->sk);
J
Jamal Hadi Salim 已提交
1632 1633 1634
	struct xfrm_state *x;
	struct km_event c;
	int err = - EINVAL;
1635
	struct xfrm_aevent_id *p = nlmsg_data(nlh);
1636 1637
	struct nlattr *rp = attrs[XFRMA_REPLAY_VAL];
	struct nlattr *lt = attrs[XFRMA_LTIME_VAL];
J
Jamal Hadi Salim 已提交
1638 1639 1640 1641 1642 1643 1644 1645

	if (!lt && !rp)
		return err;

	/* pedantic mode - thou shalt sayeth replaceth */
	if (!(nlh->nlmsg_flags&NLM_F_REPLACE))
		return err;

1646
	x = xfrm_state_lookup(net, DUMMY_MARK, &p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family);
J
Jamal Hadi Salim 已提交
1647 1648 1649 1650 1651 1652 1653
	if (x == NULL)
		return -ESRCH;

	if (x->km.state != XFRM_STATE_VALID)
		goto out;

	spin_lock_bh(&x->lock);
1654
	xfrm_update_ae_params(x, attrs);
J
Jamal Hadi Salim 已提交
1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667
	spin_unlock_bh(&x->lock);

	c.event = nlh->nlmsg_type;
	c.seq = nlh->nlmsg_seq;
	c.pid = nlh->nlmsg_pid;
	c.data.aevent = XFRM_AE_CU;
	km_state_notify(x, &c);
	err = 0;
out:
	xfrm_state_put(x);
	return err;
}

1668
static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
1669
		struct nlattr **attrs)
L
Linus Torvalds 已提交
1670
{
1671
	struct net *net = sock_net(skb->sk);
1672
	struct km_event c;
1673
	u8 type = XFRM_POLICY_TYPE_MAIN;
1674
	int err;
J
Joy Latten 已提交
1675
	struct xfrm_audit audit_info;
1676

1677
	err = copy_from_user_policy_type(&type, attrs);
1678 1679
	if (err)
		return err;
1680

J
Joy Latten 已提交
1681
	audit_info.loginuid = NETLINK_CB(skb).loginuid;
1682
	audit_info.sessionid = NETLINK_CB(skb).sessionid;
J
Joy Latten 已提交
1683
	audit_info.secid = NETLINK_CB(skb).sid;
1684
	err = xfrm_policy_flush(net, type, &audit_info);
1685 1686 1687
	if (err) {
		if (err == -ESRCH) /* empty table */
			return 0;
1688
		return err;
1689 1690
	}

1691
	c.data.type = type;
1692
	c.event = nlh->nlmsg_type;
1693 1694
	c.seq = nlh->nlmsg_seq;
	c.pid = nlh->nlmsg_pid;
1695
	c.net = net;
1696
	km_policy_notify(NULL, 0, &c);
L
Linus Torvalds 已提交
1697 1698 1699
	return 0;
}

1700
static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
1701
		struct nlattr **attrs)
1702
{
1703
	struct net *net = sock_net(skb->sk);
1704
	struct xfrm_policy *xp;
1705
	struct xfrm_user_polexpire *up = nlmsg_data(nlh);
1706
	struct xfrm_userpolicy_info *p = &up->pol;
1707
	u8 type = XFRM_POLICY_TYPE_MAIN;
1708 1709
	int err = -ENOENT;

1710
	err = copy_from_user_policy_type(&type, attrs);
1711 1712 1713
	if (err)
		return err;

1714
	if (p->index)
1715
		xp = xfrm_policy_byid(net, type, p->dir, p->index, 0, &err);
1716
	else {
1717
		struct nlattr *rt = attrs[XFRMA_SEC_CTX];
1718
		struct xfrm_sec_ctx *ctx;
1719

1720
		err = verify_sec_ctx_len(attrs);
1721 1722 1723
		if (err)
			return err;

1724
		ctx = NULL;
1725
		if (rt) {
1726
			struct xfrm_user_sec_ctx *uctx = nla_data(rt);
1727

1728 1729
			err = security_xfrm_policy_alloc(&ctx, uctx);
			if (err)
1730
				return err;
1731
		}
1732
		xp = xfrm_policy_bysel_ctx(net, type, p->dir, &p->sel, ctx, 0, &err);
1733
		security_xfrm_policy_free(ctx);
1734 1735
	}
	if (xp == NULL)
1736
		return -ENOENT;
1737

1738
	read_lock(&xp->lock);
H
Herbert Xu 已提交
1739
	if (xp->walk.dead) {
1740 1741 1742 1743 1744 1745 1746
		read_unlock(&xp->lock);
		goto out;
	}

	read_unlock(&xp->lock);
	err = 0;
	if (up->hard) {
1747 1748 1749
		uid_t loginuid = NETLINK_CB(skb).loginuid;
		uid_t sessionid = NETLINK_CB(skb).sessionid;
		u32 sid = NETLINK_CB(skb).sid;
1750
		xfrm_policy_delete(xp, p->dir);
1751
		xfrm_audit_policy_delete(xp, 1, loginuid, sessionid, sid);
J
Joy Latten 已提交
1752

1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763
	} else {
		// reset the timers here?
		printk("Dont know what to do with soft policy expire\n");
	}
	km_policy_expired(xp, p->dir, up->hard, current->pid);

out:
	xfrm_pol_put(xp);
	return err;
}

1764
static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
1765
		struct nlattr **attrs)
1766
{
1767
	struct net *net = sock_net(skb->sk);
1768 1769
	struct xfrm_state *x;
	int err;
1770
	struct xfrm_user_expire *ue = nlmsg_data(nlh);
1771 1772
	struct xfrm_usersa_info *p = &ue->state;

1773
	x = xfrm_state_lookup(net, DUMMY_MARK, &p->id.daddr, p->id.spi, p->id.proto, p->family);
1774

1775
	err = -ENOENT;
1776 1777 1778 1779
	if (x == NULL)
		return err;

	spin_lock_bh(&x->lock);
1780
	err = -EINVAL;
1781 1782 1783 1784
	if (x->km.state != XFRM_STATE_VALID)
		goto out;
	km_state_expired(x, ue->hard, current->pid);

J
Joy Latten 已提交
1785
	if (ue->hard) {
1786 1787 1788
		uid_t loginuid = NETLINK_CB(skb).loginuid;
		uid_t sessionid = NETLINK_CB(skb).sessionid;
		u32 sid = NETLINK_CB(skb).sid;
1789
		__xfrm_state_delete(x);
1790
		xfrm_audit_state_delete(x, 1, loginuid, sessionid, sid);
J
Joy Latten 已提交
1791
	}
1792
	err = 0;
1793 1794 1795 1796 1797 1798
out:
	spin_unlock_bh(&x->lock);
	xfrm_state_put(x);
	return err;
}

1799
static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh,
1800
		struct nlattr **attrs)
1801
{
1802
	struct net *net = sock_net(skb->sk);
1803 1804 1805
	struct xfrm_policy *xp;
	struct xfrm_user_tmpl *ut;
	int i;
1806
	struct nlattr *rt = attrs[XFRMA_TMPL];
1807

1808
	struct xfrm_user_acquire *ua = nlmsg_data(nlh);
1809
	struct xfrm_state *x = xfrm_state_alloc(net);
1810 1811 1812
	int err = -ENOMEM;

	if (!x)
I
Ilpo Järvinen 已提交
1813
		goto nomem;
1814 1815

	err = verify_newpolicy_info(&ua->policy);
I
Ilpo Järvinen 已提交
1816 1817
	if (err)
		goto bad_policy;
1818 1819

	/*   build an XP */
1820
	xp = xfrm_policy_construct(net, &ua->policy, attrs, &err);
I
Ilpo Järvinen 已提交
1821 1822
	if (!xp)
		goto free_state;
1823 1824 1825 1826 1827

	memcpy(&x->id, &ua->id, sizeof(ua->id));
	memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr));
	memcpy(&x->sel, &ua->sel, sizeof(ua->sel));

1828
	ut = nla_data(rt);
1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846
	/* extract the templates and for each call km_key */
	for (i = 0; i < xp->xfrm_nr; i++, ut++) {
		struct xfrm_tmpl *t = &xp->xfrm_vec[i];
		memcpy(&x->id, &t->id, sizeof(x->id));
		x->props.mode = t->mode;
		x->props.reqid = t->reqid;
		x->props.family = ut->family;
		t->aalgos = ua->aalgos;
		t->ealgos = ua->ealgos;
		t->calgos = ua->calgos;
		err = km_query(x, t, xp);

	}

	kfree(x);
	kfree(xp);

	return 0;
I
Ilpo Järvinen 已提交
1847 1848 1849 1850 1851 1852 1853

bad_policy:
	printk("BAD policy passed\n");
free_state:
	kfree(x);
nomem:
	return err;
1854 1855
}

1856 1857
#ifdef CONFIG_XFRM_MIGRATE
static int copy_from_user_migrate(struct xfrm_migrate *ma,
1858
				  struct xfrm_kmaddress *k,
1859
				  struct nlattr **attrs, int *num)
1860
{
1861
	struct nlattr *rt = attrs[XFRMA_MIGRATE];
1862 1863 1864
	struct xfrm_user_migrate *um;
	int i, num_migrate;

1865 1866 1867 1868 1869 1870 1871 1872 1873 1874
	if (k != NULL) {
		struct xfrm_user_kmaddress *uk;

		uk = nla_data(attrs[XFRMA_KMADDRESS]);
		memcpy(&k->local, &uk->local, sizeof(k->local));
		memcpy(&k->remote, &uk->remote, sizeof(k->remote));
		k->family = uk->family;
		k->reserved = uk->reserved;
	}

1875 1876
	um = nla_data(rt);
	num_migrate = nla_len(rt) / sizeof(*um);
1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899

	if (num_migrate <= 0 || num_migrate > XFRM_MAX_DEPTH)
		return -EINVAL;

	for (i = 0; i < num_migrate; i++, um++, ma++) {
		memcpy(&ma->old_daddr, &um->old_daddr, sizeof(ma->old_daddr));
		memcpy(&ma->old_saddr, &um->old_saddr, sizeof(ma->old_saddr));
		memcpy(&ma->new_daddr, &um->new_daddr, sizeof(ma->new_daddr));
		memcpy(&ma->new_saddr, &um->new_saddr, sizeof(ma->new_saddr));

		ma->proto = um->proto;
		ma->mode = um->mode;
		ma->reqid = um->reqid;

		ma->old_family = um->old_family;
		ma->new_family = um->new_family;
	}

	*num = i;
	return 0;
}

static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
1900
			   struct nlattr **attrs)
1901
{
1902
	struct xfrm_userpolicy_id *pi = nlmsg_data(nlh);
1903
	struct xfrm_migrate m[XFRM_MAX_DEPTH];
1904
	struct xfrm_kmaddress km, *kmp;
1905 1906 1907 1908
	u8 type;
	int err;
	int n = 0;

1909
	if (attrs[XFRMA_MIGRATE] == NULL)
1910
		return -EINVAL;
1911

1912 1913
	kmp = attrs[XFRMA_KMADDRESS] ? &km : NULL;

1914
	err = copy_from_user_policy_type(&type, attrs);
1915 1916 1917
	if (err)
		return err;

1918
	err = copy_from_user_migrate((struct xfrm_migrate *)m, kmp, attrs, &n);
1919 1920 1921 1922 1923 1924
	if (err)
		return err;

	if (!n)
		return 0;

1925
	xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp);
1926 1927 1928 1929 1930

	return 0;
}
#else
static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
1931
			   struct nlattr **attrs)
1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952
{
	return -ENOPROTOOPT;
}
#endif

#ifdef CONFIG_XFRM_MIGRATE
static int copy_to_user_migrate(struct xfrm_migrate *m, struct sk_buff *skb)
{
	struct xfrm_user_migrate um;

	memset(&um, 0, sizeof(um));
	um.proto = m->proto;
	um.mode = m->mode;
	um.reqid = m->reqid;
	um.old_family = m->old_family;
	memcpy(&um.old_daddr, &m->old_daddr, sizeof(um.old_daddr));
	memcpy(&um.old_saddr, &m->old_saddr, sizeof(um.old_saddr));
	um.new_family = m->new_family;
	memcpy(&um.new_daddr, &m->new_daddr, sizeof(um.new_daddr));
	memcpy(&um.new_saddr, &m->new_saddr, sizeof(um.new_saddr));

1953
	return nla_put(skb, XFRMA_MIGRATE, sizeof(um), &um);
1954 1955
}

1956 1957 1958 1959 1960 1961 1962 1963
static int copy_to_user_kmaddress(struct xfrm_kmaddress *k, struct sk_buff *skb)
{
	struct xfrm_user_kmaddress uk;

	memset(&uk, 0, sizeof(uk));
	uk.family = k->family;
	uk.reserved = k->reserved;
	memcpy(&uk.local, &k->local, sizeof(uk.local));
1964
	memcpy(&uk.remote, &k->remote, sizeof(uk.remote));
1965 1966 1967 1968 1969

	return nla_put(skb, XFRMA_KMADDRESS, sizeof(uk), &uk);
}

static inline size_t xfrm_migrate_msgsize(int num_migrate, int with_kma)
1970 1971
{
	return NLMSG_ALIGN(sizeof(struct xfrm_userpolicy_id))
1972 1973 1974
	      + (with_kma ? nla_total_size(sizeof(struct xfrm_kmaddress)) : 0)
	      + nla_total_size(sizeof(struct xfrm_user_migrate) * num_migrate)
	      + userpolicy_type_attrsize();
1975 1976
}

1977
static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m,
1978 1979
			 int num_migrate, struct xfrm_kmaddress *k,
			 struct xfrm_selector *sel, u8 dir, u8 type)
1980 1981 1982 1983 1984 1985
{
	struct xfrm_migrate *mp;
	struct xfrm_userpolicy_id *pol_id;
	struct nlmsghdr *nlh;
	int i;

1986 1987 1988
	nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_MIGRATE, sizeof(*pol_id), 0);
	if (nlh == NULL)
		return -EMSGSIZE;
1989

1990
	pol_id = nlmsg_data(nlh);
1991 1992 1993 1994 1995
	/* copy data from selector, dir, and type to the pol_id */
	memset(pol_id, 0, sizeof(*pol_id));
	memcpy(&pol_id->sel, sel, sizeof(pol_id->sel));
	pol_id->dir = dir;

1996 1997 1998
	if (k != NULL && (copy_to_user_kmaddress(k, skb) < 0))
			goto nlmsg_failure;

1999 2000 2001 2002 2003 2004 2005 2006
	if (copy_to_user_policy_type(type, skb) < 0)
		goto nlmsg_failure;

	for (i = 0, mp = m ; i < num_migrate; i++, mp++) {
		if (copy_to_user_migrate(mp, skb) < 0)
			goto nlmsg_failure;
	}

2007
	return nlmsg_end(skb, nlh);
2008
nlmsg_failure:
2009 2010
	nlmsg_cancel(skb, nlh);
	return -EMSGSIZE;
2011 2012 2013
}

static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
2014 2015
			     struct xfrm_migrate *m, int num_migrate,
			     struct xfrm_kmaddress *k)
2016
{
2017
	struct net *net = &init_net;
2018 2019
	struct sk_buff *skb;

2020
	skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate, !!k), GFP_ATOMIC);
2021 2022 2023 2024
	if (skb == NULL)
		return -ENOMEM;

	/* build migrate */
2025
	if (build_migrate(skb, m, num_migrate, k, sel, dir, type) < 0)
2026 2027
		BUG();

2028
	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_MIGRATE, GFP_ATOMIC);
2029 2030 2031
}
#else
static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
2032 2033
			     struct xfrm_migrate *m, int num_migrate,
			     struct xfrm_kmaddress *k)
2034 2035 2036 2037
{
	return -ENOPROTOOPT;
}
#endif
J
Jamal Hadi Salim 已提交
2038

2039
#define XMSGSIZE(type) sizeof(struct type)
2040 2041

static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
2042
	[XFRM_MSG_NEWSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info),
2043 2044 2045 2046 2047 2048
	[XFRM_MSG_DELSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id),
	[XFRM_MSG_GETSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id),
	[XFRM_MSG_NEWPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info),
	[XFRM_MSG_DELPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
	[XFRM_MSG_GETPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
	[XFRM_MSG_ALLOCSPI    - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userspi_info),
2049
	[XFRM_MSG_ACQUIRE     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_acquire),
2050
	[XFRM_MSG_EXPIRE      - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_expire),
2051
	[XFRM_MSG_UPDPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info),
2052
	[XFRM_MSG_UPDSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info),
2053
	[XFRM_MSG_POLEXPIRE   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire),
2054
	[XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush),
2055
	[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = 0,
J
Jamal Hadi Salim 已提交
2056 2057
	[XFRM_MSG_NEWAE       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
	[XFRM_MSG_GETAE       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
2058
	[XFRM_MSG_REPORT      - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report),
2059
	[XFRM_MSG_MIGRATE     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
2060 2061
	[XFRM_MSG_GETSADINFO  - XFRM_MSG_BASE] = sizeof(u32),
	[XFRM_MSG_GETSPDINFO  - XFRM_MSG_BASE] = sizeof(u32),
L
Linus Torvalds 已提交
2062 2063
};

2064 2065
#undef XMSGSIZE

2066
static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
J
jamal 已提交
2067 2068 2069 2070
	[XFRMA_SA]		= { .len = sizeof(struct xfrm_usersa_info)},
	[XFRMA_POLICY]		= { .len = sizeof(struct xfrm_userpolicy_info)},
	[XFRMA_LASTUSED]	= { .type = NLA_U64},
	[XFRMA_ALG_AUTH_TRUNC]	= { .len = sizeof(struct xfrm_algo_auth)},
2071
	[XFRMA_ALG_AEAD]	= { .len = sizeof(struct xfrm_algo_aead) },
2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085
	[XFRMA_ALG_AUTH]	= { .len = sizeof(struct xfrm_algo) },
	[XFRMA_ALG_CRYPT]	= { .len = sizeof(struct xfrm_algo) },
	[XFRMA_ALG_COMP]	= { .len = sizeof(struct xfrm_algo) },
	[XFRMA_ENCAP]		= { .len = sizeof(struct xfrm_encap_tmpl) },
	[XFRMA_TMPL]		= { .len = sizeof(struct xfrm_user_tmpl) },
	[XFRMA_SEC_CTX]		= { .len = sizeof(struct xfrm_sec_ctx) },
	[XFRMA_LTIME_VAL]	= { .len = sizeof(struct xfrm_lifetime_cur) },
	[XFRMA_REPLAY_VAL]	= { .len = sizeof(struct xfrm_replay_state) },
	[XFRMA_REPLAY_THRESH]	= { .type = NLA_U32 },
	[XFRMA_ETIMER_THRESH]	= { .type = NLA_U32 },
	[XFRMA_SRCADDR]		= { .len = sizeof(xfrm_address_t) },
	[XFRMA_COADDR]		= { .len = sizeof(xfrm_address_t) },
	[XFRMA_POLICY_TYPE]	= { .len = sizeof(struct xfrm_userpolicy_type)},
	[XFRMA_MIGRATE]		= { .len = sizeof(struct xfrm_user_migrate) },
2086
	[XFRMA_KMADDRESS]	= { .len = sizeof(struct xfrm_user_kmaddress) },
2087 2088
};

L
Linus Torvalds 已提交
2089
static struct xfrm_link {
2090
	int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);
L
Linus Torvalds 已提交
2091
	int (*dump)(struct sk_buff *, struct netlink_callback *);
2092
	int (*done)(struct netlink_callback *);
2093 2094 2095 2096
} xfrm_dispatch[XFRM_NR_MSGTYPES] = {
	[XFRM_MSG_NEWSA       - XFRM_MSG_BASE] = { .doit = xfrm_add_sa        },
	[XFRM_MSG_DELSA       - XFRM_MSG_BASE] = { .doit = xfrm_del_sa        },
	[XFRM_MSG_GETSA       - XFRM_MSG_BASE] = { .doit = xfrm_get_sa,
2097 2098
						   .dump = xfrm_dump_sa,
						   .done = xfrm_dump_sa_done  },
2099 2100 2101
	[XFRM_MSG_NEWPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_add_policy    },
	[XFRM_MSG_DELPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_get_policy    },
	[XFRM_MSG_GETPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_get_policy,
2102 2103
						   .dump = xfrm_dump_policy,
						   .done = xfrm_dump_policy_done },
2104
	[XFRM_MSG_ALLOCSPI    - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi },
2105
	[XFRM_MSG_ACQUIRE     - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire   },
2106
	[XFRM_MSG_EXPIRE      - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire },
2107 2108
	[XFRM_MSG_UPDPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_add_policy    },
	[XFRM_MSG_UPDSA       - XFRM_MSG_BASE] = { .doit = xfrm_add_sa        },
2109
	[XFRM_MSG_POLEXPIRE   - XFRM_MSG_BASE] = { .doit = xfrm_add_pol_expire},
2110 2111
	[XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa      },
	[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy  },
J
Jamal Hadi Salim 已提交
2112 2113
	[XFRM_MSG_NEWAE       - XFRM_MSG_BASE] = { .doit = xfrm_new_ae  },
	[XFRM_MSG_GETAE       - XFRM_MSG_BASE] = { .doit = xfrm_get_ae  },
2114
	[XFRM_MSG_MIGRATE     - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate    },
2115
	[XFRM_MSG_GETSADINFO  - XFRM_MSG_BASE] = { .doit = xfrm_get_sadinfo   },
J
Jamal Hadi Salim 已提交
2116
	[XFRM_MSG_GETSPDINFO  - XFRM_MSG_BASE] = { .doit = xfrm_get_spdinfo   },
L
Linus Torvalds 已提交
2117 2118
};

2119
static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
L
Linus Torvalds 已提交
2120
{
2121
	struct net *net = sock_net(skb->sk);
2122
	struct nlattr *attrs[XFRMA_MAX+1];
L
Linus Torvalds 已提交
2123
	struct xfrm_link *link;
2124
	int type, err;
L
Linus Torvalds 已提交
2125 2126 2127

	type = nlh->nlmsg_type;
	if (type > XFRM_MSG_MAX)
2128
		return -EINVAL;
L
Linus Torvalds 已提交
2129 2130 2131 2132 2133

	type -= XFRM_MSG_BASE;
	link = &xfrm_dispatch[type];

	/* All operations require privileges, even GET */
2134 2135
	if (security_netlink_recv(skb, CAP_NET_ADMIN))
		return -EPERM;
L
Linus Torvalds 已提交
2136

2137 2138 2139
	if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) ||
	     type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) &&
	    (nlh->nlmsg_flags & NLM_F_DUMP)) {
L
Linus Torvalds 已提交
2140
		if (link->dump == NULL)
2141
			return -EINVAL;
2142

2143
		return netlink_dump_start(net->xfrm.nlsk, skb, nlh, link->dump, link->done);
L
Linus Torvalds 已提交
2144 2145
	}

2146
	err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX,
2147
			  xfrma_policy);
2148 2149
	if (err < 0)
		return err;
L
Linus Torvalds 已提交
2150 2151

	if (link->doit == NULL)
2152
		return -EINVAL;
L
Linus Torvalds 已提交
2153

2154
	return link->doit(skb, nlh, attrs);
L
Linus Torvalds 已提交
2155 2156
}

2157
static void xfrm_netlink_rcv(struct sk_buff *skb)
L
Linus Torvalds 已提交
2158
{
2159 2160 2161
	mutex_lock(&xfrm_cfg_mutex);
	netlink_rcv_skb(skb, &xfrm_user_rcv_msg);
	mutex_unlock(&xfrm_cfg_mutex);
L
Linus Torvalds 已提交
2162 2163
}

2164 2165 2166 2167 2168
static inline size_t xfrm_expire_msgsize(void)
{
	return NLMSG_ALIGN(sizeof(struct xfrm_user_expire));
}

J
Jamal Hadi Salim 已提交
2169
static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c)
L
Linus Torvalds 已提交
2170 2171 2172 2173
{
	struct xfrm_user_expire *ue;
	struct nlmsghdr *nlh;

2174 2175 2176
	nlh = nlmsg_put(skb, c->pid, 0, XFRM_MSG_EXPIRE, sizeof(*ue), 0);
	if (nlh == NULL)
		return -EMSGSIZE;
L
Linus Torvalds 已提交
2177

2178
	ue = nlmsg_data(nlh);
L
Linus Torvalds 已提交
2179
	copy_to_user_state(x, &ue->state);
J
Jamal Hadi Salim 已提交
2180
	ue->hard = (c->data.hard != 0) ? 1 : 0;
L
Linus Torvalds 已提交
2181

2182
	return nlmsg_end(skb, nlh);
L
Linus Torvalds 已提交
2183 2184
}

2185
static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c)
L
Linus Torvalds 已提交
2186
{
2187
	struct net *net = xs_net(x);
L
Linus Torvalds 已提交
2188 2189
	struct sk_buff *skb;

2190
	skb = nlmsg_new(xfrm_expire_msgsize(), GFP_ATOMIC);
L
Linus Torvalds 已提交
2191 2192 2193
	if (skb == NULL)
		return -ENOMEM;

J
Jamal Hadi Salim 已提交
2194
	if (build_expire(skb, x, c) < 0)
L
Linus Torvalds 已提交
2195 2196
		BUG();

2197
	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC);
L
Linus Torvalds 已提交
2198 2199
}

J
Jamal Hadi Salim 已提交
2200 2201
static int xfrm_aevent_state_notify(struct xfrm_state *x, struct km_event *c)
{
2202
	struct net *net = xs_net(x);
J
Jamal Hadi Salim 已提交
2203 2204
	struct sk_buff *skb;

2205
	skb = nlmsg_new(xfrm_aevent_msgsize(), GFP_ATOMIC);
J
Jamal Hadi Salim 已提交
2206 2207 2208 2209 2210 2211
	if (skb == NULL)
		return -ENOMEM;

	if (build_aevent(skb, x, c) < 0)
		BUG();

2212
	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_AEVENTS, GFP_ATOMIC);
J
Jamal Hadi Salim 已提交
2213 2214
}

2215 2216
static int xfrm_notify_sa_flush(struct km_event *c)
{
2217
	struct net *net = c->net;
2218 2219 2220
	struct xfrm_usersa_flush *p;
	struct nlmsghdr *nlh;
	struct sk_buff *skb;
2221
	int len = NLMSG_ALIGN(sizeof(struct xfrm_usersa_flush));
2222

2223
	skb = nlmsg_new(len, GFP_ATOMIC);
2224 2225 2226
	if (skb == NULL)
		return -ENOMEM;

2227 2228 2229 2230 2231
	nlh = nlmsg_put(skb, c->pid, c->seq, XFRM_MSG_FLUSHSA, sizeof(*p), 0);
	if (nlh == NULL) {
		kfree_skb(skb);
		return -EMSGSIZE;
	}
2232

2233
	p = nlmsg_data(nlh);
2234
	p->proto = c->data.proto;
2235

2236
	nlmsg_end(skb, nlh);
2237

2238
	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC);
2239 2240
}

2241
static inline size_t xfrm_sa_len(struct xfrm_state *x)
2242
{
2243
	size_t l = 0;
2244 2245
	if (x->aead)
		l += nla_total_size(aead_len(x->aead));
2246 2247 2248 2249 2250
	if (x->aalg) {
		l += nla_total_size(sizeof(struct xfrm_algo) +
				    (x->aalg->alg_key_len + 7) / 8);
		l += nla_total_size(xfrm_alg_auth_len(x->aalg));
	}
2251
	if (x->ealg)
2252
		l += nla_total_size(xfrm_alg_len(x->ealg));
2253
	if (x->calg)
2254
		l += nla_total_size(sizeof(*x->calg));
2255
	if (x->encap)
2256
		l += nla_total_size(sizeof(*x->encap));
2257 2258 2259 2260 2261 2262
	if (x->security)
		l += nla_total_size(sizeof(struct xfrm_user_sec_ctx) +
				    x->security->ctx_len);
	if (x->coaddr)
		l += nla_total_size(sizeof(*x->coaddr));

2263 2264
	/* Must count x->lastused as it may become non-zero behind our back. */
	l += nla_total_size(sizeof(u64));
2265 2266 2267 2268 2269 2270

	return l;
}

static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c)
{
2271
	struct net *net = xs_net(x);
2272
	struct xfrm_usersa_info *p;
2273
	struct xfrm_usersa_id *id;
2274 2275 2276
	struct nlmsghdr *nlh;
	struct sk_buff *skb;
	int len = xfrm_sa_len(x);
2277 2278 2279 2280
	int headlen;

	headlen = sizeof(*p);
	if (c->event == XFRM_MSG_DELSA) {
2281
		len += nla_total_size(headlen);
2282 2283
		headlen = sizeof(*id);
	}
2284
	len += NLMSG_ALIGN(headlen);
2285

2286
	skb = nlmsg_new(len, GFP_ATOMIC);
2287 2288 2289
	if (skb == NULL)
		return -ENOMEM;

2290 2291
	nlh = nlmsg_put(skb, c->pid, c->seq, c->event, headlen, 0);
	if (nlh == NULL)
2292
		goto nla_put_failure;
2293

2294
	p = nlmsg_data(nlh);
2295
	if (c->event == XFRM_MSG_DELSA) {
2296 2297
		struct nlattr *attr;

2298
		id = nlmsg_data(nlh);
2299 2300 2301 2302 2303
		memcpy(&id->daddr, &x->id.daddr, sizeof(id->daddr));
		id->spi = x->id.spi;
		id->family = x->props.family;
		id->proto = x->id.proto;

2304 2305 2306 2307 2308
		attr = nla_reserve(skb, XFRMA_SA, sizeof(*p));
		if (attr == NULL)
			goto nla_put_failure;

		p = nla_data(attr);
2309 2310
	}

2311 2312
	if (copy_to_user_state_extra(x, p, skb))
		goto nla_put_failure;
2313

2314
	nlmsg_end(skb, nlh);
2315

2316
	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC);
2317

2318
nla_put_failure:
2319 2320
	/* Somebody screwed up with xfrm_sa_len! */
	WARN_ON(1);
2321 2322 2323 2324 2325 2326 2327 2328
	kfree_skb(skb);
	return -1;
}

static int xfrm_send_state_notify(struct xfrm_state *x, struct km_event *c)
{

	switch (c->event) {
2329
	case XFRM_MSG_EXPIRE:
2330
		return xfrm_exp_state_notify(x, c);
J
Jamal Hadi Salim 已提交
2331 2332
	case XFRM_MSG_NEWAE:
		return xfrm_aevent_state_notify(x, c);
2333 2334 2335
	case XFRM_MSG_DELSA:
	case XFRM_MSG_UPDSA:
	case XFRM_MSG_NEWSA:
2336
		return xfrm_notify_sa(x, c);
2337
	case XFRM_MSG_FLUSHSA:
2338 2339 2340 2341 2342 2343 2344 2345 2346 2347
		return xfrm_notify_sa_flush(c);
	default:
		 printk("xfrm_user: Unknown SA event %d\n", c->event);
		 break;
	}

	return 0;

}

2348 2349 2350 2351 2352 2353 2354 2355 2356
static inline size_t xfrm_acquire_msgsize(struct xfrm_state *x,
					  struct xfrm_policy *xp)
{
	return NLMSG_ALIGN(sizeof(struct xfrm_user_acquire))
	       + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr)
	       + nla_total_size(xfrm_user_sec_ctx_size(x->security))
	       + userpolicy_type_attrsize();
}

L
Linus Torvalds 已提交
2357 2358 2359 2360 2361 2362 2363 2364
static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,
			 struct xfrm_tmpl *xt, struct xfrm_policy *xp,
			 int dir)
{
	struct xfrm_user_acquire *ua;
	struct nlmsghdr *nlh;
	__u32 seq = xfrm_get_acqseq();

2365 2366 2367
	nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_ACQUIRE, sizeof(*ua), 0);
	if (nlh == NULL)
		return -EMSGSIZE;
L
Linus Torvalds 已提交
2368

2369
	ua = nlmsg_data(nlh);
L
Linus Torvalds 已提交
2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380
	memcpy(&ua->id, &x->id, sizeof(ua->id));
	memcpy(&ua->saddr, &x->props.saddr, sizeof(ua->saddr));
	memcpy(&ua->sel, &x->sel, sizeof(ua->sel));
	copy_to_user_policy(xp, &ua->policy, dir);
	ua->aalgos = xt->aalgos;
	ua->ealgos = xt->ealgos;
	ua->calgos = xt->calgos;
	ua->seq = x->km.seq = seq;

	if (copy_to_user_tmpl(xp, skb) < 0)
		goto nlmsg_failure;
2381
	if (copy_to_user_state_sec_ctx(x, skb))
2382
		goto nlmsg_failure;
2383
	if (copy_to_user_policy_type(xp->type, skb) < 0)
2384
		goto nlmsg_failure;
L
Linus Torvalds 已提交
2385

2386
	return nlmsg_end(skb, nlh);
L
Linus Torvalds 已提交
2387 2388

nlmsg_failure:
2389 2390
	nlmsg_cancel(skb, nlh);
	return -EMSGSIZE;
L
Linus Torvalds 已提交
2391 2392 2393 2394 2395
}

static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt,
			     struct xfrm_policy *xp, int dir)
{
2396
	struct net *net = xs_net(x);
L
Linus Torvalds 已提交
2397 2398
	struct sk_buff *skb;

2399
	skb = nlmsg_new(xfrm_acquire_msgsize(x, xp), GFP_ATOMIC);
L
Linus Torvalds 已提交
2400 2401 2402 2403 2404 2405
	if (skb == NULL)
		return -ENOMEM;

	if (build_acquire(skb, x, xt, xp, dir) < 0)
		BUG();

2406
	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_ACQUIRE, GFP_ATOMIC);
L
Linus Torvalds 已提交
2407 2408 2409 2410 2411
}

/* User gives us xfrm_user_policy_info followed by an array of 0
 * or more templates.
 */
2412
static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt,
L
Linus Torvalds 已提交
2413 2414
					       u8 *data, int len, int *dir)
{
2415
	struct net *net = sock_net(sk);
L
Linus Torvalds 已提交
2416 2417 2418 2419 2420
	struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data;
	struct xfrm_user_tmpl *ut = (struct xfrm_user_tmpl *) (p + 1);
	struct xfrm_policy *xp;
	int nr;

2421
	switch (sk->sk_family) {
L
Linus Torvalds 已提交
2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447
	case AF_INET:
		if (opt != IP_XFRM_POLICY) {
			*dir = -EOPNOTSUPP;
			return NULL;
		}
		break;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
	case AF_INET6:
		if (opt != IPV6_XFRM_POLICY) {
			*dir = -EOPNOTSUPP;
			return NULL;
		}
		break;
#endif
	default:
		*dir = -EINVAL;
		return NULL;
	}

	*dir = -EINVAL;

	if (len < sizeof(*p) ||
	    verify_newpolicy_info(p))
		return NULL;

	nr = ((len - sizeof(*p)) / sizeof(*ut));
2448
	if (validate_tmpl(nr, ut, p->sel.family))
L
Linus Torvalds 已提交
2449 2450
		return NULL;

2451 2452 2453
	if (p->dir > XFRM_POLICY_OUT)
		return NULL;

2454
	xp = xfrm_policy_alloc(net, GFP_KERNEL);
L
Linus Torvalds 已提交
2455 2456 2457 2458 2459 2460
	if (xp == NULL) {
		*dir = -ENOBUFS;
		return NULL;
	}

	copy_from_user_policy(xp, p);
2461
	xp->type = XFRM_POLICY_TYPE_MAIN;
L
Linus Torvalds 已提交
2462 2463 2464 2465 2466 2467 2468
	copy_templates(xp, ut, nr);

	*dir = p->dir;

	return xp;
}

2469 2470 2471 2472 2473 2474 2475 2476
static inline size_t xfrm_polexpire_msgsize(struct xfrm_policy *xp)
{
	return NLMSG_ALIGN(sizeof(struct xfrm_user_polexpire))
	       + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr)
	       + nla_total_size(xfrm_user_sec_ctx_size(xp->security))
	       + userpolicy_type_attrsize();
}

L
Linus Torvalds 已提交
2477
static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp,
J
Jamal Hadi Salim 已提交
2478
			   int dir, struct km_event *c)
L
Linus Torvalds 已提交
2479 2480 2481
{
	struct xfrm_user_polexpire *upe;
	struct nlmsghdr *nlh;
J
Jamal Hadi Salim 已提交
2482
	int hard = c->data.hard;
L
Linus Torvalds 已提交
2483

2484 2485 2486
	nlh = nlmsg_put(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe), 0);
	if (nlh == NULL)
		return -EMSGSIZE;
L
Linus Torvalds 已提交
2487

2488
	upe = nlmsg_data(nlh);
L
Linus Torvalds 已提交
2489 2490 2491
	copy_to_user_policy(xp, &upe->pol, dir);
	if (copy_to_user_tmpl(xp, skb) < 0)
		goto nlmsg_failure;
2492 2493
	if (copy_to_user_sec_ctx(xp, skb))
		goto nlmsg_failure;
2494
	if (copy_to_user_policy_type(xp->type, skb) < 0)
2495
		goto nlmsg_failure;
L
Linus Torvalds 已提交
2496 2497
	upe->hard = !!hard;

2498
	return nlmsg_end(skb, nlh);
L
Linus Torvalds 已提交
2499 2500

nlmsg_failure:
2501 2502
	nlmsg_cancel(skb, nlh);
	return -EMSGSIZE;
L
Linus Torvalds 已提交
2503 2504
}

2505
static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
L
Linus Torvalds 已提交
2506
{
2507
	struct net *net = xp_net(xp);
L
Linus Torvalds 已提交
2508 2509
	struct sk_buff *skb;

2510
	skb = nlmsg_new(xfrm_polexpire_msgsize(xp), GFP_ATOMIC);
L
Linus Torvalds 已提交
2511 2512 2513
	if (skb == NULL)
		return -ENOMEM;

J
Jamal Hadi Salim 已提交
2514
	if (build_polexpire(skb, xp, dir, c) < 0)
L
Linus Torvalds 已提交
2515 2516
		BUG();

2517
	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC);
L
Linus Torvalds 已提交
2518 2519
}

2520 2521
static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c)
{
2522
	struct net *net = xp_net(xp);
2523
	struct xfrm_userpolicy_info *p;
2524
	struct xfrm_userpolicy_id *id;
2525 2526
	struct nlmsghdr *nlh;
	struct sk_buff *skb;
2527
	int len = nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr);
2528 2529 2530 2531
	int headlen;

	headlen = sizeof(*p);
	if (c->event == XFRM_MSG_DELPOLICY) {
2532
		len += nla_total_size(headlen);
2533 2534
		headlen = sizeof(*id);
	}
2535
	len += userpolicy_type_attrsize();
2536
	len += NLMSG_ALIGN(headlen);
2537

2538
	skb = nlmsg_new(len, GFP_ATOMIC);
2539 2540 2541
	if (skb == NULL)
		return -ENOMEM;

2542 2543 2544
	nlh = nlmsg_put(skb, c->pid, c->seq, c->event, headlen, 0);
	if (nlh == NULL)
		goto nlmsg_failure;
2545

2546
	p = nlmsg_data(nlh);
2547
	if (c->event == XFRM_MSG_DELPOLICY) {
2548 2549
		struct nlattr *attr;

2550
		id = nlmsg_data(nlh);
2551 2552 2553 2554 2555 2556 2557
		memset(id, 0, sizeof(*id));
		id->dir = dir;
		if (c->data.byid)
			id->index = xp->index;
		else
			memcpy(&id->sel, &xp->selector, sizeof(id->sel));

2558 2559 2560 2561 2562
		attr = nla_reserve(skb, XFRMA_POLICY, sizeof(*p));
		if (attr == NULL)
			goto nlmsg_failure;

		p = nla_data(attr);
2563
	}
2564 2565 2566 2567

	copy_to_user_policy(xp, p, dir);
	if (copy_to_user_tmpl(xp, skb) < 0)
		goto nlmsg_failure;
2568
	if (copy_to_user_policy_type(xp->type, skb) < 0)
2569
		goto nlmsg_failure;
2570

2571
	nlmsg_end(skb, nlh);
2572

2573
	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC);
2574 2575 2576 2577 2578 2579 2580 2581

nlmsg_failure:
	kfree_skb(skb);
	return -1;
}

static int xfrm_notify_policy_flush(struct km_event *c)
{
2582
	struct net *net = c->net;
2583 2584 2585
	struct nlmsghdr *nlh;
	struct sk_buff *skb;

2586
	skb = nlmsg_new(userpolicy_type_attrsize(), GFP_ATOMIC);
2587 2588 2589
	if (skb == NULL)
		return -ENOMEM;

2590 2591 2592
	nlh = nlmsg_put(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0, 0);
	if (nlh == NULL)
		goto nlmsg_failure;
2593 2594
	if (copy_to_user_policy_type(c->data.type, skb) < 0)
		goto nlmsg_failure;
2595

2596
	nlmsg_end(skb, nlh);
2597

2598
	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC);
2599 2600 2601 2602 2603 2604 2605 2606 2607 2608

nlmsg_failure:
	kfree_skb(skb);
	return -1;
}

static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
{

	switch (c->event) {
2609 2610 2611
	case XFRM_MSG_NEWPOLICY:
	case XFRM_MSG_UPDPOLICY:
	case XFRM_MSG_DELPOLICY:
2612
		return xfrm_notify_policy(xp, dir, c);
2613
	case XFRM_MSG_FLUSHPOLICY:
2614
		return xfrm_notify_policy_flush(c);
2615
	case XFRM_MSG_POLEXPIRE:
2616 2617 2618 2619 2620 2621 2622 2623 2624
		return xfrm_exp_policy_notify(xp, dir, c);
	default:
		printk("xfrm_user: Unknown Policy event %d\n", c->event);
	}

	return 0;

}

2625 2626 2627 2628 2629
static inline size_t xfrm_report_msgsize(void)
{
	return NLMSG_ALIGN(sizeof(struct xfrm_user_report));
}

2630 2631 2632 2633 2634 2635
static int build_report(struct sk_buff *skb, u8 proto,
			struct xfrm_selector *sel, xfrm_address_t *addr)
{
	struct xfrm_user_report *ur;
	struct nlmsghdr *nlh;

2636 2637 2638
	nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur), 0);
	if (nlh == NULL)
		return -EMSGSIZE;
2639

2640
	ur = nlmsg_data(nlh);
2641 2642 2643 2644
	ur->proto = proto;
	memcpy(&ur->sel, sel, sizeof(ur->sel));

	if (addr)
2645
		NLA_PUT(skb, XFRMA_COADDR, sizeof(*addr), addr);
2646

2647
	return nlmsg_end(skb, nlh);
2648

2649
nla_put_failure:
2650 2651
	nlmsg_cancel(skb, nlh);
	return -EMSGSIZE;
2652 2653
}

2654 2655
static int xfrm_send_report(struct net *net, u8 proto,
			    struct xfrm_selector *sel, xfrm_address_t *addr)
2656 2657 2658
{
	struct sk_buff *skb;

2659
	skb = nlmsg_new(xfrm_report_msgsize(), GFP_ATOMIC);
2660 2661 2662 2663 2664 2665
	if (skb == NULL)
		return -ENOMEM;

	if (build_report(skb, proto, sel, addr) < 0)
		BUG();

2666
	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_REPORT, GFP_ATOMIC);
2667 2668
}

2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701
static inline size_t xfrm_mapping_msgsize(void)
{
	return NLMSG_ALIGN(sizeof(struct xfrm_user_mapping));
}

static int build_mapping(struct sk_buff *skb, struct xfrm_state *x,
			 xfrm_address_t *new_saddr, __be16 new_sport)
{
	struct xfrm_user_mapping *um;
	struct nlmsghdr *nlh;

	nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_MAPPING, sizeof(*um), 0);
	if (nlh == NULL)
		return -EMSGSIZE;

	um = nlmsg_data(nlh);

	memcpy(&um->id.daddr, &x->id.daddr, sizeof(um->id.daddr));
	um->id.spi = x->id.spi;
	um->id.family = x->props.family;
	um->id.proto = x->id.proto;
	memcpy(&um->new_saddr, new_saddr, sizeof(um->new_saddr));
	memcpy(&um->old_saddr, &x->props.saddr, sizeof(um->old_saddr));
	um->new_sport = new_sport;
	um->old_sport = x->encap->encap_sport;
	um->reqid = x->props.reqid;

	return nlmsg_end(skb, nlh);
}

static int xfrm_send_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr,
			     __be16 sport)
{
2702
	struct net *net = xs_net(x);
2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717
	struct sk_buff *skb;

	if (x->id.proto != IPPROTO_ESP)
		return -EINVAL;

	if (!x->encap)
		return -EINVAL;

	skb = nlmsg_new(xfrm_mapping_msgsize(), GFP_ATOMIC);
	if (skb == NULL)
		return -ENOMEM;

	if (build_mapping(skb, x, ipaddr, sport) < 0)
		BUG();

2718
	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_MAPPING, GFP_ATOMIC);
2719 2720
}

L
Linus Torvalds 已提交
2721 2722 2723 2724 2725 2726
static struct xfrm_mgr netlink_mgr = {
	.id		= "netlink",
	.notify		= xfrm_send_state_notify,
	.acquire	= xfrm_send_acquire,
	.compile_policy	= xfrm_compile_policy,
	.notify_policy	= xfrm_send_policy_notify,
2727
	.report		= xfrm_send_report,
2728
	.migrate	= xfrm_send_migrate,
2729
	.new_mapping	= xfrm_send_mapping,
L
Linus Torvalds 已提交
2730 2731
};

2732
static int __net_init xfrm_user_net_init(struct net *net)
L
Linus Torvalds 已提交
2733
{
2734 2735
	struct sock *nlsk;

2736
	nlsk = netlink_kernel_create(net, NETLINK_XFRM, XFRMNLGRP_MAX,
2737
				     xfrm_netlink_rcv, NULL, THIS_MODULE);
2738
	if (nlsk == NULL)
L
Linus Torvalds 已提交
2739
		return -ENOMEM;
2740
	net->xfrm.nlsk_stash = nlsk; /* Don't set to NULL */
2741
	rcu_assign_pointer(net->xfrm.nlsk, nlsk);
L
Linus Torvalds 已提交
2742 2743 2744
	return 0;
}

2745
static void __net_exit xfrm_user_net_exit(struct list_head *net_exit_list)
L
Linus Torvalds 已提交
2746
{
2747 2748 2749 2750 2751 2752
	struct net *net;
	list_for_each_entry(net, net_exit_list, exit_list)
		rcu_assign_pointer(net->xfrm.nlsk, NULL);
	synchronize_net();
	list_for_each_entry(net, net_exit_list, exit_list)
		netlink_kernel_release(net->xfrm.nlsk_stash);
L
Linus Torvalds 已提交
2753 2754
}

2755
static struct pernet_operations xfrm_user_net_ops = {
2756 2757
	.init	    = xfrm_user_net_init,
	.exit_batch = xfrm_user_net_exit,
2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780
};

static int __init xfrm_user_init(void)
{
	int rv;

	printk(KERN_INFO "Initializing XFRM netlink socket\n");

	rv = register_pernet_subsys(&xfrm_user_net_ops);
	if (rv < 0)
		return rv;
	rv = xfrm_register_km(&netlink_mgr);
	if (rv < 0)
		unregister_pernet_subsys(&xfrm_user_net_ops);
	return rv;
}

static void __exit xfrm_user_exit(void)
{
	xfrm_unregister_km(&netlink_mgr);
	unregister_pernet_subsys(&xfrm_user_net_ops);
}

L
Linus Torvalds 已提交
2781 2782 2783
module_init(xfrm_user_init);
module_exit(xfrm_user_exit);
MODULE_LICENSE("GPL");
2784
MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM);
2785