Repository: SerenityOS/serenity
File: Kernel/Syscalls/posix_spawn.cpp (C++)

Code before:
#include <Kernel/Devices/Generic/NullDevice.h>
#include <Kernel/Devices/TTY/TTY.h>
#include <Kernel/FileSystem/Custody.h>
#include <Kernel/Memory/Region.h>
#include <Kernel/Tasks/PerformanceManager.h>
#include <Kernel/Tasks/Process.h>
#include <Kernel/Tasks/Scheduler.h>
#include <Kernel/Tasks/ScopedProcessList.h>

namespace Kernel {
ErrorOr<FlatPtr> Process::sys$posix_spawn(Userspace<Syscall::SC_posix_spawn_params const*> user_params)
{
    VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
    TRY(require_promise(Pledge::exec));

    auto params = TRY(copy_typed_from_user(user_params));

    if (params.arguments.length > ARG_MAX || params.environment.length > ARG_MAX)
        return E2BIG;
    if (params.arguments.length == 0)
        return EINVAL;

    if (params.attr_data.ptr() != 0 || params.attr_data_size != 0 || params.serialized_file_actions_data.ptr() != 0 || params.serialized_file_actions_data_size != 0) {
        // FIXME: Implement spawn attributes and spawn file actions handling.
        return ENOTSUP;
    }

    auto path = TRY(get_syscall_path_argument(params.path));

    auto copy_user_strings = [](auto const& list, auto& output) -> ErrorOr<void> {
        if (!list.length)
            return {};
        Checked<size_t> size = sizeof(*list.strings);
        size *= list.length;
        if (size.has_overflow())
            return EOVERFLOW;
        Vector<Syscall::StringArgument, 32> strings;
        TRY(strings.try_resize(list.length));
        TRY(copy_from_user(strings.data(), list.strings, size.value()));
        for (size_t i = 0; i < list.length; ++i) {
            auto string = TRY(try_copy_kstring_from_user(strings[i]));
            TRY(output.try_append(move(string)));
        }
        return {};
    };

    Vector<NonnullOwnPtr<KString>> arguments;
    TRY(copy_user_strings(params.arguments, arguments));

    Vector<NonnullOwnPtr<KString>> environment;
    TRY(copy_user_strings(params.environment, environment));

Review comment (bug):
Very small nitpick, but the pointers should probably be compared against `nullptr`.

Code after:
#include <Kernel/Devices/Generic/NullDevice.h>
#include <Kernel/Devices/TTY/TTY.h>
#include <Kernel/FileSystem/Custody.h>
#include <Kernel/Memory/Region.h>
#include <Kernel/Tasks/PerformanceManager.h>
#include <Kernel/Tasks/Process.h>
#include <Kernel/Tasks/Scheduler.h>
#include <Kernel/Tasks/ScopedProcessList.h>

namespace Kernel {

// https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn.html
ErrorOr<FlatPtr> Process::sys$posix_spawn(Userspace<Syscall::SC_posix_spawn_params const*> user_params)
{
    VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
    TRY(require_promise(Pledge::proc));
    TRY(require_promise(Pledge::exec));

    auto params = TRY(copy_typed_from_user(user_params));

    if (params.arguments.length > ARG_MAX || params.environment.length > ARG_MAX)
        return E2BIG;
    if (params.arguments.length == 0)
        return EINVAL;

    if (params.attr_data.ptr() != 0 || params.attr_data_size != 0 || params.serialized_file_actions_data.ptr() != 0 || params.serialized_file_actions_data_size != 0) {
        // FIXME: Implement spawn attributes and spawn file actions handling.
        return ENOTSUP;
    }

    auto path = TRY(get_syscall_path_argument(params.path));

    auto copy_user_strings = [](auto const& list, auto& output) -> ErrorOr<void> {
        if (!list.length)
            return {};
        Checked<size_t> size = sizeof(*list.strings);
        size *= list.length;
        if (size.has_overflow())
            return EOVERFLOW;
        Vector<Syscall::StringArgument, 32> strings;
        TRY(strings.try_resize(list.length));
        TRY(copy_from_user(strings.data(), list.strings, size.value()));
        for (size_t i = 0; i < list.length; ++i) {
            auto string = TRY(try_copy_kstring_from_user(strings[i]));
            TRY(output.try_append(move(string)));
        }
        return {};
    };

    Vector<NonnullOwnPtr<KString>> arguments;
    TRY(copy_user_strings(params.arguments, arguments));