Blame view

net/xfrm/xfrm_user.c 68.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
10
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
   */
9409f38a0   Herbert Xu   [IPSEC]: Move lin...
12
  #include <linux/crypto.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
15
16
17
18
19
20
  #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>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
23
24
25
26
  #include <linux/pfkeyv2.h>
  #include <linux/ipsec.h>
  #include <linux/init.h>
  #include <linux/security.h>
  #include <net/sock.h>
  #include <net/xfrm.h>
88fc2c843   Thomas Graf   [XFRM]: Use gener...
27
  #include <net/netlink.h>
fa6dd8a2c   Nicolas Dichtel   xfrm: check trunc...
28
  #include <net/ah.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  #include <asm/uaccess.h>
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
30
  #if IS_ENABLED(CONFIG_IPV6)
e23c7194a   Masahide NAKAMURA   [XFRM] STATE: Add...
31
32
  #include <linux/in6.h>
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33

1a6509d99   Herbert Xu   [IPSEC]: Add supp...
34
35
36
37
  static inline int aead_len(struct xfrm_algo_aead *alg)
  {
  	return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
  }
5424f32e4   Thomas Graf   [XFRM] netlink: U...
38
  static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
  {
5424f32e4   Thomas Graf   [XFRM] netlink: U...
40
  	struct nlattr *rt = attrs[type];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
44
  	struct xfrm_algo *algp;
  
  	if (!rt)
  		return 0;
5424f32e4   Thomas Graf   [XFRM] netlink: U...
45
  	algp = nla_data(rt);
0f99be0d1   Eric Dumazet   [XFRM]: xfrm_algo...
46
  	if (nla_len(rt) < xfrm_alg_len(algp))
31c26852c   Herbert Xu   [IPSEC]: Verify k...
47
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
  	switch (type) {
  	case XFRMA_ALG_AUTH:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  	case XFRMA_ALG_CRYPT:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
  	case XFRMA_ALG_COMP:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
55
  		break;
  
  	default:
  		return -EINVAL;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
56
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
60
  
  	algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0';
  	return 0;
  }
4447bb33f   Martin Willi   xfrm: Store aalg ...
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  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;
  }
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  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;
  }
5424f32e4   Thomas Graf   [XFRM] netlink: U...
91
  static void verify_one_addr(struct nlattr **attrs, enum xfrm_attr_type_t type,
eb2971b68   Masahide NAKAMURA   [XFRM] STATE: Sea...
92
93
  			   xfrm_address_t **addrp)
  {
5424f32e4   Thomas Graf   [XFRM] netlink: U...
94
  	struct nlattr *rt = attrs[type];
eb2971b68   Masahide NAKAMURA   [XFRM] STATE: Sea...
95

cf5cb79f6   Thomas Graf   [XFRM] netlink: E...
96
  	if (rt && addrp)
5424f32e4   Thomas Graf   [XFRM] netlink: U...
97
  		*addrp = nla_data(rt);
eb2971b68   Masahide NAKAMURA   [XFRM] STATE: Sea...
98
  }
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
99

5424f32e4   Thomas Graf   [XFRM] netlink: U...
100
  static inline int verify_sec_ctx_len(struct nlattr **attrs)
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
101
  {
5424f32e4   Thomas Graf   [XFRM] netlink: U...
102
  	struct nlattr *rt = attrs[XFRMA_SEC_CTX];
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
103
  	struct xfrm_user_sec_ctx *uctx;
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
104
105
106
  
  	if (!rt)
  		return 0;
5424f32e4   Thomas Graf   [XFRM] netlink: U...
107
  	uctx = nla_data(rt);
cf5cb79f6   Thomas Graf   [XFRM] netlink: E...
108
  	if (uctx->len != (sizeof(struct xfrm_user_sec_ctx) + uctx->ctx_len))
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
109
110
111
112
  		return -EINVAL;
  
  	return 0;
  }
d8647b79c   Steffen Klassert   xfrm: Add user in...
113
114
115
116
  static inline int verify_replay(struct xfrm_usersa_info *p,
  				struct nlattr **attrs)
  {
  	struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL];
7833aa05b   Steffen Klassert   xfrm: Check for t...
117
118
  	if ((p->flags & XFRM_STATE_ESN) && !rt)
  		return -EINVAL;
d8647b79c   Steffen Klassert   xfrm: Add user in...
119
120
  	if (!rt)
  		return 0;
02aadf72f   Steffen Klassert   xfrm: Restrict ex...
121
122
  	if (p->id.proto != IPPROTO_ESP)
  		return -EINVAL;
