xfrm_user.c 72.9 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>
29
#include <net/ah.h>
L
Linus Torvalds 已提交
30
#include <asm/uaccess.h>
E
Eric Dumazet 已提交
31
#if IS_ENABLED(CONFIG_IPV6)
32 33
#include <linux/in6.h>
#endif
L
Linus Torvalds 已提交
34

35
static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
L
Linus Torvalds 已提交
36
{
37
	struct nlattr *rt = attrs[type];
L
Linus Torvalds 已提交
38 39 40 41 42
	struct xfrm_algo *algp;

	if (!rt)
		return 0;

43
	algp = nla_data(rt);
44
	if (nla_len(rt) < xfrm_alg_len(algp))
45 46
		return -EINVAL;

L
Linus Torvalds 已提交
47 48 49 50 51 52 53 54
	switch (type) {
	case XFRMA_ALG_AUTH:
	case XFRMA_ALG_CRYPT:
	case XFRMA_ALG_COMP:
		break;

	default:
		return -EINVAL;
55
	}
L
Linus Torvalds 已提交
56 57 58 59 60

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

61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
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;
}

77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
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;
}

93
static void verify_one_addr(struct nlattr **attrs, enum xfrm_attr_type_t type,
94 95
			   xfrm_address_t **addrp)
{
96
	struct nlattr *rt = attrs[type];
97

98
	if (rt && addrp)
99
		*addrp = nla_data(rt);
100
}
101

102
static inline int verify_sec_ctx_len(struct nlattr **attrs)
103
{
104
	struct nlattr *rt = attrs[XFRMA_SEC_CTX];
105 106 107 108 109
	struct xfrm_user_sec_ctx *uctx;

	if (!rt)
		return 0;

110
	uctx = nla_data(rt);
111
	if (uctx->len != (sizeof(struct xfrm_user_sec_ctx) + uctx->ctx_len))
112 113 114 115 116
		return -EINVAL;

	return 0;
}

117 118 119 120
static inline int verify_replay(struct xfrm_usersa_info *p,
				struct nlattr **attrs)
{
	struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL];
121
	struct xfrm_replay_state_esn *rs;
122

123 124 125 126 127 128 129 130 131 132 133 134 135
	if (p->flags & XFRM_STATE_ESN) {
		if (!rt)
			return -EINVAL;

		rs = nla_data(rt);

		if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8)
			return -EINVAL;

		if (nla_len(rt) < xfrm_replay_state_esn_len(rs) &&
		    nla_len(rt) != sizeof(*rs))
			return -EINVAL;
	}
136

137 138 139
	if (!rt)
		return 0;

140 141
	/* As only ESP and AH support ESN feature. */
	if ((p->id.proto != IPPROTO_ESP) && (p->id.proto != IPPROTO_AH))
142 143
		return -EINVAL;

144 145 146 147 148
	if (p->replay_window != 0)
		return -EINVAL;

	return 0;
}
149

L
Linus Torvalds 已提交
150
static int verify_newsa_info(struct xfrm_usersa_info *p,
151
			     struct nlattr **attrs)
L
Linus Torvalds 已提交
152 153 154 155 156 157 158 159 160
{
	int err;

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

	case AF_INET6:
E
Eric Dumazet 已提交
161
#if IS_ENABLED(CONFIG_IPV6)
L
Linus Torvalds 已提交
162 163 164 165 166 167 168 169
		break;
#else
		err = -EAFNOSUPPORT;
		goto out;
#endif

	default:
		goto out;
170
	}
L
Linus Torvalds 已提交
171 172 173 174

	err = -EINVAL;
	switch (p->id.proto) {
	case IPPROTO_AH:
175 176
		if ((!attrs[XFRMA_ALG_AUTH]	&&
		     !attrs[XFRMA_ALG_AUTH_TRUNC]) ||
177
		    attrs[XFRMA_ALG_AEAD]	||
178
		    attrs[XFRMA_ALG_CRYPT]	||
179
		    attrs[XFRMA_ALG_COMP]	||
180
		    attrs[XFRMA_TFCPAD])
L
Linus Torvalds 已提交
181 182 183 184
			goto out;
		break;

	case IPPROTO_ESP:
185 186 187
		if (attrs[XFRMA_ALG_COMP])
			goto out;
		if (!attrs[XFRMA_ALG_AUTH] &&
188
		    !attrs[XFRMA_ALG_AUTH_TRUNC] &&
189 190 191 192
		    !attrs[XFRMA_ALG_CRYPT] &&
		    !attrs[XFRMA_ALG_AEAD])
			goto out;
		if ((attrs[XFRMA_ALG_AUTH] ||
193
		     attrs[XFRMA_ALG_AUTH_TRUNC] ||
194 195
		     attrs[XFRMA_ALG_CRYPT]) &&
		    attrs[XFRMA_ALG_AEAD])
L
Linus Torvalds 已提交
196
			goto out;
197 198 199
		if (attrs[XFRMA_TFCPAD] &&
		    p->mode != XFRM_MODE_TUNNEL)
			goto out;
L
Linus Torvalds 已提交
200 201 202
		break;

	case IPPROTO_COMP:
203
		if (!attrs[XFRMA_ALG_COMP]	||
204
		    attrs[XFRMA_ALG_AEAD]	||
205
		    attrs[XFRMA_ALG_AUTH]	||
206
		    attrs[XFRMA_ALG_AUTH_TRUNC]	||
207
		    attrs[XFRMA_ALG_CRYPT]	||
208 209
		    attrs[XFRMA_TFCPAD]		||
		    (ntohl(p->id.spi) >= 0x10000))
L
Linus Torvalds 已提交
210 211 212
			goto out;
		break;

E
Eric Dumazet 已提交
213
#if IS_ENABLED(CONFIG_IPV6)
214 215
	case IPPROTO_DSTOPTS:
	case IPPROTO_ROUTING:
216 217
		if (attrs[XFRMA_ALG_COMP]	||
		    attrs[XFRMA_ALG_AUTH]	||
218
		    attrs[XFRMA_ALG_AUTH_TRUNC]	||
219
		    attrs[XFRMA_ALG_AEAD]	||
220 221 222
		    attrs[XFRMA_ALG_CRYPT]	||
		    attrs[XFRMA_ENCAP]		||
		    attrs[XFRMA_SEC_CTX]	||
223
		    attrs[XFRMA_TFCPAD]		||
224
		    !attrs[XFRMA_COADDR])
225 226 227 228
			goto out;
		break;
#endif

L
Linus Torvalds 已提交
229 230
	default:
		goto out;
231
	}
L
Linus Torvalds 已提交
232

233 234
	if ((err = verify_aead(attrs)))
		goto out;
235 236
	if ((err = verify_auth_trunc(attrs)))
		goto out;
237
	if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH)))
L
Linus Torvalds 已提交
238
		goto out;
239
	if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT)))
L
Linus Torvalds 已提交
240
		goto out;
241
	if ((err = verify_one_alg(attrs, XFRMA_ALG_COMP)))
L
Linus Torvalds 已提交
242
		goto out;
243
	if ((err = verify_sec_ctx_len(attrs)))
244
		goto out;
245 246
	if ((err = verify_replay(p, attrs)))
		goto out;
L
Linus Torvalds 已提交
247 248 249

	err = -EINVAL;
	switch (p->mode) {
250 251
	case XFRM_MODE_TRANSPORT:
	case XFRM_MODE_TUNNEL:
252
	case XFRM_MODE_ROUTEOPTIMIZATION:
D
Diego Beltrami 已提交
253
	case XFRM_MODE_BEET:
L
Linus Torvalds 已提交
254 255 256 257
		break;

	default:
		goto out;
258
	}
L
Linus Torvalds 已提交
259 260 261 262 263 264 265 266

	err = 0;

out:
	return err;
}

static int attach_one_algo(struct xfrm_algo **algpp, u8 *props,
267
			   struct xfrm_algo_desc *(*get_byname)(const char *, int),
268
			   struct nlattr *rta)
L
Linus Torvalds 已提交
269 270 271 272 273 274 275
{
	struct xfrm_algo *p, *ualg;
	struct xfrm_algo_desc *algo;

	if (!rta)
		return 0;

276
	ualg = nla_data(rta);
L
Linus Torvalds 已提交
277 278 279 280 281 282

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

283
	p = kmemdup(ualg, xfrm_alg_len(ualg), GFP_KERNEL);
L
Linus Torvalds 已提交
284 285 286
	if (!p)
		return -ENOMEM;

287
	strcpy(p->alg_name, algo->name);
L
Linus Torvalds 已提交
288 289 290 291
	*algpp = p;
	return 0;
}

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
static int attach_crypt(struct xfrm_state *x, struct nlattr *rta)
{
	struct xfrm_algo *p, *ualg;
	struct xfrm_algo_desc *algo;

	if (!rta)
		return 0;

	ualg = nla_data(rta);

	algo = xfrm_ealg_get_byname(ualg->alg_name, 1);
	if (!algo)
		return -ENOSYS;
	x->props.ealgo = algo->desc.sadb_alg_id;

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

	strcpy(p->alg_name, algo->name);
	x->ealg = p;
	x->geniv = algo->uinfo.encr.geniv;
	return 0;
}

317 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 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
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;
361
	if (ualg->alg_trunc_len > algo->uinfo.auth.icv_fullbits)
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
		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;
}

377
static int attach_aead(struct xfrm_state *x, struct nlattr *rta)
378 379 380 381 382 383 384 385 386 387 388 389
{
	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;
390
	x->props.ealgo = algo->desc.sadb_alg_id;
391 392 393 394 395 396

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

	strcpy(p->alg_name, algo->name);
397 398
	x->aead = p;
	x->geniv = algo->uinfo.aead.geniv;
399 400 401
	return 0;
}

402 403 404 405
static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_esn,
					 struct nlattr *rp)
{
	struct xfrm_replay_state_esn *up;
406
	int ulen;
407 408 409 410 411

	if (!replay_esn || !rp)
		return 0;

	up = nla_data(rp);
412
	ulen = xfrm_replay_state_esn_len(up);
413

414
	if (nla_len(rp) < ulen || xfrm_replay_state_esn_len(replay_esn) != ulen)
415 416 417 418 419
		return -EINVAL;

	return 0;
}

420 421 422 423 424
static int xfrm_alloc_replay_state_esn(struct xfrm_replay_state_esn **replay_esn,
				       struct xfrm_replay_state_esn **preplay_esn,
				       struct nlattr *rta)
{
	struct xfrm_replay_state_esn *p, *pp, *up;
425
	int klen, ulen;
426 427 428 429 430

	if (!rta)
		return 0;

	up = nla_data(rta);
431 432
	klen = xfrm_replay_state_esn_len(up);
	ulen = nla_len(rta) >= klen ? klen : sizeof(*up);
433

434
	p = kzalloc(klen, GFP_KERNEL);
435 436 437
	if (!p)
		return -ENOMEM;

438
	pp = kzalloc(klen, GFP_KERNEL);
439 440 441 442 443
	if (!pp) {
		kfree(p);
		return -ENOMEM;
	}

444 445 446
	memcpy(p, up, ulen);
	memcpy(pp, up, ulen);

447 448 449 450 451 452
	*replay_esn = p;
	*preplay_esn = pp;

	return 0;
}

453
static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx)
454 455 456 457 458 459 460 461 462 463
{
	int len = 0;

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

L
Linus Torvalds 已提交
464 465 466 467 468 469
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;
470 471
	x->props.replay_window = min_t(unsigned int, p->replay_window,
					sizeof(x->replay.bitmap) * 8);
L
Linus Torvalds 已提交
472 473
	x->props.reqid = p->reqid;
	x->props.family = p->family;
474
	memcpy(&x->props.saddr, &p->saddr, sizeof(x->props.saddr));
L
Linus Torvalds 已提交
475
	x->props.flags = p->flags;
476

477
	if (!x->sel.family && !(p->flags & XFRM_STATE_AF_UNSPEC))
478
		x->sel.family = p->family;
L
Linus Torvalds 已提交
479 480
}

J
Jamal Hadi Salim 已提交
481 482 483 484 485
/*
 * someday when pfkey also has support, we could have the code
 * somehow made shareable and move it to xfrm_state.c - JHS
 *
*/
486 487
static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs,
				  int update_esn)
