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