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