J
Jamal Hadi Salim 已提交
488
{
489
	struct nlattr *rp = attrs[XFRMA_REPLAY_VAL];
490
	struct nlattr *re = update_esn ? attrs[XFRMA_REPLAY_ESN_VAL] : NULL;
491 492 493
	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 已提交
494

495 496 497 498 499 500 501 502 503
	if (re) {
		struct xfrm_replay_state_esn *replay_esn;
		replay_esn = nla_data(re);
		memcpy(x->replay_esn, replay_esn,
		       xfrm_replay_state_esn_len(replay_esn));
		memcpy(x->preplay_esn, replay_esn,
		       xfrm_replay_state_esn_len(replay_esn));
	}

J
Jamal Hadi Salim 已提交
504 505
	if (rp) {
		struct xfrm_replay_state *replay;
506
		replay = nla_data(rp);
J
Jamal Hadi Salim 已提交
507 508 509 510 511 512
		memcpy(&x->replay, replay, sizeof(*replay));
		memcpy(&x->preplay, replay, sizeof(*replay));
	}

	if (lt) {
		struct xfrm_lifetime_cur *ltime;
513
		ltime = nla_data(lt);
J
Jamal Hadi Salim 已提交
514 515 516 517 518 519
		x->curlft.bytes = ltime->bytes;
		x->curlft.packets = ltime->packets;
		x->curlft.add_time = ltime->add_time;
		x->curlft.use_time = ltime->use_time;
	}

520
	if (et)
521
		x->replay_maxage = nla_get_u32(et);
J
Jamal Hadi Salim 已提交
522

523
	if (rt)
524
		x->replay_maxdiff = nla_get_u32(rt);
J
Jamal Hadi Salim 已提交
525 526
}

527 528
static struct xfrm_state *xfrm_state_construct(struct net *net,
					       struct xfrm_usersa_info *p,
529
					       struct nlattr **attrs,
L
Linus Torvalds 已提交
530 531
					       int *errp)
{
532
	struct xfrm_state *x = xfrm_state_alloc(net);
L
Linus Torvalds 已提交
533 534 535 536 537 538 539
	int err = -ENOMEM;

	if (!x)
		goto error_no_put;

	copy_from_user_state(x, p);

540 541 542
	if (attrs[XFRMA_SA_EXTRA_FLAGS])
		x->props.extra_flags = nla_get_u32(attrs[XFRMA_SA_EXTRA_FLAGS]);

543
	if ((err = attach_aead(x, attrs[XFRMA_ALG_AEAD])))
544
		goto error;
545 546
	if ((err = attach_auth_trunc(&x->aalg, &x->props.aalgo,
				     attrs[XFRMA_ALG_AUTH_TRUNC])))
L
Linus Torvalds 已提交
547
		goto error;
548 549 550 551 552
	if (!x->props.aalgo) {
		if ((err = attach_auth(&x->aalg, &x->props.aalgo,
				       attrs[XFRMA_ALG_AUTH])))
			goto error;
	}
553
	if ((err = attach_crypt(x, attrs[XFRMA_ALG_CRYPT])))
L
Linus Torvalds 已提交
554 555 556
		goto error;
	if ((err = attach_one_algo(&x->calg, &x->props.calgo,
				   xfrm_calg_get_byname,
557
				   attrs[XFRMA_ALG_COMP])))
L
Linus Torvalds 已提交
558
		goto error;
559 560 561 562 563 564 565 566

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

567 568 569
	if (attrs[XFRMA_TFCPAD])
		x->tfcpad = nla_get_u32(attrs[XFRMA_TFCPAD]);

570 571 572 573 574 575 576
	if (attrs[XFRMA_COADDR]) {
		x->coaddr = kmemdup(nla_data(attrs[XFRMA_COADDR]),
				    sizeof(*x->coaddr), GFP_KERNEL);
		if (x->coaddr == NULL)
			goto error;
	}

577 578
	xfrm_mark_get(attrs, &x->mark);

579
	err = __xfrm_init_state(x, false);
L
Linus Torvalds 已提交
580 581 582
	if (err)
		goto error;

583 584
	if (attrs[XFRMA_SEC_CTX] &&
	    security_xfrm_state_alloc(x, nla_data(attrs[XFRMA_SEC_CTX])))
585 586
		goto error;

587 588 589 590
	if ((err = xfrm_alloc_replay_state_esn(&x->replay_esn, &x->preplay_esn,
					       attrs[XFRMA_REPLAY_ESN_VAL])))
		goto error;

L
Linus Torvalds 已提交
591
	x->km.seq = p->seq;
A
Alexey Dobriyan 已提交
592
	x->replay_maxdiff = net->xfrm.sysctl_aevent_rseqth;
J
Jamal Hadi Salim 已提交
593
	/* sysctl_xfrm_aevent_etime is in 100ms units */
A
Alexey Dobriyan 已提交
594
	x->replay_maxage = (net->xfrm.sysctl_aevent_etime*HZ)/XFRM_AE_ETH_M;
J
Jamal Hadi Salim 已提交
595

596 597
	if ((err = xfrm_init_replay(x)))
		goto error;
J
Jamal Hadi Salim 已提交
598

599
	/* override default values from above */
600
	xfrm_update_ae_params(x, attrs, 0);
L
Linus Torvalds 已提交
601 602 603 604 605 606 607 608 609 610 611

	return x;

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

612
static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
613
		struct nlattr **attrs)
L
Linus Torvalds 已提交
614
{
615
	struct net *net = sock_net(skb->sk);
616
	struct xfrm_usersa_info *p = nlmsg_data(nlh);
L
Linus Torvalds 已提交
617 618
	struct xfrm_state *x;
	int err;
619
	struct km_event c;
L
Linus Torvalds 已提交
620

621
	err = verify_newsa_info(p, attrs);
L
Linus Torvalds 已提交
622 623 624
	if (err)
		return err;

625
	x = xfrm_state_construct(net, p, attrs, &err);
L
Linus Torvalds 已提交
626 627 628
	if (!x)
		return err;

629
	xfrm_state_hold(x);
L
Linus Torvalds 已提交
630 631 632 633 634
	if (nlh->nlmsg_type == XFRM_MSG_NEWSA)
		err = xfrm_state_add(x);
	else
		err = xfrm_state_update(x);

635
	xfrm_audit_state_add(x, err ? 0 : 1, true);
J
Joy Latten 已提交
636

L
Linus Torvalds 已提交
637 638
	if (err < 0) {
		x->km.state = XFRM_STATE_DEAD;
639
		__xfrm_state_put(x);
640
		goto out;
L
Linus Torvalds 已提交
641 642
	}

643
	c.seq = nlh->nlmsg_seq;
644
	c.portid = nlh->nlmsg_pid;
645
	c.event = nlh->nlmsg_type;
646 647

	km_state_notify(x, &c);
648
out:
649
	xfrm_state_put(x);
L
Linus Torvalds 已提交
650 651 652
	return err;
}

653 654
static struct xfrm_state *xfrm_user_state_lookup(struct net *net,
						 struct xfrm_usersa_id *p,
655
						 struct nlattr **attrs,
656 657 658
						 int *errp)
{
	struct xfrm_state *x = NULL;
659
	struct xfrm_mark m;
660
	int err;
661
	u32 mark = xfrm_mark_get(attrs, &m);
662 663 664

	if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) {
		err = -ESRCH;
665
		x = xfrm_state_lookup(net, mark, &p->daddr, p->spi, p->proto, p->family);
666 667 668
	} else {
		xfrm_address_t *saddr = NULL;

669
		verify_one_addr(attrs, XFRMA_SRCADDR, &saddr);
670 671 672 673 674
		if (!saddr) {
			err = -EINVAL;
			goto out;
		}

675
		err = -ESRCH;
676 677
		x = xfrm_state_lookup_byaddr(net, mark,
					     &p->daddr, saddr,
678
					     p->proto, p->family);
679 680 681 682 683 684 685 686
	}

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

687
static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
688
		struct nlattr **attrs)
L
Linus Torvalds 已提交
689
{
690
	struct net *net = sock_net(skb->sk);
L
Linus Torvalds 已提交
691
	struct xfrm_state *x;
692
	int err = -ESRCH;
693
	struct km_event c;
694
	struct xfrm_usersa_id *p = nlmsg_data(nlh);
L
Linus Torvalds 已提交
695

696
	x = xfrm_user_state_lookup(net, p, attrs, &err);
L
Linus Torvalds 已提交
697
	if (x == NULL)
698
		return err;
L
Linus Torvalds 已提交
699

700
	if ((err = security_xfrm_state_delete(x)) != 0)
C
Catherine Zhang 已提交
701 702
		goto out;

L
Linus Torvalds 已提交
703
	if (xfrm_state_kern(x)) {
C
Catherine Zhang 已提交
704 705
		err = -EPERM;
		goto out;
L
Linus Torvalds 已提交
706 707
	}

708
	err = xfrm_state_delete(x);
J
Joy Latten 已提交
709

C
Catherine Zhang 已提交
710 711
	if (err < 0)
		goto out;
712 713

	c.seq = nlh->nlmsg_seq;
714
	c.portid = nlh->nlmsg_pid;
715
	c.event = nlh->nlmsg_type;
716
	km_state_notify(x, &c);
L
Linus Torvalds 已提交
717

C
Catherine Zhang 已提交
718
out:
719
	xfrm_audit_state_delete(x, err ? 0 : 1, true);
C
Catherine Zhang 已提交
720
	xfrm_state_put(x);
721
	return err;
L
Linus Torvalds 已提交
722 723 724 725
}

static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)
{
726
	memset(p, 0, sizeof(*p));
L
Linus Torvalds 已提交
727 728 729 730 731
	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));
732
	memcpy(&p->saddr, &x->props.saddr, sizeof(p->saddr));
L
Linus Torvalds 已提交
733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
	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;
};

748 749 750 751
static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb)
{
	struct xfrm_user_sec_ctx *uctx;
	struct nlattr *attr;
752
	int ctx_size = sizeof(*uctx) + s->ctx_len;
753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768

	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;
}

769 770 771 772 773 774 775 776 777 778 779
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);
780
	strncpy(algo->alg_name, auth->alg_name, sizeof(algo->alg_name));
781 782 783 784 785 786
	memcpy(algo->alg_key, auth->alg_key, (auth->alg_key_len + 7) / 8);
	algo->alg_key_len = auth->alg_key_len;

	return 0;
}

787 788 789 790
/* 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 已提交
791
{
792
	int ret = 0;
793

794
	copy_to_user_state(x, p);
795

796 797 798 799 800 801 802
	if (x->props.extra_flags) {
		ret = nla_put_u32(skb, XFRMA_SA_EXTRA_FLAGS,
				  x->props.extra_flags);
		if (ret)
			goto out;
	}

803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848
	if (x->coaddr) {
		ret = nla_put(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr);
		if (ret)
			goto out;
	}
	if (x->lastused) {
		ret = nla_put_u64(skb, XFRMA_LASTUSED, x->lastused);
		if (ret)
			goto out;
	}
	if (x->aead) {
		ret = nla_put(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead);
		if (ret)
			goto out;
	}
	if (x->aalg) {
		ret = copy_to_user_auth(x->aalg, skb);
		if (!ret)
			ret = nla_put(skb, XFRMA_ALG_AUTH_TRUNC,
				      xfrm_alg_auth_len(x->aalg), x->aalg);
		if (ret)
			goto out;
	}
	if (x->ealg) {
		ret = nla_put(skb, XFRMA_ALG_CRYPT, xfrm_alg_len(x->ealg), x->ealg);
		if (ret)
			goto out;
	}
	if (x->calg) {
		ret = nla_put(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg);
		if (ret)
			goto out;
	}
	if (x->encap) {
		ret = nla_put(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap);
		if (ret)
			goto out;
	}
	if (x->tfcpad) {
		ret = nla_put_u32(skb, XFRMA_TFCPAD, x->tfcpad);
		if (ret)
			goto out;
	}
	ret = xfrm_mark_put(skb, &x->mark);
	if (ret)
		goto out;
849
	if (x->replay_esn)
850 851 852
		ret = nla_put(skb, XFRMA_REPLAY_ESN_VAL,
			      xfrm_replay_state_esn_len(x->replay_esn),
			      x->replay_esn);
853 854 855 856 857
	else
		ret = nla_put(skb, XFRMA_REPLAY_VAL, sizeof(x->replay),
			      &x->replay);
	if (ret)
		goto out;
858 859 860 861
	if (x->security)
		ret = copy_sec_ctx(x->security, skb);
out:
	return ret;
862 863 864 865 866 867 868 869 870 871 872
}

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;

873
	nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, sp->nlmsg_seq,
874 875 876 877 878 879 880
			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);
881 882 883 884
	if (err) {
		nlmsg_cancel(skb, nlh);
		return err;
	}
885
	nlmsg_end(skb, nlh);
L
Linus Torvalds 已提交
886 887 888
	return 0;
}

889 890 891
static int xfrm_dump_sa_done(struct netlink_callback *cb)
{
	struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
F
Fan Du 已提交
892 893 894 895
	struct sock *sk = cb->skb->sk;
	struct net *net = sock_net(sk);

	xfrm_state_walk_done(walk, net);
896 897 898
	return 0;
}

899
static const struct nla_policy xfrma_policy[XFRMA_MAX+1];
L
Linus Torvalds 已提交
900 901
static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb)
{
902
	struct net *net = sock_net(skb->sk);
903
	struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
L
Linus Torvalds 已提交
904 905
	struct xfrm_dump_info info;

906 907 908
	BUILD_BUG_ON(sizeof(struct xfrm_state_walk) >
		     sizeof(cb->args) - sizeof(cb->args[0]));

L
Linus Torvalds 已提交
909 910 911 912
	info.in_skb = cb->skb;
	info.out_skb = skb;
	info.nlmsg_seq = cb->nlh->nlmsg_seq;
	info.nlmsg_flags = NLM_F_MULTI;
913 914

	if (!cb->args[0]) {
915
		struct nlattr *attrs[XFRMA_MAX+1];
916
		struct xfrm_address_filter *filter = NULL;
917 918 919
		u8 proto = 0;
		int err;

920
		cb->args[0] = 1;
921 922 923 924 925 926

		err = nlmsg_parse(cb->nlh, 0, attrs, XFRMA_MAX,
				  xfrma_policy);
		if (err < 0)
			return err;

927
		if (attrs[XFRMA_ADDRESS_FILTER]) {
928 929
			filter = kmemdup(nla_data(attrs[XFRMA_ADDRESS_FILTER]),
					 sizeof(*filter), GFP_KERNEL);
930 931 932 933 934 935 936 937
			if (filter == NULL)
				return -ENOMEM;
		}

		if (attrs[XFRMA_PROTO])
			proto = nla_get_u8(attrs[XFRMA_PROTO]);

		xfrm_state_walk_init(walk, proto, filter);
938 939
	}

940
	(void) xfrm_state_walk(net, walk, dump_one_state, &info);
L
Linus Torvalds 已提交
941 942 943 944 945 946 947 948 949

	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;
950
	int err;
L
Linus Torvalds 已提交
951

952
	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
L
Linus Torvalds 已提交
953 954 955 956 957 958 959 960
	if (!skb)
		return ERR_PTR(-ENOMEM);

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

961 962
	err = dump_one_state(x, 0, &info);
	if (err) {
L
Linus Torvalds 已提交
963
		kfree_skb(skb);
964
		return ERR_PTR(err);
L
Linus Torvalds 已提交
965 966 967 968 969
	}

	return skb;
}

970 971 972 973 974 975 976 977 978 979 980 981 982 983
/* A wrapper for nlmsg_multicast() checking that nlsk is still available.
 * Must be called with RCU read lock.
 */
