From 4aee41a5d6b38e817540d1686bb36c388e4a3e1f Mon Sep 17 00:00:00 2001 From: Marc Date: Tue, 14 Dec 2021 14:19:14 +0100 Subject: [PATCH] Support des modules a tester --- .vscode/settings.json | 3 - binding.gyp | 7 ++ build.sh | 4 - clibs.sh | 14 ++- clibs/chibrax/file.cc | 49 ++++++++++ clibs/chibrax/syscall.cc | 62 ++++++++++++- fakesh/fakesh.c | 2 +- kernel/from_current.sh | 7 +- rootfs overrides/chibrax/.gitignore | 3 +- rootfs overrides/chibrax/cfiles.js | 15 +++ rootfs overrides/chibrax/errno.js | 133 +++++++++++++++++++++++++++ rootfs overrides/chibrax/index.js | 2 +- rootfs overrides/chibrax/kernel.js | 68 ++++++++++++++ rootfs overrides/usr/bin/lsmod.js | 3 + rootfs overrides/usr/bin/modprobe.js | 3 + rootfs overrides/usr/bin/sheebr.js | 12 ++- startQemu.sh | 8 +- 17 files changed, 368 insertions(+), 27 deletions(-) create mode 100644 clibs/chibrax/file.cc create mode 100644 rootfs overrides/chibrax/cfiles.js create mode 100644 rootfs overrides/chibrax/errno.js create mode 100644 rootfs overrides/chibrax/kernel.js create mode 100644 rootfs overrides/usr/bin/lsmod.js create mode 100644 rootfs overrides/usr/bin/modprobe.js diff --git a/.vscode/settings.json b/.vscode/settings.json index 8797bb7..047b616 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,3 @@ { "python.linting.enabled": false, - "files.associations": { - "*.inc": "cpp" - } } \ No newline at end of file diff --git a/binding.gyp b/binding.gyp index 7439fbd..7f0a122 100644 --- a/binding.gyp +++ b/binding.gyp @@ -20,6 +20,13 @@ "sources": [ "clibs/chibrax/mount.cc" ] + }, + { + "target_name": "file", + 'cflags': [ '-Wall' ], + "sources": [ + "clibs/chibrax/file.cc" + ] } ] } \ No newline at end of file diff --git a/build.sh b/build.sh index 9f56e65..1499729 100755 --- a/build.sh +++ b/build.sh @@ -43,9 +43,6 @@ cd rootfs/usr ln -s lib lib64 cd - -#installation de grub -# coreutils = cat -#sudo pacstrap rootfs || exit 1 echo "construction de la libc" chmod +x ./libc/build.sh @@ -95,7 +92,6 @@ echo "done" echo "construction du kernel" cd kernel && ./from_current.sh && cd - -sudo cp kernel/src/vmlinuz rootfs/boot || exit 1 echo "done" echo "Cloning the firmware" diff --git a/clibs.sh b/clibs.sh index abc75ed..79f6420 100755 --- a/clibs.sh +++ b/clibs.sh @@ -1,10 +1,16 @@ #!/bin/bash +echo "building node-c hooks" node node_modules/node-gyp/bin/node-gyp.js configure -sudo node node_modules/node-gyp/bin/node-gyp.js build +node node_modules/node-gyp/bin/node-gyp.js build -echo "syscall" + +echo " syscall" cp build/Release/syscall.node rootfs\ overrides/chibrax/syscall.node -echo "ioctl" +echo " ioctl" cp build/Release/ioctl.node rootfs\ overrides/chibrax/ioctl.node -echo "mount" +echo " mount" cp build/Release/mount.node rootfs\ overrides/chibrax/mount.node +echo " file" +cp build/Release/file.node rootfs\ overrides/chibrax/file.node + +echo "done" \ No newline at end of file diff --git a/clibs/chibrax/file.cc b/clibs/chibrax/file.cc new file mode 100644 index 0000000..302447f --- /dev/null +++ b/clibs/chibrax/file.cc @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include + +#define nodeparam v8::FunctionCallbackInfo + +namespace fileNode { + void nodeOpen(const nodeparam& args) { + v8::Isolate* isolate = args.GetIsolate(); + + if (args.Length() < 2 || !args[0]->IsString() || !args[1]->IsUint32() || ( args.Length() == 3 && !( args[2]->IsUndefined() || args[2]->IsUint32()))) { + isolate->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(isolate, "Argument 1 must be a path, 2 must be a number").ToLocalChecked())); + return; + } + + v8::String::Utf8Value str(isolate, args[0]); + std::string path(*str); + int flags = args[1].As()->Value(); + + if(args.Length() == 3 && args[2]->IsUndefined()) { + mode_t mode = args[2].As()->Value(); + args.GetReturnValue().Set(open(path.c_str(), flags, mode)); + } else { + args.GetReturnValue().Set(open(path.c_str(), flags)); + } + } + + void nodeClose(const nodeparam& args) { + v8::Isolate* isolate = args.GetIsolate(); + + if (args.Length() < 1 || !args[0]->IsUint32()) { + isolate->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(isolate, "Argument 1 must be a file descriptor (number)").ToLocalChecked())); + return; + } + + close(args[1].As()->Value()); + } + + void Initialize(v8::Local exports) { + NODE_SET_METHOD(exports, "open", nodeOpen); + NODE_SET_METHOD(exports, "close", nodeClose); + } + + NODE_MODULE(file_api, Initialize) +} diff --git a/clibs/chibrax/syscall.cc b/clibs/chibrax/syscall.cc index caf2b3b..5b8ba3c 100644 --- a/clibs/chibrax/syscall.cc +++ b/clibs/chibrax/syscall.cc @@ -2,19 +2,71 @@ #include #include #include +#include +#include +#define returnjs(val) args.GetReturnValue().Set(val); namespace syscallNode { + void freeList(std::list &list) { + std::list::iterator it = list.begin(); + for(; it != list.end(); it++) { + delete *it; + } + } + void nodeSyscall(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); - if (!args[0]->IsNumber()) { - isolate->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(isolate, "Argument must be a number").ToLocalChecked())); + std::list memoryToClean; + + //les registres rdi, rsi, rdx ... + long int registers[args.Length()]; + + for(int i=0; i < args.Length(); i++) { + if(args[i]->IsNumber()) { + registers[i] = args[i].As()->Value(); + } else if(args[i]->IsString()) { + v8::String::Utf8Value argv8(isolate, args[i]); + std::string *argStr = new std::string(*argv8); + //un pointer c'est un u_int32_t donc sa deverais passer + registers[i] = (long int)argStr->c_str(); + memoryToClean.push_front(argStr); + } else { + freeList(memoryToClean); + //respond -1 is something went wrong + returnjs(-1); + return; + } + } + long int syscallReturnValue; + + switch(memoryToClean.size()) { + case 1: + syscallReturnValue = syscall(registers[0]); + return; + case 2: + syscallReturnValue = syscall(registers[0], registers[1]); + return; + case 3: + syscallReturnValue = syscall(registers[0], registers[1], registers[2]); + return; + case 4: + syscallReturnValue = syscall(registers[0], registers[1], registers[2], registers[3]); + return; + case 5: + syscallReturnValue = syscall(registers[0], registers[1], registers[2], registers[3], registers[4]); + return; + + default: + //unsuported length + returnjs(-2); return; } - long argsValue = args[0].As()->Value(); - syscall(argsValue); + freeList(memoryToClean); + if(syscallReturnValue = -1) { + returnjs(errno); + } } void nodeReboot(const v8::FunctionCallbackInfo& args) { diff --git a/fakesh/fakesh.c b/fakesh/fakesh.c index 7fa2f86..23f507b 100644 --- a/fakesh/fakesh.c +++ b/fakesh/fakesh.c @@ -13,7 +13,7 @@ int main(int argc, char const *argv[]) char * args[argc]; for(int i=1; i < argc; i++) args[i-1] = (char *)argv[i]; - + //args have to be null terminated args[argc - 1] = NULL; diff --git a/kernel/from_current.sh b/kernel/from_current.sh index f0f6adb..6946e7b 100755 --- a/kernel/from_current.sh +++ b/kernel/from_current.sh @@ -23,5 +23,10 @@ cd src #make mrproper cp ../.config .config make -j$(nproc) bzImage -cp arch/x86_64/boot/bzImage vmlinuz +make -j$(nproc) modules +sudo cp arch/x86_64/boot/bzImage ../../rootfs/boot/vmlinuz || exit 1 +sudo cp System.map ../../rootfs/boot/System.map || exit 1 + +DESTDIR=$(pwd)/../../rootfs +sudo make modules_install INSTALL_MOD_PATH=$(realpath $DESTDIR) || exit 1 cd - diff --git a/rootfs overrides/chibrax/.gitignore b/rootfs overrides/chibrax/.gitignore index dbf4f60..3018483 100644 --- a/rootfs overrides/chibrax/.gitignore +++ b/rootfs overrides/chibrax/.gitignore @@ -1,3 +1,4 @@ syscall.node ioctl.node -mount.node \ No newline at end of file +mount.node +file.node \ No newline at end of file diff --git a/rootfs overrides/chibrax/cfiles.js b/rootfs overrides/chibrax/cfiles.js new file mode 100644 index 0000000..bdb80bc --- /dev/null +++ b/rootfs overrides/chibrax/cfiles.js @@ -0,0 +1,15 @@ +//@ts-check +/** + * @type {{ open: (path: string, flags: number, mode?: number) => number, close: (fd: number) => void }} + */ +//@ts-expect-error +const cfiles = require('./file.node') + +const modes = { + O_ACCMODE: 3, + O_RDONLY: 0, + O_WRONLY: 1, + O_RDWR: 2 +} + +module.exports = { ...cfiles, modes } \ No newline at end of file diff --git a/rootfs overrides/chibrax/errno.js b/rootfs overrides/chibrax/errno.js new file mode 100644 index 0000000..cba57e1 --- /dev/null +++ b/rootfs overrides/chibrax/errno.js @@ -0,0 +1,133 @@ +//@ts-check +/** @type {{ [key: number]: string | undefined }} */ +module.exports = { + 1: "EPERM", //Operation not permitted + 2: "ENOENT", //No such file or directory + 3: "ESRCH", //No such process + 4: "EINTR", //Interrupted system call + 5: "EIO", //I/O error + 6: "ENXIO", //No such device or address + 7: "E2BIG", //Argument list too long + 8: "ENOEXEC", //Exec format error + 9: "EBADF", //Bad file number + 10: "ECHILD", //No child processes + 11: "EAGAIN", //Try again + 12: "ENOMEM", //Out of memory + 13: "EACCES", //Permission denied + 14: "EFAULT", //Bad address + 15: "ENOTBLK", //Block device required + 16: "EBUSY", //Device or resource busy + 17: "EEXIST", //File exists + 18: "EXDEV", //Cross-device link + 19: "ENODEV", //No such device + 20: "ENOTDIR", //Not a directory + 21: "EISDIR", //Is a directory + 22: "EINVAL", //Invalid argument + 23: "ENFILE", //File table overflow + 24: "EMFILE", //Too many open files + 25: "ENOTTY", //Not a typewriter + 26: "ETXTBSY", //Text file busy + 27: "EFBIG", //File too large + 28: "ENOSPC", //No space left on device + 29: "ESPIPE", //Illegal seek + 30: "EROFS", //Read-only file system + 31: "EMLINK", //Too many links + 32: "EPIPE", //Broken pipe + 33: "EDOM", //Math argument out of domain of func + 34: "ERANGE", //Math result not representable + 35: "EDEADLK", //Resource deadlock would occur + 36: "ENAMETOOLONG", //File name too long + 37: "ENOLCK", //No record locks available + 38: "ENOSYS", //Function not implemented + 39: "ENOTEMPTY", //Directory not empty + 40: "ELOOP", //Too many symbolic links encountered + 42: "ENOMSG", //No message of desired type + 43: "EIDRM", //Identifier removed + 44: "ECHRNG", //Channel number out of range + 45: "EL2NSYNC", //Level 2 not synchronized + 46: "EL3HLT", //Level 3 halted + 47: "EL3RST", //Level 3 reset + 48: "ELNRNG", //Link number out of range + 49: "EUNATCH", //Protocol driver not attached + 50: "ENOCSI", //No CSI structure available + 51: "EL2HLT", //Level 2 halted + 52: "EBADE", //Invalid exchange + 53: "EBADR", //Invalid request descriptor + 54: "EXFULL", //Exchange full + 55: "ENOANO", //No anode + 56: "EBADRQC", //Invalid request code + 57: "EBADSLT", //Invalid slot + 59: "EBFONT", //Bad font file format + 60: "ENOSTR", //Device not a stream + 61: "ENODATA", //No data available + 62: "ETIME", //Timer expired + 63: "ENOSR", //Out of streams resources + 64: "ENONET", //Machine is not on the network + 65: "ENOPKG", //Package not installed + 66: "EREMOTE", //Object is remote + 67: "ENOLINK", //Link has been severed + 68: "EADV", //Advertise error + 69: "ESRMNT", //Srmount error + 70: "ECOMM", //Communication error on send + 71: "EPROTO", //Protocol error + 72: "EMULTIHOP", //Multihop attempted + 73: "EDOTDOT", //RFS specific error + 74: "EBADMSG", //Not a data message + 75: "EOVERFLOW", //Value too large for defined data type + 76: "ENOTUNIQ", //Name not unique on network + 77: "EBADFD", //File descriptor in bad state + 78: "EREMCHG", //Remote address changed + 79: "ELIBACC", //Can not access a needed shared library + 80: "ELIBBAD", //Accessing a corrupted shared library + 81: "ELIBSCN", //lib section in a.out corrupted + 82: "ELIBMAX", //Attempting to link in too many shared libraries + 83: "ELIBEXEC", //Cannot exec a shared library directly + 84: "EILSEQ", //Illegal byte sequence + 85: "ERESTART", //Interrupted system call should be restarted + 86: "ESTRPIPE", //Streams pipe error + 87: "EUSERS", //Too many users + 88: "ENOTSOCK", //Socket operation on non-socket + 89: "EDESTADDRREQ", //Destination address required + 90: "EMSGSIZE", //Message too long + 91: "EPROTOTYPE", //Protocol wrong type for socket + 92: "ENOPROTOOPT", //Protocol not available + 93: "EPROTONOSUPPORT", //Protocol not supported + 94: "ESOCKTNOSUPPORT", //Socket type not supported + 95: "EOPNOTSUPP", //Operation not supported on transport endpoint + 96: "EPFNOSUPPORT", //Protocol family not supported + 97: "EAFNOSUPPORT", //Address family not supported by protocol + 98: "EADDRINUSE", //Address already in use + 99: "EADDRNOTAVAIL", //Cannot assign requested address + 100: "ENETDOWN", //Network is down + 101: "ENETUNREACH", //Network is unreachable + 102: "ENETRESET", //Network dropped connection because of reset + 103: "ECONNABORTED", //Software caused connection abort + 104: "ECONNRESET", //Connection reset by peer + 105: "ENOBUFS", //No buffer space available + 106: "EISCONN", //Transport endpoint is already connected + 107: "ENOTCONN", //Transport endpoint is not connected + 108: "ESHUTDOWN", //Cannot send after transport endpoint shutdown + 109: "ETOOMANYREFS", //Too many references: cannot splice + 110: "ETIMEDOUT", //Connection timed out + 111: "ECONNREFUSED", //Connection refused + 112: "EHOSTDOWN", //Host is down + 113: "EHOSTUNREACH", //No route to host + 114: "EALREADY", //Operation already in progress + 115: "EINPROGRESS", //Operation now in progress + 116: "ESTALE", //Stale NFS file handle + 117: "EUCLEAN", //Structure needs cleaning + 118: "ENOTNAM", //Not a XENIX named type file + 119: "ENAVAIL", //No XENIX semaphores available + 120: "EISNAM", //Is a named type file + 121: "EREMOTEIO", //Remote I/O error + 122: "EDQUOT", //Quota exceeded + 123: "ENOMEDIUM", //No medium found + 124: "EMEDIUMTYPE", //Wrong medium type + 125: "ECANCELED", //Operation Canceled + 126: "ENOKEY", //Required key not available + 127: "EKEYEXPIRED", //Key has expired + 128: "EKEYREVOKED", //Key has been revoked + 129: "EKEYREJECTED", //Key was rejected by service + 130: "EOWNERDEAD", //Owner died + 131: "ENOTRECOVERABLE", +} \ No newline at end of file diff --git a/rootfs overrides/chibrax/index.js b/rootfs overrides/chibrax/index.js index b0d7337..26ff3fb 100644 --- a/rootfs overrides/chibrax/index.js +++ b/rootfs overrides/chibrax/index.js @@ -38,7 +38,7 @@ async function main() { //chainload into sheebr await fHook("/usr/bin/sheebr.js") reboot.disableCtrlAltSupr() - //reboot.powerOff() + reboot.powerOff() console.log("End of init reached") reboot.enableCtrlAltSupr() diff --git a/rootfs overrides/chibrax/kernel.js b/rootfs overrides/chibrax/kernel.js new file mode 100644 index 0000000..034850b --- /dev/null +++ b/rootfs overrides/chibrax/kernel.js @@ -0,0 +1,68 @@ +//@ts-check +//@ts-expect-error +const { syscall } = require('./syscall.node') +const { close, open, modes } = require('./cfiles.js') +const errno = require('./errno') +const fs = require('fs') +const path = require('path') + + + +// TBD +const SYSCALL_INIT_MODULE = 105 +const SYSCALL_FINIT_MODULE = 273 + +const doProcExists = () => fs.existsSync('/proc') + +/** + * + * @param {string} path + * @param {string} params + * @param {number} flags + * @deprecated un tested dangerous + */ +function finit_module(path, params = "", flags = 0) { + const fileDescriptor = open(path, modes.O_RDONLY) + const result = syscall(SYSCALL_FINIT_MODULE, fileDescriptor, params, flags) + if(result > 0) { + //parse linux error + console.log(errno[result]) + } else { + if(result == -1) { + console.log('non number or string argument recived') + }else if(result == -2) { + console.log('unsuported argument length (1-5)') + } + } +} + +function uname() { + if(!doProcExists) { + throw "Proc don't exists exception" + } + const linuxVersionString = fs.readFileSync('/proc/version').toString() + return linuxVersionString.split(' ')[2] +} + +/** + * @param {string} modulename + */ +function modprobe(modulename) { + const name = uname() + if(fs.existsSync(path.join('/lib/modules', name, 'kernel', modulename))) { + finit_module(path.join('/lib/modules', name, 'kernel', modulename)) + } else { + console.log("file not found " + path.join('/lib/modules', name, 'kernel', modulename)) + //throw "file not found" + } +} + + +function lsmod() { + if(!doProcExists) { + throw "Proc don't exists exception" + } + return fs.readFileSync('/proc/modules').toString('utf-8').split('\n') +} + +module.exports = { modprobe, uname, finit_module, doProcExists, lsmod } \ No newline at end of file diff --git a/rootfs overrides/usr/bin/lsmod.js b/rootfs overrides/usr/bin/lsmod.js new file mode 100644 index 0000000..851904f --- /dev/null +++ b/rootfs overrides/usr/bin/lsmod.js @@ -0,0 +1,3 @@ +const { lsmod } = require('/chibrax/kernel.js') + +console.log(lsmod()) \ No newline at end of file diff --git a/rootfs overrides/usr/bin/modprobe.js b/rootfs overrides/usr/bin/modprobe.js new file mode 100644 index 0000000..7d0244b --- /dev/null +++ b/rootfs overrides/usr/bin/modprobe.js @@ -0,0 +1,3 @@ +const { modprobe } = require('/chibrax/kernel.js') +if(process.argv[3])modprobe(process.argv[3]) +else console.log("missing argument") \ No newline at end of file diff --git a/rootfs overrides/usr/bin/sheebr.js b/rootfs overrides/usr/bin/sheebr.js index 2a8d3ff..c9da2f4 100644 --- a/rootfs overrides/usr/bin/sheebr.js +++ b/rootfs overrides/usr/bin/sheebr.js @@ -64,10 +64,14 @@ function evaluateProgram(args){ const files = fs.readdirSync(path); if(files.includes(`${args[0]}.js`)){ found = true; - //@ts-expect-error - const script = execSync(`${environment.node} ${path + '/' + args[0]}.js ${args.map(arg => {return arg.includes(' ') ? `"${arg}"` : arg}).join(' ')}`, {cwd: current_dir, env: environment, shell: true}); - process.stdout.write(script) - tobreak = true; + try { + //@ts-expect-error + const script = execSync(`${environment.node} ${path + '/' + args[0]}.js ${args.map(arg => {return arg.includes(' ') ? `"${arg}"` : arg}).join(' ')}`, {cwd: current_dir, env: environment, shell: true}); + process.stdout.write(script) + tobreak = true; + } catch(e) { + console.log("Program crashed") + } } if(tobreak) break; diff --git a/startQemu.sh b/startQemu.sh index 1726b53..a23e1eb 100755 --- a/startQemu.sh +++ b/startQemu.sh @@ -1,14 +1,16 @@ echo "Attention sur linux le son est a zero par default dans le paneau de config" qemu-system-x86_64\ + -boot menu=on\ -machine type=q35,accel=kvm\ -enable-kvm\ -object rng-random,id=rng0,filename=/dev/urandom -device virtio-rng-pci,rng=rng0\ -cpu host\ -smp 2\ - -m 4G\ + -m 4G -device virtio-balloon\ -drive file=disk.img,format=raw\ - -net user\ -k fr\ -vga qxl\ -audiodev pa,id=hda,out.mixing-engine=on \ - -device intel-hda -device hda-output,audiodev=hda \ No newline at end of file + -device intel-hda -device hda-output,audiodev=hda \ + -netdev user,id=net0 \ + -device virtio-net-pci,netdev=net0