/* * PROJECT: ReactOS Kernel * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: Internal header containing information class probing helpers * COPYRIGHT: Copyright 2022 George Bișoc */ #pragma once #include /** * @brief * Probe helper that validates the provided parameters whenever * a NtSet*** system call is invoked from user or kernel mode. * * @param[in] Class * The specific class information that the caller explicitly * requested information to be set into an object. * * @param[in] ClassList * An internal INFORMATION_CLASS_INFO consisting of a list array * of information classes checked against the requested information * classes given in Class parameter. * * @param[in] ClassListEntries * Specifies the number of class entries in an array, provided by * the ClassList parameter. * * @param[in] Buffer * A pointer to an arbitrary data content in memory to be validated. * Such pointer points to the actual arbitrary information class buffer * to be set into the object. This buffer is validated only if the * calling processor mode is UM (aka user mode). * * @param[in] BufferLength * The length of the buffer pointed by the Buffer parameter, whose size * is in bytes. * * @param[in] PreviousMode * The processor calling level mode. This level mode determines the procedure * of probing validation in action. If the level calling mode is KM (aka kernel mode) * this function will only validate the properties of the information class itself * such as the required information length size. If the calling mode is UM, the * pointer buffer provided by Buffer parameter is also validated. * * @return * The outcome of the probe validation is based upon the returned NTSTATUS code. * STATUS_SUCCESS is returned if the validation succeeded. Otherwise, one of the * following failure status codes is returned: * * STATUS_INVALID_INFO_CLASS -- Indicates the given information class is not a valid * valid SET class (ICIF_SET flag is not set to the corresponding information class) * or the actual class is not present in the class list array. * * STATUS_INFO_LENGTH_MISMATCH -- Indicates the information length doesn't match with * the one that the information class itself expects. This is the case with classes * ICIF_SET_SIZE_VARIABLE is not set, which means that the class requires a fixed * length size. * * STATUS_ACCESS_VIOLATION -- Indicates the buffer is not within the user mode probe * address range. The function will raise an exception. * * STATUS_DATATYPE_MISALIGNMENT -- Indicates the address of the buffer in memory is * not aligned to the required alignment set. */ static __inline NTSTATUS DefaultSetInfoBufferCheck( _In_ ULONG Class, _In_ const INFORMATION_CLASS_INFO *ClassList, _In_ ULONG ClassListEntries, _In_ PVOID Buffer, _In_ ULONG BufferLength, _In_ KPROCESSOR_MODE PreviousMode) { NTSTATUS Status = STATUS_SUCCESS; if (Class < ClassListEntries) { if (!(ClassList[Class].Flags & ICIF_SET)) { Status = STATUS_INVALID_INFO_CLASS; } else if (ClassList[Class].RequiredSizeSET > 0 && BufferLength != ClassList[Class].RequiredSizeSET) { if (!(ClassList[Class].Flags & ICIF_SET_SIZE_VARIABLE)) { Status = STATUS_INFO_LENGTH_MISMATCH; } } if (NT_SUCCESS(Status)) { if (PreviousMode != KernelMode) { _SEH2_TRY { ProbeForRead(Buffer, BufferLength, ClassList[Class].AlignmentSET); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; } } } else Status = STATUS_INVALID_INFO_CLASS; return Status; } /** * @brief * Probe helper that validates the provided parameters whenever * a NtQuery*** system call is invoked from user or kernel mode. * * @param[in] Class * The specific class information that the caller explicitly * requested information to be queried from an object. * * @param[in] ClassList * An internal INFORMATION_CLASS_INFO consisting of a list array * of information classes checked against the requested information * classes given in Class parameter. * * @param[in] ClassListEntries * Specifies the number of class entries in an array, provided by * the ClassList parameter. * * @param[in] Flags * Specifies a bit mask flag that influences how the query probe * validation must be performed against Buffer and ReturnLength * parameters. For further information in regard of this parameter, * see remarks. * * @param[in] Buffer * A pointer to an arbitrary data content in memory to be validated. * Such parameter must be an initialized variable where the queried * information is going to be received into this pointer. If the calling * processor mode is UM (aka user mode) this parameter is validated. * This parameter can be NULL (see remarks for more details). * * @param[in] BufferLength * The length of the buffer pointed by the Buffer parameter, whose size * is in bytes. If the Buffer parameter is NULL, this parameter can be 0. * * @param[in] ReturnLength * The returned length of the buffer whose size is in bytes. If Buffer is * NULL as well as BufferLength is 0, this parameter receives the actual * return length needed to store the buffer in memory space. If the * processor level calling mode is UM, this parameter is validated. * If ICIF_FORCE_RETURN_LENGTH_PROBE is specified in Flags parameter, * ReturnLength mustn't be NULL (see remarks). Otherwise it can be NULL. * * @param[in] ReturnLengthPtr * This parameter is of the same nature as the ReturnLength one, with the * difference being that the type parameter can be a ULONG on x86 systems * or a ULONGLONG on AMD64 systems. If the processor level calling mode is * UM, this parameter is validated. This parameter is currently unused. * * @param[in] PreviousMode * The processor calling level mode. This level mode determines the procedure * of probing validation in action. If the level calling mode is KM (aka kernel mode) * this function will only validate the properties of the information class itself * such as the required information length size. If the calling mode is UM, the * pointer buffer provided by Buffer parameter is also validated as well as * the return length parameter. * * @return * The outcome of the probe validation is based upon the returned NTSTATUS code. * STATUS_SUCCESS is returned if the validation succeeded. Otherwise, one of the * following failure status codes is returned: * * STATUS_INVALID_INFO_CLASS -- Indicates the given information class is not a valid * QUERY class (ICIF_QUERY flag is not set to the corresponding information class) * or the actual class is not present in the class list array. * * STATUS_INFO_LENGTH_MISMATCH -- Indicates the information length doesn't match with the * one that the information class itself expects. This is the case with classes where * ICIF_QUERY_SIZE_VARIABLE is not set, which means that the class requires a fixed length size. * * STATUS_ACCESS_VIOLATION -- Indicates the buffer is not within the user mode probe address range * or the buffer variable is not writable (see remarks). The function will raise an exception. * * STATUS_DATATYPE_MISALIGNMENT -- Indicates the address of the buffer in memory is not * aligned to the required alignment set. * * @remarks * The probing of Buffer and ReturnLength are influenced based on the probe flags * pointed by Flags parameter. The following flags are: * * ICIF_PROBE_READ_WRITE -- This flag explicitly tells the function to do a read and * write probe against Buffer parameter. ProbeForWrite is invoked in this case. * This is the default mechanism. * * ICIF_PROBE_READ -- This flag explicitly tells the function to do a read probe against * Buffer parameter only, that is, the function does not probe if the parameter is actually * writable. ProbeForRead is invoked in this case. * * ICIF_FORCE_RETURN_LENGTH_PROBE -- If this flag is set, the function will force probe * the ReturnLength parameter. In this scenario if ReturnLength is NULL a STATUS_ACCESS_VIOLATION * exception is raised. NtQueryInformationToken is the only NT system call where ReturnLength * has to be properly initialized and not NULL. * * Buffer parameter can be NULL if the caller does not want to actually query a certain information * from an object. This is typically with query NT syscalls where a caller has to query the actual * buffer length needed to store the queried information before doing a "real" query in the first place. */ static __inline NTSTATUS DefaultQueryInfoBufferCheck( _In_ ULONG Class, _In_ const INFORMATION_CLASS_INFO *ClassList, _In_ ULONG ClassListEntries, _In_ ULONG Flags, _In_opt_ PVOID Buffer, _In_ ULONG BufferLength, _In_opt_ PULONG ReturnLength, _In_opt_ PULONG_PTR ReturnLengthPtr, _In_ KPROCESSOR_MODE PreviousMode) { NTSTATUS Status = STATUS_SUCCESS; if (Class < ClassListEntries) { if (!(ClassList[Class].Flags & ICIF_QUERY)) { Status = STATUS_INVALID_INFO_CLASS; } else if (ClassList[Class].RequiredSizeQUERY > 0 && BufferLength != ClassList[Class].RequiredSizeQUERY) { if (!(ClassList[Class].Flags & ICIF_QUERY_SIZE_VARIABLE)) { Status = STATUS_INFO_LENGTH_MISMATCH; } } if (NT_SUCCESS(Status)) { if (PreviousMode != KernelMode) { _SEH2_TRY { if (Buffer != NULL) { if (Flags & ICIF_PROBE_READ) { ProbeForRead(Buffer, BufferLength, ClassList[Class].AlignmentQUERY); } else { ProbeForWrite(Buffer, BufferLength, ClassList[Class].AlignmentQUERY); } } if ((Flags & ICIF_FORCE_RETURN_LENGTH_PROBE) || (ReturnLength != NULL)) { ProbeForWriteUlong(ReturnLength); } if (ReturnLengthPtr != NULL) { ProbeForWrite(ReturnLengthPtr, sizeof(ULONG_PTR), sizeof(ULONG_PTR)); } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; } } } else Status = STATUS_INVALID_INFO_CLASS; return Status; }