static inline int xfrm_nlmsg_multicast(struct net *net, struct sk_buff *skb,
				       u32 pid, unsigned int group)
{
	struct sock *nlsk = rcu_dereference(net->xfrm.nlsk);

	if (nlsk)
		return nlmsg_multicast(nlsk, skb, pid, group, GFP_ATOMIC);
	else
		return -1;
}

984 985 986 987
static inline size_t xfrm_spdinfo_msgsize(void)
{
	return NLMSG_ALIGN(4)
	       + nla_total_size(sizeof(struct xfrmu_spdinfo))
988 989 990
	       + nla_total_size(sizeof(struct xfrmu_spdhinfo))
	       + nla_total_size(sizeof(struct xfrmu_spdhthresh))
	       + nla_total_size(sizeof(struct xfrmu_spdhthresh));
991 992
}

993
static int build_spdinfo(struct sk_buff *skb, struct net *net,
994
			 u32 portid, u32 seq, u32 flags)
J
Jamal Hadi Salim 已提交
995
{
996 997 998
	struct xfrmk_spdinfo si;
	struct xfrmu_spdinfo spc;
	struct xfrmu_spdhinfo sph;
999
	struct xfrmu_spdhthresh spt4, spt6;
J
Jamal Hadi Salim 已提交
1000
	struct nlmsghdr *nlh;
1001
	int err;
J
Jamal Hadi Salim 已提交
1002
	u32 *f;
1003
	unsigned lseq;
J
Jamal Hadi Salim 已提交
1004

1005
	nlh = nlmsg_put(skb, portid, seq, XFRM_MSG_NEWSPDINFO, sizeof(u32), 0);
L
Lucas De Marchi 已提交
1006
	if (nlh == NULL) /* shouldn't really happen ... */
J
Jamal Hadi Salim 已提交
1007 1008 1009 1010
		return -EMSGSIZE;

	f = nlmsg_data(nlh);
	*f = flags;
1011
	xfrm_spd_getinfo(net, &si);
1012 1013 1014 1015 1016 1017 1018 1019 1020
	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;

1021 1022 1023 1024 1025 1026 1027 1028 1029
	do {
		lseq = read_seqbegin(&net->xfrm.policy_hthresh.lock);

		spt4.lbits = net->xfrm.policy_hthresh.lbits4;
		spt4.rbits = net->xfrm.policy_hthresh.rbits4;
		spt6.lbits = net->xfrm.policy_hthresh.lbits6;
		spt6.rbits = net->xfrm.policy_hthresh.rbits6;
	} while (read_seqretry(&net->xfrm.policy_hthresh.lock, lseq));

1030 1031 1032
	err = nla_put(skb, XFRMA_SPD_INFO, sizeof(spc), &spc);
	if (!err)
		err = nla_put(skb, XFRMA_SPD_HINFO, sizeof(sph), &sph);
1033 1034 1035 1036
	if (!err)
		err = nla_put(skb, XFRMA_SPD_IPV4_HTHRESH, sizeof(spt4), &spt4);
	if (!err)
		err = nla_put(skb, XFRMA_SPD_IPV6_HTHRESH, sizeof(spt6), &spt6);
1037 1038 1039 1040
	if (err) {
		nlmsg_cancel(skb, nlh);
		return err;
	}
J
Jamal Hadi Salim 已提交
1041

1042 1043
	nlmsg_end(skb, nlh);
	return 0;
J
Jamal Hadi Salim 已提交
1044 1045
}

1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090
static int xfrm_set_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
			    struct nlattr **attrs)
{
	struct net *net = sock_net(skb->sk);
	struct xfrmu_spdhthresh *thresh4 = NULL;
	struct xfrmu_spdhthresh *thresh6 = NULL;

	/* selector prefixlen thresholds to hash policies */
	if (attrs[XFRMA_SPD_IPV4_HTHRESH]) {
		struct nlattr *rta = attrs[XFRMA_SPD_IPV4_HTHRESH];

		if (nla_len(rta) < sizeof(*thresh4))
			return -EINVAL;
		thresh4 = nla_data(rta);
		if (thresh4->lbits > 32 || thresh4->rbits > 32)
			return -EINVAL;
	}
	if (attrs[XFRMA_SPD_IPV6_HTHRESH]) {
		struct nlattr *rta = attrs[XFRMA_SPD_IPV6_HTHRESH];

		if (nla_len(rta) < sizeof(*thresh6))
			return -EINVAL;
		thresh6 = nla_data(rta);
		if (thresh6->lbits > 128 || thresh6->rbits > 128)
			return -EINVAL;
	}

	if (thresh4 || thresh6) {
		write_seqlock(&net->xfrm.policy_hthresh.lock);
		if (thresh4) {
			net->xfrm.policy_hthresh.lbits4 = thresh4->lbits;
			net->xfrm.policy_hthresh.rbits4 = thresh4->rbits;
		}
		if (thresh6) {
			net->xfrm.policy_hthresh.lbits6 = thresh6->lbits;
			net->xfrm.policy_hthresh.rbits6 = thresh6->rbits;
		}
		write_sequnlock(&net->xfrm.policy_hthresh.lock);

		xfrm_policy_hash_rebuild(net);
	}

	return 0;
}

J
Jamal Hadi Salim 已提交
1091
static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
1092
		struct nlattr **attrs)
J
Jamal Hadi Salim 已提交
1093
{
1094
	struct net *net = sock_net(skb->sk);
J
Jamal Hadi Salim 已提交
1095
	struct sk_buff *r_skb;
1096
	u32 *flags = nlmsg_data(nlh);
1097
	u32 sportid = NETLINK_CB(skb).portid;
J
Jamal Hadi Salim 已提交
1098 1099
	u32 seq = nlh->nlmsg_seq;

1100
	r_skb = nlmsg_new(xfrm_spdinfo_msgsize(), GFP_ATOMIC);
J
Jamal Hadi Salim 已提交
1101 1102 1103
	if (r_skb == NULL)
		return -ENOMEM;

1104
	if (build_spdinfo(r_skb, net, sportid, seq, *flags) < 0)
J
Jamal Hadi Salim 已提交
1105 1106
		BUG();

1107
	return nlmsg_unicast(net->xfrm.nlsk, r_skb, sportid);
J
Jamal Hadi Salim 已提交
1108 1109
}

1110 1111 1112 1113 1114 1115 1116
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 */
}

1117
static int build_sadinfo(struct sk_buff *skb, struct net *net,
1118
			 u32 portid, u32 seq, u32 flags)
J
Jamal Hadi Salim 已提交
1119
{
1120 1121
	struct xfrmk_sadinfo si;
	struct xfrmu_sadhinfo sh;
J
Jamal Hadi Salim 已提交
1122
	struct nlmsghdr *nlh;
1123
	int err;
J
Jamal Hadi Salim 已提交
1124 1125
	u32 *f;

1126
	nlh = nlmsg_put(skb, portid, seq, XFRM_MSG_NEWSADINFO, sizeof(u32), 0);
L
Lucas De Marchi 已提交
1127
	if (nlh == NULL) /* shouldn't really happen ... */
J
Jamal Hadi Salim 已提交
1128 1129 1130 1131
		return -EMSGSIZE;

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

1134 1135 1136
	sh.sadhmcnt = si.sadhmcnt;
	sh.sadhcnt = si.sadhcnt;

1137 1138 1139 1140 1141 1142 1143
	err = nla_put_u32(skb, XFRMA_SAD_CNT, si.sadcnt);
	if (!err)
		err = nla_put(skb, XFRMA_SAD_HINFO, sizeof(sh), &sh);
	if (err) {
		nlmsg_cancel(skb, nlh);
		return err;
	}
J
Jamal Hadi Salim 已提交
1144

1145 1146
	nlmsg_end(skb, nlh);
	return 0;
J
Jamal Hadi Salim 已提交
1147 1148 1149
}

static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
1150
		struct nlattr **attrs)
J
Jamal Hadi Salim 已提交
1151
{
1152
	struct net *net = sock_net(skb->sk);
J
Jamal Hadi Salim 已提交
1153
	struct sk_buff *r_skb;
1154
	u32 *flags = nlmsg_data(nlh);
1155
	u32 sportid = NETLINK_CB(skb).portid;
J
Jamal Hadi Salim 已提交
1156 1157
	u32 seq = nlh->nlmsg_seq;

1158
	r_skb = nlmsg_new(xfrm_sadinfo_msgsize(), GFP_ATOMIC);
J
Jamal Hadi Salim 已提交
1159 1160 1161
	if (r_skb == NULL)
		return -ENOMEM;

1162
	if (build_sadinfo(r_skb, net, sportid, seq, *flags) < 0)
J
Jamal Hadi Salim 已提交
1163 1164
		BUG();

1165
	return nlmsg_unicast(net->xfrm.nlsk, r_skb, sportid);
J
Jamal Hadi Salim 已提交
1166 1167
}

1168
static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
1169
		struct nlattr **attrs)
L
Linus Torvalds 已提交
1170
{
1171
	struct net *net = sock_net(skb->sk);
1172
	struct xfrm_usersa_id *p = nlmsg_data(nlh);
L
Linus Torvalds 已提交
1173 1174
	struct xfrm_state *x;
	struct sk_buff *resp_skb;
1175
	int err = -ESRCH;
L
Linus Torvalds 已提交
1176

1177
	x = xfrm_user_state_lookup(net, p, attrs, &err);
L
Linus Torvalds 已提交
1178 1179 1180 1181 1182 1183 1184
	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 {
1185
		err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, NETLINK_CB(skb).portid);
L
Linus Torvalds 已提交
1186 1187 1188 1189 1190 1191
	}
	xfrm_state_put(x);
out_noput:
	return err;
}

1192
static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
1193
		struct nlattr **attrs)
