1 /*
2 * Copyright (C) 2016 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 <errno.h>
18 #include <fcntl.h>
19 #include <stdint.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/ioctl.h>
24 #include <unistd.h>
25
26 #include <linux/major.h>
27 #include <linux/mmc/ioctl.h>
28
29 #include "ipc.h"
30 #include "log.h"
31 #include "rpmb.h"
32 #include "storage.h"
33
34 #define MMC_READ_MULTIPLE_BLOCK 18
35 #define MMC_WRITE_MULTIPLE_BLOCK 25
36 #define MMC_RELIABLE_WRITE_FLAG (1 << 31)
37
38 #define MMC_RSP_PRESENT (1 << 0)
39 #define MMC_RSP_CRC (1 << 2)
40 #define MMC_RSP_OPCODE (1 << 4)
41 #define MMC_CMD_ADTC (1 << 5)
42 #define MMC_RSP_SPI_S1 (1 << 7)
43 #define MMC_RSP_R1 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
44 #define MMC_RSP_SPI_R1 (MMC_RSP_SPI_S1)
45
46 #define MMC_WRITE_FLAG_R 0
47 #define MMC_WRITE_FLAG_W 1
48 #define MMC_WRITE_FLAG_RELW (MMC_WRITE_FLAG_W | MMC_RELIABLE_WRITE_FLAG)
49
50 #define MMC_BLOCK_SIZE 512
51
52 static int rpmb_fd = -1;
53 static uint8_t read_buf[4096];
54 static enum dev_type dev_type = UNKNOWN_RPMB;
55
56 #ifdef RPMB_DEBUG
57
print_buf(const char * prefix,const uint8_t * buf,size_t size)58 static void print_buf(const char* prefix, const uint8_t* buf, size_t size) {
59 size_t i;
60
61 printf("%s @%p [%zu]", prefix, buf, size);
62 for (i = 0; i < size; i++) {
63 if (i && i % 32 == 0) printf("\n%*s", (int)strlen(prefix), "");
64 printf(" %02x", buf[i]);
65 }
66 printf("\n");
67 fflush(stdout);
68 }
69
70 #endif
71
send_mmc_rpmb_req(int mmc_fd,const struct storage_rpmb_send_req * req)72 static int send_mmc_rpmb_req(int mmc_fd, const struct storage_rpmb_send_req* req) {
73 struct {
74 struct mmc_ioc_multi_cmd multi;
75 struct mmc_ioc_cmd cmd_buf[3];
76 } mmc = {};
77 struct mmc_ioc_cmd* cmd = mmc.multi.cmds;
78 int rc;
79
80 const uint8_t* write_buf = req->payload;
81 if (req->reliable_write_size) {
82 cmd->write_flag = MMC_WRITE_FLAG_RELW;
83 cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK;
84 cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
85 cmd->blksz = MMC_BLOCK_SIZE;
86 cmd->blocks = req->reliable_write_size / MMC_BLOCK_SIZE;
87 mmc_ioc_cmd_set_data((*cmd), write_buf);
88 #ifdef RPMB_DEBUG
89 ALOGI("opcode: 0x%x, write_flag: 0x%x\n", cmd->opcode, cmd->write_flag);
90 print_buf("request: ", write_buf, req->reliable_write_size);
91 #endif
92 write_buf += req->reliable_write_size;
93 mmc.multi.num_of_cmds++;
94 cmd++;
95 }
96
97 if (req->write_size) {
98 cmd->write_flag = MMC_WRITE_FLAG_W;
99 cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK;
100 cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
101 cmd->blksz = MMC_BLOCK_SIZE;
102 cmd->blocks = req->write_size / MMC_BLOCK_SIZE;
103 mmc_ioc_cmd_set_data((*cmd), write_buf);
104 #ifdef RPMB_DEBUG
105 ALOGI("opcode: 0x%x, write_flag: 0x%x\n", cmd->opcode, cmd->write_flag);
106 print_buf("request: ", write_buf, req->write_size);
107 #endif
108 write_buf += req->write_size;
109 mmc.multi.num_of_cmds++;
110 cmd++;
111 }
112
113 if (req->read_size) {
114 cmd->write_flag = MMC_WRITE_FLAG_R;
115 cmd->opcode = MMC_READ_MULTIPLE_BLOCK;
116 cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC, cmd->blksz = MMC_BLOCK_SIZE;
117 cmd->blocks = req->read_size / MMC_BLOCK_SIZE;
118 mmc_ioc_cmd_set_data((*cmd), read_buf);
119 #ifdef RPMB_DEBUG
120 ALOGI("opcode: 0x%x, write_flag: 0x%x\n", cmd->opcode, cmd->write_flag);
121 #endif
122 mmc.multi.num_of_cmds++;
123 cmd++;
124 }
125
126 rc = ioctl(mmc_fd, MMC_IOC_MULTI_CMD, &mmc.multi);
127 if (rc < 0) {
128 ALOGE("%s: mmc ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
129 }
130 return rc;
131 }
132
send_virt_rpmb_req(int rpmb_fd,void * read_buf,size_t read_size,const void * payload,size_t payload_size)133 static int send_virt_rpmb_req(int rpmb_fd, void* read_buf, size_t read_size, const void* payload,
134 size_t payload_size) {
135 int rc;
136 uint16_t res_count = read_size / MMC_BLOCK_SIZE;
137 uint16_t cmd_count = payload_size / MMC_BLOCK_SIZE;
138 rc = write(rpmb_fd, &res_count, sizeof(res_count));
139 if (rc < 0) {
140 return rc;
141 }
142 rc = write(rpmb_fd, &cmd_count, sizeof(cmd_count));
143 if (rc < 0) {
144 return rc;
145 }
146 rc = write(rpmb_fd, payload, payload_size);
147 if (rc < 0) {
148 return rc;
149 }
150 rc = read(rpmb_fd, read_buf, read_size);
151 return rc;
152 }
153
rpmb_send(struct storage_msg * msg,const void * r,size_t req_len)154 int rpmb_send(struct storage_msg* msg, const void* r, size_t req_len) {
155 int rc;
156 const struct storage_rpmb_send_req* req = r;
157
158 if (req_len < sizeof(*req)) {
159 ALOGW("malformed rpmb request: invalid length (%zu < %zu)\n", req_len, sizeof(*req));
160 msg->result = STORAGE_ERR_NOT_VALID;
161 goto err_response;
162 }
163
164 size_t expected_len = sizeof(*req) + req->reliable_write_size + req->write_size;
165 if (req_len != expected_len) {
166 ALOGW("malformed rpmb request: invalid length (%zu != %zu)\n", req_len, expected_len);
167 msg->result = STORAGE_ERR_NOT_VALID;
168 goto err_response;
169 }
170
171 if ((req->reliable_write_size % MMC_BLOCK_SIZE) != 0) {
172 ALOGW("invalid reliable write size %u\n", req->reliable_write_size);
173 msg->result = STORAGE_ERR_NOT_VALID;
174 goto err_response;
175 }
176
177 if ((req->write_size % MMC_BLOCK_SIZE) != 0) {
178 ALOGW("invalid write size %u\n", req->write_size);
179 msg->result = STORAGE_ERR_NOT_VALID;
180 goto err_response;
181 }
182
183 if (req->read_size % MMC_BLOCK_SIZE != 0 || req->read_size > sizeof(read_buf)) {
184 ALOGE("%s: invalid read size %u\n", __func__, req->read_size);
185 msg->result = STORAGE_ERR_NOT_VALID;
186 goto err_response;
187 }
188
189 if (dev_type == MMC_RPMB) {
190 rc = send_mmc_rpmb_req(rpmb_fd, req);
191 if (rc < 0) {
192 msg->result = STORAGE_ERR_GENERIC;
193 goto err_response;
194 }
195 } else if (dev_type == VIRT_RPMB) {
196 size_t payload_size = req->reliable_write_size + req->write_size;
197 rc = send_virt_rpmb_req(rpmb_fd, read_buf, req->read_size, req->payload, payload_size);
198 if (rc < 0) {
199 ALOGE("send_virt_rpmb_req failed: %d, %s\n", rc, strerror(errno));
200 msg->result = STORAGE_ERR_GENERIC;
201 goto err_response;
202 }
203 if (rc != req->read_size) {
204 ALOGE("send_virt_rpmb_req got incomplete response: "
205 "(size %d, expected %d)\n",
206 rc, req->read_size);
207 msg->result = STORAGE_ERR_GENERIC;
208 goto err_response;
209 }
210 } else {
211 ALOGE("Unsupported dev_type\n");
212 msg->result = STORAGE_ERR_GENERIC;
213 goto err_response;
214 }
215 #ifdef RPMB_DEBUG
216 if (req->read_size) print_buf("response: ", read_buf, req->read_size);
217 #endif
218
219 if (msg->flags & STORAGE_MSG_FLAG_POST_COMMIT) {
220 /*
221 * Nothing todo for post msg commit request as MMC_IOC_MULTI_CMD
222 * is fully synchronous in this implementation.
223 */
224 }
225
226 msg->result = STORAGE_NO_ERROR;
227 return ipc_respond(msg, read_buf, req->read_size);
228
229 err_response:
230 return ipc_respond(msg, NULL, 0);
231 }
232
rpmb_open(const char * rpmb_devname,enum dev_type open_dev_type)233 int rpmb_open(const char* rpmb_devname, enum dev_type open_dev_type) {
234 int rc;
235 dev_type = open_dev_type;
236
237 rc = open(rpmb_devname, O_RDWR, 0);
238 if (rc < 0) {
239 ALOGE("unable (%d) to open rpmb device '%s': %s\n", errno, rpmb_devname, strerror(errno));
240 return rc;
241 }
242 rpmb_fd = rc;
243 return 0;
244 }
245
rpmb_close(void)246 void rpmb_close(void) {
247 close(rpmb_fd);
248 rpmb_fd = -1;
249 }
250