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 * 9e0d1caa7SVenkat Yekkirala * Updated: Venkat Yekkirala <vyekkirala@TrustedCS.com> 10e0d1caa7SVenkat Yekkirala * 11e0d1caa7SVenkat Yekkirala * Granular IPSec Associations for use in MLS environments. 12e0d1caa7SVenkat Yekkirala * 13d28d1e08STrent Jaeger * Copyright (C) 2005 International Business Machines Corporation 14e0d1caa7SVenkat Yekkirala * Copyright (C) 2006 Trusted Computer Solutions, Inc. 15d28d1e08STrent Jaeger * 16d28d1e08STrent Jaeger * This program is free software; you can redistribute it and/or modify 17d28d1e08STrent Jaeger * it under the terms of the GNU General Public License version 2, 18d28d1e08STrent Jaeger * as published by the Free Software Foundation. 19d28d1e08STrent Jaeger */ 20d28d1e08STrent Jaeger 21d28d1e08STrent Jaeger /* 22d28d1e08STrent Jaeger * USAGE: 23d28d1e08STrent Jaeger * NOTES: 24d28d1e08STrent Jaeger * 1. Make sure to enable the following options in your kernel config: 25d28d1e08STrent Jaeger * CONFIG_SECURITY=y 26d28d1e08STrent Jaeger * CONFIG_SECURITY_NETWORK=y 27d28d1e08STrent Jaeger * CONFIG_SECURITY_NETWORK_XFRM=y 28d28d1e08STrent Jaeger * CONFIG_SECURITY_SELINUX=m/y 29d28d1e08STrent Jaeger * ISSUES: 30d28d1e08STrent Jaeger * 1. Caching packets, so they are not dropped during negotiation 31d28d1e08STrent Jaeger * 2. Emulating a reasonable SO_PEERSEC across machines 32d28d1e08STrent Jaeger * 3. Testing addition of sk_policy's with security context via setsockopt 33d28d1e08STrent Jaeger */ 34d28d1e08STrent Jaeger #include <linux/kernel.h> 35d28d1e08STrent Jaeger #include <linux/init.h> 36d28d1e08STrent Jaeger #include <linux/security.h> 37d28d1e08STrent Jaeger #include <linux/types.h> 38d28d1e08STrent Jaeger #include <linux/netfilter.h> 39d28d1e08STrent Jaeger #include <linux/netfilter_ipv4.h> 40d28d1e08STrent Jaeger #include <linux/netfilter_ipv6.h> 41d28d1e08STrent Jaeger #include <linux/ip.h> 42d28d1e08STrent Jaeger #include <linux/tcp.h> 43d28d1e08STrent Jaeger #include <linux/skbuff.h> 44d28d1e08STrent Jaeger #include <linux/xfrm.h> 45d28d1e08STrent Jaeger #include <net/xfrm.h> 46d28d1e08STrent Jaeger #include <net/checksum.h> 47d28d1e08STrent Jaeger #include <net/udp.h> 48d28d1e08STrent Jaeger #include <asm/semaphore.h> 49d28d1e08STrent Jaeger 50d28d1e08STrent Jaeger #include "avc.h" 51d28d1e08STrent Jaeger #include "objsec.h" 52d28d1e08STrent Jaeger #include "xfrm.h" 53d28d1e08STrent Jaeger 54d28d1e08STrent Jaeger 55d28d1e08STrent Jaeger /* 56d28d1e08STrent Jaeger * Returns true if an LSM/SELinux context 57d28d1e08STrent Jaeger */ 58d28d1e08STrent Jaeger static inline int selinux_authorizable_ctx(struct xfrm_sec_ctx *ctx) 59d28d1e08STrent Jaeger { 60d28d1e08STrent Jaeger return (ctx && 61d28d1e08STrent Jaeger (ctx->ctx_doi == XFRM_SC_DOI_LSM) && 62d28d1e08STrent Jaeger (ctx->ctx_alg == XFRM_SC_ALG_SELINUX)); 63d28d1e08STrent Jaeger } 64d28d1e08STrent Jaeger 65d28d1e08STrent Jaeger /* 66d28d1e08STrent Jaeger * Returns true if the xfrm contains a security blob for SELinux 67d28d1e08STrent Jaeger */ 68d28d1e08STrent Jaeger static inline int selinux_authorizable_xfrm(struct xfrm_state *x) 69d28d1e08STrent Jaeger { 70d28d1e08STrent Jaeger return selinux_authorizable_ctx(x->security); 71d28d1e08STrent Jaeger } 72d28d1e08STrent Jaeger 73d28d1e08STrent Jaeger /* 74e0d1caa7SVenkat Yekkirala * LSM hook implementation that authorizes that a flow can use 75e0d1caa7SVenkat Yekkirala * a xfrm policy rule. 76d28d1e08STrent Jaeger */ 77e0d1caa7SVenkat Yekkirala int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) 78d28d1e08STrent Jaeger { 795b368e61SVenkat Yekkirala int rc; 805b368e61SVenkat Yekkirala u32 sel_sid; 81d28d1e08STrent Jaeger struct xfrm_sec_ctx *ctx; 82d28d1e08STrent Jaeger 83d28d1e08STrent Jaeger /* Context sid is either set to label or ANY_ASSOC */ 84d28d1e08STrent Jaeger if ((ctx = xp->security)) { 85d28d1e08STrent Jaeger if (!selinux_authorizable_ctx(ctx)) 86d28d1e08STrent Jaeger return -EINVAL; 87d28d1e08STrent Jaeger 88d28d1e08STrent Jaeger sel_sid = ctx->ctx_sid; 89d28d1e08STrent Jaeger } 905b368e61SVenkat Yekkirala else 915b368e61SVenkat Yekkirala /* 925b368e61SVenkat Yekkirala * All flows should be treated as polmatch'ing an 935b368e61SVenkat Yekkirala * otherwise applicable "non-labeled" policy. This 945b368e61SVenkat Yekkirala * would prevent inadvertent "leaks". 955b368e61SVenkat Yekkirala */ 965b368e61SVenkat Yekkirala return 0; 97d28d1e08STrent Jaeger 98e0d1caa7SVenkat Yekkirala rc = avc_has_perm(fl_secid, sel_sid, SECCLASS_ASSOCIATION, 99e0d1caa7SVenkat Yekkirala ASSOCIATION__POLMATCH, 100d28d1e08STrent Jaeger NULL); 101d28d1e08STrent Jaeger 1025b368e61SVenkat Yekkirala if (rc == -EACCES) 1035b368e61SVenkat Yekkirala rc = -ESRCH; 1045b368e61SVenkat Yekkirala 105d28d1e08STrent Jaeger return rc; 106d28d1e08STrent Jaeger } 107d28d1e08STrent Jaeger 108d28d1e08STrent Jaeger /* 109e0d1caa7SVenkat Yekkirala * LSM hook implementation that authorizes that a state matches 110e0d1caa7SVenkat Yekkirala * the given policy, flow combo. 111e0d1caa7SVenkat Yekkirala */ 112e0d1caa7SVenkat Yekkirala 113e0d1caa7SVenkat Yekkirala int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp, 114e0d1caa7SVenkat Yekkirala struct flowi *fl) 115e0d1caa7SVenkat Yekkirala { 116e0d1caa7SVenkat Yekkirala u32 state_sid; 11767f83cbfSVenkat Yekkirala int rc; 118e0d1caa7SVenkat Yekkirala 11967f83cbfSVenkat Yekkirala if (!xp->security) 1205b368e61SVenkat Yekkirala if (x->security) 1215b368e61SVenkat Yekkirala /* unlabeled policy and labeled SA can't match */ 1225b368e61SVenkat Yekkirala return 0; 123e0d1caa7SVenkat Yekkirala else 1245b368e61SVenkat Yekkirala /* unlabeled policy and unlabeled SA match all flows */ 1255b368e61SVenkat Yekkirala return 1; 12667f83cbfSVenkat Yekkirala else 12767f83cbfSVenkat Yekkirala if (!x->security) 12867f83cbfSVenkat Yekkirala /* unlabeled SA and labeled policy can't match */ 12967f83cbfSVenkat Yekkirala return 0; 13067f83cbfSVenkat Yekkirala else 13167f83cbfSVenkat Yekkirala if (!selinux_authorizable_xfrm(x)) 13267f83cbfSVenkat Yekkirala /* Not a SELinux-labeled SA */ 133e0d1caa7SVenkat Yekkirala return 0; 134e0d1caa7SVenkat Yekkirala 13567f83cbfSVenkat Yekkirala state_sid = x->security->ctx_sid; 13667f83cbfSVenkat Yekkirala 13767f83cbfSVenkat Yekkirala if (fl->secid != state_sid) 13867f83cbfSVenkat Yekkirala return 0; 13967f83cbfSVenkat Yekkirala 14067f83cbfSVenkat Yekkirala rc = avc_has_perm(fl->secid, state_sid, SECCLASS_ASSOCIATION, 1415b368e61SVenkat Yekkirala ASSOCIATION__SENDTO, 1425b368e61SVenkat Yekkirala NULL)? 0:1; 1435b368e61SVenkat Yekkirala 144e0d1caa7SVenkat Yekkirala /* 14567f83cbfSVenkat Yekkirala * We don't need a separate SA Vs. policy polmatch check 14667f83cbfSVenkat Yekkirala * since the SA is now of the same label as the flow and 14767f83cbfSVenkat Yekkirala * a flow Vs. policy polmatch check had already happened 14867f83cbfSVenkat Yekkirala * in selinux_xfrm_policy_lookup() above. 149e0d1caa7SVenkat Yekkirala */ 150e0d1caa7SVenkat Yekkirala 151e0d1caa7SVenkat Yekkirala return rc; 152e0d1caa7SVenkat Yekkirala } 153e0d1caa7SVenkat Yekkirala 154e0d1caa7SVenkat Yekkirala /* 1556b877699SVenkat Yekkirala * LSM hook implementation that checks and/or returns the xfrm sid for the 1566b877699SVenkat Yekkirala * incoming packet. 157e0d1caa7SVenkat Yekkirala */ 158e0d1caa7SVenkat Yekkirala 159beb8d13bSVenkat Yekkirala int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) 160e0d1caa7SVenkat Yekkirala { 161e0d1caa7SVenkat Yekkirala struct sec_path *sp; 162e0d1caa7SVenkat Yekkirala 163beb8d13bSVenkat Yekkirala *sid = SECSID_NULL; 164e0d1caa7SVenkat Yekkirala 165e0d1caa7SVenkat Yekkirala if (skb == NULL) 166e0d1caa7SVenkat Yekkirala return 0; 167e0d1caa7SVenkat Yekkirala 168e0d1caa7SVenkat Yekkirala sp = skb->sp; 169e0d1caa7SVenkat Yekkirala if (sp) { 170e0d1caa7SVenkat Yekkirala int i, sid_set = 0; 171e0d1caa7SVenkat Yekkirala 172e0d1caa7SVenkat Yekkirala for (i = sp->len-1; i >= 0; i--) { 173e0d1caa7SVenkat Yekkirala struct xfrm_state *x = sp->xvec[i]; 174e0d1caa7SVenkat Yekkirala if (selinux_authorizable_xfrm(x)) { 175e0d1caa7SVenkat Yekkirala struct xfrm_sec_ctx *ctx = x->security; 176e0d1caa7SVenkat Yekkirala 177e0d1caa7SVenkat Yekkirala if (!sid_set) { 178beb8d13bSVenkat Yekkirala *sid = ctx->ctx_sid; 179e0d1caa7SVenkat Yekkirala sid_set = 1; 180beb8d13bSVenkat Yekkirala 181beb8d13bSVenkat Yekkirala if (!ckall) 182beb8d13bSVenkat Yekkirala break; 183e0d1caa7SVenkat Yekkirala } 184beb8d13bSVenkat Yekkirala else if (*sid != ctx->ctx_sid) 185e0d1caa7SVenkat Yekkirala return -EINVAL; 186e0d1caa7SVenkat Yekkirala } 187e0d1caa7SVenkat Yekkirala } 188e0d1caa7SVenkat Yekkirala } 189e0d1caa7SVenkat Yekkirala 190e0d1caa7SVenkat Yekkirala return 0; 191e0d1caa7SVenkat Yekkirala } 192e0d1caa7SVenkat Yekkirala 193e0d1caa7SVenkat Yekkirala /* 194d28d1e08STrent Jaeger * Security blob allocation for xfrm_policy and xfrm_state 195d28d1e08STrent Jaeger * CTX does not have a meaningful value on input 196d28d1e08STrent Jaeger */ 197e0d1caa7SVenkat Yekkirala static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, 198c1a856c9SVenkat Yekkirala struct xfrm_user_sec_ctx *uctx, u32 sid) 199d28d1e08STrent Jaeger { 200d28d1e08STrent Jaeger int rc = 0; 201d28d1e08STrent Jaeger struct task_security_struct *tsec = current->security; 202e0d1caa7SVenkat Yekkirala struct xfrm_sec_ctx *ctx = NULL; 203e0d1caa7SVenkat Yekkirala char *ctx_str = NULL; 204e0d1caa7SVenkat Yekkirala u32 str_len; 205e0d1caa7SVenkat Yekkirala 206c1a856c9SVenkat Yekkirala BUG_ON(uctx && sid); 207e0d1caa7SVenkat Yekkirala 208cb969f07SVenkat Yekkirala if (!uctx) 209cb969f07SVenkat Yekkirala goto not_from_user; 210e0d1caa7SVenkat Yekkirala 211e0d1caa7SVenkat Yekkirala if (uctx->ctx_doi != XFRM_SC_ALG_SELINUX) 212e0d1caa7SVenkat Yekkirala return -EINVAL; 213d28d1e08STrent Jaeger 214d28d1e08STrent Jaeger if (uctx->ctx_len >= PAGE_SIZE) 215d28d1e08STrent Jaeger return -ENOMEM; 216d28d1e08STrent Jaeger 217d28d1e08STrent Jaeger *ctxp = ctx = kmalloc(sizeof(*ctx) + 218910949a6SVenkat Yekkirala uctx->ctx_len + 1, 219d28d1e08STrent Jaeger GFP_KERNEL); 220d28d1e08STrent Jaeger 221d28d1e08STrent Jaeger if (!ctx) 222d28d1e08STrent Jaeger return -ENOMEM; 223d28d1e08STrent Jaeger 224d28d1e08STrent Jaeger ctx->ctx_doi = uctx->ctx_doi; 225d28d1e08STrent Jaeger ctx->ctx_len = uctx->ctx_len; 226d28d1e08STrent Jaeger ctx->ctx_alg = uctx->ctx_alg; 227d28d1e08STrent Jaeger 228d28d1e08STrent Jaeger memcpy(ctx->ctx_str, 229d28d1e08STrent Jaeger uctx+1, 230d28d1e08STrent Jaeger ctx->ctx_len); 231910949a6SVenkat Yekkirala ctx->ctx_str[ctx->ctx_len] = 0; 232d28d1e08STrent Jaeger rc = security_context_to_sid(ctx->ctx_str, 233d28d1e08STrent Jaeger ctx->ctx_len, 234d28d1e08STrent Jaeger &ctx->ctx_sid); 235d28d1e08STrent Jaeger 236d28d1e08STrent Jaeger if (rc) 237d28d1e08STrent Jaeger goto out; 238d28d1e08STrent Jaeger 239d28d1e08STrent Jaeger /* 240c8c05a8eSCatherine Zhang * Does the subject have permission to set security context? 241d28d1e08STrent Jaeger */ 242d28d1e08STrent Jaeger rc = avc_has_perm(tsec->sid, ctx->ctx_sid, 243d28d1e08STrent Jaeger SECCLASS_ASSOCIATION, 2445f8ac64bSTrent Jaeger ASSOCIATION__SETCONTEXT, NULL); 245d28d1e08STrent Jaeger if (rc) 246d28d1e08STrent Jaeger goto out; 247d28d1e08STrent Jaeger 248d28d1e08STrent Jaeger return rc; 249d28d1e08STrent Jaeger 250cb969f07SVenkat Yekkirala not_from_user: 251c1a856c9SVenkat Yekkirala rc = security_sid_to_context(sid, &ctx_str, &str_len); 252e0d1caa7SVenkat Yekkirala if (rc) 253e0d1caa7SVenkat Yekkirala goto out; 254e0d1caa7SVenkat Yekkirala 255e0d1caa7SVenkat Yekkirala *ctxp = ctx = kmalloc(sizeof(*ctx) + 256e0d1caa7SVenkat Yekkirala str_len, 257e0d1caa7SVenkat Yekkirala GFP_ATOMIC); 258e0d1caa7SVenkat Yekkirala 259e0d1caa7SVenkat Yekkirala if (!ctx) { 260e0d1caa7SVenkat Yekkirala rc = -ENOMEM; 261e0d1caa7SVenkat Yekkirala goto out; 262e0d1caa7SVenkat Yekkirala } 263e0d1caa7SVenkat Yekkirala 264e0d1caa7SVenkat Yekkirala ctx->ctx_doi = XFRM_SC_DOI_LSM; 265e0d1caa7SVenkat Yekkirala ctx->ctx_alg = XFRM_SC_ALG_SELINUX; 266c1a856c9SVenkat Yekkirala ctx->ctx_sid = sid; 267e0d1caa7SVenkat Yekkirala ctx->ctx_len = str_len; 268e0d1caa7SVenkat Yekkirala memcpy(ctx->ctx_str, 269e0d1caa7SVenkat Yekkirala ctx_str, 270e0d1caa7SVenkat Yekkirala str_len); 271e0d1caa7SVenkat Yekkirala 272e0d1caa7SVenkat Yekkirala goto out2; 273e0d1caa7SVenkat Yekkirala 274d28d1e08STrent Jaeger out: 275ee2e6841SLuiz Capitulino *ctxp = NULL; 276d28d1e08STrent Jaeger kfree(ctx); 277e0d1caa7SVenkat Yekkirala out2: 278e0d1caa7SVenkat Yekkirala kfree(ctx_str); 279d28d1e08STrent Jaeger return rc; 280d28d1e08STrent Jaeger } 281d28d1e08STrent Jaeger 282d28d1e08STrent Jaeger /* 283d28d1e08STrent Jaeger * LSM hook implementation that allocs and transfers uctx spec to 284d28d1e08STrent Jaeger * xfrm_policy. 285d28d1e08STrent Jaeger */ 286cb969f07SVenkat Yekkirala int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, 287c1a856c9SVenkat Yekkirala struct xfrm_user_sec_ctx *uctx) 288d28d1e08STrent Jaeger { 289d28d1e08STrent Jaeger int err; 290d28d1e08STrent Jaeger 291d28d1e08STrent Jaeger BUG_ON(!xp); 292c1a856c9SVenkat Yekkirala BUG_ON(!uctx); 293d28d1e08STrent Jaeger 294c1a856c9SVenkat Yekkirala err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, 0); 295d28d1e08STrent Jaeger return err; 296d28d1e08STrent Jaeger } 297d28d1e08STrent Jaeger 298d28d1e08STrent Jaeger 299d28d1e08STrent Jaeger /* 300d28d1e08STrent Jaeger * LSM hook implementation that copies security data structure from old to 301d28d1e08STrent Jaeger * new for policy cloning. 302d28d1e08STrent Jaeger */ 303d28d1e08STrent Jaeger int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) 304d28d1e08STrent Jaeger { 305d28d1e08STrent Jaeger struct xfrm_sec_ctx *old_ctx, *new_ctx; 306d28d1e08STrent Jaeger 307d28d1e08STrent Jaeger old_ctx = old->security; 308d28d1e08STrent Jaeger 309d28d1e08STrent Jaeger if (old_ctx) { 310d28d1e08STrent Jaeger new_ctx = new->security = kmalloc(sizeof(*new_ctx) + 311d28d1e08STrent Jaeger old_ctx->ctx_len, 312d28d1e08STrent Jaeger GFP_KERNEL); 313d28d1e08STrent Jaeger 314d28d1e08STrent Jaeger if (!new_ctx) 315d28d1e08STrent Jaeger return -ENOMEM; 316d28d1e08STrent Jaeger 317d28d1e08STrent Jaeger memcpy(new_ctx, old_ctx, sizeof(*new_ctx)); 318d28d1e08STrent Jaeger memcpy(new_ctx->ctx_str, old_ctx->ctx_str, new_ctx->ctx_len); 319d28d1e08STrent Jaeger } 320d28d1e08STrent Jaeger return 0; 321d28d1e08STrent Jaeger } 322d28d1e08STrent Jaeger 323d28d1e08STrent Jaeger /* 324d28d1e08STrent Jaeger * LSM hook implementation that frees xfrm_policy security information. 325d28d1e08STrent Jaeger */ 326d28d1e08STrent Jaeger void selinux_xfrm_policy_free(struct xfrm_policy *xp) 327d28d1e08STrent Jaeger { 328d28d1e08STrent Jaeger struct xfrm_sec_ctx *ctx = xp->security; 329d28d1e08STrent Jaeger if (ctx) 330d28d1e08STrent Jaeger kfree(ctx); 331d28d1e08STrent Jaeger } 332d28d1e08STrent Jaeger 333d28d1e08STrent Jaeger /* 334c8c05a8eSCatherine Zhang * LSM hook implementation that authorizes deletion of labeled policies. 335c8c05a8eSCatherine Zhang */ 336c8c05a8eSCatherine Zhang int selinux_xfrm_policy_delete(struct xfrm_policy *xp) 337c8c05a8eSCatherine Zhang { 338c8c05a8eSCatherine Zhang struct task_security_struct *tsec = current->security; 339c8c05a8eSCatherine Zhang struct xfrm_sec_ctx *ctx = xp->security; 340c8c05a8eSCatherine Zhang int rc = 0; 341c8c05a8eSCatherine Zhang 342c8c05a8eSCatherine Zhang if (ctx) 343c8c05a8eSCatherine Zhang rc = avc_has_perm(tsec->sid, ctx->ctx_sid, 344c8c05a8eSCatherine Zhang SECCLASS_ASSOCIATION, 345c8c05a8eSCatherine Zhang ASSOCIATION__SETCONTEXT, NULL); 346c8c05a8eSCatherine Zhang 347c8c05a8eSCatherine Zhang return rc; 348c8c05a8eSCatherine Zhang } 349c8c05a8eSCatherine Zhang 350c8c05a8eSCatherine Zhang /* 351d28d1e08STrent Jaeger * LSM hook implementation that allocs and transfers sec_ctx spec to 352d28d1e08STrent Jaeger * xfrm_state. 353d28d1e08STrent Jaeger */ 354e0d1caa7SVenkat Yekkirala int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx, 355c1a856c9SVenkat Yekkirala u32 secid) 356d28d1e08STrent Jaeger { 357d28d1e08STrent Jaeger int err; 358d28d1e08STrent Jaeger 359d28d1e08STrent Jaeger BUG_ON(!x); 360d28d1e08STrent Jaeger 361c1a856c9SVenkat Yekkirala err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, secid); 362d28d1e08STrent Jaeger return err; 363d28d1e08STrent Jaeger } 364d28d1e08STrent Jaeger 365d28d1e08STrent Jaeger /* 366d28d1e08STrent Jaeger * LSM hook implementation that frees xfrm_state security information. 367d28d1e08STrent Jaeger */ 368d28d1e08STrent Jaeger void selinux_xfrm_state_free(struct xfrm_state *x) 369d28d1e08STrent Jaeger { 370d28d1e08STrent Jaeger struct xfrm_sec_ctx *ctx = x->security; 371d28d1e08STrent Jaeger if (ctx) 372d28d1e08STrent Jaeger kfree(ctx); 373d28d1e08STrent Jaeger } 374d28d1e08STrent Jaeger 3752c7946a7SCatherine Zhang /* 376c8c05a8eSCatherine Zhang * LSM hook implementation that authorizes deletion of labeled SAs. 377c8c05a8eSCatherine Zhang */ 378c8c05a8eSCatherine Zhang int selinux_xfrm_state_delete(struct xfrm_state *x) 379c8c05a8eSCatherine Zhang { 380c8c05a8eSCatherine Zhang struct task_security_struct *tsec = current->security; 381c8c05a8eSCatherine Zhang struct xfrm_sec_ctx *ctx = x->security; 382c8c05a8eSCatherine Zhang int rc = 0; 383c8c05a8eSCatherine Zhang 384c8c05a8eSCatherine Zhang if (ctx) 385c8c05a8eSCatherine Zhang rc = avc_has_perm(tsec->sid, ctx->ctx_sid, 386c8c05a8eSCatherine Zhang SECCLASS_ASSOCIATION, 387c8c05a8eSCatherine Zhang ASSOCIATION__SETCONTEXT, NULL); 388c8c05a8eSCatherine Zhang 389c8c05a8eSCatherine Zhang return rc; 390c8c05a8eSCatherine Zhang } 391c8c05a8eSCatherine Zhang 392c8c05a8eSCatherine Zhang /* 393d28d1e08STrent Jaeger * LSM hook that controls access to unlabelled packets. If 394d28d1e08STrent Jaeger * a xfrm_state is authorizable (defined by macro) then it was 395d28d1e08STrent Jaeger * already authorized by the IPSec process. If not, then 396d28d1e08STrent Jaeger * we need to check for unlabelled access since this may not have 397d28d1e08STrent Jaeger * gone thru the IPSec process. 398d28d1e08STrent Jaeger */ 399e0d1caa7SVenkat Yekkirala int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, 400e0d1caa7SVenkat Yekkirala struct avc_audit_data *ad) 401d28d1e08STrent Jaeger { 402d28d1e08STrent Jaeger int i, rc = 0; 403d28d1e08STrent Jaeger struct sec_path *sp; 404e0d1caa7SVenkat Yekkirala u32 sel_sid = SECINITSID_UNLABELED; 405d28d1e08STrent Jaeger 406d28d1e08STrent Jaeger sp = skb->sp; 407d28d1e08STrent Jaeger 408d28d1e08STrent Jaeger if (sp) { 409d28d1e08STrent Jaeger for (i = 0; i < sp->len; i++) { 41067644726SDave Jones struct xfrm_state *x = sp->xvec[i]; 411d28d1e08STrent Jaeger 412e0d1caa7SVenkat Yekkirala if (x && selinux_authorizable_xfrm(x)) { 413e0d1caa7SVenkat Yekkirala struct xfrm_sec_ctx *ctx = x->security; 414e0d1caa7SVenkat Yekkirala sel_sid = ctx->ctx_sid; 415e0d1caa7SVenkat Yekkirala break; 416e0d1caa7SVenkat Yekkirala } 417d28d1e08STrent Jaeger } 418d28d1e08STrent Jaeger } 419d28d1e08STrent Jaeger 42067f83cbfSVenkat Yekkirala /* 42167f83cbfSVenkat Yekkirala * This check even when there's no association involved is 42267f83cbfSVenkat Yekkirala * intended, according to Trent Jaeger, to make sure a 42367f83cbfSVenkat Yekkirala * process can't engage in non-ipsec communication unless 42467f83cbfSVenkat Yekkirala * explicitly allowed by policy. 42567f83cbfSVenkat Yekkirala */ 42667f83cbfSVenkat Yekkirala 427e0d1caa7SVenkat Yekkirala rc = avc_has_perm(isec_sid, sel_sid, SECCLASS_ASSOCIATION, 428e0d1caa7SVenkat Yekkirala ASSOCIATION__RECVFROM, ad); 429d28d1e08STrent Jaeger 430d28d1e08STrent Jaeger return rc; 431d28d1e08STrent Jaeger } 432d28d1e08STrent Jaeger 433d28d1e08STrent Jaeger /* 434d28d1e08STrent Jaeger * POSTROUTE_LAST hook's XFRM processing: 435d28d1e08STrent Jaeger * If we have no security association, then we need to determine 436d28d1e08STrent Jaeger * whether the socket is allowed to send to an unlabelled destination. 437d28d1e08STrent Jaeger * If we do have a authorizable security association, then it has already been 43867f83cbfSVenkat Yekkirala * checked in the selinux_xfrm_state_pol_flow_match hook above. 439d28d1e08STrent Jaeger */ 440e0d1caa7SVenkat Yekkirala int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, 44167f83cbfSVenkat Yekkirala struct avc_audit_data *ad, u8 proto) 442d28d1e08STrent Jaeger { 443d28d1e08STrent Jaeger struct dst_entry *dst; 444d28d1e08STrent Jaeger int rc = 0; 445d28d1e08STrent Jaeger 446d28d1e08STrent Jaeger dst = skb->dst; 447d28d1e08STrent Jaeger 448d28d1e08STrent Jaeger if (dst) { 449d28d1e08STrent Jaeger struct dst_entry *dst_test; 450d28d1e08STrent Jaeger 451c80544dcSStephen Hemminger for (dst_test = dst; dst_test != NULL; 452d28d1e08STrent Jaeger dst_test = dst_test->child) { 453d28d1e08STrent Jaeger struct xfrm_state *x = dst_test->xfrm; 454d28d1e08STrent Jaeger 455d28d1e08STrent Jaeger if (x && selinux_authorizable_xfrm(x)) 4564e5ab4cbSJames Morris goto out; 457d28d1e08STrent Jaeger } 458d28d1e08STrent Jaeger } 459d28d1e08STrent Jaeger 46067f83cbfSVenkat Yekkirala switch (proto) { 46167f83cbfSVenkat Yekkirala case IPPROTO_AH: 46267f83cbfSVenkat Yekkirala case IPPROTO_ESP: 46367f83cbfSVenkat Yekkirala case IPPROTO_COMP: 46467f83cbfSVenkat Yekkirala /* 46567f83cbfSVenkat Yekkirala * We should have already seen this packet once before 46667f83cbfSVenkat Yekkirala * it underwent xfrm(s). No need to subject it to the 46767f83cbfSVenkat Yekkirala * unlabeled check. 46867f83cbfSVenkat Yekkirala */ 46967f83cbfSVenkat Yekkirala goto out; 47067f83cbfSVenkat Yekkirala default: 47167f83cbfSVenkat Yekkirala break; 47267f83cbfSVenkat Yekkirala } 47367f83cbfSVenkat Yekkirala 47467f83cbfSVenkat Yekkirala /* 47567f83cbfSVenkat Yekkirala * This check even when there's no association involved is 47667f83cbfSVenkat Yekkirala * intended, according to Trent Jaeger, to make sure a 47767f83cbfSVenkat Yekkirala * process can't engage in non-ipsec communication unless 47867f83cbfSVenkat Yekkirala * explicitly allowed by policy. 47967f83cbfSVenkat Yekkirala */ 48067f83cbfSVenkat Yekkirala 481d28d1e08STrent Jaeger rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION, 482e0d1caa7SVenkat Yekkirala ASSOCIATION__SENDTO, ad); 4834e5ab4cbSJames Morris out: 4844e5ab4cbSJames Morris return rc; 485d28d1e08STrent Jaeger } 486