fs.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /*
  2. * x86_64-efi/fs.h
  3. *
  4. * Copyright (C) 2017 - 2021 bzt (bztsrc@gitlab)
  5. *
  6. * Permission is hereby granted, free of charge, to any person
  7. * obtaining a copy of this software and associated documentation
  8. * files (the "Software"), to deal in the Software without
  9. * restriction, including without limitation the rights to use, copy,
  10. * modify, merge, publish, distribute, sublicense, and/or sell copies
  11. * of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be
  15. * included in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. * DEALINGS IN THE SOFTWARE.
  25. *
  26. * This file is part of the BOOTBOOT Protocol package.
  27. * @brief Filesystem drivers for initial ramdisk.
  28. *
  29. */
  30. /**
  31. * FS/Z initrd (OS/Z's native file system)
  32. */
  33. file_t fsz_initrd(unsigned char *initrd_p, char *kernel)
  34. {
  35. file_t ret = { NULL, 0 };
  36. if(initrd_p==NULL || CompareMem(initrd_p + 512,"FS/Z",4) || kernel==NULL){
  37. return ret;
  38. }
  39. unsigned char passphrase[256],chk[32],iv[32];
  40. unsigned int i,j,k,l,ss=1<<(initrd_p[518]+11);
  41. unsigned char *ent, *in=(initrd_p+*((uint64_t*)(initrd_p+560))*ss);
  42. SHA256_CTX ctx;
  43. DBG(L" * FS/Z %s\n",a2u(kernel));
  44. //decrypt initrd
  45. while(*((uint32_t*)(initrd_p+520))!=0) {
  46. Print(L" * Passphrase? ");
  47. l=ReadLine(passphrase,sizeof(passphrase));
  48. if(!l) {
  49. Print(L"\n");
  50. return ret;
  51. }
  52. if(*((uint32_t*)(initrd_p+520))!=crc32_calc((char*)passphrase,l)) {
  53. Print(L"\rBOOTBOOT-ERROR: Bad passphrase\n");
  54. continue;
  55. }
  56. Print(L"\r * Decrypting...\r");
  57. SHA256_Init(&ctx);
  58. SHA256_Update(&ctx,passphrase,l);
  59. SHA256_Update(&ctx,initrd_p+512,6);
  60. SHA256_Final(chk,&ctx);
  61. for(i=0;i<32;i++) initrd_p[i+680]^=chk[i];
  62. SHA256_Init(&ctx);
  63. SHA256_Update(&ctx,initrd_p+680,32);
  64. SHA256_Final(iv,&ctx);
  65. if(((initrd_p[519]>>4)&15)==1) {
  66. // FSZ_SB_EALG_AESCBC
  67. aes_init(iv);
  68. for(k=ss,j=1;j<*((uint32_t*)(initrd_p+528));k+=ss,j++) {
  69. aes_dec(initrd_p+k,ss);
  70. }
  71. } else {
  72. // FSZ_SB_EALG_SHACBC
  73. for(k=ss,j=1;j<*((uint32_t*)(initrd_p+528));j++) {
  74. CopyMem(chk,iv,32);
  75. for(i=0;i<ss;i++) {
  76. if(i%32==0) {
  77. SHA256_Init(&ctx);
  78. SHA256_Update(&ctx,&chk,32);
  79. SHA256_Update(&ctx,&j,4);
  80. SHA256_Final(chk,&ctx);
  81. }
  82. initrd_p[k++]^=chk[i%32]^iv[i%32];
  83. }
  84. }
  85. }
  86. ZeroMem(initrd_p+680,32); *((uint32_t*)(initrd_p+520)) = 0;
  87. *((uint32_t*)(initrd_p+1020))=crc32_calc((char *)initrd_p+512,508);
  88. Print(L" \r");
  89. }
  90. // Get the inode
  91. char *s,*e;
  92. s=e=kernel;
  93. i=0;
  94. again:
  95. while(*e!='/'&&*e!=0){e++;}
  96. if(*e=='/'){e++;}
  97. if(!CompareMem(in,"FSIN",4)){
  98. //is it inlined?
  99. if(!CompareMem(initrd_p[520]&1? in + 2048 : in + 1024,"FSDR",4)){
  100. ent=(initrd_p[520]&1? in + 2048 : in + 1024);
  101. } else if(!CompareMem(initrd_p+*((uint64_t*)(in+448))*ss,"FSDR",4)){
  102. // go, get the sector pointed
  103. ent=(initrd_p+*((uint64_t*)(in+448))*ss);
  104. } else {
  105. return ret;
  106. }
  107. //skip header
  108. unsigned char *hdr=ent; ent+=128;
  109. //iterate on directory entries
  110. int j=*((uint64_t*)(hdr+16));
  111. while(j-->0){
  112. if(!CompareMem(ent + 16,s,e-s)) {
  113. if(*e==0) {
  114. i=*((uint64_t*)(ent+0));
  115. break;
  116. } else {
  117. s=e;
  118. in=(initrd_p+*((uint64_t*)(ent+0))*ss);
  119. goto again;
  120. }
  121. }
  122. ent+=128;
  123. }
  124. } else {
  125. i=0;
  126. }
  127. if(i!=0) {
  128. // fid -> inode ptr -> data ptr
  129. unsigned char *in=(initrd_p+i*ss);
  130. if(!CompareMem(in,"FSIN",4)){
  131. ret.size=*((uint64_t*)(in+464));
  132. if(*((uint64_t*)(in+448)) == i) {
  133. if(!(in[488]&31)) {
  134. // inline data
  135. ret.ptr=(uint8_t*)(initrd_p+i*ss+(initrd_p[520]&1? 2048 : 1024));
  136. } else {
  137. // sector directory or list inlined
  138. ret.ptr=(uint8_t*)(initrd_p + *((uint64_t*)(initrd_p[520]&1? in + 2048 : in + 1024))*ss);
  139. }
  140. } else
  141. if(*((uint64_t*)(in+448))) {
  142. switch((in[488]&15) + (in[488]&16 ? 1 : 0)) {
  143. case 0: // direct data
  144. ret.ptr=(uint8_t*)(initrd_p + *((uint64_t*)(in+448)) * ss);
  145. break;
  146. case 1: // sector directory or list (only one level supported here, and no holes in files)
  147. ret.ptr=(uint8_t*)(initrd_p + *((uint64_t*)(initrd_p + *((uint64_t*)(in+448))*ss)) * ss);
  148. break;
  149. }
  150. } else ret.size=0;
  151. }
  152. }
  153. return ret;
  154. }
  155. /**
  156. * Minix3 file system
  157. * directories only checked for their first block, and kernel must be defragmented
  158. */
  159. file_t mfs_initrd(unsigned char *initrd_p, char *kernel)
  160. {
  161. UINT32 o, bs, ino_tbl;
  162. UINT8 *ino, *d;
  163. char *s = kernel, *e;
  164. file_t ret = { NULL, 0 };
  165. if(initrd_p[1048] != 'Z' || initrd_p[1049] != 'M') return ret;
  166. DBG(L" * MFS %s\n",a2u(kernel));
  167. bs = *((UINT16*)(initrd_p + 1052));
  168. ino_tbl = (2 + *((UINT16*)(initrd_p + 1030)) + *((UINT16*)(initrd_p + 1032))) * bs;
  169. ino = initrd_p + ino_tbl;
  170. again:
  171. for(e = s; *e && *e != '/'; e++);
  172. d = initrd_p + *((UINT32*)(ino + 24)) * bs;
  173. for(o = 0; o < *((UINT32*)(ino + 8)) && o < bs; o += 64, d += 64) {
  174. if(*((UINT32*)d) && !CompareMem(s, d + 4, e - s) && !d[e - s]) {
  175. ino = initrd_p + ino_tbl + (*((UINT32*)d) - 1) * 64;
  176. d = initrd_p + *((UINT32*)(ino + 24)) * bs;
  177. if(!*e) { ret.ptr = d; ret.size = *((UINT32*)(ino + 8)); return ret; }
  178. s = e + 1; goto again;
  179. }
  180. }
  181. return ret;
  182. }
  183. /**
  184. * cpio archive
  185. */
  186. file_t cpio_initrd(unsigned char *initrd_p, char *kernel)
  187. {
  188. unsigned char *ptr=initrd_p;
  189. int k;
  190. file_t ret = { NULL, 0 };
  191. if(initrd_p==NULL || kernel==NULL ||
  192. (CompareMem(initrd_p,"070701",6) && CompareMem(initrd_p,"070702",6) && CompareMem(initrd_p,"070707",6)))
  193. return ret;
  194. DBG(L" * cpio %s\n",a2u(kernel));
  195. k=strlena((unsigned char*)kernel);
  196. // hpodc archive
  197. while(!CompareMem(ptr,"070707",6)){
  198. int ns=oct2bin(ptr+8*6+11,6);
  199. int fs=oct2bin(ptr+8*6+11+6,11);
  200. if(!CompareMem(ptr+9*6+2*11,kernel,k+1) ||
  201. (ptr[9*6+2*11] == '.' && ptr[9*6+2*11+1] == '/' && !CompareMem(ptr+9*6+2*11+2,kernel,k+1))) {
  202. ret.size=fs;
  203. ret.ptr=(UINT8*)(ptr+9*6+2*11+ns);
  204. return ret;
  205. }
  206. ptr+=(76+ns+fs);
  207. }
  208. // newc and crc archive
  209. while(!CompareMem(ptr,"07070",5)){
  210. int fs=hex2bin(ptr+8*6+6,8);
  211. int ns=hex2bin(ptr+8*11+6,8);
  212. if(!CompareMem(ptr+110,kernel,k+1) || (ptr[110] == '.' && ptr[111] == '/' && !CompareMem(ptr+112,kernel,k+1))) {
  213. ret.size=fs;
  214. ret.ptr=(UINT8*)(ptr+((110+ns+3)/4)*4);
  215. return ret;
  216. }
  217. ptr+=((110+ns+3)/4)*4 + ((fs+3)/4)*4;
  218. }
  219. return ret;
  220. }
  221. /**
  222. * ustar tarball archive
  223. */
  224. file_t tar_initrd(unsigned char *initrd_p, char *kernel)
  225. {
  226. unsigned char *ptr=initrd_p;
  227. int k;
  228. file_t ret = { NULL, 0 };
  229. if(initrd_p==NULL || kernel==NULL || CompareMem(initrd_p+257,"ustar",5))
  230. return ret;
  231. DBG(L" * tar %s\n",a2u(kernel));
  232. k=strlena((unsigned char*)kernel);
  233. while(!CompareMem(ptr+257,"ustar",5)){
  234. int fs=oct2bin(ptr+0x7c,11);
  235. if(!CompareMem(ptr,kernel,k+1) || (ptr[0] == '.' && ptr[1] == '/' && !CompareMem(ptr+2,kernel,k+1))) {
  236. ret.size=fs;
  237. ret.ptr=(UINT8*)(ptr+512);
  238. return ret;
  239. }
  240. ptr+=(((fs+511)/512)+1)*512;
  241. }
  242. return ret;
  243. }
  244. /**
  245. * Simple File System
  246. */
  247. file_t sfs_initrd(unsigned char *initrd_p, char *kernel)
  248. {
  249. unsigned char *ptr, *end;
  250. int k,bs,ver;
  251. file_t ret = { NULL, 0 };
  252. if(initrd_p==NULL || kernel==NULL || (CompareMem(initrd_p+0x1AC,"SFS",3) && CompareMem(initrd_p+0x1A6,"SFS",3)))
  253. return ret;
  254. // 1.0 Brendan's version, 1.10 BenLunt's version
  255. ver=!CompareMem(initrd_p+0x1A6,"SFS",3)?10:0;
  256. bs=1<<(7+(UINT8)initrd_p[ver?0x1B6:0x1BC]);
  257. end=initrd_p + *((UINT64 *)&initrd_p[ver?0x1AA:0x1B0]) * bs; // base + total_number_of_blocks * blocksize
  258. // get index area
  259. ptr=end - *((UINT64 *)&initrd_p[ver?0x19E:0x1A4]); // end - size of index area
  260. // got a Starting Marker Entry?
  261. if(ptr[0]!=2)
  262. return ret;
  263. DBG(L" * SFS 1.%d %s\n",ver,a2u(kernel));
  264. k=strlena((unsigned char*)kernel);
  265. // iterate on index until we reach the end or Volume Identifier
  266. while(ptr<end && ptr[0]!=0x01){
  267. ptr+=64;
  268. // file entry?
  269. if(ptr[0]!=0x12)
  270. continue;
  271. // filename match?
  272. if(!CompareMem(ptr+(ver?0x23:0x22),kernel,k+1)){
  273. ret.size=*((UINTN*)&ptr[ver?0x1B:0x1A]); // file_length
  274. ret.ptr=initrd_p + *((UINT64*)&ptr[ver?0x0B:0x0A]) * bs; // base + start_block * blocksize
  275. break;
  276. }
  277. }
  278. return ret;
  279. }
  280. /**
  281. * James Molloy's initrd (for some reason it's popular among hobby OS developers)
  282. * http://www.jamesmolloy.co.uk/tutorial_html
  283. */
  284. file_t jamesm_initrd(unsigned char *initrd_p, char *kernel)
  285. {
  286. unsigned char *ptr=initrd_p+4;
  287. int i,k,nf=*((int*)initrd_p);
  288. file_t ret = { NULL, 0 };
  289. // no real magic, so we assume initrd contains at least one file...
  290. if(initrd_p==NULL || kernel==NULL || initrd_p[2]!=0 || initrd_p[3]!=0 || initrd_p[4]!=0xBF)
  291. return ret;
  292. DBG(L" * JamesM %s\n",a2u(kernel));
  293. k=strlena((unsigned char*)kernel);
  294. for(i=0;i<nf && ptr[0]==0xBF;i++) {
  295. if(!CompareMem(ptr+1,kernel,k+1)){
  296. ret.ptr=*((uint32_t*)(ptr+65)) + initrd_p;
  297. ret.size=*((uint32_t*)(ptr+69));
  298. }
  299. ptr+=73;
  300. }
  301. return ret;
  302. }
  303. /**
  304. * EchFS
  305. * http://github.com/echfs/echfs
  306. */
  307. file_t ech_initrd(unsigned char *initrd_p, char *kernel)
  308. {
  309. UINT64 parent = 0xffffffffffffffffUL, n;
  310. unsigned char *ptr;
  311. char *end, *fn;
  312. int k = 0;
  313. file_t ret = { NULL, 0 };
  314. if(initrd_p==NULL || kernel==NULL || CompareMem(initrd_p+4,"_ECH_FS_",8))
  315. return ret;
  316. DBG(L" * EchFS %s\n",a2u(kernel));
  317. CopyMem(&k, initrd_p + 28, 4);
  318. CopyMem(&n, initrd_p + 12, 8);
  319. ptr = initrd_p + (((n * 8 + k - 1) / k) + 16) * k;
  320. for(end = fn = kernel; *end && *end != '/'; end++);
  321. while(*((UINT64*)ptr)) {
  322. if(*((UINT64*)ptr) == parent && !CompareMem(ptr + 9, fn, end - fn) && !ptr[9 + end - fn]) {
  323. parent = *((UINT64*)(ptr + 240));
  324. if(!*end) {
  325. ret.size=*((UINTN*)(ptr + 248));
  326. ret.ptr=(UINT8*)(initrd_p + parent * k);
  327. break;
  328. }
  329. end++;
  330. for(fn = end; *end && *end != '/'; end++);
  331. }
  332. ptr += 256;
  333. }
  334. return ret;
  335. }
  336. /**
  337. * Static file system drivers registry
  338. */
  339. file_t (*fsdrivers[]) (unsigned char *, char *) = {
  340. fsz_initrd,
  341. mfs_initrd,
  342. cpio_initrd,
  343. tar_initrd,
  344. sfs_initrd,
  345. jamesm_initrd,
  346. ech_initrd,
  347. NULL
  348. };