mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 20:27:35 +00:00
Kernel: Enable SMAP protection during the execve() syscall
The userspace execve() wrapper now measures all the strings and puts them in a neat and tidy structure on the stack. This way we know exactly how much to copy in the kernel, and we don't have to use the SMAP-violating validate_read_str(). :^)
This commit is contained in:
parent
bf9f36bf22
commit
952bb95baa
4 changed files with 78 additions and 38 deletions
|
@ -909,50 +909,49 @@ int Process::exec(String path, Vector<String> arguments, Vector<String> environm
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Process::sys$execve(const char* filename, const char** argv, const char** envp)
|
int Process::sys$execve(const Syscall::SC_execve_params* user_params)
|
||||||
{
|
{
|
||||||
SmapDisabler disabler;
|
|
||||||
// NOTE: Be extremely careful with allocating any kernel memory in exec().
|
// NOTE: Be extremely careful with allocating any kernel memory in exec().
|
||||||
// On success, the kernel stack will be lost.
|
// On success, the kernel stack will be lost.
|
||||||
if (!validate_read_str(filename))
|
Syscall::SC_execve_params params;
|
||||||
|
if (!validate_read_typed(user_params))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (!*filename)
|
copy_from_user(¶ms, user_params, sizeof(params));
|
||||||
|
|
||||||
|
if (params.arguments.length > ARG_MAX || params.environment.length > ARG_MAX)
|
||||||
|
return -E2BIG;
|
||||||
|
|
||||||
|
if (!validate_read(params.path.characters, params.path.length))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (params.path.length == 0)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
if (argv) {
|
|
||||||
if (!validate_read_typed(argv))
|
|
||||||
return -EFAULT;
|
|
||||||
for (size_t i = 0; argv[i]; ++i) {
|
|
||||||
if (!validate_read_str(argv[i]))
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (envp) {
|
|
||||||
if (!validate_read_typed(envp))
|
|
||||||
return -EFAULT;
|
|
||||||
for (size_t i = 0; envp[i]; ++i) {
|
|
||||||
if (!validate_read_str(envp[i]))
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String path(filename);
|
auto copy_user_strings = [&](const auto& list, auto& output) {
|
||||||
|
if (!list.length)
|
||||||
|
return true;
|
||||||
|
if (!validate_read_typed(list.strings, list.length))
|
||||||
|
return false;
|
||||||
|
Vector<Syscall::SyscallString, 32> strings;
|
||||||
|
strings.resize(list.length);
|
||||||
|
copy_from_user(strings.data(), list.strings, list.length * sizeof(Syscall::SyscallString));
|
||||||
|
for (size_t i = 0; i < list.length; ++i) {
|
||||||
|
if (!validate_read(strings[i].characters, strings[i].length))
|
||||||
|
return false;
|
||||||
|
output.append(copy_string_from_user(strings[i].characters, strings[i].length));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
Vector<String> arguments;
|
Vector<String> arguments;
|
||||||
Vector<String> environment;
|
if (!copy_user_strings(params.arguments, arguments))
|
||||||
{
|
return -EFAULT;
|
||||||
auto parts = path.split('/');
|
|
||||||
if (argv) {
|
|
||||||
for (size_t i = 0; argv[i]; ++i) {
|
|
||||||
arguments.append(argv[i]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
arguments.append(parts.last());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (envp) {
|
Vector<String> environment;
|
||||||
for (size_t i = 0; envp[i]; ++i)
|
if (!copy_user_strings(params.environment, environment))
|
||||||
environment.append(envp[i]);
|
return -EFAULT;
|
||||||
}
|
|
||||||
}
|
auto path = copy_string_from_user(params.path.characters, params.path.length);
|
||||||
|
|
||||||
int rc = exec(move(path), move(arguments), move(environment));
|
int rc = exec(move(path), move(arguments), move(environment));
|
||||||
ASSERT(rc < 0); // We should never continue after a successful exec!
|
ASSERT(rc < 0); // We should never continue after a successful exec!
|
||||||
|
|
|
@ -155,7 +155,7 @@ public:
|
||||||
int sys$ttyname_r(int fd, char*, ssize_t);
|
int sys$ttyname_r(int fd, char*, ssize_t);
|
||||||
int sys$ptsname_r(int fd, char*, ssize_t);
|
int sys$ptsname_r(int fd, char*, ssize_t);
|
||||||
pid_t sys$fork(RegisterDump&);
|
pid_t sys$fork(RegisterDump&);
|
||||||
int sys$execve(const char* filename, const char** argv, const char** envp);
|
int sys$execve(const Syscall::SC_execve_params*);
|
||||||
int sys$getdtablesize();
|
int sys$getdtablesize();
|
||||||
int sys$dup(int oldfd);
|
int sys$dup(int oldfd);
|
||||||
int sys$dup2(int oldfd, int newfd);
|
int sys$dup2(int oldfd, int newfd);
|
||||||
|
|
|
@ -300,6 +300,22 @@ struct SC_set_mmap_name_params {
|
||||||
size_t name_length;
|
size_t name_length;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SyscallString {
|
||||||
|
const char* characters { nullptr };
|
||||||
|
size_t length { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SyscallStringList {
|
||||||
|
SyscallString* strings { nullptr };
|
||||||
|
size_t length { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SC_execve_params {
|
||||||
|
SyscallString path;
|
||||||
|
SyscallStringList arguments;
|
||||||
|
SyscallStringList environment;
|
||||||
|
};
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
int sync();
|
int sync();
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <Kernel/Syscall.h>
|
#include <Kernel/Syscall.h>
|
||||||
|
#include <alloca.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
@ -49,7 +50,31 @@ int execv(const char* path, char* const argv[])
|
||||||
|
|
||||||
int execve(const char* filename, char* const argv[], char* const envp[])
|
int execve(const char* filename, char* const argv[], char* const envp[])
|
||||||
{
|
{
|
||||||
int rc = syscall(SC_execve, filename, argv, envp);
|
size_t arg_count = 0;
|
||||||
|
for (size_t i = 0; argv[i]; ++i)
|
||||||
|
++arg_count;
|
||||||
|
|
||||||
|
size_t env_count = 0;
|
||||||
|
for (size_t i = 0; envp[i]; ++i)
|
||||||
|
++env_count;
|
||||||
|
|
||||||
|
auto copy_strings = [&](auto& vec, size_t count, auto& output) {
|
||||||
|
output.length = count;
|
||||||
|
for (size_t i = 0; vec[i]; ++i) {
|
||||||
|
output.strings[i].characters = vec[i];
|
||||||
|
output.strings[i].length = strlen(vec[i]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Syscall::SC_execve_params params;
|
||||||
|
params.arguments.strings = (Syscall::SyscallString*)alloca(arg_count * sizeof(Syscall::SyscallString));
|
||||||
|
params.environment.strings = (Syscall::SyscallString*)alloca(env_count * sizeof(Syscall::SyscallString));
|
||||||
|
|
||||||
|
params.path = { filename, strlen(filename) };
|
||||||
|
copy_strings(argv, arg_count, params.arguments);
|
||||||
|
copy_strings(envp, env_count, params.environment);
|
||||||
|
|
||||||
|
int rc = syscall(SC_execve, ¶ms);
|
||||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue