aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/xfrm.c
diff options
context:
space:
mode:
authorVenkat Yekkirala <vyekkirala@TrustedCS.com>2006-07-25 02:29:07 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-22 17:53:24 -0400
commite0d1caa7b0d5f02e4f34aa09c695d04251310c6c (patch)
treebf023c17abf6813f2694ebf5fafff82edd6a1023 /security/selinux/xfrm.c
parentb6340fcd761acf9249b3acbc95c4dc555d9beb07 (diff)
[MLSXFRM]: Flow based matching of xfrm policy and state
This implements a seemless mechanism for xfrm policy selection and state matching based on the flow sid. This also includes the necessary SELinux enforcement pieces. Signed-off-by: Venkat Yekkirala <vyekkirala@TrustedCS.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'security/selinux/xfrm.c')
-rw-r--r--security/selinux/xfrm.c199
1 files changed, 166 insertions, 33 deletions
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index 6c985ced8102..a502b0540e3d 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -6,7 +6,12 @@
6 * Authors: Serge Hallyn <sergeh@us.ibm.com> 6 * Authors: Serge Hallyn <sergeh@us.ibm.com>
7 * Trent Jaeger <jaegert@us.ibm.com> 7 * Trent Jaeger <jaegert@us.ibm.com>
8 * 8 *
9 * Updated: Venkat Yekkirala <vyekkirala@TrustedCS.com>
10 *
11 * Granular IPSec Associations for use in MLS environments.
12 *
9 * Copyright (C) 2005 International Business Machines Corporation 13 * Copyright (C) 2005 International Business Machines Corporation
14 * Copyright (C) 2006 Trusted Computer Solutions, Inc.
10 * 15 *
11 * This program is free software; you can redistribute it and/or modify 16 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2, 17 * it under the terms of the GNU General Public License version 2,
@@ -67,10 +72,10 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x)
67} 72}
68 73
69/* 74/*
70 * LSM hook implementation that authorizes that a socket can be used 75 * LSM hook implementation that authorizes that a flow can use
71 * with the corresponding xfrm_sec_ctx and direction. 76 * a xfrm policy rule.
72 */ 77 */
73int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir) 78int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir)
74{ 79{
75 int rc = 0; 80 int rc = 0;
76 u32 sel_sid = SECINITSID_UNLABELED; 81 u32 sel_sid = SECINITSID_UNLABELED;
@@ -84,27 +89,129 @@ int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir)
84 sel_sid = ctx->ctx_sid; 89 sel_sid = ctx->ctx_sid;
85 } 90 }
86 91
87 rc = avc_has_perm(sk_sid, sel_sid, SECCLASS_ASSOCIATION, 92 rc = avc_has_perm(fl_secid, sel_sid, SECCLASS_ASSOCIATION,
88 ((dir == FLOW_DIR_IN) ? ASSOCIATION__RECVFROM : 93 ASSOCIATION__POLMATCH,
89 ((dir == FLOW_DIR_OUT) ? ASSOCIATION__SENDTO :
90 (ASSOCIATION__SENDTO | ASSOCIATION__RECVFROM))),
91 NULL); 94 NULL);
92 95
93 return rc; 96 return rc;
94} 97}
95 98
96/* 99/*
100 * LSM hook implementation that authorizes that a state matches
101 * the given policy, flow combo.
102 */
103
104int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp,
105 struct flowi *fl)
106{
107 u32 state_sid;
108 u32 pol_sid;
109 int err;
110
111 if (x->security)
112 state_sid = x->security->ctx_sid;
113 else
114 state_sid = SECINITSID_UNLABELED;
115
116 if (xp->security)
117 pol_sid = xp->security->ctx_sid;
118 else
119 pol_sid = SECINITSID_UNLABELED;
120
121 err = avc_has_perm(state_sid, pol_sid, SECCLASS_ASSOCIATION,
122 ASSOCIATION__POLMATCH,
123 NULL);
124
125 if (err)
126 return 0;
127
128 return selinux_xfrm_flow_state_match(fl, x);
129}
130
131/*
132 * LSM hook implementation that authorizes that a particular outgoing flow
133 * can use a given security association.
134 */
135
136int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm)
137{
138 int rc = 0;
139 u32 sel_sid = SECINITSID_UNLABELED;
140 struct xfrm_sec_ctx *ctx;
141
142 /* Context sid is either set to label or ANY_ASSOC */
143 if ((ctx = xfrm->security)) {
144 if (!selinux_authorizable_ctx(ctx))
145 return 0;
146
147 sel_sid = ctx->ctx_sid;
148 }
149
150 rc = avc_has_perm(fl->secid, sel_sid, SECCLASS_ASSOCIATION,
151 ASSOCIATION__SENDTO,
152 NULL)? 0:1;
153
154 return rc;
155}
156
157/*
158 * LSM hook implementation that determines the sid for the session.
159 */
160
161int selinux_xfrm_decode_session(struct sk_buff *skb, struct flowi *fl)
162{
163 struct sec_path *sp;
164
165 fl->secid = SECSID_NULL;
166
167 if (skb == NULL)
168 return 0;
169
170 sp = skb->sp;
171 if (sp) {
172 int i, sid_set = 0;
173
174 for (i = sp->len-1; i >= 0; i--) {
175 struct xfrm_state *x = sp->xvec[i];
176 if (selinux_authorizable_xfrm(x)) {
177 struct xfrm_sec_ctx *ctx = x->security;
178
179 if (!sid_set) {
180 fl->secid = ctx->ctx_sid;
181 sid_set = 1;
182 }
183 else if (fl->secid != ctx->ctx_sid)
184 return -EINVAL;
185 }
186 }
187 }
188
189 return 0;
190}
191
192/*
97 * Security blob allocation for xfrm_policy and xfrm_state 193 * Security blob allocation for xfrm_policy and xfrm_state
98 * CTX does not have a meaningful value on input 194 * CTX does not have a meaningful value on input
99 */ 195 */
100static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *uctx) 196static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp,
197 struct xfrm_user_sec_ctx *uctx, struct xfrm_sec_ctx *pol, u32 sid)
101{ 198{
102 int rc = 0; 199 int rc = 0;
103 struct task_security_struct *tsec = current->security; 200 struct task_security_struct *tsec = current->security;
104 struct xfrm_sec_ctx *ctx; 201 struct xfrm_sec_ctx *ctx = NULL;
202 char *ctx_str = NULL;
203 u32 str_len;
204 u32 ctx_sid;
205
206 BUG_ON(uctx && pol);
207
208 if (pol)
209 goto from_policy;
105 210
106 BUG_ON(!uctx); 211 BUG_ON(!uctx);
107 BUG_ON(uctx->ctx_doi != XFRM_SC_ALG_SELINUX); 212
213 if (uctx->ctx_doi != XFRM_SC_ALG_SELINUX)
214 return -EINVAL;
108 215
109 if (uctx->ctx_len >= PAGE_SIZE) 216 if (uctx->ctx_len >= PAGE_SIZE)
110 return -ENOMEM; 217 return -ENOMEM;
@@ -141,9 +248,41 @@ static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_us
141 248
142 return rc; 249 return rc;
143 250
251from_policy:
252 BUG_ON(!pol);
253 rc = security_sid_mls_copy(pol->ctx_sid, sid, &ctx_sid);
254 if (rc)
255 goto out;
256
257 rc = security_sid_to_context(ctx_sid, &ctx_str, &str_len);
258 if (rc)
259 goto out;
260
261 *ctxp = ctx = kmalloc(sizeof(*ctx) +
262 str_len,
263 GFP_ATOMIC);
264
265 if (!ctx) {
266 rc = -ENOMEM;
267 goto out;
268 }
269
270
271 ctx->ctx_doi = XFRM_SC_DOI_LSM;
272 ctx->ctx_alg = XFRM_SC_ALG_SELINUX;
273 ctx->ctx_sid = ctx_sid;
274 ctx->ctx_len = str_len;
275 memcpy(ctx->ctx_str,
276 ctx_str,
277 str_len);
278
279 goto out2;
280
144out: 281out:
145 *ctxp = NULL; 282 *ctxp = NULL;
146 kfree(ctx); 283 kfree(ctx);
284out2:
285 kfree(ctx_str);
147 return rc; 286 return rc;
148} 287}
149 288
@@ -157,7 +296,7 @@ int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *
157 296
158 BUG_ON(!xp); 297 BUG_ON(!xp);
159 298
160 err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx); 299 err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, NULL, 0);
161 return err; 300 return err;
162} 301}
163 302
@@ -217,13 +356,14 @@ int selinux_xfrm_policy_delete(struct xfrm_policy *xp)
217 * LSM hook implementation that allocs and transfers sec_ctx spec to 356 * LSM hook implementation that allocs and transfers sec_ctx spec to
218 * xfrm_state. 357 * xfrm_state.
219 */ 358 */
220int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx) 359int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx,
360 struct xfrm_sec_ctx *pol, u32 secid)
221{ 361{
222 int err; 362 int err;
223 363
224 BUG_ON(!x); 364 BUG_ON(!x);
225 365
226 err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx); 366 err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, pol, secid);
227 return err; 367 return err;
228} 368}
229 369
@@ -329,38 +469,30 @@ int selinux_xfrm_state_delete(struct xfrm_state *x)
329 * we need to check for unlabelled access since this may not have 469 * we need to check for unlabelled access since this may not have
330 * gone thru the IPSec process. 470 * gone thru the IPSec process.
331 */ 471 */
332int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb) 472int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb,
473 struct avc_audit_data *ad)
333{ 474{
334 int i, rc = 0; 475 int i, rc = 0;
335 struct sec_path *sp; 476 struct sec_path *sp;
477 u32 sel_sid = SECINITSID_UNLABELED;
336 478
337 sp = skb->sp; 479 sp = skb->sp;
338 480
339 if (sp) { 481 if (sp) {
340 /*
341 * __xfrm_policy_check does not approve unless xfrm_policy_ok
342 * says that spi's match for policy and the socket.
343 *
344 * Only need to verify the existence of an authorizable sp.
345 */
346 for (i = 0; i < sp->len; i++) { 482 for (i = 0; i < sp->len; i++) {
347 struct xfrm_state *x = sp->xvec[i]; 483 struct xfrm_state *x = sp->xvec[i];
348 484
349 if (x && selinux_authorizable_xfrm(x)) 485 if (x && selinux_authorizable_xfrm(x)) {
350 goto accept; 486 struct xfrm_sec_ctx *ctx = x->security;
487 sel_sid = ctx->ctx_sid;
488 break;
489 }
351 } 490 }
352 } 491 }
353 492
354 /* check SELinux sock for unlabelled access */ 493 rc = avc_has_perm(isec_sid, sel_sid, SECCLASS_ASSOCIATION,
355 rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION, 494 ASSOCIATION__RECVFROM, ad);
356 ASSOCIATION__RECVFROM, NULL);
357 if (rc)
358 goto drop;
359
360accept:
361 return 0;
362 495
363drop:
364 return rc; 496 return rc;
365} 497}
366 498
@@ -371,7 +503,8 @@ drop:
371 * If we do have a authorizable security association, then it has already been 503 * If we do have a authorizable security association, then it has already been
372 * checked in xfrm_policy_lookup hook. 504 * checked in xfrm_policy_lookup hook.
373 */ 505 */
374int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb) 506int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
507 struct avc_audit_data *ad)
375{ 508{
376 struct dst_entry *dst; 509 struct dst_entry *dst;
377 int rc = 0; 510 int rc = 0;
@@ -391,7 +524,7 @@ int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb)
391 } 524 }
392 525
393 rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION, 526 rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION,
394 ASSOCIATION__SENDTO, NULL); 527 ASSOCIATION__SENDTO, ad);
395out: 528out:
396 return rc; 529 return rc;
397} 530}