]> nv-tegra.nvidia Code Review - linux-3.10.git/blobdiff - security/selinux/xfrm.c
Linux 2.6.26-rc8
[linux-3.10.git] / security / selinux / xfrm.c
index e076039690330675f6679edd39b18f02ab8e852d..8f17f542a1160bc44ccff63f8a0fe07e756e86b5 100644 (file)
 #include <net/xfrm.h>
 #include <net/checksum.h>
 #include <net/udp.h>
-#include <asm/semaphore.h>
+#include <asm/atomic.h>
 
 #include "avc.h"
 #include "objsec.h"
 #include "xfrm.h"
 
+/* Labeled XFRM instance counter */
+atomic_t selinux_xfrm_refcount = ATOMIC_INIT(0);
 
 /*
  * Returns true if an LSM/SELinux context
@@ -74,20 +76,18 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x)
  * LSM hook implementation that authorizes that a flow can use
  * a xfrm policy rule.
  */
-int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir)
+int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir)
 {
        int rc;
        u32 sel_sid;
-       struct xfrm_sec_ctx *ctx;
 
        /* Context sid is either set to label or ANY_ASSOC */
-       if ((ctx = xp->security)) {
+       if (ctx) {
                if (!selinux_authorizable_ctx(ctx))
                        return -EINVAL;
 
                sel_sid = ctx->ctx_sid;
-       }
-       else
+       } else
                /*
                 * All flows should be treated as polmatch'ing an
                 * otherwise applicable "non-labeled" policy. This
@@ -100,7 +100,7 @@ int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir)
                          NULL);
 
        if (rc == -EACCES)
-               rc = -ESRCH;
+               return -ESRCH;
 
        return rc;
 }
@@ -180,8 +180,7 @@ int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall)
 
                                        if (!ckall)
                                                break;
-                               }
-                               else if (*sid != ctx->ctx_sid)
+                               } else if (*sid != ctx->ctx_sid)
                                        return -EINVAL;
                        }
                }
@@ -284,15 +283,17 @@ out2:
  * LSM hook implementation that allocs and transfers uctx spec to
  * xfrm_policy.
  */
-int selinux_xfrm_policy_alloc(struct xfrm_policy *xp,
-               struct xfrm_user_sec_ctx *uctx)
+int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
+                             struct xfrm_user_sec_ctx *uctx)
 {
        int err;
 
-       BUG_ON(!xp);
        BUG_ON(!uctx);
 
-       err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, 0);
+       err = selinux_xfrm_sec_ctx_alloc(ctxp, uctx, 0);
+       if (err == 0)
+               atomic_inc(&selinux_xfrm_refcount);
+
        return err;
 }
 
@@ -301,49 +302,47 @@ int selinux_xfrm_policy_alloc(struct xfrm_policy *xp,
  * LSM hook implementation that copies security data structure from old to
  * new for policy cloning.
  */
-int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new)
+int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx,
+                             struct xfrm_sec_ctx **new_ctxp)
 {
-       struct xfrm_sec_ctx *old_ctx, *new_ctx;
-
-       old_ctx = old->security;
+       struct xfrm_sec_ctx *new_ctx;
 
        if (old_ctx) {
-               new_ctx = new->security = kmalloc(sizeof(*new_ctx) +
-                                                 old_ctx->ctx_len,
-                                                 GFP_KERNEL);
-
+               new_ctx = kmalloc(sizeof(*old_ctx) + old_ctx->ctx_len,
+                                 GFP_KERNEL);
                if (!new_ctx)
                        return -ENOMEM;
 
                memcpy(new_ctx, old_ctx, sizeof(*new_ctx));
                memcpy(new_ctx->ctx_str, old_ctx->ctx_str, new_ctx->ctx_len);
+               *new_ctxp = new_ctx;
        }
        return 0;
 }
 
 /*
- * LSM hook implementation that frees xfrm_policy security information.
+ * LSM hook implementation that frees xfrm_sec_ctx security information.
  */
-void selinux_xfrm_policy_free(struct xfrm_policy *xp)
+void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx)
 {
-       struct xfrm_sec_ctx *ctx = xp->security;
-       if (ctx)
-               kfree(ctx);
+       kfree(ctx);
 }
 
 /*
  * LSM hook implementation that authorizes deletion of labeled policies.
  */
-int selinux_xfrm_policy_delete(struct xfrm_policy *xp)
+int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx)
 {
        struct task_security_struct *tsec = current->security;
-       struct xfrm_sec_ctx *ctx = xp->security;
        int rc = 0;
 
-       if (ctx)
+       if (ctx) {
                rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
                                  SECCLASS_ASSOCIATION,
                                  ASSOCIATION__SETCONTEXT, NULL);
+               if (rc == 0)
+                       atomic_dec(&selinux_xfrm_refcount);
+       }
 
        return rc;
 }
@@ -360,6 +359,8 @@ int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uct
        BUG_ON(!x);
 
        err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, secid);
+       if (err == 0)
+               atomic_inc(&selinux_xfrm_refcount);
        return err;
 }
 
@@ -369,8 +370,7 @@ int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uct
 void selinux_xfrm_state_free(struct xfrm_state *x)
 {
        struct xfrm_sec_ctx *ctx = x->security;
-       if (ctx)
-               kfree(ctx);
+       kfree(ctx);
 }
 
  /*
@@ -382,10 +382,13 @@ int selinux_xfrm_state_delete(struct xfrm_state *x)
        struct xfrm_sec_ctx *ctx = x->security;
        int rc = 0;
 
-       if (ctx)
+       if (ctx) {
                rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
                                  SECCLASS_ASSOCIATION,
                                  ASSOCIATION__SETCONTEXT, NULL);
+               if (rc == 0)
+                       atomic_dec(&selinux_xfrm_refcount);
+       }
 
        return rc;
 }