diff --git a/Src/Hyperion-bash/bin/hysh b/Src/Hyperion-bash/bin/hysh index a1bc15a..f7edf76 100644 --- a/Src/Hyperion-bash/bin/hysh +++ b/Src/Hyperion-bash/bin/hysh @@ -946,23 +946,16 @@ local function runCommand(command) return end - local text = fs.readAllText(cmdPath) - local program, err = load(text, progName) - if not program then - syscall.devctl(1,"sfgc",2) - local line, rest = tostring(err):match(":(%d+): (.+)$") - if line then printInline(progName..": load error on line "..line..": "); print(rest) - else print(progName..": load error: "..tostring(err)) end - syscall.devctl(1,"sfgc",1); return - end - - local proc = syscall.spawn(function(...) - syscall.open("/dev/tty/tty1","r") - syscall.open("/dev/tty/tty1","w") - syscall.open("/dev/null","w") - local ok2, msg = pcall(program, ...) - if not ok2 then printError(progName, msg) end - end, progName, nil, {table.unpack(args, 2)}) + local proc = syscall.spawn(function() + -- Open standard fds so programs that don't do it themselves work correctly. + syscall.open("/dev/tty/tty1", "r") -- fd 0 stdin + syscall.open("/dev/tty/tty1", "w") -- fd 1 stdout + syscall.open("/dev/null", "w") -- fd 2 stderr + -- exec replaces this coroutine's code with a fresh isolated environment + -- compiled from disk by the kernel (via loadExecutable -> freshUserEnv), + -- so the child cannot share any upvalue or syscall table state with hysh. + syscall.exec(cmdPath, {table.unpack(args, 2)}) + end, progName) while true do local exited, code = syscall.collect(proc) diff --git a/Src/Hyperion-kernel/boot/kernel.lua b/Src/Hyperion-kernel/boot/kernel.lua index 326b527..28a03ef 100644 --- a/Src/Hyperion-kernel/boot/kernel.lua +++ b/Src/Hyperion-kernel/boot/kernel.lua @@ -8,7 +8,7 @@ local computer = args[6] local ifs = args[7] local kernel = {} kernel.LOG_Text="" -kernel.version="HyperionOS V1.2.0" +kernel.version="HyperionOS V1.2.3" kernel.process = "Kernel" kernel.users={[0]="root",[1]="User"} kernel.hostname = "hyperion" diff --git a/Src/Hyperion-kernel/lib/modules/hyperion/01_stdlib.kmod b/Src/Hyperion-kernel/lib/modules/hyperion/01_stdlib.kmod index 5fa01c0..997a38f 100644 --- a/Src/Hyperion-kernel/lib/modules/hyperion/01_stdlib.kmod +++ b/Src/Hyperion-kernel/lib/modules/hyperion/01_stdlib.kmod @@ -207,17 +207,29 @@ function toHex(num) return string.format("%X", num) end -syscall = setmetatable({}, { - __index = function(self, name) - return function(...) - local res = table.pack(coroutine.yield("syscall", name, ...)) - if res[1] then - return table.unpack(res, 2, res.n) - else - error(res[2], 2) +local function makeSyscallProxy() + local backing = {} + return setmetatable(backing, { + __index = function(self, name) + local raw = rawget(self, name) + if raw ~= nil then return raw end + return function(...) + local res = table.pack(coroutine.yield("syscall", name, ...)) + if res[1] then + return table.unpack(res, 2, res.n) + else + error(res[2], 2) + end end - end - end -}) + end, + __newindex = function(self, k, v) + rawset(self, k, v) + end, + }) +end + +syscall = makeSyscallProxy() + +_makeSyscallProxy = makeSyscallProxy table.serialize = serialize diff --git a/Src/Hyperion-kernel/lib/modules/hyperion/26_tty.kmod b/Src/Hyperion-kernel/lib/modules/hyperion/26_tty.kmod index 0edd9ec..e2b3123 100644 --- a/Src/Hyperion-kernel/lib/modules/hyperion/26_tty.kmod +++ b/Src/Hyperion-kernel/lib/modules/hyperion/26_tty.kmod @@ -334,6 +334,13 @@ local function buildKeyMaps() end kernel.processes.cctmond = function() + local _getTasks = function() + local ret = {} + for _, v in pairs(kernel.tasks) do ret[#ret+1] = v.pid end + return ret + end + local _sigsend = kernel.signal.sigsend + local timeout = false while true do local event = {kernel.computer:getMachineEvent()} @@ -352,8 +359,8 @@ kernel.processes.cctmond = function() end if ctrl and charOrKey == apis.keys.c then - for _, task in ipairs(syscall.getTasks()) do - syscall.sigsend(task, 1) + for _, pid in ipairs(_getTasks()) do + _sigsend(pid, 1) end end diff --git a/Src/Hyperion-kernel/lib/modules/hyperion/30_userspace.kmod b/Src/Hyperion-kernel/lib/modules/hyperion/30_userspace.kmod index 2621138..4a12670 100644 --- a/Src/Hyperion-kernel/lib/modules/hyperion/30_userspace.kmod +++ b/Src/Hyperion-kernel/lib/modules/hyperion/30_userspace.kmod @@ -55,3 +55,18 @@ local origLoad = load kernel._U = readonly(kernel._G) kernel._U._G = kernel._U kernel._U.load = function(a,b,c,d) return origLoad(a,b,c,d or kernel._U) end + +function kernel.freshUserEnv() + local locals = {} + locals.syscall = _makeSyscallProxy() + + local env = setmetatable(locals, { + __index = kernel._U, + __newindex = function(_, k, v) rawset(locals, k, v) end, + }) + + locals._G = env + locals.load = function(a, b, c, d) return origLoad(a, b, c, d or env) end + + return env +end diff --git a/Src/Hyperion-kernel/lib/modules/hyperion/45_hypervisor.kmod b/Src/Hyperion-kernel/lib/modules/hyperion/45_hypervisor.kmod index c23be56..7f414e6 100644 --- a/Src/Hyperion-kernel/lib/modules/hyperion/45_hypervisor.kmod +++ b/Src/Hyperion-kernel/lib/modules/hyperion/45_hypervisor.kmod @@ -11,14 +11,16 @@ local function bit_is_set(num, bit) return math.floor(num / (2 ^ bit)) % 2 == 1 end -local function loadExecutable(path, env) +local function loadExecutable(path) kernel.vfs.access(path, "rx") local fd = kernel.vfs.open(path, "r") local data = kernel.vfs.read(fd, 1024 * 1024 * 4) kernel.vfs.close(fd) - local func, err = load(data, "@" .. path, "t", env or kernel._U) + local env = kernel.freshUserEnv() + + local func, err = load(data, "@" .. path, "t", env) if not func then error("ENOEXEC: " .. tostring(err)) end local meta = kernel.vfs.lstat(path) @@ -92,7 +94,7 @@ local function createTask(func, name, envars, args, tgid, real_uid, eff_uid) end function sys.spawn(func, name, envars, args, tgid) - local caller = kernel.currentTask + local caller = kernel.currentTask local real_uid = caller and caller.uid or kernel.uid local eff_uid = caller and caller.euid or real_uid return createTask(func, name, envars, args, tgid, real_uid, eff_uid) @@ -357,10 +359,25 @@ function kernel.main() if task.sigq and #task.sigq ~= 0 and task.sigh then local coro = coroutine.create(task.sigh) - if kernel.config.preempt then - resumeWithTimeout(coro, task.timeSlice, table.remove(task.sigq, 1)) - else - coroutine.resume(coro, table.remove(task.sigq, 1)) + local sigret = { coroutine.resume(coro, table.remove(task.sigq, 1)) } + while coroutine.status(coro) ~= "dead" do + if sigret[1] == false then break end + if sigret[2] == "syscall" then + local scname = sigret[3] + local sysret + if kernel.syscalls[scname] then + sysret = { xpcall(kernel.syscalls[scname], debug.traceback, table.unpack(sigret, 4)) } + else + sysret = { false, "Unknown syscall: " .. tostring(scname) } + end + if not sysret[1] then + sigret = { coroutine.resume(coro, false, sysret[2]) } + else + sigret = { coroutine.resume(coro, true, table.unpack(sysret, 2)) } + end + else + sigret = { coroutine.resume(coro) } + end end end diff --git a/Src/Hyperion-kernel/lib/modules/hyperion/91_login.kmod b/Src/Hyperion-kernel/lib/modules/hyperion/91_login.kmod index 621f94b..bc54e12 100644 --- a/Src/Hyperion-kernel/lib/modules/hyperion/91_login.kmod +++ b/Src/Hyperion-kernel/lib/modules/hyperion/91_login.kmod @@ -2,7 +2,7 @@ local kernel = ... kernel.processes.login = function() - local ok, err = pcall(syscall.execspawn, "/bin/login", "login") + local ok, err = pcall(kernel.hpv.execspawn, "/bin/login", "login") if not ok then kernel.log("Failed to exec /bin/login: " .. tostring(err), "ERROR", 2) end