2 potential vulnerability fixes

This commit is contained in:
2026-02-23 23:26:21 -06:00
parent a6d2f6dca7
commit 8798a2f4fe
4 changed files with 26 additions and 23 deletions

View File

@@ -1,4 +1,7 @@
-- :Minify:-- -- :Minify:--
local kernel = ...
kernel.allowGlobalOverwrites = true
function string.hasSuffix(str, suffix) function string.hasSuffix(str, suffix)
return string.sub(str, #suffix + 1) == suffix return string.sub(str, #suffix + 1) == suffix
end end
@@ -68,30 +71,24 @@ end
local function serialize(tbl, seen) local function serialize(tbl, seen)
seen = seen or {} seen = seen or {}
-- If we've seen this table before, return a placeholder to prevent infinite loops
if seen[tbl] then return '"[Circular Reference]"' end if seen[tbl] then return '"[Circular Reference]"' end
-- Mark this table as seen
seen[tbl] = true seen[tbl] = true
local output = "{" local output = "{"
local first = true local first = true
for i, v in pairs(tbl) do for i, v in pairs(tbl) do
-- Handle comma placement more cleanly
if not first then output = output .. "," end if not first then output = output .. "," end
first = false first = false
-- Serialize Key
if type(i) == "string" then if type(i) == "string" then
output = output .. "[\"" .. i .. "\"]=" output = output .. "[\"" .. i .. "\"]="
elseif type(i) == "number" then elseif type(i) == "number" then
output = output .. "[" .. tostring(i) .. "]=" output = output .. "[" .. tostring(i) .. "]="
end end
-- Serialize Value
if type(v) == "table" then if type(v) == "table" then
-- Pass the 'seen' table down to the recursive call
output = output .. serialize(v, seen) output = output .. serialize(v, seen)
elseif type(v) == "string" then elseif type(v) == "string" then
output = output .. "[=[" .. v .. "]=]" output = output .. "[=[" .. v .. "]=]"

View File

@@ -60,21 +60,18 @@ local function parseMetafile(raw)
local etype, owner, group, perms, cmeta local etype, owner, group, perms, cmeta
if version == 0x02 then if version == 0x02 then
-- v2: etype(1) + owner(2) + group(2) + perms(2) = 7 bytes
if p + 6 > #raw then break end if p + 6 > #raw then break end
etype = raw:byte(p); p = p + 1 etype = raw:byte(p); p = p + 1
owner = raw:byte(p) + raw:byte(p+1) * 256; p = p + 2 owner = raw:byte(p) + raw:byte(p+1) * 256; p = p + 2
group = raw:byte(p) + raw:byte(p+1) * 256; p = p + 2 group = raw:byte(p) + raw:byte(p+1) * 256; p = p + 2
perms = raw:byte(p) + raw:byte(p+1) * 256; p = p + 2 perms = raw:byte(p) + raw:byte(p+1) * 256; p = p + 2
elseif version == 0x01 then elseif version == 0x01 then
-- v1: etype(1) + owner(1) + group(1) + perms(2) = 5 bytes
if p + 4 > #raw then break end if p + 4 > #raw then break end
etype = raw:byte(p); p = p + 1 etype = raw:byte(p); p = p + 1
owner = raw:byte(p); p = p + 1 owner = raw:byte(p); p = p + 1
group = raw:byte(p); p = p + 1 group = raw:byte(p); p = p + 1
perms = raw:byte(p) + raw:byte(p+1) * 256; p = p + 2 perms = raw:byte(p) + raw:byte(p+1) * 256; p = p + 2
else else
-- v0: owner(1) + group(1) + perms(1) = 3 bytes
if p + 2 > #raw then break end if p + 2 > #raw then break end
etype = 0x00 etype = 0x00
owner = raw:byte(p); p = p + 1 owner = raw:byte(p); p = p + 1
@@ -114,6 +111,22 @@ local function makeMetafile(meta)
return out return out
end end
local function validateComponent(part)
if part == "" then
error("EINVAL: empty path component", 2)
end
if part:sub(1, 2) == ".." then
error("EINVAL: illegal path component '" .. part .. "'", 2)
end
if part:find("\0", 1, true) then
error("EINVAL: null byte in path component", 2)
end
if part:find("/", 1, true) then
error("EINVAL: slash in path component", 2)
end
return true
end
local function normalizePath(path) local function normalizePath(path)
local task = kernel.currentTask local task = kernel.currentTask
local cwd = task.cwd or "/" local cwd = task.cwd or "/"
@@ -122,7 +135,9 @@ local function normalizePath(path)
for part in path:gmatch("[^/]+") do for part in path:gmatch("[^/]+") do
if part == ".." then if part == ".." then
if #parts > 0 then table.remove(parts) end if #parts > 0 then table.remove(parts) end
elseif part ~= "." and part ~= "" then elseif part == "." or part == "" then
else
validateComponent(part)
table.insert(parts, part) table.insert(parts, part)
end end
end end
@@ -164,7 +179,6 @@ local function resolveMount(normalPath)
return vfs.disks[mountId], diskPath return vfs.disks[mountId], diskPath
end end
-- Expose parser for use by other modules (e.g. permissions seeder)
vfs._parseMetafile = parseMetafile vfs._parseMetafile = parseMetafile
local function readMetaEntry(disk, parentDiskPath, filename) local function readMetaEntry(disk, parentDiskPath, filename)
@@ -181,7 +195,6 @@ local function readMetaEntry(disk, parentDiskPath, filename)
local raw = f.read(65535) local raw = f.read(65535)
if f.close then f.close() end if f.close then f.close() end
-- Auto-upgrade: if this .meta file is not v2, rewrite it as v2 now
if raw and #raw > 0 and raw:byte(1) ~= META_VERSION then if raw and #raw > 0 and raw:byte(1) ~= META_VERSION then
local upgraded = makeMetafile(parseMetafile(raw)) local upgraded = makeMetafile(parseMetafile(raw))
local wok, wf = pcall(function() return disk:open(mp, "w") end) local wok, wf = pcall(function() return disk:open(mp, "w") end)
@@ -440,7 +453,6 @@ function vfs.open(path, mode)
if type(handle) ~= "table" then error("ENFILE") end if type(handle) ~= "table" then error("ENFILE") end
end end
-- If this is a newly created file, stamp it with the creating user's ownership
if isNew then if isNew then
local euid = (task and (task.euid or task.uid)) or kernel.uid local euid = (task and (task.euid or task.uid)) or kernel.uid
local egid = (task and task.gid) or 0 local egid = (task and task.gid) or 0
@@ -629,7 +641,6 @@ function vfs.mkdir(path)
checkperms(parentMeta, "w") checkperms(parentMeta, "w")
local disk, diskPath = resolvePath(path) local disk, diskPath = resolvePath(path)
disk:makeDirectory(diskPath) disk:makeDirectory(diskPath)
-- Stamp the new directory with the creating user's ownership
local task = kernel.currentTask local task = kernel.currentTask
local euid = (task and (task.euid or task.uid)) or kernel.uid local euid = (task and (task.euid or task.uid)) or kernel.uid
local egid = (task and task.gid) or 0 local egid = (task and task.gid) or 0

View File

@@ -50,10 +50,8 @@ local function readonly(tbl)
__metatable = false __metatable = false
}) })
end end
--local origLoad = load local origLoad = load
kernel._U = readonly(kernel._G) kernel._U = readonly(kernel._G)
kernel.allowGlobalOverwrites = true
kernel._U._G = kernel._U kernel._U._G = kernel._U
--kernel._U.load = function(a,b,c,d) return origLoad(a,b,c,d or kernel._U) end kernel._U.load = function(a, b, c, d) return origLoad(a, b, c, d or kernel._U) end
kernel.allowGlobalOverwrites = false

View File

@@ -1,5 +1,2 @@
local args = {...} local kernel = ...
local kernel = args[1] kernel.allowGlobalOverwrites = false
local origLoad = load
--kernel._U.load = function(a,b,c,d) return origLoad(a,b,c,d or kernel._U) end