Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S965201AbcCOJEM (ORCPT ); Tue, 15 Mar 2016 05:04:12 -0400 Received: from mail-wm0-f48.google.com ([74.125.82.48]:34889 "EHLO mail-wm0-f48.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S964881AbcCOJDv (ORCPT ); Tue, 15 Mar 2016 05:03:51 -0400 From: Alexander Potapenko To: edumazet@google.com, rweikusat@mobileactivedefense.com, davem@davemloft.net Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org Subject: [PATCH] af_unix: closed SOCK_SEQPACKET socketpair must get SIGPIPE Date: Tue, 15 Mar 2016 10:03:44 +0100 Message-Id: <1458032624-139688-1-git-send-email-glider@google.com> X-Mailer: git-send-email 2.7.0.rc3.207.g0ac5344 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 3068 Lines: 123 According to IEEE Std 1003.1, 2013, sending data to a SOCK_SEQPACKET socketpair with MSG_NOSIGNAL flag set must result in a SIGPIPE if the socket is no longer connected. I used the following program to check the kernel behavior: /*****************/ #include #include #include #include #include void PipeHandler(int sig) { fprintf(stderr, "Killed by SIGPIPE\n"); _exit(1); } int main(int argc, char *argv[]) { if (argc < 2) return 0; struct sigaction act; act.sa_handler = PipeHandler; sigaction(SIGPIPE, &act, NULL); int fds[2]; if (strcmp(argv[1], "seqpacket") == 0) { if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) == -1) return -1; } else { if (strcmp(argv[1], "stream") == 0) { if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1) return -1; } else { return -1; } } int flags = 0; if ((argc > 2) && (strcmp(argv[2], "nosignal") == 0)) flags = MSG_NOSIGNAL; struct msghdr msg; memset(&msg, 0, sizeof(msg)); close(fds[0]); const ssize_t r = sendmsg(fds[1], &msg, flags); if (r == -1) perror("sendmsg"); return 0; } /*****************/ Without the below patch the behavior is as follows: $ ./sock seqpacket sendmsg: Broken pipe $ ./sock stream Killed by SIGPIPE $ ./sock seqpacket nosignal sendmsg: Broken pipe $ ./sock stream nosignal sendmsg: Broken pipe The behavior of the patched kernel complies with POSIX: $ ./sock seqpacket Killed by SIGPIPE $ ./sock stream Killed by SIGPIPE $ ./sock seqpacket nosignal sendmsg: Broken pipe $ ./sock stream nosignal sendmsg: Broken pipe Signed-off-by: Alexander Potapenko --- net/unix/af_unix.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 8fbe6d7..ba34c73 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1645,6 +1645,7 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, struct sock *other = NULL; int namelen = 0; /* fake GCC */ int err; + bool send_sigpipe = false; unsigned int hash; struct sk_buff *skb; long timeo; @@ -1675,6 +1676,12 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, goto out; } + if (sk->sk_shutdown & SEND_SHUTDOWN && sock->type == SOCK_SEQPACKET) { + send_sigpipe = true; + err = -EPIPE; + goto out; + } + if (test_bit(SOCK_PASSCRED, &sock->flags) && !u->addr && (err = unix_autobind(sock)) != 0) goto out; @@ -1769,8 +1776,11 @@ restart_locked: } err = -EPIPE; - if (other->sk_shutdown & RCV_SHUTDOWN) + if (other->sk_shutdown & RCV_SHUTDOWN) { + if (sock->type == SOCK_SEQPACKET) + send_sigpipe = true; goto out_unlock; + } if (sk->sk_type != SOCK_SEQPACKET) { err = security_unix_may_send(sk->sk_socket, other->sk_socket); @@ -1837,6 +1847,8 @@ out: if (other) sock_put(other); scm_destroy(&scm); + if (send_sigpipe && !(msg->msg_flags & MSG_NOSIGNAL)) + send_sig(SIGPIPE, current, 0); return err; } -- 2.7.0.rc3.207.g0ac5344