d8647b79c   Steffen Klassert   xfrm: Add user in...
123
124
125
126
127
  	if (p->replay_window != 0)
  		return -EINVAL;
  
  	return 0;
  }
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
128

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
  static int verify_newsa_info(struct xfrm_usersa_info *p,
5424f32e4   Thomas Graf   [XFRM] netlink: U...
130
  			     struct nlattr **attrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
134
135
136
137
138
139
  {
  	int err;
  
  	err = -EINVAL;
  	switch (p->family) {
  	case AF_INET:
  		break;
  
  	case AF_INET6:
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
140
  #if IS_ENABLED(CONFIG_IPV6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
143
144
145
146
147
148
  		break;
  #else
  		err = -EAFNOSUPPORT;
  		goto out;
  #endif
  
  	default:
  		goto out;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
149
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
151
152
153
  
  	err = -EINVAL;
  	switch (p->id.proto) {
  	case IPPROTO_AH:
4447bb33f   Martin Willi   xfrm: Store aalg ...
154
155
  		if ((!attrs[XFRMA_ALG_AUTH]	&&
  		     !attrs[XFRMA_ALG_AUTH_TRUNC]) ||
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
156
  		    attrs[XFRMA_ALG_AEAD]	||
35a7aa08b   Thomas Graf   [XFRM] netlink: R...
157
  		    attrs[XFRMA_ALG_CRYPT]	||
35d2856b4   Martin Willi   xfrm: Add Traffic...
158
159
  		    attrs[XFRMA_ALG_COMP]	||
  		    attrs[XFRMA_TFCPAD])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
162
163
  			goto out;
  		break;
  
  	case IPPROTO_ESP:
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
164
165
166
  		if (attrs[XFRMA_ALG_COMP])
  			goto out;
  		if (!attrs[XFRMA_ALG_AUTH] &&
4447bb33f   Martin Willi   xfrm: Store aalg ...
167
  		    !attrs[XFRMA_ALG_AUTH_TRUNC] &&
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
168
169
170
171
  		    !attrs[XFRMA_ALG_CRYPT] &&
  		    !attrs[XFRMA_ALG_AEAD])
  			goto out;
  		if ((attrs[XFRMA_ALG_AUTH] ||
4447bb33f   Martin Willi   xfrm: Store aalg ...
172
  		     attrs[XFRMA_ALG_AUTH_TRUNC] ||
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
173
174
  		     attrs[XFRMA_ALG_CRYPT]) &&
  		    attrs[XFRMA_ALG_AEAD])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
  			goto out;
35d2856b4   Martin Willi   xfrm: Add Traffic...
176
177
178
  		if (attrs[XFRMA_TFCPAD] &&
  		    p->mode != XFRM_MODE_TUNNEL)
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
181
  		break;
  
  	case IPPROTO_COMP:
35a7aa08b   Thomas Graf   [XFRM] netlink: R...
182
  		if (!attrs[XFRMA_ALG_COMP]	||
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
183
  		    attrs[XFRMA_ALG_AEAD]	||
35a7aa08b   Thomas Graf   [XFRM] netlink: R...
184
  		    attrs[XFRMA_ALG_AUTH]	||
4447bb33f   Martin Willi   xfrm: Store aalg ...
185
  		    attrs[XFRMA_ALG_AUTH_TRUNC]	||
35d2856b4   Martin Willi   xfrm: Add Traffic...
186
187
  		    attrs[XFRMA_ALG_CRYPT]	||
  		    attrs[XFRMA_TFCPAD])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
  			goto out;
  		break;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
190
  #if IS_ENABLED(CONFIG_IPV6)
e23c7194a   Masahide NAKAMURA   [XFRM] STATE: Add...
191
192
  	case IPPROTO_DSTOPTS:
  	case IPPROTO_ROUTING:
35a7aa08b   Thomas Graf   [XFRM] netlink: R...
193
194
  		if (attrs[XFRMA_ALG_COMP]	||
  		    attrs[XFRMA_ALG_AUTH]	||
4447bb33f   Martin Willi   xfrm: Store aalg ...
195
  		    attrs[XFRMA_ALG_AUTH_TRUNC]	||
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
196
  		    attrs[XFRMA_ALG_AEAD]	||
35a7aa08b   Thomas Graf   [XFRM] netlink: R...
197
198
199
  		    attrs[XFRMA_ALG_CRYPT]	||
  		    attrs[XFRMA_ENCAP]		||
  		    attrs[XFRMA_SEC_CTX]	||
35d2856b4   Martin Willi   xfrm: Add Traffic...
200
  		    attrs[XFRMA_TFCPAD]		||
35a7aa08b   Thomas Graf   [XFRM] netlink: R...
201
  		    !attrs[XFRMA_COADDR])
e23c7194a   Masahide NAKAMURA   [XFRM] STATE: Add...
202
203
204
  			goto out;
  		break;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
206
  	default:
  		goto out;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
207
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208

1a6509d99   Herbert Xu   [IPSEC]: Add supp...
209
210
  	if ((err = verify_aead(attrs)))
  		goto out;
4447bb33f   Martin Willi   xfrm: Store aalg ...
211
212
  	if ((err = verify_auth_trunc(attrs)))
  		goto out;
35a7aa08b   Thomas Graf   [XFRM] netlink: R...
213
  	if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
  		goto out;
35a7aa08b   Thomas Graf   [XFRM] netlink: R...
215
  	if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
  		goto out;
35a7aa08b   Thomas Graf   [XFRM] netlink: R...
217
  	if ((err = verify_one_alg(attrs, XFRMA_ALG_COMP)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
  		goto out;
35a7aa08b   Thomas Graf   [XFRM] netlink: R...
219
  	if ((err = verify_sec_ctx_len(attrs)))
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
220
  		goto out;
d8647b79c   Steffen Klassert   xfrm: Add user in...
221
222
  	if ((err = verify_replay(p, attrs)))
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
224
225
  
  	err = -EINVAL;
  	switch (p->mode) {
7e49e6de3   Masahide NAKAMURA   [XFRM]: Add XFRM_...
226
227
  	case XFRM_MODE_TRANSPORT:
  	case XFRM_MODE_TUNNEL:
060f02a3b   Noriaki TAKAMIYA   [XFRM] STATE: Int...
228
  	case XFRM_MODE_ROUTEOPTIMIZATION:
0a69452cb   Diego Beltrami   [XFRM]: BEET mode
229
  	case XFRM_MODE_BEET:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
231
232
233
  		break;
  
  	default:
  		goto out;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
234
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
238
239
240
241
242
  
  	err = 0;
  
  out:
  	return err;
  }
  
  static int attach_one_algo(struct xfrm_algo **algpp, u8 *props,
6f2f19ed9   David S. Miller   xfrm: Pass name a...
243
  			   struct xfrm_algo_desc *(*get_byname)(const char *, int),
5424f32e4   Thomas Graf   [XFRM] netlink: U...
244
  			   struct nlattr *rta)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
247
248
249
250
  	struct xfrm_algo *p, *ualg;
  	struct xfrm_algo_desc *algo;
  
  	if (!rta)
  		return 0;
5424f32e4   Thomas Graf   [XFRM] netlink: U...
251
  	ualg = nla_data(rta);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
254
255
256
  
  	algo = get_byname(ualg->alg_name, 1);
  	if (!algo)
  		return -ENOSYS;
  	*props = algo->desc.sadb_alg_id;
0f99be0d1   Eric Dumazet   [XFRM]: xfrm_algo...
257
  	p = kmemdup(ualg, xfrm_alg_len(ualg), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
259
  	if (!p)
  		return -ENOMEM;
04ff12609   Herbert Xu   [IPSEC]: Add comp...
260
  	strcpy(p->alg_name, algo->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
262
263
  	*algpp = p;
  	return 0;
  }
4447bb33f   Martin Willi   xfrm: Store aalg ...
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
  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;
fa6dd8a2c   Nicolas Dichtel   xfrm: check trunc...
308
309
  	if ((ualg->alg_trunc_len / 8) > MAX_AH_AUTH_LEN ||
  	    ualg->alg_trunc_len > algo->uinfo.auth.icv_fullbits)
4447bb33f   Martin Willi   xfrm: Store aalg ...
310
311
312
313
314
315
316
317
318
319
320
321
322
323
  		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;
  }
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
  static int attach_aead(struct xfrm_algo_aead **algpp, u8 *props,
  		       struct nlattr *rta)
  {
  	struct xfrm_algo_aead *p, *ualg;
  	struct xfrm_algo_desc *algo;
  
  	if (!rta)
  		return 0;
  
  	ualg = nla_data(rta);
  
  	algo = xfrm_aead_get_byname(ualg->alg_name, ualg->alg_icv_len, 1);
  	if (!algo)
  		return -ENOSYS;
  	*props = algo->desc.sadb_alg_id;
  
  	p = kmemdup(ualg, aead_len(ualg), GFP_KERNEL);
  	if (!p)
  		return -ENOMEM;
  
  	strcpy(p->alg_name, algo->name);
  	*algpp = p;
  	return 0;
  }
e2b19125e   Steffen Klassert   xfrm: Check for e...
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
  static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_esn,
  					 struct nlattr *rp)
  {
  	struct xfrm_replay_state_esn *up;
  
  	if (!replay_esn || !rp)
  		return 0;
  
  	up = nla_data(rp);
  
  	if (xfrm_replay_state_esn_len(replay_esn) !=
  			xfrm_replay_state_esn_len(up))
  		return -EINVAL;
  
  	return 0;
  }
d8647b79c   Steffen Klassert   xfrm: Add user in...
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
  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;
  
  	if (!rta)
  		return 0;
  
  	up = nla_data(rta);
  
  	p = kmemdup(up, xfrm_replay_state_esn_len(up), GFP_KERNEL);
  	if (!p)
  		return -ENOMEM;
  
  	pp = kmemdup(up, xfrm_replay_state_esn_len(up), GFP_KERNEL);
  	if (!pp) {
  		kfree(p);
  		return -ENOMEM;
  	}
  
  	*replay_esn = p;
  	*preplay_esn = pp;
  
  	return 0;
  }
661697f72   Joy Latten   [IPSEC] XFRM_USER...
390
  static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx)
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
391
  {
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
392
393
394
395
396
397
398
399
  	int len = 0;
  
  	if (xfrm_ctx) {
  		len += sizeof(struct xfrm_user_sec_ctx);
  		len += xfrm_ctx->ctx_len;
  	}
  	return len;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
402
403
404
405
406
407
408
  static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)
  {
  	memcpy(&x->id, &p->id, sizeof(x->id));
  	memcpy(&x->sel, &p->sel, sizeof(x->sel));
  	memcpy(&x->lft, &p->lft, sizeof(x->lft));
  	x->props.mode = p->mode;
  	x->props.replay_window = p->replay_window;
  	x->props.reqid = p->reqid;
  	x->props.family = p->family;
54489c14c   David S. Miller   [XFRM] xfrm_user:...
409
  	memcpy(&x->props.saddr, &p->saddr, sizeof(x->props.saddr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
  	x->props.flags = p->flags;
196b00362   Herbert Xu   [IPSEC]: Ensure t...
411

ccf9b3b83   Steffen Klassert   xfrm: Add a XFRM_...
412
  	if (!x->sel.family && !(p->flags & XFRM_STATE_AF_UNSPEC))
196b00362   Herbert Xu   [IPSEC]: Ensure t...
413
  		x->sel.family = p->family;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
  }
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
415
416
417
418
419
  /*
   * someday when pfkey also has support, we could have the code
   * somehow made shareable and move it to xfrm_state.c - JHS
   *
  */
5424f32e4   Thomas Graf   [XFRM] netlink: U...
420
  static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs)
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
421
  {
5424f32e4   Thomas Graf   [XFRM] netlink: U...
422
  	struct nlattr *rp = attrs[XFRMA_REPLAY_VAL];
d8647b79c   Steffen Klassert   xfrm: Add user in...
423
  	struct nlattr *re = attrs[XFRMA_REPLAY_ESN_VAL];
5424f32e4   Thomas Graf   [XFRM] netlink: U...
424
425
426
  	struct nlattr *lt = attrs[XFRMA_LTIME_VAL];
  	struct nlattr *et = attrs[XFRMA_ETIMER_THRESH];
  	struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH];
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
427

d8647b79c   Steffen Klassert   xfrm: Add user in...
428
429
430
431
432
433
434
435
  	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));
  	}
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
436
437
  	if (rp) {
  		struct xfrm_replay_state *replay;
5424f32e4   Thomas Graf   [XFRM] netlink: U...
438
  		replay = nla_data(rp);
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
439
440
441
442
443
444
  		memcpy(&x->replay, replay, sizeof(*replay));
  		memcpy(&x->preplay, replay, sizeof(*replay));
  	}
  
  	if (lt) {
  		struct xfrm_lifetime_cur *ltime;
5424f32e4   Thomas Graf   [XFRM] netlink: U...
445
  		ltime = nla_data(lt);
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
446
447
448
449
450
  		x->curlft.bytes = ltime->bytes;
  		x->curlft.packets = ltime->packets;
  		x->curlft.add_time = ltime->add_time;
  		x->curlft.use_time = ltime->use_time;
  	}
cf5cb79f6   Thomas Graf   [XFRM] netlink: E...
451
  	if (et)
5424f32e4   Thomas Graf   [XFRM] netlink: U...
452
  		x->replay_maxage = nla_get_u32(et);
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
453

cf5cb79f6   Thomas Graf   [XFRM] netlink: E...
454
  	if (rt)
5424f32e4   Thomas Graf   [XFRM] netlink: U...
455
  		x->replay_maxdiff = nla_get_u32(rt);
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
456
  }
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
457
458
  static struct xfrm_state *xfrm_state_construct(struct net *net,
  					       struct xfrm_usersa_info *p,
5424f32e4   Thomas Graf   [XFRM] netlink: U...
459
  					       struct nlattr **attrs,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
461
  					       int *errp)
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
462
  	struct xfrm_state *x = xfrm_state_alloc(net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
464
465
466
467
468
  	int err = -ENOMEM;
  
  	if (!x)
  		goto error_no_put;
  
  	copy_from_user_state(x, p);
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
469
470
471
  	if ((err = attach_aead(&x->aead, &x->props.ealgo,
  			       attrs[XFRMA_ALG_AEAD])))
  		goto error;
4447bb33f   Martin Willi   xfrm: Store aalg ...
472
473
  	if ((err = attach_auth_trunc(&x->aalg, &x->props.aalgo,
  				     attrs[XFRMA_ALG_AUTH_TRUNC])))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
  		goto error;
4447bb33f   Martin Willi   xfrm: Store aalg ...
475
476
477
478
479
  	if (!x->props.aalgo) {
  		if ((err = attach_auth(&x->aalg, &x->props.aalgo,
  				       attrs[XFRMA_ALG_AUTH])))
  			goto error;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
481
  	if ((err = attach_one_algo(&x->ealg, &x->props.ealgo,
  				   xfrm_ealg_get_byname,
35a7aa08b   Thomas Graf   [XFRM] netlink: R...
482
  				   attrs[XFRMA_ALG_CRYPT])))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
485
  		goto error;
  	if ((err = attach_one_algo(&x->calg, &x->props.calgo,
  				   xfrm_calg_get_byname,
35a7aa08b   Thomas Graf   [XFRM] netlink: R...
486
  				   attrs[XFRMA_ALG_COMP])))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
  		goto error;
fd21150a0   Thomas Graf   [XFRM] netlink: I...
488
489
490
491
492
493
494
  
  	if (attrs[XFRMA_ENCAP]) {
  		x->encap = kmemdup(nla_data(attrs[XFRMA_ENCAP]),
  				   sizeof(*x->encap), GFP_KERNEL);
  		if (x->encap == NULL)
  			goto error;
  	}
35d2856b4   Martin Willi   xfrm: Add Traffic...
495
496
  	if (attrs[XFRMA_TFCPAD])
  		x->tfcpad = nla_get_u32(attrs[XFRMA_TFCPAD]);
fd21150a0   Thomas Graf   [XFRM] netlink: I...
497
498
499
500
501
502
  	if (attrs[XFRMA_COADDR]) {
  		x->coaddr = kmemdup(nla_data(attrs[XFRMA_COADDR]),
  				    sizeof(*x->coaddr), GFP_KERNEL);
  		if (x->coaddr == NULL)
  			goto error;
  	}
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
503
  	xfrm_mark_get(attrs, &x->mark);
a454f0cce   Wei Yongjun   xfrm: Fix initial...
504
  	err = __xfrm_init_state(x, false);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
506
  	if (err)
  		goto error;
fd21150a0   Thomas Graf   [XFRM] netlink: I...
507
508
  	if (attrs[XFRMA_SEC_CTX] &&
  	    security_xfrm_state_alloc(x, nla_data(attrs[XFRMA_SEC_CTX])))
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
509
  		goto error;
d8647b79c   Steffen Klassert   xfrm: Add user in...
510
511
512
  	if ((err = xfrm_alloc_replay_state_esn(&x->replay_esn, &x->preplay_esn,
  					       attrs[XFRMA_REPLAY_ESN_VAL])))
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
  	x->km.seq = p->seq;
b27aeadb5   Alexey Dobriyan   netns xfrm: per-n...
514
  	x->replay_maxdiff = net->xfrm.sysctl_aevent_rseqth;
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
515
  	/* sysctl_xfrm_aevent_etime is in 100ms units */
b27aeadb5   Alexey Dobriyan   netns xfrm: per-n...
516
  	x->replay_maxage = (net->xfrm.sysctl_aevent_etime*HZ)/XFRM_AE_ETH_M;
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
517

9fdc4883d   Steffen Klassert   xfrm: Move IPsec ...
518
519
  	if ((err = xfrm_init_replay(x)))
  		goto error;
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
520

9fdc4883d   Steffen Klassert   xfrm: Move IPsec ...
521
  	/* override default values from above */
5424f32e4   Thomas Graf   [XFRM] netlink: U...
522
  	xfrm_update_ae_params(x, attrs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
525
526
527
528
529
530
531
532
  
  	return x;
  
  error:
  	x->km.state = XFRM_STATE_DEAD;
  	xfrm_state_put(x);
  error_no_put:
  	*errp = err;
  	return NULL;
  }
22e700502   Christoph Hellwig   [XFRM_USER]: avoi...
533
  static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
5424f32e4   Thomas Graf   [XFRM] netlink: U...
534
  		struct nlattr **attrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
536
  	struct net *net = sock_net(skb->sk);
7b67c8575   Thomas Graf   [XFRM] netlink: U...
537
  	struct xfrm_usersa_info *p = nlmsg_data(nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538
539
  	struct xfrm_state *x;
  	int err;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
540
  	struct km_event c;
c53fa1ed9   Patrick McHardy   netlink: kill log...
541
542
543
  	uid_t loginuid = audit_get_loginuid(current);
  	u32 sessionid = audit_get_sessionid(current);
  	u32 sid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544

35a7aa08b   Thomas Graf   [XFRM] netlink: R...
545
  	err = verify_newsa_info(p, attrs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
  	if (err)
  		return err;
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
548
  	x = xfrm_state_construct(net, p, attrs, &err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
550
  	if (!x)
  		return err;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
551
  	xfrm_state_hold(x);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552
553
554
555
  	if (nlh->nlmsg_type == XFRM_MSG_NEWSA)
  		err = xfrm_state_add(x);
  	else
  		err = xfrm_state_update(x);
c53fa1ed9   Patrick McHardy   netlink: kill log...
556
  	security_task_getsecid(current, &sid);
2532386f4   Eric Paris   Audit: collect se...
557
  	xfrm_audit_state_add(x, err ? 0 : 1, loginuid, sessionid, sid);
161a09e73   Joy Latten   audit: Add auditi...
558

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
  	if (err < 0) {
  		x->km.state = XFRM_STATE_DEAD;
21380b81e   Herbert Xu   [XFRM]: Eliminate...
561
  		__xfrm_state_put(x);
7d6dfe1f5   Patrick McHardy   [IPSEC] Fix xfrm_...
562
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
  	}
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
564
565
  	c.seq = nlh->nlmsg_seq;
  	c.pid = nlh->nlmsg_pid;
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
566
  	c.event = nlh->nlmsg_type;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
567
568
  
  	km_state_notify(x, &c);
7d6dfe1f5   Patrick McHardy   [IPSEC] Fix xfrm_...
569
  out:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
570
  	xfrm_state_put(x);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
572
  	return err;
  }
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
573
574
  static struct xfrm_state *xfrm_user_state_lookup(struct net *net,
  						 struct xfrm_usersa_id *p,
5424f32e4   Thomas Graf   [XFRM] netlink: U...
575
  						 struct nlattr **attrs,
eb2971b68   Masahide NAKAMURA   [XFRM] STATE: Sea...
576
577
578
  						 int *errp)
  {
  	struct xfrm_state *x = NULL;
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
579
  	struct xfrm_mark m;
eb2971b68   Masahide NAKAMURA   [XFRM] STATE: Sea...
580
  	int err;
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
581
  	u32 mark = xfrm_mark_get(attrs, &m);
eb2971b68   Masahide NAKAMURA   [XFRM] STATE: Sea...
582
583
584
  
  	if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) {
  		err = -ESRCH;
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
585
  		x = xfrm_state_lookup(net, mark, &p->daddr, p->spi, p->proto, p->family);
eb2971b68   Masahide NAKAMURA   [XFRM] STATE: Sea...
586
587
  	} else {
  		xfrm_address_t *saddr = NULL;
35a7aa08b   Thomas Graf   [XFRM] netlink: R...
588
  		verify_one_addr(attrs, XFRMA_SRCADDR, &saddr);
eb2971b68   Masahide NAKAMURA   [XFRM] STATE: Sea...
589
590
591
592
  		if (!saddr) {
  			err = -EINVAL;
  			goto out;
  		}
9abbffee8   Masahide NAKAMURA   [XFRM] STATE: Fix...
593
  		err = -ESRCH;
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
594
595
  		x = xfrm_state_lookup_byaddr(net, mark,
  					     &p->daddr, saddr,
221df1ed3   Alexey Dobriyan   netns xfrm: state...
596
  					     p->proto, p->family);
eb2971b68   Masahide NAKAMURA   [XFRM] STATE: Sea...
597
598
599
600
601
602
603
  	}
  
   out:
  	if (!x && errp)
  		*errp = err;
  	return x;
  }
22e700502   Christoph Hellwig   [XFRM_USER]: avoi...
604
  static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
5424f32e4   Thomas Graf   [XFRM] netlink: U...
605
  		struct nlattr **attrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
607
  	struct net *net = sock_net(skb->sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
  	struct xfrm_state *x;
eb2971b68   Masahide NAKAMURA   [XFRM] STATE: Sea...
609
  	int err = -ESRCH;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
610
  	struct km_event c;
7b67c8575   Thomas Graf   [XFRM] netlink: U...
611
  	struct xfrm_usersa_id *p = nlmsg_data(nlh);
c53fa1ed9   Patrick McHardy   netlink: kill log...
612
613
614
  	uid_t loginuid = audit_get_loginuid(current);
  	u32 sessionid = audit_get_sessionid(current);
  	u32 sid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615

fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
616
  	x = xfrm_user_state_lookup(net, p, attrs, &err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
  	if (x == NULL)
eb2971b68   Masahide NAKAMURA   [XFRM] STATE: Sea...
618
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
619

6f68dc377   David S. Miller   [NET]: Fix warnin...
620
  	if ((err = security_xfrm_state_delete(x)) != 0)
c8c05a8ee   Catherine Zhang   [LSM-IPsec]: SELi...
621
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
622
  	if (xfrm_state_kern(x)) {
c8c05a8ee   Catherine Zhang   [LSM-IPsec]: SELi...
623
624
  		err = -EPERM;
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
  	}
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
626
  	err = xfrm_state_delete(x);
161a09e73   Joy Latten   audit: Add auditi...
627

c8c05a8ee   Catherine Zhang   [LSM-IPsec]: SELi...
628
629
  	if (err < 0)
  		goto out;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
630
631
632
  
  	c.seq = nlh->nlmsg_seq;
  	c.pid = nlh->nlmsg_pid;
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
633
  	c.event = nlh->nlmsg_type;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
634
  	km_state_notify(x, &c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635

c8c05a8ee   Catherine Zhang   [LSM-IPsec]: SELi...
636
  out:
c53fa1ed9   Patrick McHardy   netlink: kill log...
637
  	security_task_getsecid(current, &sid);
2532386f4   Eric Paris   Audit: collect se...
638
  	xfrm_audit_state_delete(x, err ? 0 : 1, loginuid, sessionid, sid);
c8c05a8ee   Catherine Zhang   [LSM-IPsec]: SELi...
639
  	xfrm_state_put(x);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
640
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
642
643
644
645
646
647
648
649
  }
  
  static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)
  {
  	memcpy(&p->id, &x->id, sizeof(p->id));
  	memcpy(&p->sel, &x->sel, sizeof(p->sel));
  	memcpy(&p->lft, &x->lft, sizeof(p->lft));
  	memcpy(&p->curlft, &x->curlft, sizeof(p->curlft));
  	memcpy(&p->stats, &x->stats, sizeof(p->stats));
54489c14c   David S. Miller   [XFRM] xfrm_user:...
650
  	memcpy(&p->saddr, &x->props.saddr, sizeof(p->saddr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
652
653
654
655
656
657
658
659
660
661
662
663
  	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;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
  };
c0144beae   Thomas Graf   [XFRM] netlink: U...
665
666
  static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb)
  {
c0144beae   Thomas Graf   [XFRM] netlink: U...
667
668
  	struct xfrm_user_sec_ctx *uctx;
  	struct nlattr *attr;
68325d3b1   Herbert Xu   [XFRM] user: Move...
669
  	int ctx_size = sizeof(*uctx) + s->ctx_len;
c0144beae   Thomas Graf   [XFRM] netlink: U...
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
  
  	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;
  }
4447bb33f   Martin Willi   xfrm: Store aalg ...
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
  static int copy_to_user_auth(struct xfrm_algo_auth *auth, struct sk_buff *skb)
  {
  	struct xfrm_algo *algo;
  	struct nlattr *nla;
  
  	nla = nla_reserve(skb, XFRMA_ALG_AUTH,
  			  sizeof(*algo) + (auth->alg_key_len + 7) / 8);
  	if (!nla)
  		return -EMSGSIZE;
  
  	algo = nla_data(nla);
  	strcpy(algo->alg_name, auth->alg_name);
  	memcpy(algo->alg_key, auth->alg_key, (auth->alg_key_len + 7) / 8);
  	algo->alg_key_len = auth->alg_key_len;
  
  	return 0;
  }
68325d3b1   Herbert Xu   [XFRM] user: Move...
702
703
704
705
  /* 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)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
  	copy_to_user_state(x, p);
050f009e1   Herbert Xu   [IPSEC]: Lock sta...
708
709
710
711
712
  	if (x->coaddr)
  		NLA_PUT(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr);
  
  	if (x->lastused)
  		NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused);
050f009e1   Herbert Xu   [IPSEC]: Lock sta...
713

1a6509d99   Herbert Xu   [IPSEC]: Add supp...
714
715
  	if (x->aead)
  		NLA_PUT(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead);
4447bb33f   Martin Willi   xfrm: Store aalg ...
716
717
718
719
720
721
722
  	if (x->aalg) {
  		if (copy_to_user_auth(x->aalg, skb))
  			goto nla_put_failure;
  
  		NLA_PUT(skb, XFRMA_ALG_AUTH_TRUNC,
  			xfrm_alg_auth_len(x->aalg), x->aalg);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723
  	if (x->ealg)
0f99be0d1   Eric Dumazet   [XFRM]: xfrm_algo...
724
  		NLA_PUT(skb, XFRMA_ALG_CRYPT, xfrm_alg_len(x->ealg), x->ealg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
  	if (x->calg)
c0144beae   Thomas Graf   [XFRM] netlink: U...
726
  		NLA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
728
  
  	if (x->encap)
c0144beae   Thomas Graf   [XFRM] netlink: U...
729
  		NLA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730

35d2856b4   Martin Willi   xfrm: Add Traffic...
731
732
  	if (x->tfcpad)
  		NLA_PUT_U32(skb, XFRMA_TFCPAD, x->tfcpad);
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
733
734
  	if (xfrm_mark_put(skb, &x->mark))
  		goto nla_put_failure;
d8647b79c   Steffen Klassert   xfrm: Add user in...
735
736
737
  	if (x->replay_esn)
  		NLA_PUT(skb, XFRMA_REPLAY_ESN_VAL,
  			xfrm_replay_state_esn_len(x->replay_esn), x->replay_esn);
c0144beae   Thomas Graf   [XFRM] netlink: U...
738
739
  	if (x->security && copy_sec_ctx(x->security, skb) < 0)
  		goto nla_put_failure;
060f02a3b   Noriaki TAKAMIYA   [XFRM] STATE: Int...
740

68325d3b1   Herbert Xu   [XFRM] user: Move...
741
742
743
744
745
746
747
748
749
750
751
752
753
754
  	return 0;
  
  nla_put_failure:
  	return -EMSGSIZE;
  }
  
  static int dump_one_state(struct xfrm_state *x, int count, void *ptr)
  {
  	struct xfrm_dump_info *sp = ptr;
  	struct sk_buff *in_skb = sp->in_skb;
  	struct sk_buff *skb = sp->out_skb;
  	struct xfrm_usersa_info *p;
  	struct nlmsghdr *nlh;
  	int err;
68325d3b1   Herbert Xu   [XFRM] user: Move...
755
756
757
758
759
760
761
762
763
764
  	nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq,
  			XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags);
  	if (nlh == NULL)
  		return -EMSGSIZE;
  
  	p = nlmsg_data(nlh);
  
  	err = copy_to_user_state_extra(x, p, skb);
  	if (err)
  		goto nla_put_failure;
9825069d0   Thomas Graf   [XFRM] netlink: U...
765
  	nlmsg_end(skb, nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
766
  	return 0;
c0144beae   Thomas Graf   [XFRM] netlink: U...
767
  nla_put_failure:
9825069d0   Thomas Graf   [XFRM] netlink: U...
768
  	nlmsg_cancel(skb, nlh);
68325d3b1   Herbert Xu   [XFRM] user: Move...
769
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
  }
4c563f766   Timo Teras   [XFRM]: Speed up ...
771
772
773
774
775
776
  static int xfrm_dump_sa_done(struct netlink_callback *cb)
  {
  	struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
  	xfrm_state_walk_done(walk);
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
778
  static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb)
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
779
  	struct net *net = sock_net(skb->sk);
4c563f766   Timo Teras   [XFRM]: Speed up ...
780
  	struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
  	struct xfrm_dump_info info;
4c563f766   Timo Teras   [XFRM]: Speed up ...
782
783
  	BUILD_BUG_ON(sizeof(struct xfrm_state_walk) >
  		     sizeof(cb->args) - sizeof(cb->args[0]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
785
786
787
  	info.in_skb = cb->skb;
  	info.out_skb = skb;
  	info.nlmsg_seq = cb->nlh->nlmsg_seq;
  	info.nlmsg_flags = NLM_F_MULTI;
4c563f766   Timo Teras   [XFRM]: Speed up ...
788
789
790
791
792
  
  	if (!cb->args[0]) {
  		cb->args[0] = 1;
  		xfrm_state_walk_init(walk, 0);
  	}
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
793
  	(void) xfrm_state_walk(net, walk, dump_one_state, &info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
795
796
797
798
799
800
801
802
  
  	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;
7deb22649   Thomas Graf   [XFRM] netlink: U...
803
  	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
805
  	if (!skb)
  		return ERR_PTR(-ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
806
807
808
809
  	info.in_skb = in_skb;
  	info.out_skb = skb;
  	info.nlmsg_seq = seq;
  	info.nlmsg_flags = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
811
812
813
814
815
816
817
  
  	if (dump_one_state(x, 0, &info)) {
  		kfree_skb(skb);
  		return NULL;
  	}
  
  	return skb;
  }
7deb22649   Thomas Graf   [XFRM] netlink: U...
818
819
820
821
822
823
  static inline size_t xfrm_spdinfo_msgsize(void)
  {
  	return NLMSG_ALIGN(4)
  	       + nla_total_size(sizeof(struct xfrmu_spdinfo))
  	       + nla_total_size(sizeof(struct xfrmu_spdhinfo));
  }
e071041be   Alexey Dobriyan   netns xfrm: fix "...
824
825
  static int build_spdinfo(struct sk_buff *skb, struct net *net,
  			 u32 pid, u32 seq, u32 flags)
ecfd6b183   Jamal Hadi Salim   [XFRM]: Export SP...
826
  {
5a6d34162   Jamal Hadi Salim   [XFRM] SPD info T...
827
828
829
  	struct xfrmk_spdinfo si;
  	struct xfrmu_spdinfo spc;
  	struct xfrmu_spdhinfo sph;
ecfd6b183   Jamal Hadi Salim   [XFRM]: Export SP...
830
831
832
833
  	struct nlmsghdr *nlh;
  	u32 *f;
  
  	nlh = nlmsg_put(skb, pid, seq, XFRM_MSG_NEWSPDINFO, sizeof(u32), 0);
25985edce   Lucas De Marchi   Fix common misspe...
834
  	if (nlh == NULL) /* shouldn't really happen ... */
ecfd6b183   Jamal Hadi Salim   [XFRM]: Export SP...
835
836
837
838
  		return -EMSGSIZE;
  
  	f = nlmsg_data(nlh);
  	*f = flags;
e071041be   Alexey Dobriyan   netns xfrm: fix "...
839
  	xfrm_spd_getinfo(net, &si);
5a6d34162   Jamal Hadi Salim   [XFRM] SPD info T...
840
841
842
843
844
845
846
847
848
849
850
  	spc.incnt = si.incnt;
  	spc.outcnt = si.outcnt;
  	spc.fwdcnt = si.fwdcnt;
  	spc.inscnt = si.inscnt;
  	spc.outscnt = si.outscnt;
  	spc.fwdscnt = si.fwdscnt;
  	sph.spdhcnt = si.spdhcnt;
  	sph.spdhmcnt = si.spdhmcnt;
  
  	NLA_PUT(skb, XFRMA_SPD_INFO, sizeof(spc), &spc);
  	NLA_PUT(skb, XFRMA_SPD_HINFO, sizeof(sph), &sph);
ecfd6b183   Jamal Hadi Salim   [XFRM]: Export SP...
851
852
853
854
855
856
857
858
859
  
  	return nlmsg_end(skb, nlh);
  
  nla_put_failure:
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
  }
  
  static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
5424f32e4   Thomas Graf   [XFRM] netlink: U...
860
  		struct nlattr **attrs)
ecfd6b183   Jamal Hadi Salim   [XFRM]: Export SP...
861
  {
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
862
  	struct net *net = sock_net(skb->sk);
ecfd6b183   Jamal Hadi Salim   [XFRM]: Export SP...
863
  	struct sk_buff *r_skb;
7b67c8575   Thomas Graf   [XFRM] netlink: U...
864
  	u32 *flags = nlmsg_data(nlh);
ecfd6b183   Jamal Hadi Salim   [XFRM]: Export SP...
865
866
  	u32 spid = NETLINK_CB(skb).pid;
  	u32 seq = nlh->nlmsg_seq;
ecfd6b183   Jamal Hadi Salim   [XFRM]: Export SP...
867

7deb22649   Thomas Graf   [XFRM] netlink: U...
868
  	r_skb = nlmsg_new(xfrm_spdinfo_msgsize(), GFP_ATOMIC);
ecfd6b183   Jamal Hadi Salim   [XFRM]: Export SP...
869
870
  	if (r_skb == NULL)
  		return -ENOMEM;
e071041be   Alexey Dobriyan   netns xfrm: fix "...
871
  	if (build_spdinfo(r_skb, net, spid, seq, *flags) < 0)
ecfd6b183   Jamal Hadi Salim   [XFRM]: Export SP...
872
  		BUG();
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
873
  	return nlmsg_unicast(net->xfrm.nlsk, r_skb, spid);
ecfd6b183   Jamal Hadi Salim   [XFRM]: Export SP...
874
  }
7deb22649   Thomas Graf   [XFRM] netlink: U...
875
876
877
878
879
880
  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 */
  }
e071041be   Alexey Dobriyan   netns xfrm: fix "...
881
882
  static int build_sadinfo(struct sk_buff *skb, struct net *net,
  			 u32 pid, u32 seq, u32 flags)
28d8909bc   Jamal Hadi Salim   [XFRM]: Export SA...
883
  {
af11e3160   Jamal Hadi Salim   [XFRM] SAD info T...
884
885
  	struct xfrmk_sadinfo si;
  	struct xfrmu_sadhinfo sh;
28d8909bc   Jamal Hadi Salim   [XFRM]: Export SA...
886
887
888
889
  	struct nlmsghdr *nlh;
  	u32 *f;
  
  	nlh = nlmsg_put(skb, pid, seq, XFRM_MSG_NEWSADINFO, sizeof(u32), 0);
25985edce   Lucas De Marchi   Fix common misspe...
890
  	if (nlh == NULL) /* shouldn't really happen ... */
28d8909bc   Jamal Hadi Salim   [XFRM]: Export SA...
891
892
893
894
  		return -EMSGSIZE;
  
  	f = nlmsg_data(nlh);
  	*f = flags;
e071041be   Alexey Dobriyan   netns xfrm: fix "...
895
  	xfrm_sad_getinfo(net, &si);
28d8909bc   Jamal Hadi Salim   [XFRM]: Export SA...
896

af11e3160   Jamal Hadi Salim   [XFRM] SAD info T...
897
898
899
900
901
  	sh.sadhmcnt = si.sadhmcnt;
  	sh.sadhcnt = si.sadhcnt;
  
  	NLA_PUT_U32(skb, XFRMA_SAD_CNT, si.sadcnt);
  	NLA_PUT(skb, XFRMA_SAD_HINFO, sizeof(sh), &sh);
28d8909bc   Jamal Hadi Salim   [XFRM]: Export SA...
902
903
904
905
906
907
908
909
910
  
  	return nlmsg_end(skb, nlh);
  
  nla_put_failure:
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
  }
  
  static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
5424f32e4   Thomas Graf   [XFRM] netlink: U...
911
  		struct nlattr **attrs)
28d8909bc   Jamal Hadi Salim   [XFRM]: Export SA...
912
  {
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
913
  	struct net *net = sock_net(skb->sk);
28d8909bc   Jamal Hadi Salim   [XFRM]: Export SA...
914
  	struct sk_buff *r_skb;
7b67c8575   Thomas Graf   [XFRM] netlink: U...
915
  	u32 *flags = nlmsg_data(nlh);
28d8909bc   Jamal Hadi Salim   [XFRM]: Export SA...
916
917
  	u32 spid = NETLINK_CB(skb).pid;
  	u32 seq = nlh->nlmsg_seq;
28d8909bc   Jamal Hadi Salim   [XFRM]: Export SA...
918

7deb22649   Thomas Graf   [XFRM] netlink: U...
919
  	r_skb = nlmsg_new(xfrm_sadinfo_msgsize(), GFP_ATOMIC);
28d8909bc   Jamal Hadi Salim   [XFRM]: Export SA...
920
921
  	if (r_skb == NULL)
  		return -ENOMEM;
e071041be   Alexey Dobriyan   netns xfrm: fix "...
922
  	if (build_sadinfo(r_skb, net, spid, seq, *flags) < 0)
28d8909bc   Jamal Hadi Salim   [XFRM]: Export SA...
923
  		BUG();
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
924
  	return nlmsg_unicast(net->xfrm.nlsk, r_skb, spid);
28d8909bc   Jamal Hadi Salim   [XFRM]: Export SA...
925
  }
22e700502   Christoph Hellwig   [XFRM_USER]: avoi...
926
  static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
5424f32e4   Thomas Graf   [XFRM] netlink: U...
927
  		struct nlattr **attrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
929
  	struct net *net = sock_net(skb->sk);
7b67c8575   Thomas Graf   [XFRM] netlink: U...
930
  	struct xfrm_usersa_id *p = nlmsg_data(nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
931
932
  	struct xfrm_state *x;
  	struct sk_buff *resp_skb;
eb2971b68   Masahide NAKAMURA   [XFRM] STATE: Sea...
933
  	int err = -ESRCH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
934

fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
935
  	x = xfrm_user_state_lookup(net, p, attrs, &err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
937
938
939
940
941
942
  	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 {
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
943
  		err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, NETLINK_CB(skb).pid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
  	}
  	xfrm_state_put(x);
  out_noput:
  	return err;
  }
  
  static int verify_userspi_info(struct xfrm_userspi_info *p)
  {
  	switch (p->info.id.proto) {
  	case IPPROTO_AH:
  	case IPPROTO_ESP:
  		break;
  
  	case IPPROTO_COMP:
  		/* IPCOMP spi is 16-bits. */
  		if (p->max >= 0x10000)
  			return -EINVAL;
  		break;
  
  	default:
  		return -EINVAL;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
965
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
966
967
968
969
970
971
  
  	if (p->min > p->max)
  		return -EINVAL;
  
  	return 0;
  }
22e700502   Christoph Hellwig   [XFRM_USER]: avoi...
972
  static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
5424f32e4   Thomas Graf   [XFRM] netlink: U...
973
  		struct nlattr **attrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
974
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
975
  	struct net *net = sock_net(skb->sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976
977
978
979
980
981
  	struct xfrm_state *x;
  	struct xfrm_userspi_info *p;
  	struct sk_buff *resp_skb;
  	xfrm_address_t *daddr;
  	int family;
  	int err;
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
982
983
  	u32 mark;
  	struct xfrm_mark m;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
984

7b67c8575   Thomas Graf   [XFRM] netlink: U...
985
  	p = nlmsg_data(nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
986
987
988
989
990
991
992
993
  	err = verify_userspi_info(p);
  	if (err)
  		goto out_noput;
  
  	family = p->info.family;
  	daddr = &p->info.id.daddr;
  
  	x = NULL;
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
994
995
  
  	mark = xfrm_mark_get(attrs, &m);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
996
  	if (p->info.seq) {
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
997
  		x = xfrm_find_acq_byseq(net, mark, p->info.seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
998
999
1000
1001
1002
1003
1004
  		if (x && xfrm_addr_cmp(&x->id.daddr, daddr, family)) {
  			xfrm_state_put(x);
  			x = NULL;
  		}
  	}
  
  	if (!x)
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
1005
  		x = xfrm_find_acq(net, &m, p->info.mode, p->info.reqid,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
1007
1008
1009
1010
1011
  				  p->info.id.proto, daddr,
  				  &p->info.saddr, 1,
  				  family);
  	err = -ENOENT;
  	if (x == NULL)
  		goto out_noput;
658b219e9   Herbert Xu   [IPSEC]: Move com...
1012
1013
1014
  	err = xfrm_alloc_spi(x, p->min, p->max);
  	if (err)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1015

658b219e9   Herbert Xu   [IPSEC]: Move com...
1016
  	resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1017
1018
1019
1020
  	if (IS_ERR(resp_skb)) {
  		err = PTR_ERR(resp_skb);
  		goto out;
  	}
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
1021
  	err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, NETLINK_CB(skb).pid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1022
1023
1024
1025
1026
1027
  
  out:
  	xfrm_state_put(x);
  out_noput:
  	return err;
  }
b798a9ede   Jamal Hadi Salim   [XFRM]: Convert a...
1028
  static int verify_policy_dir(u8 dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1029
1030
1031
1032
1033
1034
1035
1036
1037
  {
  	switch (dir) {
  	case XFRM_POLICY_IN:
  	case XFRM_POLICY_OUT:
  	case XFRM_POLICY_FWD:
  		break;
  
  	default:
  		return -EINVAL;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
1038
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1039
1040
1041
  
  	return 0;
  }
b798a9ede   Jamal Hadi Salim   [XFRM]: Convert a...
1042
  static int verify_policy_type(u8 type)
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
  {
  	switch (type) {
  	case XFRM_POLICY_TYPE_MAIN:
  #ifdef CONFIG_XFRM_SUB_POLICY
  	case XFRM_POLICY_TYPE_SUB:
  #endif
  		break;
  
  	default:
  		return -EINVAL;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
1053
  	}
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1054
1055
1056
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
  static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
  {
  	switch (p->share) {
  	case XFRM_SHARE_ANY:
  	case XFRM_SHARE_SESSION:
  	case XFRM_SHARE_USER:
  	case XFRM_SHARE_UNIQUE:
  		break;
  
  	default:
  		return -EINVAL;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
1068
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1069
1070
1071
1072
1073
1074
1075
1076
  
  	switch (p->action) {
  	case XFRM_POLICY_ALLOW:
  	case XFRM_POLICY_BLOCK:
  		break;
  
  	default:
  		return -EINVAL;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
1077
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1078
1079
1080
1081
1082
1083
  
  	switch (p->sel.family) {
  	case AF_INET:
  		break;
  
  	case AF_INET6:
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
1084
  #if IS_ENABLED(CONFIG_IPV6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1085
1086
1087
1088
1089
1090
1091
  		break;
  #else
  		return  -EAFNOSUPPORT;
  #endif
  
  	default:
  		return -EINVAL;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
1092
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1093
1094
1095
  
  	return verify_policy_dir(p->dir);
  }
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1096
  static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs)
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1097
  {
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1098
  	struct nlattr *rt = attrs[XFRMA_SEC_CTX];
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1099
1100
1101
1102
  	struct xfrm_user_sec_ctx *uctx;
  
  	if (!rt)
  		return 0;
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1103
  	uctx = nla_data(rt);
03e1ad7b5   Paul Moore   LSM: Make the Lab...
1104
  	return security_xfrm_policy_alloc(&pol->security, uctx);
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1105
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
  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;
c5d18e984   Herbert Xu   [IPSEC]: Fix catc...
1125
1126
  		/* If all masks are ~0, then we allow all algorithms. */
  		t->allalgs = !~(t->aalgos & t->ealgos & t->calgos);
8511d01d7   Miika Komu   [IPSEC]: Add netl...
1127
  		t->encap_family = ut->family;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1128
1129
  	}
  }
b4ad86bf5   David S. Miller   [XFRM] xfrm_user:...
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
  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;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
1151
  #if IS_ENABLED(CONFIG_IPV6)
b4ad86bf5   David S. Miller   [XFRM] xfrm_user:...
1152
1153
1154
1155
1156
  		case AF_INET6:
  			break;
  #endif
  		default:
  			return -EINVAL;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
1157
  		}
b4ad86bf5   David S. Miller   [XFRM] xfrm_user:...
1158
1159
1160
1161
  	}
  
  	return 0;
  }
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1162
  static int copy_from_user_tmpl(struct xfrm_policy *pol, struct nlattr **attrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1163
  {
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1164
  	struct nlattr *rt = attrs[XFRMA_TMPL];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1165
1166
1167
1168
  
  	if (!rt) {
  		pol->xfrm_nr = 0;
  	} else {
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1169
1170
  		struct xfrm_user_tmpl *utmpl = nla_data(rt);
  		int nr = nla_len(rt) / sizeof(*utmpl);
b4ad86bf5   David S. Miller   [XFRM] xfrm_user:...
1171
  		int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1172

b4ad86bf5   David S. Miller   [XFRM] xfrm_user:...
1173
1174
1175
  		err = validate_tmpl(nr, utmpl, pol->family);
  		if (err)
  			return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1176

5424f32e4   Thomas Graf   [XFRM] netlink: U...
1177
  		copy_templates(pol, utmpl, nr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1178
1179
1180
  	}
  	return 0;
  }
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1181
  static int copy_from_user_policy_type(u8 *tp, struct nlattr **attrs)
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1182
  {
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1183
  	struct nlattr *rt = attrs[XFRMA_POLICY_TYPE];
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1184
  	struct xfrm_userpolicy_type *upt;
b798a9ede   Jamal Hadi Salim   [XFRM]: Convert a...
1185
  	u8 type = XFRM_POLICY_TYPE_MAIN;
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1186
1187
1188
  	int err;
  
  	if (rt) {
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1189
  		upt = nla_data(rt);
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
  		type = upt->type;
  	}
  
  	err = verify_policy_type(type);
  	if (err)
  		return err;
  
  	*tp = type;
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
  static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p)
  {
  	xp->priority = p->priority;
  	xp->index = p->index;
  	memcpy(&xp->selector, &p->sel, sizeof(xp->selector));
  	memcpy(&xp->lft, &p->lft, sizeof(xp->lft));
  	xp->action = p->action;
  	xp->flags = p->flags;
  	xp->family = p->sel.family;
  	/* XXX xp->share = p->share; */
  }
  
  static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p, int dir)
  {
  	memcpy(&p->sel, &xp->selector, sizeof(p->sel));
  	memcpy(&p->lft, &xp->lft, sizeof(p->lft));
  	memcpy(&p->curlft, &xp->curlft, sizeof(p->curlft));
  	p->priority = xp->priority;
  	p->index = xp->index;
  	p->sel.family = xp->family;
  	p->dir = dir;
  	p->action = xp->action;
  	p->flags = xp->flags;
  	p->share = XFRM_SHARE_ANY; /* XXX xp->share */
  }
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
1225
  static struct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_userpolicy_info *p, struct nlattr **attrs, int *errp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1226
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
1227
  	struct xfrm_policy *xp = xfrm_policy_alloc(net, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1228
1229
1230
1231
1232
1233
1234
1235
  	int err;
  
  	if (!xp) {
  		*errp = -ENOMEM;
  		return NULL;
  	}
  
  	copy_from_user_policy(xp, p);
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1236

35a7aa08b   Thomas Graf   [XFRM] netlink: R...
1237
  	err = copy_from_user_policy_type(&xp->type, attrs);
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1238
1239
  	if (err)
  		goto error;
35a7aa08b   Thomas Graf   [XFRM] netlink: R...
1240
1241
  	if (!(err = copy_from_user_tmpl(xp, attrs)))
  		err = copy_from_user_sec_ctx(xp, attrs);
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1242
1243
  	if (err)
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1244

295fae568   Jamal Hadi Salim   xfrm: Allow user ...
1245
  	xfrm_mark_get(attrs, &xp->mark);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1246
  	return xp;
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1247
1248
   error:
  	*errp = err;
12a169e7d   Herbert Xu   ipsec: Put dumper...
1249
  	xp->walk.dead = 1;
64c31b3f7   WANG Cong   [XFRM] xfrm_polic...
1250
  	xfrm_policy_destroy(xp);
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1251
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1252
  }
22e700502   Christoph Hellwig   [XFRM_USER]: avoi...
1253
  static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1254
  		struct nlattr **attrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1255
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
1256
  	struct net *net = sock_net(skb->sk);
7b67c8575   Thomas Graf   [XFRM] netlink: U...
1257
  	struct xfrm_userpolicy_info *p = nlmsg_data(nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1258
  	struct xfrm_policy *xp;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1259
  	struct km_event c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1260
1261
  	int err;
  	int excl;
c53fa1ed9   Patrick McHardy   netlink: kill log...
1262
1263
1264
  	uid_t loginuid = audit_get_loginuid(current);
  	u32 sessionid = audit_get_sessionid(current);
  	u32 sid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1265
1266
1267
1268
  
  	err = verify_newpolicy_info(p);
  	if (err)
  		return err;
35a7aa08b   Thomas Graf   [XFRM] netlink: R...
1269
  	err = verify_sec_ctx_len(attrs);
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1270
1271
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1272

fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
1273
  	xp = xfrm_policy_construct(net, p, attrs, &err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1274
1275
  	if (!xp)
  		return err;
25985edce   Lucas De Marchi   Fix common misspe...
1276
  	/* shouldn't excl be based on nlh flags??
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1277
1278
1279
  	 * 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 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1280
1281
  	excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY;
  	err = xfrm_policy_insert(p->dir, xp, excl);
c53fa1ed9   Patrick McHardy   netlink: kill log...
1282
  	security_task_getsecid(current, &sid);
2532386f4   Eric Paris   Audit: collect se...
1283
  	xfrm_audit_policy_add(xp, err ? 0 : 1, loginuid, sessionid, sid);
161a09e73   Joy Latten   audit: Add auditi...
1284

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1285
  	if (err) {
03e1ad7b5   Paul Moore   LSM: Make the Lab...
1286
  		security_xfrm_policy_free(xp->security);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1287
1288
1289
  		kfree(xp);
  		return err;
  	}
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
1290
  	c.event = nlh->nlmsg_type;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1291
1292
1293
  	c.seq = nlh->nlmsg_seq;
  	c.pid = nlh->nlmsg_pid;
  	km_policy_notify(xp, p->dir, &c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
  	xfrm_pol_put(xp);
  
  	return 0;
  }
  
  static int copy_to_user_tmpl(struct xfrm_policy *xp, struct sk_buff *skb)
  {
  	struct xfrm_user_tmpl vec[XFRM_MAX_DEPTH];
  	int i;
  
  	if (xp->xfrm_nr == 0)
  		return 0;
  
  	for (i = 0; i < xp->xfrm_nr; i++) {
  		struct xfrm_user_tmpl *up = &vec[i];
  		struct xfrm_tmpl *kp = &xp->xfrm_vec[i];
  
  		memcpy(&up->id, &kp->id, sizeof(up->id));
8511d01d7   Miika Komu   [IPSEC]: Add netl...
1312
  		up->family = kp->encap_family;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1313
1314
1315
1316
1317
1318
1319
1320
1321
  		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;
  	}
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1322

c0144beae   Thomas Graf   [XFRM] netlink: U...
1323
1324
  	return nla_put(skb, XFRMA_TMPL,
  		       sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr, vec);
0d681623d   Serge Hallyn   [MLSXFRM]: Add se...
1325
1326
1327
1328
1329
1330
  }
  
  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);
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1331
1332
  	}
  	return 0;
0d681623d   Serge Hallyn   [MLSXFRM]: Add se...
1333
  }
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1334

0d681623d   Serge Hallyn   [MLSXFRM]: Add se...
1335
1336
1337
1338
1339
1340
  static inline int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb)
  {
  	if (xp->security) {
  		return copy_sec_ctx(xp->security, skb);
  	}
  	return 0;
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1341
  }
cfbfd45a8   Thomas Graf   [XFRM] netlink: C...
1342
1343
1344
1345
1346
1347
1348
1349
  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
  }
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1350

f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1351
  #ifdef CONFIG_XFRM_SUB_POLICY
b798a9ede   Jamal Hadi Salim   [XFRM]: Convert a...
1352
  static int copy_to_user_policy_type(u8 type, struct sk_buff *skb)
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1353
  {
c0144beae   Thomas Graf   [XFRM] netlink: U...
1354
1355
1356
  	struct xfrm_userpolicy_type upt = {
  		.type = type,
  	};
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1357

c0144beae   Thomas Graf   [XFRM] netlink: U...
1358
  	return nla_put(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt);
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1359
1360
1361
  }
  
  #else
b798a9ede   Jamal Hadi Salim   [XFRM]: Convert a...
1362
  static inline int copy_to_user_policy_type(u8 type, struct sk_buff *skb)
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1363
1364
1365
1366
  {
  	return 0;
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1367
1368
1369
1370
1371
1372
1373
  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;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1374

79b8b7f4a   Thomas Graf   [XFRM] netlink: U...
1375
1376
1377
1378
  	nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq,
  			XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags);
  	if (nlh == NULL)
  		return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1379

7b67c8575   Thomas Graf   [XFRM] netlink: U...
1380
  	p = nlmsg_data(nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1381
1382
1383
  	copy_to_user_policy(xp, p, dir);
  	if (copy_to_user_tmpl(xp, skb) < 0)
  		goto nlmsg_failure;
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1384
1385
  	if (copy_to_user_sec_ctx(xp, skb))
  		goto nlmsg_failure;
1459bb36b   Jamal Hadi Salim   [XFRM]: Make copy...
1386
  	if (copy_to_user_policy_type(xp->type, skb) < 0)
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1387
  		goto nlmsg_failure;
295fae568   Jamal Hadi Salim   xfrm: Allow user ...
1388
1389
  	if (xfrm_mark_put(skb, &xp->mark))
  		goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1390

9825069d0   Thomas Graf   [XFRM] netlink: U...
1391
  	nlmsg_end(skb, nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1392
  	return 0;
295fae568   Jamal Hadi Salim   xfrm: Allow user ...
1393
  nla_put_failure:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1394
  nlmsg_failure:
9825069d0   Thomas Graf   [XFRM] netlink: U...
1395
1396
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1397
  }
4c563f766   Timo Teras   [XFRM]: Speed up ...
1398
1399
1400
1401
1402
1403
1404
  static int xfrm_dump_policy_done(struct netlink_callback *cb)
  {
  	struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1];
  
  	xfrm_policy_walk_done(walk);
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1405
1406
  static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb)
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
1407
  	struct net *net = sock_net(skb->sk);
4c563f766   Timo Teras   [XFRM]: Speed up ...
1408
  	struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1409
  	struct xfrm_dump_info info;
4c563f766   Timo Teras   [XFRM]: Speed up ...
1410
1411
  	BUILD_BUG_ON(sizeof(struct xfrm_policy_walk) >
  		     sizeof(cb->args) - sizeof(cb->args[0]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1412
1413
1414
1415
  	info.in_skb = cb->skb;
  	info.out_skb = skb;
  	info.nlmsg_seq = cb->nlh->nlmsg_seq;
  	info.nlmsg_flags = NLM_F_MULTI;
4c563f766   Timo Teras   [XFRM]: Speed up ...
1416
1417
1418
1419
1420
  
  	if (!cb->args[0]) {
  		cb->args[0] = 1;
  		xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY);
  	}
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
1421
  	(void) xfrm_policy_walk(net, walk, dump_one_policy, &info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
  
  	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;
7deb22649   Thomas Graf   [XFRM] netlink: U...
1432
  	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1433
1434
  	if (!skb)
  		return ERR_PTR(-ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1435
1436
1437
1438
  	info.in_skb = in_skb;
  	info.out_skb = skb;
  	info.nlmsg_seq = seq;
  	info.nlmsg_flags = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1439
1440
1441
1442
1443
1444
1445
1446
  
  	if (dump_one_policy(xp, dir, 0, &info) < 0) {
  		kfree_skb(skb);
  		return NULL;
  	}
  
  	return skb;
  }
22e700502   Christoph Hellwig   [XFRM_USER]: avoi...
1447
  static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1448
  		struct nlattr **attrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1449
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
1450
  	struct net *net = sock_net(skb->sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1451
1452
  	struct xfrm_policy *xp;
  	struct xfrm_userpolicy_id *p;
b798a9ede   Jamal Hadi Salim   [XFRM]: Convert a...
1453
  	u8 type = XFRM_POLICY_TYPE_MAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1454
  	int err;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1455
  	struct km_event c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1456
  	int delete;
295fae568   Jamal Hadi Salim   xfrm: Allow user ...
1457
1458
  	struct xfrm_mark m;
  	u32 mark = xfrm_mark_get(attrs, &m);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1459

7b67c8575   Thomas Graf   [XFRM] netlink: U...
1460
  	p = nlmsg_data(nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1461
  	delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY;
35a7aa08b   Thomas Graf   [XFRM] netlink: R...
1462
  	err = copy_from_user_policy_type(&type, attrs);
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1463
1464
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1465
1466
1467
1468
1469
  	err = verify_policy_dir(p->dir);
  	if (err)
  		return err;
  
  	if (p->index)
295fae568   Jamal Hadi Salim   xfrm: Allow user ...
1470
  		xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, delete, &err);
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1471
  	else {
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1472
  		struct nlattr *rt = attrs[XFRMA_SEC_CTX];
03e1ad7b5   Paul Moore   LSM: Make the Lab...
1473
  		struct xfrm_sec_ctx *ctx;
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1474

35a7aa08b   Thomas Graf   [XFRM] netlink: R...
1475
  		err = verify_sec_ctx_len(attrs);
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1476
1477
  		if (err)
  			return err;
2c8dd1163   Denis V. Lunev   [XFRM]: Compilati...
1478
  		ctx = NULL;
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1479
  		if (rt) {
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1480
  			struct xfrm_user_sec_ctx *uctx = nla_data(rt);
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1481

03e1ad7b5   Paul Moore   LSM: Make the Lab...
1482
1483
  			err = security_xfrm_policy_alloc(&ctx, uctx);
  			if (err)
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1484
  				return err;
2c8dd1163   Denis V. Lunev   [XFRM]: Compilati...
1485
  		}
295fae568   Jamal Hadi Salim   xfrm: Allow user ...
1486
  		xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir, &p->sel,
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
1487
  					   ctx, delete, &err);
03e1ad7b5   Paul Moore   LSM: Make the Lab...
1488
  		security_xfrm_policy_free(ctx);
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
1489
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
  	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 {
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
1500
  			err = nlmsg_unicast(net->xfrm.nlsk, resp_skb,
082a1ad57   Thomas Graf   [XFRM] netlink: U...
1501
  					    NETLINK_CB(skb).pid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1502
  		}
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1503
  	} else {
c53fa1ed9   Patrick McHardy   netlink: kill log...
1504
1505
1506
  		uid_t loginuid = audit_get_loginuid(current);
  		u32 sessionid = audit_get_sessionid(current);
  		u32 sid;
2532386f4   Eric Paris   Audit: collect se...
1507

c53fa1ed9   Patrick McHardy   netlink: kill log...
1508
  		security_task_getsecid(current, &sid);
2532386f4   Eric Paris   Audit: collect se...
1509
1510
  		xfrm_audit_policy_delete(xp, err ? 0 : 1, loginuid, sessionid,
  					 sid);
13fcfbb06   David S. Miller   [XFRM]: Fix OOPSe...
1511
1512
  
  		if (err != 0)
c8c05a8ee   Catherine Zhang   [LSM-IPsec]: SELi...
1513
  			goto out;
13fcfbb06   David S. Miller   [XFRM]: Fix OOPSe...
1514

e7443892f   Herbert Xu   [IPSEC] Set byid ...
1515
  		c.data.byid = p->index;
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
1516
  		c.event = nlh->nlmsg_type;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1517
1518
1519
  		c.seq = nlh->nlmsg_seq;
  		c.pid = nlh->nlmsg_pid;
  		km_policy_notify(xp, p->dir, &c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1520
  	}
c8c05a8ee   Catherine Zhang   [LSM-IPsec]: SELi...
1521
  out:
ef41aaa0b   Eric Paris   [IPSEC]: xfrm_pol...
1522
  	xfrm_pol_put(xp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1523
1524
  	return err;
  }
22e700502   Christoph Hellwig   [XFRM_USER]: avoi...
1525
  static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1526
  		struct nlattr **attrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1527
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
1528
  	struct net *net = sock_net(skb->sk);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1529
  	struct km_event c;
7b67c8575   Thomas Graf   [XFRM] netlink: U...
1530
  	struct xfrm_usersa_flush *p = nlmsg_data(nlh);
161a09e73   Joy Latten   audit: Add auditi...
1531
  	struct xfrm_audit audit_info;
4aa2e62c4   Joy Latten   xfrm: Add securit...
1532
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1533

c53fa1ed9   Patrick McHardy   netlink: kill log...
1534
1535
1536
  	audit_info.loginuid = audit_get_loginuid(current);
  	audit_info.sessionid = audit_get_sessionid(current);
  	security_task_getsecid(current, &audit_info.secid);
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
1537
  	err = xfrm_state_flush(net, p->proto, &audit_info);
9e64cc957   Jamal Hadi Salim   xfrm: Flushing em...
1538
1539
1540
  	if (err) {
  		if (err == -ESRCH) /* empty table */
  			return 0;
069c474e8   David S. Miller   xfrm: Revert fals...
1541
  		return err;
9e64cc957   Jamal Hadi Salim   xfrm: Flushing em...
1542
  	}
bf08867f9   Herbert Xu   [IPSEC] Turn km_e...
1543
  	c.data.proto = p->proto;
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
1544
  	c.event = nlh->nlmsg_type;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1545
1546
  	c.seq = nlh->nlmsg_seq;
  	c.pid = nlh->nlmsg_pid;
7067802e2   Alexey Dobriyan   netns xfrm: pass ...
1547
  	c.net = net;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1548
  	km_state_notify(NULL, &c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1549
1550
  	return 0;
  }
d8647b79c   Steffen Klassert   xfrm: Add user in...
1551
  static inline size_t xfrm_aevent_msgsize(struct xfrm_state *x)
7deb22649   Thomas Graf   [XFRM] netlink: U...
1552
  {
d8647b79c   Steffen Klassert   xfrm: Add user in...
1553
1554
1555
  	size_t replay_size = x->replay_esn ?
  			      xfrm_replay_state_esn_len(x->replay_esn) :
  			      sizeof(struct xfrm_replay_state);
7deb22649   Thomas Graf   [XFRM] netlink: U...
1556
  	return NLMSG_ALIGN(sizeof(struct xfrm_aevent_id))
d8647b79c   Steffen Klassert   xfrm: Add user in...
1557
  	       + nla_total_size(replay_size)
7deb22649   Thomas Graf   [XFRM] netlink: U...
1558
  	       + nla_total_size(sizeof(struct xfrm_lifetime_cur))
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
1559
  	       + nla_total_size(sizeof(struct xfrm_mark))
7deb22649   Thomas Graf   [XFRM] netlink: U...
1560
1561
1562
  	       + nla_total_size(4) /* XFRM_AE_RTHR */
  	       + nla_total_size(4); /* XFRM_AE_ETHR */
  }
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1563

214e005bc   David S. Miller   xfrm: Pass km_eve...
1564
  static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, const struct km_event *c)
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1565
1566
1567
  {
  	struct xfrm_aevent_id *id;
  	struct nlmsghdr *nlh;
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1568

79b8b7f4a   Thomas Graf   [XFRM] netlink: U...
1569
1570
1571
  	nlh = nlmsg_put(skb, c->pid, c->seq, XFRM_MSG_NEWAE, sizeof(*id), 0);
  	if (nlh == NULL)
  		return -EMSGSIZE;
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1572

7b67c8575   Thomas Graf   [XFRM] netlink: U...
1573
  	id = nlmsg_data(nlh);
2b5f6dcce   Jamal Hadi Salim   [XFRM]: Fix aeven...
1574
  	memcpy(&id->sa_id.daddr, &x->id.daddr,sizeof(x->id.daddr));
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1575
1576
1577
  	id->sa_id.spi = x->id.spi;
  	id->sa_id.family = x->props.family;
  	id->sa_id.proto = x->id.proto;
2b5f6dcce   Jamal Hadi Salim   [XFRM]: Fix aeven...
1578
1579
  	memcpy(&id->saddr, &x->props.saddr,sizeof(x->props.saddr));
  	id->reqid = x->props.reqid;
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1580
  	id->flags = c->data.aevent;
d8647b79c   Steffen Klassert   xfrm: Add user in...
1581
1582
1583
1584
1585
1586
  	if (x->replay_esn)
  		NLA_PUT(skb, XFRMA_REPLAY_ESN_VAL,
  			xfrm_replay_state_esn_len(x->replay_esn),
  			x->replay_esn);
  	else
  		NLA_PUT(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), &x->replay);
c0144beae   Thomas Graf   [XFRM] netlink: U...
1587
  	NLA_PUT(skb, XFRMA_LTIME_VAL, sizeof(x->curlft), &x->curlft);
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1588

c0144beae   Thomas Graf   [XFRM] netlink: U...
1589
1590
  	if (id->flags & XFRM_AE_RTHR)
  		NLA_PUT_U32(skb, XFRMA_REPLAY_THRESH, x->replay_maxdiff);
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1591

c0144beae   Thomas Graf   [XFRM] netlink: U...
1592
1593
1594
  	if (id->flags & XFRM_AE_ETHR)
  		NLA_PUT_U32(skb, XFRMA_ETIMER_THRESH,
  			    x->replay_maxage * 10 / HZ);
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1595

6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
1596
1597
  	if (xfrm_mark_put(skb, &x->mark))
  		goto nla_put_failure;
9825069d0   Thomas Graf   [XFRM] netlink: U...
1598
  	return nlmsg_end(skb, nlh);
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1599

c0144beae   Thomas Graf   [XFRM] netlink: U...
1600
  nla_put_failure:
9825069d0   Thomas Graf   [XFRM] netlink: U...
1601
1602
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1603
  }
22e700502   Christoph Hellwig   [XFRM_USER]: avoi...
1604
  static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1605
  		struct nlattr **attrs)
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1606
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
1607
  	struct net *net = sock_net(skb->sk);
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1608
1609
1610
1611
  	struct xfrm_state *x;
  	struct sk_buff *r_skb;
  	int err;
  	struct km_event c;
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
1612
1613
  	u32 mark;
  	struct xfrm_mark m;
7b67c8575   Thomas Graf   [XFRM] netlink: U...
1614
  	struct xfrm_aevent_id *p = nlmsg_data(nlh);
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1615
  	struct xfrm_usersa_id *id = &p->sa_id;
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
1616
1617
1618
  	mark = xfrm_mark_get(attrs, &m);
  
  	x = xfrm_state_lookup(net, mark, &id->daddr, id->spi, id->proto, id->family);
d8647b79c   Steffen Klassert   xfrm: Add user in...
1619
  	if (x == NULL)
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1620
  		return -ESRCH;
d8647b79c   Steffen Klassert   xfrm: Add user in...
1621
1622
1623
1624
1625
  
  	r_skb = nlmsg_new(xfrm_aevent_msgsize(x), GFP_ATOMIC);
  	if (r_skb == NULL) {
  		xfrm_state_put(x);
  		return -ENOMEM;
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
  	}
  
  	/*
  	 * XXX: is this lock really needed - none of the other
  	 * gets lock (the concern is things getting updated
  	 * while we are still reading) - jhs
  	*/
  	spin_lock_bh(&x->lock);
  	c.data.aevent = p->flags;
  	c.seq = nlh->nlmsg_seq;
  	c.pid = nlh->nlmsg_pid;
  
  	if (build_aevent(r_skb, x, &c) < 0)
  		BUG();
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
1640
  	err = nlmsg_unicast(net->xfrm.nlsk, r_skb, NETLINK_CB(skb).pid);
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1641
1642
1643
1644
  	spin_unlock_bh(&x->lock);
  	xfrm_state_put(x);
  	return err;
  }
22e700502   Christoph Hellwig   [XFRM_USER]: avoi...
1645
  static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1646
  		struct nlattr **attrs)
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1647
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
1648
  	struct net *net = sock_net(skb->sk);
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1649
1650
1651
  	struct xfrm_state *x;
  	struct km_event c;
  	int err = - EINVAL;
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
1652
1653
  	u32 mark = 0;
  	struct xfrm_mark m;
7b67c8575   Thomas Graf   [XFRM] netlink: U...
1654
  	struct xfrm_aevent_id *p = nlmsg_data(nlh);
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1655
  	struct nlattr *rp = attrs[XFRMA_REPLAY_VAL];
d8647b79c   Steffen Klassert   xfrm: Add user in...
1656
  	struct nlattr *re = attrs[XFRMA_REPLAY_ESN_VAL];
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1657
  	struct nlattr *lt = attrs[XFRMA_LTIME_VAL];
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1658

d8647b79c   Steffen Klassert   xfrm: Add user in...
1659
  	if (!lt && !rp && !re)
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1660
1661
1662
1663
1664
  		return err;
  
  	/* pedantic mode - thou shalt sayeth replaceth */
  	if (!(nlh->nlmsg_flags&NLM_F_REPLACE))
  		return err;
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
1665
1666
1667
  	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);
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1668
1669
1670
1671
1672
  	if (x == NULL)
  		return -ESRCH;
  
  	if (x->km.state != XFRM_STATE_VALID)
  		goto out;
e2b19125e   Steffen Klassert   xfrm: Check for e...
1673
1674
1675
  	err = xfrm_replay_verify_len(x->replay_esn, rp);
  	if (err)
  		goto out;
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1676
  	spin_lock_bh(&x->lock);
35a7aa08b   Thomas Graf   [XFRM] netlink: R...
1677
  	xfrm_update_ae_params(x, attrs);
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1678
  	spin_unlock_bh(&x->lock);
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
  
  	c.event = nlh->nlmsg_type;
  	c.seq = nlh->nlmsg_seq;
  	c.pid = nlh->nlmsg_pid;
  	c.data.aevent = XFRM_AE_CU;
  	km_state_notify(x, &c);
  	err = 0;
  out:
  	xfrm_state_put(x);
  	return err;
  }
22e700502   Christoph Hellwig   [XFRM_USER]: avoi...
1690
  static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1691
  		struct nlattr **attrs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1692
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
1693
  	struct net *net = sock_net(skb->sk);
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1694
  	struct km_event c;
b798a9ede   Jamal Hadi Salim   [XFRM]: Convert a...
1695
  	u8 type = XFRM_POLICY_TYPE_MAIN;
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1696
  	int err;
161a09e73   Joy Latten   audit: Add auditi...
1697
  	struct xfrm_audit audit_info;
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1698

35a7aa08b   Thomas Graf   [XFRM] netlink: R...
1699
  	err = copy_from_user_policy_type(&type, attrs);
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1700
1701
  	if (err)
  		return err;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1702

c53fa1ed9   Patrick McHardy   netlink: kill log...
1703
1704
1705
  	audit_info.loginuid = audit_get_loginuid(current);
  	audit_info.sessionid = audit_get_sessionid(current);
  	security_task_getsecid(current, &audit_info.secid);
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
1706
  	err = xfrm_policy_flush(net, type, &audit_info);
2f1eb65f3   Jamal Hadi Salim   xfrm: Flushing em...
1707
1708
1709
  	if (err) {
  		if (err == -ESRCH) /* empty table */
  			return 0;
069c474e8   David S. Miller   xfrm: Revert fals...
1710
  		return err;
2f1eb65f3   Jamal Hadi Salim   xfrm: Flushing em...
1711
  	}
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1712
  	c.data.type = type;
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
1713
  	c.event = nlh->nlmsg_type;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1714
1715
  	c.seq = nlh->nlmsg_seq;
  	c.pid = nlh->nlmsg_pid;
7067802e2   Alexey Dobriyan   netns xfrm: pass ...
1716
  	c.net = net;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
1717
  	km_policy_notify(NULL, 0, &c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1718
1719
  	return 0;
  }
22e700502   Christoph Hellwig   [XFRM_USER]: avoi...
1720
  static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1721
  		struct nlattr **attrs)
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1722
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
1723
  	struct net *net = sock_net(skb->sk);
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1724
  	struct xfrm_policy *xp;
