xref: /openbmc/linux/security/selinux/xfrm.c (revision ee2e6841)
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 	/*
135d28d1e08STrent Jaeger 	 * Does the subject have permission to set security or permission to
136d28d1e08STrent Jaeger 	 * do the relabel?
137d28d1e08STrent Jaeger 	 * Must be permitted to relabel from default socket type (process type)
138d28d1e08STrent Jaeger 	 * to specified context
139d28d1e08STrent Jaeger 	 */
140d28d1e08STrent Jaeger 	rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
141d28d1e08STrent Jaeger 			  SECCLASS_ASSOCIATION,
1425f8ac64bSTrent Jaeger 			  ASSOCIATION__SETCONTEXT, NULL);
143d28d1e08STrent Jaeger 	if (rc)
144d28d1e08STrent Jaeger 		goto out;
145d28d1e08STrent Jaeger 
146d28d1e08STrent Jaeger 	return rc;
147d28d1e08STrent Jaeger 
148d28d1e08STrent Jaeger out:
149ee2e6841SLuiz Capitulino 	*ctxp = NULL;
150d28d1e08STrent Jaeger 	kfree(ctx);
151d28d1e08STrent Jaeger 	return rc;
152d28d1e08STrent Jaeger }
153d28d1e08STrent Jaeger 
154d28d1e08STrent Jaeger /*
155d28d1e08STrent Jaeger  * LSM hook implementation that allocs and transfers uctx spec to
156d28d1e08STrent Jaeger  * xfrm_policy.
157d28d1e08STrent Jaeger  */
158d28d1e08STrent Jaeger int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *uctx)
159d28d1e08STrent Jaeger {
160d28d1e08STrent Jaeger 	int err;
161d28d1e08STrent Jaeger 
162d28d1e08STrent Jaeger 	BUG_ON(!xp);
163d28d1e08STrent Jaeger 
164d28d1e08STrent Jaeger 	err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx);
165d28d1e08STrent Jaeger 	return err;
166d28d1e08STrent Jaeger }
167d28d1e08STrent Jaeger 
168d28d1e08STrent Jaeger 
169d28d1e08STrent Jaeger /*
170d28d1e08STrent Jaeger  * LSM hook implementation that copies security data structure from old to
171d28d1e08STrent Jaeger  * new for policy cloning.
172d28d1e08STrent Jaeger  */
173d28d1e08STrent Jaeger int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new)
174d28d1e08STrent Jaeger {
175d28d1e08STrent Jaeger 	struct xfrm_sec_ctx *old_ctx, *new_ctx;
176d28d1e08STrent Jaeger 
177d28d1e08STrent Jaeger 	old_ctx = old->security;
178d28d1e08STrent Jaeger 
179d28d1e08STrent Jaeger 	if (old_ctx) {
180d28d1e08STrent Jaeger 		new_ctx = new->security = kmalloc(sizeof(*new_ctx) +
181d28d1e08STrent Jaeger 						  old_ctx->ctx_len,
182d28d1e08STrent Jaeger 						  GFP_KERNEL);
183d28d1e08STrent Jaeger 
184d28d1e08STrent Jaeger 		if (!new_ctx)
185d28d1e08STrent Jaeger 			return -ENOMEM;
186d28d1e08STrent Jaeger 
187d28d1e08STrent Jaeger 		memcpy(new_ctx, old_ctx, sizeof(*new_ctx));
188d28d1e08STrent Jaeger 		memcpy(new_ctx->ctx_str, old_ctx->ctx_str, new_ctx->ctx_len);
189d28d1e08STrent Jaeger 	}
190d28d1e08STrent Jaeger 	return 0;
191d28d1e08STrent Jaeger }
192d28d1e08STrent Jaeger 
193d28d1e08STrent Jaeger /*
194d28d1e08STrent Jaeger  * LSM hook implementation that frees xfrm_policy security information.
195d28d1e08STrent Jaeger  */
196d28d1e08STrent Jaeger void selinux_xfrm_policy_free(struct xfrm_policy *xp)
197d28d1e08STrent Jaeger {
198d28d1e08STrent Jaeger 	struct xfrm_sec_ctx *ctx = xp->security;
199d28d1e08STrent Jaeger 	if (ctx)
200d28d1e08STrent Jaeger 		kfree(ctx);
201d28d1e08STrent Jaeger }
202d28d1e08STrent Jaeger 
203d28d1e08STrent Jaeger /*
204d28d1e08STrent Jaeger  * LSM hook implementation that allocs and transfers sec_ctx spec to
205d28d1e08STrent Jaeger  * xfrm_state.
206d28d1e08STrent Jaeger  */
207d28d1e08STrent Jaeger int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx)
208d28d1e08STrent Jaeger {
209d28d1e08STrent Jaeger 	int err;
210d28d1e08STrent Jaeger 
211d28d1e08STrent Jaeger 	BUG_ON(!x);
212d28d1e08STrent Jaeger 
213d28d1e08STrent Jaeger 	err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx);
214d28d1e08STrent Jaeger 	return err;
215d28d1e08STrent Jaeger }
216d28d1e08STrent Jaeger 
217d28d1e08STrent Jaeger /*
218d28d1e08STrent Jaeger  * LSM hook implementation that frees xfrm_state security information.
219d28d1e08STrent Jaeger  */
220d28d1e08STrent Jaeger void selinux_xfrm_state_free(struct xfrm_state *x)
221d28d1e08STrent Jaeger {
222d28d1e08STrent Jaeger 	struct xfrm_sec_ctx *ctx = x->security;
223d28d1e08STrent Jaeger 	if (ctx)
224d28d1e08STrent Jaeger 		kfree(ctx);
225d28d1e08STrent Jaeger }
226d28d1e08STrent Jaeger 
227d28d1e08STrent Jaeger /*
228d28d1e08STrent Jaeger  * LSM hook that controls access to unlabelled packets.  If
229d28d1e08STrent Jaeger  * a xfrm_state is authorizable (defined by macro) then it was
230d28d1e08STrent Jaeger  * already authorized by the IPSec process.  If not, then
231d28d1e08STrent Jaeger  * we need to check for unlabelled access since this may not have
232d28d1e08STrent Jaeger  * gone thru the IPSec process.
233d28d1e08STrent Jaeger  */
234d28d1e08STrent Jaeger int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb)
235d28d1e08STrent Jaeger {
236d28d1e08STrent Jaeger 	int i, rc = 0;
237d28d1e08STrent Jaeger 	struct sec_path *sp;
238d28d1e08STrent Jaeger 
239d28d1e08STrent Jaeger 	sp = skb->sp;
240d28d1e08STrent Jaeger 
241d28d1e08STrent Jaeger 	if (sp) {
242d28d1e08STrent Jaeger 		/*
243d28d1e08STrent Jaeger 		 * __xfrm_policy_check does not approve unless xfrm_policy_ok
244d28d1e08STrent Jaeger 		 * says that spi's match for policy and the socket.
245d28d1e08STrent Jaeger 		 *
246d28d1e08STrent Jaeger 		 *  Only need to verify the existence of an authorizable sp.
247d28d1e08STrent Jaeger 		 */
248d28d1e08STrent Jaeger 		for (i = 0; i < sp->len; i++) {
249d28d1e08STrent Jaeger 			struct xfrm_state *x = sp->x[i].xvec;
250d28d1e08STrent Jaeger 
251d28d1e08STrent Jaeger 			if (x && selinux_authorizable_xfrm(x))
252d28d1e08STrent Jaeger 				goto accept;
253d28d1e08STrent Jaeger 		}
254d28d1e08STrent Jaeger 	}
255d28d1e08STrent Jaeger 
256d28d1e08STrent Jaeger 	/* check SELinux sock for unlabelled access */
257d28d1e08STrent Jaeger 	rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION,
258d28d1e08STrent Jaeger 			  ASSOCIATION__RECVFROM, NULL);
259d28d1e08STrent Jaeger 	if (rc)
260d28d1e08STrent Jaeger 		goto drop;
261d28d1e08STrent Jaeger 
262d28d1e08STrent Jaeger accept:
263d28d1e08STrent Jaeger 	return 0;
264d28d1e08STrent Jaeger 
265d28d1e08STrent Jaeger drop:
266d28d1e08STrent Jaeger 	return rc;
267d28d1e08STrent Jaeger }
268d28d1e08STrent Jaeger 
269d28d1e08STrent Jaeger /*
270d28d1e08STrent Jaeger  * POSTROUTE_LAST hook's XFRM processing:
271d28d1e08STrent Jaeger  * If we have no security association, then we need to determine
272d28d1e08STrent Jaeger  * whether the socket is allowed to send to an unlabelled destination.
273d28d1e08STrent Jaeger  * If we do have a authorizable security association, then it has already been
274d28d1e08STrent Jaeger  * checked in xfrm_policy_lookup hook.
275d28d1e08STrent Jaeger  */
276d28d1e08STrent Jaeger int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb)
277d28d1e08STrent Jaeger {
278d28d1e08STrent Jaeger 	struct dst_entry *dst;
279d28d1e08STrent Jaeger 	int rc = 0;
280d28d1e08STrent Jaeger 
281d28d1e08STrent Jaeger 	dst = skb->dst;
282d28d1e08STrent Jaeger 
283d28d1e08STrent Jaeger 	if (dst) {
284d28d1e08STrent Jaeger 		struct dst_entry *dst_test;
285d28d1e08STrent Jaeger 
286d28d1e08STrent Jaeger 		for (dst_test = dst; dst_test != 0;
287d28d1e08STrent Jaeger 		     dst_test = dst_test->child) {
288d28d1e08STrent Jaeger 			struct xfrm_state *x = dst_test->xfrm;
289d28d1e08STrent Jaeger 
290d28d1e08STrent Jaeger 			if (x && selinux_authorizable_xfrm(x))
291d28d1e08STrent Jaeger 				goto accept;
292d28d1e08STrent Jaeger 		}
293d28d1e08STrent Jaeger 	}
294d28d1e08STrent Jaeger 
295d28d1e08STrent Jaeger 	rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION,
296d28d1e08STrent Jaeger 			  ASSOCIATION__SENDTO, NULL);
297d28d1e08STrent Jaeger 	if (rc)
298d28d1e08STrent Jaeger 		goto drop;
299d28d1e08STrent Jaeger 
300d28d1e08STrent Jaeger accept:
301d28d1e08STrent Jaeger 	return NF_ACCEPT;
302d28d1e08STrent Jaeger 
303d28d1e08STrent Jaeger drop:
304d28d1e08STrent Jaeger 	return NF_DROP;
305d28d1e08STrent Jaeger }
306