1 Commits

Author SHA1 Message Date
7c1ee43b0a Update README
Goes for all branches.
2024-11-23 13:12:28 +01:00
4 changed files with 146 additions and 65 deletions

View File

@@ -1,6 +1,6 @@
""" """
Install script for the Python jailer. Install script for the Python jailer.
Version: 0.2.0-alpha1 Version: 1.0.0-main1
""" """
import os import os
import shutil import shutil
@@ -43,7 +43,7 @@ if setup_posix.lower() == "y":
with open("./lib64", "a+") as f: with open("./lib64", "a+") as f:
f.write("symlnk /usr/lib64/") f.write("symlnk /usr/lib64/")
f.close() f.close()
with open("./usr/bin/sh.py", "a+") as f: with open("./usr/bin/sh", "a+") as f:
f.write("symlnk /usr/bin/shell.py") f.write("symlnk /usr/bin/shell.py")
f.close() f.close()
os.mkdir("./sys") os.mkdir("./sys")
@@ -63,7 +63,7 @@ if setup_posix.lower() == "y":
f.write(usrname) f.write(usrname)
f.close() f.close()
with open("./sys/procinfo", "a+") as f: with open("./sys/procinfo", "a+") as f:
f.write("proc: vfs(/proc/)\nkernel: vfs(/proc/kcore)") f.write("proc: vfs(/proc/)\nmgr: vfs(/proc/kcore)")
f.close() f.close()
with open("./proc/kcore", "a+") as f: with open("./proc/kcore", "a+") as f:
f.write("/sys/jail_mgr.py") f.write("/sys/jail_mgr.py")
@@ -75,7 +75,6 @@ else:
os.mkdir("./usr") os.mkdir("./usr")
os.mkdir("./proc") os.mkdir("./proc")
os.mkdir(f"./home/{usrname}") os.mkdir(f"./home/{usrname}")
os.mkdir("./sys/krnl/")
print("Copying files...") print("Copying files...")
shutil.move("./main.py", "./sys/jail_mgr.py") shutil.move("./main.py", "./sys/jail_mgr.py")
shutil.move("./sh.py", "./bin/shell.py") shutil.move("./sh.py", "./bin/shell.py")
@@ -85,4 +84,4 @@ else:
f.write(usrname) f.write(usrname)
f.close() f.close()
print("Install completed! Run ./main.py to start the kernel!") print("Install completed! Run ./main.py to start the kernel!")
input("Press <Enter> to exit! ") input("Press <Enter> to exit! ")

View File

@@ -1 +1 @@
0.1.1-main1 0.2.0-main1

198
main.py
View File