7b67c8575   Thomas Graf   [XFRM] netlink: U...
1725
  	struct xfrm_user_polexpire *up = nlmsg_data(nlh);
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1726
  	struct xfrm_userpolicy_info *p = &up->pol;
b798a9ede   Jamal Hadi Salim   [XFRM]: Convert a...
1727
  	u8 type = XFRM_POLICY_TYPE_MAIN;
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1728
  	int err = -ENOENT;
295fae568   Jamal Hadi Salim   xfrm: Allow user ...
1729
1730
  	struct xfrm_mark m;
  	u32 mark = xfrm_mark_get(attrs, &m);
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1731

35a7aa08b   Thomas Graf   [XFRM] netlink: R...
1732
  	err = copy_from_user_policy_type(&type, attrs);
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
1733
1734
  	if (err)
  		return err;
c8bf4d04f   Timo Teräs   xfrm_user: verify...
1735
1736
1737
  	err = verify_policy_dir(p->dir);
  	if (err)
  		return err;
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1738
  	if (p->index)
295fae568   Jamal Hadi Salim   xfrm: Allow user ...
1739
  		xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, 0, &err);
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1740
  	else {
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1741
  		struct nlattr *rt = attrs[XFRMA_SEC_CTX];
03e1ad7b5   Paul Moore   LSM: Make the Lab...
1742
  		struct xfrm_sec_ctx *ctx;
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1743

35a7aa08b   Thomas Graf   [XFRM] netlink: R...
1744
  		err = verify_sec_ctx_len(attrs);
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1745
1746
  		if (err)
  			return err;
2c8dd1163   Denis V. Lunev   [XFRM]: Compilati...
1747
  		ctx = NULL;
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1748
  		if (rt) {
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1749
  			struct xfrm_user_sec_ctx *uctx = nla_data(rt);
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1750

03e1ad7b5   Paul Moore   LSM: Make the Lab...
1751
1752
  			err = security_xfrm_policy_alloc(&ctx, uctx);
  			if (err)
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1753
  				return err;
2c8dd1163   Denis V. Lunev   [XFRM]: Compilati...
1754
  		}
295fae568   Jamal Hadi Salim   xfrm: Allow user ...
1755
  		xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir,
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
1756
  					   &p->sel, ctx, 0, &err);
