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