tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

IPSEC (both stacks) slight adaptation to kauth(9)



Hi,

Our IPSEC stacks both have a SP PCB structure with a 'priv' field,
indicating whether this SP is "privileged" or not. The SP, which is
attached to a socket, gets this value set by by querying the socket's
uid, from the uidinfo field in the socket. In turn, the 'priv' field
is used in authorization. (If the uid is zero, it's privileged, and
vice versa.)

This of course doesn't fit with our transition to centralized
authorization and support for changing security policy (e.g. a MAC
policy that changed will not have any effect if the authorization is
done internally against a cached decision.)

The attached diff addresses this last abuse for uidinfo for
authorization by doing the following:

  1. Reorganize the switch statements so they are easier to understand.
     They differ only slightly, and as the networking stacks have enough
     duplicated code as it is, this is a step in the right direction if
     we are to eventually clean them up.

  2. Remove the 'priv' field of the SP PCB structures from both IPSEC
     and FAST_IPSEC. Isolate it to the relevant context, and retrieve
     its value in runtime and don't cache it.

  3. Replace uid comparison for privileged/unprivileged distinction with
     kauth(9) calls. For now, these are done on the generic scope as I
     have other changes in the pipe; once committed, these will be
     changed to use the network scope.

Please review. :)

Thanks,

-e.

