/* * x86_64-cb/fs.h * * Copyright (C) 2017 - 2021 bzt (bztsrc@gitlab) * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * This file is part of the BOOTBOOT Protocol package. * @brief Filesystem drivers for initial ramdisk. * */ /** * FS/Z initrd (OS/Z's native file system) */ file_t fsz_initrd(unsigned char *initrd_p, char *kernel) { file_t ret = { NULL, 0 }; if(initrd_p==NULL || memcmp(initrd_p + 512,"FS/Z",4) || kernel==NULL){ return ret; } unsigned char passphrase[256],chk[32],iv[32]; unsigned int i,j,k,l,ss=1<<(initrd_p[518]+11); unsigned char *ent, *in=(initrd_p+*((uint64_t*)(initrd_p+560))*ss); SHA256_CTX ctx; DBG(" * FS/Z %s\n",kernel); //decrypt initrd if(*((uint32_t*)(initrd_p+708))!=0 && initrd_p[519]!=0) { printf("BOOTBOOT-PANIC: Unsupported cipher\n"); return ret; } while(*((uint32_t*)(initrd_p+708))!=0) { printf(" * Passphrase? "); l=ReadLine(passphrase,sizeof(passphrase)); if(!l) { printf("\n"); return ret; } if(*((uint32_t*)(initrd_p+708))!=crc32_calc((char*)passphrase,l)) { printf("\rBOOTBOOT-ERROR: Bad passphrase\n"); continue; } printf("\r * Decrypting...\r"); SHA256_Init(&ctx); SHA256_Update(&ctx,passphrase,l); SHA256_Update(&ctx,initrd_p+512,6); SHA256_Final(chk,&ctx); for(i=0;i<28;i++) initrd_p[i+680]^=chk[i]; SHA256_Init(&ctx); SHA256_Update(&ctx,initrd_p+680,28); SHA256_Final(iv,&ctx); for(k=ss,j=1;j<*((uint32_t*)(initrd_p+528));j++) { memcpy(chk,iv,32); for(i=0;i0){ if(!memcmp(ent + 16,s,e-s)) { if(*e==0) { i=*((uint64_t*)(ent+0)); break; } else { s=e; in=(initrd_p+*((uint64_t*)(ent+0))*ss); goto again; } } ent+=128; } } else { i=0; } if(i!=0) { // fid -> inode ptr -> data ptr unsigned char *in=(initrd_p+i*ss); if(!memcmp(in,"FSIN",4)){ ret.size=*((uint64_t*)(in+464)); switch(in[488]) { case 0xFF: // inline data ret.ptr=(uint8_t*)(initrd_p+i*ss+(initrd_p[520]&1? 2048 : 1024)); break; case 0x80: case 0x7F: // sector directory or list inlined ret.ptr=(uint8_t*)(initrd_p + *((uint64_t*)(initrd_p[520]&1? in + 2048 : in + 1024))*ss); break; case 0: // direct data ret.ptr=(uint8_t*)(initrd_p + *((uint64_t*)(in+448)) * ss); break; // sector directory (only one level supported here, and no holes in files) case 0x81: case 1: ret.ptr=(uint8_t*)(initrd_p + *((uint64_t*)(initrd_p + *((uint64_t*)(in+448))*ss)) * ss); break; default: ret.size=0; break; } } } return ret; } /** * cpio archive */ file_t cpio_initrd(unsigned char *initrd_p, char *kernel) { unsigned char *ptr=initrd_p; int k; file_t ret = { NULL, 0 }; if(initrd_p==NULL || kernel==NULL || (memcmp(initrd_p,"070701",6) && memcmp(initrd_p,"070702",6) && memcmp(initrd_p,"070707",6))) return ret; DBG(" * cpio %s\n",kernel); k=strlen(kernel); // hpodc archive while(!memcmp(ptr,"070707",6)){ int ns=octbin(ptr+8*6+11,6); int fs=octbin(ptr+8*6+11+6,11); if(!memcmp(ptr+9*6+2*11,kernel,k+1) || (ptr[9*6+2*11] == '.' && ptr[9*6+2*11+1] == '/' && !memcmp(ptr+9*6+2*11+2,kernel,k+1))) { ret.size=fs; ret.ptr=(uint8_t*)(ptr+9*6+2*11+ns); return ret; } ptr+=(76+ns+fs); } // newc and crc archive while(!memcmp(ptr,"07070",5)){ int fs=hexbin(ptr+8*6+6,8); int ns=hexbin(ptr+8*11+6,8); if(!memcmp(ptr+110,kernel,k+1) || (ptr[110] == '.' && ptr[111] == '/' && !memcmp(ptr+112,kernel,k+1))) { ret.size=fs; ret.ptr=(uint8_t*)(ptr+((110+ns+3)/4)*4); return ret; } ptr+=((110+ns+3)/4)*4 + ((fs+3)/4)*4; } return ret; } /** * ustar tarball archive */ file_t tar_initrd(unsigned char *initrd_p, char *kernel) { unsigned char *ptr=initrd_p; int k; file_t ret = { NULL, 0 }; if(initrd_p==NULL || kernel==NULL || memcmp(initrd_p+257,"ustar",5)) return ret; DBG(" * tar %s\n",kernel); k=strlen(kernel); while(!memcmp(ptr+257,"ustar",5)){ int fs=octbin(ptr+0x7c,11); if(!memcmp(ptr,kernel,k+1) || (ptr[0] == '.' && ptr[1] == '/' && !memcmp(ptr+2,kernel,k+1))) { ret.size=fs; ret.ptr=(uint8_t*)(ptr+512); return ret; } ptr+=(((fs+511)/512)+1)*512; } return ret; } /** * Simple File System */ file_t sfs_initrd(unsigned char *initrd_p, char *kernel) { unsigned char *ptr, *end; int k,bs,ver; file_t ret = { NULL, 0 }; if(initrd_p==NULL || kernel==NULL || (memcmp(initrd_p+0x1AC,"SFS",3) && memcmp(initrd_p+0x1A6,"SFS",3))) return ret; // 1.0 Brendan's version, 1.10 BenLunt's version ver=!memcmp(initrd_p+0x1A6,"SFS",3)?10:0; bs=1<<(7+(uint8_t)initrd_p[ver?0x1B6:0x1BC]); end=initrd_p + *((uint64_t *)&initrd_p[ver?0x1AA:0x1B0]) * bs; // base + total_number_of_blocks * blocksize // get index area ptr=end - *((uint64_t *)&initrd_p[ver?0x19E:0x1A4]); // end - size of index area // got a Starting Marker Entry? if(ptr[0]!=2) return ret; DBG(" * SFS 1.%s %s\n", ver?"10":"0",kernel); k=strlen(kernel); // iterate on index until we reach the end or Volume Identifier while(ptr