@@ -1,58 +1,140 @@
""" """
This is a sort of OS built in Python, not bootable, but creates a custom directory structure and path definition. This is the PyJail, a jailing tool for running Python apps in a sandboxed environment.
This is the "kernel", it hosts all features and runs all programs. Version: 0.2.0-main1
For safety reasons the kernel is isolated, which means that with every shell instance, """
A new kernel instance will follow it. Same goes for every program, it will need to call upon a brand-new kernel instance. import os
Version: 0.1.1-nps3 import time
""" import runpy
import os
import runpy
class PyJail:
class PyJail: """
""" The
The "kernel" for PyNVOS """
""" def __init__(self, debug=False):
def __init__(self): self.rootpath = ""
self.rootpath = "" self.rootpath = self.fs()
self.rootpath = self.fs() self._debug = debug
with open(self.fs("/proc/klog"), "w") as f:
def run_program(self, path_to_bin): # Always use jailmgr.msg() from this point onwards.
""" f.write(f"[{time.time}] [jailmgr.__init__()] [INFO] START LOG")
Runs a specified program. f.close()
""" with open(self.fs("/proc/kproc"), "w") as f:
path_to_bin = self.fs(path_to_bin) f.write("proc: jailmgr(1)")
# print(path_to_bin) self._program_counter = 2
# print(str(self.rootpath) + str(path_to_bin)) f.close()
if path_to_bin == 3 or path_to_bin == 2: self._resolve_symlinks = False if os.path.isdir(self.fs("/bin")) else True
print("An error has occurred launching the program.")
else: def run_program(self, path_to_bin):
runpy.run_path(path_to_bin) """
Runs a specified program.
def fs(self, check_path=None) -> str: """
""" path_to_bin = self.fs(path_to_bin)
Keeps track of the jailed filesystem and makes sure any calls to any # print(path_to_bin)
file get done in the jailed filesystem # print(str(self.rootpath) + str(path_to_bin))
""" if path_to_bin == 3 or path_to_bin == 2:
if check_path is not None: self.msg("jailmgr.run_program()", "An error has occurred launching the program.", True,
if os.path.exists(f"{self.rootpath}{check_path}"): "WARNING")
if check_path.startswith("."): else:
check_path = check_path.lstrip(".") with open(self.fs("/proc/kproc"), "a+") as f:
return os.getcwd() + check_path if "vfs" in os.getcwd() else 2 f.write(f"proc: {path_to_bin}({self._program_counter})")
return self.rootpath + check_path self._program_counter += 1
elif self.rootpath in check_path: runpy.run_path(path_to_bin)
print("ERR: Cannot parse rootpath, expected vfspath")
return 3 def msg(self, caller: str, message:str, emit: bool = False, log_level: str = "INFO"):
else: """
# Path is not in the jailed fs, so we say it doesn't exist. The custom message parser, can parse messages and alert apps of said messages.
print("ERR: File/directory doesn't exist in vfspath") Replaces print statements.
return 2 Args:
else: caller: The program that called the logger
rootpath = os.getcwd() + "/vfs" message: Is the message to parse.
return rootpath emit: If the message needs to be passed to apps.
log_level: The loglevel, either DEBUG, INFO, WARNING, ERROR, CRITICAL
@staticmethod """
def is_posix_compatible() -> bool: if self._debug is True:
""" emit = True
Returns if the kernel is POSIX compatible. accepted_log_levels = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
""" if log_level.upper() not in accepted_log_levels:
return False self.msg(f"jailmgr.msg()",f"Not accepted loglevel!! {log_level}", False, "ERROR")
with open(self.fs("/proc/klog"), "a+") as f:
f.write(f"[{time.time}] [{caller}] [{log_level}] {message}")
if emit is True:
print(message)
return 0
def fs(self, check_path=None, resolve_symlinks=True):
"""
Keeps track of the jailed filesystem and makes sure any calls to any
file get done in the jailed filesystem
"""
if check_path is not None:
if os.path.exists(f"{self.rootpath}{check_path}"):
if self._resolve_symlinks is True or resolve_symlinks is True:
# This exists to ease /bin and other symlinks that are always present.
# It allows the system to drastically speed up resolving symlinks.
symlinkable_dirs = ["/bin", "/sbin", "/lib", "/lib64"]
for directory in symlinkable_dirs:
if check_path.startswith(directory):
check_path_usr_merge = f"/usr{check_path}"
return self.rootpath + check_path_usr_merge
# Well, if it doesn't start with any of them, we need to check each and every directory.
check_path_split = check_path.split("/", -1)
prepend_path = ""
for i, path in enumerate(check_path_split):
prepend_path = f"{prepend_path}/{path}" if not path.endswith("/") else f"{prepend_path}/{path}/"
check_path_split[i] = f"{prepend_path}"
check_path = ""
for i, path in enumerate(check_path_split):
if os.path.isdir(path) and i != (len(check_path_split) - 1):
# Directory is not a symlink, we can just ignore and move on.
pass
elif os.path.isdir(path) and i == (len(check_path_split) - 1):
# The last thing to access was a directory. We can safely return the full path now.
return path
elif not os.path.isdir(path) and i != (len(check_path_split) - 1):
# This was not the last thing we needed to access, so we assume it's a symlink.
# One problem is that we can't be sure, so we make sure it is a symlink.
with open(self.fs(path, False)) as f:
is_symlink = f.read()
f.close()
if is_symlink.startswith("symlnk"):
# This is a symlink!
# Symlinks always contain the full literal path that they need to access, so we can
# take that and do the same trick to split it and add the next things to it.
# raise NotImplementedError()
is_symlink_split = is_symlink.split(" ", 1)
symlink_dest = is_symlink_split[1]
symlink_dest = f"{symlink_dest}/{path}"
return symlink_dest
else:
# This is either not a symlink or an improperly configured one.
self.msg("jailmgr.fs()", "reached non-symlink file not at end of list",
False, "ERROR")
self.msg("jailmgr.fs()", "What was assumed to be a directory isn't a"
" directory nor a symlink! This might be because of a "
"typo or misconfigured symlink. The directory in question: "
f"{path}", True, "WARNING")
return 2
return self.rootpath + check_path
if check_path.startswith("."):
check_path = check_path.lstrip(".")
return os.getcwd() + check_path if "vfs" in os.getcwd() else 2
elif self.rootpath in check_path:
self.msg(f"jailmgr.fs()", "Cannot parse rootpath, expected vfspath", log_level="ERROR")
return 3
else:
# Path is not in the jailed fs, so we say it doesn't exist.
self.msg(f"jailmgr.fs()", "File/directory doesn't exist in vfspath", log_level="ERROR")
return 2
else:
rootpath = os.getcwd() + "/vfs"
self.msg("jailmgr.fs()", message=rootpath, log_level="INFO")
return rootpath
@staticmethod
def kver():
"""
Returns the jail manager version
"""
return "0.2.0-main1"

View File

@@ -1 +1 @@
0.1.0 0.2 build 0036