xref: /aosp_15_r20/trusty/kernel/app/usercopytest/iovectest.c (revision 344aa361028b423587d4ef3fa52a23d194628137)
1*344aa361SAndroid Build Coastguard Worker #include <kernel/usercopy.h>
2*344aa361SAndroid Build Coastguard Worker #include <lib/unittest/unittest.h>
3*344aa361SAndroid Build Coastguard Worker 
4*344aa361SAndroid Build Coastguard Worker typedef struct iovectest {
5*344aa361SAndroid Build Coastguard Worker     struct vmm_aspace* aspace;
6*344aa361SAndroid Build Coastguard Worker     user_addr_t buffer_addr;
7*344aa361SAndroid Build Coastguard Worker     user_addr_t iovec_addr;
8*344aa361SAndroid Build Coastguard Worker } iovectest_t;
9*344aa361SAndroid Build Coastguard Worker 
10*344aa361SAndroid Build Coastguard Worker static const char test_pattern[] = "abcdefghijklmnopqrstuvwxyz!";
11*344aa361SAndroid Build Coastguard Worker 
TEST_F_SETUP(iovectest)12*344aa361SAndroid Build Coastguard Worker TEST_F_SETUP(iovectest) {
13*344aa361SAndroid Build Coastguard Worker     _state->aspace = NULL;
14*344aa361SAndroid Build Coastguard Worker 
15*344aa361SAndroid Build Coastguard Worker     /* Setup a user address space. */
16*344aa361SAndroid Build Coastguard Worker     struct vmm_aspace* aspace = NULL;
17*344aa361SAndroid Build Coastguard Worker     ASSERT_EQ(0, vmm_create_aspace(&aspace, "iovectest", 0));
18*344aa361SAndroid Build Coastguard Worker     _state->aspace = aspace;
19*344aa361SAndroid Build Coastguard Worker     _state->buffer_addr = 8 * PAGE_SIZE;
20*344aa361SAndroid Build Coastguard Worker     _state->iovec_addr = _state->buffer_addr + 256;
21*344aa361SAndroid Build Coastguard Worker 
22*344aa361SAndroid Build Coastguard Worker     /* Allocate a page of memory. */
23*344aa361SAndroid Build Coastguard Worker     void* user_ptr = (void*)(uintptr_t)_state->buffer_addr;
24*344aa361SAndroid Build Coastguard Worker     ASSERT_EQ(0, vmm_alloc(aspace, "iovectest", PAGE_SIZE, &user_ptr, 0,
25*344aa361SAndroid Build Coastguard Worker                            VMM_FLAG_VALLOC_SPECIFIC,
26*344aa361SAndroid Build Coastguard Worker                            ARCH_MMU_FLAG_PERM_USER |
27*344aa361SAndroid Build Coastguard Worker                                    ARCH_MMU_FLAG_PERM_NO_EXECUTE));
28*344aa361SAndroid Build Coastguard Worker 
29*344aa361SAndroid Build Coastguard Worker     vmm_set_active_aspace(aspace);
30*344aa361SAndroid Build Coastguard Worker 
31*344aa361SAndroid Build Coastguard Worker     /* Write the test pattern into memory. */
32*344aa361SAndroid Build Coastguard Worker     ASSERT_EQ(0, copy_to_user(_state->buffer_addr, test_pattern,
33*344aa361SAndroid Build Coastguard Worker                               sizeof(test_pattern)));
34*344aa361SAndroid Build Coastguard Worker 
35*344aa361SAndroid Build Coastguard Worker test_abort:;
36*344aa361SAndroid Build Coastguard Worker }
37*344aa361SAndroid Build Coastguard Worker 
TEST_F_TEARDOWN(iovectest)38*344aa361SAndroid Build Coastguard Worker TEST_F_TEARDOWN(iovectest) {
39*344aa361SAndroid Build Coastguard Worker     vmm_set_active_aspace(NULL);
40*344aa361SAndroid Build Coastguard Worker     if (_state->aspace) {
41*344aa361SAndroid Build Coastguard Worker         vmm_free_aspace(_state->aspace);
42*344aa361SAndroid Build Coastguard Worker         _state->aspace = NULL;
43*344aa361SAndroid Build Coastguard Worker     }
44*344aa361SAndroid Build Coastguard Worker }
45*344aa361SAndroid Build Coastguard Worker 
46*344aa361SAndroid Build Coastguard Worker /* Check the test fixture is OK. */
TEST_F(iovectest,fixture)47*344aa361SAndroid Build Coastguard Worker TEST_F(iovectest, fixture) {
48*344aa361SAndroid Build Coastguard Worker     ASSERT_LT(0, sizeof(test_pattern));
49*344aa361SAndroid Build Coastguard Worker 
50*344aa361SAndroid Build Coastguard Worker     /* Non-zero clear because last character of the pattern is null. */
51*344aa361SAndroid Build Coastguard Worker     char buf[sizeof(test_pattern)];
52*344aa361SAndroid Build Coastguard Worker     memset(buf, 0xff, sizeof(test_pattern));
53*344aa361SAndroid Build Coastguard Worker 
54*344aa361SAndroid Build Coastguard Worker     /* Read back the test pattern. */
55*344aa361SAndroid Build Coastguard Worker     int ret = copy_from_user(buf, _state->buffer_addr, sizeof(test_pattern));
56*344aa361SAndroid Build Coastguard Worker     ASSERT_EQ(0, ret);
57*344aa361SAndroid Build Coastguard Worker 
58*344aa361SAndroid Build Coastguard Worker     /* Make sure it's what we expect. */
59*344aa361SAndroid Build Coastguard Worker     ASSERT_EQ(0, memcmp(test_pattern, buf, sizeof(test_pattern)));
60*344aa361SAndroid Build Coastguard Worker 
61*344aa361SAndroid Build Coastguard Worker test_abort:;
62*344aa361SAndroid Build Coastguard Worker }
63*344aa361SAndroid Build Coastguard Worker 
64*344aa361SAndroid Build Coastguard Worker /* Write an iovec with evenly spaced chunks to userspace. */
write_chunked_iovec(iovectest_t * _state,int size)65*344aa361SAndroid Build Coastguard Worker static int write_chunked_iovec(iovectest_t* _state, int size) {
66*344aa361SAndroid Build Coastguard Worker     struct iovec_user uiov[sizeof(test_pattern)];
67*344aa361SAndroid Build Coastguard Worker     unsigned int index = 0;
68*344aa361SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < sizeof(test_pattern); i += size, index += 1) {
69*344aa361SAndroid Build Coastguard Worker         uiov[index].iov_base = _state->buffer_addr + i;
70*344aa361SAndroid Build Coastguard Worker         int len = sizeof(test_pattern) - i;
71*344aa361SAndroid Build Coastguard Worker         if (size < len) {
72*344aa361SAndroid Build Coastguard Worker             len = size;
73*344aa361SAndroid Build Coastguard Worker         }
74*344aa361SAndroid Build Coastguard Worker         uiov[index].iov_len = len;
75*344aa361SAndroid Build Coastguard Worker     }
76*344aa361SAndroid Build Coastguard Worker 
77*344aa361SAndroid Build Coastguard Worker     /* Copy into user space. */
78*344aa361SAndroid Build Coastguard Worker     ASSERT_EQ(0,
79*344aa361SAndroid Build Coastguard Worker               copy_to_user(_state->iovec_addr, uiov,
80*344aa361SAndroid Build Coastguard Worker                            sizeof(struct iovec_user) * index),
81*344aa361SAndroid Build Coastguard Worker               "chunk %d", size);
82*344aa361SAndroid Build Coastguard Worker 
83*344aa361SAndroid Build Coastguard Worker     return index;
84*344aa361SAndroid Build Coastguard Worker 
85*344aa361SAndroid Build Coastguard Worker test_abort:
86*344aa361SAndroid Build Coastguard Worker     return 0;
87*344aa361SAndroid Build Coastguard Worker }
88*344aa361SAndroid Build Coastguard Worker 
89*344aa361SAndroid Build Coastguard Worker /* A format string to help understand the exact case the assertion failed. */
90*344aa361SAndroid Build Coastguard Worker #define LOCATION_MESSAGE "chunk size %zu / iov_cnt %d", buffer_chunk, iov_cnt
91*344aa361SAndroid Build Coastguard Worker 
92*344aa361SAndroid Build Coastguard Worker /* Copy all the data from userspace using a buffer of limited size. */
iovectest_readback(iovectest_t * _state,size_t buffer_chunk,int iov_cnt,const void * expected,size_t expected_len)93*344aa361SAndroid Build Coastguard Worker static void iovectest_readback(iovectest_t* _state,
94*344aa361SAndroid Build Coastguard Worker                                size_t buffer_chunk,
95*344aa361SAndroid Build Coastguard Worker                                int iov_cnt,
96*344aa361SAndroid Build Coastguard Worker                                const void* expected,
97*344aa361SAndroid Build Coastguard Worker                                size_t expected_len) {
98*344aa361SAndroid Build Coastguard Worker     uint8_t buf[sizeof(test_pattern) * 2];
99*344aa361SAndroid Build Coastguard Worker     memset(buf, 0xff, sizeof(buf));
100*344aa361SAndroid Build Coastguard Worker 
101*344aa361SAndroid Build Coastguard Worker     uint8_t tmp[sizeof(test_pattern) * 2];
102*344aa361SAndroid Build Coastguard Worker     memset(tmp, 0xff, sizeof(tmp));
103*344aa361SAndroid Build Coastguard Worker 
104*344aa361SAndroid Build Coastguard Worker     /* Check chunk sizes. */
105*344aa361SAndroid Build Coastguard Worker     ASSERT_LE(expected_len, sizeof(buf), LOCATION_MESSAGE);
106*344aa361SAndroid Build Coastguard Worker     ASSERT_LE(0, buffer_chunk, LOCATION_MESSAGE);
107*344aa361SAndroid Build Coastguard Worker     ASSERT_LE(buffer_chunk, sizeof(tmp), LOCATION_MESSAGE);
108*344aa361SAndroid Build Coastguard Worker 
109*344aa361SAndroid Build Coastguard Worker     /* Read the data a buffer at a time. */
110*344aa361SAndroid Build Coastguard Worker     struct iovec_iter iter = iovec_iter_create(iov_cnt);
111*344aa361SAndroid Build Coastguard Worker     size_t total_bytes = 0;
112*344aa361SAndroid Build Coastguard Worker     while (iovec_iter_has_next(&iter)) {
113*344aa361SAndroid Build Coastguard Worker         int ret = user_iovec_to_membuf_iter(tmp, buffer_chunk,
114*344aa361SAndroid Build Coastguard Worker                                             _state->iovec_addr, &iter);
115*344aa361SAndroid Build Coastguard Worker         /* Check the return value. */
116*344aa361SAndroid Build Coastguard Worker         ASSERT_LE(0, ret, LOCATION_MESSAGE);
117*344aa361SAndroid Build Coastguard Worker         ASSERT_LE(ret, buffer_chunk, LOCATION_MESSAGE);
118*344aa361SAndroid Build Coastguard Worker         /* If there is more data, the buffer should be filled. */
119*344aa361SAndroid Build Coastguard Worker         if (iter.iov_index < iter.iov_cnt) {
120*344aa361SAndroid Build Coastguard Worker             ASSERT_EQ(ret, buffer_chunk, LOCATION_MESSAGE);
121*344aa361SAndroid Build Coastguard Worker         }
122*344aa361SAndroid Build Coastguard Worker         /* Accumulate the result. */
123*344aa361SAndroid Build Coastguard Worker         memcpy(buf + total_bytes, tmp, ret);
124*344aa361SAndroid Build Coastguard Worker         total_bytes += ret;
125*344aa361SAndroid Build Coastguard Worker     }
126*344aa361SAndroid Build Coastguard Worker     /* Did we get the data we expect? */
127*344aa361SAndroid Build Coastguard Worker     ASSERT_EQ(expected_len, total_bytes, LOCATION_MESSAGE);
128*344aa361SAndroid Build Coastguard Worker     ASSERT_EQ(0, memcmp(expected, buf, expected_len), LOCATION_MESSAGE);
129*344aa361SAndroid Build Coastguard Worker 
130*344aa361SAndroid Build Coastguard Worker test_abort:;
131*344aa361SAndroid Build Coastguard Worker }
132*344aa361SAndroid Build Coastguard Worker 
133*344aa361SAndroid Build Coastguard Worker /* Test various combinations of iovec size and read buffer size. */
TEST_F(iovectest,varied_chunk_sizes)134*344aa361SAndroid Build Coastguard Worker TEST_F(iovectest, varied_chunk_sizes) {
135*344aa361SAndroid Build Coastguard Worker     /* Note the chunk sizes can exceed the size of the payload. */
136*344aa361SAndroid Build Coastguard Worker     for (size_t iovec_chunk = 1; iovec_chunk <= sizeof(test_pattern) + 2;
137*344aa361SAndroid Build Coastguard Worker          iovec_chunk++) {
138*344aa361SAndroid Build Coastguard Worker         for (size_t buffer_chunk = 1; buffer_chunk <= sizeof(test_pattern) + 2;
139*344aa361SAndroid Build Coastguard Worker              buffer_chunk++) {
140*344aa361SAndroid Build Coastguard Worker             int iov_cnt = write_chunked_iovec(_state, iovec_chunk);
141*344aa361SAndroid Build Coastguard Worker             iovectest_readback(_state, buffer_chunk, iov_cnt, test_pattern,
142*344aa361SAndroid Build Coastguard Worker                                sizeof(test_pattern));
143*344aa361SAndroid Build Coastguard Worker         }
144*344aa361SAndroid Build Coastguard Worker     }
145*344aa361SAndroid Build Coastguard Worker }
146*344aa361SAndroid Build Coastguard Worker 
147*344aa361SAndroid Build Coastguard Worker /* Make sure that zero-length iovecs have no effect. */
TEST_F(iovectest,zerolength)148*344aa361SAndroid Build Coastguard Worker TEST_F(iovectest, zerolength) {
149*344aa361SAndroid Build Coastguard Worker     struct iovec_user uiov[] = {
150*344aa361SAndroid Build Coastguard Worker             {
151*344aa361SAndroid Build Coastguard Worker                     .iov_base = _state->buffer_addr + 0,
152*344aa361SAndroid Build Coastguard Worker                     .iov_len = 0,
153*344aa361SAndroid Build Coastguard Worker             },
154*344aa361SAndroid Build Coastguard Worker             {
155*344aa361SAndroid Build Coastguard Worker                     .iov_base = 0,
156*344aa361SAndroid Build Coastguard Worker                     .iov_len = 0,
157*344aa361SAndroid Build Coastguard Worker             },
158*344aa361SAndroid Build Coastguard Worker             {
159*344aa361SAndroid Build Coastguard Worker                     .iov_base = _state->buffer_addr + 0,
160*344aa361SAndroid Build Coastguard Worker                     .iov_len = 3,
161*344aa361SAndroid Build Coastguard Worker             },
162*344aa361SAndroid Build Coastguard Worker             {
163*344aa361SAndroid Build Coastguard Worker                     .iov_base = _state->buffer_addr + 3,
164*344aa361SAndroid Build Coastguard Worker                     .iov_len = 0,
165*344aa361SAndroid Build Coastguard Worker             },
166*344aa361SAndroid Build Coastguard Worker             {
167*344aa361SAndroid Build Coastguard Worker                     .iov_base = 0,
168*344aa361SAndroid Build Coastguard Worker                     .iov_len = 0,
169*344aa361SAndroid Build Coastguard Worker             },
170*344aa361SAndroid Build Coastguard Worker             {
171*344aa361SAndroid Build Coastguard Worker                     .iov_base = _state->buffer_addr + 3,
172*344aa361SAndroid Build Coastguard Worker                     .iov_len = 0,
173*344aa361SAndroid Build Coastguard Worker             },
174*344aa361SAndroid Build Coastguard Worker             {
175*344aa361SAndroid Build Coastguard Worker                     .iov_base = _state->buffer_addr + 3,
176*344aa361SAndroid Build Coastguard Worker                     .iov_len = 25,
177*344aa361SAndroid Build Coastguard Worker             },
178*344aa361SAndroid Build Coastguard Worker             {
179*344aa361SAndroid Build Coastguard Worker                     .iov_base = _state->buffer_addr + 28,
180*344aa361SAndroid Build Coastguard Worker                     .iov_len = 0,
181*344aa361SAndroid Build Coastguard Worker             },
182*344aa361SAndroid Build Coastguard Worker             {
183*344aa361SAndroid Build Coastguard Worker                     .iov_base = 0,
184*344aa361SAndroid Build Coastguard Worker                     .iov_len = 0,
185*344aa361SAndroid Build Coastguard Worker             },
186*344aa361SAndroid Build Coastguard Worker     };
187*344aa361SAndroid Build Coastguard Worker     ASSERT_EQ(0, copy_to_user(_state->iovec_addr, uiov, sizeof(uiov)));
188*344aa361SAndroid Build Coastguard Worker 
189*344aa361SAndroid Build Coastguard Worker     iovectest_readback(_state, 10, countof(uiov), test_pattern,
190*344aa361SAndroid Build Coastguard Worker                        sizeof(test_pattern));
191*344aa361SAndroid Build Coastguard Worker 
192*344aa361SAndroid Build Coastguard Worker test_abort:;
193*344aa361SAndroid Build Coastguard Worker }
194*344aa361SAndroid Build Coastguard Worker 
195*344aa361SAndroid Build Coastguard Worker /* Make sure we can read something other than the exact test pattern. */
TEST_F(iovectest,swap_data)196*344aa361SAndroid Build Coastguard Worker TEST_F(iovectest, swap_data) {
197*344aa361SAndroid Build Coastguard Worker     struct iovec_user uiov[] = {
198*344aa361SAndroid Build Coastguard Worker             {
199*344aa361SAndroid Build Coastguard Worker                     .iov_base = _state->buffer_addr + 14,
200*344aa361SAndroid Build Coastguard Worker                     .iov_len = 14,
201*344aa361SAndroid Build Coastguard Worker             },
202*344aa361SAndroid Build Coastguard Worker             {
203*344aa361SAndroid Build Coastguard Worker                     .iov_base = _state->buffer_addr + 0,
204*344aa361SAndroid Build Coastguard Worker                     .iov_len = 14,
205*344aa361SAndroid Build Coastguard Worker             },
206*344aa361SAndroid Build Coastguard Worker     };
207*344aa361SAndroid Build Coastguard Worker     ASSERT_EQ(0, copy_to_user(_state->iovec_addr, uiov, sizeof(uiov)));
208*344aa361SAndroid Build Coastguard Worker 
209*344aa361SAndroid Build Coastguard Worker     const char expected[] = "opqrstuvwxyz!\0abcdefghijklmn";
210*344aa361SAndroid Build Coastguard Worker     iovectest_readback(_state, 11, countof(uiov), expected, 28);
211*344aa361SAndroid Build Coastguard Worker 
212*344aa361SAndroid Build Coastguard Worker test_abort:;
213*344aa361SAndroid Build Coastguard Worker }
214*344aa361SAndroid Build Coastguard Worker 
215*344aa361SAndroid Build Coastguard Worker PORT_TEST(iovectest, "com.android.kernel.iovectest");
216