Blame view

security/selinux/xfrm.c 11.1 KB
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
1
2
3
4
5
6
7
8
  /*
   *  NSA Security-Enhanced Linux (SELinux) security module
   *
   *  This file contains the SELinux XFRM hook function implementations.
   *
   *  Authors:  Serge Hallyn <sergeh@us.ibm.com>
   *	      Trent Jaeger <jaegert@us.ibm.com>
   *
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
9
10
11
12
   *  Updated: Venkat Yekkirala <vyekkirala@TrustedCS.com>
   *
   *           Granular IPSec Associations for use in MLS environments.
   *
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
13
   *  Copyright (C) 2005 International Business Machines Corporation
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
14
   *  Copyright (C) 2006 Trusted Computer Solutions, Inc.
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
   *
   *	This program is free software; you can redistribute it and/or modify
   *	it under the terms of the GNU General Public License version 2,
   *	as published by the Free Software Foundation.
   */
  
  /*
   * USAGE:
   * NOTES:
   *   1. Make sure to enable the following options in your kernel config:
   *	CONFIG_SECURITY=y
   *	CONFIG_SECURITY_NETWORK=y
   *	CONFIG_SECURITY_NETWORK_XFRM=y
   *	CONFIG_SECURITY_SELINUX=m/y
   * ISSUES:
   *   1. Caching packets, so they are not dropped during negotiation
   *   2. Emulating a reasonable SO_PEERSEC across machines
   *   3. Testing addition of sk_policy's with security context via setsockopt
   */
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
34
35
36
37
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/security.h>
  #include <linux/types.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
38
  #include <linux/slab.h>
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
39
40
41
42
43
44
45
  #include <linux/ip.h>
  #include <linux/tcp.h>
  #include <linux/skbuff.h>
  #include <linux/xfrm.h>
  #include <net/xfrm.h>
  #include <net/checksum.h>
  #include <net/udp.h>
60063497a   Arun Sharma   atomic: use <linu...
46
  #include <linux/atomic.h>
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
47
48
49
50
  
  #include "avc.h"
  #include "objsec.h"
  #include "xfrm.h"
d621d35e5   Paul Moore   SELinux: Enable d...
51
52
  /* Labeled XFRM instance counter */
  atomic_t selinux_xfrm_refcount = ATOMIC_INIT(0);
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
53
54
  
  /*
4baabeec2   Paul Moore   selinux: cleanup ...
55
   * Returns true if the context is an LSM/SELinux context.
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
56
57
58
59
60
61
62
63
64
   */
  static inline int selinux_authorizable_ctx(struct xfrm_sec_ctx *ctx)
  {
  	return (ctx &&
  		(ctx->ctx_doi == XFRM_SC_DOI_LSM) &&
  		(ctx->ctx_alg == XFRM_SC_ALG_SELINUX));
  }
  
  /*
4baabeec2   Paul Moore   selinux: cleanup ...
65
   * Returns true if the xfrm contains a security blob for SELinux.
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
66
67
68
69
70
71
72
   */
  static inline int selinux_authorizable_xfrm(struct xfrm_state *x)
  {
  	return selinux_authorizable_ctx(x->security);
  }
  
  /*
2e5aa8660   Paul Moore   lsm: split the xf...
73
74
75
76
   * Allocates a xfrm_sec_state and populates it using the supplied security
   * xfrm_user_sec_ctx context.
   */
  static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
52a4c6404   Nikolay Aleksandrov   selinux: add gfp ...
77
78
  				   struct xfrm_user_sec_ctx *uctx,
  				   gfp_t gfp)
