From patchwork Tue Jun 21 17:51:14 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 9191173 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 1811B6075E for ; Tue, 21 Jun 2016 17:52:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0D12128305 for ; Tue, 21 Jun 2016 17:52:12 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 01E922830A; Tue, 21 Jun 2016 17:52:11 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 6631128305 for ; Tue, 21 Jun 2016 17:52:11 +0000 (UTC) Received: from localhost ([::1]:53436 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bFPqM-0003T8-Fw for patchwork-qemu-devel@patchwork.kernel.org; Tue, 21 Jun 2016 13:52:10 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:34262) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bFPpu-0003R2-84 for qemu-devel@nongnu.org; Tue, 21 Jun 2016 13:51:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bFPpo-00032n-9c for qemu-devel@nongnu.org; Tue, 21 Jun 2016 13:51:41 -0400 Received: from mout.kundenserver.de ([212.227.17.24]:61907) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bFPpn-00032g-UY for qemu-devel@nongnu.org; Tue, 21 Jun 2016 13:51:36 -0400 Received: from Quad.localdomain ([78.238.229.36]) by mrelayeu.kundenserver.de (mreue101) with ESMTPSA (Nemesis) id 0LmLVi-1bpIY10EgU-00Zw0u; Tue, 21 Jun 2016 19:51:27 +0200 From: Laurent Vivier To: Riku Voipio Date: Tue, 21 Jun 2016 19:51:14 +0200 Message-Id: <1466531475-13389-3-git-send-email-laurent@vivier.eu> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1466531475-13389-1-git-send-email-laurent@vivier.eu> References: <1466531475-13389-1-git-send-email-laurent@vivier.eu> X-Provags-ID: V03:K0:0RiFi730rS/cUwW0bMaqYo17/TUf4gPId5+bYGQTzPxvum5RNLv jbBm+G3h5sMUAw6NECt2wv15kDtbYcq4XQ02RZGrmY0tFqz/vSL1yHb3i4IHaowoRVtnwg/ 2t41cewfbkp5rfRIEgXeuXAWrw5lJyNiTQEzc2FbdSUV4kzjwwA0cmUK8r0ZTKeBq8gcbX1 gMSrHRbBGsMGnFSPRDqsg== X-UI-Out-Filterresults: notjunk:1; V01:K0:F4VpDpLhm08=:xrvenHF9bx1JWUYXZ/bM70 zzbGUqfWxQuO9ndWlgJEKw+wFmqhgl8XPEmR7MM04mk7GZNt+mD7rdyxCV8q/VomHmGumRnRQ HMaPuF1R1YeP4WESAf5zU3YEuIiutBRtZkKvjuQBL/q6hn355rLAharIwoIJxJpJtxUEmVIRS /D2wRf6/PJWH03+6WCYpbcYizhh53eU0vYsdglY0j62+MAXu2n3kZ6Y5IPZUG7+Tc0OaCBJps nrY7u8zproPt+VtgwYtlUD9sdZTbBHmwMN6RpOynwZ4Xj6xksB2/qC+PsM/xHNoku2e1GIRlY 8VLi3gLEcFVI3qjk1Zl+92ikwOVnkJBxDxurZJMFsw3iBDn1mnP41703tQbdvn1dvgO/0OhCj woeDfQrKwKhCtP/TkxBiny8vk0cbAZBzivjUR8jTjZAaaWFZsa4lftNquz7a+A1FusJXNMD6z kzu+1K6jXT2bMcZj8ewjEOs2jdtkZ40Svzt+5FSvUUu2LVQpoLamB+JbFLa8kSV6JJQCjUrXY 1PNm1ZL+OmTm1VBfkRRvJkd6LHFXlfPOWWWIIur6HHW4qphC1u3z5xgSpvw2gQZyeDzg1u1rq F+EA2KAOVTiWpJl80wEEGsqIwUUPMsndkwB60D72CzTd5Gu/QLWbvIAXIPpzCimapOhlL8wEG 0nP8AcgpV23dUPIiTf7jzW+aemiY3qtSUI58QE7uBVybPiFkCLBc4jomw9RkvvJ/Wtm0= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 212.227.17.24 Subject: [Qemu-devel] [PATCH 2/3] linux-user: fix netlink memory corruption X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: qemu-devel@nongnu.org, Laurent Vivier Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Netlink is byte-swapping data in the guest memory (it's bad). It's ok when the data come from the host as they are generated by the host. But it doesn't work when data come from the guest: the guest can try to reuse these data whereas they have been byte-swapped. This is what happens in glibc: glibc generates a sequence number in nlh.nlmsg_seq and calls sendto() with this nlh. In sendto(), we byte-swap nlmsg.seq. Later, after the recvmsg(), glibc compares nlh.nlmsg_seq with sequence number given in return, and of course it fails (hangs), because nlh.nlmsg_seq is not valid anymore. The involved code in glibc is: sysdeps/unix/sysv/linux/check_pf.c:make_request() ... req.nlh.nlmsg_seq = time (NULL); ... if (TEMP_FAILURE_RETRY (__sendto (fd, (void *) &req, sizeof (req), 0, (struct sockaddr *) &nladdr, sizeof (nladdr))) < 0) ... do { ... ssize_t read_len = TEMP_FAILURE_RETRY (__recvmsg (fd, &msg, 0)); ... struct nlmsghdr *nlmh; for (nlmh = (struct nlmsghdr *) buf; NLMSG_OK (nlmh, (size_t) read_len); nlmh = (struct nlmsghdr *) NLMSG_NEXT (nlmh, read_len)) { nlmsg_seq with corrupted req.nlh.nlmsg_seq> if (nladdr.nl_pid != 0 || (pid_t) nlmh->nlmsg_pid != pid || nlmh->nlmsg_seq != req.nlh.nlmsg_seq) continue; ... else if (nlmh->nlmsg_type == NLMSG_DONE) /* We found the end, leave the loop. */ done = true; } } while (! done); As we have a continue on "nlmh->nlmsg_seq != req.nlh.nlmsg_seq", "done" cannot be set to "true" and we have an infinite loop. It's why commands like "apt-get update" or "dnf update hangs". Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9a5cd26..fdc884f 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3012,13 +3012,22 @@ static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp, if (send) { if (fd_trans_target_to_host_data(fd)) { - ret = fd_trans_target_to_host_data(fd)(msg.msg_iov->iov_base, + void *host_msg; + + host_msg = g_malloc(msg.msg_iov->iov_len); + memcpy(host_msg, msg.msg_iov->iov_base, msg.msg_iov->iov_len); + ret = fd_trans_target_to_host_data(fd)(host_msg, msg.msg_iov->iov_len); + if (ret >= 0) { + msg.msg_iov->iov_base = host_msg; + ret = get_errno(safe_sendmsg(fd, &msg, flags)); + } + g_free(host_msg); } else { ret = target_to_host_cmsg(&msg, msgp); - } - if (ret == 0) { - ret = get_errno(safe_sendmsg(fd, &msg, flags)); + if (ret == 0) { + ret = get_errno(safe_sendmsg(fd, &msg, flags)); + } } } else { ret = get_errno(safe_recvmsg(fd, &msg, flags)); @@ -3234,6 +3243,7 @@ static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags, { void *addr; void *host_msg; + void *copy_msg = NULL; abi_long ret; if ((int)addrlen < 0) { @@ -3244,23 +3254,29 @@ static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags, if (!host_msg) return -TARGET_EFAULT; if (fd_trans_target_to_host_data(fd)) { + copy_msg = host_msg; + host_msg = g_malloc(len); + memcpy(host_msg, copy_msg, len); ret = fd_trans_target_to_host_data(fd)(host_msg, len); if (ret < 0) { - unlock_user(host_msg, msg, 0); - return ret; + goto fail; } } if (target_addr) { addr = alloca(addrlen+1); ret = target_to_host_sockaddr(fd, addr, target_addr, addrlen); if (ret) { - unlock_user(host_msg, msg, 0); - return ret; + goto fail; } ret = get_errno(safe_sendto(fd, host_msg, len, flags, addr, addrlen)); } else { ret = get_errno(safe_sendto(fd, host_msg, len, flags, NULL, 0)); } +fail: + if (copy_msg) { + g_free(host_msg); + host_msg = copy_msg; + } unlock_user(host_msg, msg, 0); return ret; }