1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <android-base/cmsg.h>
18 
19 #include <android-base/file.h>
20 #include <android-base/logging.h>
21 #include <android-base/unique_fd.h>
22 #include <gtest/gtest.h>
23 
24 #if !defined(_WIN32)
25 
26 using android::base::ReceiveFileDescriptors;
27 using android::base::SendFileDescriptors;
28 using android::base::unique_fd;
29 
GetInode(int fd)30 static ino_t GetInode(int fd) {
31   struct stat st;
32   if (fstat(fd, &st) != 0) {
33     PLOG(FATAL) << "fstat failed";
34   }
35 
36   return st.st_ino;
37 }
38 
39 struct CmsgTest : ::testing::TestWithParam<bool> {
SeqpacketCmsgTest40   bool Seqpacket() { return GetParam(); }
41 
SetUpCmsgTest42   void SetUp() override {
43     ASSERT_TRUE(
44         android::base::Socketpair(Seqpacket() ? SOCK_SEQPACKET : SOCK_STREAM, &send, &recv));
45     int dup1 = dup(tmp1.fd);
46     ASSERT_NE(-1, dup1);
47     int dup2 = dup(tmp2.fd);
48     ASSERT_NE(-1, dup2);
49 
50     fd1.reset(dup1);
51     fd2.reset(dup2);
52 
53     ino1 = GetInode(dup1);
54     ino2 = GetInode(dup2);
55   }
56 
57   unique_fd send;
58   unique_fd recv;
59 
60   TemporaryFile tmp1;
61   TemporaryFile tmp2;
62 
63   unique_fd fd1;
64   unique_fd fd2;
65 
66   ino_t ino1;
67   ino_t ino2;
68 };
69 
TEST_P(CmsgTest,smoke)70 TEST_P(CmsgTest, smoke) {
71   ASSERT_EQ(1, SendFileDescriptors(send.get(), "x", 1, fd1.get()));
72 
73   char buf[2];
74   unique_fd received;
75   ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 2, &received));
76   ASSERT_EQ('x', buf[0]);
77   ASSERT_NE(-1, received.get());
78 
79   ASSERT_EQ(ino1, GetInode(received.get()));
80 }
81 
TEST_P(CmsgTest,msg_trunc)82 TEST_P(CmsgTest, msg_trunc) {
83   ASSERT_EQ(2, SendFileDescriptors(send.get(), "ab", 2, fd1.get(), fd2.get()));
84 
85   char buf[2];
86   unique_fd received1, received2;
87 
88   ssize_t rc = ReceiveFileDescriptors(recv.get(), buf, 1, &received1, &received2);
89   if (Seqpacket()) {
90     ASSERT_EQ(-1, rc);
91     ASSERT_EQ(EMSGSIZE, errno);
92     ASSERT_EQ(-1, received1.get());
93     ASSERT_EQ(-1, received2.get());
94   } else {
95     ASSERT_EQ(1, rc);
96     ASSERT_NE(-1, received1.get());
97     ASSERT_NE(-1, received2.get());
98     ASSERT_EQ(ino1, GetInode(received1.get()));
99     ASSERT_EQ(ino2, GetInode(received2.get()));
100     ASSERT_EQ(1, read(recv.get(), buf, 2));
101   }
102 }
103 
TEST_P(CmsgTest,msg_ctrunc)104 TEST_P(CmsgTest, msg_ctrunc) {
105   ASSERT_EQ(1, SendFileDescriptors(send.get(), "a", 1, fd1.get(), fd2.get()));
106 
107   char buf[2];
108   unique_fd received;
109   ASSERT_EQ(-1, ReceiveFileDescriptors(recv.get(), buf, 1, &received));
110   ASSERT_EQ(EMSGSIZE, errno);
111   ASSERT_EQ(-1, received.get());
112 }
113 
TEST_P(CmsgTest,peek)114 TEST_P(CmsgTest, peek) {
115   ASSERT_EQ(1, SendFileDescriptors(send.get(), "a", 1, fd1.get()));
116 
117   char buf[2];
118   ASSERT_EQ(1, ::recv(recv.get(), buf, sizeof(buf), MSG_PEEK));
119   ASSERT_EQ('a', buf[0]);
120 
121   unique_fd received;
122   ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 1, &received));
123   ASSERT_EQ(ino1, GetInode(received.get()));
124 }
125 
TEST_P(CmsgTest,stream_fd_association)126 TEST_P(CmsgTest, stream_fd_association) {
127   if (Seqpacket()) {
128     return;
129   }
130 
131   // fds are associated with the first byte of the write.
132   ASSERT_EQ(1, TEMP_FAILURE_RETRY(write(send.get(), "a", 1)));
133   ASSERT_EQ(2, SendFileDescriptors(send.get(), "bc", 2, fd1.get()));
134   ASSERT_EQ(1, SendFileDescriptors(send.get(), "d", 1, fd2.get()));
135   char buf[2];
136   ASSERT_EQ(2, TEMP_FAILURE_RETRY(read(recv.get(), buf, 2)));
137   ASSERT_EQ(0, memcmp(buf, "ab", 2));
138 
139   std::vector<unique_fd> received1;
140   ssize_t rc = ReceiveFileDescriptorVector(recv.get(), buf, 1, 1, &received1);
141   ASSERT_EQ(1, rc);
142   ASSERT_EQ('c', buf[0]);
143   ASSERT_TRUE(received1.empty());
144 
145   unique_fd received2;
146   rc = ReceiveFileDescriptors(recv.get(), buf, 1, &received2);
147   ASSERT_EQ(1, rc);
148   ASSERT_EQ('d', buf[0]);
149   ASSERT_EQ(ino2, GetInode(received2.get()));
150 }
151 
TEST_P(CmsgTest,multiple_fd_ordering)152 TEST_P(CmsgTest, multiple_fd_ordering) {
153   ASSERT_EQ(1, SendFileDescriptors(send.get(), "a", 1, fd1.get(), fd2.get()));
154 
155   char buf[2];
156   unique_fd received1, received2;
157   ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 1, &received1, &received2));
158 
159   ASSERT_NE(-1, received1.get());
160   ASSERT_NE(-1, received2.get());
161 
162   ASSERT_EQ(ino1, GetInode(received1.get()));
163   ASSERT_EQ(ino2, GetInode(received2.get()));
164 }
165 
TEST_P(CmsgTest,separate_fd_ordering)166 TEST_P(CmsgTest, separate_fd_ordering) {
167   ASSERT_EQ(1, SendFileDescriptors(send.get(), "a", 1, fd1.get()));
168   ASSERT_EQ(1, SendFileDescriptors(send.get(), "b", 1, fd2.get()));
169 
170   char buf[2];
171   unique_fd received1, received2;
172   ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 1, &received1));
173   ASSERT_EQ(1, ReceiveFileDescriptors(recv.get(), buf, 1, &received2));
174 
175   ASSERT_NE(-1, received1.get());
176   ASSERT_NE(-1, received2.get());
177 
178   ASSERT_EQ(ino1, GetInode(received1.get()));
179   ASSERT_EQ(ino2, GetInode(received2.get()));
180 }
181 
TEST_P(CmsgTest,separate_fds_no_coalescing)182 TEST_P(CmsgTest, separate_fds_no_coalescing) {
183   unique_fd sent1(dup(tmp1.fd));
184   unique_fd sent2(dup(tmp2.fd));
185 
186   ASSERT_EQ(1, SendFileDescriptors(send.get(), "", 1, fd1.get()));
187   ASSERT_EQ(1, SendFileDescriptors(send.get(), "", 1, fd2.get()));
188 
189   char buf[2];
190   std::vector<unique_fd> received;
191   ASSERT_EQ(1, ReceiveFileDescriptorVector(recv.get(), buf, 2, 2, &received));
192   ASSERT_EQ(1U, received.size());
193   ASSERT_EQ(ino1, GetInode(received[0].get()));
194 
195   ASSERT_EQ(1, ReceiveFileDescriptorVector(recv.get(), buf, 2, 2, &received));
196   ASSERT_EQ(1U, received.size());
197   ASSERT_EQ(ino2, GetInode(received[0].get()));
198 }
199 
200 INSTANTIATE_TEST_CASE_P(CmsgTest, CmsgTest, testing::Bool());
201 
202 #endif
203