aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/xfrm.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux/xfrm.c')
-rw-r--r--security/selinux/xfrm.c216
1 files changed, 181 insertions, 35 deletions
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index 6c985ced8102..3e742b850af6 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,130 @@ 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, u32 *sid, int ckall)
162{
163 struct sec_path *sp;
164
165 *sid = 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 *sid = ctx->ctx_sid;
181 sid_set = 1;
182
183 if (!ckall)
184 break;
185 }
186 else if (*sid != ctx->ctx_sid)
187 return -EINVAL;
188 }
189 }
190 }
191
192 return 0;
193}
194
195/*
97 * Security blob allocation for xfrm_policy and xfrm_state 196 * Security blob allocation for xfrm_policy and xfrm_state
98 * CTX does not have a meaningful value on input 197 * CTX does not have a meaningful value on input
99 */ 198 */
100static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *uctx) 199static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp,
200 struct xfrm_user_sec_ctx *uctx, struct xfrm_sec_ctx *pol, u32 sid)
101{ 201{
102 int rc = 0; 202 int rc = 0;
103 struct task_security_struct *tsec = current->security; 203 struct task_security_struct *tsec = current->security;
104 struct xfrm_sec_ctx *ctx; 204 struct xfrm_sec_ctx *ctx = NULL;
205 char *ctx_str = NULL;
206 u32 str_len;
207 u32 ctx_sid;
208
209 BUG_ON(uctx && pol);
210
211 if (!uctx)
212 goto not_from_user;
105 213
106 BUG_ON(!uctx); 214 if (uctx->ctx_doi != XFRM_SC_ALG_SELINUX)
107 BUG_ON(uctx->ctx_doi != XFRM_SC_ALG_SELINUX); 215 return -EINVAL;
108 216
109 if (uctx->ctx_len >= PAGE_SIZE) 217 if (uctx->ctx_len >= PAGE_SIZE)
110 return -ENOMEM; 218 return -ENOMEM;
@@ -141,9 +249,43 @@ static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_us
141 249
142 return rc; 250 return rc;
143 251
252not_from_user:
253 if (pol) {
254 rc = security_sid_mls_copy(pol->ctx_sid, sid, &ctx_sid);
255 if (rc)
256 goto out;
257 }
258 else
259 ctx_sid = sid;
260
261 rc = security_sid_to_context(ctx_sid, &ctx_str, &str_len);
262 if (rc)
263 goto out;
264
265 *ctxp = ctx = kmalloc(sizeof(*ctx) +
266 str_len,
267 GFP_ATOMIC);
268
269 if (!ctx) {
270 rc = -ENOMEM;
271 goto out;
272 }
273
274 ctx->ctx_doi = XFRM_SC_DOI_LSM;
275 ctx->ctx_alg = XFRM_SC_ALG_SELINUX;
276 ctx->ctx_sid = ctx_sid;
277 ctx->ctx_len = str_len;
278 memcpy(ctx->ctx_str,
279 ctx_str,
280 str_len);
281
282 goto out2;
283
144out: 284out:
145 *ctxp = NULL; 285 *ctxp = NULL;
146 kfree(ctx); 286 kfree(ctx);
287out2:
288 kfree(ctx_str);
147 return rc; 289 return rc;
148} 290}
149 291
@@ -151,13 +293,23 @@ out:
151 * LSM hook implementation that allocs and transfers uctx spec to 293 * LSM hook implementation that allocs and transfers uctx spec to
152 * xfrm_policy. 294 * xfrm_policy.
153 */ 295 */
154int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *uctx) 296int selinux_xfrm_policy_alloc(struct xfrm_policy *xp,
297 struct xfrm_user_sec_ctx *uctx, struct sock *sk)
155{ 298{
156 int err; 299 int err;
300 u32 sid;
157 301
158 BUG_ON(!xp); 302 BUG_ON(!xp);
303 BUG_ON(uctx && sk);
159 304
160 err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx); 305 if (sk) {
306 struct sk_security_struct *ssec = sk->sk_security;
307 sid = ssec->sid;
308 }
309 else
310 sid = SECSID_NULL;
311
312 err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, NULL, sid);
161 return err; 313 return err;
162} 314}
163 315
@@ -217,13 +369,14 @@ int selinux_xfrm_policy_delete(struct xfrm_policy *xp)
217 * LSM hook implementation that allocs and transfers sec_ctx spec to 369 * LSM hook implementation that allocs and transfers sec_ctx spec to
218 * xfrm_state. 370 * xfrm_state.
219 */ 371 */
220int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx) 372int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx,
373 struct xfrm_sec_ctx *pol, u32 secid)
221{ 374{
222 int err; 375 int err;
223 376
224 BUG_ON(!x); 377 BUG_ON(!x);
225 378
226 err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx); 379 err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, pol, secid);
227 return err; 380 return err;
228} 381}
229 382
@@ -329,38 +482,30 @@ int selinux_xfrm_state_delete(struct xfrm_state *x)
329 * we need to check for unlabelled access since this may not have 482 * we need to check for unlabelled access since this may not have
330 * gone thru the IPSec process. 483 * gone thru the IPSec process.
331 */ 484 */
332int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb) 485int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb,
486 struct avc_audit_data *ad)
333{ 487{
334 int i, rc = 0; 488 int i, rc = 0;
335 struct sec_path *sp; 489 struct sec_path *sp;
490 u32 sel_sid = SECINITSID_UNLABELED;
336 491
337 sp = skb->sp; 492 sp = skb->sp;
338 493
339 if (sp) { 494 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++) { 495 for (i = 0; i < sp->len; i++) {
347 struct xfrm_state *x = sp->xvec[i]; 496 struct xfrm_state *x = sp->xvec[i];
348 497
349 if (x && selinux_authorizable_xfrm(x)) 498 if (x && selinux_authorizable_xfrm(x)) {
350 goto accept; 499 struct xfrm_sec_ctx *ctx = x->security;
500 sel_sid = ctx->ctx_sid;
501 break;
502 }
351 } 503 }
352 } 504 }
353 505
354 /* check SELinux sock for unlabelled access */ 506 rc = avc_has_perm(isec_sid, sel_sid, SECCLASS_ASSOCIATION,
355 rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION, 507 ASSOCIATION__RECVFROM, ad);
356 ASSOCIATION__RECVFROM, NULL);
357 if (rc)
358 goto drop;
359
360accept:
361 return 0;
362 508
363drop:
364 return rc; 509 return rc;
365} 510}
366 511
@@ -371,7 +516,8 @@ drop:
371 * If we do have a authorizable security association, then it has already been 516 * If we do have a authorizable security association, then it has already been
372 * checked in xfrm_policy_lookup hook. 517 * checked in xfrm_policy_lookup hook.
373 */ 518 */
374int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb) 519int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
520 struct avc_audit_data *ad)
375{ 521{
376 struct dst_entry *dst; 522 struct dst_entry *dst;
377 int rc = 0; 523 int rc = 0;
@@ -391,7 +537,7 @@ int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb)
391 } 537 }
392 538
393 rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION, 539 rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION,
394 ASSOCIATION__SENDTO, NULL); 540 ASSOCIATION__SENDTO, ad);
395out: 541out:
396 return rc; 542 return rc;
397} 543}