1 /*
2  * Copyright (C) 2020 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 #define TLOG_TAG "lender"
18 
19 #include <assert.h>
20 
21 #include <inttypes.h>
22 #include <lk/macros.h>
23 #include <stddef.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/mman.h>
28 
29 #include <lib/tipc/tipc.h>
30 #include <lib/tipc/tipc_srv.h>
31 #include <lib/unittest/unittest.h>
32 
33 #include <trusty/memref.h>
34 #include <trusty/sys/mman.h>
35 #include <trusty/time.h>
36 #include <trusty_unittest.h>
37 
38 #include <lender.h>
39 #include <lender_consts.h>
40 
41 #define PAGE_SIZE 0x1000
42 #define MAX_WRITE 0x800
43 
44 static __attribute__((aligned(PAGE_SIZE))) char bss_page[PAGE_SIZE];
45 static __attribute__((aligned(PAGE_SIZE))) char rw_page[PAGE_SIZE] = {1};
46 
47 #define MM_RW (MMAP_FLAG_PROT_READ | MMAP_FLAG_PROT_WRITE)
48 
49 static handle_t bss_memref = INVALID_IPC_HANDLE;
50 static handle_t rw_memref = INVALID_IPC_HANDLE;
51 
52 /*
53  * This only creates bss_memref and rw_memref; creating a ro_memref would fail
54  * since RO segments are not backed by vmm_objs (b/149849862).
55  */
init(void)56 static void init(void) {
57     int rc = memref_create(bss_page, PAGE_SIZE, MM_RW);
58     if (rc < 0) {
59         TLOGE("bss memref create failed: (%d)\n", rc);
60         abort();
61     }
62 
63     bss_memref = rc;
64 
65     rc = memref_create(rw_page, PAGE_SIZE, MM_RW);
66     if (rc < 0) {
67         TLOGE("rw memref create failed: (%d)\n", rc);
68         abort();
69     }
70 
71     rw_memref = rc;
72 }
73 
74 static struct tipc_port_acl lender_port_acl = {
75         .flags = IPC_PORT_ALLOW_TA_CONNECT,
76         .uuid_num = 0,
77         .uuids = NULL,
78         .extra_data = NULL,
79 };
80 
81 static struct tipc_port lender_port = {
82         .name = LENDER_PORT,
83         .msg_max_size = sizeof(struct lender_msg) + MAX_WRITE,
84         .msg_queue_len = 1,
85         .acl = &lender_port_acl,
86         .priv = NULL,
87 };
88 
lender_lend(handle_t chan,enum lender_command cmd)89 static int lender_lend(handle_t chan, enum lender_command cmd) {
90     handle_t to_lend;
91     switch (cmd) {
92     case LENDER_LEND_BSS:
93         to_lend = bss_memref;
94         break;
95     case LENDER_LEND_RW:
96         to_lend = rw_memref;
97         break;
98     default:
99         TLOGE("Unsupported lend type %d\n", cmd);
100         return -1;
101     }
102 
103     if (to_lend == INVALID_IPC_HANDLE) {
104         TLOGE("Refusing to lend uninitialized handle.\n");
105         return -1;
106     }
107 
108     struct ipc_msg msg = {
109             .iov = NULL,
110             .num_iov = 0,
111             .handles = &to_lend,
112             .num_handles = 1,
113     };
114 
115     return send_msg(chan, &msg);
116 }
117 
lender_check_region(struct lender_region * region,size_t size)118 static int lender_check_region(struct lender_region* region, size_t size) {
119     size_t end;
120     if (__builtin_add_overflow(region->offset, region->size, &end)) {
121         return -1;
122     }
123 
124     if (end > size) {
125         return -1;
126     }
127 
128     return 0;
129 }
130 
lender_read_bss(handle_t chan,struct lender_region * region)131 static int lender_read_bss(handle_t chan, struct lender_region* region) {
132     if (lender_check_region(region, PAGE_SIZE) != 0) {
133         return -1;
134     }
135 
136     int rc = tipc_send1(chan, &bss_page[region->offset], region->size);
137     if (rc != (int)region->size) {
138         return -1;
139     }
140 
141     return 0;
142 }
143 
lender_write_bss(handle_t chan,struct lender_region * region,const char * data)144 static int lender_write_bss(handle_t chan,
145                             struct lender_region* region,
146                             const char* data) {
147     if (lender_check_region(region, PAGE_SIZE) != 0) {
148         return -1;
149     }
150 
151     memcpy(&bss_page[region->offset], data, region->size);
152 
153     return tipc_send1(chan, NULL, 0);
154 }
155 
lender_on_message(const struct tipc_port * port,handle_t chan,void * ctx)156 static int lender_on_message(const struct tipc_port* port,
157                              handle_t chan,
158                              void* ctx) {
159     assert(port == &lender_port);
160     assert(ctx == NULL);
161     struct lender_msg msg;
162     char data[MAX_WRITE];
163 
164     int rc = tipc_recv2(chan, sizeof(msg), &msg, sizeof(msg), data,
165                         sizeof(data));
166     if (rc < 0) {
167         TLOGE("Failed to receive message (%d)\n", rc);
168         return rc;
169     }
170 
171     switch (msg.cmd) {
172     case LENDER_LEND_BSS:
173     case LENDER_LEND_RW:
174         rc = lender_lend(chan, msg.cmd);
175         if (rc < 0) {
176             return rc;
177         }
178         break;
179     case LENDER_SUICIDE:
180         exit(0);
181         break;
182     case LENDER_READ_BSS:
183         rc = lender_read_bss(chan, &msg.region);
184         if (rc < 0) {
185             return rc;
186         }
187         break;
188     case LENDER_WRITE_BSS:
189         if (rc - sizeof(struct lender_msg) != msg.region.size) {
190             return -1;
191         }
192         rc = lender_write_bss(chan, &msg.region, data);
193         if (rc < 0) {
194             return rc;
195         }
196         break;
197     default:
198         TLOGE("Bad command: %d\n", msg.cmd);
199         return -1;
200     }
201 
202     return 0;
203 }
204 
205 static struct tipc_srv_ops lender_ops = {
206         .on_message = lender_on_message,
207 };
208 
main(void)209 int main(void) {
210     init();
211 
212     struct tipc_hset* hset = tipc_hset_create();
213 
214     if (!hset) {
215         return -1;
216     }
217 
218     int rc = tipc_add_service(hset, &lender_port, 1, 1, &lender_ops);
219     if (rc < 0) {
220         return rc;
221     }
222 
223     rc = tipc_run_event_loop(hset);
224     TLOGE("lender going down: (%d)\n", rc);
225     return rc;
226 }
227