1 /* 2 * Copyright (c) 2013, The Linux Foundation. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above 10 * copyright notice, this list of conditions and the following 11 * disclaimer in the documentation and/or other materials provided 12 * with the distribution. 13 * * Neither the name of The Linux Foundation nor the names of its 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <stdio.h> 31 #include <fcntl.h> 32 #include <errno.h> 33 #include <string.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <sys/mman.h> 37 #include <linux/qseecom.h> 38 #include <linux/msm_ion.h> 39 40 /* Service IDs */ 41 #define SCM_SVC_SSD 0x07 42 43 /* Service specific command IDs */ 44 #define SSD_PARSE_MD_ID 0x06 45 #define SSD_DECRYPT_IMG_FRAG_ID 0x07 46 47 /* SSD parsing status messages from TZ */ 48 #define SSD_PMD_ENCRYPTED 0 49 #define SSD_PMD_NOT_ENCRYPTED 1 50 #define SSD_PMD_PARSING_INCOMPLETE 6 51 52 #define SSD_HEADER_MIN_SIZE 128 53 #define MULTIPLICATION_FACTOR 2 54 55 #define SMCMOD_DECRYPT_REQ_OP_METADATA 1 56 #define SMCMOD_DECRYPT_REQ_OP_IMG_FRAG 2 57 58 struct smcmod_decrypt_req { 59 uint32_t service_id; /* in */ 60 uint32_t command_id; /* in */ 61 uint32_t operation; /* in */ 62 63 union { 64 struct { 65 uint32_t len; 66 uint32_t ion_fd; 67 } metadata; 68 struct { 69 uint32_t ctx_id; 70 uint32_t last_frag; 71 uint32_t frag_len; 72 uint32_t ion_fd; 73 uint32_t offset; 74 } img_frag; 75 } request; 76 77 union { 78 struct { 79 uint32_t status; 80 uint32_t ctx_id; 81 uint32_t end_offset; 82 } metadata; 83 struct { 84 uint32_t status; 85 } img_frag; 86 } response; 87 }; 88 89 #define SMCMOD_IOC_MAGIC 0x97 90 #define SMCMOD_IOCTL_DECRYPT_CMD \ 91 _IOWR(SMCMOD_IOC_MAGIC, 37, struct smcmod_decrypt_req) 92 93 struct ion_buf_handle { 94 unsigned char *buffer; 95 uint32_t buffer_len; 96 int ion_fd; 97 int ifd_data_fd; 98 struct ion_handle_data ion_alloc_handle; 99 }; 100 101 static int 102 ion_memalloc(struct ion_buf_handle *buf, uint32_t size, uint32_t heap) 103 { 104 struct ion_allocation_data alloc_data; 105 struct ion_fd_data fd_data; 106 unsigned char *va; 107 struct ion_handle_data handle_data; 108 int ion_fd; 109 int rc; 110 111 ion_fd = open("/dev/ion", O_RDONLY); 112 if (ion_fd < 0) { 113 fprintf(stderr, "Cannot open ION device (%s)\n", strerror(errno)); 114 return -1; 115 } 116 117 alloc_data.len = (size + 4095) & ~4095; 118 alloc_data.align = 4096; 119 120 alloc_data.flags = 0; 121 alloc_data.heap_id_mask = ION_HEAP(heap); 122 123 /* Set the buffers to be uncached */ 124 alloc_data.flags = 0; 125 126 rc = ioctl(ion_fd, ION_IOC_ALLOC, &alloc_data); 127 if (rc) { 128 fprintf(stderr, "ION buffer allocation failed (%s)\n", 129 strerror(errno)); 130 goto alloc_fail; 131 } 132 133 if (alloc_data.handle) { 134 fd_data.handle = alloc_data.handle; 135 } else { 136 fprintf(stderr, "ION alloc data returned NULL\n"); 137 rc = -1; 138 goto alloc_fail; 139 } 140 141 rc = ioctl(ion_fd, ION_IOC_MAP, &fd_data); 142 if (rc) { 143 fprintf(stderr, "ION map call failed(%s)\n", strerror(errno)); 144 goto ioctl_fail; 145 } 146 147 va = (unsigned char*)mmap(NULL, alloc_data.len, PROT_READ | PROT_WRITE, 148 MAP_SHARED, fd_data.fd, 0); 149 if (va == MAP_FAILED) { 150 fprintf(stderr, "ION memory map failed (%s)\n", strerror(errno)); 151 rc = -1; 152 goto map_fail; 153 } 154 155 buf->ion_fd = ion_fd; 156 buf->ifd_data_fd = fd_data.fd; 157 buf->buffer = va; 158 buf->ion_alloc_handle.handle = alloc_data.handle; 159 buf->buffer_len = alloc_data.len; 160 161 memset(buf->buffer, 0, buf->buffer_len); 162 return 0; 163 164 map_fail: 165 ioctl_fail: 166 handle_data.handle = alloc_data.handle; 167 if (buf->ifd_data_fd) 168 close(buf->ifd_data_fd); 169 rc = ioctl(ion_fd, ION_IOC_FREE, &handle_data); 170 if (rc) 171 fprintf(stderr, "ION free failed (%s)\n", strerror(errno)); 172 alloc_fail: 173 if (ion_fd >= 0) 174 close(ion_fd); 175 buf->ion_fd = -1; 176 return rc; 177 } 178 179 static int ion_memfree(struct ion_buf_handle *handle) 180 { 181 struct ion_handle_data handle_data; 182 int ret; 183 184 ret = munmap(handle->buffer, (handle->buffer_len + 4095) & ~4095); 185 if (ret) 186 fprintf(stderr, "munmap failed (%s)\n", strerror(errno)); 187 188 handle_data.handle = handle->ion_alloc_handle.handle; 189 close(handle->ifd_data_fd); 190 ret = ioctl(handle->ion_fd, ION_IOC_FREE, &handle_data); 191 if (ret) 192 fprintf(stderr, "ION free failed (%s)\n", strerror(errno)); 193 close(handle->ion_fd); 194 195 return ret; 196 } 197 198 static int ion_buffer_clean_inval(struct ion_buf_handle *buf, uint32_t cmd) 199 { 200 struct ion_flush_data data; 201 int rc; 202 203 data.fd = buf->ifd_data_fd; 204 data.vaddr = buf->buffer; 205 data.length = buf->buffer_len; 206 data.offset = 0; 207 data.handle = buf->ion_alloc_handle.handle; 208 209 rc = ioctl(buf->ion_fd, cmd, &data); 210 if (rc < 0) 211 fprintf(stderr, "clean_inval cache failed (%s)\n", strerror(errno)); 212 213 return rc; 214 } 215 216 static int is_encrypted(int smcmod_fd, struct ion_buf_handle *buf, 217 uint32_t len, uint32_t *ctx_id, uint32_t *end_offset) 218 { 219 struct smcmod_decrypt_req req; 220 uint32_t status; 221 int ret; 222 223 req.service_id = SCM_SVC_SSD; 224 req.command_id = SSD_PARSE_MD_ID; 225 req.operation = SMCMOD_DECRYPT_REQ_OP_METADATA; 226 req.request.metadata.len = 227 (len >= SSD_HEADER_MIN_SIZE) ? SSD_HEADER_MIN_SIZE : len; 228 req.request.metadata.ion_fd = buf->ifd_data_fd; 229 230 do { 231 ret = ioctl(smcmod_fd, SMCMOD_IOCTL_DECRYPT_CMD, &req); 232 if (ret < 0) 233 fprintf(stderr, "%s: ioctl ret=%d, %s\n", __func__, ret, 234 strerror(errno)); 235 236 status = req.response.metadata.status; 237 238 if (!ret && (status == SSD_PMD_PARSING_INCOMPLETE)) { 239 req.request.metadata.len *= MULTIPLICATION_FACTOR; 240 continue; 241 } else { 242 break; 243 } 244 } while (1); 245 246 if (!ret) { 247 if (status == SSD_PMD_ENCRYPTED) { 248 *ctx_id = req.response.metadata.ctx_id; 249 *end_offset = req.response.metadata.end_offset; 250 ret = 1; 251 } else { 252 fprintf(stderr, "Image is not encrypted (response status %d)\n", 253 status); 254 } 255 } else { 256 fprintf(stderr, "%s: call failed\n", __func__); 257 } 258 259 return ret; 260 } 261 262 static int decrypt(int smcmod_fd, struct ion_buf_handle *buf, uint32_t len, 263 uint32_t md_ctx, uint32_t offset) 264 { 265 struct smcmod_decrypt_req req; 266 int ret; 267 268 req.service_id = SCM_SVC_SSD; 269 req.command_id = SSD_DECRYPT_IMG_FRAG_ID; 270 req.operation = SMCMOD_DECRYPT_REQ_OP_IMG_FRAG; 271 req.request.img_frag.ctx_id = md_ctx; 272 req.request.img_frag.last_frag = 1; 273 req.request.img_frag.ion_fd = buf->ifd_data_fd; 274 req.request.img_frag.frag_len = len - offset; 275 req.request.img_frag.offset = offset; 276 277 ret = ioctl(smcmod_fd, SMCMOD_IOCTL_DECRYPT_CMD, &req); 278 if (ret < 0) { 279 fprintf(stderr, "decrypt ioctl failed (%s)\n", strerror(errno)); 280 return ret; 281 } 282 283 return 0; 284 } 285 286 static int save_file(const char *fname, unsigned char *buf, size_t len) 287 { 288 FILE *file; 289 size_t written; 290 291 file = fopen(fname, "wb"); 292 if (!file) { 293 fprintf(stderr, "Failed to open %s (%s)\n", fname, strerror(errno)); 294 return -errno; 295 } 296 297 written = fwrite(buf, len, 1, file); 298 if (written != 1) { 299 fclose(file); 300 fprintf(stderr, "Failed to write %s (%s)\n", fname, strerror(errno)); 301 return -errno; 302 } 303 fflush(file); 304 fclose(file); 305 fprintf(stdout, "%s written %d bytes\n", fname, len); 306 return 0; 307 } 308 309 int decrypt_image(const char *src_file, const char *dst_file) 310 { 311 int ret = -1; 312 uint32_t md_ctx = 0, offset = 0; 313 uint32_t fsize = 0; 314 FILE *file = NULL; 315 struct ion_buf_handle ionbuf; 316 int smcmod_fd = -1; 317 int qseecom_fd = -1; 318 size_t read; 319 320 memset(&ionbuf, 0, sizeof(ionbuf)); 321 ionbuf.ion_fd = -1; 322 323 qseecom_fd = open("/dev/qseecom", O_RDWR); 324 if (qseecom_fd < 0) { 325 fprintf(stderr, "Failed to open /dev/qseecom device (%s)\n", 326 strerror(errno)); 327 goto exit; 328 } 329 330 smcmod_fd = open("/dev/smcmod", O_RDWR); 331 if (smcmod_fd < 0) { 332 fprintf(stderr, "Failed to open /dev/smcmod device (%s)\n", 333 strerror(errno)); 334 goto exit; 335 } 336 337 file = fopen(src_file, "rb"); 338 if (!file) { 339 fprintf(stderr, "Failed to open %s (%s)\n", src_file, strerror(errno)); 340 goto exit; 341 } 342 343 fseek(file, 0, SEEK_END); 344 fsize = ftell(file); 345 fseek(file, 0, SEEK_SET); 346 347 ret = ion_memalloc(&ionbuf, fsize, ION_PIL1_HEAP_ID); 348 if (ret) 349 goto exit; 350 351 read = fread(ionbuf.buffer, fsize, 1, file); 352 if (read != 1) { 353 fprintf(stderr, "Failed to read %s (%s)\n", src_file, strerror(errno)); 354 ret = -errno; 355 goto exit; 356 } 357 358 ret = ion_buffer_clean_inval(&ionbuf, ION_IOC_CLEAN_INV_CACHES); 359 if (ret < 0) 360 goto exit; 361 362 ret = ioctl(qseecom_fd, QSEECOM_IOCTL_PERF_ENABLE_REQ); 363 if (ret < 0) 364 goto exit; 365 366 ret = is_encrypted(smcmod_fd, &ionbuf, fsize, &md_ctx, &offset); 367 if (ret < 0) 368 goto exit; 369 370 if (ret == 1) { 371 fprintf(stdout, "decrypting %s ...\n", src_file); 372 ret = decrypt(smcmod_fd, &ionbuf, fsize, md_ctx, offset); 373 if (ret < 0) 374 goto exit; 375 376 ion_buffer_clean_inval(&ionbuf, ION_IOC_INV_CACHES); 377 378 ret = save_file(dst_file, ionbuf.buffer + offset, fsize - offset); 379 if (ret < 0) 380 goto exit; 381 382 fprintf(stdout, "decrypting done!\n"); 383 } 384 385 exit: 386 if (ionbuf.ion_fd >= 0) 387 ion_memfree(&ionbuf); 388 389 if (qseecom_fd >= 0) { 390 ioctl(qseecom_fd, QSEECOM_IOCTL_PERF_DISABLE_REQ); 391 close(qseecom_fd); 392 } 393 394 if (smcmod_fd >= 0) 395 close(smcmod_fd); 396 397 if (file) 398 fclose(file); 399 400 return ret; 401 } 402