From 9446b87addd90a067b21c726aedd3c42694c1780 Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Fri, 18 Oct 2013 07:23:15 +0200 Subject: tipc: remove iovec length parameter from all sending functions tipc_msg_build() now copies message data from iovec to skb_buff using memcpy_fromiovecend(), which doesn't need to be passed the iovec length to perform the copying. So we remove the parameter indicating iovec length in all functions where TIPC messages are built and sent. Signed-off-by: Ying Xue Reviewed-by: Paul Gortmaker Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/socket.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'net/tipc/socket.c') diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 6cc7ddd2fb7c..d224382d8270 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -622,13 +622,11 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, res = tipc_send2name(tport->ref, &dest->addr.name.name, dest->addr.name.domain, - m->msg_iovlen, m->msg_iov, total_len); } else if (dest->addrtype == TIPC_ADDR_ID) { res = tipc_send2port(tport->ref, &dest->addr.id, - m->msg_iovlen, m->msg_iov, total_len); } else if (dest->addrtype == TIPC_ADDR_MCAST) { @@ -641,7 +639,6 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, break; res = tipc_multicast(tport->ref, &dest->addr.nameseq, - m->msg_iovlen, m->msg_iov, total_len); } @@ -707,8 +704,7 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, break; } - res = tipc_send(tport->ref, m->msg_iovlen, m->msg_iov, - total_len); + res = tipc_send(tport->ref, m->msg_iov, total_len); if (likely(res != -ELINKCONG)) break; if (timeout_val <= 0L) { -- cgit v1.2.1 From 4068243208d605b046479e25c253379069a05fed Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Fri, 18 Oct 2013 07:23:16 +0200 Subject: tipc: silence sparse warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eliminate below sparse warnings: net/tipc/link.c:1210:37: warning: cast removes address space of expression net/tipc/link.c:1218:59: warning: incorrect type in argument 2 (different address spaces) net/tipc/link.c:1218:59: expected void const [noderef] *from net/tipc/link.c:1218:59: got unsigned char const [usertype] *[assigned] sect_crs net/tipc/socket.c:341:49: warning: Using plain integer as NULL pointer net/tipc/socket.c:1371:36: warning: Using plain integer as NULL pointer net/tipc/socket.c:1694:57: warning: Using plain integer as NULL pointer Signed-off-by: Ying Xue Signed-off-by: Andreas Bofjäll Reviewed-by: Paul Gortmaker Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/socket.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net/tipc/socket.c') diff --git a/net/tipc/socket.c b/net/tipc/socket.c index d224382d8270..3906527259d1 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -338,7 +338,7 @@ static int release(struct socket *sock) buf = __skb_dequeue(&sk->sk_receive_queue); if (buf == NULL) break; - if (TIPC_SKB_CB(buf)->handle != 0) + if (TIPC_SKB_CB(buf)->handle != NULL) kfree_skb(buf); else { if ((sock->state == SS_CONNECTING) || @@ -1364,7 +1364,7 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf) return TIPC_ERR_OVERLOAD; /* Enqueue message */ - TIPC_SKB_CB(buf)->handle = 0; + TIPC_SKB_CB(buf)->handle = NULL; __skb_queue_tail(&sk->sk_receive_queue, buf); skb_set_owner_r(buf, sk); @@ -1687,7 +1687,7 @@ restart: /* Disconnect and send a 'FIN+' or 'FIN-' message to peer */ buf = __skb_dequeue(&sk->sk_receive_queue); if (buf) { - if (TIPC_SKB_CB(buf)->handle != 0) { + if (TIPC_SKB_CB(buf)->handle != NULL) { kfree_skb(buf); goto restart; } -- cgit v1.2.1 From f3d3342602f8bcbf37d7c46641cb9bca7618eb1c Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Thu, 21 Nov 2013 03:14:22 +0100 Subject: net: rework recvmsg handler msg_name and msg_namelen logic This patch now always passes msg->msg_namelen as 0. recvmsg handlers must set msg_namelen to the proper size <= sizeof(struct sockaddr_storage) to return msg_name to the user. This prevents numerous uninitialized memory leaks we had in the recvmsg handlers and makes it harder for new code to accidentally leak uninitialized memory. Optimize for the case recvfrom is called with NULL as address. We don't need to copy the address at all, so set it to NULL before invoking the recvmsg handler. We can do so, because all the recvmsg handlers must cope with the case a plain read() is called on them. read() also sets msg_name to NULL. Also document these changes in include/linux/net.h as suggested by David Miller. Changes since RFC: Set msg->msg_name = NULL if user specified a NULL in msg_name but had a non-null msg_namelen in verify_iovec/verify_compat_iovec. This doesn't affect sendto as it would bail out earlier while trying to copy-in the address. It also more naturally reflects the logic by the callers of verify_iovec. With this change in place I could remove " if (!uaddr || msg_sys->msg_namelen == 0) msg->msg_name = NULL ". This change does not alter the user visible error logic as we ignore msg_namelen as long as msg_name is NULL. Also remove two unnecessary curly brackets in ___sys_recvmsg and change comments to netdev style. Cc: David Miller Suggested-by: Eric Dumazet Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- net/tipc/socket.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'net/tipc/socket.c') diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 3906527259d1..3b61851bb927 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -980,9 +980,6 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock, goto exit; } - /* will be updated in set_orig_addr() if needed */ - m->msg_namelen = 0; - timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); restart: @@ -1091,9 +1088,6 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock, goto exit; } - /* will be updated in set_orig_addr() if needed */ - m->msg_namelen = 0; - target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len); timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); -- cgit v1.2.1 From 84602761ca4495dd409be936dfa93ed20c946684 Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Fri, 27 Dec 2013 10:18:28 +0800 Subject: tipc: fix deadlock during socket release A deadlock might occur if name table is withdrawn in socket release routine, and while packets are still being received from bearer. CPU0 CPU1 T0: recv_msg() release() T1: tipc_recv_msg() tipc_withdraw() T2: [grab node lock] [grab port lock] T3: tipc_link_wakeup_ports() tipc_nametbl_withdraw() T4: [grab port lock]* named_cluster_distribute() T5: wakeupdispatch() tipc_link_send() T6: [grab node lock]* The opposite order of holding port lock and node lock on above two different paths may result in a deadlock. If socket lock instead of port lock is used to protect port instance in tipc_withdraw(), the reverse order of holding port lock and node lock will be eliminated, as a result, the deadlock is killed as well. Reported-by: Lars Everbrand Reviewed-by: Erik Hugne Signed-off-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/socket.c | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) (limited to 'net/tipc/socket.c') diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 3b61851bb927..e741416d1d24 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -354,7 +354,7 @@ static int release(struct socket *sock) * Delete TIPC port; this ensures no more messages are queued * (also disconnects an active connection & sends a 'FIN-' to peer) */ - res = tipc_deleteport(tport->ref); + res = tipc_deleteport(tport); /* Discard any remaining (connection-based) messages in receive queue */ __skb_queue_purge(&sk->sk_receive_queue); @@ -386,30 +386,46 @@ static int release(struct socket *sock) */ static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len) { + struct sock *sk = sock->sk; struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr; - u32 portref = tipc_sk_port(sock->sk)->ref; + struct tipc_port *tport = tipc_sk_port(sock->sk); + int res = -EINVAL; - if (unlikely(!uaddr_len)) - return tipc_withdraw(portref, 0, NULL); + lock_sock(sk); + if (unlikely(!uaddr_len)) { + res = tipc_withdraw(tport, 0, NULL); + goto exit; + } - if (uaddr_len < sizeof(struct sockaddr_tipc)) - return -EINVAL; - if (addr->family != AF_TIPC) - return -EAFNOSUPPORT; + if (uaddr_len < sizeof(struct sockaddr_tipc)) { + res = -EINVAL; + goto exit; + } + if (addr->family != AF_TIPC) { + res = -EAFNOSUPPORT; + goto exit; + } if (addr->addrtype == TIPC_ADDR_NAME) addr->addr.nameseq.upper = addr->addr.nameseq.lower; - else if (addr->addrtype != TIPC_ADDR_NAMESEQ) - return -EAFNOSUPPORT; + else if (addr->addrtype != TIPC_ADDR_NAMESEQ) { + res = -EAFNOSUPPORT; + goto exit; + } if ((addr->addr.nameseq.type < TIPC_RESERVED_TYPES) && (addr->addr.nameseq.type != TIPC_TOP_SRV) && - (addr->addr.nameseq.type != TIPC_CFG_SRV)) - return -EACCES; + (addr->addr.nameseq.type != TIPC_CFG_SRV)) { + res = -EACCES; + goto exit; + } - return (addr->scope > 0) ? - tipc_publish(portref, addr->scope, &addr->addr.nameseq) : - tipc_withdraw(portref, -addr->scope, &addr->addr.nameseq); + res = (addr->scope > 0) ? + tipc_publish(tport, addr->scope, &addr->addr.nameseq) : + tipc_withdraw(tport, -addr->scope, &addr->addr.nameseq); +exit: + release_sock(sk); + return res; } /** -- cgit v1.2.1