romfs.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 2010 Free Software Foundation, Inc.
  4. *
  5. * GRUB is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * GRUB is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <grub/file.h>
  19. #include <grub/types.h>
  20. #include <grub/dl.h>
  21. #include <grub/mm.h>
  22. #include <grub/disk.h>
  23. #include <grub/fs.h>
  24. #include <grub/fshelp.h>
  25. #include <grub/lockdown.h>
  26. GRUB_MOD_LICENSE ("GPLv3+");
  27. struct grub_romfs_superblock
  28. {
  29. char magic[8];
  30. #define GRUB_ROMFS_MAGIC "-rom1fs-"
  31. grub_uint32_t total_size;
  32. grub_uint32_t chksum;
  33. char label[0];
  34. };
  35. struct grub_romfs_file_header
  36. {
  37. grub_uint32_t next_file;
  38. grub_uint32_t spec;
  39. grub_uint32_t size;
  40. grub_uint32_t chksum;
  41. char name[0];
  42. };
  43. struct grub_romfs_data
  44. {
  45. grub_disk_addr_t first_file;
  46. grub_disk_t disk;
  47. };
  48. struct grub_fshelp_node
  49. {
  50. grub_disk_addr_t addr;
  51. struct grub_romfs_data *data;
  52. grub_disk_addr_t data_addr;
  53. /* Not filled for root. */
  54. struct grub_romfs_file_header file;
  55. };
  56. #define GRUB_ROMFS_ALIGN 16
  57. #define GRUB_ROMFS_TYPE_MASK 7
  58. #define GRUB_ROMFS_TYPE_HARDLINK 0
  59. #define GRUB_ROMFS_TYPE_DIRECTORY 1
  60. #define GRUB_ROMFS_TYPE_REGULAR 2
  61. #define GRUB_ROMFS_TYPE_SYMLINK 3
  62. static grub_err_t
  63. do_checksum (void *in, grub_size_t insize)
  64. {
  65. grub_uint32_t *a = in;
  66. grub_size_t sz = insize / 4;
  67. grub_uint32_t *b = a + sz;
  68. grub_uint32_t csum = 0;
  69. while (a < b)
  70. csum += grub_be_to_cpu32 (*a++);
  71. if (csum)
  72. return grub_error (GRUB_ERR_BAD_FS, "invalid checksum");
  73. return GRUB_ERR_NONE;
  74. }
  75. static struct grub_romfs_data *
  76. grub_romfs_mount (grub_device_t dev)
  77. {
  78. union {
  79. struct grub_romfs_superblock sb;
  80. char d[512];
  81. } sb;
  82. grub_err_t err;
  83. char *ptr;
  84. grub_disk_addr_t sec = 0;
  85. struct grub_romfs_data *data;
  86. if (!dev->disk)
  87. {
  88. grub_error (GRUB_ERR_BAD_FS, "not a disk");
  89. return NULL;
  90. }
  91. err = grub_disk_read (dev->disk, 0, 0, sizeof (sb), &sb);
  92. if (err == GRUB_ERR_OUT_OF_RANGE)
  93. err = grub_errno = GRUB_ERR_BAD_FS;
  94. if (err)
  95. return NULL;
  96. if (grub_be_to_cpu32 (sb.sb.total_size) < sizeof (sb))
  97. {
  98. grub_error (GRUB_ERR_BAD_FS, "too short filesystem");
  99. return NULL;
  100. }
  101. if (grub_memcmp (sb.sb.magic, GRUB_ROMFS_MAGIC,
  102. sizeof (sb.sb.magic)) != 0)
  103. {
  104. grub_error (GRUB_ERR_BAD_FS, "not romfs");
  105. return NULL;
  106. }
  107. err = do_checksum (&sb, sizeof (sb) < grub_be_to_cpu32 (sb.sb.total_size) ?
  108. sizeof (sb) : grub_be_to_cpu32 (sb.sb.total_size));
  109. if (err)
  110. {
  111. grub_error (GRUB_ERR_BAD_FS, "checksum incorrect");
  112. return NULL;
  113. }
  114. for (ptr = sb.sb.label; (void *) ptr < (void *) (&sb + 1)
  115. && ptr - sb.d < (grub_ssize_t) grub_be_to_cpu32 (sb.sb.total_size); ptr++)
  116. if (!*ptr)
  117. break;
  118. while ((void *) ptr == &sb + 1)
  119. {
  120. sec++;
  121. err = grub_disk_read (dev->disk, sec, 0, sizeof (sb), &sb);
  122. if (err == GRUB_ERR_OUT_OF_RANGE)
  123. err = grub_errno = GRUB_ERR_BAD_FS;
  124. if (err)
  125. return NULL;
  126. for (ptr = sb.d; (void *) ptr < (void *) (&sb + 1)
  127. && (ptr - sb.d + (sec << GRUB_DISK_SECTOR_BITS)
  128. < grub_be_to_cpu32 (sb.sb.total_size));
  129. ptr++)
  130. if (!*ptr)
  131. break;
  132. }
  133. data = grub_malloc (sizeof (*data));
  134. if (!data)
  135. return NULL;
  136. data->first_file = ALIGN_UP (ptr + 1 - sb.d, GRUB_ROMFS_ALIGN)
  137. + (sec << GRUB_DISK_SECTOR_BITS);
  138. data->disk = dev->disk;
  139. return data;
  140. }
  141. static char *
  142. grub_romfs_read_symlink (grub_fshelp_node_t node)
  143. {
  144. char *ret;
  145. grub_err_t err;
  146. ret = grub_malloc (grub_be_to_cpu32 (node->file.size) + 1);
  147. if (!ret)
  148. return NULL;
  149. err = grub_disk_read (node->data->disk,
  150. (node->data_addr) >> GRUB_DISK_SECTOR_BITS,
  151. (node->data_addr) & (GRUB_DISK_SECTOR_SIZE - 1),
  152. grub_be_to_cpu32 (node->file.size), ret);
  153. if (err)
  154. {
  155. grub_free (ret);
  156. return NULL;
  157. }
  158. ret[grub_be_to_cpu32 (node->file.size)] = 0;
  159. return ret;
  160. }
  161. static int
  162. grub_romfs_iterate_dir (grub_fshelp_node_t dir,
  163. grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
  164. {
  165. grub_disk_addr_t caddr;
  166. struct grub_romfs_file_header hdr;
  167. unsigned nptr;
  168. unsigned i, j;
  169. grub_size_t a = 0;
  170. grub_properly_aligned_t *name = NULL;
  171. for (caddr = dir->data_addr; caddr;
  172. caddr = grub_be_to_cpu32 (hdr.next_file) & ~(GRUB_ROMFS_ALIGN - 1))
  173. {
  174. grub_disk_addr_t naddr = caddr + sizeof (hdr);
  175. grub_uint32_t csum = 0;
  176. enum grub_fshelp_filetype filetype = GRUB_FSHELP_UNKNOWN;
  177. struct grub_fshelp_node *node = NULL;
  178. grub_err_t err;
  179. err = grub_disk_read (dir->data->disk, caddr >> GRUB_DISK_SECTOR_BITS,
  180. caddr & (GRUB_DISK_SECTOR_SIZE - 1),
  181. sizeof (hdr), &hdr);
  182. if (err)
  183. {
  184. grub_free (name);
  185. return 1;
  186. }
  187. for (nptr = 0; ; nptr++, naddr += 16)
  188. {
  189. if (a <= nptr)
  190. {
  191. grub_properly_aligned_t *on;
  192. a = 2 * (nptr + 1);
  193. on = name;
  194. name = grub_realloc (name, a * 16);
  195. if (!name)
  196. {
  197. grub_free (on);
  198. return 1;
  199. }
  200. }
  201. COMPILE_TIME_ASSERT (16 % sizeof (name[0]) == 0);
  202. err = grub_disk_read (dir->data->disk, naddr >> GRUB_DISK_SECTOR_BITS,
  203. naddr & (GRUB_DISK_SECTOR_SIZE - 1),
  204. 16, name + (16 / sizeof (name[0])) * nptr);
  205. if (err)
  206. return 1;
  207. for (j = 0; j < 16; j++)
  208. if (!((char *) name)[16 * nptr + j])
  209. break;
  210. if (j != 16)
  211. break;
  212. }
  213. for (i = 0; i < sizeof (hdr) / sizeof (grub_uint32_t); i++)
  214. csum += grub_be_to_cpu32 (((grub_uint32_t *) &hdr)[i]);
  215. for (i = 0; i < (nptr + 1) * 4; i++)
  216. csum += grub_be_to_cpu32 (((grub_uint32_t *) name)[i]);
  217. if (csum != 0)
  218. {
  219. grub_error (GRUB_ERR_BAD_FS, "invalid checksum");
  220. grub_free (name);
  221. return 1;
  222. }
  223. node = grub_malloc (sizeof (*node));
  224. if (!node)
  225. return 1;
  226. node->addr = caddr;
  227. node->data_addr = caddr + (nptr + 1) * 16 + sizeof (hdr);
  228. node->data = dir->data;
  229. node->file = hdr;
  230. switch (grub_be_to_cpu32 (hdr.next_file) & GRUB_ROMFS_TYPE_MASK)
  231. {
  232. case GRUB_ROMFS_TYPE_REGULAR:
  233. filetype = GRUB_FSHELP_REG;
  234. break;
  235. case GRUB_ROMFS_TYPE_SYMLINK:
  236. filetype = GRUB_FSHELP_SYMLINK;
  237. break;
  238. case GRUB_ROMFS_TYPE_DIRECTORY:
  239. node->data_addr = grub_be_to_cpu32 (hdr.spec);
  240. filetype = GRUB_FSHELP_DIR;
  241. break;
  242. case GRUB_ROMFS_TYPE_HARDLINK:
  243. {
  244. grub_disk_addr_t laddr;
  245. node->addr = laddr = grub_be_to_cpu32 (hdr.spec);
  246. err = grub_disk_read (dir->data->disk,
  247. laddr >> GRUB_DISK_SECTOR_BITS,
  248. laddr & (GRUB_DISK_SECTOR_SIZE - 1),
  249. sizeof (node->file), &node->file);
  250. if (err)
  251. return 1;
  252. if ((grub_be_to_cpu32 (node->file.next_file) & GRUB_ROMFS_TYPE_MASK)
  253. == GRUB_ROMFS_TYPE_REGULAR
  254. || (grub_be_to_cpu32 (node->file.next_file)
  255. & GRUB_ROMFS_TYPE_MASK) == GRUB_ROMFS_TYPE_SYMLINK)
  256. {
  257. laddr += sizeof (hdr);
  258. while (1)
  259. {
  260. char buf[16];
  261. err = grub_disk_read (dir->data->disk,
  262. laddr >> GRUB_DISK_SECTOR_BITS,
  263. laddr & (GRUB_DISK_SECTOR_SIZE - 1),
  264. 16, buf);
  265. if (err)
  266. return 1;
  267. for (i = 0; i < 16; i++)
  268. if (!buf[i])
  269. break;
  270. if (i != 16)
  271. break;
  272. laddr += 16;
  273. }
  274. node->data_addr = laddr + 16;
  275. }
  276. if ((grub_be_to_cpu32 (node->file.next_file)
  277. & GRUB_ROMFS_TYPE_MASK) == GRUB_ROMFS_TYPE_REGULAR)
  278. filetype = GRUB_FSHELP_REG;
  279. if ((grub_be_to_cpu32 (node->file.next_file)
  280. & GRUB_ROMFS_TYPE_MASK) == GRUB_ROMFS_TYPE_SYMLINK)
  281. filetype = GRUB_FSHELP_SYMLINK;
  282. if ((grub_be_to_cpu32 (node->file.next_file) & GRUB_ROMFS_TYPE_MASK)
  283. == GRUB_ROMFS_TYPE_DIRECTORY)
  284. {
  285. node->data_addr = grub_be_to_cpu32 (node->file.spec);
  286. filetype = GRUB_FSHELP_DIR;
  287. }
  288. break;
  289. }
  290. }
  291. if (hook ((char *) name, filetype, node, hook_data))
  292. {
  293. grub_free (name);
  294. return 1;
  295. }
  296. }
  297. grub_free (name);
  298. return 0;
  299. }
  300. /* Context for grub_romfs_dir. */
  301. struct grub_romfs_dir_ctx
  302. {
  303. grub_fs_dir_hook_t hook;
  304. void *hook_data;
  305. };
  306. /* Helper for grub_romfs_dir. */
  307. static int
  308. grub_romfs_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
  309. grub_fshelp_node_t node, void *data)
  310. {
  311. struct grub_romfs_dir_ctx *ctx = data;
  312. struct grub_dirhook_info info;
  313. grub_memset (&info, 0, sizeof (info));
  314. info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
  315. grub_free (node);
  316. return ctx->hook (filename, &info, ctx->hook_data);
  317. }
  318. static grub_err_t
  319. grub_romfs_dir (grub_device_t device, const char *path,
  320. grub_fs_dir_hook_t hook, void *hook_data)
  321. {
  322. struct grub_romfs_dir_ctx ctx = { hook, hook_data };
  323. struct grub_romfs_data *data = 0;
  324. struct grub_fshelp_node *fdiro = 0, start;
  325. data = grub_romfs_mount (device);
  326. if (! data)
  327. goto fail;
  328. start.addr = data->first_file;
  329. start.data_addr = data->first_file;
  330. start.data = data;
  331. grub_fshelp_find_file (path, &start, &fdiro, grub_romfs_iterate_dir,
  332. grub_romfs_read_symlink, GRUB_FSHELP_DIR);
  333. if (grub_errno)
  334. goto fail;
  335. grub_romfs_iterate_dir (fdiro, grub_romfs_dir_iter, &ctx);
  336. fail:
  337. grub_free (data);
  338. return grub_errno;
  339. }
  340. static grub_err_t
  341. grub_romfs_open (struct grub_file *file, const char *name)
  342. {
  343. struct grub_romfs_data *data = 0;
  344. struct grub_fshelp_node *fdiro = 0, start;
  345. data = grub_romfs_mount (file->device);
  346. if (! data)
  347. goto fail;
  348. start.addr = data->first_file;
  349. start.data_addr = data->first_file;
  350. start.data = data;
  351. grub_fshelp_find_file (name, &start, &fdiro, grub_romfs_iterate_dir,
  352. grub_romfs_read_symlink, GRUB_FSHELP_REG);
  353. if (grub_errno)
  354. goto fail;
  355. file->size = grub_be_to_cpu32 (fdiro->file.size);
  356. file->data = fdiro;
  357. return GRUB_ERR_NONE;
  358. fail:
  359. grub_free (data);
  360. return grub_errno;
  361. }
  362. static grub_ssize_t
  363. grub_romfs_read (grub_file_t file, char *buf, grub_size_t len)
  364. {
  365. struct grub_fshelp_node *data = file->data;
  366. /* XXX: The file is stored in as a single extent. */
  367. data->data->disk->read_hook = file->read_hook;
  368. data->data->disk->read_hook_data = file->read_hook_data;
  369. grub_disk_read (data->data->disk,
  370. (data->data_addr + file->offset) >> GRUB_DISK_SECTOR_BITS,
  371. (data->data_addr + file->offset) & (GRUB_DISK_SECTOR_SIZE - 1),
  372. len, buf);
  373. data->data->disk->read_hook = NULL;
  374. if (grub_errno)
  375. return -1;
  376. return len;
  377. }
  378. static grub_err_t
  379. grub_romfs_close (grub_file_t file)
  380. {
  381. struct grub_fshelp_node *data = file->data;
  382. grub_free (data->data);
  383. grub_free (data);
  384. return GRUB_ERR_NONE;
  385. }
  386. static grub_err_t
  387. grub_romfs_label (grub_device_t device, char **label)
  388. {
  389. struct grub_romfs_data *data;
  390. grub_err_t err;
  391. *label = NULL;
  392. data = grub_romfs_mount (device);
  393. if (!data)
  394. return grub_errno;
  395. *label = grub_malloc (data->first_file + 1
  396. - sizeof (struct grub_romfs_superblock));
  397. if (!*label)
  398. {
  399. grub_free (data);
  400. return grub_errno;
  401. }
  402. err = grub_disk_read (device->disk, 0, sizeof (struct grub_romfs_superblock),
  403. data->first_file
  404. - sizeof (struct grub_romfs_superblock),
  405. *label);
  406. if (err)
  407. {
  408. grub_free (data);
  409. grub_free (*label);
  410. *label = NULL;
  411. return err;
  412. }
  413. (*label)[data->first_file - sizeof (struct grub_romfs_superblock)] = 0;
  414. grub_free (data);
  415. return GRUB_ERR_NONE;
  416. }
  417. static struct grub_fs grub_romfs_fs =
  418. {
  419. .name = "romfs",
  420. .fs_dir = grub_romfs_dir,
  421. .fs_open = grub_romfs_open,
  422. .fs_read = grub_romfs_read,
  423. .fs_close = grub_romfs_close,
  424. .fs_label = grub_romfs_label,
  425. #ifdef GRUB_UTIL
  426. .reserved_first_sector = 0,
  427. .blocklist_install = 0,
  428. #endif
  429. .next = 0
  430. };
  431. GRUB_MOD_INIT(romfs)
  432. {
  433. if (!grub_is_lockdown ())
  434. {
  435. grub_romfs_fs.mod = mod;
  436. grub_fs_register (&grub_romfs_fs);
  437. }
  438. }
  439. GRUB_MOD_FINI(romfs)
  440. {
  441. if (!grub_is_lockdown ())
  442. grub_fs_unregister (&grub_romfs_fs);
  443. }