L
Linus Torvalds 已提交
1194
{
1195
	struct net *net = sock_net(skb->sk);
L
Linus Torvalds 已提交
1196 1197 1198 1199 1200 1201
	struct xfrm_state *x;
	struct xfrm_userspi_info *p;
	struct sk_buff *resp_skb;
	xfrm_address_t *daddr;
	int family;
	int err;
1202 1203
	u32 mark;
	struct xfrm_mark m;
L
Linus Torvalds 已提交
1204

1205
	p = nlmsg_data(nlh);
1206
	err = verify_spi_info(p->info.id.proto, p->min, p->max);
L
Linus Torvalds 已提交
1207 1208 1209 1210 1211 1212 1213
	if (err)
		goto out_noput;

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

	x = NULL;
1214 1215

	mark = xfrm_mark_get(attrs, &m);
L
Linus Torvalds 已提交
1216
	if (p->info.seq) {
1217
		x = xfrm_find_acq_byseq(net, mark, p->info.seq);
1218
		if (x && !xfrm_addr_equal(&x->id.daddr, daddr, family)) {
L
Linus Torvalds 已提交
1219 1220 1221 1222 1223 1224
			xfrm_state_put(x);
			x = NULL;
		}
	}

	if (!x)
1225
		x = xfrm_find_acq(net, &m, p->info.mode, p->info.reqid,
L
Linus Torvalds 已提交
1226 1227 1228 1229 1230 1231 1232
				  p->info.id.proto, daddr,
				  &p->info.saddr, 1,
				  family);
	err = -ENOENT;
	if (x == NULL)
		goto out_noput;

1233 1234 1235
	err = xfrm_alloc_spi(x, p->min, p->max);
	if (err)
		goto out;
L
Linus Torvalds 已提交
1236

1237
	resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq);
L
Linus Torvalds 已提交
1238 1239 1240 1241 1242
	if (IS_ERR(resp_skb)) {
		err = PTR_ERR(resp_skb);
		goto out;
	}

1243
	err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, NETLINK_CB(skb).portid);
L
Linus Torvalds 已提交
1244 1245 1246 1247 1248 1249 1250

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

1251
static int verify_policy_dir(u8 dir)
L
Linus Torvalds 已提交
1252 1253 1254 1255 1256 1257 1258 1259 1260
{
	switch (dir) {
	case XFRM_POLICY_IN:
	case XFRM_POLICY_OUT:
	case XFRM_POLICY_FWD:
		break;

	default:
		return -EINVAL;
1261
	}
L
Linus Torvalds 已提交
1262 1263 1264 1265

	return 0;
}

1266
static int verify_policy_type(u8 type)
1267 1268 1269 1270 1271 1272 1273 1274 1275 1276
{
	switch (type) {
	case XFRM_POLICY_TYPE_MAIN:
#ifdef CONFIG_XFRM_SUB_POLICY
	case XFRM_POLICY_TYPE_SUB:
#endif
		break;

	default:
		return -EINVAL;
1277
	}
1278 1279 1280 1281

	return 0;
}

L
Linus Torvalds 已提交
1282 1283
static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
{
1284 1285
	int ret;

L
Linus Torvalds 已提交
1286 1287 1288 1289 1290 1291 1292 1293 1294
	switch (p->share) {
	case XFRM_SHARE_ANY:
	case XFRM_SHARE_SESSION:
	case XFRM_SHARE_USER:
	case XFRM_SHARE_UNIQUE:
		break;

	default:
		return -EINVAL;
1295
	}
L
Linus Torvalds 已提交
1296 1297 1298 1299 1300 1301 1302 1303

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

	default:
		return -EINVAL;
1304
	}
L
Linus Torvalds 已提交
1305 1306 1307 1308 1309 1310

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

	case AF_INET6:
E
Eric Dumazet 已提交
1311
#if IS_ENABLED(CONFIG_IPV6)
L
Linus Torvalds 已提交
1312 1313 1314 1315 1316 1317 1318
		break;
#else
		return  -EAFNOSUPPORT;
#endif

	default:
		return -EINVAL;
1319
	}
L
Linus Torvalds 已提交
1320

1321 1322 1323 1324 1325 1326 1327
	ret = verify_policy_dir(p->dir);
	if (ret)
		return ret;
	if (p->index && ((p->index & XFRM_POLICY_MAX) != p->dir))
		return -EINVAL;

	return 0;
L
Linus Torvalds 已提交
1328 1329
}

1330
static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs)
1331
{
1332
	struct nlattr *rt = attrs[XFRMA_SEC_CTX];
1333 1334 1335 1336 1337
	struct xfrm_user_sec_ctx *uctx;

	if (!rt)
		return 0;

1338
	uctx = nla_data(rt);
1339
	return security_xfrm_policy_alloc(&pol->security, uctx, GFP_KERNEL);
1340 1341
}

L
Linus Torvalds 已提交
1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360
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;
1361 1362
		/* If all masks are ~0, then we allow all algorithms. */
		t->allalgs = !~(t->aalgos & t->ealgos & t->calgos);
1363
		t->encap_family = ut->family;
L
Linus Torvalds 已提交
1364 1365 1366
	}
}

1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387
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;
E
Eric Dumazet 已提交
1388
#if IS_ENABLED(CONFIG_IPV6)
1389 1390 1391 1392 1393
		case AF_INET6:
			break;
#endif
		default:
			return -EINVAL;
1394
		}
1395 1396 1397 1398 1399
	}

	return 0;
}

1400
static int copy_from_user_tmpl(struct xfrm_policy *pol, struct nlattr **attrs)
L
Linus Torvalds 已提交
1401
{
1402
	struct nlattr *rt = attrs[XFRMA_TMPL];
L
Linus Torvalds 已提交
1403 1404 1405 1406

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

1411 1412 1413
		err = validate_tmpl(nr, utmpl, pol->family);
		if (err)
			return err;
L
Linus Torvalds 已提交
1414

1415
		copy_templates(pol, utmpl, nr);
L
Linus Torvalds 已提交
1416 1417 1418 1419
	}
	return 0;
}

1420
static int copy_from_user_policy_type(u8 *tp, struct nlattr **attrs)
1421
{
1422
	struct nlattr *rt = attrs[XFRMA_POLICY_TYPE];
1423
	struct xfrm_userpolicy_type *upt;
1424
	u8 type = XFRM_POLICY_TYPE_MAIN;
1425 1426 1427
	int err;

	if (rt) {
1428
		upt = nla_data(rt);
1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439
		type = upt->type;
	}

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

	*tp = type;
	return 0;
}

L
Linus Torvalds 已提交
1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453
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)
{
1454
	memset(p, 0, sizeof(*p));
L
Linus Torvalds 已提交
1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466
	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 */
}

1467
static struct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_userpolicy_info *p, struct nlattr **attrs, int *errp)
L
Linus Torvalds 已提交
1468
{
1469
	struct xfrm_policy *xp = xfrm_policy_alloc(net, GFP_KERNEL);
L
Linus Torvalds 已提交
1470 1471 1472 1473 1474 1475 1476 1477
	int err;

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

	copy_from_user_policy(xp, p);
1478

1479
	err = copy_from_user_policy_type(&xp->type, attrs);
1480 1481 1482
	if (err)
		goto error;

1483 1484
	if (!(err = copy_from_user_tmpl(xp, attrs)))
		err = copy_from_user_sec_ctx(xp, attrs);
1485 1486
	if (err)
		goto error;
L
Linus Torvalds 已提交
1487

1488 1489
	xfrm_mark_get(attrs, &xp->mark);

L
Linus Torvalds 已提交
1490
	return xp;
1491 1492
 error:
	*errp = err;
H
Herbert Xu 已提交
1493
	xp->walk.dead = 1;
1494
	xfrm_policy_destroy(xp);
1495
	return NULL;
L
Linus Torvalds 已提交
1496 1497
}

1498
static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
1499
		struct nlattr **attrs)
L
Linus Torvalds 已提交
1500
{
1501
	struct net *net = sock_net(skb->sk);
1502
	struct xfrm_userpolicy_info *p = nlmsg_data(nlh);
L
Linus Torvalds 已提交
1503
	struct xfrm_policy *xp;
1504
	struct km_event c;
L
Linus Torvalds 已提交
1505 1506 1507 1508
	int err;
	int excl;

	err = verify_newpolicy_info(p);
1509 1510
	if (err)
		return err;
1511
	err = verify_sec_ctx_len(attrs);
L
Linus Torvalds 已提交
1512 1513 1514
	if (err)
		return err;

1515
	xp = xfrm_policy_construct(net, p, attrs, &err);
L
Linus Torvalds 已提交
1516 1517 1518
	if (!xp)
		return err;

L
Lucas De Marchi 已提交
1519
	/* shouldn't excl be based on nlh flags??
1520 1521 1522
	 * 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 已提交
1523 1524
	excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY;
	err = xfrm_policy_insert(p->dir, xp, excl);
1525
	xfrm_audit_policy_add(xp, err ? 0 : 1, true);
J
Joy Latten 已提交
1526

L
Linus Torvalds 已提交
1527
	if (err) {
1528
		security_xfrm_policy_free(xp->security);
L
Linus Torvalds 已提交
1529 1530 1531 1532
		kfree(xp);
		return err;
	}

1533
	c.event = nlh->nlmsg_type;
1534
	c.seq = nlh->nlmsg_seq;
1535
	c.portid = nlh->nlmsg_pid;
1536 1537
	km_policy_notify(xp, p->dir, &c);

L
Linus Torvalds 已提交
1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554
	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];

1555
		memset(up, 0, sizeof(*up));
L
Linus Torvalds 已提交
1556
		memcpy(&up->id, &kp->id, sizeof(up->id));
1557
		up->family = kp->encap_family;
L
Linus Torvalds 已提交
1558 1559 1560 1561 1562 1563 1564 1565 1566
		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;
	}
1567

1568 1569
	return nla_put(skb, XFRMA_TMPL,
		       sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr, vec);
1570 1571 1572 1573 1574 1575
}

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);
1576 1577
	}
	return 0;
1578
}
1579

1580 1581
static inline int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb)
{
1582
	if (xp->security)
1583 1584
		return copy_sec_ctx(xp->security, skb);
	return 0;
1585
}
1586 1587 1588 1589 1590 1591 1592 1593
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
}
1594

1595
#ifdef CONFIG_XFRM_SUB_POLICY
1596
static int copy_to_user_policy_type(u8 type, struct sk_buff *skb)
1597
{
1598 1599 1600
	struct xfrm_userpolicy_type upt = {
		.type = type,
	};
1601

1602
	return nla_put(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt);
1603 1604 1605
}

#else
1606
static inline int copy_to_user_policy_type(u8 type, struct sk_buff *skb)
1607 1608 1609 1610 1611
{
	return 0;
}
#endif

L
Linus Torvalds 已提交
1612 1613 1614 1615 1616 1617 1618
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;
1619
	int err;
L
Linus Torvalds 已提交
1620

1621
	nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, sp->nlmsg_seq,
1622 1623 1624
			XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags);
	if (nlh == NULL)
		return -EMSGSIZE;
L
Linus Torvalds 已提交
1625

1626
	p = nlmsg_data(nlh);
L
Linus Torvalds 已提交
1627
	copy_to_user_policy(xp, p, dir);
1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638
	err = copy_to_user_tmpl(xp, skb);
	if (!err)
		err = copy_to_user_sec_ctx(xp, skb);
	if (!err)
		err = copy_to_user_policy_type(xp->type, skb);
	if (!err)
		err = xfrm_mark_put(skb, &xp->mark);
	if (err) {
		nlmsg_cancel(skb, nlh);
		return err;
	}
1639
	nlmsg_end(skb, nlh);
L
Linus Torvalds 已提交
1640 1641 1642
	return 0;
}

1643 1644 1645
static int xfrm_dump_policy_done(struct netlink_callback *cb)
{
	struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1];
F
Fan Du 已提交
1646
	struct net *net = sock_net(cb->skb->sk);
1647

F
Fan Du 已提交
1648
	xfrm_policy_walk_done(walk, net);
1649 1650 1651
	return 0;
}

L
Linus Torvalds 已提交
1652 1653
static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb)
{
1654
	struct net *net = sock_net(skb->sk);
1655
	struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1];
L
Linus Torvalds 已提交
1656 1657
	struct xfrm_dump_info info;

1658 1659 1660
	BUILD_BUG_ON(sizeof(struct xfrm_policy_walk) >
		     sizeof(cb->args) - sizeof(cb->args[0]));

L
Linus Torvalds 已提交
1661 1662 1663 1664
	info.in_skb = cb->skb;
	info.out_skb = skb;
	info.nlmsg_seq = cb->nlh->nlmsg_seq;
	info.nlmsg_flags = NLM_F_MULTI;
1665 1666 1667 1668 1669 1670

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

1671
	(void) xfrm_policy_walk(net, walk, dump_one_policy, &info);
L
Linus Torvalds 已提交
1672 1673 1674 1675 1676 1677 1678 1679 1680 1681

	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;
1682
	int err;
L
Linus Torvalds 已提交
1683

1684
	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
L
Linus Torvalds 已提交
1685 1686 1687 1688 1689 1690 1691 1692
	if (!skb)
		return ERR_PTR(-ENOMEM);

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

1693 1694
	err = dump_one_policy(xp, dir, 0, &info);
	if (err) {
L
Linus Torvalds 已提交
1695
		kfree_skb(skb);
1696
		return ERR_PTR(err);
L
Linus Torvalds 已提交
1697 1698 1699 1700 1701
	}

	return skb;
}

1702
static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
1703
		struct nlattr **attrs)
L
Linus Torvalds 已提交
1704
{
1705
	struct net *net = sock_net(skb->sk);
L
Linus Torvalds 已提交
1706 1707
	struct xfrm_policy *xp;
	struct xfrm_userpolicy_id *p;
1708
	u8 type = XFRM_POLICY_TYPE_MAIN;
L
Linus Torvalds 已提交
1709
	int err;
1710
	struct km_event c;
L
Linus Torvalds 已提交
1711
	int delete;
1712 1713
	struct xfrm_mark m;
	u32 mark = xfrm_mark_get(attrs, &m);
L
Linus Torvalds 已提交
1714

1715
	p = nlmsg_data(nlh);
L
Linus Torvalds 已提交
1716 1717
	delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY;

1718
	err = copy_from_user_policy_type(&type, attrs);
1719 1720 1721
	if (err)
		return err;

L
Linus Torvalds 已提交
1722 1723 1724 1725 1726
	err = verify_policy_dir(p->dir);
	if (err)
		return err;

	if (p->index)
1727
		xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, delete, &err);
1728
	else {
1729
		struct nlattr *rt = attrs[XFRMA_SEC_CTX];
1730
		struct xfrm_sec_ctx *ctx;
1731

1732
		err = verify_sec_ctx_len(attrs);
1733 1734 1735
		if (err)
			return err;

1736
		ctx = NULL;
1737
		if (rt) {
1738
			struct xfrm_user_sec_ctx *uctx = nla_data(rt);
1739

1740
			err = security_xfrm_policy_alloc(&ctx, uctx, GFP_KERNEL);
1741
			if (err)
1742
				return err;
1743
		}
1744
		xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir, &p->sel,
1745
					   ctx, delete, &err);
1746
		security_xfrm_policy_free(ctx);
1747
	}
L
Linus Torvalds 已提交
1748 1749 1750 1751 1752 1753 1754 1755 1756 1757
	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 {
1758
			err = nlmsg_unicast(net->xfrm.nlsk, resp_skb,
1759
					    NETLINK_CB(skb).portid);
L
Linus Torvalds 已提交
1760
		}
1761
	} else {
1762
		xfrm_audit_policy_delete(xp, err ? 0 : 1, true);
1763 1764

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

1767
		c.data.byid = p->index;
1768
		c.event = nlh->nlmsg_type;
1769
		c.seq = nlh->nlmsg_seq;
1770
		c.portid = nlh->nlmsg_pid;
1771
		km_policy_notify(xp, p->dir, &c);
L
Linus Torvalds 已提交
1772 1773
	}

C
Catherine Zhang 已提交
1774
out:
1775
	xfrm_pol_put(xp);
1776 1777
	if (delete && err == 0)
		xfrm_garbage_collect(net);
L
Linus Torvalds 已提交
1778 1779 1780
	return err;
}

1781
static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
1782
		struct nlattr **attrs)
L
Linus Torvalds 已提交
1783
{
1784
	struct net *net = sock_net(skb->sk);
1785
	struct km_event c;
1786
	struct xfrm_usersa_flush *p = nlmsg_data(nlh);
1787
	int err;
L
Linus Torvalds 已提交
1788

1789
	err = xfrm_state_flush(net, p->proto, true);
1790 1791 1792
	if (err) {
		if (err == -ESRCH) /* empty table */
			return 0;
1793
		return err;
1794
	}
