diff options
| author | Christian Krinitsin <mail@krinitsin.com> | 2025-07-03 19:39:53 +0200 |
|---|---|---|
| committer | Christian Krinitsin <mail@krinitsin.com> | 2025-07-03 19:39:53 +0200 |
| commit | dee4dcba78baf712cab403d47d9db319ab7f95d6 (patch) | |
| tree | 418478faf06786701a56268672f73d6b0b4eb239 /results/classifier/108/debug/2553 | |
| parent | 4d9e26c0333abd39bdbd039dcdb30ed429c475ba (diff) | |
| download | emulator-bug-study-dee4dcba78baf712cab403d47d9db319ab7f95d6.tar.gz emulator-bug-study-dee4dcba78baf712cab403d47d9db319ab7f95d6.zip | |
restructure results
Diffstat (limited to 'results/classifier/108/debug/2553')
| -rw-r--r-- | results/classifier/108/debug/2553 | 97 |
1 files changed, 0 insertions, 97 deletions
diff --git a/results/classifier/108/debug/2553 b/results/classifier/108/debug/2553 deleted file mode 100644 index 119ae6fe..00000000 --- a/results/classifier/108/debug/2553 +++ /dev/null @@ -1,97 +0,0 @@ -debug: 0.967 -performance: 0.960 -network: 0.957 -device: 0.949 -graphic: 0.945 -PID: 0.945 -socket: 0.933 -other: 0.931 -boot: 0.930 -files: 0.923 -permissions: 0.916 -semantic: 0.912 -KVM: 0.869 -vnc: 0.863 - -Joining IP multicast fails when emulating 64-bit Linux -Description of problem: -I have some code that joins IP multicast groups and I'd like to use QEMU to test it on big-endian and/or 32-bit platforms. But when I compile it for 64-bit big-endian platforms (e.g. PowerPC64) and run it under QEMU user-mode emulation, the setsockopt(IP_ADD_MEMBERSHIP) call fails with ENODEV. - -This appears to refer to the imr_ifindex ("interface index") field in struct ip_mreqn not being valid, which in turn appears to be because it's not being correctly marshalled from the binary under emulation, to the host's *actual* setsockopt system call. - -I *think* this may be because linux-user/syscall_defs.h (https://github.com/qemu/qemu/blob/master/linux-user/syscall_defs.h) contains the following at line 210: - -``` -struct target_ip_mreqn { - struct target_in_addr imr_multiaddr; - struct target_in_addr imr_address; - abi_long imr_ifindex; -}; -``` - -but the actual Linux ip_mreqn has imr_ifindex as an int (32-bit everywhere) not a long (64-bit on PPC64); the size of this structure is 12 on all Linux platforms. - -I opted to submit an issue instead of just patching it, in case there was some wider context I hadn't seen? -Steps to reproduce: -1. take the following C program (distilled from a larger program): - -``` -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <stdio.h> -#include <stdlib.h> - -int main(int argc, char *argv[]) -{ - int fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - perror("socket"); - return 1; - } - - struct ip_mreqn mreq; - mreq.imr_multiaddr.s_addr = inet_addr("239.255.255.250"); - mreq.imr_address.s_addr = htonl(INADDR_ANY); - mreq.imr_ifindex = 1; - int size = sizeof(mreq); - printf("size=%u\n", size); - if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, - (char*) &mreq, sizeof(mreq)) < 0) { - perror("setsockopt"); - return 1; - } - printf("OK\n"); - return 0; -} -``` - -2. confirm it works compiled native on amd64/x86_64: - -``` -[peter@amd64 misc]$ gcc mcast.c -o mcast -[peter@amd64 misc]$ ./mcast -size=12 -OK -``` - -3. watch it *not* work emulated: - -``` -[peter@amd64 misc]$ powerpc64-linux-gnu-gcc mcast.c -o mcast.ppc64 -[peter@amd64 misc]$ QEMU_LD_PREFIX=/usr/powerpc64-linux-gnu qemu-ppc64 ./mcast.ppc64 -size=12 -setsockopt: No such device -``` -Additional information: -If the target_ip_mreqn issue is real, the following code in syscall.c helped conceal it: - - if (optlen < sizeof (struct target_ip_mreq) || - optlen > sizeof (struct target_ip_mreqn)) { - return -TARGET_EINVAL; - } - -Should this instead be testing for size equal to target_ip_mreq or equal to target_ip_mreqn, not anywhere in between? in this case target_ip_mreq is 8 bytes, target_ip_mreqn is 16 bytes, but optlen is 12. The end result is that QEMU passes 4 bytes of uninitialised stack memory as imr_ifindex! - -The actual kernel behaviour appears to be: smaller than ip_mreq, EINVAL; between ip_mreq and ip_mreqn, silently treat as ip_mreq; larger or equal to ip_mreqn, silently treat as ip_mreqn. see https://github.com/torvalds/linux/blob/b31c4492884252a8360f312a0ac2049349ddf603/net/ipv4/ip_sockglue.c#L1234 |