swrap: call libc_write() directly for internal fds
authorStefan Metzmacher <metze@samba.org>
Wed, 17 Feb 2021 10:00:53 +0000 (11:00 +0100)
committerAndreas Schneider <asn@samba.org>
Mon, 15 Mar 2021 07:04:58 +0000 (08:04 +0100)
Otherwise we may deadlock with a backtrace like this:

swrap_accept():
 ...
 SWRAP_LOCK_SI(si);
 swrap_pcap_dump_packet() ->
   write() ->
     swrap_write() ->
       SWRAP_LOCK_SI(si) -> abort()

This can happen if libc_open() called from swrap_pcap_get_fd()
return a stale fd. This may happen if glibc calls socket()
and closes it with __close_nocancel() instead of close().

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14640

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
src/socket_wrapper.c

index b6c76372d770d2f078f127c7957179c84661368a..3bf60f1b557f5d103b7783bcc19c706ac2a9e87c 100644 (file)
@@ -3004,7 +3004,7 @@ static int swrap_pcap_get_fd(const char *fname)
                file_hdr.frame_max_len  = SWRAP_FRAME_LENGTH_MAX;
                file_hdr.link_type      = 0x0065; /* 101 RAW IP */
 
-               if (write(fd, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) {
+               if (libc_write(fd, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) {
                        libc_close(fd);
                        fd = -1;
                }
@@ -3339,7 +3339,7 @@ static void swrap_pcap_dump_packet(struct socket_info *si,
 
        fd = swrap_pcap_get_fd(file_name);
        if (fd != -1) {
-               if (write(fd, packet, packet_len) != (ssize_t)packet_len) {
+               if (libc_write(fd, packet, packet_len) != (ssize_t)packet_len) {
                        free(packet);
                        goto done;
                }
@@ -5546,7 +5546,7 @@ static int swrap_sendmsg_unix_scm_rights(const struct cmsghdr *cmsg,
                return -1;
        }
 
-       sret = write(pipefd[1], &info, sizeof(info));
+       sret = libc_write(pipefd[1], &info, sizeof(info));
        if (sret != sizeof(info)) {
                int saved_errno = errno;
                if (sret != -1) {