1795
	c.data.proto = p->proto;
1796
	c.event = nlh->nlmsg_type;
1797
	c.seq = nlh->nlmsg_seq;
1798
	c.portid = nlh->nlmsg_pid;
1799
	c.net = net;
1800 1801
	km_state_notify(NULL, &c);

L
Linus Torvalds 已提交
1802 1803 1804
	return 0;
}

1805
static inline size_t xfrm_aevent_msgsize(struct xfrm_state *x)
1806
{
1807 1808 1809 1810
	size_t replay_size = x->replay_esn ?
			      xfrm_replay_state_esn_len(x->replay_esn) :
			      sizeof(struct xfrm_replay_state);

1811
	return NLMSG_ALIGN(sizeof(struct xfrm_aevent_id))
1812
	       + nla_total_size(replay_size)
1813
	       + nla_total_size(sizeof(struct xfrm_lifetime_cur))
1814
	       + nla_total_size(sizeof(struct xfrm_mark))
1815 1816 1817
	       + nla_total_size(4) /* XFRM_AE_RTHR */
	       + nla_total_size(4); /* XFRM_AE_ETHR */
}
J
Jamal Hadi Salim 已提交
1818

1819
static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, const struct km_event *c)
J
Jamal Hadi Salim 已提交
1820 1821 1822
{
	struct xfrm_aevent_id *id;
	struct nlmsghdr *nlh;
1823
	int err;
J
Jamal Hadi Salim 已提交
1824

1825
	nlh = nlmsg_put(skb, c->portid, c->seq, XFRM_MSG_NEWAE, sizeof(*id), 0);
1826 1827
	if (nlh == NULL)
		return -EMSGSIZE;
J
Jamal Hadi Salim 已提交
1828

1829
	id = nlmsg_data(nlh);
1830
	memcpy(&id->sa_id.daddr, &x->id.daddr, sizeof(x->id.daddr));
J
Jamal Hadi Salim 已提交
1831 1832 1833
	id->sa_id.spi = x->id.spi;
	id->sa_id.family = x->props.family;
	id->sa_id.proto = x->id.proto;
1834
	memcpy(&id->saddr, &x->props.saddr, sizeof(x->props.saddr));
1835
	id->reqid = x->props.reqid;
J
Jamal Hadi Salim 已提交
1836 1837
	id->flags = c->data.aevent;

1838
	if (x->replay_esn) {
1839 1840 1841
		err = nla_put(skb, XFRMA_REPLAY_ESN_VAL,
			      xfrm_replay_state_esn_len(x->replay_esn),
			      x->replay_esn);
1842
	} else {
1843 1844
		err = nla_put(skb, XFRMA_REPLAY_VAL, sizeof(x->replay),
			      &x->replay);
1845
	}
1846 1847 1848 1849 1850
	if (err)
		goto out_cancel;
	err = nla_put(skb, XFRMA_LTIME_VAL, sizeof(x->curlft), &x->curlft);
	if (err)
		goto out_cancel;
J
Jamal Hadi Salim 已提交
1851

1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865
	if (id->flags & XFRM_AE_RTHR) {
		err = nla_put_u32(skb, XFRMA_REPLAY_THRESH, x->replay_maxdiff);
		if (err)
			goto out_cancel;
	}
	if (id->flags & XFRM_AE_ETHR) {
		err = nla_put_u32(skb, XFRMA_ETIMER_THRESH,
				  x->replay_maxage * 10 / HZ);
		if (err)
			goto out_cancel;
	}
	err = xfrm_mark_put(skb, &x->mark);
	if (err)
		goto out_cancel;
1866

1867 1868
	nlmsg_end(skb, nlh);
	return 0;
J
Jamal Hadi Salim 已提交
1869

1870
out_cancel:
1871
	nlmsg_cancel(skb, nlh);
1872
	return err;
J
Jamal Hadi Salim 已提交
1873 1874
}

1875
static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
1876
		struct nlattr **attrs)
J
Jamal Hadi Salim 已提交
1877
{
1878
	struct net *net = sock_net(skb->sk);
J
Jamal Hadi Salim 已提交
1879 1880 1881 1882
	struct xfrm_state *x;
	struct sk_buff *r_skb;
	int err;
	struct km_event c;
1883 1884
	u32 mark;
	struct xfrm_mark m;
1885
	struct xfrm_aevent_id *p = nlmsg_data(nlh);
J
Jamal Hadi Salim 已提交
1886 1887
	struct xfrm_usersa_id *id = &p->sa_id;

1888 1889 1890
	mark = xfrm_mark_get(attrs, &m);

	x = xfrm_state_lookup(net, mark, &id->daddr, id->spi, id->proto, id->family);
1891
	if (x == NULL)
J
Jamal Hadi Salim 已提交
1892
		return -ESRCH;
1893 1894 1895 1896 1897

	r_skb = nlmsg_new(xfrm_aevent_msgsize(x), GFP_ATOMIC);
	if (r_skb == NULL) {
		xfrm_state_put(x);
		return -ENOMEM;
J
Jamal Hadi Salim 已提交
1898 1899 1900 1901 1902 1903 1904 1905 1906 1907
	}

	/*
	 * 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;
1908
	c.portid = nlh->nlmsg_pid;
J
Jamal Hadi Salim 已提交
1909 1910 1911

	if (build_aevent(r_skb, x, &c) < 0)
		BUG();
1912
	err = nlmsg_unicast(net->xfrm.nlsk, r_skb, NETLINK_CB(skb).portid);
J
Jamal Hadi Salim 已提交
1913 1914 1915 1916 1917
	spin_unlock_bh(&x->lock);
	xfrm_state_put(x);
	return err;
}

1918
static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
1919
		struct nlattr **attrs)
J
Jamal Hadi Salim 已提交
1920
{
1921
	struct net *net = sock_net(skb->sk);
J
Jamal Hadi Salim 已提交
1922 1923
	struct xfrm_state *x;
	struct km_event c;
1924
	int err = -EINVAL;
1925 1926
	u32 mark = 0;
	struct xfrm_mark m;
1927
	struct xfrm_aevent_id *p = nlmsg_data(nlh);
1928
	struct nlattr *rp = attrs[XFRMA_REPLAY_VAL];
1929
	struct nlattr *re = attrs[XFRMA_REPLAY_ESN_VAL];
1930
	struct nlattr *lt = attrs[XFRMA_LTIME_VAL];
J
Jamal Hadi Salim 已提交
1931

1932
	if (!lt && !rp && !re)
J
Jamal Hadi Salim 已提交
1933 1934 1935 1936 1937 1938
		return err;

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

1939 1940 1941
	mark = xfrm_mark_get(attrs, &m);

	x = xfrm_state_lookup(net, mark, &p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family);
J
Jamal Hadi Salim 已提交
1942 1943 1944 1945 1946 1947
	if (x == NULL)
		return -ESRCH;

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

1948
	err = xfrm_replay_verify_len(x->replay_esn, re);
1949 1950 1951
	if (err)
		goto out;

J
Jamal Hadi Salim 已提交
1952
	spin_lock_bh(&x->lock);
1953
	xfrm_update_ae_params(x, attrs, 1);
J
Jamal Hadi Salim 已提交
1954 1955 1956 1957
	spin_unlock_bh(&x->lock);

	c.event = nlh->nlmsg_type;
	c.seq = nlh->nlmsg_seq;
1958
	c.portid = nlh->nlmsg_pid;
J
Jamal Hadi Salim 已提交
1959 1960 1961 1962 1963 1964 1965 1966
	c.data.aevent = XFRM_AE_CU;
	km_state_notify(x, &c);
	err = 0;
out:
	xfrm_state_put(x);
	return err;
}

1967
static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
1968
		struct nlattr **attrs)
L
Linus Torvalds 已提交
1969
{
1970
	struct net *net = sock_net(skb->sk);
1971
	struct km_event c;
1972
	u8 type = XFRM_POLICY_TYPE_MAIN;
1973 1974
	int err;

1975
	err = copy_from_user_policy_type(&type, attrs);
1976 1977
	if (err)
		return err;
1978

1979
	err = xfrm_policy_flush(net, type, true);
1980 1981 1982
	if (err) {
		if (err == -ESRCH) /* empty table */
			return 0;
1983
		return err;
1984 1985
	}

1986
	c.data.type = type;
1987
	c.event = nlh->nlmsg_type;
1988
	c.seq = nlh->nlmsg_seq;
1989
	c.portid = nlh->nlmsg_pid;
1990
	c.net = net;
1991
	km_policy_notify(NULL, 0, &c);
L
Linus Torvalds 已提交
1992 1993 1994
	return 0;
}

1995
static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
1996
		struct nlattr **attrs)
1997
{
1998
	struct net *net = sock_net(skb->sk);
1999
	struct xfrm_policy *xp;
2000
	struct xfrm_user_polexpire *up = nlmsg_data(nlh);
2001
	struct xfrm_userpolicy_info *p = &up->pol;
2002
	u8 type = XFRM_POLICY_TYPE_MAIN;
2003
	int err = -ENOENT;
2004 2005
	struct xfrm_mark m;
	u32 mark = xfrm_mark_get(attrs, &m);
2006

2007
	err = copy_from_user_policy_type(&type, attrs);
2008 2009 2010
	if (err)
		return err;

2011 2012 2013 2014
	err = verify_policy_dir(p->dir);
	if (err)
		return err;

2015
	if (p->index)
2016
		xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, 0, &err);
