Module: xenomai-head
Branch: master
Commit: a654f4f62499fd69852aaa9dbd3a96c0074a4868
URL:    
http://git.xenomai.org/?p=xenomai-head.git;a=commit;h=a654f4f62499fd69852aaa9dbd3a96c0074a4868

Author: Philippe Gerum <r...@xenomai.org>
Date:   Mon Sep 14 15:20:47 2009 +0200

rtipc: fix potential access race to remote socket

---

 ksrc/drivers/ipc/bufp.c     |   52 ++++++++++++++++++++++--------------------
 ksrc/drivers/ipc/iddp.c     |   49 ++++++++++++++++++++-------------------
 ksrc/drivers/ipc/internal.h |   16 +++++++++++++
 ksrc/drivers/ipc/xddp.c     |   45 +++++++++++++++---------------------
 4 files changed, 87 insertions(+), 75 deletions(-)

diff --git a/ksrc/drivers/ipc/bufp.c b/ksrc/drivers/ipc/bufp.c
index 99616bb..ba14fd4 100644
--- a/ksrc/drivers/ipc/bufp.c
+++ b/ksrc/drivers/ipc/bufp.c
@@ -525,29 +525,30 @@ static ssize_t __bufp_sendmsg(struct rtipc_private *priv,
                              const struct sockaddr_ipc *daddr)
 {
        struct bufp_socket *sk = priv->state, *rsk;
-       struct rtdm_dev_context *rcontext = NULL; /* Fake GCC */
-       ssize_t len, rdlen, vlen, ret;
+       struct rtdm_dev_context *rcontext;
+       ssize_t len, rdlen, vlen, ret = 0;
        struct xnbufd bufd;
-       int nvec, to;
+       int nvec;
+       void *p;
 
        len = rtipc_get_iov_flatlen(iov, iovlen);
        if (len == 0)
                return 0;
 
-       to = daddr->sipc_port;
+       p = xnmap_fetch_nocheck(portmap, daddr->sipc_port);
+       if (p == NULL)
+               return -ECONNRESET;
+
+       rcontext = rtdm_context_get(rtipc_map2fd(p));
+       if (rcontext == NULL)
+               return -ECONNRESET;
+
+       rsk = rtipc_context_to_state(rcontext);
+       if (!test_bit(_BUFP_BOUND, &rsk->status)) {
+               rtdm_context_unlock(rcontext);
+               return -ECONNREFUSED;
+       }
 
-       RTDM_EXECUTE_ATOMICALLY(
-               rsk = xnmap_fetch_nocheck(portmap, to);
-               if (unlikely(rsk == NULL))
-                       ret = -ECONNRESET;
-               else {
-                       rcontext = rtdm_private_to_context(rsk->priv);
-                       rtdm_context_lock(rcontext);
-                       ret = 0;
-               }
-       );
-       if (ret)
-               return ret;
        /*
         * We may only send complete messages, so there is no point in
         * accepting messages which are larger than what the buffer
@@ -658,10 +659,11 @@ static ssize_t bufp_write(struct rtipc_private *priv,
        return __bufp_sendmsg(priv, user_info, &iov, 1, 0, &sk->peer);
 }
 
-static int __bufp_bind_socket(struct bufp_socket *sk,
+static int __bufp_bind_socket(struct rtipc_private *priv,
                              struct sockaddr_ipc *sa)
 {
-       int ret = 0, port;
+       struct bufp_socket *sk = priv->state;
+       int ret = 0, port, fd;
 
        if (sa->sipc_family != AF_RTIPC)
                return -EINVAL;
@@ -678,9 +680,10 @@ static int __bufp_bind_socket(struct bufp_socket *sk,
        if (ret)
                return ret;
 
-       port = sa->sipc_port;
        /* Will auto-select a free port number if unspec (-1). */
-       port = xnmap_enter(portmap, port, sk);
+       port = sa->sipc_port;
+       fd = rtdm_private_to_context(priv)->fd;
+       port = xnmap_enter(portmap, port, rtipc_fd2map(fd));
        if (port < 0)
                return port == -EEXIST ? -EADDRINUSE : -ENOMEM;
 
@@ -954,11 +957,12 @@ static int __bufp_getsockopt(struct bufp_socket *sk,
        return ret;
 }
 
-static int __bufp_ioctl(struct bufp_socket *sk,
+static int __bufp_ioctl(struct rtipc_private *priv,
                        rtdm_user_info_t *user_info,
                        unsigned int request, void *arg)
 {
        struct sockaddr_ipc saddr, *saddrp = &saddr;
+       struct bufp_socket *sk = priv->state;
        int ret = 0;
 
        switch (request) {
@@ -976,7 +980,7 @@ static int __bufp_ioctl(struct bufp_socket *sk,
                        return ret;
                if (saddrp == NULL)
                        return -EFAULT;
-               ret = __bufp_bind_socket(sk, saddrp);
+               ret = __bufp_bind_socket(priv, saddrp);
                break;
 
        case _RTIOC_GETSOCKNAME:
@@ -1015,12 +1019,10 @@ static int bufp_ioctl(struct rtipc_private *priv,
                      rtdm_user_info_t *user_info,
                      unsigned int request, void *arg)
 {
-       struct bufp_socket *sk = priv->state;
-
        if (rtdm_in_rt_context() && request == _RTIOC_BIND)
                return -ENOSYS; /* Try downgrading to NRT */
 
-       return __bufp_ioctl(sk, user_info, request, arg);
+       return __bufp_ioctl(priv, user_info, request, arg);
 }
 
 static int __init bufp_init(void)
diff --git a/ksrc/drivers/ipc/iddp.c b/ksrc/drivers/ipc/iddp.c
index 13240a2..a407946 100644
--- a/ksrc/drivers/ipc/iddp.c
+++ b/ksrc/drivers/ipc/iddp.c
@@ -372,30 +372,30 @@ static ssize_t __iddp_sendmsg(struct rtipc_private *priv,
                              const struct sockaddr_ipc *daddr)
 {
        struct iddp_socket *sk = priv->state, *rsk;
-       struct rtdm_dev_context *rcontext = NULL; /* Fake GCC */
+       struct rtdm_dev_context *rcontext;
        struct iddp_message *mbuf;
-       int nvec, wroff, ret, to;
        ssize_t len, rdlen, vlen;
+       int nvec, wroff, ret;
        struct xnbufd bufd;
+       void *p;
 
        len = rtipc_get_iov_flatlen(iov, iovlen);
        if (len == 0)
                return 0;
 
-       to = daddr->sipc_port;
+       p = xnmap_fetch_nocheck(portmap, daddr->sipc_port);
+       if (p == NULL)
+               return -ECONNRESET;
 
-       RTDM_EXECUTE_ATOMICALLY(
-               rsk = xnmap_fetch_nocheck(portmap, to);
-               if (unlikely(rsk == NULL))
-                       ret = -ECONNRESET;
-               else {
-                       rcontext = rtdm_private_to_context(rsk->priv);
-                       rtdm_context_lock(rcontext);
-                       ret = 0;
-               }
-       );
-       if (ret)
-               return ret;
+       rcontext = rtdm_context_get(rtipc_map2fd(p));
+       if (rcontext == NULL)
+               return -ECONNRESET;
+
+       rsk = rtipc_context_to_state(rcontext);
+       if (!test_bit(_IDDP_BOUND, &rsk->status)) {
+               rtdm_context_unlock(rcontext);
+               return -ECONNREFUSED;
+       }
 
        mbuf = __iddp_alloc_mbuf(rsk, len, flags, sk->tx_timeout, &ret);
        if (unlikely(ret)) {
@@ -513,10 +513,11 @@ static ssize_t iddp_write(struct rtipc_private *priv,
        return __iddp_sendmsg(priv, user_info, &iov, 1, 0, &sk->peer);
 }
 
-static int __iddp_bind_socket(struct iddp_socket *sk,
+static int __iddp_bind_socket(struct rtipc_private *priv,
                              struct sockaddr_ipc *sa)
 {
-       int ret = 0, port;
+       struct iddp_socket *sk = priv->state;
+       int ret = 0, port, fd;
        void *poolmem;
        size_t poolsz;
 
@@ -535,9 +536,10 @@ static int __iddp_bind_socket(struct iddp_socket *sk,
        if (ret)
                return ret;
 
-       port = sa->sipc_port;
        /* Will auto-select a free port number if unspec (-1). */
-       port = xnmap_enter(portmap, port, sk);
+       port = sa->sipc_port;
+       fd = rtdm_private_to_context(priv)->fd;
+       port = xnmap_enter(portmap, port, rtipc_fd2map(fd));
        if (port < 0)
                return port == -EEXIST ? -EADDRINUSE : -ENOMEM;
 
@@ -839,11 +841,12 @@ static int __iddp_getsockopt(struct iddp_socket *sk,
        return ret;
 }
 
-static int __iddp_ioctl(struct iddp_socket *sk,
+static int __iddp_ioctl(struct rtipc_private *priv,
                        rtdm_user_info_t *user_info,
                        unsigned int request, void *arg)
 {
        struct sockaddr_ipc saddr, *saddrp = &saddr;
+       struct iddp_socket *sk = priv->state;
        int ret = 0;
 
        switch (request) {
@@ -861,7 +864,7 @@ static int __iddp_ioctl(struct iddp_socket *sk,
                        return ret;
                if (saddrp == NULL)
                        return -EFAULT;
-               ret = __iddp_bind_socket(sk, saddrp);
+               ret = __iddp_bind_socket(priv, saddrp);
                break;
 
        case _RTIOC_GETSOCKNAME:
@@ -900,12 +903,10 @@ static int iddp_ioctl(struct rtipc_private *priv,
                      rtdm_user_info_t *user_info,
                      unsigned int request, void *arg)
 {
-       struct iddp_socket *sk = priv->state;
-
        if (rtdm_in_rt_context() && request == _RTIOC_BIND)
                return -ENOSYS; /* Try downgrading to NRT */
 
-       return __iddp_ioctl(sk, user_info, request, arg);
+       return __iddp_ioctl(priv, user_info, request, arg);
 }
 
 static int __init iddp_init(void)
diff --git a/ksrc/drivers/ipc/internal.h b/ksrc/drivers/ipc/internal.h
index adf43dc..737038e 100644
--- a/ksrc/drivers/ipc/internal.h
+++ b/ksrc/drivers/ipc/internal.h
@@ -62,6 +62,22 @@ struct rtipc_protocol {
        } proto_ops;
 };
 
+static inline void *rtipc_context_to_state(struct rtdm_dev_context *context)
+{
+       struct rtipc_private *p = rtdm_context_to_private(context);
+       return p->state;
+}
+
+static inline void *rtipc_fd2map(int fd)
+{
+       return (void *)(fd + 1);
+}
+
+static inline int rtipc_map2fd(void *p)
+{
+       return (int)(p) - 1;
+}
+
 static inline nanosecs_rel_t rtipc_timeval_to_ns(const struct timeval *tv)
 {
        nanosecs_rel_t ns = tv->tv_usec * 1000;
diff --git a/ksrc/drivers/ipc/xddp.c b/ksrc/drivers/ipc/xddp.c
index 58ca073..f62147a 100644
--- a/ksrc/drivers/ipc/xddp.c
+++ b/ksrc/drivers/ipc/xddp.c
@@ -64,7 +64,7 @@ static struct sockaddr_ipc nullsa = {
        .sipc_port = -1
 };
 
-static struct xddp_socket *portmap[CONFIG_XENO_OPT_PIPE_NRDEV];
+static int portmap[CONFIG_XENO_OPT_PIPE_NRDEV]; /* indexes RTDM fildes */
 
 #define _XDDP_SYNCWAIT  0
 #define _XDDP_ATOMIC    1
@@ -260,18 +260,14 @@ static int xddp_close(struct rtipc_private *priv,
                      rtdm_user_info_t *user_info)
 {
        struct xddp_socket *sk = priv->state;
-       int bound;
 
-       RTDM_EXECUTE_ATOMICALLY(
-               bound = test_bit(_XDDP_BOUND, &sk->status);
-               if (bound)
-                       portmap[sk->name.sipc_port] = NULL;
-               sk->monitor = NULL;
-       );
+       sk->monitor = NULL;
 
-       if (!bound)
+       if (!test_bit(_XDDP_BOUND, &sk->status))
                return 0;
 
+       portmap[sk->name.sipc_port] = -1;
+
        if (sk->handle)
                xnregistry_remove(sk->handle);
 
@@ -476,8 +472,8 @@ static ssize_t __xddp_sendmsg(struct rtipc_private *priv,
                              const struct sockaddr_ipc *daddr)
 {
        ssize_t len, rdlen, wrlen, vlen, ret, sublen;
-       struct rtdm_dev_context *rcontext = NULL; /* Fake GCC */
        struct xddp_socket *sk = priv->state;
+       struct rtdm_dev_context *rcontext;
        struct xddp_message *mbuf;
        struct xddp_socket *rsk;
        int nvec, to, from;
@@ -490,21 +486,15 @@ static ssize_t __xddp_sendmsg(struct rtipc_private *priv,
        from = sk->name.sipc_port;
        to = daddr->sipc_port;
 
-       RTDM_EXECUTE_ATOMICALLY(
-               rsk = portmap[to];
-               if (rsk) {
-                       if (!test_bit(_XDDP_BOUND, &rsk->status))
-                               ret = -ECONNREFUSED;
-                       else {
-                               rcontext = rtdm_private_to_context(rsk->priv);
-                               rtdm_context_lock(rcontext);
-                               ret = 0;
-                       }
-               } else
-                       ret = -ECONNRESET;
-       );
-       if (ret)
-               return ret;
+       rcontext = rtdm_context_get(portmap[to]);
+       if (rcontext == NULL)
+               return -ECONNRESET;
+
+       rsk = rtipc_context_to_state(rcontext);
+       if (!test_bit(_XDDP_BOUND, &rsk->status)) {
+               rtdm_context_unlock(rcontext);
+               return -ECONNREFUSED;
+       }
 
        sublen = len;
        nvec = 0;
@@ -742,6 +732,8 @@ static int __xddp_bind_socket(struct rtipc_private *priv,
        ret = xnpipe_connect(sa->sipc_port, &ops,
                             rtdm_private_to_context(priv));
        if (ret < 0) {
+               if (ret == -EBUSY)
+                       ret = -EADDRINUSE;
        fail_freeheap:
                if (sk->bufpool == &sk->privpool)
                        xnheap_destroy(&sk->privpool,
@@ -752,6 +744,7 @@ static int __xddp_bind_socket(struct rtipc_private *priv,
        }
 
        sk->minor = ret;
+       sa->sipc_port = ret;
        sk->name = *sa;
        /* Set default destination if unset at binding time. */
        if (sk->peer.sipc_port < 0)
@@ -768,7 +761,7 @@ static int __xddp_bind_socket(struct rtipc_private *priv,
        }
 
        RTDM_EXECUTE_ATOMICALLY(
-               portmap[sk->minor] = sk;
+               portmap[sk->minor] = rtdm_private_to_context(priv)->fd;
                __clear_bit(_XDDP_BINDING, &sk->status);
                __set_bit(_XDDP_BOUND, &sk->status);
        );


_______________________________________________
Xenomai-git mailing list
Xenomai-git@gna.org
https://mail.gna.org/listinfo/xenomai-git

Reply via email to