03e1ad7b5   Paul Moore   LSM: Make the Lab...
1757
  		security_xfrm_policy_free(ctx);
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1758
  	}
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1759
  	if (xp == NULL)
ef41aaa0b   Eric Paris   [IPSEC]: xfrm_pol...
1760
  		return -ENOENT;
03e1ad7b5   Paul Moore   LSM: Make the Lab...
1761

ea2dea9da   Timo Teräs   xfrm: remove poli...
1762
  	if (unlikely(xp->walk.dead))
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1763
  		goto out;
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1764

6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1765
1766
  	err = 0;
  	if (up->hard) {
c53fa1ed9   Patrick McHardy   netlink: kill log...
1767
1768
1769
1770
1771
  		uid_t loginuid = audit_get_loginuid(current);
  		u32 sessionid = audit_get_sessionid(current);
  		u32 sid;
  
  		security_task_getsecid(current, &sid);
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1772
  		xfrm_policy_delete(xp, p->dir);
2532386f4   Eric Paris   Audit: collect se...
1773
  		xfrm_audit_policy_delete(xp, 1, loginuid, sessionid, sid);
161a09e73   Joy Latten   audit: Add auditi...
1774

6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1775
1776
  	} else {
  		// reset the timers here?
62db5cfd7   stephen hemminger   xfrm: add severit...
1777
1778
  		WARN(1, "Dont know what to do with soft policy expire
  ");
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
1779
1780
1781
1782
1783
1784
1785
  	}
  	km_policy_expired(xp, p->dir, up->hard, current->pid);
  
  out:
  	xfrm_pol_put(xp);
  	return err;
  }