2017
	else {
2018
		struct nlattr *rt = attrs[XFRMA_SEC_CTX];
2019
		struct xfrm_sec_ctx *ctx;
2020

2021
		err = verify_sec_ctx_len(attrs);
2022 2023 2024
		if (err)
			return err;

2025
		ctx = NULL;
2026
		if (rt) {
2027
			struct xfrm_user_sec_ctx *uctx = nla_data(rt);
2028

2029
			err = security_xfrm_policy_alloc(&ctx, uctx, GFP_KERNEL);
2030
			if (err)
2031
				return err;
2032
		}
2033
		xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir,
2034
					   &p->sel, ctx, 0, &err);
2035
		security_xfrm_policy_free(ctx);
2036 2037
	}
	if (xp == NULL)
2038
		return -ENOENT;
2039

2040
	if (unlikely(xp->walk.dead))
2041 2042 2043 2044 2045
		goto out;

	err = 0;
	if (up->hard) {
		xfrm_policy_delete(xp, p->dir);
2046
		xfrm_audit_policy_delete(xp, 1, true);
2047 2048
	} else {
		// reset the timers here?
J
Jakub Wilk 已提交
2049
		WARN(1, "Don't know what to do with soft policy expire\n");
2050
	}
2051
	km_policy_expired(xp, p->dir, up->hard, nlh->nlmsg_pid);
2052 2053 2054 2055 2056 2057

out:
	xfrm_pol_put(xp);
	return err;
}

2058
static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
2059
		struct nlattr **attrs)
2060
{
2061
	struct net *net = sock_net(skb->sk);
2062 2063
	struct xfrm_state *x;
	int err;
2064
	struct xfrm_user_expire *ue = nlmsg_data(nlh);
2065
	struct xfrm_usersa_info *p = &ue->state;
2066
	struct xfrm_mark m;
2067
	u32 mark = xfrm_mark_get(attrs, &m);
2068

2069
	x = xfrm_state_lookup(net, mark, &p->id.daddr, p->id.spi, p->id.proto, p->family);
2070

2071
	err = -ENOENT;
2072 2073 2074 2075
	if (x == NULL)
		return err;

	spin_lock_bh(&x->lock);
2076
	err = -EINVAL;
2077 2078
	if (x->km.state != XFRM_STATE_VALID)
		goto out;
2079
	km_state_expired(x, ue->hard, nlh->nlmsg_pid);
2080

J
Joy Latten 已提交
2081
	if (ue->hard) {
2082
		__xfrm_state_delete(x);
2083
		xfrm_audit_state_delete(x, 1, true);
J
Joy Latten 已提交
2084
	}
2085
	err = 0;
2086 2087 2088 2089 2090 2091
out:
	spin_unlock_bh(&x->lock);
	xfrm_state_put(x);
	return err;
}

2092
static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh,
2093
		struct nlattr **attrs)
2094
{
2095
	struct net *net = sock_net(skb->sk);
2096 2097 2098
	struct xfrm_policy *xp;
	struct xfrm_user_tmpl *ut;
	int i;
2099
	struct nlattr *rt = attrs[XFRMA_TMPL];
2100
	struct xfrm_mark mark;
2101

2102
	struct xfrm_user_acquire *ua = nlmsg_data(nlh);
2103
	struct xfrm_state *x = xfrm_state_alloc(net);
2104 2105 2106
	int err = -ENOMEM;

	if (!x)
I
Ilpo Järvinen 已提交
2107
		goto nomem;
2108

2109 2110
	xfrm_mark_get(attrs, &mark);

2111
	err = verify_newpolicy_info(&ua->policy);
I
Ilpo Järvinen 已提交
2112 2113
	if (err)
		goto bad_policy;
2114 2115

	/*   build an XP */
2116
	xp = xfrm_policy_construct(net, &ua->policy, attrs, &err);
I
Ilpo Järvinen 已提交
2117 2118
	if (!xp)
		goto free_state;
2119 2120 2121 2122

	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));
2123 2124
	xp->mark.m = x->mark.m = mark.m;
	xp->mark.v = x->mark.v = mark.v;
2125
	ut = nla_data(rt);
2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143
	/* 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 已提交
2144 2145

bad_policy:
S
stephen hemminger 已提交
2146
	WARN(1, "BAD policy passed\n");
I
Ilpo Järvinen 已提交
2147 2148 2149 2150
free_state:
	kfree(x);
nomem:
	return err;
2151 2152
}

2153 2154
#ifdef CONFIG_XFRM_MIGRATE
static int copy_from_user_migrate(struct xfrm_migrate *ma,
2155
				  struct xfrm_kmaddress *k,
2156
				  struct nlattr **attrs, int *num)
2157
{
2158
	struct nlattr *rt = attrs[XFRMA_MIGRATE];
2159 2160 2161
	struct xfrm_user_migrate *um;
	int i, num_migrate;

2162 2163 2164 2165 2166 2167 2168 2169 2170 2171
	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;
	}

2172 2173
	um = nla_data(rt);
	num_migrate = nla_len(rt) / sizeof(*um);
2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196

	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,
2197
			   struct nlattr **attrs)
2198
{
2199
	struct xfrm_userpolicy_id *pi = nlmsg_data(nlh);
2200
	struct xfrm_migrate m[XFRM_MAX_DEPTH];
2201
	struct xfrm_kmaddress km, *kmp;
2202 2203 2204
	u8 type;
	int err;
	int n = 0;
2205
	struct net *net = sock_net(skb->sk);
2206

2207
	if (attrs[XFRMA_MIGRATE] == NULL)
2208
		return -EINVAL;
2209

2210 2211
	kmp = attrs[XFRMA_KMADDRESS] ? &km : NULL;

2212
	err = copy_from_user_policy_type(&type, attrs);
2213 2214 2215
	if (err)
		return err;

2216
	err = copy_from_user_migrate((struct xfrm_migrate *)m, kmp, attrs, &n);
2217 2218 2219 2220 2221 2222
	if (err)
		return err;

	if (!n)
		return 0;

2223
	xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net);
2224 2225 2226 2227 2228

	return 0;
}
#else
static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
2229
			   struct nlattr **attrs)
2230 2231 2232 2233 2234 2235
{
	return -ENOPROTOOPT;
}
#endif

#ifdef CONFIG_XFRM_MIGRATE
2236
static int copy_to_user_migrate(const struct xfrm_migrate *m, struct sk_buff *skb)
2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250
{
	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));

2251
	return nla_put(skb, XFRMA_MIGRATE, sizeof(um), &um);
2252 2253
}

2254
static int copy_to_user_kmaddress(const struct xfrm_kmaddress *k, struct sk_buff *skb)
2255 2256 2257 2258 2259 2260 2261
{
	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));
2262
	memcpy(&uk.remote, &k->remote, sizeof(uk.remote));
2263 2264 2265 2266 2267

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

static inline size_t xfrm_migrate_msgsize(int num_migrate, int with_kma)
2268 2269
{
	return NLMSG_ALIGN(sizeof(struct xfrm_userpolicy_id))
2270 2271 2272
	      + (with_kma ? nla_total_size(sizeof(struct xfrm_kmaddress)) : 0)
	      + nla_total_size(sizeof(struct xfrm_user_migrate) * num_migrate)
	      + userpolicy_type_attrsize();
2273 2274
}

2275 2276 2277
static int build_migrate(struct sk_buff *skb, const struct xfrm_migrate *m,
			 int num_migrate, const struct xfrm_kmaddress *k,
			 const struct xfrm_selector *sel, u8 dir, u8 type)
2278
{
2279
	const struct xfrm_migrate *mp;
2280 2281
	struct xfrm_userpolicy_id *pol_id;
	struct nlmsghdr *nlh;
2282
	int i, err;
2283

2284 2285 2286
	nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_MIGRATE, sizeof(*pol_id), 0);
	if (nlh == NULL)
		return -EMSGSIZE;
2287

2288
	pol_id = nlmsg_data(nlh);
2289 2290 2291 2292 2293
	/* 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;

2294 2295 2296 2297 2298 2299 2300 2301
	if (k != NULL) {
		err = copy_to_user_kmaddress(k, skb);
		if (err)
			goto out_cancel;
	}
	err = copy_to_user_policy_type(type, skb);
	if (err)
		goto out_cancel;
2302
	for (i = 0, mp = m ; i < num_migrate; i++, mp++) {
2303 2304 2305
		err = copy_to_user_migrate(mp, skb);
		if (err)
			goto out_cancel;
2306 2307
	}

2308 2309
	nlmsg_end(skb, nlh);
	return 0;
2310 2311

out_cancel:
2312
	nlmsg_cancel(skb, nlh);
2313
	return err;
2314 2315
}

2316 2317 2318
static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
			     const struct xfrm_migrate *m, int num_migrate,
			     const struct xfrm_kmaddress *k)
2319
{
2320
	struct net *net = &init_net;
2321 2322
	struct sk_buff *skb;

2323
	skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate, !!k), GFP_ATOMIC);
2324 2325 2326 2327
	if (skb == NULL)
		return -ENOMEM;

	/* build migrate */
2328
	if (build_migrate(skb, m, num_migrate, k, sel, dir, type) < 0)
2329 2330
		BUG();

2331
	return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_MIGRATE);
2332 2333
}
#else
2334 2335 2336
static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
			     const struct xfrm_migrate *m, int num_migrate,
			     const struct xfrm_kmaddress *k)
2337 2338 2339 2340
{
	return -ENOPROTOOPT;
}
#endif
J
Jamal Hadi Salim 已提交
2341

2342
#define XMSGSIZE(type) sizeof(struct type)
2343 2344

static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
2345
	[XFRM_MSG_NEWSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info),
2346 2347 2348 2349 2350 2351
	[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),
2352
	[XFRM_MSG_ACQUIRE     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_acquire),
2353
	[XFRM_MSG_EXPIRE      - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_expire),
2354
	[XFRM_MSG_UPDPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info),
2355
	[XFRM_MSG_UPDSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info),
2356
	[XFRM_MSG_POLEXPIRE   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire),
2357
	[XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush),
2358
	[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = 0,
J
Jamal Hadi Salim 已提交
2359 2360
	[XFRM_MSG_NEWAE       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
	[XFRM_MSG_GETAE       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
2361
	[XFRM_MSG_REPORT      - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report),
2362
	[XFRM_MSG_MIGRATE     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
2363
	[XFRM_MSG_GETSADINFO  - XFRM_MSG_BASE] = sizeof(u32),
2364
	[XFRM_MSG_NEWSPDINFO  - XFRM_MSG_BASE] = sizeof(u32),
2365
	[XFRM_MSG_GETSPDINFO  - XFRM_MSG_BASE] = sizeof(u32),
L
Linus Torvalds 已提交
2366 2367
};

2368 2369
#undef XMSGSIZE

2370
static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
J
jamal 已提交
2371 2372 2373 2374
	[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)},
2375
	[XFRMA_ALG_AEAD]	= { .len = sizeof(struct xfrm_algo_aead) },
2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389
	[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) },
2390
	[XFRMA_KMADDRESS]	= { .len = sizeof(struct xfrm_user_kmaddress) },
2391
	[XFRMA_MARK]		= { .len = sizeof(struct xfrm_mark) },
2392
	[XFRMA_TFCPAD]		= { .type = NLA_U32 },
2393
	[XFRMA_REPLAY_ESN_VAL]	= { .len = sizeof(struct xfrm_replay_state_esn) },
2394
	[XFRMA_SA_EXTRA_FLAGS]	= { .type = NLA_U32 },
2395
	[XFRMA_PROTO]		= { .type = NLA_U8 },
2396
	[XFRMA_ADDRESS_FILTER]	= { .len = sizeof(struct xfrm_address_filter) },
2397 2398
};

2399 2400 2401 2402 2403
static const struct nla_policy xfrma_spd_policy[XFRMA_SPD_MAX+1] = {
	[XFRMA_SPD_IPV4_HTHRESH] = { .len = sizeof(struct xfrmu_spdhthresh) },
	[XFRMA_SPD_IPV6_HTHRESH] = { .len = sizeof(struct xfrmu_spdhthresh) },
};

2404
static const struct xfrm_link {
2405
	int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);
L
Linus Torvalds 已提交
2406
	int (*dump)(struct sk_buff *, struct netlink_callback *);
2407
	int (*done)(struct netlink_callback *);
2408 2409
	const struct nla_policy *nla_pol;
	int nla_max;
2410 2411 2412 2413
} 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,
2414 2415
						   .dump = xfrm_dump_sa,
						   .done = xfrm_dump_sa_done  },
2416 2417 2418
	[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,
2419 2420
						   .dump = xfrm_dump_policy,
						   .done = xfrm_dump_policy_done },
2421
	[XFRM_MSG_ALLOCSPI    - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi },
2422
	[XFRM_MSG_ACQUIRE     - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire   },
2423
	[XFRM_MSG_EXPIRE      - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire },
2424 2425
	[XFRM_MSG_UPDPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_add_policy    },
	[XFRM_MSG_UPDSA       - XFRM_MSG_BASE] = { .doit = xfrm_add_sa        },
