gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/socket_ip_unbound.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 <netinet/in.h>
    17  #include <sys/socket.h>
    18  #include <sys/types.h>
    19  #include <sys/un.h>
    20  
    21  #include <cstdio>
    22  #include <cstring>
    23  
    24  #include "gmock/gmock.h"
    25  #include "gtest/gtest.h"
    26  #include "test/syscalls/linux/ip_socket_test_util.h"
    27  #include "test/util/socket_util.h"
    28  #include "test/util/test_util.h"
    29  
    30  namespace gvisor {
    31  namespace testing {
    32  
    33  // Test fixture for tests that apply to pairs of IP sockets.
    34  using IPUnboundSocketTest = SimpleSocketTest;
    35  
    36  TEST_P(IPUnboundSocketTest, TtlDefault) {
    37    auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
    38  
    39    int get = -1;
    40    socklen_t get_sz = sizeof(get);
    41    EXPECT_THAT(getsockopt(socket->get(), IPPROTO_IP, IP_TTL, &get, &get_sz),
    42                SyscallSucceedsWithValue(0));
    43    EXPECT_TRUE(get == 64 || get == 127);
    44    EXPECT_EQ(get_sz, sizeof(get));
    45  }
    46  
    47  TEST_P(IPUnboundSocketTest, SetTtl) {
    48    auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
    49  
    50    int get1 = -1;
    51    socklen_t get1_sz = sizeof(get1);
    52    EXPECT_THAT(getsockopt(socket->get(), IPPROTO_IP, IP_TTL, &get1, &get1_sz),
    53                SyscallSucceedsWithValue(0));
    54    EXPECT_EQ(get1_sz, sizeof(get1));
    55  
    56    int set = 100;
    57    if (set == get1) {
    58      set += 1;
    59    }
    60    socklen_t set_sz = sizeof(set);
    61    EXPECT_THAT(setsockopt(socket->get(), IPPROTO_IP, IP_TTL, &set, set_sz),
    62                SyscallSucceedsWithValue(0));
    63  
    64    int get2 = -1;
    65    socklen_t get2_sz = sizeof(get2);
    66    EXPECT_THAT(getsockopt(socket->get(), IPPROTO_IP, IP_TTL, &get2, &get2_sz),
    67                SyscallSucceedsWithValue(0));
    68    EXPECT_EQ(get2_sz, sizeof(get2));
    69    EXPECT_EQ(get2, set);
    70  }
    71  
    72  TEST_P(IPUnboundSocketTest, ResetTtlToDefault) {
    73    auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
    74  
    75    int get1 = -1;
    76    socklen_t get1_sz = sizeof(get1);
    77    EXPECT_THAT(getsockopt(socket->get(), IPPROTO_IP, IP_TTL, &get1, &get1_sz),
    78                SyscallSucceedsWithValue(0));
    79    EXPECT_EQ(get1_sz, sizeof(get1));
    80  
    81    int set1 = 100;
    82    if (set1 == get1) {
    83      set1 += 1;
    84    }
    85    socklen_t set1_sz = sizeof(set1);
    86    EXPECT_THAT(setsockopt(socket->get(), IPPROTO_IP, IP_TTL, &set1, set1_sz),
    87                SyscallSucceedsWithValue(0));
    88  
    89    int set2 = -1;
    90    socklen_t set2_sz = sizeof(set2);
    91    EXPECT_THAT(setsockopt(socket->get(), IPPROTO_IP, IP_TTL, &set2, set2_sz),
    92                SyscallSucceedsWithValue(0));
    93  
    94    int get2 = -1;
    95    socklen_t get2_sz = sizeof(get2);
    96    EXPECT_THAT(getsockopt(socket->get(), IPPROTO_IP, IP_TTL, &get2, &get2_sz),
    97                SyscallSucceedsWithValue(0));
    98    EXPECT_EQ(get2_sz, sizeof(get2));
    99    EXPECT_TRUE(get2 == 64 || get2 == 127);
   100    EXPECT_EQ(get2, get1);
   101  }
   102  
   103  TEST_P(IPUnboundSocketTest, ZeroTtl) {
   104    auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
   105  
   106    int set = 0;
   107    socklen_t set_sz = sizeof(set);
   108    EXPECT_THAT(setsockopt(socket->get(), IPPROTO_IP, IP_TTL, &set, set_sz),
   109                SyscallFailsWithErrno(EINVAL));
   110  }
   111  
   112  TEST_P(IPUnboundSocketTest, InvalidLargeTtl) {
   113    auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
   114  
   115    int set = 256;
   116    socklen_t set_sz = sizeof(set);
   117    EXPECT_THAT(setsockopt(socket->get(), IPPROTO_IP, IP_TTL, &set, set_sz),
   118                SyscallFailsWithErrno(EINVAL));
   119  }
   120  
   121  TEST_P(IPUnboundSocketTest, InvalidNegativeTtl) {
   122    auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
   123  
   124    int set = -2;
   125    socklen_t set_sz = sizeof(set);
   126    EXPECT_THAT(setsockopt(socket->get(), IPPROTO_IP, IP_TTL, &set, set_sz),
   127                SyscallFailsWithErrno(EINVAL));
   128  }
   129  
   130  struct TOSOption {
   131    int level;
   132    int option;
   133    int cmsg_level;
   134  };
   135  
   136  constexpr int INET_ECN_MASK = 3;
   137  
   138  static TOSOption GetTOSOption(int domain) {
   139    TOSOption opt;
   140    switch (domain) {
   141      case AF_INET:
   142        opt.level = IPPROTO_IP;
   143        opt.option = IP_TOS;
   144        opt.cmsg_level = SOL_IP;
   145        break;
   146      case AF_INET6:
   147        opt.level = IPPROTO_IPV6;
   148        opt.option = IPV6_TCLASS;
   149        opt.cmsg_level = SOL_IPV6;
   150        break;
   151    }
   152    return opt;
   153  }
   154  
   155  TEST_P(IPUnboundSocketTest, TOSDefault) {
   156    auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
   157    TOSOption t = GetTOSOption(GetParam().domain);
   158    int get = -1;
   159    socklen_t get_sz = sizeof(get);
   160    constexpr int kDefaultTOS = 0;
   161    ASSERT_THAT(getsockopt(socket->get(), t.level, t.option, &get, &get_sz),
   162                SyscallSucceedsWithValue(0));
   163    EXPECT_EQ(get_sz, sizeof(get));
   164    EXPECT_EQ(get, kDefaultTOS);
   165  }
   166  
   167  TEST_P(IPUnboundSocketTest, SetTOS) {
   168    auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
   169    int set = 0xC0;
   170    socklen_t set_sz = sizeof(set);
   171    TOSOption t = GetTOSOption(GetParam().domain);
   172    EXPECT_THAT(setsockopt(socket->get(), t.level, t.option, &set, set_sz),
   173                SyscallSucceedsWithValue(0));
   174  
   175    int get = -1;
   176    socklen_t get_sz = sizeof(get);
   177    ASSERT_THAT(getsockopt(socket->get(), t.level, t.option, &get, &get_sz),
   178                SyscallSucceedsWithValue(0));
   179    EXPECT_EQ(get_sz, sizeof(get));
   180    EXPECT_EQ(get, set);
   181  }
   182  
   183  TEST_P(IPUnboundSocketTest, ZeroTOS) {
   184    auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
   185    int set = 0;
   186    socklen_t set_sz = sizeof(set);
   187    TOSOption t = GetTOSOption(GetParam().domain);
   188    EXPECT_THAT(setsockopt(socket->get(), t.level, t.option, &set, set_sz),
   189                SyscallSucceedsWithValue(0));
   190    int get = -1;
   191    socklen_t get_sz = sizeof(get);
   192    ASSERT_THAT(getsockopt(socket->get(), t.level, t.option, &get, &get_sz),
   193                SyscallSucceedsWithValue(0));
   194    EXPECT_EQ(get_sz, sizeof(get));
   195    EXPECT_EQ(get, set);
   196  }
   197  
   198  TEST_P(IPUnboundSocketTest, InvalidLargeTOS) {
   199    auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
   200    // Test with exceeding the byte space.
   201    int set = 256;
   202    constexpr int kDefaultTOS = 0;
   203    socklen_t set_sz = sizeof(set);
   204    TOSOption t = GetTOSOption(GetParam().domain);
   205    if (GetParam().domain == AF_INET) {
   206      EXPECT_THAT(setsockopt(socket->get(), t.level, t.option, &set, set_sz),
   207                  SyscallSucceedsWithValue(0));
   208    } else {
   209      EXPECT_THAT(setsockopt(socket->get(), t.level, t.option, &set, set_sz),
   210                  SyscallFailsWithErrno(EINVAL));
   211    }
   212    int get = -1;
   213    socklen_t get_sz = sizeof(get);
   214    ASSERT_THAT(getsockopt(socket->get(), t.level, t.option, &get, &get_sz),
   215                SyscallSucceedsWithValue(0));
   216    EXPECT_EQ(get_sz, sizeof(get));
   217    EXPECT_EQ(get, kDefaultTOS);
   218  }
   219  
   220  TEST_P(IPUnboundSocketTest, CheckSkipECN) {
   221    // Test is inconsistant on different kernels.
   222    SKIP_IF(!IsRunningOnGvisor() || IsRunningWithHostinet());
   223    auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
   224    int set = 0xFF;
   225    socklen_t set_sz = sizeof(set);
   226    TOSOption t = GetTOSOption(GetParam().domain);
   227    EXPECT_THAT(setsockopt(socket->get(), t.level, t.option, &set, set_sz),
   228                SyscallSucceedsWithValue(0));
   229    int expect = static_cast<uint8_t>(set);
   230    if (GetParam().protocol == IPPROTO_TCP) {
   231      expect &= ~INET_ECN_MASK;
   232    }
   233    int get = -1;
   234    socklen_t get_sz = sizeof(get);
   235    ASSERT_THAT(getsockopt(socket->get(), t.level, t.option, &get, &get_sz),
   236                SyscallSucceedsWithValue(0));
   237    EXPECT_EQ(get_sz, sizeof(get));
   238    EXPECT_EQ(get, expect);
   239  }
   240  
   241  TEST_P(IPUnboundSocketTest, ZeroTOSOptionSize) {
   242    auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
   243    int set = 0xC0;
   244    socklen_t set_sz = 0;
   245    TOSOption t = GetTOSOption(GetParam().domain);
   246    if (GetParam().domain == AF_INET) {
   247      EXPECT_THAT(setsockopt(socket->get(), t.level, t.option, &set, set_sz),
   248                  SyscallSucceedsWithValue(0));
   249    } else {
   250      EXPECT_THAT(setsockopt(socket->get(), t.level, t.option, &set, set_sz),
   251                  SyscallFailsWithErrno(EINVAL));
   252    }
   253    int get = -1;
   254    socklen_t get_sz = 0;
   255    ASSERT_THAT(getsockopt(socket->get(), t.level, t.option, &get, &get_sz),
   256                SyscallSucceedsWithValue(0));
   257    EXPECT_EQ(get_sz, 0);
   258    EXPECT_EQ(get, -1);
   259  }
   260  
   261  TEST_P(IPUnboundSocketTest, SmallTOSOptionSize) {
   262    auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
   263    int set = 0xC0;
   264    constexpr int kDefaultTOS = 0;
   265    TOSOption t = GetTOSOption(GetParam().domain);
   266    for (socklen_t i = 1; i < sizeof(int); i++) {
   267      int expect_tos;
   268      socklen_t expect_sz;
   269      if (GetParam().domain == AF_INET) {
   270        EXPECT_THAT(setsockopt(socket->get(), t.level, t.option, &set, i),
   271                    SyscallSucceedsWithValue(0));
   272        expect_tos = set;
   273        expect_sz = sizeof(uint8_t);
   274      } else {
   275        EXPECT_THAT(setsockopt(socket->get(), t.level, t.option, &set, i),
   276                    SyscallFailsWithErrno(EINVAL));
   277        expect_tos = kDefaultTOS;
   278        expect_sz = i;
   279      }
   280      uint get = -1;
   281      socklen_t get_sz = i;
   282      ASSERT_THAT(getsockopt(socket->get(), t.level, t.option, &get, &get_sz),
   283                  SyscallSucceedsWithValue(0));
   284      EXPECT_EQ(get_sz, expect_sz);
   285      // Account for partial copies by getsockopt, retrieve the lower
   286      // bits specified by get_sz, while comparing against expect_tos.
   287      EXPECT_EQ(get & ~(~static_cast<uint>(0) << (get_sz * 8)), expect_tos);
   288    }
   289  }
   290  
   291  TEST_P(IPUnboundSocketTest, LargeTOSOptionSize) {
   292    auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
   293    int set = 0xC0;
   294    TOSOption t = GetTOSOption(GetParam().domain);
   295    for (socklen_t i = sizeof(int); i < 10; i++) {
   296      EXPECT_THAT(setsockopt(socket->get(), t.level, t.option, &set, i),
   297                  SyscallSucceedsWithValue(0));
   298      int get = -1;
   299      socklen_t get_sz = i;
   300      // We expect the system call handler to only copy atmost sizeof(int) bytes
   301      // as asserted by the check below. Hence, we do not expect the copy to
   302      // overflow in getsockopt.
   303      ASSERT_THAT(getsockopt(socket->get(), t.level, t.option, &get, &get_sz),
   304                  SyscallSucceedsWithValue(0));
   305      EXPECT_EQ(get_sz, sizeof(int));
   306      EXPECT_EQ(get, set);
   307    }
   308  }
   309  
   310  TEST_P(IPUnboundSocketTest, NegativeTOS) {
   311    auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
   312  
   313    int set = -1;
   314    socklen_t set_sz = sizeof(set);
   315    TOSOption t = GetTOSOption(GetParam().domain);
   316    EXPECT_THAT(setsockopt(socket->get(), t.level, t.option, &set, set_sz),
   317                SyscallSucceedsWithValue(0));
   318    int expect;
   319    if (GetParam().domain == AF_INET) {
   320      expect = static_cast<uint8_t>(set);
   321      if (GetParam().protocol == IPPROTO_TCP) {
   322        expect &= ~INET_ECN_MASK;
   323      }
   324    } else {
   325      // On IPv6 TCLASS, setting -1 has the effect of resetting the
   326      // TrafficClass.
   327      expect = 0;
   328    }
   329    int get = -1;
   330    socklen_t get_sz = sizeof(get);
   331    ASSERT_THAT(getsockopt(socket->get(), t.level, t.option, &get, &get_sz),
   332                SyscallSucceedsWithValue(0));
   333    EXPECT_EQ(get_sz, sizeof(get));
   334    EXPECT_EQ(get, expect);
   335  }
   336  
   337  TEST_P(IPUnboundSocketTest, InvalidNegativeTOS) {
   338    auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
   339    int set = -2;
   340    socklen_t set_sz = sizeof(set);
   341    TOSOption t = GetTOSOption(GetParam().domain);
   342    int expect;
   343    if (GetParam().domain == AF_INET) {
   344      ASSERT_THAT(setsockopt(socket->get(), t.level, t.option, &set, set_sz),
   345                  SyscallSucceedsWithValue(0));
   346      expect = static_cast<uint8_t>(set);
   347      if (GetParam().protocol == IPPROTO_TCP) {
   348        expect &= ~INET_ECN_MASK;
   349      }
   350    } else {
   351      ASSERT_THAT(setsockopt(socket->get(), t.level, t.option, &set, set_sz),
   352                  SyscallFailsWithErrno(EINVAL));
   353      expect = 0;
   354    }
   355    int get = 0;
   356    socklen_t get_sz = sizeof(get);
   357    ASSERT_THAT(getsockopt(socket->get(), t.level, t.option, &get, &get_sz),
   358                SyscallSucceedsWithValue(0));
   359    EXPECT_EQ(get_sz, sizeof(get));
   360    EXPECT_EQ(get, expect);
   361  }
   362  
   363  TEST_P(IPUnboundSocketTest, NullTOS) {
   364    auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
   365    TOSOption t = GetTOSOption(GetParam().domain);
   366    int set_sz = sizeof(int);
   367    if (GetParam().domain == AF_INET) {
   368      EXPECT_THAT(setsockopt(socket->get(), t.level, t.option, nullptr, set_sz),
   369                  SyscallFailsWithErrno(EFAULT));
   370    } else {  // AF_INET6
   371      // The AF_INET6 behavior is not yet compatible. gVisor will try to read
   372      // optval from user memory at syscall handler, it needs substantial
   373      // refactoring to implement this behavior just for IPv6.
   374      if (IsRunningOnGvisor()) {
   375        EXPECT_THAT(setsockopt(socket->get(), t.level, t.option, nullptr, set_sz),
   376                    SyscallFailsWithErrno(EFAULT));
   377      } else {
   378        // Linux's IPv6 stack treats nullptr optval as input of 0, so the call
   379        // succeeds. (net/ipv6/ipv6_sockglue.c, do_ipv6_setsockopt())
   380        //
   381        // Linux's implementation would need fixing as passing a nullptr as optval
   382        // and non-zero optlen may not be valid.
   383        // TODO(b/158666797): Combine the gVisor and linux cases for IPv6.
   384        // Some kernel versions return EFAULT, so we handle both.
   385        EXPECT_THAT(
   386            setsockopt(socket->get(), t.level, t.option, nullptr, set_sz),
   387            AnyOf(SyscallFailsWithErrno(EFAULT), SyscallSucceedsWithValue(0)));
   388      }
   389    }
   390    socklen_t get_sz = sizeof(int);
   391    EXPECT_THAT(getsockopt(socket->get(), t.level, t.option, nullptr, &get_sz),
   392                SyscallFailsWithErrno(EFAULT));
   393    int get = -1;
   394    EXPECT_THAT(getsockopt(socket->get(), t.level, t.option, &get, nullptr),
   395                SyscallFailsWithErrno(EFAULT));
   396  }
   397  
   398  TEST_P(IPUnboundSocketTest, InsufficientBufferTOS) {
   399    SKIP_IF(GetParam().protocol == IPPROTO_TCP);
   400  
   401    auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
   402    TOSOption t = GetTOSOption(GetParam().domain);
   403  
   404    in_addr addr4;
   405    in6_addr addr6;
   406    ASSERT_THAT(inet_pton(AF_INET, "127.0.0.1", &addr4), ::testing::Eq(1));
   407    ASSERT_THAT(inet_pton(AF_INET6, "fe80::", &addr6), ::testing::Eq(1));
   408  
   409    cmsghdr cmsg = {};
   410    cmsg.cmsg_len = sizeof(cmsg);
   411    cmsg.cmsg_level = t.cmsg_level;
   412    cmsg.cmsg_type = t.option;
   413  
   414    msghdr msg = {};
   415    msg.msg_control = &cmsg;
   416    msg.msg_controllen = sizeof(cmsg);
   417    if (GetParam().domain == AF_INET) {
   418      msg.msg_name = &addr4;
   419      msg.msg_namelen = sizeof(addr4);
   420    } else {
   421      msg.msg_name = &addr6;
   422      msg.msg_namelen = sizeof(addr6);
   423    }
   424  
   425    EXPECT_THAT(sendmsg(socket->get(), &msg, 0), SyscallFailsWithErrno(EINVAL));
   426  }
   427  
   428  TEST_P(IPUnboundSocketTest, ReuseAddrDefault) {
   429    auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
   430  
   431    int get = -1;
   432    socklen_t get_sz = sizeof(get);
   433    ASSERT_THAT(
   434        getsockopt(socket->get(), SOL_SOCKET, SO_REUSEADDR, &get, &get_sz),
   435        SyscallSucceedsWithValue(0));
   436    EXPECT_EQ(get, kSockOptOff);
   437    EXPECT_EQ(get_sz, sizeof(get));
   438  }
   439  
   440  TEST_P(IPUnboundSocketTest, SetReuseAddr) {
   441    auto socket = ASSERT_NO_ERRNO_AND_VALUE(NewSocket());
   442  
   443    ASSERT_THAT(setsockopt(socket->get(), SOL_SOCKET, SO_REUSEADDR, &kSockOptOn,
   444                           sizeof(kSockOptOn)),
   445                SyscallSucceedsWithValue(0));
   446  
   447    int get = -1;
   448    socklen_t get_sz = sizeof(get);
   449    ASSERT_THAT(
   450        getsockopt(socket->get(), SOL_SOCKET, SO_REUSEADDR, &get, &get_sz),
   451        SyscallSucceedsWithValue(0));
   452    EXPECT_EQ(get, kSockOptOn);
   453    EXPECT_EQ(get_sz, sizeof(get));
   454  }
   455  
   456  INSTANTIATE_TEST_SUITE_P(
   457      IPUnboundSockets, IPUnboundSocketTest,
   458      ::testing::ValuesIn(VecCat<SocketKind>(
   459          ApplyVec<SocketKind>(IPv4UDPUnboundSocket,
   460                               std::vector<int>{0, SOCK_NONBLOCK}),
   461          ApplyVec<SocketKind>(IPv6UDPUnboundSocket,
   462                               std::vector<int>{0, SOCK_NONBLOCK}),
   463          ApplyVec<SocketKind>(IPv4TCPUnboundSocket,
   464                               std::vector{0, SOCK_NONBLOCK}),
   465          ApplyVec<SocketKind>(IPv6TCPUnboundSocket,
   466                               std::vector{0, SOCK_NONBLOCK}))));
   467  
   468  }  // namespace testing
   469  }  // namespace gvisor