summaryrefslogtreecommitdiff
path: root/linux-user/syscall.c
diff options
context:
space:
mode:
authorJonathan Neuschäfer <j.neuschaefer@gmx.net>2015-09-03 07:27:26 +0200
committerRiku Voipio <riku.voipio@linaro.org>2015-09-28 16:39:43 +0300
commitee1045877a7e226945c7cec2bda80039bd2d0c8e (patch)
tree00161e36d739a5ccfb44e26d25f1708bb1ddc9ab /linux-user/syscall.c
parent59baae9a626396a3a05840279084c4bf2beb8f40 (diff)
downloadqemu-ee1045877a7e226945c7cec2bda80039bd2d0c8e.tar.gz
linux-user: fix cmsg conversion in case of multiple headers
Currently, __target_cmsg_nxthdr compares a pointer derived from target_cmsg against the msg_control field of target_msgh (through subtraction). This failed for me when emulating i386 code under x86_64, because pointers in the host address space and pointers in the guest address space were not the same. This patch passes the initial value of target_cmsg into __target_cmsg_nxthdr. I found and fixed two more related bugs: - __target_cmsg_nxthdr now returns the new cmsg pointer instead of the old one. - tgt_space (in host_to_target_cmsg) doesn't count "sizeof (struct target_cmsghdr)" twice anymore. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Jonathan Neuschäfer <j.neuschaefer@gmx.net> Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r--linux-user/syscall.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 7fbaa8bb67..75ac32c05d 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -1181,7 +1181,7 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
abi_long msg_controllen;
abi_ulong target_cmsg_addr;
- struct target_cmsghdr *target_cmsg;
+ struct target_cmsghdr *target_cmsg, *target_cmsg_start;
socklen_t space = 0;
msg_controllen = tswapal(target_msgh->msg_controllen);
@@ -1189,6 +1189,7 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
goto the_end;
target_cmsg_addr = tswapal(target_msgh->msg_control);
target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1);
+ target_cmsg_start = target_cmsg;
if (!target_cmsg)
return -TARGET_EFAULT;
@@ -1247,7 +1248,8 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
}
cmsg = CMSG_NXTHDR(msgh, cmsg);
- target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
+ target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
+ target_cmsg_start);
}
unlock_user(target_cmsg, target_cmsg_addr, 0);
the_end:
@@ -1261,7 +1263,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
abi_long msg_controllen;
abi_ulong target_cmsg_addr;
- struct target_cmsghdr *target_cmsg;
+ struct target_cmsghdr *target_cmsg, *target_cmsg_start;
socklen_t space = 0;
msg_controllen = tswapal(target_msgh->msg_controllen);
@@ -1269,6 +1271,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
goto the_end;
target_cmsg_addr = tswapal(target_msgh->msg_control);
target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0);
+ target_cmsg_start = target_cmsg;
if (!target_cmsg)
return -TARGET_EFAULT;
@@ -1382,14 +1385,15 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
}
target_cmsg->cmsg_len = tswapal(tgt_len);
- tgt_space = TARGET_CMSG_SPACE(tgt_len);
+ tgt_space = TARGET_CMSG_SPACE(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);
+ target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg,
+ target_cmsg_start);
}
unlock_user(target_cmsg, target_cmsg_addr, space);
the_end: