xref: /openbmc/linux/security/selinux/xfrm.c (revision 4e5ab4cb)
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  *
9d28d1e08STrent Jaeger  *  Copyright (C) 2005 International Business Machines Corporation
10d28d1e08STrent Jaeger  *
11d28d1e08STrent Jaeger  *	This program is free software; you can redistribute it and/or modify
12d28d1e08STrent Jaeger  *	it under the terms of the GNU General Public License version 2,
13d28d1e08STrent Jaeger  *	as published by the Free Software Foundation.
14d28d1e08STrent Jaeger  */
15d28d1e08STrent Jaeger 
16d28d1e08STrent Jaeger /*
17d28d1e08STrent Jaeger  * USAGE:
18d28d1e08STrent Jaeger  * NOTES:
19d28d1e08STrent Jaeger  *   1. Make sure to enable the following options in your kernel config:
20d28d1e08STrent Jaeger  *	CONFIG_SECURITY=y
21d28d1e08STrent Jaeger  *	CONFIG_SECURITY_NETWORK=y
22d28d1e08STrent Jaeger  *	CONFIG_SECURITY_NETWORK_XFRM=y
23d28d1e08STrent Jaeger  *	CONFIG_SECURITY_SELINUX=m/y
24d28d1e08STrent Jaeger  * ISSUES:
25d28d1e08STrent Jaeger  *   1. Caching packets, so they are not dropped during negotiation
26d28d1e08STrent Jaeger  *   2. Emulating a reasonable SO_PEERSEC across machines
27d28d1e08STrent Jaeger  *   3. Testing addition of sk_policy's with security context via setsockopt
28d28d1e08STrent Jaeger  */
29d28d1e08STrent Jaeger #include <linux/config.h>
30d28d1e08STrent Jaeger #include <linux/module.h>
31d28d1e08STrent Jaeger #include <linux/kernel.h>
32d28d1e08STrent Jaeger #include <linux/init.h>
33d28d1e08STrent Jaeger #include <linux/security.h>
34d28d1e08STrent Jaeger #include <linux/types.h>
35d28d1e08STrent Jaeger #include <linux/netfilter.h>
36d28d1e08STrent Jaeger #include <linux/netfilter_ipv4.h>
37d28d1e08STrent Jaeger #include <linux/netfilter_ipv6.h>
38d28d1e08STrent Jaeger #include <linux/ip.h>
39d28d1e08STrent Jaeger #include <linux/tcp.h>
40d28d1e08STrent Jaeger #include <linux/skbuff.h>
41d28d1e08STrent Jaeger #include <linux/xfrm.h>
42d28d1e08STrent Jaeger #include <net/xfrm.h>
43d28d1e08STrent Jaeger #include <net/checksum.h>
44d28d1e08STrent Jaeger #include <net/udp.h>
45d28d1e08STrent Jaeger #include <asm/semaphore.h>
46d28d1e08STrent Jaeger 
47d28d1e08STrent Jaeger #include "avc.h"
48d28d1e08STrent Jaeger #include "objsec.h"
49d28d1e08STrent Jaeger #include "xfrm.h"
50d28d1e08STrent Jaeger 
51d28d1e08STrent Jaeger 
52d28d1e08STrent Jaeger /*
53d28d1e08STrent Jaeger  * Returns true if an LSM/SELinux context
54d28d1e08STrent Jaeger  */
55d28d1e08STrent Jaeger static inline int selinux_authorizable_ctx(struct xfrm_sec_ctx *ctx)
56d28d1e08STrent Jaeger {
57d28d1e08STrent Jaeger 	return (ctx &&
58d28d1e08STrent Jaeger 		(ctx->ctx_doi == XFRM_SC_DOI_LSM) &&
59d28d1e08STrent Jaeger 		(ctx->ctx_alg == XFRM_SC_ALG_SELINUX));
60d28d1e08STrent Jaeger }
61d28d1e08STrent Jaeger 
62d28d1e08STrent Jaeger /*
63d28d1e08STrent Jaeger  * Returns true if the xfrm contains a security blob for SELinux
64d28d1e08STrent Jaeger  */
65d28d1e08STrent Jaeger static inline int selinux_authorizable_xfrm(struct xfrm_state *x)
66d28d1e08STrent Jaeger {
67d28d1e08STrent Jaeger 	return selinux_authorizable_ctx(x->security);
68d28d1e08STrent Jaeger }
69d28d1e08STrent Jaeger 
70d28d1e08STrent Jaeger /*
71d28d1e08STrent Jaeger  * LSM hook implementation that authorizes that a socket can be used
72d28d1e08STrent Jaeger  * with the corresponding xfrm_sec_ctx and direction.
73d28d1e08STrent Jaeger  */
74d28d1e08STrent Jaeger int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir)
75d28d1e08STrent Jaeger {
76d28d1e08STrent Jaeger 	int rc = 0;
77d28d1e08STrent Jaeger 	u32 sel_sid = SECINITSID_UNLABELED;
78d28d1e08STrent Jaeger 	struct xfrm_sec_ctx *ctx;
79d28d1e08STrent Jaeger 
80d28d1e08STrent Jaeger 	/* Context sid is either set to label or ANY_ASSOC */
81d28d1e08STrent Jaeger 	if ((ctx = xp->security)) {
82d28d1e08STrent Jaeger 		if (!selinux_authorizable_ctx(ctx))
83d28d1e08STrent Jaeger 			return -EINVAL;
84d28d1e08STrent Jaeger 
85d28d1e08STrent Jaeger 		sel_sid = ctx->ctx_sid;
86d28d1e08STrent Jaeger 	}
87d28d1e08STrent Jaeger 
88d28d1e08STrent Jaeger 	rc = avc_has_perm(sk_sid, sel_sid, SECCLASS_ASSOCIATION,
89d28d1e08STrent Jaeger 			  ((dir == FLOW_DIR_IN) ? ASSOCIATION__RECVFROM :
90d28d1e08STrent Jaeger 			   ((dir == FLOW_DIR_OUT) ?  ASSOCIATION__SENDTO :
91d28d1e08STrent Jaeger 			    (ASSOCIATION__SENDTO | ASSOCIATION__RECVFROM))),
92d28d1e08STrent Jaeger 			  NULL);
93d28d1e08STrent Jaeger 
94d28d1e08STrent Jaeger 	return rc;
95d28d1e08STrent Jaeger }
96d28d1e08STrent Jaeger 
97d28d1e08STrent Jaeger /*
98d28d1e08STrent Jaeger  * Security blob allocation for xfrm_policy and xfrm_state
99d28d1e08STrent Jaeger  * CTX does not have a meaningful value on input
100d28d1e08STrent Jaeger  */
101d28d1e08STrent Jaeger static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *uctx)
102d28d1e08STrent Jaeger {
103d28d1e08STrent Jaeger 	int rc = 0;
104d28d1e08STrent Jaeger 	struct task_security_struct *tsec = current->security;
105d28d1e08STrent Jaeger 	struct xfrm_sec_ctx *ctx;
106d28d1e08STrent Jaeger 
107d28d1e08STrent Jaeger 	BUG_ON(!uctx);
108d28d1e08STrent Jaeger 	BUG_ON(uctx->ctx_doi != XFRM_SC_ALG_SELINUX);
109d28d1e08STrent Jaeger 
110d28d1e08STrent Jaeger 	if (uctx->ctx_len >= PAGE_SIZE)
111d28d1e08STrent Jaeger 		return -ENOMEM;
112d28d1e08STrent Jaeger 
113d28d1e08STrent Jaeger 	*ctxp = ctx = kmalloc(sizeof(*ctx) +
114d28d1e08STrent Jaeger 			      uctx->ctx_len,
115d28d1e08STrent Jaeger 			      GFP_KERNEL);
116d28d1e08STrent Jaeger 
117d28d1e08STrent Jaeger 	if (!ctx)
118d28d1e08STrent Jaeger 		return -ENOMEM;
119d28d1e08STrent Jaeger 
120d28d1e08STrent Jaeger 	ctx->ctx_doi = uctx->ctx_doi;
121d28d1e08STrent Jaeger 	ctx->ctx_len = uctx->ctx_len;
122d28d1e08STrent Jaeger 	ctx->ctx_alg = uctx->ctx_alg;
123d28d1e08STrent Jaeger 
124d28d1e08STrent Jaeger 	memcpy(ctx->ctx_str,
125d28d1e08STrent Jaeger 	       uctx+1,
126d28d1e08STrent Jaeger 	       ctx->ctx_len);
127d28d1e08STrent Jaeger 	rc = security_context_to_sid(ctx->ctx_str,
128d28d1e08STrent Jaeger 				     ctx->ctx_len,
129d28d1e08STrent Jaeger 				     &ctx->ctx_sid);
130d28d1e08STrent Jaeger 
131d28d1e08STrent Jaeger 	if (rc)
132d28d1e08STrent Jaeger 		goto out;
133d28d1e08STrent Jaeger 
134d28d1e08STrent Jaeger 	/*
135c8c05a8eSCatherine Zhang 	 * Does the subject have permission to set security context?
136d28d1e08STrent Jaeger 	 */
137d28d1e08STrent Jaeger 	rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
138d28d1e08STrent Jaeger 			  SECCLASS_ASSOCIATION,
1395f8ac64bSTrent Jaeger 			  ASSOCIATION__SETCONTEXT, NULL);
140d28d1e08STrent Jaeger 	if (rc)
141d28d1e08STrent Jaeger 		goto out;
142d28d1e08STrent Jaeger 
143d28d1e08STrent Jaeger 	return rc;
144d28d1e08STrent Jaeger 
145d28d1e08STrent Jaeger out:
146ee2e6841SLuiz Capitulino 	*ctxp = NULL;
147d28d1e08STrent Jaeger 	kfree(ctx);
148d28d1e08STrent Jaeger 	return rc;
149d28d1e08STrent Jaeger }
150d28d1e08STrent Jaeger 
151d28d1e08STrent Jaeger /*
152d28d1e08STrent Jaeger  * LSM hook implementation that allocs and transfers uctx spec to
153d28d1e08STrent Jaeger  * xfrm_policy.
154d28d1e08STrent Jaeger  */
155d28d1e08STrent Jaeger int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *uctx)
156d28d1e08STrent Jaeger {
157d28d1e08STrent Jaeger 	int err;
158d28d1e08STrent Jaeger 
159d28d1e08STrent Jaeger 	BUG_ON(!xp);
160d28d1e08STrent Jaeger 
161d28d1e08STrent Jaeger 	err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx);
162d28d1e08STrent Jaeger 	return err;
163d28d1e08STrent Jaeger }
164d28d1e08STrent Jaeger 
165d28d1e08STrent Jaeger 
166d28d1e08STrent Jaeger /*
167d28d1e08STrent Jaeger  * LSM hook implementation that copies security data structure from old to
168d28d1e08STrent Jaeger  * new for policy cloning.
169d28d1e08STrent Jaeger  */
170d28d1e08STrent Jaeger int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new)
171d28d1e08STrent Jaeger {
172d28d1e08STrent Jaeger 	struct xfrm_sec_ctx *old_ctx, *new_ctx;
173d28d1e08STrent Jaeger 
174d28d1e08STrent Jaeger 	old_ctx = old->security;
175d28d1e08STrent Jaeger 
176d28d1e08STrent Jaeger 	if (old_ctx) {
177d28d1e08STrent Jaeger 		new_ctx = new->security = kmalloc(sizeof(*new_ctx) +
178d28d1e08STrent Jaeger 						  old_ctx->ctx_len,
179d28d1e08STrent Jaeger 						  GFP_KERNEL);
180d28d1e08STrent Jaeger 
181d28d1e08STrent Jaeger 		if (!new_ctx)
182d28d1e08STrent Jaeger 			return -ENOMEM;
183d28d1e08STrent Jaeger 
184d28d1e08STrent Jaeger 		memcpy(new_ctx, old_ctx, sizeof(*new_ctx));
185d28d1e08STrent Jaeger 		memcpy(new_ctx->ctx_str, old_ctx->ctx_str, new_ctx->ctx_len);
186d28d1e08STrent Jaeger 	}
187d28d1e08STrent Jaeger 	return 0;
188d28d1e08STrent Jaeger }
189d28d1e08STrent Jaeger 
190d28d1e08STrent Jaeger /*
191d28d1e08STrent Jaeger  * LSM hook implementation that frees xfrm_policy security information.
192d28d1e08STrent Jaeger  */
193d28d1e08STrent Jaeger void selinux_xfrm_policy_free(struct xfrm_policy *xp)
194d28d1e08STrent Jaeger {
195d28d1e08STrent Jaeger 	struct xfrm_sec_ctx *ctx = xp->security;
196d28d1e08STrent Jaeger 	if (ctx)
197d28d1e08STrent Jaeger 		kfree(ctx);
198d28d1e08STrent Jaeger }
199d28d1e08STrent Jaeger 
200d28d1e08STrent Jaeger /*
201c8c05a8eSCatherine Zhang  * LSM hook implementation that authorizes deletion of labeled policies.
202c8c05a8eSCatherine Zhang  */
203c8c05a8eSCatherine Zhang int selinux_xfrm_policy_delete(struct xfrm_policy *xp)
204c8c05a8eSCatherine Zhang {
205c8c05a8eSCatherine Zhang 	struct task_security_struct *tsec = current->security;
206c8c05a8eSCatherine Zhang 	struct xfrm_sec_ctx *ctx = xp->security;
207c8c05a8eSCatherine Zhang 	int rc = 0;
208c8c05a8eSCatherine Zhang 
209c8c05a8eSCatherine Zhang 	if (ctx)
210c8c05a8eSCatherine Zhang 		rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
211c8c05a8eSCatherine Zhang 				  SECCLASS_ASSOCIATION,
212c8c05a8eSCatherine Zhang 				  ASSOCIATION__SETCONTEXT, NULL);
213c8c05a8eSCatherine Zhang 
214c8c05a8eSCatherine Zhang 	return rc;
215c8c05a8eSCatherine Zhang }
216c8c05a8eSCatherine Zhang 
217c8c05a8eSCatherine Zhang /*
218d28d1e08STrent Jaeger  * LSM hook implementation that allocs and transfers sec_ctx spec to
219d28d1e08STrent Jaeger  * xfrm_state.
220d28d1e08STrent Jaeger  */
221d28d1e08STrent Jaeger int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx)
222d28d1e08STrent Jaeger {
223d28d1e08STrent Jaeger 	int err;
224d28d1e08STrent Jaeger 
225d28d1e08STrent Jaeger 	BUG_ON(!x);
226d28d1e08STrent Jaeger 
227d28d1e08STrent Jaeger 	err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx);
228d28d1e08STrent Jaeger 	return err;
229d28d1e08STrent Jaeger }
230d28d1e08STrent Jaeger 
231d28d1e08STrent Jaeger /*
232d28d1e08STrent Jaeger  * LSM hook implementation that frees xfrm_state security information.
233d28d1e08STrent Jaeger  */
234d28d1e08STrent Jaeger void selinux_xfrm_state_free(struct xfrm_state *x)
235d28d1e08STrent Jaeger {
236d28d1e08STrent Jaeger 	struct xfrm_sec_ctx *ctx = x->security;
237d28d1e08STrent Jaeger 	if (ctx)
238d28d1e08STrent Jaeger 		kfree(ctx);
239d28d1e08STrent Jaeger }
240d28d1e08STrent Jaeger 
241d28d1e08STrent Jaeger /*
2422c7946a7SCatherine Zhang  * SELinux internal function to retrieve the context of a connected
2432c7946a7SCatherine Zhang  * (sk->sk_state == TCP_ESTABLISHED) TCP socket based on its security
2442c7946a7SCatherine Zhang  * association used to connect to the remote socket.
2452c7946a7SCatherine Zhang  *
2462c7946a7SCatherine Zhang  * Retrieve via getsockopt SO_PEERSEC.
2472c7946a7SCatherine Zhang  */
2482c7946a7SCatherine Zhang u32 selinux_socket_getpeer_stream(struct sock *sk)
2492c7946a7SCatherine Zhang {
2502c7946a7SCatherine Zhang 	struct dst_entry *dst, *dst_test;
2512c7946a7SCatherine Zhang 	u32 peer_sid = SECSID_NULL;
2522c7946a7SCatherine Zhang 
2532c7946a7SCatherine Zhang 	if (sk->sk_state != TCP_ESTABLISHED)
2542c7946a7SCatherine Zhang 		goto out;
2552c7946a7SCatherine Zhang 
2562c7946a7SCatherine Zhang 	dst = sk_dst_get(sk);
2572c7946a7SCatherine Zhang 	if (!dst)
2582c7946a7SCatherine Zhang 		goto out;
2592c7946a7SCatherine Zhang 
2602c7946a7SCatherine Zhang  	for (dst_test = dst; dst_test != 0;
2612c7946a7SCatherine Zhang       	     dst_test = dst_test->child) {
2622c7946a7SCatherine Zhang 		struct xfrm_state *x = dst_test->xfrm;
2632c7946a7SCatherine Zhang 
2642c7946a7SCatherine Zhang  		if (x && selinux_authorizable_xfrm(x)) {
2652c7946a7SCatherine Zhang 	 	 	struct xfrm_sec_ctx *ctx = x->security;
2662c7946a7SCatherine Zhang 			peer_sid = ctx->ctx_sid;
2672c7946a7SCatherine Zhang 			break;
2682c7946a7SCatherine Zhang 		}
2692c7946a7SCatherine Zhang 	}
2702c7946a7SCatherine Zhang 	dst_release(dst);
2712c7946a7SCatherine Zhang 
2722c7946a7SCatherine Zhang out:
2732c7946a7SCatherine Zhang 	return peer_sid;
2742c7946a7SCatherine Zhang }
2752c7946a7SCatherine Zhang 
2762c7946a7SCatherine Zhang /*
2772c7946a7SCatherine Zhang  * SELinux internal function to retrieve the context of a UDP packet
2782c7946a7SCatherine Zhang  * based on its security association used to connect to the remote socket.
2792c7946a7SCatherine Zhang  *
2802c7946a7SCatherine Zhang  * Retrieve via setsockopt IP_PASSSEC and recvmsg with control message
2812c7946a7SCatherine Zhang  * type SCM_SECURITY.
2822c7946a7SCatherine Zhang  */
2832c7946a7SCatherine Zhang u32 selinux_socket_getpeer_dgram(struct sk_buff *skb)
2842c7946a7SCatherine Zhang {
2852c7946a7SCatherine Zhang 	struct sec_path *sp;
2862c7946a7SCatherine Zhang 
2872c7946a7SCatherine Zhang 	if (skb == NULL)
2882c7946a7SCatherine Zhang 		return SECSID_NULL;
2892c7946a7SCatherine Zhang 
2902c7946a7SCatherine Zhang 	if (skb->sk->sk_protocol != IPPROTO_UDP)
2912c7946a7SCatherine Zhang 		return SECSID_NULL;
2922c7946a7SCatherine Zhang 
2932c7946a7SCatherine Zhang 	sp = skb->sp;
2942c7946a7SCatherine Zhang 	if (sp) {
2952c7946a7SCatherine Zhang 		int i;
2962c7946a7SCatherine Zhang 
2972c7946a7SCatherine Zhang 		for (i = sp->len-1; i >= 0; i--) {
29867644726SDave Jones 			struct xfrm_state *x = sp->xvec[i];
2992c7946a7SCatherine Zhang 			if (selinux_authorizable_xfrm(x)) {
3002c7946a7SCatherine Zhang 				struct xfrm_sec_ctx *ctx = x->security;
3012c7946a7SCatherine Zhang 				return ctx->ctx_sid;
3022c7946a7SCatherine Zhang 			}
3032c7946a7SCatherine Zhang 		}
3042c7946a7SCatherine Zhang 	}
3052c7946a7SCatherine Zhang 
3062c7946a7SCatherine Zhang 	return SECSID_NULL;
3072c7946a7SCatherine Zhang }
3082c7946a7SCatherine Zhang 
3092c7946a7SCatherine Zhang  /*
310c8c05a8eSCatherine Zhang   * LSM hook implementation that authorizes deletion of labeled SAs.
311c8c05a8eSCatherine Zhang   */
312c8c05a8eSCatherine Zhang int selinux_xfrm_state_delete(struct xfrm_state *x)
313c8c05a8eSCatherine Zhang {
314c8c05a8eSCatherine Zhang 	struct task_security_struct *tsec = current->security;
315c8c05a8eSCatherine Zhang 	struct xfrm_sec_ctx *ctx = x->security;
316c8c05a8eSCatherine Zhang 	int rc = 0;
317c8c05a8eSCatherine Zhang 
318c8c05a8eSCatherine Zhang 	if (ctx)
319c8c05a8eSCatherine Zhang 		rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
320c8c05a8eSCatherine Zhang 				  SECCLASS_ASSOCIATION,
321c8c05a8eSCatherine Zhang 				  ASSOCIATION__SETCONTEXT, NULL);
322c8c05a8eSCatherine Zhang 
323c8c05a8eSCatherine Zhang 	return rc;
324c8c05a8eSCatherine Zhang }
325c8c05a8eSCatherine Zhang 
326c8c05a8eSCatherine Zhang /*
327d28d1e08STrent Jaeger  * LSM hook that controls access to unlabelled packets.  If
328d28d1e08STrent Jaeger  * a xfrm_state is authorizable (defined by macro) then it was
329d28d1e08STrent Jaeger  * already authorized by the IPSec process.  If not, then
330d28d1e08STrent Jaeger  * we need to check for unlabelled access since this may not have
331d28d1e08STrent Jaeger  * gone thru the IPSec process.
332d28d1e08STrent Jaeger  */
333d28d1e08STrent Jaeger int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb)
334d28d1e08STrent Jaeger {
335d28d1e08STrent Jaeger 	int i, rc = 0;
336d28d1e08STrent Jaeger 	struct sec_path *sp;
337d28d1e08STrent Jaeger 
338d28d1e08STrent Jaeger 	sp = skb->sp;
339d28d1e08STrent Jaeger 
340d28d1e08STrent Jaeger 	if (sp) {
341d28d1e08STrent Jaeger 		/*
342d28d1e08STrent Jaeger 		 * __xfrm_policy_check does not approve unless xfrm_policy_ok
343d28d1e08STrent Jaeger 		 * says that spi's match for policy and the socket.
344d28d1e08STrent Jaeger 		 *
345d28d1e08STrent Jaeger 		 *  Only need to verify the existence of an authorizable sp.
346d28d1e08STrent Jaeger 		 */
347d28d1e08STrent Jaeger 		for (i = 0; i < sp->len; i++) {
34867644726SDave Jones 			struct xfrm_state *x = sp->xvec[i];
349d28d1e08STrent Jaeger 
350d28d1e08STrent Jaeger 			if (x && selinux_authorizable_xfrm(x))
351d28d1e08STrent Jaeger 				goto accept;
352d28d1e08STrent Jaeger 		}
353d28d1e08STrent Jaeger 	}
354d28d1e08STrent Jaeger 
355d28d1e08STrent Jaeger 	/* check SELinux sock for unlabelled access */
356d28d1e08STrent Jaeger 	rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION,
357d28d1e08STrent Jaeger 			  ASSOCIATION__RECVFROM, NULL);
358d28d1e08STrent Jaeger 	if (rc)
359d28d1e08STrent Jaeger 		goto drop;
360d28d1e08STrent Jaeger 
361d28d1e08STrent Jaeger accept:
362d28d1e08STrent Jaeger 	return 0;
363d28d1e08STrent Jaeger 
364d28d1e08STrent Jaeger drop:
365d28d1e08STrent Jaeger 	return rc;
366d28d1e08STrent Jaeger }
367d28d1e08STrent Jaeger 
368d28d1e08STrent Jaeger /*
369d28d1e08STrent Jaeger  * POSTROUTE_LAST hook's XFRM processing:
370d28d1e08STrent Jaeger  * If we have no security association, then we need to determine
371d28d1e08STrent Jaeger  * whether the socket is allowed to send to an unlabelled destination.
372d28d1e08STrent Jaeger  * If we do have a authorizable security association, then it has already been
373d28d1e08STrent Jaeger  * checked in xfrm_policy_lookup hook.
374d28d1e08STrent Jaeger  */
375d28d1e08STrent Jaeger int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb)
376d28d1e08STrent Jaeger {
377d28d1e08STrent Jaeger 	struct dst_entry *dst;
378d28d1e08STrent Jaeger 	int rc = 0;
379d28d1e08STrent Jaeger 
380d28d1e08STrent Jaeger 	dst = skb->dst;
381d28d1e08STrent Jaeger 
382d28d1e08STrent Jaeger 	if (dst) {
383d28d1e08STrent Jaeger 		struct dst_entry *dst_test;
384d28d1e08STrent Jaeger 
385d28d1e08STrent Jaeger 		for (dst_test = dst; dst_test != 0;
386d28d1e08STrent Jaeger 		     dst_test = dst_test->child) {
387d28d1e08STrent Jaeger 			struct xfrm_state *x = dst_test->xfrm;
388d28d1e08STrent Jaeger 
389d28d1e08STrent Jaeger 			if (x && selinux_authorizable_xfrm(x))
3904e5ab4cbSJames Morris 				goto out;
391d28d1e08STrent Jaeger 		}
392d28d1e08STrent Jaeger 	}
393d28d1e08STrent Jaeger 
394d28d1e08STrent Jaeger 	rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION,
395d28d1e08STrent Jaeger 			  ASSOCIATION__SENDTO, NULL);
3964e5ab4cbSJames Morris out:
3974e5ab4cbSJames Morris 	return rc;
398d28d1e08STrent Jaeger }
399