This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Dave-ee Jones's profile picture

Clear computer memory?

Started by Dave-ee Jones, 07 August 2017 - 04:49 AM
Dave-ee Jones #1
Posted 07 August 2017 - 06:49 AM
Was thinking of a way to defend yourself against malicious floppies in disk drives trying to bypass your computer's startup file, and I thought, well, what if whenever you called restart or caught "Ctrl + R" (as well as the shutdown methods) it just rebooted/shutdown a completely separate "layer" of the computer.

Let me explain - the reason you restart a computer (unmaliciously) is usually just to reset memory and have a clean boot / program start. So what if you made a program that catches reboot/shutdown sequences (Ctrl + R/S, os.shutdown(), os.reboot(), shell.run("reboot"), shell.run("shutdown") etc.) and just clears memory while starting a clean shell/startup program?

This would make it so the computer never actually restarts/shuts down without the server/game crashing or restarting, making it impossible for someone to bypass your startup program.

Just an idea, not sure if it's possible to reset RAM but you could maybe catch all the variables created in a base layer of your OS? Refer to this:

Potentially already thought of before, but I'll give it a go..

Multi-layer OS.
Granted, the one shown below is only two layers, but basically what happens is the OS has 2 (or more) coroutines running - one which runs background processes like timers (like the clock), more important key pressses (like ones that handle "Home", "Back", "Task Manager" etc.), change variables in the background as needed (even things as simple as changing UI colours). This layer will be the BASE. The next layer up can be the OS layer. This is what you see and what you can do. It handles all on-screen UI interaction and handles all the functions that you would expect from a UI.
You click on "Control Panel" you expect the Control Panel to open, where you can change user details, UI colours, system options etc.
You click on "Create a window" and you can create a second window that has DJShell running in it.

It just works, and works better than the one coroutine trying to handle everything at once. Most real OS' use the same technique, you just don't notice it as an end-user because it's not meant to be noticed - it's just meant to work.
Plus, you can have a more constant feel with the OS, accessing windows, taskbar or a specific key from ANYWHERE in the OS, not just where the OS is listening. Because of the BASE layer, the OS will ALWAYS be listening to certain commands, as long as it is running.



"Home", "Back", "Forward" and "Task Manager" can be described as something like Android's Home, Back and Running Processes buttons. These (being on CC) are bound to specific keys, which can be accessed from anywhere in the OS.

Pretty nifty idea, though I've never seen an OS that utilises this layer system enough.
Bomb Bloke #2
Posted 07 August 2017 - 08:35 AM
So what if you made a program that catches reboot/shutdown sequences (Ctrl + R/S, os.shutdown(), os.reboot(), shell.run("reboot"), shell.run("shutdown") etc.) and just clears memory while starting a clean shell/startup program?

Ctrl + R/S don't work in the manner you're thinking - you can't "detect" that they've been pressed.

There are a couple of other ways to protect the system startup process, though. Under CC1.77 or later you can set shell.allow_disk_startup to false, preventing overrides from external disk drives. Even prior to that, making your computer boot from a disk drive placed on top of it will ensure that any other drives connected will be ignored.

Of course, neither of these techniques are much good if people get physical access to your system, in which case there's nothing stopping them from placing your computer into a disk drive and simply doing what they like with it. Of course, there are other mods for dealing with that sort of problem.
The Crazy Phoenix #3
Posted 07 August 2017 - 08:02 PM
As Bomb Bloke has already pointed out, it is not possible to do that.

However, it is still possible to clear the RAM by manipulating the subprograms' environment table.


local mt = {__index = _G, __metatable = function() return nil end}
while true do
    local env = {}
    env._G = env
    setmetatable(env, mt)
    os.run(env, multishell and "/rom/programs/advanced/multishell" or "/rom/programs/shell")
end

That will reset the environment and restart the shell every time the shell is exited.
Dave-ee Jones #4
Posted 08 August 2017 - 12:42 AM
As Bomb Bloke has already pointed out, it is not possible to do that.

However, it is still possible to clear the RAM by manipulating the subprograms' environment table.


local mt = {__index = _G, __metatable = function() return nil end}
while true do
	local env = {}
	env._G = env
	setmetatable(env, mt)
	os.run(env, multishell and "/rom/programs/advanced/multishell" or "/rom/programs/shell")
end

That will reset the environment and restart the shell every time the shell is exited.

Yeah, that would work, but as you both say Ctrl + R/S is captured by the bios not by the events.

Even prior to that, making your computer boot from a disk drive placed on top of it will ensure that any other drives connected will be ignored.

Are you sure it's the top? I was told it was the bottom..Have to check it up. Thanks though!
Bomb Bloke #5
Posted 08 August 2017 - 02:48 AM
However, it is still possible to clear the RAM by manipulating the subprograms' environment table.

Creating a system that allows a full reset without a reboot would be much trickier. Function environments, as well as sub-tables within _G, won't reset that way.
The Crazy Phoenix #6
Posted 08 August 2017 - 11:09 AM
However, it is still possible to clear the RAM by manipulating the subprograms' environment table.

Creating a system that allows a full reset without a reboot would be much trickier. Function environments, as well as sub-tables within _G, won't reset that way.

Is there anything more than deep copying the global environment?


local env = {}
local tcp = {{_G, env}}
while #tcp > 0 do
	local current = tcp[#tcp]
	tcp[#tcp] = nil
	for key, value in pairs(current[1]) do
		if type(value) == "table" then
			tcp[#tcp + 1] = {value, current[2][key]}
		elseif type(value) == "function" then
			current[2][key] = function()
				_ENV = env
				value()
			end
			-- You can use setfenv but it will modify the original function.
		else
			current[2][key] =  value
		end
	end
end
Edited on 08 August 2017 - 12:06 PM
Bomb Bloke #7
Posted 08 August 2017 - 01:24 PM
You're missing a "current[2][key] = {}" as well as a check for recursion (see here for a copier I wrote just the other day, if that helps), and I suspect your function wrapper will break future attempts to setfenv things (not that anyone does that…), but no other issues are immediately obvious to me.
The Crazy Phoenix #8
Posted 08 August 2017 - 02:11 PM
I added a table that maps every table to its copy to fix the issue with the recursion. It should even work on indirect recursion ("a contains b and b contains a" instead of simply "a contains a").
The function wrapper is the only way of preventing people from changing the environment of the original function.
Perhaps load and string.dump might be the only way of fixing both issues.


local env = {}
local tcp = {{_G, env}}
local cpd = {[_G] = env}
while #tcp > 0 do
	local current = tcp[#tcp]
	tcp[#tcp] = nil
	for key, value in pairs(current[1]) do
		if type(value) == "table" then
			if cpd[value] then
				current[2][key] = cpd[value]
			else
				current[2][key] = {}
				tcp[#tcp + 1] = {value, current[2][key]}
				cpd[value] = current[2][key]
			end
		elseif type(value) == "function" then
			current[2][key] = function()
				_ENV = env
				value()
			end
			-- You can use setfenv but it will modify the original function.
		else
			current[2][key] =  value
		end
	end
end
Edited on 08 August 2017 - 12:13 PM