1d39887f5SBreno Leitao // SPDX-License-Identifier: GPL-2.0 2d39887f5SBreno Leitao /* 3d39887f5SBreno Leitao * Quick test for getsockopt{_iter} tests. 4d39887f5SBreno Leitao * 5d39887f5SBreno Leitao * Each fixture targets one converted protocol and pins down the 6d39887f5SBreno Leitao * returned-length / errno semantics across buffer-size variations, 7d39887f5SBreno Leitao * an unknown optname and a bogus level. 8d39887f5SBreno Leitao * 9d39887f5SBreno Leitao * - netlink: NETLINK_PKTINFO covers the flag-style int path; the 10d39887f5SBreno Leitao * NETLINK_LIST_MEMBERSHIPS cases cover the size-discovery path 11d39887f5SBreno Leitao * that always reports the required buffer length back via optlen, 12d39887f5SBreno Leitao * even when the user buffer is too small to receive any group bits. 13d39887f5SBreno Leitao * - vsock: SO_VM_SOCKETS_BUFFER_SIZE covers the u64 path. 14d39887f5SBreno Leitao * 15d39887f5SBreno Leitao * Author: Breno Leitao <leitao@debian.org> 16d39887f5SBreno Leitao */ 17d39887f5SBreno Leitao 18d39887f5SBreno Leitao #include <errno.h> 19d39887f5SBreno Leitao #include <stdint.h> 20d39887f5SBreno Leitao #include <stdio.h> 21d39887f5SBreno Leitao #include <string.h> 22d39887f5SBreno Leitao #include <unistd.h> 23d39887f5SBreno Leitao #include <linux/netlink.h> 24d39887f5SBreno Leitao #include <linux/rtnetlink.h> 25*c8c2bd2bSBreno Leitao #include <linux/time_types.h> 26d39887f5SBreno Leitao #include <linux/vm_sockets.h> 27d39887f5SBreno Leitao #include <sys/socket.h> 28d39887f5SBreno Leitao #include "kselftest_harness.h" 29d39887f5SBreno Leitao 30d39887f5SBreno Leitao #ifndef AF_VSOCK 31d39887f5SBreno Leitao #define AF_VSOCK 40 32d39887f5SBreno Leitao #endif 33d39887f5SBreno Leitao 34d39887f5SBreno Leitao /* ---------- netlink ---------- */ 35d39887f5SBreno Leitao 36d39887f5SBreno Leitao FIXTURE(netlink) 37d39887f5SBreno Leitao { 38d39887f5SBreno Leitao int fd; 39d39887f5SBreno Leitao }; 40d39887f5SBreno Leitao 41d39887f5SBreno Leitao FIXTURE_SETUP(netlink) 42d39887f5SBreno Leitao { 43d39887f5SBreno Leitao int group = RTNLGRP_LINK; 44d39887f5SBreno Leitao 45d39887f5SBreno Leitao self->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 46d39887f5SBreno Leitao if (self->fd < 0) 47d39887f5SBreno Leitao SKIP(return, "AF_NETLINK socket: %s", strerror(errno)); 48d39887f5SBreno Leitao 49d39887f5SBreno Leitao /* Joining a multicast group grows nlk->ngroups so the 50d39887f5SBreno Leitao * NETLINK_LIST_MEMBERSHIPS path has a non-zero size to report. 51d39887f5SBreno Leitao */ 52d39887f5SBreno Leitao if (setsockopt(self->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, 53d39887f5SBreno Leitao &group, sizeof(group)) < 0) 54d39887f5SBreno Leitao SKIP(return, "NETLINK_ADD_MEMBERSHIP: %s", strerror(errno)); 55d39887f5SBreno Leitao } 56d39887f5SBreno Leitao 57d39887f5SBreno Leitao FIXTURE_TEARDOWN(netlink) 58d39887f5SBreno Leitao { 59d39887f5SBreno Leitao if (self->fd >= 0) 60d39887f5SBreno Leitao close(self->fd); 61d39887f5SBreno Leitao } 62d39887f5SBreno Leitao 63d39887f5SBreno Leitao TEST_F(netlink, pktinfo_exact) 64d39887f5SBreno Leitao { 65*c8c2bd2bSBreno Leitao socklen_t optlen; 66d39887f5SBreno Leitao int val = -1; 67*c8c2bd2bSBreno Leitao 68*c8c2bd2bSBreno Leitao optlen = sizeof(val); 69d39887f5SBreno Leitao 70d39887f5SBreno Leitao ASSERT_EQ(0, getsockopt(self->fd, SOL_NETLINK, NETLINK_PKTINFO, 71d39887f5SBreno Leitao &val, &optlen)); 72d39887f5SBreno Leitao ASSERT_EQ(sizeof(int), optlen); 73d39887f5SBreno Leitao ASSERT_TRUE(val == 0 || val == 1); 74d39887f5SBreno Leitao } 75d39887f5SBreno Leitao 76d39887f5SBreno Leitao TEST_F(netlink, pktinfo_oversize_clamped) 77d39887f5SBreno Leitao { 78d39887f5SBreno Leitao char buf[16] = {}; 79*c8c2bd2bSBreno Leitao socklen_t optlen; 80*c8c2bd2bSBreno Leitao 81*c8c2bd2bSBreno Leitao optlen = sizeof(buf); 82d39887f5SBreno Leitao 83d39887f5SBreno Leitao ASSERT_EQ(0, getsockopt(self->fd, SOL_NETLINK, NETLINK_PKTINFO, 84d39887f5SBreno Leitao buf, &optlen)); 85d39887f5SBreno Leitao ASSERT_EQ(sizeof(int), optlen); 86d39887f5SBreno Leitao } 87d39887f5SBreno Leitao 88d39887f5SBreno Leitao TEST_F(netlink, pktinfo_undersize) 89d39887f5SBreno Leitao { 90d39887f5SBreno Leitao char buf[2] = {}; 91*c8c2bd2bSBreno Leitao socklen_t optlen; 92*c8c2bd2bSBreno Leitao 93*c8c2bd2bSBreno Leitao optlen = sizeof(buf); 94d39887f5SBreno Leitao 95d39887f5SBreno Leitao ASSERT_EQ(-1, getsockopt(self->fd, SOL_NETLINK, NETLINK_PKTINFO, 96d39887f5SBreno Leitao buf, &optlen)); 97d39887f5SBreno Leitao ASSERT_EQ(EINVAL, errno); 98*c8c2bd2bSBreno Leitao ASSERT_EQ(sizeof(buf), optlen); 99d39887f5SBreno Leitao } 100d39887f5SBreno Leitao 101d39887f5SBreno Leitao TEST_F(netlink, list_memberships_size_discovery) 102d39887f5SBreno Leitao { 103d39887f5SBreno Leitao socklen_t optlen = 0; 104d39887f5SBreno Leitao char dummy; 105d39887f5SBreno Leitao 106d39887f5SBreno Leitao ASSERT_EQ(0, getsockopt(self->fd, SOL_NETLINK, 107d39887f5SBreno Leitao NETLINK_LIST_MEMBERSHIPS, 108d39887f5SBreno Leitao &dummy, &optlen)); 109d39887f5SBreno Leitao ASSERT_GT(optlen, 0); 110d39887f5SBreno Leitao ASSERT_EQ(0, optlen % sizeof(__u32)); 111d39887f5SBreno Leitao } 112d39887f5SBreno Leitao 113d39887f5SBreno Leitao TEST_F(netlink, list_memberships_full_read) 114d39887f5SBreno Leitao { 115d39887f5SBreno Leitao __u32 buf[64] = {}; 116*c8c2bd2bSBreno Leitao socklen_t optlen; 117*c8c2bd2bSBreno Leitao 118*c8c2bd2bSBreno Leitao optlen = sizeof(buf); 119d39887f5SBreno Leitao 120d39887f5SBreno Leitao ASSERT_EQ(0, getsockopt(self->fd, SOL_NETLINK, 121d39887f5SBreno Leitao NETLINK_LIST_MEMBERSHIPS, 122d39887f5SBreno Leitao buf, &optlen)); 123d39887f5SBreno Leitao ASSERT_GT(optlen, 0); 124d39887f5SBreno Leitao ASSERT_LE(optlen, sizeof(buf)); 125d39887f5SBreno Leitao ASSERT_EQ(0, optlen % sizeof(__u32)); 126d39887f5SBreno Leitao } 127d39887f5SBreno Leitao 128d39887f5SBreno Leitao TEST_F(netlink, bad_level) 129d39887f5SBreno Leitao { 130*c8c2bd2bSBreno Leitao socklen_t optlen; 131d39887f5SBreno Leitao int val; 132*c8c2bd2bSBreno Leitao 133*c8c2bd2bSBreno Leitao optlen = sizeof(val); 134d39887f5SBreno Leitao 135d39887f5SBreno Leitao ASSERT_EQ(-1, getsockopt(self->fd, SOL_SOCKET + 1, NETLINK_PKTINFO, 136d39887f5SBreno Leitao &val, &optlen)); 137d39887f5SBreno Leitao ASSERT_EQ(ENOPROTOOPT, errno); 138*c8c2bd2bSBreno Leitao ASSERT_EQ(sizeof(val), optlen); 139d39887f5SBreno Leitao } 140d39887f5SBreno Leitao 141d39887f5SBreno Leitao TEST_F(netlink, bad_optname) 142d39887f5SBreno Leitao { 143*c8c2bd2bSBreno Leitao socklen_t optlen; 144d39887f5SBreno Leitao int val; 145*c8c2bd2bSBreno Leitao 146*c8c2bd2bSBreno Leitao optlen = sizeof(val); 147d39887f5SBreno Leitao 148d39887f5SBreno Leitao ASSERT_EQ(-1, getsockopt(self->fd, SOL_NETLINK, 0x7fff, 149d39887f5SBreno Leitao &val, &optlen)); 150d39887f5SBreno Leitao ASSERT_EQ(ENOPROTOOPT, errno); 151*c8c2bd2bSBreno Leitao ASSERT_EQ(sizeof(val), optlen); 152d39887f5SBreno Leitao } 153d39887f5SBreno Leitao 154d39887f5SBreno Leitao /* ---------- vsock ---------- */ 155d39887f5SBreno Leitao 156d39887f5SBreno Leitao FIXTURE(vsock) 157d39887f5SBreno Leitao { 158d39887f5SBreno Leitao int fd; 159d39887f5SBreno Leitao }; 160d39887f5SBreno Leitao 161d39887f5SBreno Leitao FIXTURE_SETUP(vsock) 162d39887f5SBreno Leitao { 163d39887f5SBreno Leitao self->fd = socket(AF_VSOCK, SOCK_STREAM, 0); 164d39887f5SBreno Leitao if (self->fd < 0) 165d39887f5SBreno Leitao SKIP(return, "AF_VSOCK socket: %s", strerror(errno)); 166d39887f5SBreno Leitao } 167d39887f5SBreno Leitao 168d39887f5SBreno Leitao FIXTURE_TEARDOWN(vsock) 169d39887f5SBreno Leitao { 170d39887f5SBreno Leitao if (self->fd >= 0) 171d39887f5SBreno Leitao close(self->fd); 172d39887f5SBreno Leitao } 173d39887f5SBreno Leitao 174d39887f5SBreno Leitao TEST_F(vsock, buffer_size_exact) 175d39887f5SBreno Leitao { 176*c8c2bd2bSBreno Leitao socklen_t optlen; 177d39887f5SBreno Leitao uint64_t val = 0; 178*c8c2bd2bSBreno Leitao 179*c8c2bd2bSBreno Leitao optlen = sizeof(val); 180d39887f5SBreno Leitao 181d39887f5SBreno Leitao ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK, 182d39887f5SBreno Leitao SO_VM_SOCKETS_BUFFER_SIZE, 183d39887f5SBreno Leitao &val, &optlen)); 184d39887f5SBreno Leitao ASSERT_EQ(sizeof(uint64_t), optlen); 185d39887f5SBreno Leitao ASSERT_GT(val, 0); 186d39887f5SBreno Leitao } 187d39887f5SBreno Leitao 188d39887f5SBreno Leitao TEST_F(vsock, buffer_size_oversize_clamped) 189d39887f5SBreno Leitao { 190d39887f5SBreno Leitao char buf[16] = {}; 191*c8c2bd2bSBreno Leitao socklen_t optlen; 192*c8c2bd2bSBreno Leitao 193*c8c2bd2bSBreno Leitao optlen = sizeof(buf); 194d39887f5SBreno Leitao 195d39887f5SBreno Leitao ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK, 196d39887f5SBreno Leitao SO_VM_SOCKETS_BUFFER_SIZE, 197d39887f5SBreno Leitao buf, &optlen)); 198d39887f5SBreno Leitao ASSERT_EQ(sizeof(uint64_t), optlen); 199d39887f5SBreno Leitao } 200d39887f5SBreno Leitao 201d39887f5SBreno Leitao TEST_F(vsock, buffer_size_undersize) 202d39887f5SBreno Leitao { 203d39887f5SBreno Leitao char buf[4] = {}; 204*c8c2bd2bSBreno Leitao socklen_t optlen; 205*c8c2bd2bSBreno Leitao 206*c8c2bd2bSBreno Leitao optlen = sizeof(buf); 207d39887f5SBreno Leitao 208d39887f5SBreno Leitao ASSERT_EQ(-1, getsockopt(self->fd, AF_VSOCK, 209d39887f5SBreno Leitao SO_VM_SOCKETS_BUFFER_SIZE, 210d39887f5SBreno Leitao buf, &optlen)); 211d39887f5SBreno Leitao ASSERT_EQ(EINVAL, errno); 212*c8c2bd2bSBreno Leitao ASSERT_EQ(sizeof(buf), optlen); 213d39887f5SBreno Leitao } 214d39887f5SBreno Leitao 215d39887f5SBreno Leitao TEST_F(vsock, bad_level) 216d39887f5SBreno Leitao { 217*c8c2bd2bSBreno Leitao socklen_t optlen; 218d39887f5SBreno Leitao uint64_t val; 219*c8c2bd2bSBreno Leitao 220*c8c2bd2bSBreno Leitao optlen = sizeof(val); 221d39887f5SBreno Leitao 222d39887f5SBreno Leitao ASSERT_EQ(-1, getsockopt(self->fd, SOL_SOCKET + 1, 223d39887f5SBreno Leitao SO_VM_SOCKETS_BUFFER_SIZE, 224d39887f5SBreno Leitao &val, &optlen)); 225d39887f5SBreno Leitao ASSERT_EQ(ENOPROTOOPT, errno); 226*c8c2bd2bSBreno Leitao ASSERT_EQ(sizeof(val), optlen); 227d39887f5SBreno Leitao } 228d39887f5SBreno Leitao 229d39887f5SBreno Leitao TEST_F(vsock, bad_optname) 230d39887f5SBreno Leitao { 231*c8c2bd2bSBreno Leitao socklen_t optlen; 232d39887f5SBreno Leitao uint64_t val; 233*c8c2bd2bSBreno Leitao 234*c8c2bd2bSBreno Leitao optlen = sizeof(val); 235d39887f5SBreno Leitao 236d39887f5SBreno Leitao ASSERT_EQ(-1, getsockopt(self->fd, AF_VSOCK, 0x7fff, 237d39887f5SBreno Leitao &val, &optlen)); 238d39887f5SBreno Leitao ASSERT_EQ(ENOPROTOOPT, errno); 239*c8c2bd2bSBreno Leitao ASSERT_EQ(sizeof(val), optlen); 240*c8c2bd2bSBreno Leitao } 241*c8c2bd2bSBreno Leitao 242*c8c2bd2bSBreno Leitao /* SO_VM_SOCKETS_CONNECT_TIMEOUT_{NEW,OLD} return a sock_timeval-shaped 243*c8c2bd2bSBreno Leitao * payload, which is wider than u64 on 64-bit. They exercise the path 244*c8c2bd2bSBreno Leitao * where the protocol's reported lv (16 bytes) is larger than the 245*c8c2bd2bSBreno Leitao * common 8-byte u64 case covered above. 246*c8c2bd2bSBreno Leitao */ 247*c8c2bd2bSBreno Leitao TEST_F(vsock, connect_timeout_new_exact) 248*c8c2bd2bSBreno Leitao { 249*c8c2bd2bSBreno Leitao struct __kernel_sock_timeval tv = {}; 250*c8c2bd2bSBreno Leitao socklen_t optlen; 251*c8c2bd2bSBreno Leitao 252*c8c2bd2bSBreno Leitao optlen = sizeof(tv); 253*c8c2bd2bSBreno Leitao 254*c8c2bd2bSBreno Leitao ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK, 255*c8c2bd2bSBreno Leitao SO_VM_SOCKETS_CONNECT_TIMEOUT_NEW, 256*c8c2bd2bSBreno Leitao &tv, &optlen)); 257*c8c2bd2bSBreno Leitao ASSERT_EQ(sizeof(tv), optlen); 258*c8c2bd2bSBreno Leitao } 259*c8c2bd2bSBreno Leitao 260*c8c2bd2bSBreno Leitao TEST_F(vsock, connect_timeout_new_oversize_clamped) 261*c8c2bd2bSBreno Leitao { 262*c8c2bd2bSBreno Leitao char buf[sizeof(struct __kernel_sock_timeval) * 2] = {}; 263*c8c2bd2bSBreno Leitao socklen_t optlen; 264*c8c2bd2bSBreno Leitao 265*c8c2bd2bSBreno Leitao optlen = sizeof(buf); 266*c8c2bd2bSBreno Leitao 267*c8c2bd2bSBreno Leitao ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK, 268*c8c2bd2bSBreno Leitao SO_VM_SOCKETS_CONNECT_TIMEOUT_NEW, 269*c8c2bd2bSBreno Leitao buf, &optlen)); 270*c8c2bd2bSBreno Leitao ASSERT_EQ(sizeof(struct __kernel_sock_timeval), optlen); 271*c8c2bd2bSBreno Leitao } 272*c8c2bd2bSBreno Leitao 273*c8c2bd2bSBreno Leitao TEST_F(vsock, connect_timeout_new_undersize) 274*c8c2bd2bSBreno Leitao { 275*c8c2bd2bSBreno Leitao socklen_t optlen; 276*c8c2bd2bSBreno Leitao uint64_t val; 277*c8c2bd2bSBreno Leitao 278*c8c2bd2bSBreno Leitao optlen = sizeof(val); 279*c8c2bd2bSBreno Leitao 280*c8c2bd2bSBreno Leitao ASSERT_EQ(-1, getsockopt(self->fd, AF_VSOCK, 281*c8c2bd2bSBreno Leitao SO_VM_SOCKETS_CONNECT_TIMEOUT_NEW, 282*c8c2bd2bSBreno Leitao &val, &optlen)); 283*c8c2bd2bSBreno Leitao ASSERT_EQ(EINVAL, errno); 284*c8c2bd2bSBreno Leitao ASSERT_EQ(sizeof(val), optlen); 285*c8c2bd2bSBreno Leitao } 286*c8c2bd2bSBreno Leitao 287*c8c2bd2bSBreno Leitao TEST_F(vsock, connect_timeout_old_exact) 288*c8c2bd2bSBreno Leitao { 289*c8c2bd2bSBreno Leitao struct __kernel_old_timeval tv = {}; 290*c8c2bd2bSBreno Leitao socklen_t optlen; 291*c8c2bd2bSBreno Leitao 292*c8c2bd2bSBreno Leitao optlen = sizeof(tv); 293*c8c2bd2bSBreno Leitao 294*c8c2bd2bSBreno Leitao ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK, 295*c8c2bd2bSBreno Leitao SO_VM_SOCKETS_CONNECT_TIMEOUT_OLD, 296*c8c2bd2bSBreno Leitao &tv, &optlen)); 297*c8c2bd2bSBreno Leitao ASSERT_EQ(sizeof(tv), optlen); 298d39887f5SBreno Leitao } 299d39887f5SBreno Leitao 300d39887f5SBreno Leitao TEST_HARNESS_MAIN 301