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> 48d621d35eSPaul Moore #include <asm/atomic.h> 49d28d1e08STrent Jaeger 50d28d1e08STrent Jaeger #include "avc.h" 51d28d1e08STrent Jaeger #include "objsec.h" 52d28d1e08STrent Jaeger #include "xfrm.h" 53d28d1e08STrent Jaeger 54d621d35eSPaul Moore /* Labeled XFRM instance counter */ 55d621d35eSPaul Moore atomic_t selinux_xfrm_refcount = ATOMIC_INIT(0); 56d28d1e08STrent Jaeger 57d28d1e08STrent Jaeger /* 58d28d1e08STrent Jaeger * Returns true if an LSM/SELinux context 59d28d1e08STrent Jaeger */ 60d28d1e08STrent Jaeger static inline int selinux_authorizable_ctx(struct xfrm_sec_ctx *ctx) 61d28d1e08STrent Jaeger { 62d28d1e08STrent Jaeger return (ctx && 63d28d1e08STrent Jaeger (ctx->ctx_doi == XFRM_SC_DOI_LSM) && 64d28d1e08STrent Jaeger (ctx->ctx_alg == XFRM_SC_ALG_SELINUX)); 65d28d1e08STrent Jaeger } 66d28d1e08STrent Jaeger 67d28d1e08STrent Jaeger /* 68d28d1e08STrent Jaeger * Returns true if the xfrm contains a security blob for SELinux 69d28d1e08STrent Jaeger */ 70d28d1e08STrent Jaeger static inline int selinux_authorizable_xfrm(struct xfrm_state *x) 71d28d1e08STrent Jaeger { 72d28d1e08STrent Jaeger return selinux_authorizable_ctx(x->security); 73d28d1e08STrent Jaeger } 74d28d1e08STrent Jaeger 75d28d1e08STrent Jaeger /* 76e0d1caa7SVenkat Yekkirala * LSM hook implementation that authorizes that a flow can use 77e0d1caa7SVenkat Yekkirala * a xfrm policy rule. 78d28d1e08STrent Jaeger */ 7903e1ad7bSPaul Moore int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir) 80d28d1e08STrent Jaeger { 815b368e61SVenkat Yekkirala int rc; 825b368e61SVenkat Yekkirala u32 sel_sid; 83d28d1e08STrent Jaeger 84d28d1e08STrent Jaeger /* Context sid is either set to label or ANY_ASSOC */ 8503e1ad7bSPaul Moore if (ctx) { 86d28d1e08STrent Jaeger if (!selinux_authorizable_ctx(ctx)) 87d28d1e08STrent Jaeger return -EINVAL; 88d28d1e08STrent Jaeger 89d28d1e08STrent Jaeger sel_sid = ctx->ctx_sid; 9003e1ad7bSPaul Moore } 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) 10303e1ad7bSPaul Moore return -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; 1833c1c88abSEric Paris } else if (*sid != ctx->ctx_sid) 184e0d1caa7SVenkat Yekkirala return -EINVAL; 185e0d1caa7SVenkat Yekkirala } 186e0d1caa7SVenkat Yekkirala } 187e0d1caa7SVenkat Yekkirala } 188e0d1caa7SVenkat Yekkirala 189e0d1caa7SVenkat Yekkirala return 0; 190e0d1caa7SVenkat Yekkirala } 191e0d1caa7SVenkat Yekkirala 192e0d1caa7SVenkat Yekkirala /* 193d28d1e08STrent Jaeger * Security blob allocation for xfrm_policy and xfrm_state 194d28d1e08STrent Jaeger * CTX does not have a meaningful value on input 195d28d1e08STrent Jaeger */ 196e0d1caa7SVenkat Yekkirala static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, 197c1a856c9SVenkat Yekkirala struct xfrm_user_sec_ctx *uctx, u32 sid) 198d28d1e08STrent Jaeger { 199d28d1e08STrent Jaeger int rc = 0; 20086a264abSDavid Howells const struct task_security_struct *tsec = current_security(); 201e0d1caa7SVenkat Yekkirala struct xfrm_sec_ctx *ctx = NULL; 202e0d1caa7SVenkat Yekkirala char *ctx_str = NULL; 203e0d1caa7SVenkat Yekkirala u32 str_len; 204e0d1caa7SVenkat Yekkirala 205c1a856c9SVenkat Yekkirala BUG_ON(uctx && sid); 206e0d1caa7SVenkat Yekkirala 207cb969f07SVenkat Yekkirala if (!uctx) 208cb969f07SVenkat Yekkirala goto not_from_user; 209e0d1caa7SVenkat Yekkirala 210e0d1caa7SVenkat Yekkirala if (uctx->ctx_doi != XFRM_SC_ALG_SELINUX) 211e0d1caa7SVenkat Yekkirala return -EINVAL; 212d28d1e08STrent Jaeger 21357002bfbSStephen Rothwell str_len = uctx->ctx_len; 21457002bfbSStephen Rothwell if (str_len >= PAGE_SIZE) 215d28d1e08STrent Jaeger return -ENOMEM; 216d28d1e08STrent Jaeger 217d28d1e08STrent Jaeger *ctxp = ctx = kmalloc(sizeof(*ctx) + 21857002bfbSStephen Rothwell str_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; 22557002bfbSStephen Rothwell ctx->ctx_len = str_len; 226d28d1e08STrent Jaeger ctx->ctx_alg = uctx->ctx_alg; 227d28d1e08STrent Jaeger 228d28d1e08STrent Jaeger memcpy(ctx->ctx_str, 229d28d1e08STrent Jaeger uctx+1, 23057002bfbSStephen Rothwell str_len); 23157002bfbSStephen Rothwell ctx->ctx_str[str_len] = 0; 232d28d1e08STrent Jaeger rc = security_context_to_sid(ctx->ctx_str, 23357002bfbSStephen Rothwell str_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 */ 28603e1ad7bSPaul Moore int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, 287c1a856c9SVenkat Yekkirala struct xfrm_user_sec_ctx *uctx) 288d28d1e08STrent Jaeger { 289d28d1e08STrent Jaeger int err; 290d28d1e08STrent Jaeger 291c1a856c9SVenkat Yekkirala BUG_ON(!uctx); 292d28d1e08STrent Jaeger 29303e1ad7bSPaul Moore err = selinux_xfrm_sec_ctx_alloc(ctxp, uctx, 0); 294d621d35eSPaul Moore if (err == 0) 295d621d35eSPaul Moore atomic_inc(&selinux_xfrm_refcount); 296d621d35eSPaul Moore 297d28d1e08STrent Jaeger return err; 298d28d1e08STrent Jaeger } 299d28d1e08STrent Jaeger 300d28d1e08STrent Jaeger 301d28d1e08STrent Jaeger /* 302d28d1e08STrent Jaeger * LSM hook implementation that copies security data structure from old to 303d28d1e08STrent Jaeger * new for policy cloning. 304d28d1e08STrent Jaeger */ 30503e1ad7bSPaul Moore int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, 30603e1ad7bSPaul Moore struct xfrm_sec_ctx **new_ctxp) 307d28d1e08STrent Jaeger { 30803e1ad7bSPaul Moore struct xfrm_sec_ctx *new_ctx; 309d28d1e08STrent Jaeger 310d28d1e08STrent Jaeger if (old_ctx) { 31103e1ad7bSPaul Moore new_ctx = kmalloc(sizeof(*old_ctx) + old_ctx->ctx_len, 312d28d1e08STrent Jaeger GFP_KERNEL); 313d28d1e08STrent Jaeger if (!new_ctx) 314d28d1e08STrent Jaeger return -ENOMEM; 315d28d1e08STrent Jaeger 316d28d1e08STrent Jaeger memcpy(new_ctx, old_ctx, sizeof(*new_ctx)); 317d28d1e08STrent Jaeger memcpy(new_ctx->ctx_str, old_ctx->ctx_str, new_ctx->ctx_len); 31803e1ad7bSPaul Moore *new_ctxp = new_ctx; 319d28d1e08STrent Jaeger } 320d28d1e08STrent Jaeger return 0; 321d28d1e08STrent Jaeger } 322d28d1e08STrent Jaeger 323d28d1e08STrent Jaeger /* 32403e1ad7bSPaul Moore * LSM hook implementation that frees xfrm_sec_ctx security information. 325d28d1e08STrent Jaeger */ 32603e1ad7bSPaul Moore void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx) 327d28d1e08STrent Jaeger { 328d28d1e08STrent Jaeger kfree(ctx); 329d28d1e08STrent Jaeger } 330d28d1e08STrent Jaeger 331d28d1e08STrent Jaeger /* 332c8c05a8eSCatherine Zhang * LSM hook implementation that authorizes deletion of labeled policies. 333c8c05a8eSCatherine Zhang */ 33403e1ad7bSPaul Moore int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx) 335c8c05a8eSCatherine Zhang { 33686a264abSDavid Howells const struct task_security_struct *tsec = current_security(); 337c8c05a8eSCatherine Zhang int rc = 0; 338c8c05a8eSCatherine Zhang 339d621d35eSPaul Moore if (ctx) { 340c8c05a8eSCatherine Zhang rc = avc_has_perm(tsec->sid, ctx->ctx_sid, 341c8c05a8eSCatherine Zhang SECCLASS_ASSOCIATION, 342c8c05a8eSCatherine Zhang ASSOCIATION__SETCONTEXT, NULL); 343d621d35eSPaul Moore if (rc == 0) 344d621d35eSPaul Moore atomic_dec(&selinux_xfrm_refcount); 345d621d35eSPaul Moore } 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); 362d621d35eSPaul Moore if (err == 0) 363d621d35eSPaul Moore atomic_inc(&selinux_xfrm_refcount); 364d28d1e08STrent Jaeger return err; 365d28d1e08STrent Jaeger } 366d28d1e08STrent Jaeger 367d28d1e08STrent Jaeger /* 368d28d1e08STrent Jaeger * LSM hook implementation that frees xfrm_state security information. 369d28d1e08STrent Jaeger */ 370d28d1e08STrent Jaeger void selinux_xfrm_state_free(struct xfrm_state *x) 371d28d1e08STrent Jaeger { 372d28d1e08STrent Jaeger struct xfrm_sec_ctx *ctx = x->security; 373d28d1e08STrent Jaeger kfree(ctx); 374d28d1e08STrent Jaeger } 375d28d1e08STrent Jaeger 3762c7946a7SCatherine Zhang /* 377c8c05a8eSCatherine Zhang * LSM hook implementation that authorizes deletion of labeled SAs. 378c8c05a8eSCatherine Zhang */ 379c8c05a8eSCatherine Zhang int selinux_xfrm_state_delete(struct xfrm_state *x) 380c8c05a8eSCatherine Zhang { 38186a264abSDavid Howells const struct task_security_struct *tsec = current_security(); 382c8c05a8eSCatherine Zhang struct xfrm_sec_ctx *ctx = x->security; 383c8c05a8eSCatherine Zhang int rc = 0; 384c8c05a8eSCatherine Zhang 385d621d35eSPaul Moore if (ctx) { 386c8c05a8eSCatherine Zhang rc = avc_has_perm(tsec->sid, ctx->ctx_sid, 387c8c05a8eSCatherine Zhang SECCLASS_ASSOCIATION, 388c8c05a8eSCatherine Zhang ASSOCIATION__SETCONTEXT, NULL); 389d621d35eSPaul Moore if (rc == 0) 390d621d35eSPaul Moore atomic_dec(&selinux_xfrm_refcount); 391d621d35eSPaul Moore } 392c8c05a8eSCatherine Zhang 393c8c05a8eSCatherine Zhang return rc; 394c8c05a8eSCatherine Zhang } 395c8c05a8eSCatherine Zhang 396c8c05a8eSCatherine Zhang /* 397d28d1e08STrent Jaeger * LSM hook that controls access to unlabelled packets. If 398d28d1e08STrent Jaeger * a xfrm_state is authorizable (defined by macro) then it was 399d28d1e08STrent Jaeger * already authorized by the IPSec process. If not, then 400d28d1e08STrent Jaeger * we need to check for unlabelled access since this may not have 401d28d1e08STrent Jaeger * gone thru the IPSec process. 402d28d1e08STrent Jaeger */ 403e0d1caa7SVenkat Yekkirala int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, 404e0d1caa7SVenkat Yekkirala struct avc_audit_data *ad) 405d28d1e08STrent Jaeger { 406d28d1e08STrent Jaeger int i, rc = 0; 407d28d1e08STrent Jaeger struct sec_path *sp; 408e0d1caa7SVenkat Yekkirala u32 sel_sid = SECINITSID_UNLABELED; 409d28d1e08STrent Jaeger 410d28d1e08STrent Jaeger sp = skb->sp; 411d28d1e08STrent Jaeger 412d28d1e08STrent Jaeger if (sp) { 413d28d1e08STrent Jaeger for (i = 0; i < sp->len; i++) { 41467644726SDave Jones struct xfrm_state *x = sp->xvec[i]; 415d28d1e08STrent Jaeger 416e0d1caa7SVenkat Yekkirala if (x && selinux_authorizable_xfrm(x)) { 417e0d1caa7SVenkat Yekkirala struct xfrm_sec_ctx *ctx = x->security; 418e0d1caa7SVenkat Yekkirala sel_sid = ctx->ctx_sid; 419e0d1caa7SVenkat Yekkirala break; 420e0d1caa7SVenkat Yekkirala } 421d28d1e08STrent Jaeger } 422d28d1e08STrent Jaeger } 423d28d1e08STrent Jaeger 42467f83cbfSVenkat Yekkirala /* 42567f83cbfSVenkat Yekkirala * This check even when there's no association involved is 42667f83cbfSVenkat Yekkirala * intended, according to Trent Jaeger, to make sure a 42767f83cbfSVenkat Yekkirala * process can't engage in non-ipsec communication unless 42867f83cbfSVenkat Yekkirala * explicitly allowed by policy. 42967f83cbfSVenkat Yekkirala */ 43067f83cbfSVenkat Yekkirala 431e0d1caa7SVenkat Yekkirala rc = avc_has_perm(isec_sid, sel_sid, SECCLASS_ASSOCIATION, 432e0d1caa7SVenkat Yekkirala ASSOCIATION__RECVFROM, ad); 433d28d1e08STrent Jaeger 434d28d1e08STrent Jaeger return rc; 435d28d1e08STrent Jaeger } 436d28d1e08STrent Jaeger 437d28d1e08STrent Jaeger /* 438d28d1e08STrent Jaeger * POSTROUTE_LAST hook's XFRM processing: 439d28d1e08STrent Jaeger * If we have no security association, then we need to determine 440d28d1e08STrent Jaeger * whether the socket is allowed to send to an unlabelled destination. 441d28d1e08STrent Jaeger * If we do have a authorizable security association, then it has already been 44267f83cbfSVenkat Yekkirala * checked in the selinux_xfrm_state_pol_flow_match hook above. 443d28d1e08STrent Jaeger */ 444e0d1caa7SVenkat Yekkirala int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, 44567f83cbfSVenkat Yekkirala struct avc_audit_data *ad, u8 proto) 446d28d1e08STrent Jaeger { 447d28d1e08STrent Jaeger struct dst_entry *dst; 448d28d1e08STrent Jaeger int rc = 0; 449d28d1e08STrent Jaeger 450d28d1e08STrent Jaeger dst = skb->dst; 451d28d1e08STrent Jaeger 452d28d1e08STrent Jaeger if (dst) { 453d28d1e08STrent Jaeger struct dst_entry *dst_test; 454d28d1e08STrent Jaeger 455c80544dcSStephen Hemminger for (dst_test = dst; dst_test != NULL; 456d28d1e08STrent Jaeger dst_test = dst_test->child) { 457d28d1e08STrent Jaeger struct xfrm_state *x = dst_test->xfrm; 458d28d1e08STrent Jaeger 459d28d1e08STrent Jaeger if (x && selinux_authorizable_xfrm(x)) 4604e5ab4cbSJames Morris goto out; 461d28d1e08STrent Jaeger } 462d28d1e08STrent Jaeger } 463d28d1e08STrent Jaeger 46467f83cbfSVenkat Yekkirala switch (proto) { 46567f83cbfSVenkat Yekkirala case IPPROTO_AH: 46667f83cbfSVenkat Yekkirala case IPPROTO_ESP: 46767f83cbfSVenkat Yekkirala case IPPROTO_COMP: 46867f83cbfSVenkat Yekkirala /* 46967f83cbfSVenkat Yekkirala * We should have already seen this packet once before 47067f83cbfSVenkat Yekkirala * it underwent xfrm(s). No need to subject it to the 47167f83cbfSVenkat Yekkirala * unlabeled check. 47267f83cbfSVenkat Yekkirala */ 47367f83cbfSVenkat Yekkirala goto out; 47467f83cbfSVenkat Yekkirala default: 47567f83cbfSVenkat Yekkirala break; 47667f83cbfSVenkat Yekkirala } 47767f83cbfSVenkat Yekkirala 47867f83cbfSVenkat Yekkirala /* 47967f83cbfSVenkat Yekkirala * This check even when there's no association involved is 48067f83cbfSVenkat Yekkirala * intended, according to Trent Jaeger, to make sure a 48167f83cbfSVenkat Yekkirala * process can't engage in non-ipsec communication unless 48267f83cbfSVenkat Yekkirala * explicitly allowed by policy. 48367f83cbfSVenkat Yekkirala */ 48467f83cbfSVenkat Yekkirala 485d28d1e08STrent Jaeger rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION, 486e0d1caa7SVenkat Yekkirala ASSOCIATION__SENDTO, ad); 4874e5ab4cbSJames Morris out: 4884e5ab4cbSJames Morris return rc; 489d28d1e08STrent Jaeger } 490