From 5afa43629d56ef034c263dd057b00f5cd894d607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Hord=C3=A9?= Date: Sat, 26 Jan 2019 10:50:18 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20pr=C3=A9paration=20de=20la=20gestion=20?= =?UTF-8?q?du=20CRAMFS=20depuis=20les=20sources=20de=20Linux?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/cramfs.h | 83 ++++++++++++ include/math.h | 2 +- lib/cramfs.c | 325 +++++++++++++++++++++++++++++++++++++++++++++++ lib/math.c | 54 ++++++++ lib/memory.c | 1 + system/system.c | 14 +- 6 files changed, 476 insertions(+), 3 deletions(-) create mode 100644 include/cramfs.h create mode 100644 lib/cramfs.c diff --git a/include/cramfs.h b/include/cramfs.h new file mode 100644 index 0000000..f21ff92 --- /dev/null +++ b/include/cramfs.h @@ -0,0 +1,83 @@ +/*******************************************************************************/ +/* COS2000 - Compatible Operating System - LGPL v3 - Hordé Nicolas */ +/* */ + +/* Sources modifiées du noyau Linux cramfs_fs.h +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ + +#include "types.h" + +#ifndef _CRAMFS +#define _CRAMFS + +#define CRAMFS_SIGNATURE "Compressed ROMFS" + +#define CRAMFS_MODE_WIDTH 16 +#define CRAMFS_UID_WIDTH 16 +#define CRAMFS_SIZE_WIDTH 24 +#define CRAMFS_GID_WIDTH 8 +#define CRAMFS_NAMELEN_WIDTH 6 +#define CRAMFS_OFFSET_WIDTH 26 +#define CRAMFS_MAGIC 0x28cd3d45 +#define CRAMFS_MAXPATHLEN (((1 << CRAMFS_NAMELEN_WIDTH) - 1) << 2) +#define PAD_SIZE 512 +#define PAGE_CACHE_SIZE (4096) +typedef struct cramfs_inode { + u32 mode:CRAMFS_MODE_WIDTH; + u32 uid:CRAMFS_UID_WIDTH; + u32 size:CRAMFS_SIZE_WIDTH; + u32 gid:CRAMFS_GID_WIDTH; + u32 namelen:CRAMFS_NAMELEN_WIDTH; + u32 offset:CRAMFS_OFFSET_WIDTH; +} cramfs_inode; + +typedef struct cramfs_info { + u32 crc; + u32 edition; + u32 blocks; + u32 files; +} cramfs_info; + +typedef struct cramfs_super { + u32 magic; /* 0x28cd3d45 - random number */ + u32 size; /* length in bytes */ + u32 flags; /* feature flags */ + u32 future; /* reserved for future use */ + u8 signature[16]; /* "Compressed ROMFS" */ + cramfs_info fsid; /* unique filesystem info */ + u8 name[16]; /* user-defined name */ + cramfs_inode root; /* root inode data */ +} cramfs_super; + +#define S_ISDIR(m) ((m & 0170000) == 0040000) /* directory */ +#define S_ISCHR(m) ((m & 0170000) == 0020000) /* char special */ +#define S_ISBLK(m) ((m & 0170000) == 0060000) /* block special */ +#define S_ISREG(m) ((m & 0170000) == 0100000) /* regular file */ +#define S_ISFIFO(m) ((m & 0170000) == 0010000) /* fifo */ +#define S_ISLNK(m) ((m & 0170000) == 0120000) /* symbolic link */ +#define S_ISSOCK(m) ((m & 0170000) == 0140000) /* socket */ + +#define CRAMFS_FLAG_FSID_VERSION_2 0x00000001 /* fsid version #2 */ +#define CRAMFS_FLAG_SORTED_DIRS 0x00000002 /* sorted dirs */ +#define CRAMFS_FLAG_HOLES 0x00000100 /* support for holes */ +#define CRAMFS_FLAG_WRONG_SIGNATURE 0x00000200 /* reserved */ +#define CRAMFS_FLAG_SHIFTED_ROOT_OFFSET 0x00000400 /* shifted root fs */ +#define CRAMFS_FLAG_EXT_BLOCK_POINTERS 0x00000800 /* block pointer extensions */ + +#define CRAMFS_SUPPORTED_FLAGS ( 0x000000ff \ + | CRAMFS_FLAG_HOLES \ + | CRAMFS_FLAG_WRONG_SIGNATURE \ + | CRAMFS_FLAG_SHIFTED_ROOT_OFFSET \ + | CRAMFS_FLAG_EXT_BLOCK_POINTERS ) + +#define CRAMFS_BLK_FLAG_UNCOMPRESSED (1 << 31) +#define CRAMFS_BLK_FLAG_DIRECT_PTR (1 << 30) + +#define CRAMFS_BLK_FLAGS ( CRAMFS_BLK_FLAG_UNCOMPRESSED \ + | CRAMFS_BLK_FLAG_DIRECT_PTR ) + +#define CRAMFS_BLK_DIRECT_PTR_SHIFT 2 + +u32 test_super(u8 *src, u32 length); + +#endif diff --git a/include/math.h b/include/math.h index 97299de..24c4767 100644 --- a/include/math.h +++ b/include/math.h @@ -8,7 +8,7 @@ #define EPSILON 1E-40 #define degtorad(deg) (deg * PI / 180.0) #define radtodeg(rad) (rad * 180.0 / PI) - +u32 crc32(u32 inCrc32, u8 *buf, u32 size); double cos(double x); double sin(double x); float cosf(float x); diff --git a/lib/cramfs.c b/lib/cramfs.c new file mode 100644 index 0000000..799c465 --- /dev/null +++ b/lib/cramfs.c @@ -0,0 +1,325 @@ +/*******************************************************************************/ +/* COS2000 - Compatible Operating System - LGPL v3 - Hordé Nicolas */ +/* */ +/* Quelques portions modifiée proviennent de cramfsck - check a cramfs file system + * + * Copyright (C) 2000-2002 Transmeta Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * 1999/12/03: Linus Torvalds (cramfs tester and unarchive program) + * 2000/06/03: Daniel Quinlan (CRC and length checking program) + * 2000/06/04: Daniel Quinlan (merged programs, added options, support + * for special files, preserve permissions and + * ownership, cramfs superblock v2, bogus mode + * test, pathname length test, etc.) + * 2000/06/06: Daniel Quinlan (support for holes, pretty-printing, + * symlink size test) + * 2000/07/11: Daniel Quinlan (file length tests, start at offset 0 or 512, + * fsck-compatible exit codes) + * 2000/07/15: Daniel Quinlan (initial support for block devices) + * 2002/01/10: Daniel Quinlan (additional checks, test more return codes, + * use read if mmap fails, standardize messages) + * 2015/06/09: Yves-Noel Weweler (support for ignoring errors, when + * extracting obscure cramfs files) */ + +#include "types.h" +#include "cramfs.h" +#include "boot.h" +#include "memory.h" + +u8* initrambloc; +u8 start; +cramfs_super* super; +extern bootparams* allparams; + +/*******************************************************************************/ +/* Copie l'initram CRAMFS vers un malloc */ +void remap_initram() +{ + virtual_range_use_kernel(allparams->ramdiskaddr, allparams->ramdiskaddr, allparams->ramdisksize, PAGE_NOFLAG); + initrambloc=vmalloc(allparams->ramdisksize); + memcpy(allparams->ramdiskaddr,initrambloc,allparams->ramdisksize,0); + virtual_range_free_kernel(allparams->ramdiskaddr,allparams->ramdisksize); +} + +/*******************************************************************************/ +/* Lit l'inode et renvoie un pointeur grâce à vmalloc */ + +cramfs_inode *cramfs_iget(cramfs_inode * i) +{ + cramfs_inode *inode = vmalloc(sizeof(cramfs_inode)); + if (!inode) + return NULL; + *inode = *i; + return inode; +} + +/*******************************************************************************/ +/* Lit l'inode principal */ + +cramfs_inode *read_super(void) +{ + u32 offset = super.root.offset << 2; + + if (!S_ISDIR(super.root.mode)) + return NULL; /* fichier */ + if (!(super.flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) && ((offset != sizeof(cramfs_super)) && + (offset != PAD_SIZE + sizeof(cramfs_super)))) + return NULL ; /*offset erronée */ + return cramfs_iget(&super.root); +} + + + +static int uncompress_block(void *src, int len) +{ + int err; + + stream.next_in = src; + stream.avail_in = len; + + stream.next_out = (unsigned char *) outbuffer; + stream.avail_out = PAGE_CACHE_SIZE*2; + + inflateReset(&stream); + + if (len > PAGE_CACHE_SIZE*2) { + die(FSCK_UNCORRECTED, 0, "data block too large"); + } + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + die(FSCK_UNCORRECTED, 0, "decompression error %p(%d): %s", + zError(err), src, len); + } + return stream.total_out; +} + +static void do_uncompress(char *path, int fd, unsigned long offset, unsigned long size) +{ + unsigned long curr = offset + 4 * ((size + PAGE_CACHE_SIZE - 1) / PAGE_CACHE_SIZE); + + do { + unsigned long out = PAGE_CACHE_SIZE; + unsigned long next = *(u32 *) romfs_read(offset); + + if (next > end_data) { + end_data = next; + } + + offset += 4; + if (curr == next) { + if (opt_verbose > 1) { + printf(" hole at %ld (%d)\n", curr, PAGE_CACHE_SIZE); + } + if (size < PAGE_CACHE_SIZE) + out = size; + memset(outbuffer, 0x00, out); + } + else { + if (opt_verbose > 1) { + printf(" uncompressing block at %ld to %ld (%ld)\n", curr, next, next - curr); + } + out = uncompress_block(romfs_read(curr), next - curr); + } + if (size >= PAGE_CACHE_SIZE) { + if (out != PAGE_CACHE_SIZE) { + die(FSCK_UNCORRECTED, 0, "non-block (%ld) bytes", out); + } + } else { + if (out != size) { + die(FSCK_UNCORRECTED, 0, "non-size (%ld vs %ld) bytes", out, size); + } + } + size -= out; + if (opt_extract) { + if (write(fd, outbuffer, out) < 0) { + die(FSCK_ERROR, 1, "write failed: %s", path); + } + } + curr = next; + } while (size); +} + +tatic void change_file_status(char *path, struct cramfs_inode *i) +{ + struct utimbuf epoch = { 0, 0 }; + + if (euid == 0) { + if (lchown(path, i->uid, i->gid) < 0) { + die(FSCK_ERROR, 1, "lchown failed: %s", path); + } + if (S_ISLNK(i->mode)) + return; + if ((S_ISUID | S_ISGID) & i->mode) { + if (chmod(path, i->mode) < 0) { + die(FSCK_ERROR, 1, "chown failed: %s", path); + } + } + } + if (S_ISLNK(i->mode)) + return; + if (utime(path, &epoch) < 0) { + die(FSCK_ERROR, 1, "utime failed: %s", path); + } +} + +static void do_directory(char *path, struct cramfs_inode *i) +{ + int pathlen = strlen(path); + int count = i->size; + unsigned long offset = i->offset << 2; + char *newpath = malloc(pathlen + 256); + + if (!newpath) { + die(FSCK_ERROR, 1, "malloc failed"); + } + if (offset == 0 && count != 0) { + die(FSCK_UNCORRECTED, 0, "directory inode has zero offset and non-zero size: %s", path); + } + if (offset != 0 && offset < start_dir) { + start_dir = offset; + } + /* TODO: Do we need to check end_dir for empty case? */ + memcpy(newpath, path, pathlen); + newpath[pathlen] = '/'; + pathlen++; + if (opt_verbose) { + print_node('d', i, path); + } + if (opt_extract) { + if (mkdir(path, i->mode) < 0) { + die(FSCK_ERROR, 1, "mkdir failed: %s", path); + } + change_file_status(path, i); + } + while (count > 0) { + struct cramfs_inode *child = iget(offset); + int size; + int newlen = child->namelen << 2; + + size = sizeof(struct cramfs_inode) + newlen; + count -= size; + + offset += sizeof(struct cramfs_inode); + + memcpy(newpath + pathlen, romfs_read(offset), newlen); + newpath[pathlen + newlen] = 0; + if (newlen == 0) { + die(FSCK_UNCORRECTED, 0, "filename length is zero"); + } + if ((pathlen + newlen) - strlen(newpath) > 3) { + die(FSCK_UNCORRECTED, 0, "bad filename length"); + } + expand_fs(newpath, child); + + offset += newlen; + + if (offset <= start_dir) { + die(FSCK_UNCORRECTED, 0, "bad inode offset"); + } + if (offset > end_dir) { + end_dir = offset; + } + iput(child); /* free(child) */ + } + free(newpath); +} + +void do_file(u8 *path, cramfs_inode *i) +{ + u32 offset = i->offset << 2; + if (offset == 0 && i->size != 0) + return /*null de taille non nulle */ + if (i->size == 0 && offset != 0) + return /*non null de taille nulle */ + if (offset != 0 && offset < start_data) + start_data = offset; + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, i->mode); + if (i->size) + do_uncompress(path, fd, offset, i->size); + close(fd); + change_file_status(path, i); +} + +void expand_fs(u8 *path, cramfs_inode *inode) +{ + if (S_ISDIR(inode->mode)) { + do_directory(path, inode); + } + else if (S_ISREG(inode->mode)) { + do_file(path, inode); + } + else if (S_ISLNK(inode->mode)) { + /*do_symlink(path, inode);*/ + } + else { + /*do_special_inode(path, inode);*/ + } +} + +/*******************************************************************************/ +/* Vérification d'une image cramfs */ +/* ERREURS : +/* 1=taille du super bloc trop petite */ +/* 2=pas de magic */ +/* 3=pas géré */ +/* 4=superbloc trop petit */ +/* 5=aucune fichier */ +/* 6=taille entrée des fichiers trop petite */ +/* 7=taille entrée des fichiers trop grande */ +/* 8=version de cramfs non supportée */ +/* 9=crc erroné */ + +u32 test_super(u8 *src, u32 length) { + super=(cramfs_super*)src; + start = 0xFF; + if (length < sizeof(cramfs_super)) { + return 1; + } + if (super->magic == CRAMFS_MAGIC) { + start = 0; + } + else if (length >= (PAD_SIZE + sizeof(super))) { + if (super->magic == CRAMFS_MAGIC) { + start = PAD_SIZE; + } + } + else + return 2; + if (super->flags & ~CRAMFS_SUPPORTED_FLAGS) + return 3; + if (super->size < PAGE_CACHE_SIZE) + return 4; + if (super->flags & CRAMFS_FLAG_FSID_VERSION_2) { + if (super->fsid.files == 0) + return 5; + if (length < super->size) + return 6; + else if (length > super->size) + return 7; + } + else + return 8; + u32 oldcrc=super->fsid.crc; + super->fsid.crc = crc32(0, 0, 0); + u32 newcrc=crc32(0,src+*start,super->size-*start); + super->fsid.crc = oldcrc; + if (newcrc!=oldcrc) + return 9; + return NULL; +} + + diff --git a/lib/math.c b/lib/math.c index be72d7f..0e6147d 100644 --- a/lib/math.c +++ b/lib/math.c @@ -5,6 +5,60 @@ #include "timer.h" #include "math.h" +/*******************************************************************************/ +/* Calcule un checksum 32 bits */ + +u32 crc32(u32 inCrc32, u8 *buf, u32 size) +{ + static const u32 crcTable[256] = { + 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535, + 0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD, + 0xE7B82D07,0x90BF1D91,0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D, + 0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC, + 0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,0x3B6E20C8,0x4C69105E,0xD56041E4, + 0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C, + 0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,0x26D930AC, + 0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F, + 0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB, + 0xB6662D3D,0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F, + 0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB, + 0x086D3D2D,0x91646C97,0xE6635C01,0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E, + 0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA, + 0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,0x4DB26158,0x3AB551CE, + 0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A, + 0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9, + 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409, + 0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81, + 0xB7BD5C3B,0xC0BA6CAD,0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739, + 0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8, + 0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,0xF00F9344,0x8708A3D2,0x1E01F268, + 0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0, + 0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,0xD6D6A3E8, + 0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B, + 0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF, + 0x4669BE79,0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703, + 0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7, + 0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A, + 0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE, + 0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,0x86D3D2D4,0xF1D4E242, + 0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6, + 0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45, + 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D, + 0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5, + 0x47B2CF7F,0x30B5FFE9,0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605, + 0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94, + 0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D }; + u32 crc32; + u8 *byteBuf; + u32 i; + crc32 = inCrc32 ^ 0xFFFFFFFF; + byteBuf = (u8*) buf; + for (i=0; i < size; i++) { + crc32 = (crc32 >> 8) ^ crcTable[ (crc32 ^ byteBuf[i]) & 0xFF ]; + } + return( crc32 ^ 0xFFFFFFFF ); +} + /*******************************************************************************/ /* Arithmétique 64 bits */ diff --git a/lib/memory.c b/lib/memory.c index 4f77372..4c0dda9 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -16,6 +16,7 @@ extern bootparams* allparams; /*******************************************************************************/ /* Erreur fatale */ + void panic(u8 * string) { printf("KERNEL PANIC: %s\r\nSysteme arrete...\n"); diff --git a/system/system.c b/system/system.c index 2852490..de89f62 100644 --- a/system/system.c +++ b/system/system.c @@ -17,6 +17,7 @@ #include "memory.h" #include "system.h" #include "boot.h" +#include "cramfs.h" static u8 warnmsg[] = "\033[150C\033[8D\033[37m\033[1m[ \033[36mNON\033[37m ]\033[0m"; @@ -28,6 +29,7 @@ static u8 key = 0; extern wrapper_timer; extern wrapper_interruption20; +extern u8* initrambloc; bootparams* allparams; @@ -63,10 +65,14 @@ void main(bootparams** params) print("\033[2J\r\n\000"); logo(); - print("\033[37m\033[0m -Initilisation de la memoire virtuelle"); + print("\033[37m\033[0m -Initialisation de la memoire virtuelle"); initgdt(&&next); next: - initpaging(*allparams); + initpaging(); + ok(); + + print("\033[37m\033[0m -Remapping de l'arborescence de demarrage et du VESA"); + remap_initram(); remap_memory(VESA_FBMEM); ok(); @@ -110,6 +116,10 @@ next: finit(); ok(); + printf(" -Initialisation de l'arborescence"); + test_super(initrambloc ,allparams->ramdisksize); + ok(); + retry: sti(); shell();