osafeloader.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /*
  2. * osafeloader
  3. *
  4. * Copyright (C) 2016 Rafał Miłecki <[email protected]>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. */
  10. #include <byteswap.h>
  11. #include <endian.h>
  12. #include <errno.h>
  13. #include <stdint.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <unistd.h>
  18. #include "md5.h"
  19. #if !defined(__BYTE_ORDER)
  20. #error "Unknown byte order"
  21. #endif
  22. #if __BYTE_ORDER == __BIG_ENDIAN
  23. #define cpu_to_be32(x) (x)
  24. #define be32_to_cpu(x) (x)
  25. #define cpu_to_be16(x) (x)
  26. #define be16_to_cpu(x) (x)
  27. #elif __BYTE_ORDER == __LITTLE_ENDIAN
  28. #define cpu_to_be32(x) bswap_32(x)
  29. #define be32_to_cpu(x) bswap_32(x)
  30. #define cpu_to_be16(x) bswap_16(x)
  31. #define be16_to_cpu(x) bswap_16(x)
  32. #else
  33. #error "Unsupported endianness"
  34. #endif
  35. struct safeloader_header {
  36. uint32_t imagesize;
  37. uint8_t md5[16];
  38. } __attribute__ ((packed));
  39. char *safeloader_path;
  40. char *partition_name;
  41. char *out_path;
  42. static inline size_t osafeloader_min(size_t x, size_t y) {
  43. return x < y ? x : y;
  44. }
  45. static const uint8_t md5_salt[16] = {
  46. 0x7a, 0x2b, 0x15, 0xed,
  47. 0x9b, 0x98, 0x59, 0x6d,
  48. 0xe5, 0x04, 0xab, 0x44,
  49. 0xac, 0x2a, 0x9f, 0x4e,
  50. };
  51. /**************************************************
  52. * Info
  53. **************************************************/
  54. static int osafeloader_info(int argc, char **argv) {
  55. FILE *safeloader;
  56. struct safeloader_header hdr;
  57. MD5_CTX ctx;
  58. size_t bytes, imagesize;
  59. uint8_t buf[1024];
  60. uint8_t md5[16];
  61. char name[32];
  62. int base, size, i;
  63. int err = 0;
  64. if (argc < 3) {
  65. fprintf(stderr, "No SafeLoader file passed\n");
  66. err = -EINVAL;
  67. goto out;
  68. }
  69. safeloader_path = argv[2];
  70. safeloader = fopen(safeloader_path, "r");
  71. if (!safeloader) {
  72. fprintf(stderr, "Couldn't open %s\n", safeloader_path);
  73. err = -EACCES;
  74. goto out;
  75. }
  76. bytes = fread(&hdr, 1, sizeof(hdr), safeloader);
  77. if (bytes != sizeof(hdr)) {
  78. fprintf(stderr, "Couldn't read %s header\n", safeloader_path);
  79. err = -EIO;
  80. goto err_close;
  81. }
  82. imagesize = be32_to_cpu(hdr.imagesize);
  83. MD5_Init(&ctx);
  84. MD5_Update(&ctx, md5_salt, sizeof(md5_salt));
  85. while ((bytes = fread(buf, 1, osafeloader_min(sizeof(buf), imagesize), safeloader)) > 0) {
  86. MD5_Update(&ctx, buf, bytes);
  87. imagesize -= bytes;
  88. }
  89. MD5_Final(md5, &ctx);
  90. if (memcmp(md5, hdr.md5, 16)) {
  91. fprintf(stderr, "Broken SafeLoader file with invalid MD5\n");
  92. err = -EIO;
  93. goto err_close;
  94. }
  95. printf("%10s: %d\n", "Image size", be32_to_cpu(hdr.imagesize));
  96. printf("%10s: ", "MD5");
  97. for (i = 0; i < 16; i++)
  98. printf("%02x", md5[i]);
  99. printf("\n");
  100. /* Skip header & vendor info */
  101. fseek(safeloader, 0x1014, SEEK_SET);
  102. while (fscanf(safeloader, "fwup-ptn %s base 0x%x size 0x%x\t\r\n", name, &base, &size) == 3) {
  103. printf("%10s: %s (0x%x - 0x%x)\n", "Partition", name, base, base + size);
  104. }
  105. err_close:
  106. fclose(safeloader);
  107. out:
  108. return err;
  109. }
  110. /**************************************************
  111. * Extract
  112. **************************************************/
  113. static void osafeloader_extract_parse_options(int argc, char **argv) {
  114. int c;
  115. while ((c = getopt(argc, argv, "p:o:")) != -1) {
  116. switch (c) {
  117. case 'p':
  118. partition_name = optarg;
  119. break;
  120. case 'o':
  121. out_path = optarg;
  122. break;
  123. }
  124. }
  125. }
  126. static int osafeloader_extract(int argc, char **argv) {
  127. FILE *safeloader;
  128. FILE *out;
  129. struct safeloader_header hdr;
  130. size_t bytes;
  131. char name[32];
  132. int base, size;
  133. int err = 0;
  134. if (argc < 3) {
  135. fprintf(stderr, "No SafeLoader file passed\n");
  136. err = -EINVAL;
  137. goto out;
  138. }
  139. safeloader_path = argv[2];
  140. optind = 3;
  141. osafeloader_extract_parse_options(argc, argv);
  142. if (!partition_name) {
  143. fprintf(stderr, "No partition name specified\n");
  144. err = -EINVAL;
  145. goto out;
  146. } else if (!out_path) {
  147. fprintf(stderr, "No output file specified\n");
  148. err = -EINVAL;
  149. goto out;
  150. }
  151. safeloader = fopen(safeloader_path, "r");
  152. if (!safeloader) {
  153. fprintf(stderr, "Couldn't open %s\n", safeloader_path);
  154. err = -EACCES;
  155. goto out;
  156. }
  157. out = fopen(out_path, "w");
  158. if (!out) {
  159. fprintf(stderr, "Couldn't open %s\n", out_path);
  160. err = -EACCES;
  161. goto err_close_safeloader;
  162. }
  163. bytes = fread(&hdr, 1, sizeof(hdr), safeloader);
  164. if (bytes != sizeof(hdr)) {
  165. fprintf(stderr, "Couldn't read %s header\n", safeloader_path);
  166. err = -EIO;
  167. goto err_close_out;
  168. }
  169. /* Skip vendor info */
  170. fseek(safeloader, 0x1000, SEEK_CUR);
  171. err = -ENOENT;
  172. while (fscanf(safeloader, "fwup-ptn %s base 0x%x size 0x%x\t\r\n", name, &base, &size) == 3) {
  173. uint8_t buf[1024];
  174. if (strcmp(name, partition_name))
  175. continue;
  176. err = 0;
  177. fseek(safeloader, sizeof(hdr) + 0x1000 + base, SEEK_SET);
  178. while ((bytes = fread(buf, 1, osafeloader_min(sizeof(buf), size), safeloader)) > 0) {
  179. if (fwrite(buf, 1, bytes, out) != bytes) {
  180. fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path);
  181. err = -EIO;
  182. break;
  183. }
  184. size -= bytes;
  185. }
  186. if (size) {
  187. fprintf(stderr, "Couldn't extract whole partition %s from %s (%d B left)\n", partition_name, safeloader_path, size);
  188. err = -EIO;
  189. }
  190. break;
  191. }
  192. err_close_out:
  193. fclose(out);
  194. err_close_safeloader:
  195. fclose(safeloader);
  196. out:
  197. return err;
  198. }
  199. /**************************************************
  200. * Start
  201. **************************************************/
  202. static void usage() {
  203. printf("Usage:\n");
  204. printf("\n");
  205. printf("Info about SafeLoader:\n");
  206. printf("\tosafeloader info <file>\n");
  207. printf("\n");
  208. printf("Extract from SafeLoader:\n");
  209. printf("\tosafeloader extract <file> [options]\n");
  210. printf("\t-p name\t\t\t\tname of partition to extract\n");
  211. printf("\t-o file\t\t\t\toutput file\n");
  212. }
  213. int main(int argc, char **argv) {
  214. if (argc > 1) {
  215. if (!strcmp(argv[1], "info"))
  216. return osafeloader_info(argc, argv);
  217. else if (!strcmp(argv[1], "extract"))
  218. return osafeloader_extract(argc, argv);
  219. }
  220. usage();
  221. return 0;
  222. }