2e5aa8660   Paul Moore   lsm: split the xf...
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  {
  	int rc;
  	const struct task_security_struct *tsec = current_security();
  	struct xfrm_sec_ctx *ctx = NULL;
  	u32 str_len;
  
  	if (ctxp == NULL || uctx == NULL ||
  	    uctx->ctx_doi != XFRM_SC_DOI_LSM ||
  	    uctx->ctx_alg != XFRM_SC_ALG_SELINUX)
  		return -EINVAL;
  
  	str_len = uctx->ctx_len;
  	if (str_len >= PAGE_SIZE)
  		return -ENOMEM;
52a4c6404   Nikolay Aleksandrov   selinux: add gfp ...
93
  	ctx = kmalloc(sizeof(*ctx) + str_len + 1, gfp);
2e5aa8660   Paul Moore   lsm: split the xf...
94
95
96
97
98
99
100
101
  	if (!ctx)
  		return -ENOMEM;
  
  	ctx->ctx_doi = XFRM_SC_DOI_LSM;
  	ctx->ctx_alg = XFRM_SC_ALG_SELINUX;
  	ctx->ctx_len = str_len;
  	memcpy(ctx->ctx_str, &uctx[1], str_len);
  	ctx->ctx_str[str_len] = '\0';
52a4c6404   Nikolay Aleksandrov   selinux: add gfp ...
102
  	rc = security_context_to_sid(ctx->ctx_str, str_len, &ctx->ctx_sid, gfp);
2e5aa8660   Paul Moore   lsm: split the xf...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
  	if (rc)
  		goto err;
  
  	rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
  			  SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, NULL);
  	if (rc)
  		goto err;
  
  	*ctxp = ctx;
  	atomic_inc(&selinux_xfrm_refcount);
  	return 0;
  
  err:
  	kfree(ctx);
  	return rc;
  }
  
  /*
ccf17cc4b   Paul Moore   selinux: cleanup ...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
   * Free the xfrm_sec_ctx structure.
   */
  static void selinux_xfrm_free(struct xfrm_sec_ctx *ctx)
  {
  	if (!ctx)
  		return;
  
  	atomic_dec(&selinux_xfrm_refcount);
  	kfree(ctx);
  }
  
  /*
   * Authorize the deletion of a labeled SA or policy rule.
   */
  static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx)
  {
  	const struct task_security_struct *tsec = current_security();
  
  	if (!ctx)
  		return 0;
  
  	return avc_has_perm(tsec->sid, ctx->ctx_sid,
  			    SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT,
  			    NULL);
  }
  
  /*
4baabeec2   Paul Moore   selinux: cleanup ...
148
149
   * LSM hook implementation that authorizes that a flow can use a xfrm policy
   * rule.
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
150
   */
03e1ad7b5   Paul Moore   LSM: Make the Lab...
151
  int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir)
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
152
  {
5b368e61c   Venkat Yekkirala   IPsec: correct se...
153
  	int rc;
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
154

96484348a   Paul Moore   selinux: cleanup ...
155
156
157
  	/* All flows should be treated as polmatch'ing an otherwise applicable
  	 * "non-labeled" policy. This would prevent inadvertent "leaks". */
  	if (!ctx)
5b368e61c   Venkat Yekkirala   IPsec: correct se...
158
  		return 0;
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
159

96484348a   Paul Moore   selinux: cleanup ...
160
161
162
  	/* Context sid is either set to label or ANY_ASSOC */
  	if (!selinux_authorizable_ctx(ctx))
  		return -EINVAL;
5b368e61c   Venkat Yekkirala   IPsec: correct se...
163

96484348a   Paul Moore   selinux: cleanup ...
164
165
166
  	rc = avc_has_perm(fl_secid, ctx->ctx_sid,
  			  SECCLASS_ASSOCIATION, ASSOCIATION__POLMATCH, NULL);
  	return (rc == -EACCES ? -ESRCH : rc);
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
167
168
169
  }
  
  /*
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
170
171
172
   * LSM hook implementation that authorizes that a state matches
   * the given policy, flow combo.
   */
96484348a   Paul Moore   selinux: cleanup ...
173
174
175
  int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
  				      struct xfrm_policy *xp,
  				      const struct flowi *fl)
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
176
177
  {
  	u32 state_sid;
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
178

67f83cbf0   Venkat Yekkirala   SELinux: Fix SA s...
179
  	if (!xp->security)
5b368e61c   Venkat Yekkirala   IPsec: correct se...
180
181
182
183
184
185
  		if (x->security)
  			/* unlabeled policy and labeled SA can't match */
  			return 0;
  		else
  			/* unlabeled policy and unlabeled SA match all flows */
  			return 1;
5b368e61c   Venkat Yekkirala   IPsec: correct se...
186
  	else
67f83cbf0   Venkat Yekkirala   SELinux: Fix SA s...
187
188
  		if (!x->security)
  			/* unlabeled SA and labeled policy can't match */
5b368e61c   Venkat Yekkirala   IPsec: correct se...
189
  			return 0;
67f83cbf0   Venkat Yekkirala   SELinux: Fix SA s...
190
191
192
193
  		else
  			if (!selinux_authorizable_xfrm(x))
  				/* Not a SELinux-labeled SA */
  				return 0;
5b368e61c   Venkat Yekkirala   IPsec: correct se...
194

67f83cbf0   Venkat Yekkirala   SELinux: Fix SA s...
195
  	state_sid = x->security->ctx_sid;
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
196

1d28f42c1   David S. Miller   net: Put flowi_* ...
197
  	if (fl->flowi_secid != state_sid)
67f83cbf0   Venkat Yekkirala   SELinux: Fix SA s...
198
  		return 0;
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
199

96484348a   Paul Moore   selinux: cleanup ...
200
201
202
203
204
205
  	/* We don't need a separate SA Vs. policy polmatch check since the SA
  	 * is now of the same label as the flow and a flow Vs. policy polmatch
  	 * check had already happened in selinux_xfrm_policy_lookup() above. */
  	return (avc_has_perm(fl->flowi_secid, state_sid,
  			    SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO,
  			    NULL) ? 0 : 1);
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
206
  }
