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

Code before:
/*
 * Copyright (c) 2025, Tomás Simões <tomasprsimoes@tecnico.ulisboa.pt>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <Kernel/Debug.h>
#include <Kernel/Devices/BaseDevices.h>
#include <Kernel/Devices/Device.h>
#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_NO_PROCESS_BIG_LOCK(this);
    TRY(require_promise(Pledge::proc));

    auto params = TRY(copy_typed_from_user(user_params));

    // TODO: Add further validation for other pointers in `args` to ensure they are valid, non-null where expected, and point to userspace memory.
    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) {

Review comment (suggestion):
I think also requiring the `exec` pledge might be more correct.
That should match the required promises for the fork+exec posix_spawn implementation.

Code after:
/*
 * Copyright (c) 2025, Tomás Simões <tomasprsimoes@tecnico.ulisboa.pt>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <Kernel/Debug.h>
#include <Kernel/Devices/BaseDevices.h>
#include <Kernel/Devices/Device.h>
#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));