From patchwork Tue Jul 19 12:54:00 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Riku Voipio X-Patchwork-Id: 650173 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3rv0Wb5VV2z9s2G for ; Tue, 19 Jul 2016 23:00:11 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b=RsFCAF6L; dkim-atps=neutral Received: from localhost ([::1]:55703 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bPUd6-0004oO-P1 for incoming@patchwork.ozlabs.org; Tue, 19 Jul 2016 09:00:08 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42805) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bPUXa-00073U-33 for qemu-devel@nongnu.org; Tue, 19 Jul 2016 08:54:27 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bPUXV-0003KW-1P for qemu-devel@nongnu.org; Tue, 19 Jul 2016 08:54:25 -0400 Received: from mail-lf0-x22b.google.com ([2a00:1450:4010:c07::22b]:35419) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bPUXU-0003KA-Lb for qemu-devel@nongnu.org; Tue, 19 Jul 2016 08:54:20 -0400 Received: by mail-lf0-x22b.google.com with SMTP id f93so13379377lfi.2 for ; Tue, 19 Jul 2016 05:54:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=LtO1Mjt9HY+fj7iZSw7yh+mlWOeKOUlRs2gRW9lRIwY=; b=RsFCAF6LdMSookfmA4qyy/7C5qnOWARM8KC5PvVOjyksz01KPbqXkjqOXlKTwAhLDA RRi8AsVNdgFIYRUThYCcUWaIIVWWt9x5C9dz6XC1gvDtyj0+Qvr5XdAaLV7SeK/oTjjA mL5/eInYYDLaFxO/pexu4C7AFTpnFXyRCbeDo= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=LtO1Mjt9HY+fj7iZSw7yh+mlWOeKOUlRs2gRW9lRIwY=; b=mWkZaMjcEpSVmAL5O6ThS7FKCLwvpYANCVAIokazKV/UL9R7QNEQghqKw0BEUArXP6 SXWonR/rIJYpw+h9xchK7b7LOk+ew53dcTQdX7zSprbKN9Mu+Ni6MTP6Qdq98XOzOjPE ez6W8XSlVbUpq9Xfym7WdO0HwOJ8OlwvHOSnt+5jNGPeleEB184pRmHEAtIXC74ttgfb cEtfIeX3ze7qB8ZcYFt8BAe0CYzLsxlHv3zEZSKuX2wI/1Pqz0/Tg+HWMfr+9J/H6hYL w+STv2OKg+m6O7eC5JAcPHNjui87KX6nY7j/gOx0wztwc4EzOXDCzK1ROysnPMFUrQMI +ToA== X-Gm-Message-State: ALyK8tK0tPwAnbj2HSUtV2NUVTeP7ztROL9Vl0y13uLE5aRHRo7PZhqtinVXYaLZw6hU9OQW X-Received: by 10.46.1.35 with SMTP id 35mr16025769ljb.8.1468932859539; Tue, 19 Jul 2016 05:54:19 -0700 (PDT) Received: from beaming.home (91-157-170-157.elisa-laajakaista.fi. [91.157.170.157]) by smtp.gmail.com with ESMTPSA id g3sm2248898lfe.14.2016.07.19.05.54.18 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 19 Jul 2016 05:54:18 -0700 (PDT) From: riku.voipio@linaro.org To: qemu-devel@nongnu.org Date: Tue, 19 Jul 2016 15:54:00 +0300 Message-Id: <7d61d892327d803ae43d14500601e48031b4632c.1468932683.git.riku.voipio@linaro.org> X-Mailer: git-send-email 2.1.4 In-Reply-To: References: X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2a00:1450:4010:c07::22b Subject: [Qemu-devel] [PULL 02/16] 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: Laurent Vivier Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Laurent Vivier 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 Signed-off-by: Riku Voipio --- 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 59defff..491ab55 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3017,13 +3017,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)); @@ -3239,6 +3248,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) { @@ -3249,23 +3259,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; }