22e700502   Christoph Hellwig   [XFRM_USER]: avoi...
1786
  static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1787
  		struct nlattr **attrs)
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
1788
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
1789
  	struct net *net = sock_net(skb->sk);
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
1790
1791
  	struct xfrm_state *x;
  	int err;
7b67c8575   Thomas Graf   [XFRM] netlink: U...
1792
  	struct xfrm_user_expire *ue = nlmsg_data(nlh);
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
1793
  	struct xfrm_usersa_info *p = &ue->state;
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
1794
  	struct xfrm_mark m;
928497f02   Nicolas Dichtel   xfrm_user: avoid ...
1795
  	u32 mark = xfrm_mark_get(attrs, &m);
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
1796

6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
1797
  	x = xfrm_state_lookup(net, mark, &p->id.daddr, p->id.spi, p->id.proto, p->family);
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
1798

3a765aa52   David S. Miller   [XFRM] xfrm_user:...
1799
  	err = -ENOENT;
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
1800
1801
  	if (x == NULL)
  		return err;
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
1802
  	spin_lock_bh(&x->lock);
3a765aa52   David S. Miller   [XFRM] xfrm_user:...
1803
  	err = -EINVAL;
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
1804
1805
1806
  	if (x->km.state != XFRM_STATE_VALID)
  		goto out;
  	km_state_expired(x, ue->hard, current->pid);
