mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-11 13:36:13 +03:00
Using the kernel stack is preferable, especially when the examined strings should be limited to a reasonable length. This is a small improvement, because if we don't actually move these strings then we don't need to own heap allocations for them during the syscall handler function scope. In addition to that, some kernel strings are known to be limited, like the hostname string, for these strings we also can use FixedStringBuffer to store and copy to and from these buffers, without using any heap allocations at all.
97 lines
3.3 KiB
C++
97 lines
3.3 KiB
C++
/*
|
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <AK/FixedStringBuffer.h>
|
|
#include <AK/StringView.h>
|
|
#include <Kernel/Tasks/Process.h>
|
|
|
|
namespace Kernel {
|
|
|
|
ErrorOr<FlatPtr> Process::sys$pledge(Userspace<Syscall::SC_pledge_params const*> user_params)
|
|
{
|
|
VERIFY_NO_PROCESS_BIG_LOCK(this);
|
|
auto params = TRY(copy_typed_from_user(user_params));
|
|
|
|
FixedStringBuffer<all_promises_strings_length_with_spaces> promises {};
|
|
bool promises_provided { false };
|
|
FixedStringBuffer<all_promises_strings_length_with_spaces> execpromises {};
|
|
bool execpromises_provided { false };
|
|
|
|
if (params.promises.characters) {
|
|
promises_provided = true;
|
|
promises = TRY(get_syscall_string_fixed_buffer<all_promises_strings_length_with_spaces>(params.promises));
|
|
}
|
|
|
|
if (params.execpromises.characters) {
|
|
execpromises_provided = true;
|
|
execpromises = TRY(get_syscall_string_fixed_buffer<all_promises_strings_length_with_spaces>(params.execpromises));
|
|
}
|
|
|
|
auto parse_pledge = [&](auto pledge_spec, u32& mask) {
|
|
auto found_invalid_pledge = true;
|
|
pledge_spec.for_each_split_view(' ', SplitBehavior::Nothing, [&mask, &found_invalid_pledge](auto const& part) {
|
|
#define __ENUMERATE_PLEDGE_PROMISE(x) \
|
|
if (part == #x##sv) { \
|
|
mask |= (1u << (u32)Pledge::x); \
|
|
return; \
|
|
}
|
|
ENUMERATE_PLEDGE_PROMISES
|
|
#undef __ENUMERATE_PLEDGE_PROMISE
|
|
found_invalid_pledge = false;
|
|
});
|
|
return found_invalid_pledge;
|
|
};
|
|
|
|
u32 new_promises = 0;
|
|
if (promises_provided) {
|
|
if (!parse_pledge(promises.representable_view(), new_promises))
|
|
return EINVAL;
|
|
}
|
|
|
|
u32 new_execpromises = 0;
|
|
if (execpromises_provided) {
|
|
if (!parse_pledge(execpromises.representable_view(), new_execpromises))
|
|
return EINVAL;
|
|
}
|
|
|
|
return with_mutable_protected_data([&](auto& protected_data) -> ErrorOr<FlatPtr> {
|
|
if (promises_provided) {
|
|
if (protected_data.has_promises && (new_promises & ~protected_data.promises)) {
|
|
if (!(protected_data.promises & (1u << (u32)Pledge::no_error)))
|
|
return EPERM;
|
|
new_promises &= protected_data.promises;
|
|
}
|
|
}
|
|
|
|
if (execpromises_provided) {
|
|
if (protected_data.has_execpromises && (new_execpromises & ~protected_data.execpromises)) {
|
|
if (!(protected_data.promises & (1u << (u32)Pledge::no_error)))
|
|
return EPERM;
|
|
new_execpromises &= protected_data.execpromises;
|
|
}
|
|
}
|
|
|
|
// Only apply promises after all validation has occurred, this ensures
|
|
// we don't introduce logic bugs like applying the promises, and then
|
|
// erroring out when parsing the exec promises later. Such bugs silently
|
|
// leave the caller in an unexpected state.
|
|
|
|
if (promises_provided) {
|
|
protected_data.has_promises = true;
|
|
protected_data.promises = new_promises;
|
|
}
|
|
|
|
if (execpromises_provided) {
|
|
protected_data.has_execpromises = true;
|
|
protected_data.execpromises = new_execpromises;
|
|
}
|
|
|
|
return 0;
|
|
});
|
|
}
|
|
|
|
}
|