Accept uevent netlink sockets as silent
[!NOTE]
First piece of the general USB translation layer discussed in #319; it stands alone as a bug fix and does not depend on the rest of that series.
Summary
socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT) now returns a working silent socket. libusb's non-udev build refuses to initialize at all without one (linux_usbfs.c:416-430 aborts libusb_init when the hotplug monitor cannot start), so every libusb program in a guest died at init, whether or not it ever touched a device.
What
NETLINK_KOBJECT_UEVENTsockets are accepted next toNETLINK_ROUTE: never readable, sopolltimes out and a non-blockingrecvreportsEAGAIN, which is what a real Linux kernel with no hotplug activity looks like. Synthesizing uevents on device attach is deliberately out of scope here.sendtoon a uevent socket reportsEPERM, matchinguevent_net_rcv_skb()for a sender withoutCAP_SYS_ADMIN.SOL_SOCKEToptions work on netlink fds; they previously failedEBADFbecause the sockopt path accepted onlyFD_SOCKET. The set followssk_setsockopt()/sk_getsockopt()rather than accepting everything:SO_RCVBUF/SO_SNDBUFclamp tormem_max/wmem_maxas an unsigned value, double, then floor atSOCK_MIN_RCVBUF(2304) orSOCK_MIN_SNDBUF(4608), which differ;SO_RCVTIMEOis honored by the blocking receive path (deadline taken once on entry,EAGAINon expiry) rather than accepted and dropped;SO_LINGERand the timeout options require their real payload length (8 and 16) instead of four bytes;SO_DEBUGwith a nonzero value needsCAP_NET_ADMIN(EACCES);SO_REUSEPORTwith a nonzero value isEOPNOTSUPPon a non-inet socket;SO_SNDLOWAThas no setter at all (ENOPROTOOPT); and everything settable reads back throughgetsockoptwith the right payload length. Unrecognized options reportENOPROTOOPT.SOCK_NONBLOCK/SOCK_CLOEXECare now published into the fd's linux_flags. That was dropped before, and it affectedNETLINK_ROUTEsockets too.- New guest test
tests/test-uevent-socket.c, wired intotest-matrix.sh. Its assertions also hold on a real Linux kernel: a payload belowNLMSG_HDRLENis swallowed there andsendtoreturns its length, so the test accepts either outcome and pinsEPERMwhenever the send fails.
Evidence
A statically linked libusb test (current libusb git, --disable-udev, so the netlink monitor is the one in play), run under the same host and guest binary on both sides:
upstream main 628181b: libusb_init = -99 (LIBUSB_ERROR_OTHER)
this branch: libusb_init = 0 (LIBUSB_SUCCESS)
get_device_list = 0
get_device_list returns 0 because enumeration needs the synthetic /sys/bus/usb and /dev/bus/usb trees that come later in the series; init succeeding is what this change is for.
test-uevent-socket under elfuse: 40 passed, 0 failed
test-matrix elfuse-aarch64: 266 passed, 0 failed, 10 skipped
The test asserts relations rather than constants, because the floors derive from sizeof(struct sk_buff) and the caps are sysctls: the send floor is checked to be exactly twice the receive floor, -1 and INT_MAX are checked to read back equal, and the honored SO_RCVTIMEO is timed with a jiffy of slack. Those assertions hold on a real Linux kernel, which matters because this test runs in the qemu-aarch64 matrix lane as well.
make check exits 0 on a clean rebuild (host suite 27/27, guardrail PASS), and the NETLINK_ROUTE behavior is unchanged.