Make the seccomp filter more restrictive :3

This commit is contained in:
Dpeta 2023-01-28 23:44:13 +01:00
parent 6c3d5dbb21
commit a4caa2065d
2 changed files with 112 additions and 87 deletions

View file

@ -1,7 +1,9 @@
"""
Applies a seccomp filter on Linux via libseccomp's Python bindings.
May have some security benefits, but since Python and Qt use many calls
and are pretty high-level, things are very prone to breaking.
Has some security benefits, but since Python and Qt use many calls
and are pretty high-level, things are prone to breaking.
Certain features like opening links almost always break.
Libseccomp's Python bindings aren't available on the pypi, check your distro's
package manager for python-libseccomp (Arch) or python3-seccomp (Debian).
@ -21,7 +23,11 @@ pesterchum_log = logging.getLogger("pchumLogger")
def activate_seccomp():
"""Sets the process into seccomp filter mode."""
if seccomp is None:
pesterchum_log.error("Failed to import seccomp.")
pesterchum_log.error(
"Failed to import seccomp, verify you have"
" python-libseccomp (Arch) or python3-seccomp (Debian) installed"
" and aren't running a pyinstaller build."
)
return
# Violation gives "Operation not permitted".
sec_filter = seccomp.SyscallFilter(defaction=seccomp.ERRNO(1))
@ -31,89 +37,76 @@ def activate_seccomp():
# Allow only UNIX and INET sockets, see the linux manual and source on socket for reference.
# Arg(0, seccomp.EQ, 1) means argument 0 must be equal to 1, 1 being the value of AF_UNIX.
sec_filter.add_rule(seccomp.ALLOW, "socket", seccomp.Arg(0, seccomp.EQ, 1)) # AF_UNIX
sec_filter.add_rule(seccomp.ALLOW, "socket", seccomp.Arg(0, seccomp.EQ, 2)) # AF_INET
# Allow AF_UNIX
sec_filter.add_rule(seccomp.ALLOW, "socket", seccomp.Arg(0, seccomp.EQ, 1))
# Allow AF_INET
sec_filter.add_rule(seccomp.ALLOW, "socket", seccomp.Arg(0, seccomp.EQ, 2))
# We can kill ourselves in case of skill issues but not others.
# Python/Qt might close itself via kill call in case of error.
sec_filter.add_rule(seccomp.ALLOW, "kill", seccomp.Arg(0, seccomp.EQ, os.getpid()))
sec_filter.add_rule(seccomp.ALLOW, "tgkill", seccomp.Arg(1, seccomp.EQ, threading.get_native_id()))
sec_filter.add_rule(
seccomp.ALLOW, "tgkill", seccomp.Arg(1, seccomp.EQ, threading.get_native_id())
)
# Allow openat as along as it's not in R+W mode.
# We can't really lock down open/openat further without breaking everything,
# even though it's one of the most important calls to lock down.
# Could probably allow breaking out of the sandbox in the case of full-on RCE/ACE.
sec_filter.add_rule(seccomp.ALLOW, "openat", seccomp.Arg(2, seccomp.NE, 2))
sec_filter.load()
def restrict_open():
# Allow only opening for reading/writing
sec_filter.add_rule(seccomp.ALLOW, "openat", seccomp.Arg(0, seccomp.EQ, os.getpid()))
# Required for Pesterchum to run.
# Required for Pesterchum to function normally.
# Pesterchum doesn't call most of these directly, there's a lot of abstraction with Python and Qt.
PCHUM_SYSTEM_CALLS = [
"access",
"bind",
"brk",
"clone3",
"close",
"connect",
"eventfd2",
"exit",
"exit_group",
"faccessat",
"faccessat2",
"fallocate",
"fcntl",
"fsync",
"ftruncate",
"futex",
"getcwd",
"getdents64",
"getegid",
"geteuid",
"getgid",
"getpeername",
"getpid",
"getrandom",
"getresgid",
"getresuid",
"getsockname",
"getsockopt",
"gettid",
"getuid",
"ioctl",
"lseek",
"memfd_create",
"mkdir",
"mmap",
"mprotect",
"munmap",
"newfstatat",
"openat",
"pipe2",
"poll",
"prctl",
"pselect6",
"pwrite64",
"read",
"recv",
"recvfrom",
"recvfrom",
"recvmmsg",
"recvmsg",
"restart_syscall",
"rseq",
"rt_sigaction",
"rt_sigprocmask",
"rt_sigreturn",
"sched_getaffinity",
"sched_getattr",
"sched_setattr",
"select",
"sendmmsg",
"sendmsg",
"sendto",
"setsockopt",
"shutdown",
"statx",
"umask",
"uname",
"write",
"access", # Files
"brk", # Required
"clone3", # Required
"close", # Sockets (Audio + Network)
"connect", # Sockets (Audio + Network)
"exit", # Exiting
"exit_group", # Exiting
"fallocate", # Qt
"fcntl", # Required (+ Audio)
"fsync", # Fsync log files
"ftruncate", # Required
"futex", # Required
"getcwd", # Get working directory
"getdents64", # Files? Required.
"getgid", # Audio
"getpeername", # Connect
"getpid", # Audio
"getrandom", # Malloc
"getsockname", # Required for sockets
"getsockopt", # Required for sockets
"getuid", # Audio
"ioctl", # Socket/Network
"lseek", # Files
"memfd_create", # Required (For Qt?)
"mkdir", # Gotta make folderz sometimez
"mmap", # Audio
"mprotect", # QThread::start
"munmap", # Required (segfault)
"newfstatat", # Required (Audio + Path?)
"pipe2", # Audio
"poll", # Required for literally everything
"pselect6", # Sockets/Network
"read", # It's read :3
"readlink", # Files
"recv", # Network
"recvfrom", # Network + DNS
"recvmsg", # Sockets (incl. Audio + Network)
"rseq", # Required
"rt_sigprocmask", # Required (segfault)
"select", # Useful for sockets
"sendmmsg", # Network
"sendmsg", # Sockets
"sendto", # Eternal eepy!! Sockets + required for waking up mainloop.
"setsockopt", # Audio
"statx", # File info
"uname", # Required
"write", # Required
]
"""
@ -130,6 +123,35 @@ EXTRA_CALLS = [
"open",
"time",
"listen",
]
# Required on launch
LAUNCH_CALLS = [
"prctl",
"faccessat",
"faccessat2",
"pwrite64",
]
# Required before full initialize
PRE_INITIALIZE_CALLS = [
"bind",
"eventfd2",
"getegid",
"geteuid",
"getresgid",
"getresuid",
"gettid",
"recvmmsg",
"restart_syscall",
"rt_sigaction",
"rt_sigreturn",
"sched_getaffinity",
"sched_getattr",
"sched_setattr",
"shutdown",
"umask",
]
# Required for opening links, but opening links still doesn't work anyway.
LINK_CALLS = [
"wait4", # for links?
"clone", # for links?
]

