diff options
Diffstat (limited to 'security/selinux/xfrm.c')
-rw-r--r-- | security/selinux/xfrm.c | 207 |
1 files changed, 60 insertions, 147 deletions
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 675b995a67c3..bd8d1ef40a90 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c | |||
@@ -115,76 +115,46 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy * | |||
115 | struct flowi *fl) | 115 | struct flowi *fl) |
116 | { | 116 | { |
117 | u32 state_sid; | 117 | u32 state_sid; |
118 | u32 pol_sid; | 118 | int rc; |
119 | int err; | ||
120 | 119 | ||
121 | if (xp->security) { | 120 | if (!xp->security) |
122 | if (!x->security) | ||
123 | /* unlabeled SA and labeled policy can't match */ | ||
124 | return 0; | ||
125 | else | ||
126 | state_sid = x->security->ctx_sid; | ||
127 | pol_sid = xp->security->ctx_sid; | ||
128 | } else | ||
129 | if (x->security) | 121 | if (x->security) |
130 | /* unlabeled policy and labeled SA can't match */ | 122 | /* unlabeled policy and labeled SA can't match */ |
131 | return 0; | 123 | return 0; |
132 | else | 124 | else |
133 | /* unlabeled policy and unlabeled SA match all flows */ | 125 | /* unlabeled policy and unlabeled SA match all flows */ |
134 | return 1; | 126 | return 1; |
135 | |||
136 | err = avc_has_perm(state_sid, pol_sid, SECCLASS_ASSOCIATION, | ||
137 | ASSOCIATION__POLMATCH, | ||
138 | NULL); | ||
139 | |||
140 | if (err) | ||
141 | return 0; | ||
142 | |||
143 | err = avc_has_perm(fl->secid, state_sid, SECCLASS_ASSOCIATION, | ||
144 | ASSOCIATION__SENDTO, | ||
145 | NULL)? 0:1; | ||
146 | |||
147 | return err; | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * LSM hook implementation that authorizes that a particular outgoing flow | ||
152 | * can use a given security association. | ||
153 | */ | ||
154 | |||
155 | int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm, | ||
156 | struct xfrm_policy *xp) | ||
157 | { | ||
158 | int rc = 0; | ||
159 | u32 sel_sid = SECINITSID_UNLABELED; | ||
160 | struct xfrm_sec_ctx *ctx; | ||
161 | |||
162 | if (!xp->security) | ||
163 | if (!xfrm->security) | ||
164 | return 1; | ||
165 | else | ||
166 | return 0; | ||
167 | else | 127 | else |
168 | if (!xfrm->security) | 128 | if (!x->security) |
129 | /* unlabeled SA and labeled policy can't match */ | ||
169 | return 0; | 130 | return 0; |
131 | else | ||
132 | if (!selinux_authorizable_xfrm(x)) | ||
133 | /* Not a SELinux-labeled SA */ | ||
134 | return 0; | ||
170 | 135 | ||
171 | /* Context sid is either set to label or ANY_ASSOC */ | 136 | state_sid = x->security->ctx_sid; |
172 | if ((ctx = xfrm->security)) { | ||
173 | if (!selinux_authorizable_ctx(ctx)) | ||
174 | return 0; | ||
175 | 137 | ||
176 | sel_sid = ctx->ctx_sid; | 138 | if (fl->secid != state_sid) |
177 | } | 139 | return 0; |
178 | 140 | ||
179 | rc = avc_has_perm(fl->secid, sel_sid, SECCLASS_ASSOCIATION, | 141 | rc = avc_has_perm(fl->secid, state_sid, SECCLASS_ASSOCIATION, |
180 | ASSOCIATION__SENDTO, | 142 | ASSOCIATION__SENDTO, |
181 | NULL)? 0:1; | 143 | NULL)? 0:1; |
182 | 144 | ||
145 | /* | ||
146 | * We don't need a separate SA Vs. policy polmatch check | ||
147 | * since the SA is now of the same label as the flow and | ||
148 | * a flow Vs. policy polmatch check had already happened | ||
149 | * in selinux_xfrm_policy_lookup() above. | ||
150 | */ | ||
151 | |||
183 | return rc; | 152 | return rc; |
184 | } | 153 | } |
185 | 154 | ||
186 | /* | 155 | /* |
187 | * LSM hook implementation that determines the sid for the session. | 156 | * LSM hook implementation that checks and/or returns the xfrm sid for the |
157 | * incoming packet. | ||
188 | */ | 158 | */ |
189 | 159 | ||
190 | int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) | 160 | int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) |
@@ -226,16 +196,15 @@ int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) | |||
226 | * CTX does not have a meaningful value on input | 196 | * CTX does not have a meaningful value on input |
227 | */ | 197 | */ |
228 | static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, | 198 | static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, |
229 | struct xfrm_user_sec_ctx *uctx, struct xfrm_sec_ctx *pol, u32 sid) | 199 | struct xfrm_user_sec_ctx *uctx, u32 sid) |
230 | { | 200 | { |
231 | int rc = 0; | 201 | int rc = 0; |
232 | struct task_security_struct *tsec = current->security; | 202 | struct task_security_struct *tsec = current->security; |
233 | struct xfrm_sec_ctx *ctx = NULL; | 203 | struct xfrm_sec_ctx *ctx = NULL; |
234 | char *ctx_str = NULL; | 204 | char *ctx_str = NULL; |
235 | u32 str_len; | 205 | u32 str_len; |
236 | u32 ctx_sid; | ||
237 | 206 | ||
238 | BUG_ON(uctx && pol); | 207 | BUG_ON(uctx && sid); |
239 | 208 | ||
240 | if (!uctx) | 209 | if (!uctx) |
241 | goto not_from_user; | 210 | goto not_from_user; |
@@ -279,15 +248,7 @@ static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, | |||
279 | return rc; | 248 | return rc; |
280 | 249 | ||
281 | not_from_user: | 250 | not_from_user: |
282 | if (pol) { | 251 | rc = security_sid_to_context(sid, &ctx_str, &str_len); |
283 | rc = security_sid_mls_copy(pol->ctx_sid, sid, &ctx_sid); | ||
284 | if (rc) | ||
285 | goto out; | ||
286 | } | ||
287 | else | ||
288 | ctx_sid = sid; | ||
289 | |||
290 | rc = security_sid_to_context(ctx_sid, &ctx_str, &str_len); | ||
291 | if (rc) | 252 | if (rc) |
292 | goto out; | 253 | goto out; |
293 | 254 | ||
@@ -302,7 +263,7 @@ not_from_user: | |||
302 | 263 | ||
303 | ctx->ctx_doi = XFRM_SC_DOI_LSM; | 264 | ctx->ctx_doi = XFRM_SC_DOI_LSM; |
304 | ctx->ctx_alg = XFRM_SC_ALG_SELINUX; | 265 | ctx->ctx_alg = XFRM_SC_ALG_SELINUX; |
305 | ctx->ctx_sid = ctx_sid; | 266 | ctx->ctx_sid = sid; |
306 | ctx->ctx_len = str_len; | 267 | ctx->ctx_len = str_len; |
307 | memcpy(ctx->ctx_str, | 268 | memcpy(ctx->ctx_str, |
308 | ctx_str, | 269 | ctx_str, |
@@ -323,22 +284,14 @@ out2: | |||
323 | * xfrm_policy. | 284 | * xfrm_policy. |
324 | */ | 285 | */ |
325 | int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, | 286 | int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, |
326 | struct xfrm_user_sec_ctx *uctx, struct sock *sk) | 287 | struct xfrm_user_sec_ctx *uctx) |
327 | { | 288 | { |
328 | int err; | 289 | int err; |
329 | u32 sid; | ||
330 | 290 | ||
331 | BUG_ON(!xp); | 291 | BUG_ON(!xp); |
332 | BUG_ON(uctx && sk); | 292 | BUG_ON(!uctx); |
333 | |||
334 | if (sk) { | ||
335 | struct sk_security_struct *ssec = sk->sk_security; | ||
336 | sid = ssec->sid; | ||
337 | } | ||
338 | else | ||
339 | sid = SECSID_NULL; | ||
340 | 293 | ||
341 | err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, NULL, sid); | 294 | err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, 0); |
342 | return err; | 295 | return err; |
343 | } | 296 | } |
344 | 297 | ||
@@ -399,13 +352,13 @@ int selinux_xfrm_policy_delete(struct xfrm_policy *xp) | |||
399 | * xfrm_state. | 352 | * xfrm_state. |
400 | */ | 353 | */ |
401 | int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx, | 354 | int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx, |
402 | struct xfrm_sec_ctx *pol, u32 secid) | 355 | u32 secid) |
403 | { | 356 | { |
404 | int err; | 357 | int err; |
405 | 358 | ||
406 | BUG_ON(!x); | 359 | BUG_ON(!x); |
407 | 360 | ||
408 | err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, pol, secid); | 361 | err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, secid); |
409 | return err; | 362 | return err; |
410 | } | 363 | } |
411 | 364 | ||
@@ -419,74 +372,6 @@ void selinux_xfrm_state_free(struct xfrm_state *x) | |||
419 | kfree(ctx); | 372 | kfree(ctx); |
420 | } | 373 | } |
421 | 374 | ||
422 | /* | ||
423 | * SELinux internal function to retrieve the context of a connected | ||
424 | * (sk->sk_state == TCP_ESTABLISHED) TCP socket based on its security | ||
425 | * association used to connect to the remote socket. | ||
426 | * | ||
427 | * Retrieve via getsockopt SO_PEERSEC. | ||
428 | */ | ||
429 | u32 selinux_socket_getpeer_stream(struct sock *sk) | ||
430 | { | ||
431 | struct dst_entry *dst, *dst_test; | ||
432 | u32 peer_sid = SECSID_NULL; | ||
433 | |||
434 | if (sk->sk_state != TCP_ESTABLISHED) | ||
435 | goto out; | ||
436 | |||
437 | dst = sk_dst_get(sk); | ||
438 | if (!dst) | ||
439 | goto out; | ||
440 | |||
441 | for (dst_test = dst; dst_test != 0; | ||
442 | dst_test = dst_test->child) { | ||
443 | struct xfrm_state *x = dst_test->xfrm; | ||
444 | |||
445 | if (x && selinux_authorizable_xfrm(x)) { | ||
446 | struct xfrm_sec_ctx *ctx = x->security; | ||
447 | peer_sid = ctx->ctx_sid; | ||
448 | break; | ||
449 | } | ||
450 | } | ||
451 | dst_release(dst); | ||
452 | |||
453 | out: | ||
454 | return peer_sid; | ||
455 | } | ||
456 | |||
457 | /* | ||
458 | * SELinux internal function to retrieve the context of a UDP packet | ||
459 | * based on its security association used to connect to the remote socket. | ||
460 | * | ||
461 | * Retrieve via setsockopt IP_PASSSEC and recvmsg with control message | ||
462 | * type SCM_SECURITY. | ||
463 | */ | ||
464 | u32 selinux_socket_getpeer_dgram(struct sk_buff *skb) | ||
465 | { | ||
466 | struct sec_path *sp; | ||
467 | |||
468 | if (skb == NULL) | ||
469 | return SECSID_NULL; | ||
470 | |||
471 | if (skb->sk->sk_protocol != IPPROTO_UDP) | ||
472 | return SECSID_NULL; | ||
473 | |||
474 | sp = skb->sp; | ||
475 | if (sp) { | ||
476 | int i; | ||
477 | |||
478 | for (i = sp->len-1; i >= 0; i--) { | ||
479 | struct xfrm_state *x = sp->xvec[i]; | ||
480 | if (selinux_authorizable_xfrm(x)) { | ||
481 | struct xfrm_sec_ctx *ctx = x->security; | ||
482 | return ctx->ctx_sid; | ||
483 | } | ||
484 | } | ||
485 | } | ||
486 | |||
487 | return SECSID_NULL; | ||
488 | } | ||
489 | |||
490 | /* | 375 | /* |
491 | * LSM hook implementation that authorizes deletion of labeled SAs. | 376 | * LSM hook implementation that authorizes deletion of labeled SAs. |
492 | */ | 377 | */ |
@@ -532,6 +417,13 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, | |||
532 | } | 417 | } |
533 | } | 418 | } |
534 | 419 | ||
420 | /* | ||
421 | * This check even when there's no association involved is | ||
422 | * intended, according to Trent Jaeger, to make sure a | ||
423 | * process can't engage in non-ipsec communication unless | ||
424 | * explicitly allowed by policy. | ||
425 | */ | ||
426 | |||
535 | rc = avc_has_perm(isec_sid, sel_sid, SECCLASS_ASSOCIATION, | 427 | rc = avc_has_perm(isec_sid, sel_sid, SECCLASS_ASSOCIATION, |
536 | ASSOCIATION__RECVFROM, ad); | 428 | ASSOCIATION__RECVFROM, ad); |
537 | 429 | ||
@@ -543,10 +435,10 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, | |||
543 | * If we have no security association, then we need to determine | 435 | * If we have no security association, then we need to determine |
544 | * whether the socket is allowed to send to an unlabelled destination. | 436 | * whether the socket is allowed to send to an unlabelled destination. |
545 | * If we do have a authorizable security association, then it has already been | 437 | * If we do have a authorizable security association, then it has already been |
546 | * checked in xfrm_policy_lookup hook. | 438 | * checked in the selinux_xfrm_state_pol_flow_match hook above. |
547 | */ | 439 | */ |
548 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, | 440 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, |
549 | struct avc_audit_data *ad) | 441 | struct avc_audit_data *ad, u8 proto) |
550 | { | 442 | { |
551 | struct dst_entry *dst; | 443 | struct dst_entry *dst; |
552 | int rc = 0; | 444 | int rc = 0; |
@@ -565,6 +457,27 @@ int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, | |||
565 | } | 457 | } |
566 | } | 458 | } |
567 | 459 | ||
460 | switch (proto) { | ||
461 | case IPPROTO_AH: | ||
462 | case IPPROTO_ESP: | ||
463 | case IPPROTO_COMP: | ||
464 | /* | ||
465 | * We should have already seen this packet once before | ||
466 | * it underwent xfrm(s). No need to subject it to the | ||
467 | * unlabeled check. | ||
468 | */ | ||
469 | goto out; | ||
470 | default: | ||
471 | break; | ||
472 | } | ||
473 | |||
474 | /* | ||
475 | * This check even when there's no association involved is | ||
476 | * intended, according to Trent Jaeger, to make sure a | ||
477 | * process can't engage in non-ipsec communication unless | ||
478 | * explicitly allowed by policy. | ||
479 | */ | ||
480 | |||
568 | rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION, | 481 | rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION, |
569 | ASSOCIATION__SENDTO, ad); | 482 | ASSOCIATION__SENDTO, ad); |
570 | out: | 483 | out: |