From patchwork Tue May 26 18:46:31 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 48994 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-wi0-f198.google.com (mail-wi0-f198.google.com [209.85.212.198]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 5970C202A3 for ; Tue, 26 May 2015 18:46:45 +0000 (UTC) Received: by wifq9 with SMTP id q9sf23991107wif.3 for ; Tue, 26 May 2015 11:46:44 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :list-post:list-help:list-archive:list-unsubscribe; bh=mmbWSQuwo9RxNzfZxpzyAwu1NH/QUwkBg9mXAJ58tDs=; b=QLw+yqdiC9GJ9H3rdHikP0fLFDaVAUzTtw6es8/UNG7Eq3/iH6HIHEpfKgFW6u7sBm U7vg6c6DiEnc1aUcpFIwWiq8gTQIbhHht4cQPYPLCI+10uyfKHhZvtgPQPev0+cHZAY+ dllYh9hrWDBRYBldIeCJG7JFSqzMlrsMDEV/lOf3+tpkYUhdVa70T2VMcRp/j1JPzCeQ x5Ra5fh/nXjJ6vHnvKr4zoCzdZnp8FQn9RmgbMGnuXOBza+i7galqaPRenGsacXWTMpL n2uieUD68oYoB5Y5W4IUbCVD92YXrZ+BsO3eqUdQdx9L3CFyfyyuJFPmkhKk1yMFc7bw 9SwQ== X-Gm-Message-State: ALoCoQlRXb6ZGuXkxN7SAlN+YlIHPxHzAk4R34wDqHoe6nLF0RzD9dXueNQ4OEk6l0jyA/GPAVKu X-Received: by 10.152.184.73 with SMTP id es9mr28581780lac.4.1432666004677; Tue, 26 May 2015 11:46:44 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.36.65 with SMTP id o1ls946584laj.108.gmail; Tue, 26 May 2015 11:46:44 -0700 (PDT) X-Received: by 10.152.206.75 with SMTP id lm11mr23667237lac.41.1432666004515; Tue, 26 May 2015 11:46:44 -0700 (PDT) Received: from mail-la0-f49.google.com (mail-la0-f49.google.com. [209.85.215.49]) by mx.google.com with ESMTPS id es16si11613203lbc.122.2015.05.26.11.46.44 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 26 May 2015 11:46:44 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.49 as permitted sender) client-ip=209.85.215.49; Received: by lagv1 with SMTP id v1so74179356lag.3 for ; Tue, 26 May 2015 11:46:44 -0700 (PDT) X-Received: by 10.153.6.36 with SMTP id cr4mr24684168lad.56.1432666004318; Tue, 26 May 2015 11:46:44 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.112.108.230 with SMTP id hn6csp2751552lbb; Tue, 26 May 2015 11:46:43 -0700 (PDT) X-Received: by 10.66.140.36 with SMTP id rd4mr51329146pab.109.1432666002285; Tue, 26 May 2015 11:46:42 -0700 (PDT) Received: from mnementh.archaic.org.uk (mnementh.archaic.org.uk. [2001:8b0:1d0::1]) by mx.google.com with ESMTPS id pn6si22203998pdb.15.2015.05.26.11.46.39 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Tue, 26 May 2015 11:46:41 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::1 as permitted sender) client-ip=2001:8b0:1d0::1; Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.80) (envelope-from ) id 1YxJs1-0008Ug-0t; Tue, 26 May 2015 19:46:33 +0100 From: Peter Maydell To: qemu-devel@nongnu.org Cc: patches@linaro.org, Riku Voipio Subject: [PATCH 1/2] linux-user: Fix length handling in host_to_target_cmsg Date: Tue, 26 May 2015 19:46:31 +0100 Message-Id: <1432665992-32622-2-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1432665992-32622-1-git-send-email-peter.maydell@linaro.org> References: <1432665992-32622-1-git-send-email-peter.maydell@linaro.org> X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: peter.maydell@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.49 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , The previous code for handling payload length when converting cmsg structures from host to target had a number of problems: * we required the msg->msg_controllen to declare the buffer to have enough space for final trailing padding (we were checking against CMSG_SPACE), whereas the kernel does not require this, and common userspace code assumes this. (In particular, glibc's "try to talk to nscd" code that it will run on startup will receive a cmsg with a 4 byte payload and only allocate 4 bytes for it, which was causing us to do the wrong thing on architectures that need 8-alignment.) * we weren't correctly handling the fact that the SO_TIMESTAMP payload may be larger for the target than the host * we weren't marking the messages with MSG_CTRUNC when we did need to truncate a message that wasn't truncated by the host, but were instead logging a QEMU message; since truncation is always the result of a guest giving us an insufficiently sized buffer, we should report it to the guest as the kernel does and don't log anything Rewrite the parts of the function that deal with length to fix these issues, and add a comment in target_to_host_cmsg to explain why the overflow logging it does is a QEMU bug, not a guest issue. Signed-off-by: Peter Maydell --- linux-user/syscall.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 8 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1622ad6..3db6a90 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1202,6 +1202,15 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh, space += CMSG_SPACE(len); if (space > msgh->msg_controllen) { space -= CMSG_SPACE(len); + /* This is a QEMU bug, since we allocated the payload + * area ourselves (unlike overflow in host-to-target + * conversion, which is just the guest giving us a buffer + * that's too small). It can't happen for the payload types + * we currently support; if it becomes an issue in future + * we would need to improve our allocation strategy to + * something more intelligent than "twice the size of the + * target buffer we're reading from". + */ gemu_log("Host cmsg overflow\n"); break; } @@ -1267,11 +1276,16 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, void *target_data = TARGET_CMSG_DATA(target_cmsg); int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr)); + int tgt_len, tgt_space; - space += TARGET_CMSG_SPACE(len); - if (space > msg_controllen) { - space -= TARGET_CMSG_SPACE(len); - gemu_log("Target cmsg overflow\n"); + /* We never copy a half-header but may copy half-data; + * this is Linux's behaviour in put_cmsg(). Note that + * truncation here is a guest problem (which we report + * to the guest via the CTRUNC bit), unlike truncation + * in target_to_host_cmsg, which is a QEMU bug. + */ + if (msg_controllen < sizeof(struct cmsghdr)) { + target_msgh->msg_flags |= tswap32(MSG_CTRUNC); break; } @@ -1281,8 +1295,35 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level); } target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type); - target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len)); + tgt_len = TARGET_CMSG_LEN(len); + + /* Payload types which need a different size of payload on + * the target must adjust tgt_len here. + */ + switch (cmsg->cmsg_level) { + case SOL_SOCKET: + switch (cmsg->cmsg_type) { + case SO_TIMESTAMP: + tgt_len = sizeof(struct target_timeval); + break; + default: + break; + } + default: + break; + } + + if (msg_controllen < tgt_len) { + target_msgh->msg_flags |= tswap32(MSG_CTRUNC); + tgt_len = msg_controllen; + } + + /* We must now copy-and-convert len bytes of payload + * into tgt_len bytes of destination space. Bear in mind + * that in both source and destination we may be dealing + * with a truncated value! + */ switch (cmsg->cmsg_level) { case SOL_SOCKET: switch (cmsg->cmsg_type) { @@ -1290,7 +1331,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, { int *fd = (int *)data; int *target_fd = (int *)target_data; - int i, numfds = len / sizeof(int); + int i, numfds = tgt_len / sizeof(int); for (i = 0; i < numfds; i++) target_fd[i] = tswap32(fd[i]); @@ -1302,8 +1343,10 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, struct target_timeval *target_tv = (struct target_timeval *)target_data; - if (len != sizeof(struct timeval)) + if (len != sizeof(struct timeval) || + tgt_len != sizeof(struct target_timeval)) { goto unimplemented; + } /* copy struct timeval to target */ target_tv->tv_sec = tswapal(tv->tv_sec); @@ -1330,9 +1373,19 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, unimplemented: gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type); - memcpy(target_data, data, len); + memcpy(target_data, data, MIN(len, tgt_len)); + if (tgt_len > len) { + memset(target_data + len, 0, tgt_len - len); + } } + target_cmsg->cmsg_len = tswapal(tgt_len); + tgt_space = TARGET_CMSG_SPACE(tgt_len); + if (msg_controllen < tgt_space) { + tgt_space = msg_controllen; + } + msg_controllen -= tgt_space; + space += tgt_space; cmsg = CMSG_NXTHDR(msgh, cmsg); target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg); }