gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/bind_external.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  #ifdef __linux__
    16  #include <sys/epoll.h>
    17  #endif  // __linux__
    18  #include <errno.h>
    19  #include <stdlib.h>
    20  #include <sys/socket.h>
    21  #include <sys/un.h>
    22  
    23  #include <cstring>
    24  #include <string>
    25  #include <tuple>
    26  
    27  #include "gmock/gmock.h"
    28  #include "gtest/gtest.h"
    29  #include "test/util/file_descriptor.h"
    30  #include "test/util/fs_util.h"
    31  #include "test/util/socket_util.h"
    32  #include "test/util/test_util.h"
    33  
    34  // This file contains tests specific to binding to host UDS that will be
    35  // connected to from outside the sandbox / test.
    36  //
    37  // A set of ultity sockets will be created externally in $TEST_UDS_TREE and
    38  // $TEST_UDS_ATTACH_TREE for these tests to interact with.
    39  
    40  namespace gvisor {
    41  namespace testing {
    42  
    43  namespace {
    44  
    45  struct ProtocolSocket {
    46    int protocol;
    47    std::string name;
    48  };
    49  
    50  // Parameter is (socket root dir, ProtocolSocket).
    51  using GoferStreamSeqpacketTest =
    52      ::testing::TestWithParam<std::tuple<std::string, ProtocolSocket>>;
    53  
    54  // Bind to a socket, then Listen and Accept.
    55  TEST_P(GoferStreamSeqpacketTest, BindListenAccept) {
    56    std::string env;
    57    ProtocolSocket proto;
    58    std::tie(env, proto) = GetParam();
    59  
    60    char* val = getenv(env.c_str());
    61    ASSERT_NE(val, nullptr);
    62    std::string root(val);
    63  
    64    FileDescriptor sock =
    65        ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_UNIX, proto.protocol, 0));
    66  
    67    std::string socket_path = JoinPath(root, proto.name, "created-in-sandbox");
    68  
    69    struct sockaddr_un addr = {};
    70    addr.sun_family = AF_UNIX;
    71    memcpy(addr.sun_path, socket_path.c_str(), socket_path.length());
    72  
    73    ASSERT_THAT(
    74        bind(sock.get(), reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)),
    75        SyscallSucceeds());
    76    ASSERT_THAT(listen(sock.get(), 1), SyscallSucceeds());
    77  
    78    // Bind again on that socket with a diff address should fail.
    79    std::string socket_path2 = socket_path + "-fail";
    80    struct sockaddr_un addr2 = {};
    81    addr2.sun_family = AF_UNIX;
    82    memcpy(addr2.sun_path, socket_path2.c_str(), socket_path2.length());
    83    ASSERT_THAT(bind(sock.get(), reinterpret_cast<struct sockaddr*>(&addr2),
    84                     sizeof(addr2)),
    85                SyscallFailsWithErrno(EINVAL));
    86  
    87    FileDescriptor accSock =
    88        ASSERT_NO_ERRNO_AND_VALUE(Accept(sock.get(), NULL, NULL));
    89  
    90    // Other socket should be echo client.
    91    constexpr int kBufferSize = 64;
    92    char send_buffer[kBufferSize];
    93    memset(send_buffer, 'a', sizeof(send_buffer));
    94  
    95    ASSERT_THAT(WriteFd(accSock.get(), send_buffer, sizeof(send_buffer)),
    96                SyscallSucceedsWithValue(sizeof(send_buffer)));
    97  
    98    char recv_buffer[kBufferSize];
    99    ASSERT_THAT(ReadFd(accSock.get(), recv_buffer, sizeof(recv_buffer)),
   100                SyscallSucceedsWithValue(sizeof(recv_buffer)));
   101    ASSERT_EQ(0, memcmp(send_buffer, recv_buffer, sizeof(send_buffer)));
   102  }
   103  
   104  // Create socket, register with epoll, bind to socket, Listen, wait for socket
   105  // to become ready using epoll and then Accept.
   106  TEST_P(GoferStreamSeqpacketTest, EpollBindListenWaitAccept) {
   107    std::string env;
   108    ProtocolSocket proto;
   109    std::tie(env, proto) = GetParam();
   110  
   111    char* val = getenv(env.c_str());
   112    ASSERT_NE(val, nullptr);
   113    std::string root(val);
   114  
   115    FileDescriptor sock =
   116        ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_UNIX, proto.protocol, 0));
   117  
   118    // Epoll on sockfd.
   119    int efd;
   120    ASSERT_THAT(efd = epoll_create(1), SyscallSucceeds());
   121    FileDescriptor epollfd(efd);
   122    struct epoll_event event = {};
   123    event.events = EPOLLIN;
   124    ASSERT_THAT(epoll_ctl(epollfd.get(), EPOLL_CTL_ADD, sock.get(), &event),
   125                SyscallSucceeds());
   126  
   127    std::string socket_path =
   128        JoinPath(root, proto.name, "created-in-sandbox-epoll");
   129  
   130    struct sockaddr_un addr = {};
   131    addr.sun_family = AF_UNIX;
   132    memcpy(addr.sun_path, socket_path.c_str(), socket_path.length());
   133  
   134    ASSERT_THAT(
   135        bind(sock.get(), reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)),
   136        SyscallSucceeds());
   137    ASSERT_THAT(listen(sock.get(), 1), SyscallSucceeds());
   138  
   139    struct epoll_event results = {};
   140    ASSERT_THAT(RetryEINTR(epoll_wait)(epollfd.get(), &results, 1, -1),
   141                SyscallSucceeds());
   142  
   143    FileDescriptor accSock =
   144        ASSERT_NO_ERRNO_AND_VALUE(Accept(sock.get(), NULL, NULL));
   145  
   146    // Other socket should be echo client.
   147    constexpr int kBufferSize = 64;
   148    char send_buffer[kBufferSize];
   149    memset(send_buffer, 'a', sizeof(send_buffer));
   150  
   151    ASSERT_THAT(WriteFd(accSock.get(), send_buffer, sizeof(send_buffer)),
   152                SyscallSucceedsWithValue(sizeof(send_buffer)));
   153  
   154    char recv_buffer[kBufferSize];
   155    ASSERT_THAT(ReadFd(accSock.get(), recv_buffer, sizeof(recv_buffer)),
   156                SyscallSucceedsWithValue(sizeof(recv_buffer)));
   157    ASSERT_EQ(0, memcmp(send_buffer, recv_buffer, sizeof(send_buffer)));
   158  }
   159  
   160  INSTANTIATE_TEST_SUITE_P(
   161      StreamSeqpacket, GoferStreamSeqpacketTest,
   162      ::testing::Combine(::testing::Values("TEST_CONNECTOR_TREE"),
   163                         ::testing::Values(ProtocolSocket{SOCK_STREAM, "stream"},
   164                                           ProtocolSocket{SOCK_SEQPACKET,
   165                                                          "seqpacket"})));
   166  
   167  }  // namespace
   168  
   169  }  // namespace testing
   170  }  // namespace gvisor