161a09e73   Joy Latten   audit: Add auditi...
1807
  	if (ue->hard) {
c53fa1ed9   Patrick McHardy   netlink: kill log...
1808
1809
1810
1811
1812
  		uid_t loginuid = audit_get_loginuid(current);
  		u32 sessionid = audit_get_sessionid(current);
  		u32 sid;
  
  		security_task_getsecid(current, &sid);
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
1813
  		__xfrm_state_delete(x);
2532386f4   Eric Paris   Audit: collect se...
1814
  		xfrm_audit_state_delete(x, 1, loginuid, sessionid, sid);
161a09e73   Joy Latten   audit: Add auditi...
1815
  	}
3a765aa52   David S. Miller   [XFRM] xfrm_user:...
1816
  	err = 0;
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
1817
1818
1819
1820
1821
  out:
  	spin_unlock_bh(&x->lock);
  	xfrm_state_put(x);
  	return err;
  }
22e700502   Christoph Hellwig   [XFRM_USER]: avoi...
1822
  static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh,
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1823
  		struct nlattr **attrs)
980ebd257   Jamal Hadi Salim   [IPSEC]: Sync ser...
1824
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
1825
  	struct net *net = sock_net(skb->sk);
980ebd257   Jamal Hadi Salim   [IPSEC]: Sync ser...
1826
1827
1828
  	struct xfrm_policy *xp;
  	struct xfrm_user_tmpl *ut;
  	int i;
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1829
  	struct nlattr *rt = attrs[XFRMA_TMPL];
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
1830
  	struct xfrm_mark mark;
980ebd257   Jamal Hadi Salim   [IPSEC]: Sync ser...
1831

7b67c8575   Thomas Graf   [XFRM] netlink: U...
1832
  	struct xfrm_user_acquire *ua = nlmsg_data(nlh);
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
1833
  	struct xfrm_state *x = xfrm_state_alloc(net);
980ebd257   Jamal Hadi Salim   [IPSEC]: Sync ser...
1834
1835
1836
  	int err = -ENOMEM;
  
  	if (!x)
d8eb93078   Ilpo Järvinen   xfrm: join error ...
1837
  		goto nomem;
980ebd257   Jamal Hadi Salim   [IPSEC]: Sync ser...
1838

6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
1839
  	xfrm_mark_get(attrs, &mark);
980ebd257   Jamal Hadi Salim   [IPSEC]: Sync ser...
1840
  	err = verify_newpolicy_info(&ua->policy);
d8eb93078   Ilpo Järvinen   xfrm: join error ...
1841
1842
  	if (err)
  		goto bad_policy;
980ebd257   Jamal Hadi Salim   [IPSEC]: Sync ser...
1843
1844
  
  	/*   build an XP */
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
1845
  	xp = xfrm_policy_construct(net, &ua->policy, attrs, &err);
d8eb93078   Ilpo Järvinen   xfrm: join error ...
1846
1847
  	if (!xp)
  		goto free_state;
980ebd257   Jamal Hadi Salim   [IPSEC]: Sync ser...
1848
1849
1850
1851
  
  	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));
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
1852
1853
  	xp->mark.m = x->mark.m = mark.m;
  	xp->mark.v = x->mark.v = mark.v;
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1854
  	ut = nla_data(rt);
980ebd257   Jamal Hadi Salim   [IPSEC]: Sync ser...
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
  	/* 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;
d8eb93078   Ilpo Järvinen   xfrm: join error ...
1873
1874
  
  bad_policy:
62db5cfd7   stephen hemminger   xfrm: add severit...
1875
1876
  	WARN(1, "BAD policy passed
  ");
d8eb93078   Ilpo Järvinen   xfrm: join error ...
1877
1878
1879
1880
  free_state:
  	kfree(x);
  nomem:
  	return err;
980ebd257   Jamal Hadi Salim   [IPSEC]: Sync ser...
1881
  }
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
1882
  #ifdef CONFIG_XFRM_MIGRATE
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
1883
  static int copy_from_user_migrate(struct xfrm_migrate *ma,
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
1884
  				  struct xfrm_kmaddress *k,
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1885
  				  struct nlattr **attrs, int *num)
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
1886
  {
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1887
  	struct nlattr *rt = attrs[XFRMA_MIGRATE];
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
1888
1889
  	struct xfrm_user_migrate *um;
  	int i, num_migrate;
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
1890
1891
1892
1893
1894
1895
1896
1897
1898
  	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;
  	}
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1899
1900
  	um = nla_data(rt);
  	num_migrate = nla_len(rt) / sizeof(*um);
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
  
  	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,
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1924
  			   struct nlattr **attrs)
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
1925
  {
7b67c8575   Thomas Graf   [XFRM] netlink: U...
1926
  	struct xfrm_userpolicy_id *pi = nlmsg_data(nlh);
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
1927
  	struct xfrm_migrate m[XFRM_MAX_DEPTH];
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
1928
  	struct xfrm_kmaddress km, *kmp;
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
1929
1930
1931
  	u8 type;
  	int err;
  	int n = 0;
35a7aa08b   Thomas Graf   [XFRM] netlink: R...
1932
  	if (attrs[XFRMA_MIGRATE] == NULL)
cf5cb79f6   Thomas Graf   [XFRM] netlink: E...
1933
  		return -EINVAL;
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
1934

13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
1935
  	kmp = attrs[XFRMA_KMADDRESS] ? &km : NULL;
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1936
  	err = copy_from_user_policy_type(&type, attrs);
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
1937
1938
  	if (err)
  		return err;
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
1939
  	err = copy_from_user_migrate((struct xfrm_migrate *)m, kmp, attrs, &n);
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
1940
1941
1942
1943
1944
  	if (err)
  		return err;
  
  	if (!n)
  		return 0;
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
1945
  	xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp);
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
1946
1947
1948
1949
1950
  
  	return 0;
  }
  #else
  static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
5424f32e4   Thomas Graf   [XFRM] netlink: U...
1951
  			   struct nlattr **attrs)
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
1952
1953
1954
1955
1956
1957
  {
  	return -ENOPROTOOPT;
  }
  #endif
  
  #ifdef CONFIG_XFRM_MIGRATE
183cad127   David S. Miller   xfrm: Const'ify p...
1958
  static int copy_to_user_migrate(const struct xfrm_migrate *m, struct sk_buff *skb)
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
  {
  	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));
c0144beae   Thomas Graf   [XFRM] netlink: U...
1972
  	return nla_put(skb, XFRMA_MIGRATE, sizeof(um), &um);
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
1973
  }
183cad127   David S. Miller   xfrm: Const'ify p...
1974
  static int copy_to_user_kmaddress(const struct xfrm_kmaddress *k, struct sk_buff *skb)
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
1975
1976
1977
1978
1979
1980
1981
  {
  	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));
a1caa3229   Arnaud Ebalard   XFRM: copy_to_use...
1982
  	memcpy(&uk.remote, &k->remote, sizeof(uk.remote));
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
1983
1984
1985
1986
1987
  
  	return nla_put(skb, XFRMA_KMADDRESS, sizeof(uk), &uk);
  }
  
  static inline size_t xfrm_migrate_msgsize(int num_migrate, int with_kma)
7deb22649   Thomas Graf   [XFRM] netlink: U...
1988
1989
  {
  	return NLMSG_ALIGN(sizeof(struct xfrm_userpolicy_id))
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
1990
1991
1992
  	      + (with_kma ? nla_total_size(sizeof(struct xfrm_kmaddress)) : 0)
  	      + nla_total_size(sizeof(struct xfrm_user_migrate) * num_migrate)
  	      + userpolicy_type_attrsize();
7deb22649   Thomas Graf   [XFRM] netlink: U...
1993
  }
183cad127   David S. Miller   xfrm: Const'ify p...
1994
1995
1996
  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)
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
1997
  {
183cad127   David S. Miller   xfrm: Const'ify p...
1998
  	const struct xfrm_migrate *mp;
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
1999
2000
  	struct xfrm_userpolicy_id *pol_id;
  	struct nlmsghdr *nlh;
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
2001
  	int i;
79b8b7f4a   Thomas Graf   [XFRM] netlink: U...
2002
2003
2004
  	nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_MIGRATE, sizeof(*pol_id), 0);
  	if (nlh == NULL)
  		return -EMSGSIZE;
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
2005

7b67c8575   Thomas Graf   [XFRM] netlink: U...
2006
  	pol_id = nlmsg_data(nlh);
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
2007
2008
2009
2010
  	/* 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;
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
2011
2012
  	if (k != NULL && (copy_to_user_kmaddress(k, skb) < 0))
  			goto nlmsg_failure;
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
2013
2014
2015
2016
2017
2018
2019
  	if (copy_to_user_policy_type(type, skb) < 0)
  		goto nlmsg_failure;
  
  	for (i = 0, mp = m ; i < num_migrate; i++, mp++) {
  		if (copy_to_user_migrate(mp, skb) < 0)
  			goto nlmsg_failure;
  	}
9825069d0   Thomas Graf   [XFRM] netlink: U...
2020
  	return nlmsg_end(skb, nlh);
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
2021
  nlmsg_failure:
9825069d0   Thomas Graf   [XFRM] netlink: U...
2022
2023
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
2024
  }
183cad127   David S. Miller   xfrm: Const'ify p...
2025
2026
2027
  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)
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
2028
  {
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
2029
  	struct net *net = &init_net;
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
2030
  	struct sk_buff *skb;
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
2031

13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
2032
  	skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate, !!k), GFP_ATOMIC);
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
2033
2034
2035
2036
  	if (skb == NULL)
  		return -ENOMEM;
  
  	/* build migrate */
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
2037
  	if (build_migrate(skb, m, num_migrate, k, sel, dir, type) < 0)
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
2038
  		BUG();
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
2039
  	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_MIGRATE, GFP_ATOMIC);
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
2040
2041
  }
  #else
183cad127   David S. Miller   xfrm: Const'ify p...
2042
2043
2044
  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)
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
2045
2046
2047
2048
  {
  	return -ENOPROTOOPT;
  }
  #endif
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
2049

a7bd9a45c   Thomas Graf   [XFRM] netlink: U...
2050
  #define XMSGSIZE(type) sizeof(struct type)
492b558b3   Thomas Graf   [XFRM]: Cleanup x...
2051
2052
  
  static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
66f9a2590   David S. Miller   Revert "xfrm: For...
2053
  	[XFRM_MSG_NEWSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info),
492b558b3   Thomas Graf   [XFRM]: Cleanup x...
2054
2055
2056
2057
2058
2059
  	[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),
980ebd257   Jamal Hadi Salim   [IPSEC]: Sync ser...
2060
  	[XFRM_MSG_ACQUIRE     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_acquire),
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
2061
  	[XFRM_MSG_EXPIRE      - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_expire),
492b558b3   Thomas Graf   [XFRM]: Cleanup x...
2062
  	[XFRM_MSG_UPDPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info),
66f9a2590   David S. Miller   Revert "xfrm: For...
2063
  	[XFRM_MSG_UPDSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info),
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
2064
  	[XFRM_MSG_POLEXPIRE   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire),
492b558b3   Thomas Graf   [XFRM]: Cleanup x...
2065
  	[XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush),
a7bd9a45c   Thomas Graf   [XFRM] netlink: U...
2066
  	[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = 0,
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
2067
2068
  	[XFRM_MSG_NEWAE       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
  	[XFRM_MSG_GETAE       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
97a64b457   Masahide NAKAMURA   [XFRM]: Introduce...
2069
  	[XFRM_MSG_REPORT      - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report),
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
2070
  	[XFRM_MSG_MIGRATE     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
a7bd9a45c   Thomas Graf   [XFRM] netlink: U...
2071
2072
  	[XFRM_MSG_GETSADINFO  - XFRM_MSG_BASE] = sizeof(u32),
  	[XFRM_MSG_GETSPDINFO  - XFRM_MSG_BASE] = sizeof(u32),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2073
  };
492b558b3   Thomas Graf   [XFRM]: Cleanup x...
2074
  #undef XMSGSIZE
cf5cb79f6   Thomas Graf   [XFRM] netlink: E...
2075
  static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
c28e93040   jamal   xfrm: validate at...
2076
2077
2078
2079
  	[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)},
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
2080
  	[XFRMA_ALG_AEAD]	= { .len = sizeof(struct xfrm_algo_aead) },
cf5cb79f6   Thomas Graf   [XFRM] netlink: E...
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
  	[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) },
13c1d1893   Arnaud Ebalard   xfrm: MIGRATE enh...
2095
  	[XFRMA_KMADDRESS]	= { .len = sizeof(struct xfrm_user_kmaddress) },
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
2096
  	[XFRMA_MARK]		= { .len = sizeof(struct xfrm_mark) },
35d2856b4   Martin Willi   xfrm: Add Traffic...
2097
  	[XFRMA_TFCPAD]		= { .type = NLA_U32 },
d8647b79c   Steffen Klassert   xfrm: Add user in...
2098
  	[XFRMA_REPLAY_ESN_VAL]	= { .len = sizeof(struct xfrm_replay_state_esn) },
cf5cb79f6   Thomas Graf   [XFRM] netlink: E...
2099
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2100
  static struct xfrm_link {
5424f32e4   Thomas Graf   [XFRM] netlink: U...
2101
  	int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2102
  	int (*dump)(struct sk_buff *, struct netlink_callback *);
4c563f766   Timo Teras   [XFRM]: Speed up ...
2103
  	int (*done)(struct netlink_callback *);
492b558b3   Thomas Graf   [XFRM]: Cleanup x...
2104
2105
2106
2107
  } 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,
4c563f766   Timo Teras   [XFRM]: Speed up ...
2108
2109
  						   .dump = xfrm_dump_sa,
  						   .done = xfrm_dump_sa_done  },
492b558b3   Thomas Graf   [XFRM]: Cleanup x...
2110
2111
2112
  	[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,
4c563f766   Timo Teras   [XFRM]: Speed up ...
2113
2114
  						   .dump = xfrm_dump_policy,
  						   .done = xfrm_dump_policy_done },
492b558b3   Thomas Graf   [XFRM]: Cleanup x...
2115
  	[XFRM_MSG_ALLOCSPI    - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi },
980ebd257   Jamal Hadi Salim   [IPSEC]: Sync ser...
2116
  	[XFRM_MSG_ACQUIRE     - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire   },
53bc6b4d2   Jamal Hadi Salim   [IPSEC]: Sync ser...
2117
  	[XFRM_MSG_EXPIRE      - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire },
492b558b3   Thomas Graf   [XFRM]: Cleanup x...
2118
2119
  	[XFRM_MSG_UPDPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_add_policy    },
  	[XFRM_MSG_UPDSA       - XFRM_MSG_BASE] = { .doit = xfrm_add_sa        },
6c5c8ca7f   Jamal Hadi Salim   [IPSEC]: Sync ser...
2120
  	[XFRM_MSG_POLEXPIRE   - XFRM_MSG_BASE] = { .doit = xfrm_add_pol_expire},
492b558b3   Thomas Graf   [XFRM]: Cleanup x...
2121
2122
  	[XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa      },
  	[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy  },
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
2123
2124
  	[XFRM_MSG_NEWAE       - XFRM_MSG_BASE] = { .doit = xfrm_new_ae  },
  	[XFRM_MSG_GETAE       - XFRM_MSG_BASE] = { .doit = xfrm_get_ae  },
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
2125
  	[XFRM_MSG_MIGRATE     - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate    },
566ec0344   Jamal Hadi Salim   [XFRM]: Missing b...
2126
  	[XFRM_MSG_GETSADINFO  - XFRM_MSG_BASE] = { .doit = xfrm_get_sadinfo   },
ecfd6b183   Jamal Hadi Salim   [XFRM]: Export SP...
2127
  	[XFRM_MSG_GETSPDINFO  - XFRM_MSG_BASE] = { .doit = xfrm_get_spdinfo   },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2128
  };
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
2129
  static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2130
  {
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
2131
  	struct net *net = sock_net(skb->sk);
35a7aa08b   Thomas Graf   [XFRM] netlink: R...
2132
  	struct nlattr *attrs[XFRMA_MAX+1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2133
  	struct xfrm_link *link;
a7bd9a45c   Thomas Graf   [XFRM] netlink: U...
2134
  	int type, err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2135

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2136
  	type = nlh->nlmsg_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2137
  	if (type > XFRM_MSG_MAX)
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
2138
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2139
2140
2141
2142
2143
  
  	type -= XFRM_MSG_BASE;
  	link = &xfrm_dispatch[type];
  
  	/* All operations require privileges, even GET */
fd7784615   Eric Paris   security: remove ...
2144
  	if (!capable(CAP_NET_ADMIN))
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
2145
  		return -EPERM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2146

492b558b3   Thomas Graf   [XFRM]: Cleanup x...
2147
2148
  	if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) ||
  	     type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) &&
b8f3ab429   David S. Miller   Revert "netlink: ...
2149
  	    (nlh->nlmsg_flags & NLM_F_DUMP)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2150
  		if (link->dump == NULL)
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
2151
  			return -EINVAL;
88fc2c843   Thomas Graf   [XFRM]: Use gener...
2152