2426
	[XFRM_MSG_POLEXPIRE   - XFRM_MSG_BASE] = { .doit = xfrm_add_pol_expire},
2427 2428
	[XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa      },
	[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy  },
J
Jamal Hadi Salim 已提交
2429 2430
	[XFRM_MSG_NEWAE       - XFRM_MSG_BASE] = { .doit = xfrm_new_ae  },
	[XFRM_MSG_GETAE       - XFRM_MSG_BASE] = { .doit = xfrm_get_ae  },
2431
	[XFRM_MSG_MIGRATE     - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate    },
2432
	[XFRM_MSG_GETSADINFO  - XFRM_MSG_BASE] = { .doit = xfrm_get_sadinfo   },
2433 2434 2435
	[XFRM_MSG_NEWSPDINFO  - XFRM_MSG_BASE] = { .doit = xfrm_set_spdinfo,
						   .nla_pol = xfrma_spd_policy,
						   .nla_max = XFRMA_SPD_MAX },
J
Jamal Hadi Salim 已提交
2436
	[XFRM_MSG_GETSPDINFO  - XFRM_MSG_BASE] = { .doit = xfrm_get_spdinfo   },
L
Linus Torvalds 已提交
2437 2438
};

2439
static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
L
Linus Torvalds 已提交
2440
{
2441
	struct net *net = sock_net(skb->sk);
2442
	struct nlattr *attrs[XFRMA_MAX+1];
2443
	const struct xfrm_link *link;
2444
	int type, err;
L
Linus Torvalds 已提交
2445

2446 2447 2448 2449 2450
#ifdef CONFIG_COMPAT
	if (is_compat_task())
		return -ENOTSUPP;
#endif

L
Linus Torvalds 已提交
2451 2452
	type = nlh->nlmsg_type;
	if (type > XFRM_MSG_MAX)
2453
		return -EINVAL;
L
Linus Torvalds 已提交
2454 2455 2456 2457 2458

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

	/* All operations require privileges, even GET */
2459
	if (!netlink_net_capable(skb, CAP_NET_ADMIN))
2460
		return -EPERM;
L
Linus Torvalds 已提交
2461

2462 2463
	if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) ||
	     type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) &&
2464
	    (nlh->nlmsg_flags & NLM_F_DUMP)) {
L
Linus Torvalds 已提交
2465
		if (link->dump == NULL)
2466
			return -EINVAL;
2467

2468 2469 2470 2471 2472 2473 2474
		{
			struct netlink_dump_control c = {
				.dump = link->dump,
				.done = link->done,
			};
			return netlink_dump_start(net->xfrm.nlsk, skb, nlh, &c);
		}
L
Linus Torvalds 已提交
2475 2476
	}

2477 2478 2479
	err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs,
			  link->nla_max ? : XFRMA_MAX,
			  link->nla_pol ? : xfrma_policy);
2480 2481
	if (err < 0)
		return err;
L
Linus Torvalds 已提交
2482 2483

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

2486
	return link->doit(skb, nlh, attrs);
L
Linus Torvalds 已提交
2487 2488
}

2489
static void xfrm_netlink_rcv(struct sk_buff *skb)
L
Linus Torvalds 已提交
2490
{
F
Fan Du 已提交
2491 2492 2493
	struct net *net = sock_net(skb->sk);

	mutex_lock(&net->xfrm.xfrm_cfg_mutex);
2494
	netlink_rcv_skb(skb, &xfrm_user_rcv_msg);
F
Fan Du 已提交
2495
	mutex_unlock(&net->xfrm.xfrm_cfg_mutex);
L
Linus Torvalds 已提交
2496 2497
}

2498 2499
static inline size_t xfrm_expire_msgsize(void)
{
2500 2501
	return NLMSG_ALIGN(sizeof(struct xfrm_user_expire))
	       + nla_total_size(sizeof(struct xfrm_mark));
2502 2503
}

2504
static int build_expire(struct sk_buff *skb, struct xfrm_state *x, const struct km_event *c)
L
Linus Torvalds 已提交
2505 2506 2507
{
	struct xfrm_user_expire *ue;
	struct nlmsghdr *nlh;
2508
	int err;
L
Linus Torvalds 已提交
2509

2510
	nlh = nlmsg_put(skb, c->portid, 0, XFRM_MSG_EXPIRE, sizeof(*ue), 0);
2511 2512
	if (nlh == NULL)
		return -EMSGSIZE;
L
Linus Torvalds 已提交
2513

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

2518 2519 2520
	err = xfrm_mark_put(skb, &x->mark);
	if (err)
		return err;
2521

2522 2523
	nlmsg_end(skb, nlh);
	return 0;
L
Linus Torvalds 已提交
2524 2525
}

2526
static int xfrm_exp_state_notify(struct xfrm_state *x, const struct km_event *c)
L
Linus Torvalds 已提交
2527
{
2528
	struct net *net = xs_net(x);
L
Linus Torvalds 已提交
2529 2530
	struct sk_buff *skb;

2531
	skb = nlmsg_new(xfrm_expire_msgsize(), GFP_ATOMIC);
L
Linus Torvalds 已提交
2532 2533 2534
	if (skb == NULL)
		return -ENOMEM;

2535 2536 2537 2538
	if (build_expire(skb, x, c) < 0) {
		kfree_skb(skb);
		return -EMSGSIZE;
	}
L
Linus Torvalds 已提交
2539

2540
	return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_EXPIRE);
L
Linus Torvalds 已提交
2541 2542
}

2543
static int xfrm_aevent_state_notify(struct xfrm_state *x, const struct km_event *c)
J
Jamal Hadi Salim 已提交
2544
{
2545
	struct net *net = xs_net(x);
J
Jamal Hadi Salim 已提交
2546 2547
	struct sk_buff *skb;

2548
	skb = nlmsg_new(xfrm_aevent_msgsize(x), GFP_ATOMIC);
J
Jamal Hadi Salim 已提交
2549 2550 2551 2552 2553 2554
	if (skb == NULL)
		return -ENOMEM;

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

2555
	return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_AEVENTS);
J
Jamal Hadi Salim 已提交
2556 2557
}

2558
static int xfrm_notify_sa_flush(const struct km_event *c)
2559
{
2560
	struct net *net = c->net;
2561 2562 2563
	struct xfrm_usersa_flush *p;
	struct nlmsghdr *nlh;
	struct sk_buff *skb;
2564
	int len = NLMSG_ALIGN(sizeof(struct xfrm_usersa_flush));
2565

2566
	skb = nlmsg_new(len, GFP_ATOMIC);
2567 2568 2569
	if (skb == NULL)
		return -ENOMEM;

2570
	nlh = nlmsg_put(skb, c->portid, c->seq, XFRM_MSG_FLUSHSA, sizeof(*p), 0);
2571 2572 2573 2574
	if (nlh == NULL) {
		kfree_skb(skb);
		return -EMSGSIZE;
	}
2575

2576
	p = nlmsg_data(nlh);
2577
	p->proto = c->data.proto;
2578

2579
	nlmsg_end(skb, nlh);
2580

2581
	return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_SA);
2582 2583
}

2584
static inline size_t xfrm_sa_len(struct xfrm_state *x)
2585
{
2586
	size_t l = 0;
2587 2588
	if (x->aead)
		l += nla_total_size(aead_len(x->aead));
2589 2590 2591 2592 2593
	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));
	}
2594
	if (x->ealg)
2595
		l += nla_total_size(xfrm_alg_len(x->ealg));
2596
	if (x->calg)
2597
		l += nla_total_size(sizeof(*x->calg));
2598
	if (x->encap)
2599
		l += nla_total_size(sizeof(*x->encap));
2600 2601
	if (x->tfcpad)
		l += nla_total_size(sizeof(x->tfcpad));
2602 2603
	if (x->replay_esn)
		l += nla_total_size(xfrm_replay_state_esn_len(x->replay_esn));
2604 2605
	else
		l += nla_total_size(sizeof(struct xfrm_replay_state));
2606 2607 2608 2609 2610
	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));
2611 2612
	if (x->props.extra_flags)
		l += nla_total_size(sizeof(x->props.extra_flags));
2613

2614 2615
	/* Must count x->lastused as it may become non-zero behind our back. */
	l += nla_total_size(sizeof(u64));
2616 2617 2618 2619

	return l;
}

2620
static int xfrm_notify_sa(struct xfrm_state *x, const struct km_event *c)
2621
{
2622
	struct net *net = xs_net(x);
2623
	struct xfrm_usersa_info *p;
2624
	struct xfrm_usersa_id *id;
2625 2626 2627
	struct nlmsghdr *nlh;
	struct sk_buff *skb;
	int len = xfrm_sa_len(x);
2628
	int headlen, err;
2629 2630 2631

	headlen = sizeof(*p);
	if (c->event == XFRM_MSG_DELSA) {
2632
		len += nla_total_size(headlen);
2633
		headlen = sizeof(*id);
2634
		len += nla_total_size(sizeof(struct xfrm_mark));
2635
	}
2636
	len += NLMSG_ALIGN(headlen);
2637

2638
	skb = nlmsg_new(len, GFP_ATOMIC);
2639 2640 2641
	if (skb == NULL)
		return -ENOMEM;

2642
	nlh = nlmsg_put(skb, c->portid, c->seq, c->event, headlen, 0);
2643
	err = -EMSGSIZE;
2644
	if (nlh == NULL)
2645
		goto out_free_skb;
2646

2647
	p = nlmsg_data(nlh);
2648
	if (c->event == XFRM_MSG_DELSA) {
2649 2650
		struct nlattr *attr;

2651
		id = nlmsg_data(nlh);
2652 2653 2654 2655 2656
		memcpy(&id->daddr, &x->id.daddr, sizeof(id->daddr));
		id->spi = x->id.spi;
		id->family = x->props.family;
		id->proto = x->id.proto;

2657
		attr = nla_reserve(skb, XFRMA_SA, sizeof(*p));
2658
		err = -EMSGSIZE;
2659
		if (attr == NULL)
2660
			goto out_free_skb;
2661 2662

		p = nla_data(attr);
2663
	}
2664 2665 2666
	err = copy_to_user_state_extra(x, p, skb);
	if (err)
		goto out_free_skb;
2667

2668
	nlmsg_end(skb, nlh);
2669

2670
	return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_SA);
2671

2672
out_free_skb:
2673
	kfree_skb(skb);
2674
	return err;
2675 2676
}

2677
static int xfrm_send_state_notify(struct xfrm_state *x, const struct km_event *c)
2678 2679 2680
{

	switch (c->event) {
2681
	case XFRM_MSG_EXPIRE:
2682
		return xfrm_exp_state_notify(x, c);
J
Jamal Hadi Salim 已提交
2683 2684
	case XFRM_MSG_NEWAE:
		return xfrm_aevent_state_notify(x, c);
2685 2686 2687
	case XFRM_MSG_DELSA:
	case XFRM_MSG_UPDSA:
	case XFRM_MSG_NEWSA:
2688
		return xfrm_notify_sa(x, c);
2689
	case XFRM_MSG_FLUSHSA:
2690 2691
		return xfrm_notify_sa_flush(c);
	default:
S
stephen hemminger 已提交
2692 2693 2694
		printk(KERN_NOTICE "xfrm_user: Unknown SA event %d\n",
		       c->event);
		break;
2695 2696 2697 2698 2699 2700
	}

	return 0;

}

2701 2702 2703 2704 2705
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)
2706
	       + nla_total_size(sizeof(struct xfrm_mark))
2707 2708 2709 2710
	       + nla_total_size(xfrm_user_sec_ctx_size(x->security))
	       + userpolicy_type_attrsize();
}

L
Linus Torvalds 已提交
2711
static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,
2712
			 struct xfrm_tmpl *xt, struct xfrm_policy *xp)
L
Linus Torvalds 已提交
2713
{
2714
	__u32 seq = xfrm_get_acqseq();
L
Linus Torvalds 已提交
2715 2716
	struct xfrm_user_acquire *ua;
	struct nlmsghdr *nlh;
2717
	int err;
L
Linus Torvalds 已提交
2718

2719 2720 2721
	nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_ACQUIRE, sizeof(*ua), 0);
	if (nlh == NULL)
		return -EMSGSIZE;
L
Linus Torvalds 已提交
2722

2723
	ua = nlmsg_data(nlh);
L
Linus Torvalds 已提交
2724 2725 2726
	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));
2727
	copy_to_user_policy(xp, &ua->policy, XFRM_POLICY_OUT);
L
Linus Torvalds 已提交
2728 2729 2730 2731 2732
	ua->aalgos = xt->aalgos;
	ua->ealgos = xt->ealgos;
	ua->calgos = xt->calgos;
	ua->seq = x->km.seq = seq;

