tipc: Reject connection protocol message sent to unconnected port
authorAllan Stephens <allan.stephens@windriver.com>
Wed, 1 Jun 2011 19:08:10 +0000 (15:08 -0400)
committerPaul Gortmaker <paul.gortmaker@windriver.com>
Fri, 24 Jun 2011 20:18:18 +0000 (16:18 -0400)
Restructures the logic used in tipc_port_recv_proto_msg() to ensure
that incoming connection protocol messages are handled properly. The
routine now uses a two-stage process that first ensures the message
applies on an existing connection and then processes the request.
This corrects a loophole that allowed a connection probe request to
be processed if it was sent to an unconnected port that had no names
bound to it.

Signed-off-by: Allan Stephens <allan.stephens@windriver.com>
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
net/tipc/port.c

index 8be68e0bf300f36b170d685a727099729ce83e60..1b20b963a2fc9f8644e6ada2e408caaf3dfa3213 100644 (file)
@@ -526,62 +526,63 @@ static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *p_ptr, u32 er
 void tipc_port_recv_proto_msg(struct sk_buff *buf)
 {
        struct tipc_msg *msg = buf_msg(buf);
-       struct tipc_port *p_ptr = tipc_port_lock(msg_destport(msg));
-       u32 err = TIPC_OK;
+       struct tipc_port *p_ptr;
        struct sk_buff *r_buf = NULL;
-       struct sk_buff *abort_buf = NULL;
-
-       if (!p_ptr) {
-               err = TIPC_ERR_NO_PORT;
-       } else if (p_ptr->connected) {
-               if ((port_peernode(p_ptr) != msg_orignode(msg)) ||
-                   (port_peerport(p_ptr) != msg_origport(msg))) {
-                       err = TIPC_ERR_NO_PORT;
-               } else if (msg_type(msg) == CONN_ACK) {
-                       int wakeup = tipc_port_congested(p_ptr) &&
-                                    p_ptr->congested &&
-                                    p_ptr->wakeup;
-                       p_ptr->acked += msg_msgcnt(msg);
-                       if (tipc_port_congested(p_ptr))
-                               goto exit;
-                       p_ptr->congested = 0;
-                       if (!wakeup)
-                               goto exit;
-                       p_ptr->wakeup(p_ptr);
-                       goto exit;
-               }
-       } else if (p_ptr->published) {
-               err = TIPC_ERR_NO_PORT;
-       }
-       if (err) {
-               r_buf = port_build_proto_msg(msg_origport(msg),
-                                            msg_orignode(msg),
-                                            msg_destport(msg),
+       u32 orignode = msg_orignode(msg);
+       u32 origport = msg_origport(msg);
+       u32 destport = msg_destport(msg);
+       int wakeable;
+
+       /* Validate connection */
+
+       p_ptr = tipc_port_lock(destport);
+       if (!p_ptr || !p_ptr->connected ||
+           (port_peernode(p_ptr) != orignode) ||
+           (port_peerport(p_ptr) != origport)) {
+               r_buf = port_build_proto_msg(origport,
+                                            orignode,
+                                            destport,
                                             tipc_own_addr,
                                             TIPC_HIGH_IMPORTANCE,
                                             TIPC_CONN_MSG,
-                                            err,
+                                            TIPC_ERR_NO_PORT,
                                             0);
+               if (p_ptr)
+                       tipc_port_unlock(p_ptr);
                goto exit;
        }
 
-       /* All is fine */
-       if (msg_type(msg) == CONN_PROBE) {
-               r_buf = port_build_proto_msg(msg_origport(msg),
-                                            msg_orignode(msg),
-                                            msg_destport(msg),
+       /* Process protocol message sent by peer */
+
+       switch (msg_type(msg)) {
+       case CONN_ACK:
+               wakeable = tipc_port_congested(p_ptr) && p_ptr->congested &&
+                       p_ptr->wakeup;
+               p_ptr->acked += msg_msgcnt(msg);
+               if (!tipc_port_congested(p_ptr)) {
+                       p_ptr->congested = 0;
+                       if (wakeable)
+                               p_ptr->wakeup(p_ptr);
+               }
+               break;
+       case CONN_PROBE:
+               r_buf = port_build_proto_msg(origport,
+                                            orignode,
+                                            destport,
                                             tipc_own_addr,
                                             CONN_MANAGER,
                                             CONN_PROBE_REPLY,
                                             TIPC_OK,
                                             0);
+               break;
+       default:
+               /* CONN_PROBE_REPLY or unrecognized - no action required */
+               break;
        }
        p_ptr->probing_state = CONFIRMED;
+       tipc_port_unlock(p_ptr);
 exit:
-       if (p_ptr)
-               tipc_port_unlock(p_ptr);
        tipc_net_route_msg(r_buf);
-       tipc_net_route_msg(abort_buf);
        buf_discard(buf);
 }