forked from Hyperion/HyperionOS
file permissions fixes
This commit is contained in:
@@ -111,43 +111,52 @@ local function makeMetafile(meta)
|
|||||||
return out
|
return out
|
||||||
end
|
end
|
||||||
|
|
||||||
local function validateComponent(part)
|
local SAFE_COMPONENT_PATTERN = "^[A-Za-z0-9_.+%-%@ %(%)%[%] ]+$"
|
||||||
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 "/"
|
||||||
if path:sub(1,1) ~= "/" then path = cwd .. "/" .. path end
|
|
||||||
local parts = {}
|
if path:sub(1, 1) ~= "/" then
|
||||||
for part in path:gmatch("[^/]+") do
|
path = cwd .. "/" .. path
|
||||||
if part == ".." then
|
end
|
||||||
if #parts > 0 then table.remove(parts) end
|
|
||||||
elseif part == "." or part == "" then
|
local stack = {}
|
||||||
|
local i = 1
|
||||||
|
local len = #path
|
||||||
|
while i <= len do
|
||||||
|
local j = path:find("/", i, true)
|
||||||
|
local comp
|
||||||
|
if j then
|
||||||
|
comp = path:sub(i, j - 1)
|
||||||
|
i = j + 1
|
||||||
else
|
else
|
||||||
validateComponent(part)
|
comp = path:sub(i)
|
||||||
table.insert(parts, part)
|
i = len + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if comp == "" or comp == "." then
|
||||||
|
elseif comp == ".." then
|
||||||
|
if #stack > 0 then
|
||||||
|
table.remove(stack)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if not comp:match(SAFE_COMPONENT_PATTERN) then
|
||||||
|
error("EINVAL: illegal characters in path component: " .. comp, 2)
|
||||||
|
end
|
||||||
|
table.insert(stack, comp)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local result = "/" .. table.concat(parts, "/")
|
|
||||||
|
local result = "/" .. table.concat(stack, "/")
|
||||||
|
|
||||||
local root = task and task.root
|
local root = task and task.root
|
||||||
if root and root ~= "/" then
|
if root and root ~= "/" then
|
||||||
if result ~= root and result:sub(1, #root + 1) ~= root .. "/" then
|
if result ~= root and result:sub(1, #root + 1) ~= root .. "/" then
|
||||||
result = root
|
result = root
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -29,14 +29,47 @@ local function makeEntry(name, etype, owner, group, perms, cmeta)
|
|||||||
.. string.char(#cmeta) .. cmeta
|
.. string.char(#cmeta) .. cmeta
|
||||||
end
|
end
|
||||||
|
|
||||||
local function writeMeta(dir, entries)
|
local REG = 0x00
|
||||||
|
|
||||||
|
local function mergeMeta(dir, entries)
|
||||||
local diskDir = dir
|
local diskDir = dir
|
||||||
if diskDir:sub(1,1) == "/" then diskDir = diskDir:sub(2) end
|
if diskDir:sub(1,1) == "/" then diskDir = diskDir:sub(2) end
|
||||||
local metaPath = (diskDir == "" and ".meta" or diskDir .. "/.meta")
|
local metaPath = (diskDir == "" and ".meta" or diskDir .. "/.meta")
|
||||||
|
|
||||||
local data = string.char(META_VERSION)
|
local existing = {}
|
||||||
|
local rok, rf = pcall(function() return rootDisk:open(metaPath, "r") end)
|
||||||
|
if rok and rf then
|
||||||
|
local raw = rf.read(65535)
|
||||||
|
if rf.close then rf.close() end
|
||||||
|
existing = (kernel.vfs._parseMetafile and kernel.vfs._parseMetafile(raw)) or {}
|
||||||
|
end
|
||||||
|
|
||||||
for _, e in ipairs(entries) do
|
for _, e in ipairs(entries) do
|
||||||
data = data .. makeEntry(e[1], e[2] or 0x00, e[3], e[4], e[5], e[6])
|
local name = e[1]
|
||||||
|
local etype = e[2] or REG
|
||||||
|
local owner = e[3] or 0
|
||||||
|
local group = e[4] or 0
|
||||||
|
local perms = e[5] or RWX_RX_RX
|
||||||
|
local cmeta = e[6] or ""
|
||||||
|
existing[name] = {
|
||||||
|
etype = etype,
|
||||||
|
owner = owner,
|
||||||
|
group = group,
|
||||||
|
perms = perms,
|
||||||
|
cmeta = cmeta,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local data = string.char(META_VERSION)
|
||||||
|
for name, m in pairs(existing) do
|
||||||
|
data = data .. makeEntry(
|
||||||
|
name,
|
||||||
|
m.etype or REG,
|
||||||
|
m.owner or 0,
|
||||||
|
m.group or 0,
|
||||||
|
m.perms or RWX_RX_RX,
|
||||||
|
m.cmeta or ""
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
local ok, err = pcall(function()
|
local ok, err = pcall(function()
|
||||||
@@ -49,10 +82,49 @@ local function writeMeta(dir, entries)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local REG = 0x00
|
kernel.log("Seeding filesystem permissions...", "INFO")
|
||||||
|
|
||||||
-- All known /bin entries with their permissions
|
mergeMeta("/", {
|
||||||
local BIN_ENTRIES = {
|
{"bin", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"boot", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"dev", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"etc", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"home", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"lib", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"root", REG, 0, 0, RW____ },
|
||||||
|
{"sbin", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"tmp", REG, 0, 0, RWXRWXRWX},
|
||||||
|
{"usr", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"var", REG, 0, 0, RWX_RX_RX},
|
||||||
|
})
|
||||||
|
|
||||||
|
mergeMeta("/boot", {
|
||||||
|
{"kernel.lua", REG, 0, 0, RW_R_R },
|
||||||
|
{"boot.cfg", REG, 0, 0, RW_R_R },
|
||||||
|
{"safeboot.cfg", REG, 0, 0, RW_R_R },
|
||||||
|
{"fstab", REG, 0, 0, RW_R_R },
|
||||||
|
{"initfs", REG, 0, 0, RW_R_R },
|
||||||
|
{"cct", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"oc", REG, 0, 0, RWX_RX_RX},
|
||||||
|
})
|
||||||
|
|
||||||
|
mergeMeta("/boot/cct", {
|
||||||
|
{"boot.lua", REG, 0, 0, RW_R_R},
|
||||||
|
{"initdisks", REG, 0, 0, RW_R_R},
|
||||||
|
{"eeprom", REG, 0, 0, RW_R_R},
|
||||||
|
})
|
||||||
|
|
||||||
|
mergeMeta("/boot/oc", {
|
||||||
|
{"boot.lua", REG, 0, 0, RW_R_R},
|
||||||
|
{"initfs.lua",REG, 0, 0, RW_R_R},
|
||||||
|
{"eeprom", REG, 0, 0, RW_R_R},
|
||||||
|
})
|
||||||
|
|
||||||
|
mergeMeta("/sbin", {
|
||||||
|
{"init.lua", REG, 0, 0, RWX_RX_RX},
|
||||||
|
})
|
||||||
|
|
||||||
|
mergeMeta("/bin", {
|
||||||
{"cat", REG, 0, 0, RWX_RX_RX},
|
{"cat", REG, 0, 0, RWX_RX_RX},
|
||||||
{"chattr", REG, 0, 0, RWX_RX_RX},
|
{"chattr", REG, 0, 0, RWX_RX_RX},
|
||||||
{"chgrp", REG, 0, 0, RWX_RX_RX},
|
{"chgrp", REG, 0, 0, RWX_RX_RX},
|
||||||
@@ -86,6 +158,7 @@ local BIN_ENTRIES = {
|
|||||||
{"sed", REG, 0, 0, RWX_RX_RX},
|
{"sed", REG, 0, 0, RWX_RX_RX},
|
||||||
{"socktest", REG, 0, 0, RWX_RX_RX},
|
{"socktest", REG, 0, 0, RWX_RX_RX},
|
||||||
{"spm", REG, 0, 0, RWX_RX_RX},
|
{"spm", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"startup", REG, 0, 0, RWX_RX_RX},
|
||||||
{"su", REG, 0, 0, SUID_755 },
|
{"su", REG, 0, 0, SUID_755 },
|
||||||
{"sudo", REG, 0, 0, SUID_755 },
|
{"sudo", REG, 0, 0, SUID_755 },
|
||||||
{"sysdump", REG, 0, 0, RWX_RX_RX},
|
{"sysdump", REG, 0, 0, RWX_RX_RX},
|
||||||
@@ -95,105 +168,13 @@ local BIN_ENTRIES = {
|
|||||||
{"usermod", REG, 0, 0, RWX_RX_RX},
|
{"usermod", REG, 0, 0, RWX_RX_RX},
|
||||||
{"whoami", REG, 0, 0, RWX_RX_RX},
|
{"whoami", REG, 0, 0, RWX_RX_RX},
|
||||||
{"yes", REG, 0, 0, RWX_RX_RX},
|
{"yes", REG, 0, 0, RWX_RX_RX},
|
||||||
{"startup", REG, 0, 0, RWX_RX_RX},
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Merge entries: always ensure all known entries exist with correct permissions.
|
|
||||||
-- This handles both fresh installs and upgrades (adds missing entries, upgrades
|
|
||||||
-- the on-disk format to v2 by rewriting).
|
|
||||||
local function mergeMeta(dir, entries)
|
|
||||||
local diskDir = dir
|
|
||||||
if diskDir:sub(1,1) == "/" then diskDir = diskDir:sub(2) end
|
|
||||||
local metaPath = (diskDir == "" and ".meta" or diskDir .. "/.meta")
|
|
||||||
|
|
||||||
-- Read existing meta (may be v1 or v2)
|
|
||||||
local existing = {}
|
|
||||||
local rok, rf = pcall(function() return rootDisk:open(metaPath, "r") end)
|
|
||||||
if rok and rf then
|
|
||||||
local raw = rf.read(65535)
|
|
||||||
if rf.close then rf.close() end
|
|
||||||
-- Parse using the VFS parser (handles v0/v1/v2)
|
|
||||||
existing = kernel.vfs and kernel.vfs._parseMetafile and kernel.vfs._parseMetafile(raw) or {}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Add any missing entries (don't overwrite existing customised perms)
|
|
||||||
for _, e in ipairs(entries) do
|
|
||||||
if not existing[e[1]] then
|
|
||||||
existing[e[1]] = {
|
|
||||||
etype = e[2] or 0x00,
|
|
||||||
owner = e[3] or 0,
|
|
||||||
group = e[4] or 0,
|
|
||||||
perms = e[5] or RWX_RX_RX,
|
|
||||||
cmeta = e[6] or "",
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Write back as v2
|
|
||||||
local data = string.char(META_VERSION)
|
|
||||||
for name, m in pairs(existing) do
|
|
||||||
data = data .. makeEntry(name, m.etype or 0x00, m.owner or 0, m.group or 0, m.perms or RWX_RX_RX, m.cmeta or "")
|
|
||||||
end
|
|
||||||
|
|
||||||
local ok, err = pcall(function()
|
|
||||||
local f = rootDisk:open(metaPath, "w")
|
|
||||||
f.write(data)
|
|
||||||
f.close()
|
|
||||||
end)
|
|
||||||
if not ok then
|
|
||||||
kernel.log("permissions: failed to write " .. metaPath .. ": " .. tostring(err), "WARN", 8)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local freshInstall = not rootDisk:fileExists(".meta")
|
|
||||||
|
|
||||||
if freshInstall then
|
|
||||||
kernel.log("Seeding filesystem permissions...", "INFO")
|
|
||||||
|
|
||||||
-- / (only on fresh install — these dirs are stable)
|
|
||||||
writeMeta("/", {
|
|
||||||
{"bin", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"boot", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"dev", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"etc", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"home", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"lib", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"root", REG, 0, 0, RW____ },
|
|
||||||
{"sbin", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"tmp", REG, 0, 0, RWXRWXRWX},
|
|
||||||
{"usr", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"var", REG, 0, 0, RWX_RX_RX},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
writeMeta("/bin/startup", {
|
mergeMeta("/bin/startup", {
|
||||||
{"test.lua", REG, 0, 0, RWX_RX_RX},
|
{"test.lua", REG, 0, 0, RWX_RX_RX},
|
||||||
})
|
})
|
||||||
|
|
||||||
writeMeta("/etc", {
|
mergeMeta("/lib", {
|
||||||
{"passwd", REG, 0, 0, RW_R_R},
|
|
||||||
{"shadow", REG, 0, 0, RW____},
|
|
||||||
{"pam.d", REG, 0, 0, RWX_RX_RX},
|
|
||||||
})
|
|
||||||
|
|
||||||
writeMeta("/etc/pam.d", {
|
|
||||||
{"secret", REG, 0, 0, RW____},
|
|
||||||
})
|
|
||||||
|
|
||||||
writeMeta("/sbin", {
|
|
||||||
{"init.lua", REG, 0, 0, RWX_RX_RX},
|
|
||||||
})
|
|
||||||
|
|
||||||
writeMeta("/boot", {
|
|
||||||
{"kernel.lua", REG, 0, 0, RW_R_R },
|
|
||||||
{"boot.cfg", REG, 0, 0, RW_R_R },
|
|
||||||
{"safeboot.cfg", REG, 0, 0, RW_R_R },
|
|
||||||
{"fstab", REG, 0, 0, RW_R_R },
|
|
||||||
{"initfs", REG, 0, 0, RW_R_R },
|
|
||||||
{"cct", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"oc", REG, 0, 0, RWX_RX_RX},
|
|
||||||
})
|
|
||||||
|
|
||||||
writeMeta("/lib", {
|
|
||||||
{"sys", REG, 0, 0, RWX_RX_RX},
|
{"sys", REG, 0, 0, RWX_RX_RX},
|
||||||
{"modules", REG, 0, 0, RWX_RX_RX},
|
{"modules", REG, 0, 0, RWX_RX_RX},
|
||||||
{"crypto", REG, 0, 0, RWX_RX_RX},
|
{"crypto", REG, 0, 0, RWX_RX_RX},
|
||||||
@@ -203,12 +184,50 @@ if freshInstall then
|
|||||||
{"bit32", REG, 0, 0, RW_R_R },
|
{"bit32", REG, 0, 0, RW_R_R },
|
||||||
})
|
})
|
||||||
|
|
||||||
|
mergeMeta("/lib/sys", {
|
||||||
|
{"fs", REG, 0, 0, RW_R_R},
|
||||||
|
{"hpv", REG, 0, 0, RW_R_R},
|
||||||
|
{"ipc", REG, 0, 0, RW_R_R},
|
||||||
|
{"term", REG, 0, 0, RW_R_R},
|
||||||
|
{"init", REG, 0, 0, RW_R_R},
|
||||||
|
})
|
||||||
|
|
||||||
|
mergeMeta("/lib/modules", {
|
||||||
|
{"Hyperion", REG, 0, 0, RWX_RX_RX},
|
||||||
|
})
|
||||||
|
|
||||||
|
mergeMeta("/lib/modules/Hyperion", {
|
||||||
|
{"01_stdlib.kmod", REG, 0, 0, RW_R_R},
|
||||||
|
{"10_vfs.kmod", REG, 0, 0, RW_R_R},
|
||||||
|
{"11_require.kmod", REG, 0, 0, RW_R_R},
|
||||||
|
{"12_devfs.kmod", REG, 0, 0, RW_R_R},
|
||||||
|
{"12_tmpfs.kmod", REG, 0, 0, RW_R_R},
|
||||||
|
{"13_loopdev.kmod", REG, 0, 0, RW_R_R},
|
||||||
|
{"14_keventd.kmod", REG, 0, 0, RW_R_R},
|
||||||
|
{"19_fstab.kmod", REG, 0, 0, RW_R_R},
|
||||||
|
{"20_signals.kmod", REG, 0, 0, RW_R_R},
|
||||||
|
{"20_socket.kmod", REG, 0, 0, RW_R_R},
|
||||||
|
{"26_tty.kmod", REG, 0, 0, RW_R_R},
|
||||||
|
{"30_userspace.kmod", REG, 0, 0, RW_R_R},
|
||||||
|
{"40_auth.kmod", REG, 0, 0, RW_R_R},
|
||||||
|
{"45_hypervisor.kmod", REG, 0, 0, RW_R_R},
|
||||||
|
{"47_dbg.kmod", REG, 0, 0, RW_R_R},
|
||||||
|
{"50_gpio.kmod", REG, 0, 0, RW_R_R},
|
||||||
|
{"70_stdlibadv.kmod", REG, 0, 0, RW_R_R},
|
||||||
|
{"90_init.kmod", REG, 0, 0, RW_R_R},
|
||||||
|
{"91_login.kmod", REG, 0, 0, RW_R_R},
|
||||||
|
{"92_permissions.kmod", REG, 0, 0, RW_R_R},
|
||||||
|
{"99_final.kmod", REG, 0, 0, RW_R_R},
|
||||||
|
})
|
||||||
|
|
||||||
|
mergeMeta("/etc", {
|
||||||
|
{"passwd", REG, 0, 0, RW_R_R },
|
||||||
|
{"shadow", REG, 0, 0, RW____ },
|
||||||
|
{"pam.d", REG, 0, 0, RWX_RX_RX},
|
||||||
|
})
|
||||||
|
|
||||||
|
mergeMeta("/etc/pam.d", {
|
||||||
|
{"secret", REG, 0, 0, RW____},
|
||||||
|
})
|
||||||
|
|
||||||
kernel.log("Filesystem permissions seeded.", "INFO")
|
kernel.log("Filesystem permissions seeded.", "INFO")
|
||||||
else
|
|
||||||
kernel.log("Permissions already seeded, merging /bin updates...", "INFO")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Always merge /bin — adds missing entries and upgrades format to v2
|
|
||||||
mergeMeta("/bin", BIN_ENTRIES)
|
|
||||||
|
|
||||||
kernel.log("Permission module loaded.", "INFO")
|
|
||||||
|
|||||||
Reference in New Issue
Block a user