2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743
	err = copy_to_user_tmpl(xp, skb);
	if (!err)
		err = copy_to_user_state_sec_ctx(x, skb);
	if (!err)
		err = copy_to_user_policy_type(xp->type, skb);
	if (!err)
		err = xfrm_mark_put(skb, &xp->mark);
	if (err) {
		nlmsg_cancel(skb, nlh);
		return err;
	}
L
Linus Torvalds 已提交
2744

2745 2746
	nlmsg_end(skb, nlh);
	return 0;
L
Linus Torvalds 已提交
2747 2748 2749
}

static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt,
2750
			     struct xfrm_policy *xp)
L
Linus Torvalds 已提交
2751
{
2752
	struct net *net = xs_net(x);
L
Linus Torvalds 已提交
2753 2754
	struct sk_buff *skb;

2755
	skb = nlmsg_new(xfrm_acquire_msgsize(x, xp), GFP_ATOMIC);
L
Linus Torvalds 已提交
2756 2757 2758
	if (skb == NULL)
		return -ENOMEM;

2759
	if (build_acquire(skb, x, xt, xp) < 0)
L
Linus Torvalds 已提交
2760 2761
		BUG();

2762
	return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_ACQUIRE);
L
Linus Torvalds 已提交
2763 2764 2765 2766 2767
}

/* User gives us xfrm_user_policy_info followed by an array of 0
 * or more templates.
 */
2768
static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt,
L
Linus Torvalds 已提交
2769 2770
					       u8 *data, int len, int *dir)
{
2771
	struct net *net = sock_net(sk);
L
Linus Torvalds 已提交
2772 2773 2774 2775 2776
	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;

2777
	switch (sk->sk_family) {
L
Linus Torvalds 已提交
2778 2779 2780 2781 2782 2783
	case AF_INET:
		if (opt != IP_XFRM_POLICY) {
			*dir = -EOPNOTSUPP;
			return NULL;
		}
		break;
E
Eric Dumazet 已提交
2784
#if IS_ENABLED(CONFIG_IPV6)
L
Linus Torvalds 已提交
2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803
	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));
2804
	if (validate_tmpl(nr, ut, p->sel.family))
L
Linus Torvalds 已提交
2805 2806
		return NULL;

2807 2808 2809
	if (p->dir > XFRM_POLICY_OUT)
		return NULL;

2810
	xp = xfrm_policy_alloc(net, GFP_ATOMIC);
L
Linus Torvalds 已提交
2811 2812 2813 2814 2815 2816
	if (xp == NULL) {
		*dir = -ENOBUFS;
		return NULL;
	}

	copy_from_user_policy(xp, p);
2817
	xp->type = XFRM_POLICY_TYPE_MAIN;
L
Linus Torvalds 已提交
2818 2819 2820 2821 2822 2823 2824
	copy_templates(xp, ut, nr);

	*dir = p->dir;

	return xp;
}

2825 2826 2827 2828 2829
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))
2830
	       + nla_total_size(sizeof(struct xfrm_mark))
2831 2832 2833
	       + userpolicy_type_attrsize();
}

L
Linus Torvalds 已提交
2834
static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp,
2835
			   int dir, const struct km_event *c)
L
Linus Torvalds 已提交
2836 2837
{
	struct xfrm_user_polexpire *upe;
J
Jamal Hadi Salim 已提交
2838
	int hard = c->data.hard;
2839 2840
	struct nlmsghdr *nlh;
	int err;
L
Linus Torvalds 已提交
2841

2842
	nlh = nlmsg_put(skb, c->portid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe), 0);
2843 2844
	if (nlh == NULL)
		return -EMSGSIZE;
L
Linus Torvalds 已提交
2845

2846
	upe = nlmsg_data(nlh);
L
Linus Torvalds 已提交
2847
	copy_to_user_policy(xp, &upe->pol, dir);
2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858
	err = copy_to_user_tmpl(xp, skb);
	if (!err)
		err = copy_to_user_sec_ctx(xp, skb);
	if (!err)
		err = copy_to_user_policy_type(xp->type, skb);
	if (!err)
		err = xfrm_mark_put(skb, &xp->mark);
	if (err) {
		nlmsg_cancel(skb, nlh);
		return err;
	}
L
Linus Torvalds 已提交
2859 2860
	upe->hard = !!hard;

2861 2862
	nlmsg_end(skb, nlh);
	return 0;
L
Linus Torvalds 已提交
2863 2864
}

2865
static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c)
L
Linus Torvalds 已提交
2866
{
2867
	struct net *net = xp_net(xp);
L
Linus Torvalds 已提交
2868 2869
	struct sk_buff *skb;

2870
	skb = nlmsg_new(xfrm_polexpire_msgsize(xp), GFP_ATOMIC);
L
Linus Torvalds 已提交
2871 2872 2873
	if (skb == NULL)
		return -ENOMEM;

J
Jamal Hadi Salim 已提交
2874
	if (build_polexpire(skb, xp, dir, c) < 0)
L
Linus Torvalds 已提交
2875 2876
		BUG();

2877
	return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_EXPIRE);
L
Linus Torvalds 已提交
2878 2879
}

2880
static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, const struct km_event *c)
2881
{
2882
	int len = nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr);
2883
	struct net *net = xp_net(xp);
2884
	struct xfrm_userpolicy_info *p;
2885
	struct xfrm_userpolicy_id *id;
2886 2887
	struct nlmsghdr *nlh;
	struct sk_buff *skb;
2888
	int headlen, err;
2889 2890 2891

	headlen = sizeof(*p);
	if (c->event == XFRM_MSG_DELPOLICY) {
2892
		len += nla_total_size(headlen);
2893 2894
		headlen = sizeof(*id);
	}
2895
	len += userpolicy_type_attrsize();
2896
	len += nla_total_size(sizeof(struct xfrm_mark));
2897
	len += NLMSG_ALIGN(headlen);
2898

2899
	skb = nlmsg_new(len, GFP_ATOMIC);
2900 2901 2902
	if (skb == NULL)
		return -ENOMEM;

2903
	nlh = nlmsg_put(skb, c->portid, c->seq, c->event, headlen, 0);
2904
	err = -EMSGSIZE;
2905
	if (nlh == NULL)
2906
		goto out_free_skb;
2907

2908
	p = nlmsg_data(nlh);
2909
	if (c->event == XFRM_MSG_DELPOLICY) {
2910 2911
		struct nlattr *attr;

2912
		id = nlmsg_data(nlh);
2913 2914 2915 2916 2917 2918 2919
		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));

2920
		attr = nla_reserve(skb, XFRMA_POLICY, sizeof(*p));
2921
		err = -EMSGSIZE;
2922
		if (attr == NULL)
2923
			goto out_free_skb;
2924 2925

		p = nla_data(attr);
2926
	}
2927 2928

	copy_to_user_policy(xp, p, dir);
2929 2930 2931 2932 2933 2934 2935
	err = copy_to_user_tmpl(xp, skb);
	if (!err)
		err = copy_to_user_policy_type(xp->type, skb);
	if (!err)
		err = xfrm_mark_put(skb, &xp->mark);
	if (err)
		goto out_free_skb;
2936

2937
	nlmsg_end(skb, nlh);
2938

2939
	return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_POLICY);
2940

2941
out_free_skb:
2942
	kfree_skb(skb);
2943
	return err;
2944 2945
}

2946
static int xfrm_notify_policy_flush(const struct km_event *c)
2947
{
2948
	struct net *net = c->net;
2949 2950
	struct nlmsghdr *nlh;
	struct sk_buff *skb;
2951
	int err;
2952

2953
	skb = nlmsg_new(userpolicy_type_attrsize(), GFP_ATOMIC);
2954 2955 2956
	if (skb == NULL)
		return -ENOMEM;

2957
	nlh = nlmsg_put(skb, c->portid, c->seq, XFRM_MSG_FLUSHPOLICY, 0, 0);
2958
	err = -EMSGSIZE;
2959
	if (nlh == NULL)
2960 2961 2962 2963
		goto out_free_skb;
	err = copy_to_user_policy_type(c->data.type, skb);
	if (err)
		goto out_free_skb;
2964

2965
	nlmsg_end(skb, nlh);
2966

2967
	return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_POLICY);
2968

2969
out_free_skb:
2970
	kfree_skb(skb);
2971
	return err;
2972 2973
}

2974
static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c)
2975 2976 2977
{

	switch (c->event) {
2978 2979 2980
	case XFRM_MSG_NEWPOLICY:
	case XFRM_MSG_UPDPOLICY:
	case XFRM_MSG_DELPOLICY:
2981
		return xfrm_notify_policy(xp, dir, c);
2982
	case XFRM_MSG_FLUSHPOLICY:
2983
		return xfrm_notify_policy_flush(c);
2984
	case XFRM_MSG_POLEXPIRE:
2985 2986
		return xfrm_exp_policy_notify(xp, dir, c);
	default:
S
stephen hemminger 已提交
2987 2988
		printk(KERN_NOTICE "xfrm_user: Unknown Policy event %d\n",
		       c->event);
2989 2990 2991 2992 2993 2994
	}

	return 0;

}

2995 2996 2997 2998 2999
static inline size_t xfrm_report_msgsize(void)
{
	return NLMSG_ALIGN(sizeof(struct xfrm_user_report));
}

3000 3001 3002 3003 3004 3005
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;

3006 3007 3008
	nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur), 0);
	if (nlh == NULL)
		return -EMSGSIZE;
3009

3010
	ur = nlmsg_data(nlh);
3011 3012 3013
	ur->proto = proto;
	memcpy(&ur->sel, sel, sizeof(ur->sel));

3014 3015 3016 3017 3018 3019 3020
	if (addr) {
		int err = nla_put(skb, XFRMA_COADDR, sizeof(*addr), addr);
		if (err) {
			nlmsg_cancel(skb, nlh);
			return err;
		}
	}
3021 3022
	nlmsg_end(skb, nlh);
	return 0;
3023 3024
}

3025 3026
static int xfrm_send_report(struct net *net, u8 proto,
			    struct xfrm_selector *sel, xfrm_address_t *addr)
3027 3028 3029
{
	struct sk_buff *skb;

3030
	skb = nlmsg_new(xfrm_report_msgsize(), GFP_ATOMIC);
3031 3032 3033 3034 3035 3036
	if (skb == NULL)
		return -ENOMEM;

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

3037
	return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_REPORT);
3038 3039
}

3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066
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;

3067 3068
	nlmsg_end(skb, nlh);
	return 0;
3069 3070 3071 3072 3073
}

static int xfrm_send_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr,
			     __be16 sport)
{
3074
	struct net *net = xs_net(x);
3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089
	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();

3090
	return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_MAPPING);
3091 3092
}

3093 3094 3095 3096 3097
static bool xfrm_is_alive(const struct km_event *c)
{
	return (bool)xfrm_acquire_is_on(c->net);
}

L
Linus Torvalds 已提交
3098 3099 3100 3101 3102 3103
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,
3104
	.report		= xfrm_send_report,
3105
	.migrate	= xfrm_send_migrate,
3106
	.new_mapping	= xfrm_send_mapping,
3107
	.is_alive	= xfrm_is_alive,
L
Linus Torvalds 已提交
3108 3109
};

3110
static int __net_init xfrm_user_net_init(struct net *net)
L
Linus Torvalds 已提交
3111
{
3112
	struct sock *nlsk;
3113 3114 3115 3116
	struct netlink_kernel_cfg cfg = {
		.groups	= XFRMNLGRP_MAX,
		.input	= xfrm_netlink_rcv,
	};
3117

3118
	nlsk = netlink_kernel_create(net, NETLINK_XFRM, &cfg);
3119
	if (nlsk == NULL)
L
Linus Torvalds 已提交
3120
		return -ENOMEM;
3121
	net->xfrm.nlsk_stash = nlsk; /* Don't set to NULL */
3122
	rcu_assign_pointer(net->xfrm.nlsk, nlsk);
L
Linus Torvalds 已提交
3123 3124 3125
	return 0;
}

3126
static void __net_exit xfrm_user_net_exit(struct list_head *net_exit_list)
L
Linus Torvalds 已提交
3127
{
3128 3129
	struct net *net;
	list_for_each_entry(net, net_exit_list, exit_list)
3130
		RCU_INIT_POINTER(net->xfrm.nlsk, NULL);
3131 3132 3133
	synchronize_net();
	list_for_each_entry(net, net_exit_list, exit_list)
		netlink_kernel_release(net->xfrm.nlsk_stash);
L
Linus Torvalds 已提交
3134 3135
}

3136
static struct pernet_operations xfrm_user_net_ops = {
3137 3138
	.init	    = xfrm_user_net_init,
	.exit_batch = xfrm_user_net_exit,
3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161
};

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 已提交
3162 3163 3164
module_init(xfrm_user_init);
module_exit(xfrm_user_exit);
MODULE_LICENSE("GPL");
3165
MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM);
3166