This is a read-only snapshot of the ComputerCraft forums,
taken in April 2020.
Simulating Root
Started by skwerlman, 19 March 2014 - 05:01 AMPosted 19 March 2014 - 06:01 AM
I basically want to trick an arbitrary program in an arbitrary path into thinking it is in the root folder when it is run through my program. I've thought about overriding the fs API, but I'm not sure how to proceed. Any advice?
Posted 19 March 2014 - 07:30 AM
Something like this should do the trick.
Edit: realized it would mess up fs.open. Fixed it.
local newPath = "/fakeroot/"
local overrideFs= {}
for k,v in pairs _G.fs do
overrideFs[k] = function(...)
local args = {...}
for i=1,#args do
if k == "open" and i ~= 2 then
args[i] = newPath..args[i]
end
end
return v(unpack(args))
end
end
setmetatable(getfenv(), {
__index = function(t,k)
if k == "fs" then
return overrideFs
end
return _G[k]
end
})
What im doing here is overriding every fs function, with a new function which adds the newPath to every argument and then calls the original function. Then i set the index metamethod to use the override table if fs is called. This is something i just put together on my phone, so i can't guarantee it'll work though :P/>/>Edit: realized it would mess up fs.open. Fixed it.
Edited on 19 March 2014 - 08:45 AM
Posted 19 March 2014 - 07:34 AM
So if someone calls fs.open("/file") it'll actually open "/fakeroot/file"?
Edited on 19 March 2014 - 06:35 AM
Posted 19 March 2014 - 07:39 AM
Yeah pretty much. If you want to load a program with this without changing it's code, you can replace the getfenv with a loadfile. setmetatable should return the function to call the code with the override implemented.
Posted 19 March 2014 - 07:44 AM
Well, first there was a typo in your code, but when I fixed that and ran it as wrappedFS.lua I got:
Wait, nvm, I did something wrong.
wrappedFS.lua:18: vm error:
java.lang.ArrayIndexOutOfBoundsException
I assume that's unintended?Wait, nvm, I did something wrong.
Edited on 19 March 2014 - 06:47 AM
Posted 19 March 2014 - 07:52 AM
I suppose running it on the global environment might cause some issues, try using it on a loaded program or something.
Edit: typing on my phone is so slow lol, just saw your edit.
setmetatable(loadfile"/fileName",
__index = function(t,k)
if k == "fs" then
return overrideFs[k]
elseif _G[k] and k ~= "_G" then
return _G[k]
end
end
})()
I made a small change that might help aswell.Edit: typing on my phone is so slow lol, just saw your edit.
Edited on 19 March 2014 - 06:53 AM
Posted 19 March 2014 - 07:54 AM
To anyone else who is trying this and wants to completely 'fool' the program I've found that mimicking the fs API is not sufficient. You'll also need to mimic APIs such as io, paintutils (loadImage), os (loadAPI), loadfile, etc. OneOS does this, if you want to take a look at it check out this file.
Edited on 19 March 2014 - 06:55 AM
Posted 19 March 2014 - 08:16 AM
I'll see if I can come up with a way to recursively run CometWolf's routine on every CC API. Then I'll never have to update unless they add a new hardcoded API.
Posted 19 March 2014 - 08:22 AM
I'll see if I can come up with a way to recursively run CometWolf's routine on every CC API. Then I'll never have to update unless they add a new hardcoded API.
Yes, I'd be interested to see if you can, that will prevent the need to manually update OneOS every time APIs are changed or added.
Posted 19 March 2014 - 09:14 AM
why not just do it based on the list taken from fs.list(/rom/apis/) if you change the pointer to the FS API in all those to point to the new FS API then you'd be good.Yes, I'd be interested to see if you can, that will prevent the need to manually update OneOS every time APIs are changed or added.I'll see if I can come up with a way to recursively run CometWolf's routine on every CC API. Then I'll never have to update unless they add a new hardcoded API.
Posted 19 March 2014 - 09:19 AM
This would change fs globally, but it would do what you want.
for k,v in pairs(_G) do
if type(v) == "table" then
setmetatable(v,
{
__index = function(t2,k2)
if k2 == "fs" then
return overrideFs[k2]
end
return _G[k2]
end
}
)
end
end
I can take a shot at sandboxing this when im not on my phone :P/>Posted 19 March 2014 - 09:32 AM
Would it though? I found that the API's FS wouldn't change.why not just do it based on the list taken from fs.list(/rom/apis/) if you change the pointer to the FS API in all those to point to the new FS API then you'd be good.Yes, I'd be interested to see if you can, that will prevent the need to manually update OneOS every time APIs are changed or added.I'll see if I can come up with a way to recursively run CometWolf's routine on every CC API. Then I'll never have to update unless they add a new hardcoded API.
Posted 19 March 2014 - 09:35 AM
Would it though? I found that the API's FS wouldn't change.why not just do it based on the list taken from fs.list(/rom/apis/) if you change the pointer to the FS API in all those to point to the new FS API then you'd be good.Yes, I'd be interested to see if you can, that will prevent the need to manually update OneOS every time APIs are changed or added.I'll see if I can come up with a way to recursively run CometWolf's routine on every CC API. Then I'll never have to update unless they add a new hardcoded API.
originalbit came up with an os.loadAPI replacement that would let you pass references of APIs to the loaded API. I use it in LuaGRUB's startup file.
EDIT: I got this far:
local newRoot = "/t/"
local apiDir = '/rom/apis/'
local tAPI = fs.list(apiDir)
local oldFS = fs
for n,e in ipairs(tAPI) do
if not oldFS.isDir(apiDir..e) then
print('Unloading '..e)
os.unloadAPI(apiDir..e)
end
end
function loadAPI(path)
local name = string.match(oldFS.getName(path), '(%a+)%.?.-')
local env = setmetatable({fs = overrideFs, os = overrideOs}, { __index = _G }) -- passes a ref of the shell api to the loaded api
local func, err = loadfile(path)
if not func then
return false, printError(err)
end
setfenv(func, env)
func()
local api = {}
for k,v in pairs(env) do
api[k] = v
end
_G[name] = api
return true
end
local overrideFs= {}
for k,v in ipairs(_G.fs) do
overrideFs[k] = function(...)
local args = {...}
for i=1,#args do
if not (k == "open" and i == 2) then
args[i] = newRoot..args[i]
end
end
return v(unpack(args))
end
end
local overrideOs= {}
for k,v in ipairs(_G.os) do
overrideOs[k] = function(...)
local args = {...}
for i=1,#args do
if k == "loadAPI" or k == "unloadAPI" then
args[i] = newRoot..args[i]
end
end
return v(unpack(args))
end
end
setmetatable(getfenv(0), {
__index = function(t,k)
if k ~= "_G" then
if k == "fs" then
return overrideFs[k]
elseif k == "os" then
return overrideOs[k]
elseif _G[k] then
return _G[k]
end
end
end
})
for n,e in ipairs(tAPI) do
if not oldFS.isDir(apiDir..e) then
print('Loading '..e)
loadAPI(apiDir..e)
end
end
shell.run('ls') -- in here to make sure shell.isDir() functions properly
The issue now is that every time I run it, I get a vm error at line 64 'java.lang.ArrayIndexOutOfBoundsException' when loading the colors API.If I could fix that, I think we'd be overriding every API that uses the filesystem. (And then some)
Edited on 19 March 2014 - 10:12 AM
Posted 19 March 2014 - 11:28 AM
Don't forget, if they pass the path ".." They're back in the root
Posted 19 March 2014 - 11:32 AM
Good point. But I might leave that up to OS authors. They may want a root mode, and it's not really my place to restrict them. I may find a way to require a password, though.Don't forget, if they pass the path ".." They're back in the root
Posted 19 March 2014 - 11:58 AM
Tip: GitHub repo apemanzilla/ApeOs, then navigate to /system/apis/safe_FS.luaGood point. But I might leave that up to OS authors. They may want a root mode, and it's not really my place to restrict them. I may find a way to require a password, though.Don't forget, if they pass the path ".." They're back in the root
Should give you a pretty well sandboxed fs API. (It also include io.open :P/>)
Edited on 19 March 2014 - 10:59 AM
Posted 19 March 2014 - 12:57 PM
I looked at how it's implemented, but it doesn't look like it overrides fs. Do you do that elsewhere?Tip: GitHub repo apemanzilla/ApeOs, then navigate to /system/apis/safe_FS.luaGood point. But I might leave that up to OS authors. They may want a root mode, and it's not really my place to restrict them. I may find a way to require a password, though.Don't forget, if they pass the path ".." They're back in the root
Should give you a pretty well sandboxed fs API. (It also include io.open :P/>)
Posted 19 March 2014 - 01:06 PM
Good point. But I might leave that up to OS authors. They may want a root mode, and it's not really my place to restrict them. I may find a way to require a password, though.Don't forget, if they pass the path ".." They're back in the root
local path = root..shell.resolve(filePath)
filePath can contain as many .. as they want, or any forwards slashes or anything, but they're not getting anywhere with it.the best thing about shell.resolve is that the file does not need to exist for the file path to be sanitised :)/>
Posted 19 March 2014 - 01:14 PM
I tested his hypothesis, and this worked:Good point. But I might leave that up to OS authors. They may want a root mode, and it's not really my place to restrict them. I may find a way to require a password, though.Don't forget, if they pass the path ".." They're back in the rootfilePath can contain as many .. as they want, or any forwards slashes or anything, but they're not getting anywhere with it.local path = root..shell.resolve(filePath)
the best thing about shell.resolve is that the file does not need to exist for the file path to be sanitised :)/>
> test2
> cd ..
..> ls
rom
test test2
..>
Posted 19 March 2014 - 01:40 PM
what?I tested his hypothesis, and this worked:> test2 > cd .. ..> ls rom test test2 ..>
Posted 19 March 2014 - 01:58 PM
I was able to cd into '..', or root, in this case.what?I tested his hypothesis, and this worked:> test2 > cd .. ..> ls rom test test2 ..>
There was nothing preventing me from doing so.
Posted 19 March 2014 - 02:06 PM
after having implemented the code that I suggested?I was able to cd into '..', or root, in this case.
There was nothing preventing me from doing so.
Posted 19 March 2014 - 03:10 PM
Why don't you just use fs.combine(root,fs.combine("",path))? Yes, I know it looks ugly but it should work fine.
Posted 19 March 2014 - 07:30 PM
Yeah, since I'm on Linux, '..' is actually a symlink to the parent directory. On windows however, it's a special case handled by cd, so I think your code would work there, but since it's an actual directory on my fs, the only way to sanitize it correctly would be to check for and replace absolute paths equal to '/..'after having implemented the code that I suggested?I was able to cd into '..', or root, in this case.
There was nothing preventing me from doing so.
Posted 19 March 2014 - 10:43 PM
I'm on OSX I know what '..' is and its handled the same way as it is in Linux ('cause both are Unix). I performed tests and it worked perfectly fine for me. could I possibly get a copy of the code you used to test?Yeah, since I'm on Linux, '..' is actually a symlink to the parent directory. On windows however, it's a special case handled by cd, so I think your code would work there, but since it's an actual directory on my fs, the only way to sanitize it correctly would be to check for and replace absolute paths equal to '/..'
Posted 20 March 2014 - 12:39 AM
Unfortunately, I've been overhauling my code, and I don't think the version that gave me that result exists.I'm on OSX I know what '..' is and its handled the same way as it is in Linux ('cause both are Unix). I performed tests and it worked perfectly fine for me. could I possibly get a copy of the code you used to test?Yeah, since I'm on Linux, '..' is actually a symlink to the parent directory. On windows however, it's a special case handled by cd, so I think your code would work there, but since it's an actual directory on my fs, the only way to sanitize it correctly would be to check for and replace absolute paths equal to '/..'
Posted 20 March 2014 - 03:32 AM
*Facepalm*Unfortunately, I've been overhauling my code, and I don't think the version that gave me that result exists.I'm on OSX I know what '..' is and its handled the same way as it is in Linux ('cause both are Unix). I performed tests and it worked perfectly fine for me. could I possibly get a copy of the code you used to test?Yeah, since I'm on Linux, '..' is actually a symlink to the parent directory. On windows however, it's a special case handled by cd, so I think your code would work there, but since it's an actual directory on my fs, the only way to sanitize it correctly would be to check for and replace absolute paths equal to '/..'