View file

@ -17,6 +17,7 @@ if os.path.dirname(sys.argv[0]):
import ostools
import nickservmsgs
import pytwmn
if ostools.isLinux():
import libseccomp
@ -113,8 +114,9 @@ if ostools.isLinux():
action="store_true",
help=(
"Restrict the system calls Pesterchum is allowed to make via seccomp."
" May have some security benefits, but since Python and Qt use many calls"
" and are pretty high-level, things are very prone to breaking."
" Has some security benefits, but since Python and Qt use many calls"
" and are pretty high-level, things are prone to breaking."
" Certain features like opening links always break."
" (Requires Linux and libseccomp's Python bindings, not available in frozen builds.)"
),
)
@ -1401,10 +1403,6 @@ class PesterWindow(MovingWindow):
self.honk = options["honk"]
else:
self.honk = True
# Activate seccomp if enabled
if "seccomp" in options:
if options["seccomp"]:
libseccomp.activate_seccomp()
self.modes = ""
self.sound_type = None
@ -1694,6 +1692,11 @@ class PesterWindow(MovingWindow):
self.sincerecv = 0 # Time since last recv
self.lastCheckPing = None
# Activate seccomp on Linux if enabled
if "seccomp" in options:
if options["seccomp"]:
libseccomp.activate_seccomp()
@QtCore.pyqtSlot(QString, QString)
def updateMsg(self, ver, url):
if not hasattr(self, "updatemenu"):
@ -4568,7 +4571,7 @@ class MainProgram(QtCore.QObject):
if ostools.isLinux():
if args.seccomp:
options["seccomp"] = True
except Exception as e:
print(e)
return options