Bug 156397
Summary: | LTC13414-32-bit ping6 on 64-bit kernel not working | ||||||
---|---|---|---|---|---|---|---|
Product: | Red Hat Enterprise Linux 3 | Reporter: | Issue Tracker <tao> | ||||
Component: | kernel | Assignee: | David Woodhouse <dwmw2> | ||||
Status: | CLOSED ERRATA | QA Contact: | Brian Brock <bbrock> | ||||
Severity: | medium | Docs Contact: | |||||
Priority: | medium | ||||||
Version: | 3.0 | CC: | davem, dhowells, jparadis, petrides, tao | ||||
Target Milestone: | --- | ||||||
Target Release: | --- | ||||||
Hardware: | All | ||||||
OS: | Linux | ||||||
Whiteboard: | |||||||
Fixed In Version: | RHSA-2006-0144 | Doc Type: | Bug Fix | ||||
Doc Text: | Story Points: | --- | |||||
Clone Of: | Environment: | ||||||
Last Closed: | 2006-03-15 15:57:43 UTC | Type: | --- | ||||
Regression: | --- | Mount Type: | --- | ||||
Documentation: | --- | CRM: | |||||
Verified Versions: | Category: | --- | |||||
oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |||||
Cloudforms Team: | --- | Target Upstream Version: | |||||
Embargoed: | |||||||
Bug Depends On: | |||||||
Bug Blocks: | 168424 | ||||||
Attachments: |
|
Description
Issue Tracker
2005-04-29 18:59:35 UTC
Okay... I borrowed an x86_64 machine that had RHEL-3 installed. The ping6 installed by default is 64-bit and works. If I stick a 32-bit i386 ping6 on there, that doesn't work, just like with ppc32/ppc64. It may still be in the arch 32->64 bit translation, since it's mostly the same for both archs. I used gdb to examine the parameters supplied to recvmsg() in userspace [strace won't show them unless the syscall returns successfully]: Breakpoint 1, 0x0ff4b8ec in recvmsg () from /lib/tls/libc.so.6 (gdb) i r $r3 $r4 $r5 r3 0x6 6 [arg 0: sockfd] r4 0xffffd618 4294956568 [arg 1: msg] r5 0x0 0 [arg 2: flags] (gdb) x/7 $r4 [struct msghdr *msg] 0xffffd618: 0xffffc598 [msg_name] 0x00000080 [msg_namelen == 128] 0xffffd640 [msg_iov] 0x00000001 [msg_iovlen] 0xffffd628: 0xffffc618 [msg_control] 0x00001000 [msg_controllen == 4096] 0x00000000 [msg_flags] (gdb) x/2 0xffffd640 [struct iovec *msg->msg_iovlen] 0xffffd640: 0x1003a008 [iov_base] 0x00001070 [iov_len == 4208] (gdb) fini Run till exit from #0 0x0ff4b8ec in recvmsg () from /lib/tls/libc.so.6 0x10003b14 in ?? () The parameters here look reasonable, and in any case, the syscall isn't returning EINVAL or EFAULT. I instrumented sys_recvmsg32() in the ppc64 kernel: + + printk("recvmsg(,{%p,%d,%p,%lu,%p,%lu,%x},,,)\n", + kern_msg.msg_name, kern_msg.msg_namelen, + kern_msg.msg_iov, (unsigned long) kern_msg.msg_iovlen, + kern_msg.msg_control, (unsigned long) kern_msg.msg_controllen, + kern_msg.msg_flags); + printk("iov[0] = {%p,%lu}\n", + kern_msg.msg_iov[0].iov_base, + kern_msg.msg_iov[0].iov_len); + printk("recvmsg(,,%d,%x,)\n", total_len, user_flags); + err = sock->ops->recvmsg(sock, &kern_msg, total_len, user_flags, &scm); + + printk("recvmsg() = %d\n", err); + Which gave results that look exactly like the userspace results, except where the addressed objects have been teleported to kernelspace: recvmsg(,{c00000000e0afb40,128,c00000000e0afa80,1,00000000ffffc618,4096,0},,,) iov[0] = {000000001003a008,4208} recvmsg(,,4208,0,) recvmsg() = -11 [EAGAIN] I've instrumented sys_recvmsg() too, to see how the parameters given to the 64-bit ping64 are arrayed when passed on to the protocol handler: ping6: recvmsg64() recvmsg64(, {c00000000ea4baa8,128,c00000000ea4b9e0,1,000001ff7fffe2a0,4096,0},,,) iov64[0] = {000000001003b010,4208} recvmsg64(,,4208,0,) recvmsg64() = 64 64 bytes from fec0:ac10:1269:4242:20e:a6ff:fe20:4978: icmp_seq=0 ttl=64 time=0.566 ms ping6: recvmsg64() recvmsg64(, {c00000000ea4baa8,128,c00000000ea4b9e0,1,000001ff7fffe2a0,4096,0},,,) iov64[0] = {000000001003b010,4208} recvmsg64(,,4208,40,) recvmsg64() = -11 Note that the first call to recvmsg() looks almost identical to the 32-bit version, apart from the fact that it returns successfully. The second call has an extra flag set (MSG_DONTWAIT I think), and fails with EAGAIN, but this seems reasonable as I think it's just to clean up extra copies of the ping reply. Fixing "hardware" field. Fixing "hardware" field back again. The problem here seems to be that the 32-bit compatibility setsockopt() in ppc64 and x86_64 manually swaps each pair of 32-bit words in the 'struct icmp6_filter' argument when setting a filter.... for (i = 0; i < 8; i += 2) { u32 tmp = kfilter.data[i]; kfilter.data[i] = kfilter.data[i + 1]; kfilter.data[i + 1] = tmp; } I don't quite understand why it's doing this, but just bypassing it and letting sockopt(SOL_ICMPV6, ICMPV6_FILTER) through unmangled appears to make ping6 work correctly. This also seems at first glance to match what the 2.6 kernel does. It seems strange that someone added code for doing a conversion which is entirely gratuitous though -- I need to double-check that removing it is really the correct thing to do. Definitely looks like it can go. Here's the patch where the offending code was removed from 2.6: http://www.kernel.org/git/?p=linux/kernel/git/tglx/history.git;a=commit;h=531066f2b238b5aef235be9027fa3464f6b2d125 I'll generate a patch for 2.4 to remove the various instances of the same conversion. Created attachment 120155 [details]
Patch.
Appears to affect only x86_64 and ppc64 (of the platforms we care about for
RHEL3).
A fix for this problem has just been committed to the RHEL3 U7 patch pool this evening (in kernel version 2.4.21-37.7.EL). An advisory has been issued which should help the problem described in this bug report. This report is therefore being closed with a resolution of ERRATA. For more information on the solution and/or where to find the updated files, please follow the link below. You may reopen this bug report if the solution does not work for you. http://rhn.redhat.com/errata/RHSA-2006-0144.html |