linux.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. #include <grub/types.h>
  2. #include <grub/err.h>
  3. #include <grub/linux.h>
  4. #include <grub/misc.h>
  5. #include <grub/file.h>
  6. #include <grub/mm.h>
  7. #include <grub/safemath.h>
  8. struct newc_head
  9. {
  10. char magic[6];
  11. char ino[8];
  12. char mode[8];
  13. char uid[8];
  14. char gid[8];
  15. char nlink[8];
  16. char mtime[8];
  17. char filesize[8];
  18. char devmajor[8];
  19. char devminor[8];
  20. char rdevmajor[8];
  21. char rdevminor[8];
  22. char namesize[8];
  23. char check[8];
  24. } GRUB_PACKED;
  25. struct grub_linux_initrd_component
  26. {
  27. grub_file_t file;
  28. char *newc_name;
  29. grub_off_t size;
  30. };
  31. struct dir
  32. {
  33. char *name;
  34. struct dir *next;
  35. struct dir *child;
  36. };
  37. static char
  38. hex (grub_uint8_t val)
  39. {
  40. if (val < 10)
  41. return '0' + val;
  42. return 'a' + val - 10;
  43. }
  44. static void
  45. set_field (char *var, grub_uint32_t val)
  46. {
  47. int i;
  48. char *ptr = var;
  49. for (i = 28; i >= 0; i -= 4)
  50. *ptr++ = hex((val >> i) & 0xf);
  51. }
  52. static grub_uint8_t *
  53. make_header (grub_uint8_t *ptr,
  54. const char *name, grub_size_t len,
  55. grub_uint32_t mode,
  56. grub_off_t fsize)
  57. {
  58. struct newc_head *head = (struct newc_head *) ptr;
  59. grub_uint8_t *optr;
  60. grub_size_t oh = 0;
  61. grub_dprintf ("linux", "newc: Creating path '%s', mode=%s%o, size=%" PRIuGRUB_OFFSET "\n", name, (mode == 0) ? "" : "0", mode, fsize);
  62. grub_memcpy (head->magic, "070701", 6);
  63. set_field (head->ino, 0);
  64. set_field (head->mode, mode);
  65. set_field (head->uid, 0);
  66. set_field (head->gid, 0);
  67. set_field (head->nlink, 1);
  68. set_field (head->mtime, 0);
  69. set_field (head->filesize, fsize);
  70. set_field (head->devmajor, 0);
  71. set_field (head->devminor, 0);
  72. set_field (head->rdevmajor, 0);
  73. set_field (head->rdevminor, 0);
  74. set_field (head->namesize, len);
  75. set_field (head->check, 0);
  76. optr = ptr;
  77. ptr += sizeof (struct newc_head);
  78. grub_memcpy (ptr, name, len);
  79. ptr += len;
  80. oh = ALIGN_UP_OVERHEAD (ptr - optr, 4);
  81. grub_memset (ptr, 0, oh);
  82. ptr += oh;
  83. return ptr;
  84. }
  85. static void
  86. free_dir (struct dir *root)
  87. {
  88. if (!root)
  89. return;
  90. free_dir (root->next);
  91. free_dir (root->child);
  92. grub_free (root->name);
  93. grub_free (root);
  94. }
  95. static grub_err_t
  96. insert_dir (const char *name, struct dir **root,
  97. grub_uint8_t *ptr, grub_size_t *size)
  98. {
  99. struct dir *cur, **head = root;
  100. const char *cb, *ce = name;
  101. *size = 0;
  102. while (1)
  103. {
  104. for (cb = ce; *cb == '/'; cb++);
  105. for (ce = cb; *ce && *ce != '/'; ce++);
  106. if (!*ce)
  107. break;
  108. for (cur = *root; cur; cur = cur->next)
  109. if (grub_memcmp (cur->name, cb, ce - cb) == 0
  110. && cur->name[ce - cb] == 0)
  111. break;
  112. if (!cur)
  113. {
  114. struct dir *n;
  115. n = grub_zalloc (sizeof (*n));
  116. if (!n)
  117. return 0;
  118. n->next = *head;
  119. n->name = grub_strndup (cb, ce - cb);
  120. if (ptr)
  121. {
  122. /*
  123. * Create the substring with the trailing NUL byte
  124. * to be included in the cpio header.
  125. */
  126. char *tmp_name = grub_strndup (name, ce - name);
  127. if (!tmp_name) {
  128. grub_free (n->name);
  129. grub_free (n);
  130. return grub_errno;
  131. }
  132. ptr = make_header (ptr, tmp_name, ce - name + 1,
  133. 040777, 0);
  134. grub_free (tmp_name);
  135. }
  136. if (grub_add (*size,
  137. ALIGN_UP ((ce - (char *) name + 1)
  138. + sizeof (struct newc_head), 4),
  139. size))
  140. {
  141. grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
  142. grub_free (n->name);
  143. grub_free (n);
  144. return grub_errno;
  145. }
  146. *head = n;
  147. cur = n;
  148. }
  149. root = &cur->next;
  150. }
  151. return GRUB_ERR_NONE;
  152. }
  153. grub_err_t
  154. grub_initrd_init (int argc, char *argv[],
  155. struct grub_linux_initrd_context *initrd_ctx)
  156. {
  157. int i;
  158. int newc = 0;
  159. struct dir *root = 0;
  160. initrd_ctx->nfiles = 0;
  161. initrd_ctx->components = 0;
  162. initrd_ctx->components = grub_calloc (argc, sizeof (initrd_ctx->components[0]));
  163. if (!initrd_ctx->components)
  164. return grub_errno;
  165. initrd_ctx->size = 0;
  166. for (i = 0; i < argc; i++)
  167. {
  168. const char *fname = argv[i];
  169. initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4);
  170. if (grub_memcmp (argv[i], "newc:", 5) == 0)
  171. {
  172. const char *ptr, *eptr;
  173. ptr = argv[i] + 5;
  174. while (*ptr == '/')
  175. ptr++;
  176. eptr = grub_strchr (ptr, ':');
  177. if (eptr)
  178. {
  179. grub_size_t dir_size, name_len;
  180. initrd_ctx->components[i].newc_name = grub_strndup (ptr, eptr - ptr);
  181. if (!initrd_ctx->components[i].newc_name ||
  182. insert_dir (initrd_ctx->components[i].newc_name, &root, 0,
  183. &dir_size))
  184. {
  185. grub_initrd_close (initrd_ctx);
  186. return grub_errno;
  187. }
  188. name_len = grub_strlen (initrd_ctx->components[i].newc_name) + 1;
  189. if (grub_add (initrd_ctx->size,
  190. ALIGN_UP (sizeof (struct newc_head) + name_len, 4),
  191. &initrd_ctx->size) ||
  192. grub_add (initrd_ctx->size, dir_size, &initrd_ctx->size))
  193. goto overflow;
  194. newc = 1;
  195. fname = eptr + 1;
  196. }
  197. }
  198. else if (newc)
  199. {
  200. if (grub_add (initrd_ctx->size,
  201. ALIGN_UP (sizeof (struct newc_head)
  202. + sizeof ("TRAILER!!!"), 4),
  203. &initrd_ctx->size))
  204. goto overflow;
  205. free_dir (root);
  206. root = 0;
  207. newc = 0;
  208. }
  209. initrd_ctx->components[i].file = grub_file_open (fname,
  210. GRUB_FILE_TYPE_LINUX_INITRD
  211. | GRUB_FILE_TYPE_NO_DECOMPRESS);
  212. if (!initrd_ctx->components[i].file)
  213. {
  214. grub_initrd_close (initrd_ctx);
  215. return grub_errno;
  216. }
  217. initrd_ctx->nfiles++;
  218. initrd_ctx->components[i].size
  219. = grub_file_size (initrd_ctx->components[i].file);
  220. if (grub_add (initrd_ctx->size, initrd_ctx->components[i].size,
  221. &initrd_ctx->size))
  222. goto overflow;
  223. }
  224. if (newc)
  225. {
  226. initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4);
  227. if (grub_add (initrd_ctx->size,
  228. ALIGN_UP (sizeof (struct newc_head)
  229. + sizeof ("TRAILER!!!"), 4),
  230. &initrd_ctx->size))
  231. goto overflow;
  232. free_dir (root);
  233. root = 0;
  234. }
  235. return GRUB_ERR_NONE;
  236. overflow:
  237. free_dir (root);
  238. grub_initrd_close (initrd_ctx);
  239. return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
  240. }
  241. grub_size_t
  242. grub_get_initrd_size (struct grub_linux_initrd_context *initrd_ctx)
  243. {
  244. return initrd_ctx->size;
  245. }
  246. void
  247. grub_initrd_close (struct grub_linux_initrd_context *initrd_ctx)
  248. {
  249. int i;
  250. if (!initrd_ctx->components)
  251. return;
  252. for (i = 0; i < initrd_ctx->nfiles; i++)
  253. {
  254. grub_free (initrd_ctx->components[i].newc_name);
  255. grub_file_close (initrd_ctx->components[i].file);
  256. }
  257. grub_free (initrd_ctx->components);
  258. initrd_ctx->components = 0;
  259. }
  260. grub_err_t
  261. grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx,
  262. void *target)
  263. {
  264. grub_uint8_t *ptr = target;
  265. int i;
  266. int newc = 0;
  267. struct dir *root = 0;
  268. grub_ssize_t cursize = 0;
  269. for (i = 0; i < initrd_ctx->nfiles; i++)
  270. {
  271. grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
  272. ptr += ALIGN_UP_OVERHEAD (cursize, 4);
  273. if (initrd_ctx->components[i].newc_name)
  274. {
  275. grub_size_t dir_size;
  276. if (insert_dir (initrd_ctx->components[i].newc_name, &root, ptr,
  277. &dir_size))
  278. {
  279. free_dir (root);
  280. grub_initrd_close (initrd_ctx);
  281. return grub_errno;
  282. }
  283. ptr += dir_size;
  284. ptr = make_header (ptr, initrd_ctx->components[i].newc_name,
  285. grub_strlen (initrd_ctx->components[i].newc_name) + 1,
  286. 0100777,
  287. initrd_ctx->components[i].size);
  288. newc = 1;
  289. }
  290. else if (newc)
  291. {
  292. ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!"),
  293. 0, 0);
  294. free_dir (root);
  295. root = 0;
  296. newc = 0;
  297. }
  298. cursize = initrd_ctx->components[i].size;
  299. if (grub_file_read (initrd_ctx->components[i].file, ptr, cursize)
  300. != cursize)
  301. {
  302. if (!grub_errno)
  303. grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
  304. initrd_ctx->components[i].file->name);
  305. grub_initrd_close (initrd_ctx);
  306. return grub_errno;
  307. }
  308. ptr += cursize;
  309. }
  310. if (newc)
  311. {
  312. grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
  313. ptr += ALIGN_UP_OVERHEAD (cursize, 4);
  314. ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!"), 0, 0);
  315. }
  316. free_dir (root);
  317. root = 0;
  318. return GRUB_ERR_NONE;
  319. }