--- squashfs-tools/unsquashfs.c +++ squashfs-tools/unsquashfs.c @@ -79,6 +79,9 @@ int user_xattrs = FALSE; int scan_for_superblock = FALSE; off_t superblock_offset = 0; +int has_swapped_endianess = FALSE; +off_t nmi_vector_offset = (off_t)-1; +unsigned int nmi_vector_size = 0; int exit_on_error = FALSE; @@ -686,6 +689,8 @@ continue; } + has_swapped_endianess = (buf.magic == SQUASHFS_MAGIC_SWAP); + TRACE("find_superblock:%s magic 0x%08X found at 0x%08X\n", (buf.magic == SQUASHFS_MAGIC_SWAP ? " swapped" : ""), buf.magic, (unsigned int)offset); // do not rely on MAGIC only, check a little bit more @@ -708,14 +713,98 @@ return (off_t) -1; } +char nmi_vector_id[] = "NMI Boot Vector"; +typedef struct nmi_vector_buf { + unsigned int firmware_length; + unsigned int vector_size; + char vector_id[32]; +} nmi_vector_buf; + +off_t find_nmi_vector_location(int fd, unsigned int *nmi_vector_size) { + off_t offset; + nmi_vector_buf buf; + + for (offset = 0x40; /* forever */; offset += 256) { + if (lseek(fd, offset, SEEK_SET) == -1) { + ERROR("Lseek failed because %s\n", strerror(errno)); + break; + } + + if (read(fd, &buf, sizeof(nmi_vector_buf)) != sizeof(nmi_vector_buf)) { + break; + } + + if (strncmp(buf.vector_id, nmi_vector_id, 1+strlen(nmi_vector_id)) != 0) { + continue; + } + + if (has_swapped_endianess) { + buf.vector_size = inswap_le32(buf.vector_size); + buf.firmware_length = inswap_le32(buf.firmware_length); + } + TRACE("find_nmi_vector_location: found NMI vector at=0x%08X, size=0x%08X, firmware_length=0x%08X\n", (unsigned int)(offset - 0x40), buf.vector_size, buf.firmware_length); + + *nmi_vector_size = buf.vector_size; + + return offset - 0x40; + } + + return (off_t) -1; +} + int read_fs_bytes(int fd, long long byte, int bytes, void *buff) { off_t off = byte + superblock_offset; int res, count; +#ifdef SQUASHFS_TRACE + unsigned char *b; +#endif TRACE("read_fs_bytes: reading from position 0x%llx, bytes %d\n", byte, bytes); + if (nmi_vector_offset != (off_t) -1) { + /* + - if we're below and the last byte to read doesn't cross the line, there's + nothing to do (case A) - this case needs no handling and so it's the + default path, if none of the others match + - if we're above or even at the "magic border", we simply add the gap size + to the requested offset (case B) + - the only special case is a read starting before nmi_vector_gap_start and + running into the gap - here we'll split this single read into two + recursive calls to our own function, where the 1st access is shortened + to stop at the last byte before the gap and the 2nd will start over at + the gap offset and read the remaining bytes (it's case B for this + recursive call) + */ + + if (off >= nmi_vector_offset) { + /* case B */ + off += nmi_vector_size; + } else if ((off < nmi_vector_offset) && ((off + bytes) > nmi_vector_offset)) { + /* case C */ + TRACE("read_fs_bytes: split read needed, abs=0x%08lX, rel=0x%08lX, count=0x%X, to=0x%08X\n", (long) off, (long) byte, bytes, buff); + + TRACE("read_fs_bytes: part 1 from=0x%08lX, size=0x%08lX", (long) byte, (long) (nmi_vector_offset - off)); + if (read_fs_bytes(fd, byte, nmi_vector_offset - off, buff) == FALSE) { + return FALSE; + } + +#ifdef SQUASHFS_TRACE + b = buff + (nmi_vector_offset - off) - 4; +#endif + TRACE("read_fs_bytes: buffer content around the gap: 0x%08lX %02x %02x %02x %02x %02x %02x %02x %02x\n", b, *b, *(b + 1), *(b + 2), *(b + 3), *(b + 4), *(b + 5), *(b + 6), *(b + 7)); + + TRACE("read_fs_bytes: part 2 from=0x%08lX, size=0x%08lX", (long) (nmi_vector_offset - superblock_offset), (long) (bytes - (nmi_vector_offset - off))); + if (read_fs_bytes(fd, nmi_vector_offset - superblock_offset, bytes - (nmi_vector_offset - off), buff + (nmi_vector_offset - off)) == FALSE) { + return FALSE; + } + TRACE("read_fs_bytes: buffer content around the gap: 0x%08lX %02x %02x %02x %02x %02x %02x %02x %02x\n", b, *b, *(b + 1), *(b + 2), *(b + 3), *(b + 4), *(b + 5), *(b + 6), *(b + 7)); + + return TRUE; + } + } + if(lseek(fd, off, SEEK_SET) == -1) { ERROR("Lseek failed because %s\n", strerror(errno)); return FALSE; @@ -2793,6 +2882,7 @@ ERROR("\t-exit-on-error\t\ttreat normally ignored errors as fatal\n"); ERROR("\t-scan or -k\t\ttreat filesystem as a combined image\n"); ERROR("\t\t\t\t(kernel+SquashFS) and scan it to locate the superblock\n"); + ERROR("\t\t\t\tand the NMI vector gap\n"); ERROR("\nDecompressors available:\n"); display_compressors("", ""); } @@ -2816,6 +2906,11 @@ } ERROR("Found a valid superblock at offset 0x%08X while scanning %s.\n", (unsigned int) superblock_offset, argv[i]); + + nmi_vector_offset = find_nmi_vector_location(fd, &nmi_vector_size); + if (nmi_vector_offset != (off_t) -1) { + ERROR("NMI vector found at 0x%08X, size=%d\n", (unsigned int) nmi_vector_offset, nmi_vector_size); + } } if(read_super(argv[i]) == FALSE)