gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/unix_domain_socket_test_util.cc (about)

     1  // Copyright 2018 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 "test/syscalls/linux/unix_domain_socket_test_util.h"
    16  
    17  #include <sys/un.h>
    18  
    19  #include <vector>
    20  
    21  #include "gtest/gtest.h"
    22  #include "absl/strings/str_cat.h"
    23  #include "test/util/test_util.h"
    24  
    25  namespace gvisor {
    26  namespace testing {
    27  
    28  std::string DescribeUnixDomainSocketType(int type) {
    29    const char* type_str = nullptr;
    30    switch (type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)) {
    31      case SOCK_STREAM:
    32        type_str = "SOCK_STREAM";
    33        break;
    34      case SOCK_DGRAM:
    35        type_str = "SOCK_DGRAM";
    36        break;
    37      case SOCK_SEQPACKET:
    38        type_str = "SOCK_SEQPACKET";
    39        break;
    40    }
    41    if (!type_str) {
    42      return absl::StrCat("Unix domain socket with unknown type ", type);
    43    } else {
    44      return absl::StrCat(((type & SOCK_NONBLOCK) != 0) ? "non-blocking " : "",
    45                          ((type & SOCK_CLOEXEC) != 0) ? "close-on-exec " : "",
    46                          type_str, " Unix domain socket");
    47    }
    48  }
    49  
    50  SocketPairKind UnixDomainSocketPair(int type) {
    51    return SocketPairKind{DescribeUnixDomainSocketType(type), AF_UNIX, type, 0,
    52                          SyscallSocketPairCreator(AF_UNIX, type, 0)};
    53  }
    54  
    55  SocketPairKind FilesystemBoundUnixDomainSocketPair(int type) {
    56    std::string description = absl::StrCat(DescribeUnixDomainSocketType(type),
    57                                           " created with filesystem binding");
    58    if ((type & SOCK_DGRAM) == SOCK_DGRAM) {
    59      return SocketPairKind{
    60          description, AF_UNIX, type, 0,
    61          FilesystemBidirectionalBindSocketPairCreator(AF_UNIX, type, 0)};
    62    }
    63    return SocketPairKind{
    64        description, AF_UNIX, type, 0,
    65        FilesystemAcceptBindSocketPairCreator(AF_UNIX, type, 0)};
    66  }
    67  
    68  SocketPairKind AbstractBoundUnixDomainSocketPair(int type) {
    69    std::string description =
    70        absl::StrCat(DescribeUnixDomainSocketType(type),
    71                     " created with abstract namespace binding");
    72    if ((type & SOCK_DGRAM) == SOCK_DGRAM) {
    73      return SocketPairKind{
    74          description, AF_UNIX, type, 0,
    75          AbstractBidirectionalBindSocketPairCreator(AF_UNIX, type, 0)};
    76    }
    77    return SocketPairKind{description, AF_UNIX, type, 0,
    78                          AbstractAcceptBindSocketPairCreator(AF_UNIX, type, 0)};
    79  }
    80  
    81  SocketPairKind SocketpairGoferUnixDomainSocketPair(int type) {
    82    std::string description = absl::StrCat(DescribeUnixDomainSocketType(type),
    83                                           " created with the socketpair gofer");
    84    return SocketPairKind{description, AF_UNIX, type, 0,
    85                          SocketpairGoferSocketPairCreator(AF_UNIX, type, 0)};
    86  }
    87  
    88  SocketPairKind SocketpairGoferFileSocketPair(int type) {
    89    std::string description =
    90        absl::StrCat(((type & O_NONBLOCK) != 0) ? "non-blocking " : "",
    91                     ((type & O_CLOEXEC) != 0) ? "close-on-exec " : "",
    92                     "file socket created with the socketpair gofer");
    93    // The socketpair gofer always creates SOCK_STREAM sockets on open(2).
    94    return SocketPairKind{description, AF_UNIX, SOCK_STREAM, 0,
    95                          SocketpairGoferFileSocketPairCreator(type)};
    96  }
    97  
    98  SocketPairKind FilesystemUnboundUnixDomainSocketPair(int type) {
    99    return SocketPairKind{absl::StrCat(DescribeUnixDomainSocketType(type),
   100                                       " unbound with a filesystem address"),
   101                          AF_UNIX, type, 0,
   102                          FilesystemUnboundSocketPairCreator(AF_UNIX, type, 0)};
   103  }
   104  
   105  SocketPairKind AbstractUnboundUnixDomainSocketPair(int type) {
   106    return SocketPairKind{
   107        absl::StrCat(DescribeUnixDomainSocketType(type),
   108                     " unbound with an abstract namespace address"),
   109        AF_UNIX, type, 0, AbstractUnboundSocketPairCreator(AF_UNIX, type, 0)};
   110  }
   111  
   112  void SendSingleFD(int sock, int fd, char buf[], int buf_size) {
   113    ASSERT_NO_FATAL_FAILURE(SendFDs(sock, &fd, 1, buf, buf_size));
   114  }
   115  
   116  void SendFDs(int sock, int fds[], int fds_size, char buf[], int buf_size) {
   117    struct msghdr msg = {};
   118    std::vector<char> control(CMSG_SPACE(fds_size * sizeof(int)));
   119    msg.msg_control = &control[0];
   120    msg.msg_controllen = control.size();
   121  
   122    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
   123    cmsg->cmsg_len = CMSG_LEN(fds_size * sizeof(int));
   124    cmsg->cmsg_level = SOL_SOCKET;
   125    cmsg->cmsg_type = SCM_RIGHTS;
   126    for (int i = 0; i < fds_size; i++) {
   127      memcpy(CMSG_DATA(cmsg) + i * sizeof(int), &fds[i], sizeof(int));
   128    }
   129  
   130    ASSERT_THAT(SendMsg(sock, &msg, buf, buf_size),
   131                IsPosixErrorOkAndHolds(buf_size));
   132  }
   133  
   134  void RecvSingleFD(int sock, int* fd, char buf[], int buf_size) {
   135    ASSERT_NO_FATAL_FAILURE(RecvFDs(sock, fd, 1, buf, buf_size, buf_size));
   136  }
   137  
   138  void RecvSingleFD(int sock, int* fd, char buf[], int buf_size,
   139                    int expected_size) {
   140    ASSERT_NO_FATAL_FAILURE(RecvFDs(sock, fd, 1, buf, buf_size, expected_size));
   141  }
   142  
   143  void RecvFDs(int sock, int fds[], int fds_size, char buf[], int buf_size) {
   144    ASSERT_NO_FATAL_FAILURE(
   145        RecvFDs(sock, fds, fds_size, buf, buf_size, buf_size));
   146  }
   147  
   148  void RecvFDs(int sock, int fds[], int fds_size, char buf[], int buf_size,
   149               int expected_size, bool peek) {
   150    struct msghdr msg = {};
   151    std::vector<char> control(CMSG_SPACE(fds_size * sizeof(int)));
   152    msg.msg_control = &control[0];
   153    msg.msg_controllen = control.size();
   154  
   155    struct iovec iov;
   156    iov.iov_base = buf;
   157    iov.iov_len = buf_size;
   158    msg.msg_iov = &iov;
   159    msg.msg_iovlen = 1;
   160  
   161    int flags = 0;
   162    if (peek) {
   163      flags |= MSG_PEEK;
   164    }
   165  
   166    ASSERT_THAT(RetryEINTR(recvmsg)(sock, &msg, flags),
   167                SyscallSucceedsWithValue(expected_size));
   168    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
   169    ASSERT_NE(cmsg, nullptr);
   170    ASSERT_EQ(cmsg->cmsg_len, CMSG_LEN(fds_size * sizeof(int)));
   171    ASSERT_EQ(cmsg->cmsg_level, SOL_SOCKET);
   172    ASSERT_EQ(cmsg->cmsg_type, SCM_RIGHTS);
   173  
   174    for (int i = 0; i < fds_size; i++) {
   175      memcpy(&fds[i], CMSG_DATA(cmsg) + i * sizeof(int), sizeof(int));
   176    }
   177  }
   178  
   179  void RecvFDs(int sock, int fds[], int fds_size, char buf[], int buf_size,
   180               int expected_size) {
   181    ASSERT_NO_FATAL_FAILURE(
   182        RecvFDs(sock, fds, fds_size, buf, buf_size, expected_size, false));
   183  }
   184  
   185  void PeekSingleFD(int sock, int* fd, char buf[], int buf_size) {
   186    ASSERT_NO_FATAL_FAILURE(RecvFDs(sock, fd, 1, buf, buf_size, buf_size, true));
   187  }
   188  
   189  void RecvNoCmsg(int sock, char buf[], int buf_size, int expected_size) {
   190    struct msghdr msg = {};
   191    char control[CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred))];
   192    msg.msg_control = control;
   193    msg.msg_controllen = sizeof(control);
   194  
   195    struct iovec iov;
   196    iov.iov_base = buf;
   197    iov.iov_len = buf_size;
   198    msg.msg_iov = &iov;
   199    msg.msg_iovlen = 1;
   200  
   201    ASSERT_THAT(RetryEINTR(recvmsg)(sock, &msg, 0),
   202                SyscallSucceedsWithValue(expected_size));
   203    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
   204    EXPECT_EQ(cmsg, nullptr);
   205  }
   206  
   207  void SendNullCmsg(int sock, char buf[], int buf_size) {
   208    struct msghdr msg = {};
   209    msg.msg_control = nullptr;
   210    msg.msg_controllen = 0;
   211  
   212    ASSERT_THAT(SendMsg(sock, &msg, buf, buf_size),
   213                IsPosixErrorOkAndHolds(buf_size));
   214  }
   215  
   216  void SendCreds(int sock, ucred creds, char buf[], int buf_size) {
   217    struct msghdr msg = {};
   218  
   219    char control[CMSG_SPACE(sizeof(struct ucred))];
   220    msg.msg_control = control;
   221    msg.msg_controllen = sizeof(control);
   222  
   223    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
   224    cmsg->cmsg_level = SOL_SOCKET;
   225    cmsg->cmsg_type = SCM_CREDENTIALS;
   226    cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
   227    memcpy(CMSG_DATA(cmsg), &creds, sizeof(struct ucred));
   228  
   229    ASSERT_THAT(SendMsg(sock, &msg, buf, buf_size),
   230                IsPosixErrorOkAndHolds(buf_size));
   231  }
   232  
   233  void SendCredsAndFD(int sock, ucred creds, int fd, char buf[], int buf_size) {
   234    struct msghdr msg = {};
   235  
   236    char control[CMSG_SPACE(sizeof(struct ucred)) + CMSG_SPACE(sizeof(int))] = {};
   237    msg.msg_control = control;
   238    msg.msg_controllen = sizeof(control);
   239  
   240    struct cmsghdr* cmsg1 = CMSG_FIRSTHDR(&msg);
   241    cmsg1->cmsg_level = SOL_SOCKET;
   242    cmsg1->cmsg_type = SCM_CREDENTIALS;
   243    cmsg1->cmsg_len = CMSG_LEN(sizeof(struct ucred));
   244    memcpy(CMSG_DATA(cmsg1), &creds, sizeof(struct ucred));
   245  
   246    struct cmsghdr* cmsg2 = CMSG_NXTHDR(&msg, cmsg1);
   247    cmsg2->cmsg_level = SOL_SOCKET;
   248    cmsg2->cmsg_type = SCM_RIGHTS;
   249    cmsg2->cmsg_len = CMSG_LEN(sizeof(int));
   250    memcpy(CMSG_DATA(cmsg2), &fd, sizeof(int));
   251  
   252    ASSERT_THAT(SendMsg(sock, &msg, buf, buf_size),
   253                IsPosixErrorOkAndHolds(buf_size));
   254  }
   255  
   256  void RecvCreds(int sock, ucred* creds, char buf[], int buf_size) {
   257    ASSERT_NO_FATAL_FAILURE(RecvCreds(sock, creds, buf, buf_size, buf_size));
   258  }
   259  
   260  void RecvCreds(int sock, ucred* creds, char buf[], int buf_size,
   261                 int expected_size) {
   262    struct msghdr msg = {};
   263    char control[CMSG_SPACE(sizeof(struct ucred))];
   264    msg.msg_control = control;
   265    msg.msg_controllen = sizeof(control);
   266  
   267    struct iovec iov;
   268    iov.iov_base = buf;
   269    iov.iov_len = buf_size;
   270    msg.msg_iov = &iov;
   271    msg.msg_iovlen = 1;
   272  
   273    ASSERT_THAT(RetryEINTR(recvmsg)(sock, &msg, 0),
   274                SyscallSucceedsWithValue(expected_size));
   275    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
   276    ASSERT_NE(cmsg, nullptr);
   277    ASSERT_EQ(cmsg->cmsg_len, CMSG_LEN(sizeof(struct ucred)));
   278    ASSERT_EQ(cmsg->cmsg_level, SOL_SOCKET);
   279    ASSERT_EQ(cmsg->cmsg_type, SCM_CREDENTIALS);
   280  
   281    memcpy(creds, CMSG_DATA(cmsg), sizeof(struct ucred));
   282  }
   283  
   284  void RecvCredsAndFD(int sock, ucred* creds, int* fd, char buf[], int buf_size) {
   285    struct msghdr msg = {};
   286    char control[CMSG_SPACE(sizeof(struct ucred)) + CMSG_SPACE(sizeof(int))];
   287    msg.msg_control = control;
   288    msg.msg_controllen = sizeof(control);
   289  
   290    struct iovec iov;
   291    iov.iov_base = buf;
   292    iov.iov_len = buf_size;
   293    msg.msg_iov = &iov;
   294    msg.msg_iovlen = 1;
   295  
   296    ASSERT_THAT(RetryEINTR(recvmsg)(sock, &msg, 0),
   297                SyscallSucceedsWithValue(buf_size));
   298  
   299    struct cmsghdr* cmsg1 = CMSG_FIRSTHDR(&msg);
   300    ASSERT_NE(cmsg1, nullptr);
   301    ASSERT_EQ(cmsg1->cmsg_len, CMSG_LEN(sizeof(struct ucred)));
   302    ASSERT_EQ(cmsg1->cmsg_level, SOL_SOCKET);
   303    ASSERT_EQ(cmsg1->cmsg_type, SCM_CREDENTIALS);
   304    memcpy(creds, CMSG_DATA(cmsg1), sizeof(struct ucred));
   305  
   306    struct cmsghdr* cmsg2 = CMSG_NXTHDR(&msg, cmsg1);
   307    ASSERT_NE(cmsg2, nullptr);
   308    ASSERT_EQ(cmsg2->cmsg_len, CMSG_LEN(sizeof(int)));
   309    ASSERT_EQ(cmsg2->cmsg_level, SOL_SOCKET);
   310    ASSERT_EQ(cmsg2->cmsg_type, SCM_RIGHTS);
   311    memcpy(fd, CMSG_DATA(cmsg2), sizeof(int));
   312  }
   313  
   314  void RecvSingleFDUnaligned(int sock, int* fd, char buf[], int buf_size) {
   315    struct msghdr msg = {};
   316    char control[CMSG_SPACE(sizeof(int)) - sizeof(int)];
   317    msg.msg_control = control;
   318    msg.msg_controllen = sizeof(control);
   319  
   320    struct iovec iov;
   321    iov.iov_base = buf;
   322    iov.iov_len = buf_size;
   323    msg.msg_iov = &iov;
   324    msg.msg_iovlen = 1;
   325  
   326    ASSERT_THAT(RetryEINTR(recvmsg)(sock, &msg, 0),
   327                SyscallSucceedsWithValue(buf_size));
   328  
   329    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
   330    ASSERT_NE(cmsg, nullptr);
   331    ASSERT_EQ(cmsg->cmsg_len, CMSG_LEN(sizeof(int)));
   332    ASSERT_EQ(cmsg->cmsg_level, SOL_SOCKET);
   333    ASSERT_EQ(cmsg->cmsg_type, SCM_RIGHTS);
   334  
   335    memcpy(fd, CMSG_DATA(cmsg), sizeof(int));
   336  }
   337  
   338  void SetSoPassCred(int sock) {
   339    int one = 1;
   340    EXPECT_THAT(setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)),
   341                SyscallSucceeds());
   342  }
   343  
   344  void UnsetSoPassCred(int sock) {
   345    int zero = 0;
   346    EXPECT_THAT(setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &zero, sizeof(zero)),
   347                SyscallSucceeds());
   348  }
   349  
   350  }  // namespace testing
   351  }  // namespace gvisor