817eff718   Paul Moore   selinux: look for...
207
  static u32 selinux_xfrm_skb_sid_egress(struct sk_buff *skb)
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
208
  {
817eff718   Paul Moore   selinux: look for...
209
210
211
212
213
214
215
216
  	struct dst_entry *dst = skb_dst(skb);
  	struct xfrm_state *x;
  
  	if (dst == NULL)
  		return SECSID_NULL;
  	x = dst->xfrm;
  	if (x == NULL || !selinux_authorizable_xfrm(x))
  		return SECSID_NULL;
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
217

817eff718   Paul Moore   selinux: look for...
218
219
220
221
222
223
224
225
  	return x->security->ctx_sid;
  }
  
  static int selinux_xfrm_skb_sid_ingress(struct sk_buff *skb,
  					u32 *sid, int ckall)
  {
  	u32 sid_session = SECSID_NULL;
  	struct sec_path *sp = skb->sp;
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
226

e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
227
  	if (sp) {
e21936958   Paul Moore   selinux: cleanup ...
228
  		int i;
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
229

e21936958   Paul Moore   selinux: cleanup ...
230
  		for (i = sp->len - 1; i >= 0; i--) {
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
231
232
233
  			struct xfrm_state *x = sp->xvec[i];
  			if (selinux_authorizable_xfrm(x)) {
  				struct xfrm_sec_ctx *ctx = x->security;
e21936958   Paul Moore   selinux: cleanup ...
234
235
  				if (sid_session == SECSID_NULL) {
  					sid_session = ctx->ctx_sid;
beb8d13be   Venkat Yekkirala   [MLSXFRM]: Add fl...
236
  					if (!ckall)
e21936958   Paul Moore   selinux: cleanup ...
237
238
239
  						goto out;
  				} else if (sid_session != ctx->ctx_sid) {
  					*sid = SECSID_NULL;
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
240
  					return -EINVAL;
e21936958   Paul Moore   selinux: cleanup ...
241
  				}
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
242
243
244
  			}
  		}
  	}
e21936958   Paul Moore   selinux: cleanup ...
245
246
  out:
  	*sid = sid_session;
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
247
248
249
250
  	return 0;
  }
  
  /*
817eff718   Paul Moore   selinux: look for...
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
   * LSM hook implementation that checks and/or returns the xfrm sid for the
   * incoming packet.
   */
  int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall)
  {
  	if (skb == NULL) {
  		*sid = SECSID_NULL;
  		return 0;
  	}
  	return selinux_xfrm_skb_sid_ingress(skb, sid, ckall);
  }
  
  int selinux_xfrm_skb_sid(struct sk_buff *skb, u32 *sid)
  {
  	int rc;
  
  	rc = selinux_xfrm_skb_sid_ingress(skb, sid, 0);
  	if (rc == 0 && *sid == SECSID_NULL)
  		*sid = selinux_xfrm_skb_sid_egress(skb);
  
  	return rc;
  }
  
  /*
4baabeec2   Paul Moore   selinux: cleanup ...
275
   * LSM hook implementation that allocs and transfers uctx spec to xfrm_policy.
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
276
   */
03e1ad7b5   Paul Moore   LSM: Make the Lab...
277
  int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
52a4c6404   Nikolay Aleksandrov   selinux: add gfp ...
278
279
  			      struct xfrm_user_sec_ctx *uctx,
  			      gfp_t gfp)
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
280
  {
52a4c6404   Nikolay Aleksandrov   selinux: add gfp ...
281
  	return selinux_xfrm_alloc_user(ctxp, uctx, gfp);
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
282
  }
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
283
  /*
4baabeec2   Paul Moore   selinux: cleanup ...
284
285
   * LSM hook implementation that copies security data structure from old to new
   * for policy cloning.
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
286
   */
