summaryrefslogtreecommitdiff
path: root/Kernel
diff options
context:
space:
mode:
authorLiav A <liavalb@gmail.com>2022-12-23 13:51:47 +0200
committerBrian Gianforcaro <b.gianfo@gmail.com>2022-12-30 15:49:37 -0500
commite598f22768aa281dbf1f907f652472b3bc088271 (patch)
treec03f29b0ab0f880e27fbf03f040e70e867b80f1e /Kernel
parent0e010790a4f602a2b5a38514d607830d1c0df402 (diff)
downloadserenity-e598f22768aa281dbf1f907f652472b3bc088271.zip
Kernel: Disallow executing SUID binaries if process is jailed
Check if the process we are currently running is in a jail, and if that is the case, fail early with the EPERM error code. Also, as Brian noted, we should also disallow attaching to a jail in case of already running within a setid executable, as this leaves the user with false thinking of being secure (because you can't exec new setid binaries), but the current program is still marked setid, which means that at the very least we gained permissions while we didn't expect it, so let's block it.
Diffstat (limited to 'Kernel')
-rw-r--r--Kernel/Process.h1
-rw-r--r--Kernel/Syscalls/execve.cpp12
-rw-r--r--Kernel/Syscalls/jail.cpp11
3 files changed, 22 insertions, 2 deletions
diff --git a/Kernel/Process.h b/Kernel/Process.h
index bf9d2d0c0c..c897d4f962 100644
--- a/Kernel/Process.h
+++ b/Kernel/Process.h
@@ -118,6 +118,7 @@ class Process final
// FIXME: This should be a NonnullRefPtr
RefPtr<Credentials> credentials;
bool dumpable { false };
+ bool executable_is_setid { false };
Atomic<bool> has_promises { false };
Atomic<u32> promises { 0 };
Atomic<bool> has_execpromises { false };
diff --git a/Kernel/Syscalls/execve.cpp b/Kernel/Syscalls/execve.cpp
index d201b22616..4f1e06d149 100644
--- a/Kernel/Syscalls/execve.cpp
+++ b/Kernel/Syscalls/execve.cpp
@@ -472,6 +472,15 @@ ErrorOr<void> Process::do_exec(NonnullLockRefPtr<OpenFileDescription> main_progr
{
VERIFY(is_user_process());
VERIFY(!Processor::in_critical());
+ auto main_program_metadata = main_program_description->metadata();
+ // NOTE: Don't allow running SUID binaries at all if we are in a jail.
+ TRY(Process::current().jail().with([&](auto& my_jail) -> ErrorOr<void> {
+ if (my_jail && (main_program_metadata.is_setuid() || main_program_metadata.is_setgid())) {
+ return Error::from_errno(EPERM);
+ }
+ return {};
+ }));
+
// Although we *could* handle a pseudo_path here, trying to execute something that doesn't have
// a custody (e.g. BlockDevice or RandomDevice) is pretty suspicious anyway.
auto path = TRY(main_program_description->original_absolute_path());
@@ -507,8 +516,6 @@ ErrorOr<void> Process::do_exec(NonnullLockRefPtr<OpenFileDescription> main_progr
bool executable_is_setid = false;
if (!(main_program_description->custody()->mount_flags() & MS_NOSUID)) {
- auto main_program_metadata = main_program_description->metadata();
-
auto new_euid = old_credentials->euid();
auto new_egid = old_credentials->egid();
auto new_suid = old_credentials->suid();
@@ -551,6 +558,7 @@ ErrorOr<void> Process::do_exec(NonnullLockRefPtr<OpenFileDescription> main_progr
with_mutable_protected_data([&](auto& protected_data) {
protected_data.credentials = move(new_credentials);
protected_data.dumpable = !executable_is_setid;
+ protected_data.executable_is_setid = executable_is_setid;
});
// We make sure to enter the new address space before destroying the old one.
diff --git a/Kernel/Syscalls/jail.cpp b/Kernel/Syscalls/jail.cpp
index 68497bf515..0f5ac4e16c 100644
--- a/Kernel/Syscalls/jail.cpp
+++ b/Kernel/Syscalls/jail.cpp
@@ -45,6 +45,17 @@ ErrorOr<FlatPtr> Process::sys$jail_attach(Userspace<Syscall::SC_jail_attach_para
VERIFY_NO_PROCESS_BIG_LOCK(this);
TRY(require_promise(Pledge::jail));
+ // NOTE: Because the user might run a binary that is using this syscall and
+ // that binary was marked as SUID, then the user might be unaware of the
+ // fact that while no new setuid binaries might be executed, he is already
+ // running within such binary so for the sake of completeness and preventing
+ // naive sense of being secure, we should block that.
+ TRY(with_protected_data([&](auto& protected_data) -> ErrorOr<void> {
+ if (protected_data.executable_is_setid)
+ return EPERM;
+ return {};
+ }));
+
auto params = TRY(copy_typed_from_user(user_params));
return m_attached_jail.with([&](auto& my_jail) -> ErrorOr<FlatPtr> {
// Note: If we are already in a jail, don't let the process escape it even if