1 #include <errno.h>
2 #include <gtest/gtest.h>
3 #include <netdb.h>
4 #include <string.h>
5 #include <sys/un.h>
6 #include <vector>
7 using namespace testing::ext;
8
9 class FortifyRecvchkTest : public testing::Test {
SetUp()10 void SetUp() override {}
TearDown()11 void TearDown() override {}
12 };
13
14 struct DataLink {
15 std::function<bool(int)> callbackFn;
16 const char* sockPath;
17 };
18
ConnectFunc(void * data)19 static void* ConnectFunc(void* data)
20 {
21 DataLink* p = reinterpret_cast<DataLink*>(data);
22 std::function<bool(int)> callbackFn = p->callbackFn;
23 void* returnValue = nullptr;
24
25 int fd = socket(PF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
26 if (fd < 0) {
27 return reinterpret_cast<void*>(-1);
28 }
29
30 struct sockaddr_un addr;
31 memset(&addr, 0, sizeof(addr));
32 addr.sun_family = AF_UNIX;
33 addr.sun_path[0] = '\0';
34 strcpy(addr.sun_path + 1, p->sockPath);
35
36 if (connect(fd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) < 0) {
37 returnValue = reinterpret_cast<void*>(-1);
38 } else if (callbackFn && !callbackFn(fd)) {
39 returnValue = reinterpret_cast<void*>(-1);
40 }
41
42 close(fd);
43 return returnValue;
44 }
45
46 struct ReturnVal {
47 int fd;
48 struct sockaddr_un addr;
49 };
50
SockInit(const char * sockPath,struct ReturnVal & returnVal)51 static void SockInit(const char* sockPath, struct ReturnVal& returnVal)
52 {
53 int fd = socket(PF_UNIX, SOCK_SEQPACKET, 0);
54 EXPECT_NE(fd, -1);
55
56 struct sockaddr_un addr;
57 memset(&addr, 0, sizeof(addr));
58 addr.sun_family = AF_UNIX;
59 addr.sun_path[0] = '\0';
60 strcpy(addr.sun_path + 1, sockPath);
61 EXPECT_NE(-1, bind(fd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)));
62 EXPECT_NE(-1, listen(fd, 1));
63
64 returnVal.fd = fd;
65 returnVal.addr = addr;
66 }
67
CallSelectFunc(struct ReturnVal returnVal)68 static void CallSelectFunc(struct ReturnVal returnVal)
69 {
70 fd_set readSet;
71 FD_ZERO(&readSet);
72 FD_SET(returnVal.fd, &readSet);
73 timeval tv = { .tv_sec = 5, .tv_usec = 0 };
74 EXPECT_GT(select(returnVal.fd + 1, &readSet, nullptr, nullptr, &tv), 0);
75 }
76
77 const char* g_testRecv = "hello";
Send(int fd)78 static bool Send(int fd)
79 {
80 if (send(fd, g_testRecv, strlen(g_testRecv) + 1, 0) < 0) {
81 return false;
82 }
83 return true;
84 }
85
86 /**
87 * @tc.name: __recv_chk_001
88 * @tc.desc: This test case helps ensure that the recv_chk function can successfully receive data from a connected
89 * socket and that the received data matches the expected content.
90 * @tc.type: FUNC
91 **/
92 HWTEST_F(FortifyRecvchkTest, __recv_chk_001, TestSize.Level1)
93 {
94 const char* sockPath = "test_recv_chk";
95 struct ReturnVal returnVal;
96 SockInit(sockPath, returnVal);
97 DataLink ConnectData;
98 ConnectData.callbackFn = Send;
99 ConnectData.sockPath = sockPath;
100
101 struct sockaddr_un* addr = &returnVal.addr;
102 pthread_t thread;
103 int ret = pthread_create(&thread, nullptr, ConnectFunc, &ConnectData);
104 EXPECT_EQ(0, ret);
105 CallSelectFunc(returnVal);
106
107 socklen_t len = sizeof(*addr);
108 int acceptFd = accept(returnVal.fd, reinterpret_cast<struct sockaddr*>(addr), &len);
109 EXPECT_NE(acceptFd, -1) << strerror(errno);
110 char buf[BUFSIZ];
111 memset(buf, 0, sizeof(buf));
112 size_t len1 = sizeof(buf);
113 size_t result = static_cast<size_t>(__recv_chk(acceptFd, buf, len1, len1, 0));
114 EXPECT_EQ(strlen(g_testRecv) + 1, result);
115 EXPECT_STREQ(g_testRecv, buf);
116 close(acceptFd);
117
118 void* retVal;
119 EXPECT_EQ(0, pthread_join(thread, &retVal));
120 EXPECT_EQ(nullptr, retVal);
121 close(returnVal.fd);
122 }
123