03e1ad7b5   Paul Moore   LSM: Make the Lab...
287
288
  int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx,
  			      struct xfrm_sec_ctx **new_ctxp)
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
289
  {
03e1ad7b5   Paul Moore   LSM: Make the Lab...
290
  	struct xfrm_sec_ctx *new_ctx;
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
291

ccf17cc4b   Paul Moore   selinux: cleanup ...
292
293
  	if (!old_ctx)
  		return 0;
7d1db4b24   Duan Jiong   selinux: Use kmem...
294
295
  	new_ctx = kmemdup(old_ctx, sizeof(*old_ctx) + old_ctx->ctx_len,
  			  GFP_ATOMIC);
ccf17cc4b   Paul Moore   selinux: cleanup ...
296
297
  	if (!new_ctx)
  		return -ENOMEM;
ccf17cc4b   Paul Moore   selinux: cleanup ...
298
299
  	atomic_inc(&selinux_xfrm_refcount);
  	*new_ctxp = new_ctx;
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
300

d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
301
302
303
304
  	return 0;
  }
  
  /*
03e1ad7b5   Paul Moore   LSM: Make the Lab...
305
   * LSM hook implementation that frees xfrm_sec_ctx security information.
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
306
   */
03e1ad7b5   Paul Moore   LSM: Make the Lab...
307
  void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx)
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
308
  {
ccf17cc4b   Paul Moore   selinux: cleanup ...
309
  	selinux_xfrm_free(ctx);
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
310
311
312
  }
  
  /*
c8c05a8ee   Catherine Zhang   [LSM-IPsec]: SELi...
313
314
   * LSM hook implementation that authorizes deletion of labeled policies.
   */
03e1ad7b5   Paul Moore   LSM: Make the Lab...
315
  int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx)
c8c05a8ee   Catherine Zhang   [LSM-IPsec]: SELi...
316
  {
ccf17cc4b   Paul Moore   selinux: cleanup ...
317
  	return selinux_xfrm_delete(ctx);
c8c05a8ee   Catherine Zhang   [LSM-IPsec]: SELi...
318
319
320
  }
  
  /*
2e5aa8660   Paul Moore   lsm: split the xf...
321
322
   * LSM hook implementation that allocates a xfrm_sec_state, populates it using
   * the supplied security context, and assigns it to the xfrm_state.
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
323
   */
2e5aa8660   Paul Moore   lsm: split the xf...
324
325
  int selinux_xfrm_state_alloc(struct xfrm_state *x,
  			     struct xfrm_user_sec_ctx *uctx)
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
326
  {
52a4c6404   Nikolay Aleksandrov   selinux: add gfp ...
327
  	return selinux_xfrm_alloc_user(&x->security, uctx, GFP_KERNEL);
2e5aa8660   Paul Moore   lsm: split the xf...
328
  }
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
329

2e5aa8660   Paul Moore   lsm: split the xf...
330
331
332
333
334
335
336
337
338
339
340
  /*
   * LSM hook implementation that allocates a xfrm_sec_state and populates based
   * on a secid.
   */
  int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
  				     struct xfrm_sec_ctx *polsec, u32 secid)
  {
  	int rc;
  	struct xfrm_sec_ctx *ctx;
  	char *ctx_str = NULL;
  	int str_len;
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
341

2e5aa8660   Paul Moore   lsm: split the xf...
342
343
344
345
346
347
348
349
350
351
352
  	if (!polsec)
  		return 0;
  
  	if (secid == 0)
  		return -EINVAL;
  
  	rc = security_sid_to_context(secid, &ctx_str, &str_len);
  	if (rc)
  		return rc;
  
  	ctx = kmalloc(sizeof(*ctx) + str_len, GFP_ATOMIC);
0af901643   Geyslan G. Bem   selinux: fix poss...
353
354
355
356
  	if (!ctx) {
  		rc = -ENOMEM;
  		goto out;
  	}
2e5aa8660   Paul Moore   lsm: split the xf...
357
358
359
360
361
362
  
  	ctx->ctx_doi = XFRM_SC_DOI_LSM;
  	ctx->ctx_alg = XFRM_SC_ALG_SELINUX;
  	ctx->ctx_sid = secid;
  	ctx->ctx_len = str_len;
  	memcpy(ctx->ctx_str, ctx_str, str_len);
2e5aa8660   Paul Moore   lsm: split the xf...
363
364
365
  
  	x->security = ctx;
  	atomic_inc(&selinux_xfrm_refcount);
0af901643   Geyslan G. Bem   selinux: fix poss...
366
367
368
  out:
  	kfree(ctx_str);
  	return rc;
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
369
370
371
372
373
374
375
  }
  
  /*
   * LSM hook implementation that frees xfrm_state security information.
   */
  void selinux_xfrm_state_free(struct xfrm_state *x)
  {
ccf17cc4b   Paul Moore   selinux: cleanup ...
376
  	selinux_xfrm_free(x->security);
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
377
  }
