gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/socket_bind_to_device.cc (about) 1 // Copyright 2019 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <arpa/inet.h> 16 #include <linux/if_tun.h> 17 #include <net/if.h> 18 #include <netinet/in.h> 19 #include <sys/ioctl.h> 20 #include <sys/socket.h> 21 #include <sys/types.h> 22 #include <sys/un.h> 23 24 #include <cstdio> 25 #include <cstring> 26 #include <map> 27 #include <memory> 28 #include <unordered_map> 29 #include <unordered_set> 30 #include <utility> 31 #include <vector> 32 33 #include "gmock/gmock.h" 34 #include "gtest/gtest.h" 35 #include "test/syscalls/linux/ip_socket_test_util.h" 36 #include "test/syscalls/linux/socket_bind_to_device_util.h" 37 #include "test/util/capability_util.h" 38 #include "test/util/socket_util.h" 39 #include "test/util/test_util.h" 40 #include "test/util/thread_util.h" 41 42 namespace gvisor { 43 namespace testing { 44 45 using std::string; 46 47 // Test fixture for SO_BINDTODEVICE tests. 48 class BindToDeviceTest : public ::testing::TestWithParam<SocketKind> { 49 protected: 50 void SetUp() override { 51 printf("Testing case: %s\n", GetParam().description.c_str()); 52 ASSERT_TRUE(ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW))) 53 << "CAP_NET_RAW is required to use SO_BINDTODEVICE"; 54 55 interface_name_ = "eth1"; 56 auto interface_names = GetInterfaceNames(); 57 if (interface_names.find(interface_name_) == interface_names.end()) { 58 // Need a tunnel. 59 tunnel_ = ASSERT_NO_ERRNO_AND_VALUE(Tunnel::New()); 60 interface_name_ = tunnel_->GetName(); 61 ASSERT_FALSE(interface_name_.empty()); 62 } 63 socket_ = ASSERT_NO_ERRNO_AND_VALUE(GetParam().Create()); 64 } 65 66 string interface_name() const { return interface_name_; } 67 68 int socket_fd() const { return socket_->get(); } 69 70 private: 71 std::unique_ptr<Tunnel> tunnel_; 72 string interface_name_; 73 std::unique_ptr<FileDescriptor> socket_; 74 }; 75 76 constexpr char kIllegalIfnameChar = '/'; 77 78 // Tests getsockopt of the default value. 79 TEST_P(BindToDeviceTest, GetsockoptDefault) { 80 char name_buffer[IFNAMSIZ * 2]; 81 char original_name_buffer[IFNAMSIZ * 2]; 82 socklen_t name_buffer_size; 83 84 // Read the default SO_BINDTODEVICE. 85 memset(original_name_buffer, kIllegalIfnameChar, sizeof(name_buffer)); 86 for (size_t i = 0; i <= sizeof(name_buffer); i++) { 87 memset(name_buffer, kIllegalIfnameChar, sizeof(name_buffer)); 88 name_buffer_size = i; 89 EXPECT_THAT(getsockopt(socket_fd(), SOL_SOCKET, SO_BINDTODEVICE, 90 name_buffer, &name_buffer_size), 91 SyscallSucceedsWithValue(0)); 92 EXPECT_EQ(name_buffer_size, 0); 93 EXPECT_EQ(memcmp(name_buffer, original_name_buffer, sizeof(name_buffer)), 94 0); 95 } 96 } 97 98 // Tests setsockopt of invalid device name. 99 TEST_P(BindToDeviceTest, SetsockoptInvalidDeviceName) { 100 char name_buffer[IFNAMSIZ * 2]; 101 socklen_t name_buffer_size; 102 103 // Set an invalid device name. 104 memset(name_buffer, kIllegalIfnameChar, 5); 105 name_buffer_size = 5; 106 EXPECT_THAT(setsockopt(socket_fd(), SOL_SOCKET, SO_BINDTODEVICE, name_buffer, 107 name_buffer_size), 108 SyscallFailsWithErrno(ENODEV)); 109 } 110 111 // Tests setsockopt of a buffer with a valid device name but not 112 // null-terminated, with different sizes of buffer. 113 TEST_P(BindToDeviceTest, SetsockoptValidDeviceNameWithoutNullTermination) { 114 char name_buffer[IFNAMSIZ * 2]; 115 socklen_t name_buffer_size; 116 117 strncpy(name_buffer, interface_name().c_str(), interface_name().size() + 1); 118 // Intentionally overwrite the null at the end. 119 memset(name_buffer + interface_name().size(), kIllegalIfnameChar, 120 sizeof(name_buffer) - interface_name().size()); 121 for (size_t i = 1; i <= sizeof(name_buffer); i++) { 122 name_buffer_size = i; 123 SCOPED_TRACE(absl::StrCat("Buffer size: ", i)); 124 // It should only work if the size provided is exactly right. 125 if (name_buffer_size == interface_name().size()) { 126 EXPECT_THAT(setsockopt(socket_fd(), SOL_SOCKET, SO_BINDTODEVICE, 127 name_buffer, name_buffer_size), 128 SyscallSucceeds()); 129 } else { 130 EXPECT_THAT(setsockopt(socket_fd(), SOL_SOCKET, SO_BINDTODEVICE, 131 name_buffer, name_buffer_size), 132 SyscallFailsWithErrno(ENODEV)); 133 } 134 } 135 } 136 137 // Tests setsockopt of a buffer with a valid device name and null-terminated, 138 // with different sizes of buffer. 139 TEST_P(BindToDeviceTest, SetsockoptValidDeviceNameWithNullTermination) { 140 char name_buffer[IFNAMSIZ * 2]; 141 socklen_t name_buffer_size; 142 143 strncpy(name_buffer, interface_name().c_str(), interface_name().size() + 1); 144 // Don't overwrite the null at the end. 145 memset(name_buffer + interface_name().size() + 1, kIllegalIfnameChar, 146 sizeof(name_buffer) - interface_name().size() - 1); 147 for (size_t i = 1; i <= sizeof(name_buffer); i++) { 148 name_buffer_size = i; 149 SCOPED_TRACE(absl::StrCat("Buffer size: ", i)); 150 // It should only work if the size provided is at least the right size. 151 if (name_buffer_size >= interface_name().size()) { 152 EXPECT_THAT(setsockopt(socket_fd(), SOL_SOCKET, SO_BINDTODEVICE, 153 name_buffer, name_buffer_size), 154 SyscallSucceeds()); 155 } else { 156 EXPECT_THAT(setsockopt(socket_fd(), SOL_SOCKET, SO_BINDTODEVICE, 157 name_buffer, name_buffer_size), 158 SyscallFailsWithErrno(ENODEV)); 159 } 160 } 161 } 162 163 // Tests that setsockopt of an invalid device name doesn't unset the previous 164 // valid setsockopt. 165 TEST_P(BindToDeviceTest, SetsockoptValidThenInvalid) { 166 char name_buffer[IFNAMSIZ * 2]; 167 socklen_t name_buffer_size; 168 169 // Write successfully. 170 strncpy(name_buffer, interface_name().c_str(), sizeof(name_buffer)); 171 ASSERT_THAT(setsockopt(socket_fd(), SOL_SOCKET, SO_BINDTODEVICE, name_buffer, 172 sizeof(name_buffer)), 173 SyscallSucceeds()); 174 175 // Read it back successfully. 176 memset(name_buffer, kIllegalIfnameChar, sizeof(name_buffer)); 177 name_buffer_size = sizeof(name_buffer); 178 EXPECT_THAT(getsockopt(socket_fd(), SOL_SOCKET, SO_BINDTODEVICE, name_buffer, 179 &name_buffer_size), 180 SyscallSucceeds()); 181 EXPECT_EQ(name_buffer_size, interface_name().size() + 1); 182 EXPECT_STREQ(name_buffer, interface_name().c_str()); 183 184 // Write unsuccessfully. 185 memset(name_buffer, kIllegalIfnameChar, sizeof(name_buffer)); 186 name_buffer_size = 5; 187 EXPECT_THAT(setsockopt(socket_fd(), SOL_SOCKET, SO_BINDTODEVICE, name_buffer, 188 sizeof(name_buffer)), 189 SyscallFailsWithErrno(ENODEV)); 190 191 // Read it back successfully, it's unchanged. 192 memset(name_buffer, kIllegalIfnameChar, sizeof(name_buffer)); 193 name_buffer_size = sizeof(name_buffer); 194 EXPECT_THAT(getsockopt(socket_fd(), SOL_SOCKET, SO_BINDTODEVICE, name_buffer, 195 &name_buffer_size), 196 SyscallSucceeds()); 197 EXPECT_EQ(name_buffer_size, interface_name().size() + 1); 198 EXPECT_STREQ(name_buffer, interface_name().c_str()); 199 } 200 201 // Tests that setsockopt of zero-length string correctly unsets the previous 202 // value. 203 TEST_P(BindToDeviceTest, SetsockoptValidThenClear) { 204 char name_buffer[IFNAMSIZ * 2]; 205 socklen_t name_buffer_size; 206 207 // Write successfully. 208 strncpy(name_buffer, interface_name().c_str(), sizeof(name_buffer)); 209 EXPECT_THAT(setsockopt(socket_fd(), SOL_SOCKET, SO_BINDTODEVICE, name_buffer, 210 sizeof(name_buffer)), 211 SyscallSucceeds()); 212 213 // Read it back successfully. 214 memset(name_buffer, kIllegalIfnameChar, sizeof(name_buffer)); 215 name_buffer_size = sizeof(name_buffer); 216 EXPECT_THAT(getsockopt(socket_fd(), SOL_SOCKET, SO_BINDTODEVICE, name_buffer, 217 &name_buffer_size), 218 SyscallSucceeds()); 219 EXPECT_EQ(name_buffer_size, interface_name().size() + 1); 220 EXPECT_STREQ(name_buffer, interface_name().c_str()); 221 222 // Clear it successfully. 223 name_buffer_size = 0; 224 EXPECT_THAT(setsockopt(socket_fd(), SOL_SOCKET, SO_BINDTODEVICE, name_buffer, 225 name_buffer_size), 226 SyscallSucceeds()); 227 228 // Read it back successfully, it's cleared. 229 memset(name_buffer, kIllegalIfnameChar, sizeof(name_buffer)); 230 name_buffer_size = sizeof(name_buffer); 231 EXPECT_THAT(getsockopt(socket_fd(), SOL_SOCKET, SO_BINDTODEVICE, name_buffer, 232 &name_buffer_size), 233 SyscallSucceeds()); 234 EXPECT_EQ(name_buffer_size, 0); 235 } 236 237 // Tests that setsockopt of empty string correctly unsets the previous 238 // value. 239 TEST_P(BindToDeviceTest, SetsockoptValidThenClearWithNull) { 240 char name_buffer[IFNAMSIZ * 2]; 241 socklen_t name_buffer_size; 242 243 // Write successfully. 244 strncpy(name_buffer, interface_name().c_str(), sizeof(name_buffer)); 245 EXPECT_THAT(setsockopt(socket_fd(), SOL_SOCKET, SO_BINDTODEVICE, name_buffer, 246 sizeof(name_buffer)), 247 SyscallSucceeds()); 248 249 // Read it back successfully. 250 memset(name_buffer, kIllegalIfnameChar, sizeof(name_buffer)); 251 name_buffer_size = sizeof(name_buffer); 252 EXPECT_THAT(getsockopt(socket_fd(), SOL_SOCKET, SO_BINDTODEVICE, name_buffer, 253 &name_buffer_size), 254 SyscallSucceeds()); 255 EXPECT_EQ(name_buffer_size, interface_name().size() + 1); 256 EXPECT_STREQ(name_buffer, interface_name().c_str()); 257 258 // Clear it successfully. 259 memset(name_buffer, kIllegalIfnameChar, sizeof(name_buffer)); 260 name_buffer[0] = 0; 261 name_buffer_size = sizeof(name_buffer); 262 EXPECT_THAT(setsockopt(socket_fd(), SOL_SOCKET, SO_BINDTODEVICE, name_buffer, 263 name_buffer_size), 264 SyscallSucceeds()); 265 266 // Read it back successfully, it's cleared. 267 memset(name_buffer, kIllegalIfnameChar, sizeof(name_buffer)); 268 name_buffer_size = sizeof(name_buffer); 269 EXPECT_THAT(getsockopt(socket_fd(), SOL_SOCKET, SO_BINDTODEVICE, name_buffer, 270 &name_buffer_size), 271 SyscallSucceeds()); 272 EXPECT_EQ(name_buffer_size, 0); 273 } 274 275 // Tests getsockopt with different buffer sizes. 276 TEST_P(BindToDeviceTest, GetsockoptDevice) { 277 char name_buffer[IFNAMSIZ * 2]; 278 socklen_t name_buffer_size; 279 280 // Write successfully. 281 strncpy(name_buffer, interface_name().c_str(), sizeof(name_buffer)); 282 ASSERT_THAT(setsockopt(socket_fd(), SOL_SOCKET, SO_BINDTODEVICE, name_buffer, 283 sizeof(name_buffer)), 284 SyscallSucceeds()); 285 286 // Read it back at various buffer sizes. 287 for (size_t i = 0; i <= sizeof(name_buffer); i++) { 288 memset(name_buffer, kIllegalIfnameChar, sizeof(name_buffer)); 289 name_buffer_size = i; 290 SCOPED_TRACE(absl::StrCat("Buffer size: ", i)); 291 // Linux only allows a buffer at least IFNAMSIZ, even if less would suffice 292 // for this interface name. 293 if (name_buffer_size >= IFNAMSIZ) { 294 EXPECT_THAT(getsockopt(socket_fd(), SOL_SOCKET, SO_BINDTODEVICE, 295 name_buffer, &name_buffer_size), 296 SyscallSucceeds()); 297 EXPECT_EQ(name_buffer_size, interface_name().size() + 1); 298 EXPECT_STREQ(name_buffer, interface_name().c_str()); 299 } else { 300 EXPECT_THAT(getsockopt(socket_fd(), SOL_SOCKET, SO_BINDTODEVICE, 301 name_buffer, &name_buffer_size), 302 SyscallFailsWithErrno(EINVAL)); 303 EXPECT_EQ(name_buffer_size, i); 304 } 305 } 306 } 307 308 INSTANTIATE_TEST_SUITE_P(BindToDeviceTest, BindToDeviceTest, 309 ::testing::Values(IPv4UDPUnboundSocket(0), 310 IPv4TCPUnboundSocket(0))); 311 312 } // namespace testing 313 } // namespace gvisor