c7ac8679b   Greg Rose   rtnetlink: Comput...
2153
2154
  		return netlink_dump_start(net->xfrm.nlsk, skb, nlh,
  					  link->dump, link->done, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2155
  	}
35a7aa08b   Thomas Graf   [XFRM] netlink: R...
2156
  	err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX,
cf5cb79f6   Thomas Graf   [XFRM] netlink: E...
2157
  			  xfrma_policy);
a7bd9a45c   Thomas Graf   [XFRM] netlink: U...
2158
2159
  	if (err < 0)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2160
2161
  
  	if (link->doit == NULL)
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
2162
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2163

5424f32e4   Thomas Graf   [XFRM] netlink: U...
2164
  	return link->doit(skb, nlh, attrs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2165
  }
cd40b7d39   Denis V. Lunev   [NET]: make netli...
2166
  static void xfrm_netlink_rcv(struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2167
  {
cd40b7d39   Denis V. Lunev   [NET]: make netli...
2168
2169
2170
  	mutex_lock(&xfrm_cfg_mutex);
  	netlink_rcv_skb(skb, &xfrm_user_rcv_msg);
  	mutex_unlock(&xfrm_cfg_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2171
  }
7deb22649   Thomas Graf   [XFRM] netlink: U...
2172
2173
  static inline size_t xfrm_expire_msgsize(void)
  {
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
2174
2175
  	return NLMSG_ALIGN(sizeof(struct xfrm_user_expire))
  	       + nla_total_size(sizeof(struct xfrm_mark));
7deb22649   Thomas Graf   [XFRM] netlink: U...
2176
  }
214e005bc   David S. Miller   xfrm: Pass km_eve...
2177
  static int build_expire(struct sk_buff *skb, struct xfrm_state *x, const struct km_event *c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2178
2179
2180
  {
  	struct xfrm_user_expire *ue;
  	struct nlmsghdr *nlh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2181

79b8b7f4a   Thomas Graf   [XFRM] netlink: U...
2182
2183
2184
  	nlh = nlmsg_put(skb, c->pid, 0, XFRM_MSG_EXPIRE, sizeof(*ue), 0);
  	if (nlh == NULL)
  		return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2185

7b67c8575   Thomas Graf   [XFRM] netlink: U...
2186
  	ue = nlmsg_data(nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2187
  	copy_to_user_state(x, &ue->state);
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
2188
  	ue->hard = (c->data.hard != 0) ? 1 : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2189

6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
2190
2191
  	if (xfrm_mark_put(skb, &x->mark))
  		goto nla_put_failure;
9825069d0   Thomas Graf   [XFRM] netlink: U...
2192
  	return nlmsg_end(skb, nlh);
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
2193
2194
2195
  
  nla_put_failure:
  	return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2196
  }
214e005bc   David S. Miller   xfrm: Pass km_eve...
2197
  static int xfrm_exp_state_notify(struct xfrm_state *x, const struct km_event *c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2198
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
2199
  	struct net *net = xs_net(x);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2200
  	struct sk_buff *skb;
7deb22649   Thomas Graf   [XFRM] netlink: U...
2201
  	skb = nlmsg_new(xfrm_expire_msgsize(), GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2202
2203
  	if (skb == NULL)
  		return -ENOMEM;
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
2204
2205
2206
2207
  	if (build_expire(skb, x, c) < 0) {
  		kfree_skb(skb);
  		return -EMSGSIZE;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2208

a6483b790   Alexey Dobriyan   netns xfrm: per-n...
2209
  	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2210
  }
214e005bc   David S. Miller   xfrm: Pass km_eve...
2211
  static int xfrm_aevent_state_notify(struct xfrm_state *x, const struct km_event *c)
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
2212
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
2213
  	struct net *net = xs_net(x);
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
2214
  	struct sk_buff *skb;
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
2215

d8647b79c   Steffen Klassert   xfrm: Add user in...
2216
  	skb = nlmsg_new(xfrm_aevent_msgsize(x), GFP_ATOMIC);
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
2217
2218
2219
2220
2221
  	if (skb == NULL)
  		return -ENOMEM;
  
  	if (build_aevent(skb, x, c) < 0)
  		BUG();
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
2222
  	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_AEVENTS, GFP_ATOMIC);
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
2223
  }
214e005bc   David S. Miller   xfrm: Pass km_eve...
2224
  static int xfrm_notify_sa_flush(const struct km_event *c)
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2225
  {
7067802e2   Alexey Dobriyan   netns xfrm: pass ...
2226
  	struct net *net = c->net;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2227
2228
2229
  	struct xfrm_usersa_flush *p;
  	struct nlmsghdr *nlh;
  	struct sk_buff *skb;
7deb22649   Thomas Graf   [XFRM] netlink: U...
2230
  	int len = NLMSG_ALIGN(sizeof(struct xfrm_usersa_flush));
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2231

7deb22649   Thomas Graf   [XFRM] netlink: U...
2232
  	skb = nlmsg_new(len, GFP_ATOMIC);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2233
2234
  	if (skb == NULL)
  		return -ENOMEM;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2235

79b8b7f4a   Thomas Graf   [XFRM] netlink: U...
2236
2237
2238
2239
2240
  	nlh = nlmsg_put(skb, c->pid, c->seq, XFRM_MSG_FLUSHSA, sizeof(*p), 0);
  	if (nlh == NULL) {
  		kfree_skb(skb);
  		return -EMSGSIZE;
  	}
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2241

7b67c8575   Thomas Graf   [XFRM] netlink: U...
2242
  	p = nlmsg_data(nlh);
bf08867f9   Herbert Xu   [IPSEC] Turn km_e...
2243
  	p->proto = c->data.proto;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2244

9825069d0   Thomas Graf   [XFRM] netlink: U...
2245
  	nlmsg_end(skb, nlh);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2246

a6483b790   Alexey Dobriyan   netns xfrm: per-n...
2247
  	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2248
  }
7deb22649   Thomas Graf   [XFRM] netlink: U...
2249
  static inline size_t xfrm_sa_len(struct xfrm_state *x)
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2250
  {
7deb22649   Thomas Graf   [XFRM] netlink: U...
2251
  	size_t l = 0;
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
2252
2253
  	if (x->aead)
  		l += nla_total_size(aead_len(x->aead));
4447bb33f   Martin Willi   xfrm: Store aalg ...
2254
2255
2256
2257
2258
  	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));
  	}
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2259
  	if (x->ealg)
0f99be0d1   Eric Dumazet   [XFRM]: xfrm_algo...
2260
  		l += nla_total_size(xfrm_alg_len(x->ealg));
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2261
  	if (x->calg)
7deb22649   Thomas Graf   [XFRM] netlink: U...
2262
  		l += nla_total_size(sizeof(*x->calg));
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2263
  	if (x->encap)
7deb22649   Thomas Graf   [XFRM] netlink: U...
2264
  		l += nla_total_size(sizeof(*x->encap));
35d2856b4   Martin Willi   xfrm: Add Traffic...
2265
2266
  	if (x->tfcpad)
  		l += nla_total_size(sizeof(x->tfcpad));
d8647b79c   Steffen Klassert   xfrm: Add user in...
2267
2268
  	if (x->replay_esn)
  		l += nla_total_size(xfrm_replay_state_esn_len(x->replay_esn));
68325d3b1   Herbert Xu   [XFRM] user: Move...
2269
2270
2271
2272
2273
  	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));
d26f39840   Herbert Xu   [IPSEC]: Make x->...
2274
2275
  	/* Must count x->lastused as it may become non-zero behind our back. */
  	l += nla_total_size(sizeof(u64));
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2276
2277
2278
  
  	return l;
  }
214e005bc   David S. Miller   xfrm: Pass km_eve...
2279
  static int xfrm_notify_sa(struct xfrm_state *x, const struct km_event *c)
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2280
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
2281
  	struct net *net = xs_net(x);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2282
  	struct xfrm_usersa_info *p;
0603eac0d   Herbert Xu   [IPSEC]: Add XFRM...
2283
  	struct xfrm_usersa_id *id;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2284
2285
  	struct nlmsghdr *nlh;
  	struct sk_buff *skb;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2286
  	int len = xfrm_sa_len(x);
0603eac0d   Herbert Xu   [IPSEC]: Add XFRM...
2287
2288
2289
2290
  	int headlen;
  
  	headlen = sizeof(*p);
  	if (c->event == XFRM_MSG_DELSA) {
7deb22649   Thomas Graf   [XFRM] netlink: U...
2291
  		len += nla_total_size(headlen);
0603eac0d   Herbert Xu   [IPSEC]: Add XFRM...
2292
  		headlen = sizeof(*id);
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
2293
  		len += nla_total_size(sizeof(struct xfrm_mark));
0603eac0d   Herbert Xu   [IPSEC]: Add XFRM...
2294
  	}
7deb22649   Thomas Graf   [XFRM] netlink: U...
2295
  	len += NLMSG_ALIGN(headlen);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2296

7deb22649   Thomas Graf   [XFRM] netlink: U...
2297
  	skb = nlmsg_new(len, GFP_ATOMIC);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2298
2299
  	if (skb == NULL)
  		return -ENOMEM;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2300

79b8b7f4a   Thomas Graf   [XFRM] netlink: U...
2301
2302
  	nlh = nlmsg_put(skb, c->pid, c->seq, c->event, headlen, 0);
  	if (nlh == NULL)
c0144beae   Thomas Graf   [XFRM] netlink: U...
2303
  		goto nla_put_failure;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2304

7b67c8575   Thomas Graf   [XFRM] netlink: U...
2305
  	p = nlmsg_data(nlh);
0603eac0d   Herbert Xu   [IPSEC]: Add XFRM...
2306
  	if (c->event == XFRM_MSG_DELSA) {
c0144beae   Thomas Graf   [XFRM] netlink: U...
2307
  		struct nlattr *attr;
7b67c8575   Thomas Graf   [XFRM] netlink: U...
2308
  		id = nlmsg_data(nlh);
0603eac0d   Herbert Xu   [IPSEC]: Add XFRM...
2309
2310
2311
2312
  		memcpy(&id->daddr, &x->id.daddr, sizeof(id->daddr));
  		id->spi = x->id.spi;
  		id->family = x->props.family;
  		id->proto = x->id.proto;
c0144beae   Thomas Graf   [XFRM] netlink: U...
2313
2314
2315
2316
2317
  		attr = nla_reserve(skb, XFRMA_SA, sizeof(*p));
  		if (attr == NULL)
  			goto nla_put_failure;
  
  		p = nla_data(attr);
0603eac0d   Herbert Xu   [IPSEC]: Add XFRM...
2318
  	}
68325d3b1   Herbert Xu   [XFRM] user: Move...
2319
2320
  	if (copy_to_user_state_extra(x, p, skb))
  		goto nla_put_failure;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2321

9825069d0   Thomas Graf   [XFRM] netlink: U...
2322
  	nlmsg_end(skb, nlh);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2323

a6483b790   Alexey Dobriyan   netns xfrm: per-n...
2324
  	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2325

c0144beae   Thomas Graf   [XFRM] netlink: U...
2326
  nla_put_failure:
68325d3b1   Herbert Xu   [XFRM] user: Move...
2327
2328
  	/* Somebody screwed up with xfrm_sa_len! */
  	WARN_ON(1);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2329
2330
2331
  	kfree_skb(skb);
  	return -1;
  }
214e005bc   David S. Miller   xfrm: Pass km_eve...
2332
  static int xfrm_send_state_notify(struct xfrm_state *x, const struct km_event *c)
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2333
2334
2335
  {
  
  	switch (c->event) {
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
2336
  	case XFRM_MSG_EXPIRE:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2337
  		return xfrm_exp_state_notify(x, c);
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
2338
2339
  	case XFRM_MSG_NEWAE:
  		return xfrm_aevent_state_notify(x, c);
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
2340
2341
2342
  	case XFRM_MSG_DELSA:
  	case XFRM_MSG_UPDSA:
  	case XFRM_MSG_NEWSA:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2343
  		return xfrm_notify_sa(x, c);
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
2344
  	case XFRM_MSG_FLUSHSA:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2345
2346
  		return xfrm_notify_sa_flush(c);
  	default:
62db5cfd7   stephen hemminger   xfrm: add severit...
2347
2348
2349
2350
  		printk(KERN_NOTICE "xfrm_user: Unknown SA event %d
  ",
  		       c->event);
  		break;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2351
2352
2353
2354
2355
  	}
  
  	return 0;
  
  }
7deb22649   Thomas Graf   [XFRM] netlink: U...
2356
2357
2358
2359
2360
  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)
6f26b61e1   Jamal Hadi Salim   xfrm: Allow user ...
2361
  	       + nla_total_size(sizeof(struct xfrm_mark))
7deb22649   Thomas Graf   [XFRM] netlink: U...
2362
2363
2364
  	       + nla_total_size(xfrm_user_sec_ctx_size(x->security))
  	       + userpolicy_type_attrsize();
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2365
2366
2367
2368
2369
2370
  static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,
  			 struct xfrm_tmpl *xt, struct xfrm_policy *xp,
  			 int dir)
  {
  	struct xfrm_user_acquire *ua;
  	struct nlmsghdr *nlh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2371
  	__u32 seq = xfrm_get_acqseq();
79b8b7f4a   Thomas Graf   [XFRM] netlink: U...
2372
2373
2374
  	nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_ACQUIRE, sizeof(*ua), 0);
  	if (nlh == NULL)
  		return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2375

7b67c8575   Thomas Graf   [XFRM] netlink: U...
2376
  	ua = nlmsg_data(nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
  	memcpy(&ua->id, &x->id, sizeof(ua->id));
  	memcpy(&ua->saddr, &x->props.saddr, sizeof(ua->saddr));
  	memcpy(&ua->sel, &x->sel, sizeof(ua->sel));
  	copy_to_user_policy(xp, &ua->policy, dir);
  	ua->aalgos = xt->aalgos;
  	ua->ealgos = xt->ealgos;
  	ua->calgos = xt->calgos;
  	ua->seq = x->km.seq = seq;
  
  	if (copy_to_user_tmpl(xp, skb) < 0)
  		goto nlmsg_failure;
0d681623d   Serge Hallyn   [MLSXFRM]: Add se...
2388
  	if (copy_to_user_state_sec_ctx(x, skb))
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
2389
  		goto nlmsg_failure;
1459bb36b   Jamal Hadi Salim   [XFRM]: Make copy...
2390
  	if (copy_to_user_policy_type(xp->type, skb) < 0)
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
2391
  		goto nlmsg_failure;
295fae568   Jamal Hadi Salim   xfrm: Allow user ...
2392
2393
  	if (xfrm_mark_put(skb, &xp->mark))
  		goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2394

9825069d0   Thomas Graf   [XFRM] netlink: U...
2395
  	return nlmsg_end(skb, nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2396

295fae568   Jamal Hadi Salim   xfrm: Allow user ...
2397
  nla_put_failure:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2398
  nlmsg_failure:
9825069d0   Thomas Graf   [XFRM] netlink: U...
2399
2400
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2401
2402
2403
2404
2405
  }
  
  static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt,
  			     struct xfrm_policy *xp, int dir)
  {
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
2406
  	struct net *net = xs_net(x);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2407
  	struct sk_buff *skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2408

7deb22649   Thomas Graf   [XFRM] netlink: U...
2409
  	skb = nlmsg_new(xfrm_acquire_msgsize(x, xp), GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2410
2411
2412
2413
2414
  	if (skb == NULL)
  		return -ENOMEM;
  
  	if (build_acquire(skb, x, xt, xp, dir) < 0)
  		BUG();
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
2415
  	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_ACQUIRE, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2416
2417
2418
2419
2420
  }
  
  /* User gives us xfrm_user_policy_info followed by an array of 0
   * or more templates.
   */
cb969f072   Venkat Yekkirala   [MLSXFRM]: Defaul...
2421
  static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2422
2423
  					       u8 *data, int len, int *dir)
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
2424
  	struct net *net = sock_net(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2425
2426
2427
2428
  	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;
cb969f072   Venkat Yekkirala   [MLSXFRM]: Defaul...
2429
  	switch (sk->sk_family) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2430
2431
2432
2433
2434
2435
  	case AF_INET:
  		if (opt != IP_XFRM_POLICY) {
  			*dir = -EOPNOTSUPP;
  			return NULL;
  		}
  		break;
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
2436
  #if IS_ENABLED(CONFIG_IPV6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
  	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));
b4ad86bf5   David S. Miller   [XFRM] xfrm_user:...
2456
  	if (validate_tmpl(nr, ut, p->sel.family))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2457
  		return NULL;
a4f1bac62   Herbert Xu   [XFRM]: Fix possi...
2458
2459
  	if (p->dir > XFRM_POLICY_OUT)
  		return NULL;