4baabeec2   Paul Moore   selinux: cleanup ...
378
379
380
  /*
   * LSM hook implementation that authorizes deletion of labeled SAs.
   */
c8c05a8ee   Catherine Zhang   [LSM-IPsec]: SELi...
381
382
  int selinux_xfrm_state_delete(struct xfrm_state *x)
  {
ccf17cc4b   Paul Moore   selinux: cleanup ...
383
  	return selinux_xfrm_delete(x->security);
c8c05a8ee   Catherine Zhang   [LSM-IPsec]: SELi...
384
  }
2c7946a7b   Catherine Zhang   [SECURITY]: TCP/U...
385
  /*
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
386
387
388
389
390
391
   * LSM hook that controls access to unlabelled packets.  If
   * a xfrm_state is authorizable (defined by macro) then it was
   * already authorized by the IPSec process.  If not, then
   * we need to check for unlabelled access since this may not have
   * gone thru the IPSec process.
   */
eef9b4162   Paul Moore   selinux: cleanup ...
392
393
  int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
  			      struct common_audit_data *ad)
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
394
  {
eef9b4162   Paul Moore   selinux: cleanup ...
395
396
397
  	int i;
  	struct sec_path *sp = skb->sp;
  	u32 peer_sid = SECINITSID_UNLABELED;
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
398
399
  
  	if (sp) {
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
400
  		for (i = 0; i < sp->len; i++) {
676447263   Dave Jones   [SELINUX] Fix bui...
401
  			struct xfrm_state *x = sp->xvec[i];
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
402

e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
403
404
  			if (x && selinux_authorizable_xfrm(x)) {
  				struct xfrm_sec_ctx *ctx = x->security;
eef9b4162   Paul Moore   selinux: cleanup ...
405
  				peer_sid = ctx->ctx_sid;
e0d1caa7b   Venkat Yekkirala   [MLSXFRM]: Flow b...
406
407
  				break;
  			}
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
408
409
  		}
  	}
eef9b4162   Paul Moore   selinux: cleanup ...
410
411
412
413
414
  	/* This check even when there's no association involved is intended,
  	 * according to Trent Jaeger, to make sure a process can't engage in
  	 * non-IPsec communication unless explicitly allowed by policy. */
  	return avc_has_perm(sk_sid, peer_sid,
  			    SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, ad);
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
415
416
417
418
419
420
421
  }
  
  /*
   * POSTROUTE_LAST hook's XFRM processing:
   * If we have no security association, then we need to determine
   * whether the socket is allowed to send to an unlabelled destination.
   * If we do have a authorizable security association, then it has already been
67f83cbf0   Venkat Yekkirala   SELinux: Fix SA s...
422
   * checked in the selinux_xfrm_state_pol_flow_match hook above.
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
423
   */
eef9b4162   Paul Moore   selinux: cleanup ...
424
425
  int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb,
  				struct common_audit_data *ad, u8 proto)
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
426
427
  {
  	struct dst_entry *dst;
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
428

67f83cbf0   Venkat Yekkirala   SELinux: Fix SA s...
429
430
431
432
  	switch (proto) {
  	case IPPROTO_AH:
  	case IPPROTO_ESP:
  	case IPPROTO_COMP:
eef9b4162   Paul Moore   selinux: cleanup ...
433
434
435
436
  		/* We should have already seen this packet once before it
  		 * underwent xfrm(s). No need to subject it to the unlabeled
  		 * check. */
  		return 0;
67f83cbf0   Venkat Yekkirala   SELinux: Fix SA s...
437
438
439
  	default:
  		break;
  	}
eef9b4162   Paul Moore   selinux: cleanup ...
440
441
442
  	dst = skb_dst(skb);
  	if (dst) {
  		struct dst_entry *iter;
67f83cbf0   Venkat Yekkirala   SELinux: Fix SA s...
443

eef9b4162   Paul Moore   selinux: cleanup ...
444
445
446
447
448
449
450
451
452
453
454
455
456
  		for (iter = dst; iter != NULL; iter = iter->child) {
  			struct xfrm_state *x = iter->xfrm;
  
  			if (x && selinux_authorizable_xfrm(x))
  				return 0;
  		}
  	}
  
  	/* This check even when there's no association involved is intended,
  	 * according to Trent Jaeger, to make sure a process can't engage in
  	 * non-IPsec communication unless explicitly allowed by policy. */
  	return avc_has_perm(sk_sid, SECINITSID_UNLABELED,
  			    SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, ad);
d28d1e080   Trent Jaeger   [LSM-IPSec]: Per-...
457
  }