cgpt_wrapper.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /* Copyright 2015 The Chromium OS Authors. All rights reserved.
  2. * Use of this source code is governed by a BSD-style license that can be
  3. * found in the LICENSE file.
  4. *
  5. * This utility wraps around "cgpt" execution to work with NAND. If the target
  6. * device is an MTD device, this utility will read the GPT structures from
  7. * FMAP, invokes "cgpt" on that, and writes the result back to NOR flash. */
  8. #include <err.h>
  9. #include <errno.h>
  10. #include <fcntl.h>
  11. #include <inttypes.h>
  12. #include <limits.h>
  13. #include <linux/major.h>
  14. #include <stdbool.h>
  15. #include <stdlib.h>
  16. #include <stdint.h>
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include <sys/stat.h>
  20. #include <sys/sysmacros.h>
  21. #include <sys/types.h>
  22. #include <unistd.h>
  23. #include "2sysincludes.h"
  24. #include "2common.h"
  25. #include "2sha.h"
  26. #include "cgpt.h"
  27. #include "cgpt_nor.h"
  28. #include "file_keys.h"
  29. // Check if cmdline |argv| has "-D". "-D" signifies that GPT structs are stored
  30. // off device, and hence we should not wrap around cgpt.
  31. static bool has_dash_D(int argc, const char *const argv[]) {
  32. int i;
  33. // We go from 2, because the second arg is a cgpt command such as "create".
  34. for (i = 2; i < argc; ++i) {
  35. if (strcmp("-D", argv[i]) == 0) {
  36. return true;
  37. }
  38. }
  39. return false;
  40. }
  41. // Check if |device_path| is an MTD device based on its major number being 90.
  42. static bool is_mtd(const char *device_path) {
  43. struct stat stat;
  44. if (lstat(device_path, &stat) != 0) {
  45. return false;
  46. }
  47. if (major(stat.st_rdev) != MTD_CHAR_MAJOR) {
  48. return false;
  49. }
  50. return true;
  51. }
  52. // Return the element in |argv| that is an MTD device.
  53. static const char *find_mtd_device(int argc, const char *const argv[]) {
  54. int i;
  55. for (i = 2; i < argc; ++i) {
  56. if (is_mtd(argv[i])) {
  57. return argv[i];
  58. }
  59. }
  60. return NULL;
  61. }
  62. static int wrap_cgpt(int argc,
  63. const char *const argv[],
  64. const char *mtd_device) {
  65. uint8_t original_hash[VB2_SHA1_DIGEST_SIZE];
  66. uint8_t modified_hash[VB2_SHA1_DIGEST_SIZE];
  67. int ret = 0;
  68. // Create a temp dir to work in.
  69. ret++;
  70. char temp_dir[] = "/tmp/cgpt_wrapper.XXXXXX";
  71. if (ReadNorFlash(temp_dir) != 0) {
  72. return ret;
  73. }
  74. char rw_gpt_path[PATH_MAX];
  75. if (snprintf(rw_gpt_path, sizeof(rw_gpt_path), "%s/rw_gpt", temp_dir) < 0) {
  76. goto cleanup;
  77. }
  78. if (VB2_SUCCESS != DigestFile(rw_gpt_path, VB2_HASH_SHA1,
  79. original_hash, sizeof(original_hash))) {
  80. Error("Cannot compute original GPT digest.\n");
  81. goto cleanup;
  82. }
  83. // Obtain the MTD size.
  84. ret++;
  85. uint64_t drive_size = 0;
  86. if (GetMtdSize(mtd_device, &drive_size) != 0) {
  87. Error("Cannot get the size of %s.\n", mtd_device);
  88. goto cleanup;
  89. }
  90. // Launch cgpt on "rw_gpt" with -D size.
  91. ret++;
  92. const char** my_argv = calloc(argc + 2 + 1, sizeof(char *));
  93. if (my_argv == NULL) {
  94. errno = ENOMEM;
  95. goto cleanup;
  96. }
  97. memcpy(my_argv, argv, sizeof(char *) * argc);
  98. char *real_cgpt;
  99. if (asprintf(&real_cgpt, "%s.bin", argv[0]) == -1) {
  100. free(my_argv);
  101. goto cleanup;
  102. }
  103. my_argv[0] = real_cgpt;
  104. int i;
  105. for (i = 2; i < argc; ++i) {
  106. if (strcmp(my_argv[i], mtd_device) == 0) {
  107. my_argv[i] = rw_gpt_path;
  108. }
  109. }
  110. my_argv[argc] = "-D";
  111. char size[32];
  112. snprintf(size, sizeof(size), "%" PRIu64, drive_size);
  113. my_argv[argc + 1] = size;
  114. i = ForkExecV(NULL, my_argv);
  115. free(real_cgpt);
  116. free(my_argv);
  117. if (i != 0) {
  118. Error("Cannot exec cgpt to modify rw_gpt.\n");
  119. goto cleanup;
  120. }
  121. // Write back "rw_gpt" to NOR flash in two chunks.
  122. ret++;
  123. if (VB2_SUCCESS == DigestFile(rw_gpt_path, VB2_HASH_SHA1,
  124. modified_hash, sizeof(modified_hash))) {
  125. if (memcmp(original_hash, modified_hash, VB2_SHA1_DIGEST_SIZE) != 0) {
  126. ret = WriteNorFlash(temp_dir);
  127. } else {
  128. ret = 0;
  129. }
  130. }
  131. cleanup:
  132. RemoveDir(temp_dir);
  133. return ret;
  134. }
  135. int main(int argc, const char *argv[]) {
  136. char resolved_cgpt[PATH_MAX];
  137. pid_t pid = getpid();
  138. char exe_link[40];
  139. int retval = 0;
  140. if (argc < 1) {
  141. return -1;
  142. }
  143. const char *orig_argv0 = argv[0];
  144. snprintf(exe_link, sizeof(exe_link), "/proc/%d/exe", pid);
  145. memset(resolved_cgpt, 0, sizeof(resolved_cgpt));
  146. if (readlink(exe_link, resolved_cgpt, sizeof(resolved_cgpt) - 1) == -1) {
  147. perror("readlink");
  148. return -1;
  149. }
  150. argv[0] = resolved_cgpt;
  151. if (argc > 2 && !has_dash_D(argc, argv)) {
  152. const char *mtd_device = find_mtd_device(argc, argv);
  153. if (mtd_device) {
  154. retval = wrap_cgpt(argc, argv, mtd_device);
  155. goto cleanup;
  156. }
  157. }
  158. // Forward to cgpt as-is. Real cgpt has been renamed cgpt.bin.
  159. char *real_cgpt;
  160. if (asprintf(&real_cgpt, "%s.bin", argv[0]) == -1) {
  161. retval = -1;
  162. goto cleanup;
  163. }
  164. argv[0] = real_cgpt;
  165. if (execv(argv[0], (char * const *)argv) == -1) {
  166. err(-2, "execv(%s) failed", real_cgpt);
  167. }
  168. free(real_cgpt);
  169. retval = -2;
  170. cleanup:
  171. argv[0] = orig_argv0;
  172. return retval;
  173. }