Index: netipsec/ipsec.h
===================================================================
RCS file: /cvsroot/src/sys/netipsec/ipsec.h,v
retrieving revision 1.24
diff -u -p -r1.24 ipsec.h
--- netipsec/ipsec.h    10 May 2009 02:13:07 -0000      1.24
+++ netipsec/ipsec.h    31 Dec 2009 04:20:09 -0000
@@ -116,7 +116,6 @@ struct ipsecrequest {
 struct inpcbpolicy {
        struct secpolicy *sp_in;
        struct secpolicy *sp_out;
-       int priv;                       /* privileged socket ? */
 
 #ifdef __NetBSD__
        /* cached policy */
Index: netipsec/ipsec.c
===================================================================
RCS file: /cvsroot/src/sys/netipsec/ipsec.c,v
retrieving revision 1.46
diff -u -p -r1.46 ipsec.c
--- netipsec/ipsec.c    30 Jul 2009 14:41:59 -0000      1.46
+++ netipsec/ipsec.c    31 Dec 2009 04:20:11 -0000
@@ -513,8 +513,9 @@ ipsec_getpolicybysock(struct mbuf *m, u_
 {
        struct inpcbpolicy *pcbsp = NULL;
        struct secpolicy *currsp = NULL;        /* policy on socket */
-       struct secpolicy *sp;
-       int af;
+       struct secpolicy *sp = NULL; /* XXX gcc */
+       struct socket *so;
+       int af, unpriv;
 
        IPSEC_ASSERT(m != NULL, ("ipsec_getpolicybysock: null mbuf"));
        IPSEC_ASSERT(inp != NULL, ("ipsec_getpolicybysock: null inpcb"));
@@ -524,6 +525,7 @@ ipsec_getpolicybysock(struct mbuf *m, u_
 
        IPSEC_ASSERT(PCB_SOCKET(inp) != NULL,
                ("ipsec_getppolicybysock: null socket\n"));
+       so = PCB_SOCKET(inp);
 
        /* XXX FIXME inpcb/in6pcb  vs socket*/
        af = PCB_FAMILY(inp);
@@ -578,61 +580,52 @@ ipsec_getpolicybysock(struct mbuf *m, u_
        }
        IPSEC_ASSERT(currsp != NULL, ("ipsec_getpolicybysock: null currsp"));
 
-       if (pcbsp->priv) {                      /* when privilieged socket */
-               switch (currsp->policy) {
-               case IPSEC_POLICY_BYPASS:
-               case IPSEC_POLICY_IPSEC:
-                       currsp->refcnt++;
-                       sp = currsp;
-                       break;
+       unpriv = kauth_authorize_generic(so->so_cred, KAUTH_GENERIC_ISSUSER, 
NULL);
+       if (unpriv || currsp->policy == IPSEC_POLICY_ENTRUST) {
+               sp = KEY_ALLOCSP(&currsp->spidx, dir);
+               if (sp == NULL)
+                       sp = KEY_ALLOCSP_DEFAULT(af);
 
-               case IPSEC_POLICY_ENTRUST:
-                       /* look for a policy in SPD */
-                       sp = KEY_ALLOCSP(&currsp->spidx, dir);
-                       if (sp == NULL)         /* no SP found */
-                               sp = KEY_ALLOCSP_DEFAULT(af);
-                       break;
+               return sp;
+       }
 
-               default:
+       switch (currsp->policy) {
+       case IPSEC_POLICY_BYPASS:
+               unpriv = kauth_authorize_generic(so->so_cred,
+                   KAUTH_GENERIC_ISSUSER, NULL);
+               if (unpriv) {
                        ipseclog((LOG_ERR, "ipsec_getpolicybysock: "
-                                 "Invalid policy for PCB %d\n", 
currsp->policy));
+                          "Illegal policy for non-priviliged defined %d\n",
+                           currsp->policy));
                        *error = EINVAL;
                        return NULL;
                }
-       } else {                                /* unpriv, SPD has policy */
-               sp = KEY_ALLOCSP(&currsp->spidx, dir);
-               if (sp == NULL) {               /* no SP found */
-                       switch (currsp->policy) {
-                       case IPSEC_POLICY_BYPASS:
-                               ipseclog((LOG_ERR, "ipsec_getpolicybysock: "
-                                          "Illegal policy for non-priviliged 
defined %d\n",
-                                       currsp->policy));
-                               *error = EINVAL;
-                               return NULL;
+               currsp->refcnt++;
+               sp = currsp;
+               break;
 
-                       case IPSEC_POLICY_ENTRUST:
-                               sp = KEY_ALLOCSP_DEFAULT(af);
-                               break;
+       case IPSEC_POLICY_IPSEC:
+               currsp->refcnt++;
+               sp = currsp;
+               break;
 
-                       case IPSEC_POLICY_IPSEC:
-                               currsp->refcnt++;
-                               sp = currsp;
-                               break;
+       case IPSEC_POLICY_ENTRUST:
+               /* Everything that needs to be done is done at this point. */
+               break;
 
-                       default:
-                               ipseclog((LOG_ERR, "ipsec_getpolicybysock: "
-                                  "Invalid policy for PCB %d\n", 
currsp->policy));
-                               *error = EINVAL;
-                               return NULL;
-                       }
-               }
+       default:
+               ipseclog((LOG_ERR, "ipsec_getpolicybysock: "
+                         "Invalid policy for PCB %d\n", currsp->policy));
+               *error = EINVAL;
+               return NULL;
        }
+
        IPSEC_ASSERT(sp != NULL,
-               ("ipsec_getpolicybysock: null SP (priv %u policy %u",
-                pcbsp->priv, currsp->policy));
+               ("ipsec_getpolicybysock: null SP (unpriv %u policy %u",
+                unpriv, currsp->policy));
        KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
-               printf("DP ipsec_getpolicybysock (priv %u policy %u) allocates "
-                          "SP:%p (refcnt %u)\n", pcbsp->priv, currsp->policy,
+               printf("DP ipsec_getpolicybysock (unpriv %u policy %u) 
allocates "
+                          "SP:%p (refcnt %u)\n", unpriv, currsp->policy,
                           sp, sp->refcnt));
 #ifdef __NetBSD__
        ipsec_fillpcbcache(pcbsp, m, sp, dir);
@@ -1170,11 +1163,6 @@ ipsec_init_policy(struct socket *so, str
                return ENOBUFS;
        }
 
-       if (IPSEC_PRIVILEGED_SO(so))
-               new->priv = 1;
-       else
-               new->priv = 0;
-
        if ((new->sp_in = KEY_NEWSP()) == NULL) {
                ipsec_delpcbpolicy(new);
                return ENOBUFS;
@@ -1215,8 +1203,6 @@ ipsec_copy_policy(struct inpcbpolicy *ol
        } else
                return ENOBUFS;
 
-       new->priv = old->priv;
-
        return 0;
 }
 
Index: netipsec/ipsec_osdep.h
===================================================================
RCS file: /cvsroot/src/sys/netipsec/ipsec_osdep.h,v
retrieving revision 1.22
diff -u -p -r1.22 ipsec_osdep.h
--- netipsec/ipsec_osdep.h      20 Jan 2008 18:09:12 -0000      1.22
+++ netipsec/ipsec_osdep.h      31 Dec 2009 04:20:11 -0000
@@ -192,7 +192,8 @@ if_handoff(struct ifqueue *ifq, struct m
 
 #ifdef __NetBSD__
 /* superuser opened socket? */
-#define IPSEC_PRIVILEGED_SO(so) ((so)->so_uidinfo->ui_uid == 0)
+/* Should not be used. Use kauth(9) instead. */
+#define IPSEC_PRIVILEGED_SO(so) (kauth_cred_geteuid((so)->so_cred) == 0)
 #endif /* __NetBSD__ */
 
 /*
Index: netinet6/ipsec.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/ipsec.c,v
retrieving revision 1.143
diff -u -p -r1.143 ipsec.c
--- netinet6/ipsec.c    30 Dec 2009 23:23:58 -0000      1.143
+++ netinet6/ipsec.c    31 Dec 2009 04:20:13 -0000
@@ -424,6 +424,7 @@ ipsec4_getpolicybysock(struct mbuf *m, u
        struct pf_tag *t;
 #endif
        u_int16_t tag;
+       int unpriv;
 
        /* sanity check */
        if (m == NULL || so == NULL || error == NULL)
@@ -478,67 +479,52 @@ ipsec4_getpolicybysock(struct mbuf *m, u
        if (currsp == NULL)
                panic("ipsec4_getpolicybysock: currsp is NULL.");
 
-       /* when privileged socket */
-       if (pcbsp->priv) {
-               switch (currsp->policy) {
-               case IPSEC_POLICY_BYPASS:
-               case IPSEC_POLICY_IPSEC:
-                       currsp->refcnt++;
-                       *error = 0;
-                       ipsec_fillpcbcache(pcbsp, m, currsp, dir);
-                       return currsp;
-
-               case IPSEC_POLICY_ENTRUST:
-                       /* look for a policy in SPD */
-                       if (ipsec_setspidx_mbuf(&spidx, AF_INET, m, 1) == 0 &&
-                           (kernsp = key_allocsp(tag, &spidx, dir)) != NULL) {
-                               /* SP found */
-                               KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
-                                       printf("DP ipsec4_getpolicybysock 
called "
-                                              "to allocate SP:%p\n", kernsp));
-                               *error = 0;
-                               ipsec_fillpcbcache(pcbsp, m, kernsp, dir);
-                               return kernsp;
-                       }
-
-                       /* no SP found */
-                       ip4_def_policy->refcnt++;
+       /*
+        * Look for a security policy in the SPD if
+        *   1. We are unprivileged, or
+        *   2. We are looking up a policy...
+        */
+       unpriv = kauth_authorize_generic(so->so_cred, KAUTH_GENERIC_ISSUSER,
+           NULL);
+       if (unpriv ||
+           currsp->policy == IPSEC_POLICY_ENTRUST) {
+               /* look for a policy in SPD */
+               if (ipsec_setspidx_mbuf(&spidx, AF_INET, m, 1) == 0 &&
+                   (kernsp = key_allocsp(tag, &spidx, dir)) != NULL) {
+                       /* SP found */
+                       KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
+                               printf("DP ipsec4_getpolicybysock called "
+                                      "to allocate SP:%p\n", kernsp));
                        *error = 0;
-                       ipsec_fillpcbcache(pcbsp, m, ip4_def_policy, dir);
-                       return ip4_def_policy;
+                       ipsec_fillpcbcache(pcbsp, m, kernsp, dir);
+                       return kernsp;
+               }
+       }
 
-               default:
+       /* no SP found */
+       switch (currsp->policy) {
+       case IPSEC_POLICY_BYPASS:
+               /* Must be privileged. */
+               unpriv = kauth_authorize_generic(so->so_cred,
+                   KAUTH_GENERIC_ISSUSER, NULL);
+               if (unpriv) {
                        ipseclog((LOG_ERR, "ipsec4_getpolicybysock: "
-                             "Invalid policy for PCB %d\n", currsp->policy));
+                              "Illegal policy for non-privileged defined %d\n",
+                               currsp->policy));
                        *error = EINVAL;
                        return NULL;
                }
-               /* NOTREACHED */
-       }
-
-       /* when non-privileged socket */
-       /* look for a policy in SPD */
-       if (ipsec_setspidx_mbuf(&spidx, AF_INET, m, 1) == 0 &&
-           (kernsp = key_allocsp(tag, &spidx, dir)) != NULL) {
-               /* SP found */
-               KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
-                       printf("DP ipsec4_getpolicybysock called "
-                              "to allocate SP:%p\n", kernsp));
+               currsp->refcnt++;
                *error = 0;
-               ipsec_fillpcbcache(pcbsp, m, kernsp, dir);
-               return kernsp;
-       }
+               ipsec_fillpcbcache(pcbsp, m, currsp, dir);
+               return currsp;
 
-       /* no SP found */
-       switch (currsp->policy) {
-       case IPSEC_POLICY_BYPASS:
-               ipseclog((LOG_ERR, "ipsec4_getpolicybysock: "
-                      "Illegal policy for non-privileged defined %d\n",
-                       currsp->policy));
-               *error = EINVAL;
-               return NULL;
 
        case IPSEC_POLICY_ENTRUST:
+               /*
+                * We have looked up the policy outside the switch, and it must
+                * have not been found. Return the default policy.
+                */
                ip4_def_policy->refcnt++;
                *error = 0;
                ipsec_fillpcbcache(pcbsp, m, ip4_def_policy, dir);
@@ -643,6 +629,7 @@ ipsec6_getpolicybysock(struct mbuf *m, u
        struct pf_tag *t;
 #endif
        u_int16_t tag;
+       int unpriv;
 
        /* sanity check */
        if (m == NULL || so == NULL || error == NULL)
@@ -691,70 +678,38 @@ ipsec6_getpolicybysock(struct mbuf *m, u
        if (currsp == NULL)
                panic("ipsec6_getpolicybysock: currsp is NULL.");
 
-       /* when privileged socket */
-       if (pcbsp->priv) {
-               switch (currsp->policy) {
-               case IPSEC_POLICY_BYPASS:
-                       currsp->refcnt++;
-                       *error = 0;
-                       ipsec_fillpcbcache(pcbsp, m, currsp, dir);
-                       return currsp;
-
-               case IPSEC_POLICY_ENTRUST:
-                       /* look for a policy in SPD */
-                       if (ipsec_setspidx_mbuf(&spidx, AF_INET6, m, 1) == 0 &&
-                           (kernsp = key_allocsp(tag, &spidx, dir)) != NULL) {
-                               /* SP found */
-                               KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
-                                       printf("DP ipsec6_getpolicybysock 
called "
-                                              "to allocate SP:%p\n", kernsp));
-                               *error = 0;
-                               ipsec_fillpcbcache(pcbsp, m, kernsp, dir);
-                               return kernsp;
-                       }
-
-                       /* no SP found */
-                       ip6_def_policy->refcnt++;
+       unpriv = kauth_authorize_generic(so->so_cred, KAUTH_GENERIC_ISSUSER,
+           NULL);
+       if (unpriv || currsp->policy == IPSEC_POLICY_ENTRUST) {
+               /* look for a policy in SPD */
+               if (ipsec_setspidx_mbuf(&spidx, AF_INET6, m, 1) == 0 &&
+                   (kernsp = key_allocsp(tag, &spidx, dir)) != NULL) {
+                       /* SP found */
+                       KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
+                               printf("DP ipsec6_getpolicybysock called "
+                                      "to allocate SP:%p\n", kernsp));
                        *error = 0;
-                       ipsec_fillpcbcache(pcbsp, m, ip6_def_policy, dir);
-                       return ip6_def_policy;
-
-               case IPSEC_POLICY_IPSEC:
-                       currsp->refcnt++;
-                       *error = 0;
-                       ipsec_fillpcbcache(pcbsp, m, currsp, dir);
-                       return currsp;
-
-               default:
-                       ipseclog((LOG_ERR, "ipsec6_getpolicybysock: "
-                           "Invalid policy for PCB %d\n", currsp->policy));
-                       *error = EINVAL;
-                       return NULL;
+                       ipsec_fillpcbcache(pcbsp, m, kernsp, dir);
+                       return kernsp;
                }
-               /* NOTREACHED */
-       }
-
-       /* when non-privileged socket */
-       /* look for a policy in SPD */
-       if (ipsec_setspidx_mbuf(&spidx, AF_INET6, m, 1) == 0 &&
-           (kernsp = key_allocsp(tag, &spidx, dir)) != NULL) {
-               /* SP found */
-               KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
-                       printf("DP ipsec6_getpolicybysock called "
-                              "to allocate SP:%p\n", kernsp));
-               *error = 0;
-               ipsec_fillpcbcache(pcbsp, m, kernsp, dir);
-               return kernsp;
        }
 
        /* no SP found */
        switch (currsp->policy) {
        case IPSEC_POLICY_BYPASS:
-               ipseclog((LOG_ERR, "ipsec6_getpolicybysock: "
-                   "Illegal policy for non-privileged defined %d\n",
-                   currsp->policy));
-               *error = EINVAL;
-               return NULL;
+               unpriv = kauth_authorize_generic(so->so_cred,
+                   KAUTH_GENERIC_ISSUSER, NULL);
+               if (unpriv) {
+                       ipseclog((LOG_ERR, "ipsec6_getpolicybysock: "
+                           "Illegal policy for non-privileged defined %d\n",
+                           currsp->policy));
+                       *error = EINVAL;
+                       return NULL;
+               }
+               currsp->refcnt++;
+               *error = 0;
+               ipsec_fillpcbcache(pcbsp, m, currsp, dir);
+               return currsp;
 
        case IPSEC_POLICY_ENTRUST:
                ip6_def_policy->refcnt++;
@@ -1230,11 +1185,6 @@ ipsec_init_pcbpolicy(struct socket *so, 
        }
        memset(new, 0, sizeof(*new));
 
-       if (so->so_uidinfo->ui_uid == 0)        /* XXX-kauth */
-               new->priv = 1;
-       else
-               new->priv = 0;
-
        new->sp_in = in;
        new->sp_in->refcnt++;
        new->sp_out = out;
@@ -1268,8 +1218,6 @@ ipsec_copy_pcbpolicy(struct inpcbpolicy 
                new->sp_out->refcnt++;
        }
 
-       new->priv = old->priv;
-
        return 0;
 }
 
Index: netinet6/ipsec.h
===================================================================
RCS file: /cvsroot/src/sys/netinet6/ipsec.h,v
retrieving revision 1.51
diff -u -p -r1.51 ipsec.h
--- netinet6/ipsec.h    6 May 2009 21:41:59 -0000       1.51
+++ netinet6/ipsec.h    31 Dec 2009 04:20:13 -0000
@@ -124,7 +124,6 @@ struct ipsecrequest {
 struct inpcbpolicy {
        struct secpolicy *sp_in;
        struct secpolicy *sp_out;
-       int priv;                       /* privileged socket ? */
 
        /* cached policy */
        struct {


Home | Main Index | Thread Index | Old Index