2f09a4d5d   Herbert Xu   xfrm: Use GFP_ATO...
2460
  	xp = xfrm_policy_alloc(net, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2461
2462
2463
2464
2465
2466
  	if (xp == NULL) {
  		*dir = -ENOBUFS;
  		return NULL;
  	}
  
  	copy_from_user_policy(xp, p);
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
2467
  	xp->type = XFRM_POLICY_TYPE_MAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2468
2469
2470
2471
2472
2473
  	copy_templates(xp, ut, nr);
  
  	*dir = p->dir;
  
  	return xp;
  }
7deb22649   Thomas Graf   [XFRM] netlink: U...
2474
2475
2476
2477
2478
  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))
295fae568   Jamal Hadi Salim   xfrm: Allow user ...
2479
  	       + nla_total_size(sizeof(struct xfrm_mark))
7deb22649   Thomas Graf   [XFRM] netlink: U...
2480
2481
  	       + userpolicy_type_attrsize();
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2482
  static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp,
214e005bc   David S. Miller   xfrm: Pass km_eve...
2483
  			   int dir, const struct km_event *c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2484
2485
2486
  {
  	struct xfrm_user_polexpire *upe;
  	struct nlmsghdr *nlh;
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
2487
  	int hard = c->data.hard;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2488

79b8b7f4a   Thomas Graf   [XFRM] netlink: U...
2489
2490
2491
  	nlh = nlmsg_put(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe), 0);
  	if (nlh == NULL)
  		return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2492

7b67c8575   Thomas Graf   [XFRM] netlink: U...
2493
  	upe = nlmsg_data(nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2494
2495
2496
  	copy_to_user_policy(xp, &upe->pol, dir);
  	if (copy_to_user_tmpl(xp, skb) < 0)
  		goto nlmsg_failure;
df71837d5   Trent Jaeger   [LSM-IPSec]: Secu...
2497
2498
  	if (copy_to_user_sec_ctx(xp, skb))
  		goto nlmsg_failure;
1459bb36b   Jamal Hadi Salim   [XFRM]: Make copy...
2499
  	if (copy_to_user_policy_type(xp->type, skb) < 0)
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
2500
  		goto nlmsg_failure;
295fae568   Jamal Hadi Salim   xfrm: Allow user ...
2501
2502
  	if (xfrm_mark_put(skb, &xp->mark))
  		goto nla_put_failure;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2503
  	upe->hard = !!hard;
9825069d0   Thomas Graf   [XFRM] netlink: U...
2504
  	return nlmsg_end(skb, nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2505

295fae568   Jamal Hadi Salim   xfrm: Allow user ...
2506
  nla_put_failure:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2507
  nlmsg_failure:
9825069d0   Thomas Graf   [XFRM] netlink: U...
2508
2509
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2510
  }
214e005bc   David S. Miller   xfrm: Pass km_eve...
2511
  static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2512
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
2513
  	struct net *net = xp_net(xp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2514
  	struct sk_buff *skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2515

7deb22649   Thomas Graf   [XFRM] netlink: U...
2516
  	skb = nlmsg_new(xfrm_polexpire_msgsize(xp), GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2517
2518
  	if (skb == NULL)
  		return -ENOMEM;
d51d081d6   Jamal Hadi Salim   [IPSEC]: Sync ser...
2519
  	if (build_polexpire(skb, xp, dir, c) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2520
  		BUG();
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
2521
  	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2522
  }
214e005bc   David S. Miller   xfrm: Pass km_eve...
2523
  static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, const struct km_event *c)
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2524
  {
fc34acd36   Alexey Dobriyan   netns xfrm: xfrm_...
2525
  	struct net *net = xp_net(xp);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2526
  	struct xfrm_userpolicy_info *p;
0603eac0d   Herbert Xu   [IPSEC]: Add XFRM...
2527
  	struct xfrm_userpolicy_id *id;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2528
2529
  	struct nlmsghdr *nlh;
  	struct sk_buff *skb;
7deb22649   Thomas Graf   [XFRM] netlink: U...
2530
  	int len = nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr);
0603eac0d   Herbert Xu   [IPSEC]: Add XFRM...
2531
2532
2533
2534
  	int headlen;
  
  	headlen = sizeof(*p);
  	if (c->event == XFRM_MSG_DELPOLICY) {
7deb22649   Thomas Graf   [XFRM] netlink: U...
2535
  		len += nla_total_size(headlen);
0603eac0d   Herbert Xu   [IPSEC]: Add XFRM...
2536
2537
  		headlen = sizeof(*id);
  	}
cfbfd45a8   Thomas Graf   [XFRM] netlink: C...
2538
  	len += userpolicy_type_attrsize();
295fae568   Jamal Hadi Salim   xfrm: Allow user ...
2539
  	len += nla_total_size(sizeof(struct xfrm_mark));
7deb22649   Thomas Graf   [XFRM] netlink: U...
2540
  	len += NLMSG_ALIGN(headlen);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2541

7deb22649   Thomas Graf   [XFRM] netlink: U...
2542
  	skb = nlmsg_new(len, GFP_ATOMIC);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2543
2544
  	if (skb == NULL)
  		return -ENOMEM;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2545

79b8b7f4a   Thomas Graf   [XFRM] netlink: U...
2546
2547
2548
  	nlh = nlmsg_put(skb, c->pid, c->seq, c->event, headlen, 0);
  	if (nlh == NULL)
  		goto nlmsg_failure;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2549

7b67c8575   Thomas Graf   [XFRM] netlink: U...
2550
  	p = nlmsg_data(nlh);
0603eac0d   Herbert Xu   [IPSEC]: Add XFRM...
2551
  	if (c->event == XFRM_MSG_DELPOLICY) {
c0144beae   Thomas Graf   [XFRM] netlink: U...
2552
  		struct nlattr *attr;
7b67c8575   Thomas Graf   [XFRM] netlink: U...
2553
  		id = nlmsg_data(nlh);
0603eac0d   Herbert Xu   [IPSEC]: Add XFRM...
2554
2555
2556
2557
2558
2559
  		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));
c0144beae   Thomas Graf   [XFRM] netlink: U...
2560
2561
2562
2563
2564
  		attr = nla_reserve(skb, XFRMA_POLICY, sizeof(*p));
  		if (attr == NULL)
  			goto nlmsg_failure;
  
  		p = nla_data(attr);
0603eac0d   Herbert Xu   [IPSEC]: Add XFRM...
2565
  	}
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2566

26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2567
2568
2569
  	copy_to_user_policy(xp, p, dir);
  	if (copy_to_user_tmpl(xp, skb) < 0)
  		goto nlmsg_failure;
1459bb36b   Jamal Hadi Salim   [XFRM]: Make copy...
2570
  	if (copy_to_user_policy_type(xp->type, skb) < 0)
f7b6983f0   Masahide NAKAMURA   [XFRM] POLICY: Su...
2571
  		goto nlmsg_failure;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2572

295fae568   Jamal Hadi Salim   xfrm: Allow user ...
2573
2574
  	if (xfrm_mark_put(skb, &xp->mark))
  		goto nla_put_failure;
9825069d0   Thomas Graf   [XFRM] netlink: U...
2575
  	nlmsg_end(skb, nlh);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2576

a6483b790   Alexey Dobriyan   netns xfrm: per-n...
2577
  	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2578

295fae568   Jamal Hadi Salim   xfrm: Allow user ...
2579
  nla_put_failure:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2580
2581
2582
2583
  nlmsg_failure:
  	kfree_skb(skb);
  	return -1;
  }
214e005bc   David S. Miller   xfrm: Pass km_eve...
2584
  static int xfrm_notify_policy_flush(const struct km_event *c)
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2585
  {
7067802e2   Alexey Dobriyan   netns xfrm: pass ...
2586
  	struct net *net = c->net;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2587
2588
  	struct nlmsghdr *nlh;
  	struct sk_buff *skb;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2589

7deb22649   Thomas Graf   [XFRM] netlink: U...
2590
  	skb = nlmsg_new(userpolicy_type_attrsize(), GFP_ATOMIC);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2591
2592
  	if (skb == NULL)
  		return -ENOMEM;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2593

79b8b7f4a   Thomas Graf   [XFRM] netlink: U...
2594
2595
2596
  	nlh = nlmsg_put(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0, 0);
  	if (nlh == NULL)
  		goto nlmsg_failure;
0c51f53c5   Jamal Hadi Salim   [XFRM]: Make flus...
2597
2598
  	if (copy_to_user_policy_type(c->data.type, skb) < 0)
  		goto nlmsg_failure;
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2599

9825069d0   Thomas Graf   [XFRM] netlink: U...
2600
  	nlmsg_end(skb, nlh);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2601

a6483b790   Alexey Dobriyan   netns xfrm: per-n...
2602
  	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2603
2604
2605
2606
2607
  
  nlmsg_failure:
  	kfree_skb(skb);
  	return -1;
  }
214e005bc   David S. Miller   xfrm: Pass km_eve...
2608
  static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c)
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2609
2610
2611
  {
  
  	switch (c->event) {
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
2612
2613
2614
  	case XFRM_MSG_NEWPOLICY:
  	case XFRM_MSG_UPDPOLICY:
  	case XFRM_MSG_DELPOLICY:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2615
  		return xfrm_notify_policy(xp, dir, c);
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
2616
  	case XFRM_MSG_FLUSHPOLICY:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2617
  		return xfrm_notify_policy_flush(c);
f60f6b8f7   Herbert Xu   [IPSEC] Use XFRM_...
2618
  	case XFRM_MSG_POLEXPIRE:
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2619
2620
  		return xfrm_exp_policy_notify(xp, dir, c);
  	default:
62db5cfd7   stephen hemminger   xfrm: add severit...
2621
2622
2623
  		printk(KERN_NOTICE "xfrm_user: Unknown Policy event %d
  ",
  		       c->event);
26b15dad9   Jamal Hadi Salim   [IPSEC] Add compl...
2624
2625
2626
2627
2628
  	}
  
  	return 0;
  
  }
7deb22649   Thomas Graf   [XFRM] netlink: U...
2629
2630
2631
2632
  static inline size_t xfrm_report_msgsize(void)
  {
  	return NLMSG_ALIGN(sizeof(struct xfrm_user_report));
  }
97a64b457   Masahide NAKAMURA   [XFRM]: Introduce...
2633
2634
2635
2636
2637
  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;
97a64b457   Masahide NAKAMURA   [XFRM]: Introduce...
2638

79b8b7f4a   Thomas Graf   [XFRM] netlink: U...
2639
2640
2641
  	nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur), 0);
  	if (nlh == NULL)
  		return -EMSGSIZE;
97a64b457   Masahide NAKAMURA   [XFRM]: Introduce...
2642

7b67c8575   Thomas Graf   [XFRM] netlink: U...
2643
  	ur = nlmsg_data(nlh);
97a64b457   Masahide NAKAMURA   [XFRM]: Introduce...
2644
2645
2646
2647
  	ur->proto = proto;
  	memcpy(&ur->sel, sel, sizeof(ur->sel));
  
  	if (addr)
c0144beae   Thomas Graf   [XFRM] netlink: U...
2648
  		NLA_PUT(skb, XFRMA_COADDR, sizeof(*addr), addr);
97a64b457   Masahide NAKAMURA   [XFRM]: Introduce...
2649

9825069d0   Thomas Graf   [XFRM] netlink: U...
2650
  	return nlmsg_end(skb, nlh);
97a64b457   Masahide NAKAMURA   [XFRM]: Introduce...
2651

c0144beae   Thomas Graf   [XFRM] netlink: U...
2652
  nla_put_failure:
9825069d0   Thomas Graf   [XFRM] netlink: U...
2653
2654
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
97a64b457   Masahide NAKAMURA   [XFRM]: Introduce...
2655
  }
db983c114   Alexey Dobriyan   netns xfrm: KM re...
2656
2657
  static int xfrm_send_report(struct net *net, u8 proto,
  			    struct xfrm_selector *sel, xfrm_address_t *addr)
97a64b457   Masahide NAKAMURA   [XFRM]: Introduce...
2658
2659
  {
  	struct sk_buff *skb;
97a64b457   Masahide NAKAMURA   [XFRM]: Introduce...
2660

7deb22649   Thomas Graf   [XFRM] netlink: U...
2661
  	skb = nlmsg_new(xfrm_report_msgsize(), GFP_ATOMIC);
97a64b457   Masahide NAKAMURA   [XFRM]: Introduce...
2662
2663
2664
2665
2666
  	if (skb == NULL)
  		return -ENOMEM;
  
  	if (build_report(skb, proto, sel, addr) < 0)
  		BUG();
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
2667
  	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_REPORT, GFP_ATOMIC);
97a64b457   Masahide NAKAMURA   [XFRM]: Introduce...
2668
  }
3a2dfbe8a   Martin Willi   xfrm: Notify chan...
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
  static inline size_t xfrm_mapping_msgsize(void)
  {
  	return NLMSG_ALIGN(sizeof(struct xfrm_user_mapping));
  }
  
  static int build_mapping(struct sk_buff *skb, struct xfrm_state *x,
  			 xfrm_address_t *new_saddr, __be16 new_sport)
  {
  	struct xfrm_user_mapping *um;
  	struct nlmsghdr *nlh;
  
  	nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_MAPPING, sizeof(*um), 0);
  	if (nlh == NULL)
  		return -EMSGSIZE;
  
  	um = nlmsg_data(nlh);
  
  	memcpy(&um->id.daddr, &x->id.daddr, sizeof(um->id.daddr));
  	um->id.spi = x->id.spi;
  	um->id.family = x->props.family;
  	um->id.proto = x->id.proto;
  	memcpy(&um->new_saddr, new_saddr, sizeof(um->new_saddr));
  	memcpy(&um->old_saddr, &x->props.saddr, sizeof(um->old_saddr));
  	um->new_sport = new_sport;
  	um->old_sport = x->encap->encap_sport;
  	um->reqid = x->props.reqid;
  
  	return nlmsg_end(skb, nlh);
  }
  
  static int xfrm_send_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr,
  			     __be16 sport)
  {
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
2702
  	struct net *net = xs_net(x);
3a2dfbe8a   Martin Willi   xfrm: Notify chan...
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
  	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();
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
2717
  	return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_MAPPING, GFP_ATOMIC);
3a2dfbe8a   Martin Willi   xfrm: Notify chan...
2718
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2719
2720
2721
2722
2723
2724
  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,
97a64b457   Masahide NAKAMURA   [XFRM]: Introduce...
2725
  	.report		= xfrm_send_report,
5c79de6e7   Shinta Sugimoto   [XFRM]: User inte...
2726
  	.migrate	= xfrm_send_migrate,
3a2dfbe8a   Martin Willi   xfrm: Notify chan...
2727
  	.new_mapping	= xfrm_send_mapping,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2728
  };
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
2729
  static int __net_init xfrm_user_net_init(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2730
  {
be33690d8   Patrick McHardy   [XFRM]: Fix aeven...
2731
  	struct sock *nlsk;
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
2732
  	nlsk = netlink_kernel_create(net, NETLINK_XFRM, XFRMNLGRP_MAX,
af65bdfce   Patrick McHardy   [NETLINK]: Switch...
2733
  				     xfrm_netlink_rcv, NULL, THIS_MODULE);
be33690d8   Patrick McHardy   [XFRM]: Fix aeven...
2734
  	if (nlsk == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2735
  		return -ENOMEM;
d79d792ef   Eric W. Biederman   net: Allow xfrm_u...
2736
  	net->xfrm.nlsk_stash = nlsk; /* Don't set to NULL */
cf778b00e   Eric Dumazet   net: reintroduce ...
2737
  	rcu_assign_pointer(net->xfrm.nlsk, nlsk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2738
2739
  	return 0;
  }
d79d792ef   Eric W. Biederman   net: Allow xfrm_u...
2740
  static void __net_exit xfrm_user_net_exit(struct list_head *net_exit_list)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2741
  {
d79d792ef   Eric W. Biederman   net: Allow xfrm_u...
2742
2743
  	struct net *net;
  	list_for_each_entry(net, net_exit_list, exit_list)
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
2744
  		RCU_INIT_POINTER(net->xfrm.nlsk, NULL);
d79d792ef   Eric W. Biederman   net: Allow xfrm_u...
2745
2746
2747
  	synchronize_net();
  	list_for_each_entry(net, net_exit_list, exit_list)
  		netlink_kernel_release(net->xfrm.nlsk_stash);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2748
  }
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
2749
  static struct pernet_operations xfrm_user_net_ops = {
d79d792ef   Eric W. Biederman   net: Allow xfrm_u...
2750
2751
  	.init	    = xfrm_user_net_init,
  	.exit_batch = xfrm_user_net_exit,
a6483b790   Alexey Dobriyan   netns xfrm: per-n...
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
  };
  
  static int __init xfrm_user_init(void)
  {
  	int rv;
  
  	printk(KERN_INFO "Initializing XFRM netlink socket
  ");
  
  	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);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2775
2776
2777
  module_init(xfrm_user_init);
  module_exit(xfrm_user_exit);
  MODULE_LICENSE("GPL");
4fdb3bb72   Harald Welte   [NETLINK]: Add pr...
2778
  MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM);
f8cd54884   Jamal Hadi Salim   [IPSEC]: Sync ser...
2779