// Copyright 2018 The gVisor Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include "gtest/gtest.h" #include "test/syscalls/linux/socket_test_util.h" #include "test/syscalls/linux/unix_domain_socket_test_util.h" #include "test/util/test_util.h" namespace gvisor { namespace testing { namespace { // Test fixture for tests that apply to pairs of connected unix stream sockets. using UnixStreamSocketPairTest = SocketPairTest; // FDPassPartialRead checks that sent control messages cannot be read after // any of their associated data has been read while ignoring the control message // by using read(2) instead of recvmsg(2). TEST_P(UnixStreamSocketPairTest, FDPassPartialRead) { auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); char sent_data[20]; RandomizeBuffer(sent_data, sizeof(sent_data)); auto pair = ASSERT_NO_ERRNO_AND_VALUE(UnixDomainSocketPair(SOCK_SEQPACKET).Create()); ASSERT_NO_FATAL_FAILURE(SendSingleFD(sockets->first_fd(), pair->second_fd(), sent_data, sizeof(sent_data))); char received_data[sizeof(sent_data) / 2]; ASSERT_THAT( ReadFd(sockets->second_fd(), received_data, sizeof(received_data)), SyscallSucceedsWithValue(sizeof(received_data))); EXPECT_EQ(0, memcmp(sent_data, received_data, sizeof(received_data))); RecvNoCmsg(sockets->second_fd(), received_data, sizeof(received_data)); EXPECT_EQ(0, memcmp(sent_data + sizeof(received_data), received_data, sizeof(received_data))); } TEST_P(UnixStreamSocketPairTest, FDPassCoalescedRead) { auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); char sent_data1[20]; RandomizeBuffer(sent_data1, sizeof(sent_data1)); auto pair1 = ASSERT_NO_ERRNO_AND_VALUE(UnixDomainSocketPair(SOCK_SEQPACKET).Create()); ASSERT_NO_FATAL_FAILURE(SendSingleFD(sockets->first_fd(), pair1->second_fd(), sent_data1, sizeof(sent_data1))); char sent_data2[20]; RandomizeBuffer(sent_data2, sizeof(sent_data2)); auto pair2 = ASSERT_NO_ERRNO_AND_VALUE(UnixDomainSocketPair(SOCK_SEQPACKET).Create()); ASSERT_NO_FATAL_FAILURE(SendSingleFD(sockets->first_fd(), pair2->second_fd(), sent_data2, sizeof(sent_data2))); char received_data[sizeof(sent_data1) + sizeof(sent_data2)]; ASSERT_THAT( ReadFd(sockets->second_fd(), received_data, sizeof(received_data)), SyscallSucceedsWithValue(sizeof(received_data))); EXPECT_EQ(0, memcmp(sent_data1, received_data, sizeof(sent_data1))); EXPECT_EQ(0, memcmp(sent_data2, received_data + sizeof(sent_data1), sizeof(sent_data2))); } // ZeroLengthMessageFDDiscarded checks that control messages associated with // zero length messages are discarded. TEST_P(UnixStreamSocketPairTest, ZeroLengthMessageFDDiscarded) { auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); // Zero length arrays are invalid in ISO C++, so allocate one of size 1 and // send a length of 0. char sent_data1[1] = {}; auto pair = ASSERT_NO_ERRNO_AND_VALUE(UnixDomainSocketPair(SOCK_SEQPACKET).Create()); ASSERT_NO_FATAL_FAILURE( SendSingleFD(sockets->first_fd(), pair->second_fd(), sent_data1, 0)); char sent_data2[20]; RandomizeBuffer(sent_data2, sizeof(sent_data2)); ASSERT_THAT(WriteFd(sockets->first_fd(), sent_data2, sizeof(sent_data2)), SyscallSucceedsWithValue(sizeof(sent_data2))); char received_data[sizeof(sent_data2)] = {}; RecvNoCmsg(sockets->second_fd(), received_data, sizeof(received_data)); EXPECT_EQ(0, memcmp(sent_data2, received_data, sizeof(received_data))); } // FDPassCoalescedRecv checks that control messages not in the first message are // preserved in a coalesced recv. TEST_P(UnixStreamSocketPairTest, FDPassCoalescedRecv) { auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); char sent_data[20]; RandomizeBuffer(sent_data, sizeof(sent_data)); ASSERT_THAT(WriteFd(sockets->first_fd(), sent_data, sizeof(sent_data) / 2), SyscallSucceedsWithValue(sizeof(sent_data) / 2)); auto pair = ASSERT_NO_ERRNO_AND_VALUE(UnixDomainSocketPair(SOCK_SEQPACKET).Create()); ASSERT_NO_FATAL_FAILURE(SendSingleFD(sockets->first_fd(), pair->second_fd(), sent_data + sizeof(sent_data) / 2, sizeof(sent_data) / 2)); char received_data[sizeof(sent_data)]; int fd = -1; ASSERT_NO_FATAL_FAILURE(RecvSingleFD(sockets->second_fd(), &fd, received_data, sizeof(received_data))); EXPECT_EQ(0, memcmp(sent_data, received_data, sizeof(sent_data))); ASSERT_NO_FATAL_FAILURE(TransferTest(fd, pair->first_fd())); } // ReadsNotCoalescedAfterFDPass checks that messages after a message containing // an FD control message are not coalesced. TEST_P(UnixStreamSocketPairTest, ReadsNotCoalescedAfterFDPass) { auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); char sent_data[20]; RandomizeBuffer(sent_data, sizeof(sent_data)); auto pair = ASSERT_NO_ERRNO_AND_VALUE(UnixDomainSocketPair(SOCK_SEQPACKET).Create()); ASSERT_NO_FATAL_FAILURE(SendSingleFD(sockets->first_fd(), pair->second_fd(), sent_data, sizeof(sent_data) / 2)); ASSERT_THAT(WriteFd(sockets->first_fd(), sent_data + sizeof(sent_data) / 2, sizeof(sent_data) / 2), SyscallSucceedsWithValue(sizeof(sent_data) / 2)); char received_data[sizeof(sent_data)]; int fd = -1; ASSERT_NO_FATAL_FAILURE(RecvSingleFD(sockets->second_fd(), &fd, received_data, sizeof(received_data), sizeof(sent_data) / 2)); EXPECT_EQ(0, memcmp(sent_data, received_data, sizeof(sent_data) / 2)); ASSERT_NO_FATAL_FAILURE(TransferTest(fd, pair->first_fd())); EXPECT_THAT(close(fd), SyscallSucceeds()); ASSERT_NO_FATAL_FAILURE( RecvNoCmsg(sockets->second_fd(), received_data, sizeof(sent_data) / 2)); EXPECT_EQ(0, memcmp(sent_data + sizeof(sent_data) / 2, received_data, sizeof(sent_data) / 2)); } // FDPassNotCombined checks that FD control messages are not combined in a // coalesced read. TEST_P(UnixStreamSocketPairTest, FDPassNotCombined) { auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); char sent_data[20]; RandomizeBuffer(sent_data, sizeof(sent_data)); auto pair1 = ASSERT_NO_ERRNO_AND_VALUE(UnixDomainSocketPair(SOCK_SEQPACKET).Create()); ASSERT_NO_FATAL_FAILURE(SendSingleFD(sockets->first_fd(), pair1->second_fd(), sent_data, sizeof(sent_data) / 2)); auto pair2 = ASSERT_NO_ERRNO_AND_VALUE(UnixDomainSocketPair(SOCK_SEQPACKET).Create()); ASSERT_NO_FATAL_FAILURE(SendSingleFD(sockets->first_fd(), pair2->second_fd(), sent_data + sizeof(sent_data) / 2, sizeof(sent_data) / 2)); char received_data[sizeof(sent_data)]; int fd = -1; ASSERT_NO_FATAL_FAILURE(RecvSingleFD(sockets->second_fd(), &fd, received_data, sizeof(received_data), sizeof(sent_data) / 2)); EXPECT_EQ(0, memcmp(sent_data, received_data, sizeof(sent_data) / 2)); ASSERT_NO_FATAL_FAILURE(TransferTest(fd, pair1->first_fd())); EXPECT_THAT(close(fd), SyscallSucceeds()); fd = -1; ASSERT_NO_FATAL_FAILURE(RecvSingleFD(sockets->second_fd(), &fd, received_data, sizeof(received_data), sizeof(sent_data) / 2)); EXPECT_EQ(0, memcmp(sent_data + sizeof(sent_data) / 2, received_data, sizeof(sent_data) / 2)); ASSERT_NO_FATAL_FAILURE(TransferTest(fd, pair2->first_fd())); EXPECT_THAT(close(fd), SyscallSucceeds()); } TEST_P(UnixStreamSocketPairTest, CredPassPartialRead) { auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); char sent_data[20]; RandomizeBuffer(sent_data, sizeof(sent_data)); struct ucred sent_creds; ASSERT_THAT(sent_creds.pid = getpid(), SyscallSucceeds()); ASSERT_THAT(sent_creds.uid = getuid(), SyscallSucceeds()); ASSERT_THAT(sent_creds.gid = getgid(), SyscallSucceeds()); ASSERT_NO_FATAL_FAILURE( SendCreds(sockets->first_fd(), sent_creds, sent_data, sizeof(sent_data))); int one = 1; ASSERT_THAT(setsockopt(sockets->second_fd(), SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)), SyscallSucceeds()); for (int i = 0; i < 2; i++) { char received_data[10]; struct ucred received_creds; ASSERT_NO_FATAL_FAILURE(RecvCreds(sockets->second_fd(), &received_creds, received_data, sizeof(received_data), sizeof(received_data))); EXPECT_EQ(0, memcmp(sent_data + i * sizeof(received_data), received_data, sizeof(received_data))); EXPECT_EQ(sent_creds.pid, received_creds.pid); EXPECT_EQ(sent_creds.uid, received_creds.uid); EXPECT_EQ(sent_creds.gid, received_creds.gid); } } // Unix stream sockets peek in the same way as datagram sockets. // // SinglePeek checks that only a single message is peekable in a single recv. TEST_P(UnixStreamSocketPairTest, SinglePeek) { if (!IsRunningOnGvisor()) { // Don't run this test on linux kernels newer than 4.3.x Linux kernel commit // 9f389e35674f5b086edd70ed524ca0f287259725 which changes this behavior. We // used to target 3.11 compatibility, so disable this test on newer kernels. // // NOTE(b/118902768): Bring this up to Linux 4.4 compatibility. auto version = ASSERT_NO_ERRNO_AND_VALUE(GetKernelVersion()); SKIP_IF(version.major > 4 || (version.major == 4 && version.minor >= 3)); } auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); char sent_data[40]; RandomizeBuffer(sent_data, sizeof(sent_data)); ASSERT_THAT(RetryEINTR(send)(sockets->first_fd(), sent_data, sizeof(sent_data) / 2, 0), SyscallSucceedsWithValue(sizeof(sent_data) / 2)); ASSERT_THAT( RetryEINTR(send)(sockets->first_fd(), sent_data + sizeof(sent_data) / 2, sizeof(sent_data) / 2, 0), SyscallSucceedsWithValue(sizeof(sent_data) / 2)); char received_data[sizeof(sent_data)]; for (int i = 0; i < 3; i++) { memset(received_data, 0, sizeof(received_data)); ASSERT_THAT(RetryEINTR(recv)(sockets->second_fd(), received_data, sizeof(received_data), MSG_PEEK), SyscallSucceedsWithValue(sizeof(sent_data) / 2)); EXPECT_EQ(0, memcmp(sent_data, received_data, sizeof(sent_data) / 2)); } memset(received_data, 0, sizeof(received_data)); ASSERT_THAT(RetryEINTR(recv)(sockets->second_fd(), received_data, sizeof(sent_data) / 2, 0), SyscallSucceedsWithValue(sizeof(sent_data) / 2)); EXPECT_EQ(0, memcmp(sent_data, received_data, sizeof(sent_data) / 2)); memset(received_data, 0, sizeof(received_data)); ASSERT_THAT(RetryEINTR(recv)(sockets->second_fd(), received_data, sizeof(sent_data) / 2, 0), SyscallSucceedsWithValue(sizeof(sent_data) / 2)); EXPECT_EQ(0, memcmp(sent_data + sizeof(sent_data) / 2, received_data, sizeof(sent_data) / 2)); } TEST_P(UnixStreamSocketPairTest, CredsNotCoalescedUp) { auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); char sent_data1[20]; RandomizeBuffer(sent_data1, sizeof(sent_data1)); ASSERT_THAT(WriteFd(sockets->first_fd(), sent_data1, sizeof(sent_data1)), SyscallSucceedsWithValue(sizeof(sent_data1))); SetSoPassCred(sockets->second_fd()); char sent_data2[20]; RandomizeBuffer(sent_data2, sizeof(sent_data2)); ASSERT_THAT(WriteFd(sockets->first_fd(), sent_data2, sizeof(sent_data2)), SyscallSucceedsWithValue(sizeof(sent_data2))); char received_data[sizeof(sent_data1) + sizeof(sent_data2)]; struct ucred received_creds; ASSERT_NO_FATAL_FAILURE(RecvCreds(sockets->second_fd(), &received_creds, received_data, sizeof(received_data), sizeof(sent_data1))); EXPECT_EQ(0, memcmp(sent_data1, received_data, sizeof(sent_data1))); struct ucred want_creds { 0, 65534, 65534 }; EXPECT_EQ(want_creds.pid, received_creds.pid); EXPECT_EQ(want_creds.uid, received_creds.uid); EXPECT_EQ(want_creds.gid, received_creds.gid); ASSERT_NO_FATAL_FAILURE(RecvCreds(sockets->second_fd(), &received_creds, received_data, sizeof(received_data), sizeof(sent_data2))); EXPECT_EQ(0, memcmp(sent_data2, received_data, sizeof(sent_data2))); ASSERT_THAT(want_creds.pid = getpid(), SyscallSucceeds()); ASSERT_THAT(want_creds.uid = getuid(), SyscallSucceeds()); ASSERT_THAT(want_creds.gid = getgid(), SyscallSucceeds()); EXPECT_EQ(want_creds.pid, received_creds.pid); EXPECT_EQ(want_creds.uid, received_creds.uid); EXPECT_EQ(want_creds.gid, received_creds.gid); } TEST_P(UnixStreamSocketPairTest, CredsNotCoalescedDown) { auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); SetSoPassCred(sockets->second_fd()); char sent_data1[20]; RandomizeBuffer(sent_data1, sizeof(sent_data1)); ASSERT_THAT(WriteFd(sockets->first_fd(), sent_data1, sizeof(sent_data1)), SyscallSucceedsWithValue(sizeof(sent_data1))); UnsetSoPassCred(sockets->second_fd()); char sent_data2[20]; RandomizeBuffer(sent_data2, sizeof(sent_data2)); ASSERT_THAT(WriteFd(sockets->first_fd(), sent_data2, sizeof(sent_data2)), SyscallSucceedsWithValue(sizeof(sent_data2))); SetSoPassCred(sockets->second_fd()); char received_data[sizeof(sent_data1) + sizeof(sent_data2)]; struct ucred received_creds; ASSERT_NO_FATAL_FAILURE(RecvCreds(sockets->second_fd(), &received_creds, received_data, sizeof(received_data), sizeof(sent_data1))); EXPECT_EQ(0, memcmp(sent_data1, received_data, sizeof(sent_data1))); struct ucred want_creds; ASSERT_THAT(want_creds.pid = getpid(), SyscallSucceeds()); ASSERT_THAT(want_creds.uid = getuid(), SyscallSucceeds()); ASSERT_THAT(want_creds.gid = getgid(), SyscallSucceeds()); EXPECT_EQ(want_creds.pid, received_creds.pid); EXPECT_EQ(want_creds.uid, received_creds.uid); EXPECT_EQ(want_creds.gid, received_creds.gid); ASSERT_NO_FATAL_FAILURE(RecvCreds(sockets->second_fd(), &received_creds, received_data, sizeof(received_data), sizeof(sent_data2))); EXPECT_EQ(0, memcmp(sent_data2, received_data, sizeof(sent_data2))); want_creds = {0, 65534, 65534}; EXPECT_EQ(want_creds.pid, received_creds.pid); EXPECT_EQ(want_creds.uid, received_creds.uid); EXPECT_EQ(want_creds.gid, received_creds.gid); } TEST_P(UnixStreamSocketPairTest, CoalescedCredsNoPasscred) { auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); SetSoPassCred(sockets->second_fd()); char sent_data1[20]; RandomizeBuffer(sent_data1, sizeof(sent_data1)); ASSERT_THAT(WriteFd(sockets->first_fd(), sent_data1, sizeof(sent_data1)), SyscallSucceedsWithValue(sizeof(sent_data1))); UnsetSoPassCred(sockets->second_fd()); char sent_data2[20]; RandomizeBuffer(sent_data2, sizeof(sent_data2)); ASSERT_THAT(WriteFd(sockets->first_fd(), sent_data2, sizeof(sent_data2)), SyscallSucceedsWithValue(sizeof(sent_data2))); char received_data[sizeof(sent_data1) + sizeof(sent_data2)]; ASSERT_NO_FATAL_FAILURE( RecvNoCmsg(sockets->second_fd(), received_data, sizeof(received_data))); EXPECT_EQ(0, memcmp(sent_data1, received_data, sizeof(sent_data1))); EXPECT_EQ(0, memcmp(sent_data2, received_data + sizeof(sent_data1), sizeof(sent_data2))); } TEST_P(UnixStreamSocketPairTest, CoalescedCreds1) { auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); char sent_data1[20]; RandomizeBuffer(sent_data1, sizeof(sent_data1)); ASSERT_THAT(WriteFd(sockets->first_fd(), sent_data1, sizeof(sent_data1)), SyscallSucceedsWithValue(sizeof(sent_data1))); char sent_data2[20]; RandomizeBuffer(sent_data2, sizeof(sent_data2)); ASSERT_THAT(WriteFd(sockets->first_fd(), sent_data2, sizeof(sent_data2)), SyscallSucceedsWithValue(sizeof(sent_data2))); SetSoPassCred(sockets->second_fd()); char received_data[sizeof(sent_data1) + sizeof(sent_data2)]; struct ucred received_creds; ASSERT_NO_FATAL_FAILURE(RecvCreds(sockets->second_fd(), &received_creds, received_data, sizeof(received_data))); EXPECT_EQ(0, memcmp(sent_data1, received_data, sizeof(sent_data1))); EXPECT_EQ(0, memcmp(sent_data2, received_data + sizeof(sent_data1), sizeof(sent_data2))); struct ucred want_creds { 0, 65534, 65534 }; EXPECT_EQ(want_creds.pid, received_creds.pid); EXPECT_EQ(want_creds.uid, received_creds.uid); EXPECT_EQ(want_creds.gid, received_creds.gid); } TEST_P(UnixStreamSocketPairTest, CoalescedCreds2) { auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); SetSoPassCred(sockets->second_fd()); char sent_data1[20]; RandomizeBuffer(sent_data1, sizeof(sent_data1)); ASSERT_THAT(WriteFd(sockets->first_fd(), sent_data1, sizeof(sent_data1)), SyscallSucceedsWithValue(sizeof(sent_data1))); char sent_data2[20]; RandomizeBuffer(sent_data2, sizeof(sent_data2)); ASSERT_THAT(WriteFd(sockets->first_fd(), sent_data2, sizeof(sent_data2)), SyscallSucceedsWithValue(sizeof(sent_data2))); char received_data[sizeof(sent_data1) + sizeof(sent_data2)]; struct ucred received_creds; ASSERT_NO_FATAL_FAILURE(RecvCreds(sockets->second_fd(), &received_creds, received_data, sizeof(received_data))); EXPECT_EQ(0, memcmp(sent_data1, received_data, sizeof(sent_data1))); EXPECT_EQ(0, memcmp(sent_data2, received_data + sizeof(sent_data1), sizeof(sent_data2))); struct ucred want_creds; ASSERT_THAT(want_creds.pid = getpid(), SyscallSucceeds()); ASSERT_THAT(want_creds.uid = getuid(), SyscallSucceeds()); ASSERT_THAT(want_creds.gid = getgid(), SyscallSucceeds()); EXPECT_EQ(want_creds.pid, received_creds.pid); EXPECT_EQ(want_creds.uid, received_creds.uid); EXPECT_EQ(want_creds.gid, received_creds.gid); } TEST_P(UnixStreamSocketPairTest, NonCoalescedDifferingCreds1) { auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); char sent_data1[20]; RandomizeBuffer(sent_data1, sizeof(sent_data1)); ASSERT_THAT(WriteFd(sockets->first_fd(), sent_data1, sizeof(sent_data1)), SyscallSucceedsWithValue(sizeof(sent_data1))); SetSoPassCred(sockets->second_fd()); char sent_data2[20]; RandomizeBuffer(sent_data2, sizeof(sent_data2)); ASSERT_THAT(WriteFd(sockets->first_fd(), sent_data2, sizeof(sent_data2)), SyscallSucceedsWithValue(sizeof(sent_data2))); char received_data1[sizeof(sent_data1) + sizeof(sent_data2)]; struct ucred received_creds1; ASSERT_NO_FATAL_FAILURE(RecvCreds(sockets->second_fd(), &received_creds1, received_data1, sizeof(sent_data1))); EXPECT_EQ(0, memcmp(sent_data1, received_data1, sizeof(sent_data1))); struct ucred want_creds1 { 0, 65534, 65534 }; EXPECT_EQ(want_creds1.pid, received_creds1.pid); EXPECT_EQ(want_creds1.uid, received_creds1.uid); EXPECT_EQ(want_creds1.gid, received_creds1.gid); char received_data2[sizeof(sent_data1) + sizeof(sent_data2)]; struct ucred received_creds2; ASSERT_NO_FATAL_FAILURE(RecvCreds(sockets->second_fd(), &received_creds2, received_data2, sizeof(sent_data2))); EXPECT_EQ(0, memcmp(sent_data2, received_data2, sizeof(sent_data2))); struct ucred want_creds2; ASSERT_THAT(want_creds2.pid = getpid(), SyscallSucceeds()); ASSERT_THAT(want_creds2.uid = getuid(), SyscallSucceeds()); ASSERT_THAT(want_creds2.gid = getgid(), SyscallSucceeds()); EXPECT_EQ(want_creds2.pid, received_creds2.pid); EXPECT_EQ(want_creds2.uid, received_creds2.uid); EXPECT_EQ(want_creds2.gid, received_creds2.gid); } TEST_P(UnixStreamSocketPairTest, NonCoalescedDifferingCreds2) { auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); SetSoPassCred(sockets->second_fd()); char sent_data1[20]; RandomizeBuffer(sent_data1, sizeof(sent_data1)); ASSERT_THAT(WriteFd(sockets->first_fd(), sent_data1, sizeof(sent_data1)), SyscallSucceedsWithValue(sizeof(sent_data1))); UnsetSoPassCred(sockets->second_fd()); char sent_data2[20]; RandomizeBuffer(sent_data2, sizeof(sent_data2)); ASSERT_THAT(WriteFd(sockets->first_fd(), sent_data2, sizeof(sent_data2)), SyscallSucceedsWithValue(sizeof(sent_data2))); SetSoPassCred(sockets->second_fd()); char received_data1[sizeof(sent_data1) + sizeof(sent_data2)]; struct ucred received_creds1; ASSERT_NO_FATAL_FAILURE(RecvCreds(sockets->second_fd(), &received_creds1, received_data1, sizeof(sent_data1))); EXPECT_EQ(0, memcmp(sent_data1, received_data1, sizeof(sent_data1))); struct ucred want_creds1; ASSERT_THAT(want_creds1.pid = getpid(), SyscallSucceeds()); ASSERT_THAT(want_creds1.uid = getuid(), SyscallSucceeds()); ASSERT_THAT(want_creds1.gid = getgid(), SyscallSucceeds()); EXPECT_EQ(want_creds1.pid, received_creds1.pid); EXPECT_EQ(want_creds1.uid, received_creds1.uid); EXPECT_EQ(want_creds1.gid, received_creds1.gid); char received_data2[sizeof(sent_data1) + sizeof(sent_data2)]; struct ucred received_creds2; ASSERT_NO_FATAL_FAILURE(RecvCreds(sockets->second_fd(), &received_creds2, received_data2, sizeof(sent_data2))); EXPECT_EQ(0, memcmp(sent_data2, received_data2, sizeof(sent_data2))); struct ucred want_creds2 { 0, 65534, 65534 }; EXPECT_EQ(want_creds2.pid, received_creds2.pid); EXPECT_EQ(want_creds2.uid, received_creds2.uid); EXPECT_EQ(want_creds2.gid, received_creds2.gid); } TEST_P(UnixStreamSocketPairTest, CoalescedDifferingCreds) { auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); SetSoPassCred(sockets->second_fd()); char sent_data1[20]; RandomizeBuffer(sent_data1, sizeof(sent_data1)); ASSERT_THAT(WriteFd(sockets->first_fd(), sent_data1, sizeof(sent_data1)), SyscallSucceedsWithValue(sizeof(sent_data1))); char sent_data2[20]; RandomizeBuffer(sent_data2, sizeof(sent_data2)); ASSERT_THAT(WriteFd(sockets->first_fd(), sent_data2, sizeof(sent_data2)), SyscallSucceedsWithValue(sizeof(sent_data2))); UnsetSoPassCred(sockets->second_fd()); char sent_data3[20]; RandomizeBuffer(sent_data3, sizeof(sent_data3)); ASSERT_THAT(WriteFd(sockets->first_fd(), sent_data3, sizeof(sent_data3)), SyscallSucceedsWithValue(sizeof(sent_data3))); char received_data[sizeof(sent_data1) + sizeof(sent_data2) + sizeof(sent_data3)]; ASSERT_NO_FATAL_FAILURE( RecvNoCmsg(sockets->second_fd(), received_data, sizeof(received_data))); EXPECT_EQ(0, memcmp(sent_data1, received_data, sizeof(sent_data1))); EXPECT_EQ(0, memcmp(sent_data2, received_data + sizeof(sent_data1), sizeof(sent_data2))); EXPECT_EQ(0, memcmp(sent_data3, received_data + sizeof(sent_data1) + sizeof(sent_data2), sizeof(sent_data3))); } INSTANTIATE_TEST_SUITE_P( AllUnixDomainSockets, UnixStreamSocketPairTest, ::testing::ValuesIn(IncludeReversals(VecCat( ApplyVec(UnixDomainSocketPair, AllBitwiseCombinations(List{SOCK_STREAM}, List{ 0, SOCK_NONBLOCK})), ApplyVec(FilesystemBoundUnixDomainSocketPair, AllBitwiseCombinations(List{SOCK_STREAM}, List{ 0, SOCK_NONBLOCK})), ApplyVec( AbstractBoundUnixDomainSocketPair, AllBitwiseCombinations(List{SOCK_STREAM}, List{0, SOCK_NONBLOCK})))))); // Test fixture for tests that apply to pairs of unbound unix stream sockets. using UnboundUnixStreamSocketPairTest = SocketPairTest; TEST_P(UnboundUnixStreamSocketPairTest, SendtoWithoutConnect) { auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); ASSERT_THAT(bind(sockets->first_fd(), sockets->first_addr(), sockets->first_addr_size()), SyscallSucceeds()); char data = 'a'; ASSERT_THAT(sendto(sockets->second_fd(), &data, sizeof(data), 0, sockets->first_addr(), sockets->first_addr_size()), SyscallFailsWithErrno(EOPNOTSUPP)); } TEST_P(UnboundUnixStreamSocketPairTest, SendtoWithoutConnectIgnoresAddr) { // FIXME(b/68223466): gVisor tries to find /foo/bar and thus returns ENOENT. if (IsRunningOnGvisor()) { return; } auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); ASSERT_THAT(bind(sockets->first_fd(), sockets->first_addr(), sockets->first_addr_size()), SyscallSucceeds()); // Even a bogus address is completely ignored. constexpr char kPath[] = "/foo/bar"; // Sanity check that kPath doesn't exist. struct stat s; ASSERT_THAT(stat(kPath, &s), SyscallFailsWithErrno(ENOENT)); struct sockaddr_un addr = {}; addr.sun_family = AF_UNIX; memcpy(addr.sun_path, kPath, sizeof(kPath)); char data = 'a'; ASSERT_THAT( sendto(sockets->second_fd(), &data, sizeof(data), 0, reinterpret_cast(&addr), sizeof(addr)), SyscallFailsWithErrno(EOPNOTSUPP)); } INSTANTIATE_TEST_SUITE_P( AllUnixDomainSockets, UnboundUnixStreamSocketPairTest, ::testing::ValuesIn(IncludeReversals(VecCat( ApplyVec(FilesystemUnboundUnixDomainSocketPair, AllBitwiseCombinations(List{SOCK_STREAM}, List{ 0, SOCK_NONBLOCK})), ApplyVec( AbstractUnboundUnixDomainSocketPair, AllBitwiseCombinations(List{SOCK_STREAM}, List{0, SOCK_NONBLOCK})))))); } // namespace } // namespace testing } // namespace gvisor