xref: /openbmc/linux/security/selinux/xfrm.c (revision 2294be0f)
1d28d1e08STrent Jaeger /*
2d28d1e08STrent Jaeger  *  NSA Security-Enhanced Linux (SELinux) security module
3d28d1e08STrent Jaeger  *
4d28d1e08STrent Jaeger  *  This file contains the SELinux XFRM hook function implementations.
5d28d1e08STrent Jaeger  *
6d28d1e08STrent Jaeger  *  Authors:  Serge Hallyn <sergeh@us.ibm.com>
7d28d1e08STrent Jaeger  *	      Trent Jaeger <jaegert@us.ibm.com>
8d28d1e08STrent Jaeger  *
9e0d1caa7SVenkat Yekkirala  *  Updated: Venkat Yekkirala <vyekkirala@TrustedCS.com>
10e0d1caa7SVenkat Yekkirala  *
11e0d1caa7SVenkat Yekkirala  *           Granular IPSec Associations for use in MLS environments.
12e0d1caa7SVenkat Yekkirala  *
13d28d1e08STrent Jaeger  *  Copyright (C) 2005 International Business Machines Corporation
14e0d1caa7SVenkat Yekkirala  *  Copyright (C) 2006 Trusted Computer Solutions, Inc.
15d28d1e08STrent Jaeger  *
16d28d1e08STrent Jaeger  *	This program is free software; you can redistribute it and/or modify
17d28d1e08STrent Jaeger  *	it under the terms of the GNU General Public License version 2,
18d28d1e08STrent Jaeger  *	as published by the Free Software Foundation.
19d28d1e08STrent Jaeger  */
20d28d1e08STrent Jaeger 
21d28d1e08STrent Jaeger /*
22d28d1e08STrent Jaeger  * USAGE:
23d28d1e08STrent Jaeger  * NOTES:
24d28d1e08STrent Jaeger  *   1. Make sure to enable the following options in your kernel config:
25d28d1e08STrent Jaeger  *	CONFIG_SECURITY=y
26d28d1e08STrent Jaeger  *	CONFIG_SECURITY_NETWORK=y
27d28d1e08STrent Jaeger  *	CONFIG_SECURITY_NETWORK_XFRM=y
28d28d1e08STrent Jaeger  *	CONFIG_SECURITY_SELINUX=m/y
29d28d1e08STrent Jaeger  * ISSUES:
30d28d1e08STrent Jaeger  *   1. Caching packets, so they are not dropped during negotiation
31d28d1e08STrent Jaeger  *   2. Emulating a reasonable SO_PEERSEC across machines
32d28d1e08STrent Jaeger  *   3. Testing addition of sk_policy's with security context via setsockopt
33d28d1e08STrent Jaeger  */
34d28d1e08STrent Jaeger #include <linux/kernel.h>
35d28d1e08STrent Jaeger #include <linux/init.h>
36d28d1e08STrent Jaeger #include <linux/security.h>
37d28d1e08STrent Jaeger #include <linux/types.h>
385a0e3ad6STejun Heo #include <linux/slab.h>
39d28d1e08STrent Jaeger #include <linux/ip.h>
40d28d1e08STrent Jaeger #include <linux/tcp.h>
41d28d1e08STrent Jaeger #include <linux/skbuff.h>
42d28d1e08STrent Jaeger #include <linux/xfrm.h>
43d28d1e08STrent Jaeger #include <net/xfrm.h>
44d28d1e08STrent Jaeger #include <net/checksum.h>
45d28d1e08STrent Jaeger #include <net/udp.h>
4660063497SArun Sharma #include <linux/atomic.h>
47d28d1e08STrent Jaeger 
48d28d1e08STrent Jaeger #include "avc.h"
49d28d1e08STrent Jaeger #include "objsec.h"
50d28d1e08STrent Jaeger #include "xfrm.h"
51d28d1e08STrent Jaeger 
52d621d35eSPaul Moore /* Labeled XFRM instance counter */
53d621d35eSPaul Moore atomic_t selinux_xfrm_refcount = ATOMIC_INIT(0);
54d28d1e08STrent Jaeger 
55d28d1e08STrent Jaeger /*
564baabeecSPaul Moore  * Returns true if the context is an LSM/SELinux context.
57d28d1e08STrent Jaeger  */
58d28d1e08STrent Jaeger static inline int selinux_authorizable_ctx(struct xfrm_sec_ctx *ctx)
59d28d1e08STrent Jaeger {
60d28d1e08STrent Jaeger 	return (ctx &&
61d28d1e08STrent Jaeger 		(ctx->ctx_doi == XFRM_SC_DOI_LSM) &&
62d28d1e08STrent Jaeger 		(ctx->ctx_alg == XFRM_SC_ALG_SELINUX));
63d28d1e08STrent Jaeger }
64d28d1e08STrent Jaeger 
65d28d1e08STrent Jaeger /*
664baabeecSPaul Moore  * Returns true if the xfrm contains a security blob for SELinux.
67d28d1e08STrent Jaeger  */
68d28d1e08STrent Jaeger static inline int selinux_authorizable_xfrm(struct xfrm_state *x)
69d28d1e08STrent Jaeger {
70d28d1e08STrent Jaeger 	return selinux_authorizable_ctx(x->security);
71d28d1e08STrent Jaeger }
72d28d1e08STrent Jaeger 
73d28d1e08STrent Jaeger /*
742e5aa866SPaul Moore  * Allocates a xfrm_sec_state and populates it using the supplied security
752e5aa866SPaul Moore  * xfrm_user_sec_ctx context.
762e5aa866SPaul Moore  */
772e5aa866SPaul Moore static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
7852a4c640SNikolay Aleksandrov 				   struct xfrm_user_sec_ctx *uctx,
7952a4c640SNikolay Aleksandrov 				   gfp_t gfp)
802e5aa866SPaul Moore {
812e5aa866SPaul Moore 	int rc;
822e5aa866SPaul Moore 	const struct task_security_struct *tsec = current_security();
832e5aa866SPaul Moore 	struct xfrm_sec_ctx *ctx = NULL;
842e5aa866SPaul Moore 	u32 str_len;
852e5aa866SPaul Moore 
862e5aa866SPaul Moore 	if (ctxp == NULL || uctx == NULL ||
872e5aa866SPaul Moore 	    uctx->ctx_doi != XFRM_SC_DOI_LSM ||
882e5aa866SPaul Moore 	    uctx->ctx_alg != XFRM_SC_ALG_SELINUX)
892e5aa866SPaul Moore 		return -EINVAL;
902e5aa866SPaul Moore 
912e5aa866SPaul Moore 	str_len = uctx->ctx_len;
922e5aa866SPaul Moore 	if (str_len >= PAGE_SIZE)
932e5aa866SPaul Moore 		return -ENOMEM;
942e5aa866SPaul Moore 
9552a4c640SNikolay Aleksandrov 	ctx = kmalloc(sizeof(*ctx) + str_len + 1, gfp);
962e5aa866SPaul Moore 	if (!ctx)
972e5aa866SPaul Moore 		return -ENOMEM;
982e5aa866SPaul Moore 
992e5aa866SPaul Moore 	ctx->ctx_doi = XFRM_SC_DOI_LSM;
1002e5aa866SPaul Moore 	ctx->ctx_alg = XFRM_SC_ALG_SELINUX;
1012e5aa866SPaul Moore 	ctx->ctx_len = str_len;
1022e5aa866SPaul Moore 	memcpy(ctx->ctx_str, &uctx[1], str_len);
1032e5aa866SPaul Moore 	ctx->ctx_str[str_len] = '\0';
104aa8e712cSStephen Smalley 	rc = security_context_to_sid(&selinux_state, ctx->ctx_str, str_len,
105aa8e712cSStephen Smalley 				     &ctx->ctx_sid, gfp);
1062e5aa866SPaul Moore 	if (rc)
1072e5aa866SPaul Moore 		goto err;
1082e5aa866SPaul Moore 
1096b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
1106b6bc620SStephen Smalley 			  tsec->sid, ctx->ctx_sid,
1112e5aa866SPaul Moore 			  SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, NULL);
1122e5aa866SPaul Moore 	if (rc)
1132e5aa866SPaul Moore 		goto err;
1142e5aa866SPaul Moore 
1152e5aa866SPaul Moore 	*ctxp = ctx;
1162e5aa866SPaul Moore 	atomic_inc(&selinux_xfrm_refcount);
1172e5aa866SPaul Moore 	return 0;
1182e5aa866SPaul Moore 
1192e5aa866SPaul Moore err:
1202e5aa866SPaul Moore 	kfree(ctx);
1212e5aa866SPaul Moore 	return rc;
1222e5aa866SPaul Moore }
1232e5aa866SPaul Moore 
1242e5aa866SPaul Moore /*
125ccf17cc4SPaul Moore  * Free the xfrm_sec_ctx structure.
126ccf17cc4SPaul Moore  */
127ccf17cc4SPaul Moore static void selinux_xfrm_free(struct xfrm_sec_ctx *ctx)
128ccf17cc4SPaul Moore {
129ccf17cc4SPaul Moore 	if (!ctx)
130ccf17cc4SPaul Moore 		return;
131ccf17cc4SPaul Moore 
132ccf17cc4SPaul Moore 	atomic_dec(&selinux_xfrm_refcount);
133ccf17cc4SPaul Moore 	kfree(ctx);
134ccf17cc4SPaul Moore }
135ccf17cc4SPaul Moore 
136ccf17cc4SPaul Moore /*
137ccf17cc4SPaul Moore  * Authorize the deletion of a labeled SA or policy rule.
138ccf17cc4SPaul Moore  */
139ccf17cc4SPaul Moore static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx)
140ccf17cc4SPaul Moore {
141ccf17cc4SPaul Moore 	const struct task_security_struct *tsec = current_security();
142ccf17cc4SPaul Moore 
143ccf17cc4SPaul Moore 	if (!ctx)
144ccf17cc4SPaul Moore 		return 0;
145ccf17cc4SPaul Moore 
1466b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
1476b6bc620SStephen Smalley 			    tsec->sid, ctx->ctx_sid,
148ccf17cc4SPaul Moore 			    SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT,
149ccf17cc4SPaul Moore 			    NULL);
150ccf17cc4SPaul Moore }
151ccf17cc4SPaul Moore 
152ccf17cc4SPaul Moore /*
1534baabeecSPaul Moore  * LSM hook implementation that authorizes that a flow can use a xfrm policy
1544baabeecSPaul Moore  * rule.
155d28d1e08STrent Jaeger  */
15603e1ad7bSPaul Moore int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir)
157d28d1e08STrent Jaeger {
1585b368e61SVenkat Yekkirala 	int rc;
15996484348SPaul Moore 
16096484348SPaul Moore 	/* All flows should be treated as polmatch'ing an otherwise applicable
16196484348SPaul Moore 	 * "non-labeled" policy. This would prevent inadvertent "leaks". */
16296484348SPaul Moore 	if (!ctx)
16396484348SPaul Moore 		return 0;
164d28d1e08STrent Jaeger 
165d28d1e08STrent Jaeger 	/* Context sid is either set to label or ANY_ASSOC */
166d28d1e08STrent Jaeger 	if (!selinux_authorizable_ctx(ctx))
167d28d1e08STrent Jaeger 		return -EINVAL;
168d28d1e08STrent Jaeger 
1696b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
1706b6bc620SStephen Smalley 			  fl_secid, ctx->ctx_sid,
17196484348SPaul Moore 			  SECCLASS_ASSOCIATION, ASSOCIATION__POLMATCH, NULL);
17296484348SPaul Moore 	return (rc == -EACCES ? -ESRCH : rc);
173d28d1e08STrent Jaeger }
174d28d1e08STrent Jaeger 
175d28d1e08STrent Jaeger /*
176e0d1caa7SVenkat Yekkirala  * LSM hook implementation that authorizes that a state matches
177e0d1caa7SVenkat Yekkirala  * the given policy, flow combo.
178e0d1caa7SVenkat Yekkirala  */
17996484348SPaul Moore int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
18096484348SPaul Moore 				      struct xfrm_policy *xp,
181e33f7704SDavid S. Miller 				      const struct flowi *fl)
182e0d1caa7SVenkat Yekkirala {
183e0d1caa7SVenkat Yekkirala 	u32 state_sid;
184e0d1caa7SVenkat Yekkirala 
18567f83cbfSVenkat Yekkirala 	if (!xp->security)
1865b368e61SVenkat Yekkirala 		if (x->security)
1875b368e61SVenkat Yekkirala 			/* unlabeled policy and labeled SA can't match */
1885b368e61SVenkat Yekkirala 			return 0;
189e0d1caa7SVenkat Yekkirala 		else
1905b368e61SVenkat Yekkirala 			/* unlabeled policy and unlabeled SA match all flows */
1915b368e61SVenkat Yekkirala 			return 1;
19267f83cbfSVenkat Yekkirala 	else
19367f83cbfSVenkat Yekkirala 		if (!x->security)
19467f83cbfSVenkat Yekkirala 			/* unlabeled SA and labeled policy can't match */
19567f83cbfSVenkat Yekkirala 			return 0;
19667f83cbfSVenkat Yekkirala 		else
19767f83cbfSVenkat Yekkirala 			if (!selinux_authorizable_xfrm(x))
19867f83cbfSVenkat Yekkirala 				/* Not a SELinux-labeled SA */
199e0d1caa7SVenkat Yekkirala 				return 0;
200e0d1caa7SVenkat Yekkirala 
20167f83cbfSVenkat Yekkirala 	state_sid = x->security->ctx_sid;
20267f83cbfSVenkat Yekkirala 
2031d28f42cSDavid S. Miller 	if (fl->flowi_secid != state_sid)
20467f83cbfSVenkat Yekkirala 		return 0;
20567f83cbfSVenkat Yekkirala 
20696484348SPaul Moore 	/* We don't need a separate SA Vs. policy polmatch check since the SA
20796484348SPaul Moore 	 * is now of the same label as the flow and a flow Vs. policy polmatch
20896484348SPaul Moore 	 * check had already happened in selinux_xfrm_policy_lookup() above. */
2096b6bc620SStephen Smalley 	return (avc_has_perm(&selinux_state,
2106b6bc620SStephen Smalley 			     fl->flowi_secid, state_sid,
21196484348SPaul Moore 			    SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO,
21296484348SPaul Moore 			    NULL) ? 0 : 1);
213e0d1caa7SVenkat Yekkirala }
214e0d1caa7SVenkat Yekkirala 
215817eff71SPaul Moore static u32 selinux_xfrm_skb_sid_egress(struct sk_buff *skb)
216817eff71SPaul Moore {
217817eff71SPaul Moore 	struct dst_entry *dst = skb_dst(skb);
218817eff71SPaul Moore 	struct xfrm_state *x;
219817eff71SPaul Moore 
220817eff71SPaul Moore 	if (dst == NULL)
221817eff71SPaul Moore 		return SECSID_NULL;
222817eff71SPaul Moore 	x = dst->xfrm;
223817eff71SPaul Moore 	if (x == NULL || !selinux_authorizable_xfrm(x))
224817eff71SPaul Moore 		return SECSID_NULL;
225817eff71SPaul Moore 
226817eff71SPaul Moore 	return x->security->ctx_sid;
227817eff71SPaul Moore }
228817eff71SPaul Moore 
229817eff71SPaul Moore static int selinux_xfrm_skb_sid_ingress(struct sk_buff *skb,
230817eff71SPaul Moore 					u32 *sid, int ckall)
231e0d1caa7SVenkat Yekkirala {
232e2193695SPaul Moore 	u32 sid_session = SECSID_NULL;
2332294be0fSFlorian Westphal 	struct sec_path *sp = skb_sec_path(skb);
234e0d1caa7SVenkat Yekkirala 
235e0d1caa7SVenkat Yekkirala 	if (sp) {
236e2193695SPaul Moore 		int i;
237e0d1caa7SVenkat Yekkirala 
238e0d1caa7SVenkat Yekkirala 		for (i = sp->len - 1; i >= 0; i--) {
239e0d1caa7SVenkat Yekkirala 			struct xfrm_state *x = sp->xvec[i];
240e0d1caa7SVenkat Yekkirala 			if (selinux_authorizable_xfrm(x)) {
241e0d1caa7SVenkat Yekkirala 				struct xfrm_sec_ctx *ctx = x->security;
242e0d1caa7SVenkat Yekkirala 
243e2193695SPaul Moore 				if (sid_session == SECSID_NULL) {
244e2193695SPaul Moore 					sid_session = ctx->ctx_sid;
245beb8d13bSVenkat Yekkirala 					if (!ckall)
246e2193695SPaul Moore 						goto out;
247e2193695SPaul Moore 				} else if (sid_session != ctx->ctx_sid) {
248e2193695SPaul Moore 					*sid = SECSID_NULL;
249e0d1caa7SVenkat Yekkirala 					return -EINVAL;
250e0d1caa7SVenkat Yekkirala 				}
251e0d1caa7SVenkat Yekkirala 			}
252e0d1caa7SVenkat Yekkirala 		}
253e2193695SPaul Moore 	}
254e0d1caa7SVenkat Yekkirala 
255e2193695SPaul Moore out:
256e2193695SPaul Moore 	*sid = sid_session;
257e0d1caa7SVenkat Yekkirala 	return 0;
258e0d1caa7SVenkat Yekkirala }
259e0d1caa7SVenkat Yekkirala 
260e0d1caa7SVenkat Yekkirala /*
261817eff71SPaul Moore  * LSM hook implementation that checks and/or returns the xfrm sid for the
262817eff71SPaul Moore  * incoming packet.
263817eff71SPaul Moore  */
264817eff71SPaul Moore int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall)
265817eff71SPaul Moore {
266817eff71SPaul Moore 	if (skb == NULL) {
267817eff71SPaul Moore 		*sid = SECSID_NULL;
268817eff71SPaul Moore 		return 0;
269817eff71SPaul Moore 	}
270817eff71SPaul Moore 	return selinux_xfrm_skb_sid_ingress(skb, sid, ckall);
271817eff71SPaul Moore }
272817eff71SPaul Moore 
273817eff71SPaul Moore int selinux_xfrm_skb_sid(struct sk_buff *skb, u32 *sid)
274817eff71SPaul Moore {
275817eff71SPaul Moore 	int rc;
276817eff71SPaul Moore 
277817eff71SPaul Moore 	rc = selinux_xfrm_skb_sid_ingress(skb, sid, 0);
278817eff71SPaul Moore 	if (rc == 0 && *sid == SECSID_NULL)
279817eff71SPaul Moore 		*sid = selinux_xfrm_skb_sid_egress(skb);
280817eff71SPaul Moore 
281817eff71SPaul Moore 	return rc;
282817eff71SPaul Moore }
283817eff71SPaul Moore 
284817eff71SPaul Moore /*
2854baabeecSPaul Moore  * LSM hook implementation that allocs and transfers uctx spec to xfrm_policy.
286d28d1e08STrent Jaeger  */
28703e1ad7bSPaul Moore int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
28852a4c640SNikolay Aleksandrov 			      struct xfrm_user_sec_ctx *uctx,
28952a4c640SNikolay Aleksandrov 			      gfp_t gfp)
290d28d1e08STrent Jaeger {
29152a4c640SNikolay Aleksandrov 	return selinux_xfrm_alloc_user(ctxp, uctx, gfp);
292d28d1e08STrent Jaeger }
293d28d1e08STrent Jaeger 
294d28d1e08STrent Jaeger /*
2954baabeecSPaul Moore  * LSM hook implementation that copies security data structure from old to new
2964baabeecSPaul Moore  * for policy cloning.
297d28d1e08STrent Jaeger  */
29803e1ad7bSPaul Moore int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx,
29903e1ad7bSPaul Moore 			      struct xfrm_sec_ctx **new_ctxp)
300d28d1e08STrent Jaeger {
30103e1ad7bSPaul Moore 	struct xfrm_sec_ctx *new_ctx;
302d28d1e08STrent Jaeger 
303ccf17cc4SPaul Moore 	if (!old_ctx)
304ccf17cc4SPaul Moore 		return 0;
305ccf17cc4SPaul Moore 
3067d1db4b2SDuan Jiong 	new_ctx = kmemdup(old_ctx, sizeof(*old_ctx) + old_ctx->ctx_len,
3077d1db4b2SDuan Jiong 			  GFP_ATOMIC);
308d28d1e08STrent Jaeger 	if (!new_ctx)
309d28d1e08STrent Jaeger 		return -ENOMEM;
310e4e8536fSPaul Moore 	atomic_inc(&selinux_xfrm_refcount);
31103e1ad7bSPaul Moore 	*new_ctxp = new_ctx;
312ccf17cc4SPaul Moore 
313d28d1e08STrent Jaeger 	return 0;
314d28d1e08STrent Jaeger }
315d28d1e08STrent Jaeger 
316d28d1e08STrent Jaeger /*
31703e1ad7bSPaul Moore  * LSM hook implementation that frees xfrm_sec_ctx security information.
318d28d1e08STrent Jaeger  */
31903e1ad7bSPaul Moore void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx)
320d28d1e08STrent Jaeger {
321ccf17cc4SPaul Moore 	selinux_xfrm_free(ctx);
322d28d1e08STrent Jaeger }
323d28d1e08STrent Jaeger 
324d28d1e08STrent Jaeger /*
325c8c05a8eSCatherine Zhang  * LSM hook implementation that authorizes deletion of labeled policies.
326c8c05a8eSCatherine Zhang  */
32703e1ad7bSPaul Moore int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx)
328c8c05a8eSCatherine Zhang {
329ccf17cc4SPaul Moore 	return selinux_xfrm_delete(ctx);
330c8c05a8eSCatherine Zhang }
331c8c05a8eSCatherine Zhang 
332c8c05a8eSCatherine Zhang /*
3332e5aa866SPaul Moore  * LSM hook implementation that allocates a xfrm_sec_state, populates it using
3342e5aa866SPaul Moore  * the supplied security context, and assigns it to the xfrm_state.
335d28d1e08STrent Jaeger  */
3362e5aa866SPaul Moore int selinux_xfrm_state_alloc(struct xfrm_state *x,
3372e5aa866SPaul Moore 			     struct xfrm_user_sec_ctx *uctx)
338d28d1e08STrent Jaeger {
33952a4c640SNikolay Aleksandrov 	return selinux_xfrm_alloc_user(&x->security, uctx, GFP_KERNEL);
3402e5aa866SPaul Moore }
341d28d1e08STrent Jaeger 
3422e5aa866SPaul Moore /*
3432e5aa866SPaul Moore  * LSM hook implementation that allocates a xfrm_sec_state and populates based
3442e5aa866SPaul Moore  * on a secid.
3452e5aa866SPaul Moore  */
3462e5aa866SPaul Moore int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
3472e5aa866SPaul Moore 				     struct xfrm_sec_ctx *polsec, u32 secid)
3482e5aa866SPaul Moore {
3492e5aa866SPaul Moore 	int rc;
3502e5aa866SPaul Moore 	struct xfrm_sec_ctx *ctx;
3512e5aa866SPaul Moore 	char *ctx_str = NULL;
3522e5aa866SPaul Moore 	int str_len;
353d28d1e08STrent Jaeger 
3542e5aa866SPaul Moore 	if (!polsec)
3552e5aa866SPaul Moore 		return 0;
3562e5aa866SPaul Moore 
3572e5aa866SPaul Moore 	if (secid == 0)
3582e5aa866SPaul Moore 		return -EINVAL;
3592e5aa866SPaul Moore 
360aa8e712cSStephen Smalley 	rc = security_sid_to_context(&selinux_state, secid, &ctx_str,
361aa8e712cSStephen Smalley 				     &str_len);
3622e5aa866SPaul Moore 	if (rc)
3632e5aa866SPaul Moore 		return rc;
3642e5aa866SPaul Moore 
3652e5aa866SPaul Moore 	ctx = kmalloc(sizeof(*ctx) + str_len, GFP_ATOMIC);
3660af90164SGeyslan G. Bem 	if (!ctx) {
3670af90164SGeyslan G. Bem 		rc = -ENOMEM;
3680af90164SGeyslan G. Bem 		goto out;
3690af90164SGeyslan G. Bem 	}
3702e5aa866SPaul Moore 
3712e5aa866SPaul Moore 	ctx->ctx_doi = XFRM_SC_DOI_LSM;
3722e5aa866SPaul Moore 	ctx->ctx_alg = XFRM_SC_ALG_SELINUX;
3732e5aa866SPaul Moore 	ctx->ctx_sid = secid;
3742e5aa866SPaul Moore 	ctx->ctx_len = str_len;
3752e5aa866SPaul Moore 	memcpy(ctx->ctx_str, ctx_str, str_len);
3762e5aa866SPaul Moore 
3772e5aa866SPaul Moore 	x->security = ctx;
378d621d35eSPaul Moore 	atomic_inc(&selinux_xfrm_refcount);
3790af90164SGeyslan G. Bem out:
3800af90164SGeyslan G. Bem 	kfree(ctx_str);
3810af90164SGeyslan G. Bem 	return rc;
382d28d1e08STrent Jaeger }
383d28d1e08STrent Jaeger 
384d28d1e08STrent Jaeger /*
385d28d1e08STrent Jaeger  * LSM hook implementation that frees xfrm_state security information.
386d28d1e08STrent Jaeger  */
387d28d1e08STrent Jaeger void selinux_xfrm_state_free(struct xfrm_state *x)
388d28d1e08STrent Jaeger {
389ccf17cc4SPaul Moore 	selinux_xfrm_free(x->security);
390d28d1e08STrent Jaeger }
391d28d1e08STrent Jaeger 
3922c7946a7SCatherine Zhang /*
393c8c05a8eSCatherine Zhang  * LSM hook implementation that authorizes deletion of labeled SAs.
394c8c05a8eSCatherine Zhang  */
395c8c05a8eSCatherine Zhang int selinux_xfrm_state_delete(struct xfrm_state *x)
396c8c05a8eSCatherine Zhang {
397ccf17cc4SPaul Moore 	return selinux_xfrm_delete(x->security);
398c8c05a8eSCatherine Zhang }
399c8c05a8eSCatherine Zhang 
400c8c05a8eSCatherine Zhang /*
401d28d1e08STrent Jaeger  * LSM hook that controls access to unlabelled packets.  If
402d28d1e08STrent Jaeger  * a xfrm_state is authorizable (defined by macro) then it was
403d28d1e08STrent Jaeger  * already authorized by the IPSec process.  If not, then
404d28d1e08STrent Jaeger  * we need to check for unlabelled access since this may not have
405d28d1e08STrent Jaeger  * gone thru the IPSec process.
406d28d1e08STrent Jaeger  */
407eef9b416SPaul Moore int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
4082bf49690SThomas Liu 			      struct common_audit_data *ad)
409d28d1e08STrent Jaeger {
410eef9b416SPaul Moore 	int i;
4112294be0fSFlorian Westphal 	struct sec_path *sp = skb_sec_path(skb);
412eef9b416SPaul Moore 	u32 peer_sid = SECINITSID_UNLABELED;
413d28d1e08STrent Jaeger 
414d28d1e08STrent Jaeger 	if (sp) {
415d28d1e08STrent Jaeger 		for (i = 0; i < sp->len; i++) {
41667644726SDave Jones 			struct xfrm_state *x = sp->xvec[i];
417d28d1e08STrent Jaeger 
418e0d1caa7SVenkat Yekkirala 			if (x && selinux_authorizable_xfrm(x)) {
419e0d1caa7SVenkat Yekkirala 				struct xfrm_sec_ctx *ctx = x->security;
420eef9b416SPaul Moore 				peer_sid = ctx->ctx_sid;
421e0d1caa7SVenkat Yekkirala 				break;
422e0d1caa7SVenkat Yekkirala 			}
423d28d1e08STrent Jaeger 		}
424d28d1e08STrent Jaeger 	}
425d28d1e08STrent Jaeger 
426eef9b416SPaul Moore 	/* This check even when there's no association involved is intended,
427eef9b416SPaul Moore 	 * according to Trent Jaeger, to make sure a process can't engage in
428eef9b416SPaul Moore 	 * non-IPsec communication unless explicitly allowed by policy. */
4296b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
4306b6bc620SStephen Smalley 			    sk_sid, peer_sid,
431eef9b416SPaul Moore 			    SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, ad);
432d28d1e08STrent Jaeger }
433d28d1e08STrent Jaeger 
434d28d1e08STrent Jaeger /*
435d28d1e08STrent Jaeger  * POSTROUTE_LAST hook's XFRM processing:
436d28d1e08STrent Jaeger  * If we have no security association, then we need to determine
437d28d1e08STrent Jaeger  * whether the socket is allowed to send to an unlabelled destination.
438d28d1e08STrent Jaeger  * If we do have a authorizable security association, then it has already been
43967f83cbfSVenkat Yekkirala  * checked in the selinux_xfrm_state_pol_flow_match hook above.
440d28d1e08STrent Jaeger  */
441eef9b416SPaul Moore int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb,
4422bf49690SThomas Liu 				struct common_audit_data *ad, u8 proto)
443d28d1e08STrent Jaeger {
444d28d1e08STrent Jaeger 	struct dst_entry *dst;
445d28d1e08STrent Jaeger 
44667f83cbfSVenkat Yekkirala 	switch (proto) {
44767f83cbfSVenkat Yekkirala 	case IPPROTO_AH:
44867f83cbfSVenkat Yekkirala 	case IPPROTO_ESP:
44967f83cbfSVenkat Yekkirala 	case IPPROTO_COMP:
450eef9b416SPaul Moore 		/* We should have already seen this packet once before it
451eef9b416SPaul Moore 		 * underwent xfrm(s). No need to subject it to the unlabeled
452eef9b416SPaul Moore 		 * check. */
453eef9b416SPaul Moore 		return 0;
45467f83cbfSVenkat Yekkirala 	default:
45567f83cbfSVenkat Yekkirala 		break;
45667f83cbfSVenkat Yekkirala 	}
45767f83cbfSVenkat Yekkirala 
458eef9b416SPaul Moore 	dst = skb_dst(skb);
459eef9b416SPaul Moore 	if (dst) {
460eef9b416SPaul Moore 		struct dst_entry *iter;
46167f83cbfSVenkat Yekkirala 
462b92cf4aaSDavid Miller 		for (iter = dst; iter != NULL; iter = xfrm_dst_child(iter)) {
463eef9b416SPaul Moore 			struct xfrm_state *x = iter->xfrm;
464eef9b416SPaul Moore 
465eef9b416SPaul Moore 			if (x && selinux_authorizable_xfrm(x))
466eef9b416SPaul Moore 				return 0;
467eef9b416SPaul Moore 		}
468eef9b416SPaul Moore 	}
469eef9b416SPaul Moore 
470eef9b416SPaul Moore 	/* This check even when there's no association involved is intended,
471eef9b416SPaul Moore 	 * according to Trent Jaeger, to make sure a process can't engage in
472eef9b416SPaul Moore 	 * non-IPsec communication unless explicitly allowed by policy. */
4736b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state, sk_sid, SECINITSID_UNLABELED,
474eef9b416SPaul Moore 			    SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, ad);
475d28d1e08STrent Jaeger }
476