rust-netlink / netlink-sys

netlink sockets, with optional integration with tokio
Other
17 stars 11 forks source link

Test failures on big endian. #4

Open plugwash opened 2 years ago

plugwash commented 2 years ago

As a result of Debian CI tests I discovered that two tests in this package fail on big endian systems. The problem was initially discovered on s390x, but I was also able to reproduce it on powerpc and ppc64.

---- socket::test::options stdout ----
thread 'socket::test::options' panicked at 'assertion failed: sock.get_cap_ack().unwrap()', src/socket.rs:613:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- mio::tests::test_event_loop stdout ----
thread 'mio::tests::test_event_loop' panicked at 'assertion failed: !events.is_empty()', src/mio.rs:82:9

failures:
    mio::tests::test_event_loop
    socket::test::options

I started digging into the first of these failures, by writing a test program in C.

#include <asm/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <stdio.h>

int main() {
        int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
        printf("%d\n",fd);
        socklen_t len;
        int value;

        value = 0xdeadbeef;
        len = sizeof(value);
        getsockopt(fd,SOL_NETLINK, NETLINK_CAP_ACK, &value,&len);
        printf("%x %x\n",value,len);

        value = 1;
        setsockopt(fd,SOL_NETLINK, NETLINK_CAP_ACK, &value,sizeof(value));

        value = 0xdeadbeef;
        len = sizeof(value);
        getsockopt(fd,SOL_NETLINK, NETLINK_CAP_ACK, &value,&len);
        printf("%x %x\n",value,len);
}

The conclusion I came to is that contary to the documentation the getsockopt call only sets a single byte. On little endian systems this is the least significant byte and the code in netlink-sys works, however on big endian systems the byte set is the most significant byte and the code in netlink-sys doesn't work.

I belive this is a kernel issue, but a potential workaround is to use != 0 rather than == 1, this is consistent with how C/C++ programmers are likely to test the result of such a call (an if statement in C/C++ has an implicit != 0).