Module: xenomai-3
Branch: wip/drivers
Commit: 59284782ac15e24a55f57581bdb4dccd4bc84a73
URL:    
http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=59284782ac15e24a55f57581bdb4dccd4bc84a73

Author: Philippe Gerum <r...@xenomai.org>
Date:   Tue Sep  6 09:40:34 2016 +0200

drivers/ipc: fix potential race in select()

Acquiring the poll state and binding the selector must be done
atomically, so that such state does not change before xnselect_bind()
decides whether the caller should wait.

---

 kernel/drivers/ipc/bufp.c  |    7 +------
 kernel/drivers/ipc/iddp.c  |    7 +------
 kernel/drivers/ipc/rtipc.c |   26 +++++++++++++-------------
 kernel/drivers/ipc/xddp.c  |    7 +------
 4 files changed, 16 insertions(+), 31 deletions(-)

diff --git a/kernel/drivers/ipc/bufp.c b/kernel/drivers/ipc/bufp.c
index f129eaa..2e7f5ad 100644
--- a/kernel/drivers/ipc/bufp.c
+++ b/kernel/drivers/ipc/bufp.c
@@ -1043,15 +1043,12 @@ static int bufp_ioctl(struct rtdm_fd *fd,
        return ret;
 }
 
-static unsigned int bufp_pollstate(struct rtdm_fd *fd)
+static unsigned int bufp_pollstate(struct rtdm_fd *fd) /* atomic */
 {
        struct rtipc_private *priv = rtdm_fd_to_private(fd);
        struct bufp_socket *sk = priv->state, *rsk;
        unsigned int mask = 0;
        struct rtdm_fd *rfd;
-       spl_t s;
-
-       cobalt_atomic_enter(s);
 
        if (test_bit(_BUFP_BOUND, &sk->status) && sk->fillsz > 0)
                mask |= POLLIN;
@@ -1072,8 +1069,6 @@ static unsigned int bufp_pollstate(struct rtdm_fd *fd)
        } else
                mask |= POLLOUT;
 
-       cobalt_atomic_leave(s);
-
        return mask;
 }
 
diff --git a/kernel/drivers/ipc/iddp.c b/kernel/drivers/ipc/iddp.c
index 028e40a..6d3da57 100644
--- a/kernel/drivers/ipc/iddp.c
+++ b/kernel/drivers/ipc/iddp.c
@@ -935,15 +935,12 @@ static void iddp_exit(void)
        xnmap_delete(portmap);
 }
 
-static unsigned int iddp_pollstate(struct rtdm_fd *fd)
+static unsigned int iddp_pollstate(struct rtdm_fd *fd) /* atomic */
 {
        struct rtipc_private *priv = rtdm_fd_to_private(fd);
        struct iddp_socket *sk = priv->state;
        unsigned int mask = 0;
        struct rtdm_fd *rfd;
-       spl_t s;
-
-       cobalt_atomic_enter(s);
 
        if (test_bit(_IDDP_BOUND, &sk->status) && !list_empty(&sk->inq))
                mask |= POLLIN;
@@ -966,8 +963,6 @@ static unsigned int iddp_pollstate(struct rtdm_fd *fd)
        } else
                mask |= POLLOUT;
 
-       cobalt_atomic_leave(s);
-
        return mask;
 }
 
diff --git a/kernel/drivers/ipc/rtipc.c b/kernel/drivers/ipc/rtipc.c
index 77fc7dd..7bd4950 100644
--- a/kernel/drivers/ipc/rtipc.c
+++ b/kernel/drivers/ipc/rtipc.c
@@ -481,28 +481,28 @@ static int rtipc_select(struct rtdm_fd *fd, struct 
xnselector *selector,
        spl_t s;
        int ret;
        
+       if (type != XNSELECT_READ && type != XNSELECT_WRITE)
+               return -EINVAL;
+
+       binding = xnmalloc(sizeof(*binding));
+       if (binding == NULL)
+               return -ENOMEM;
+
+       cobalt_atomic_enter(s);
+
        pollstate = priv->proto->proto_ops.pollstate(fd);
 
-       switch (type) {
-       case XNSELECT_READ:
+       if (type == XNSELECT_READ) {
                mask = pollstate & POLLIN;
                block = &priv->recv_block;
-               break;
-       case XNSELECT_WRITE:
+       } else {
                mask = pollstate & POLLOUT;
                block = &priv->send_block;
-               break;
-       default:
-               return -EINVAL;
        }
 
-       binding = xnmalloc(sizeof(*binding));
-       if (binding == NULL)
-               return -ENOMEM;
-
-       xnlock_get_irqsave(&nklock, s);
        ret = xnselect_bind(block, binding, selector, type, index, mask);
-       xnlock_put_irqrestore(&nklock, s);
+
+       cobalt_atomic_leave(s);
 
        if (ret)
                xnfree(binding);
diff --git a/kernel/drivers/ipc/xddp.c b/kernel/drivers/ipc/xddp.c
index c91aa02..c48b935 100644
--- a/kernel/drivers/ipc/xddp.c
+++ b/kernel/drivers/ipc/xddp.c
@@ -1081,15 +1081,12 @@ static int xddp_ioctl(struct rtdm_fd *fd,
        return ret;
 }
 
-static unsigned int xddp_pollstate(struct rtdm_fd *fd)
+static unsigned int xddp_pollstate(struct rtdm_fd *fd) /* atomic */
 {
        struct rtipc_private *priv = rtdm_fd_to_private(fd);
        struct xddp_socket *sk = priv->state, *rsk;
        unsigned int mask = 0, pollstate;
        struct rtdm_fd *rfd;
-       spl_t s;
-
-       cobalt_atomic_enter(s);
 
        pollstate = __xnpipe_pollstate(sk->minor);
        if (test_bit(_XDDP_BOUND, &sk->status))
@@ -1110,8 +1107,6 @@ static unsigned int xddp_pollstate(struct rtdm_fd *fd)
        } else
                mask |= POLLOUT;
 
-       cobalt_atomic_leave(s);
-
        return mask;
 }
 


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

Reply via email to