1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Internal header containing information class probing helpers 5 * COPYRIGHT: Copyright 2022 George Bișoc <george.bisoc@reactos.org> 6 */ 7 8 #pragma once 9 10 #include <reactos/probe.h> 11 12 /** 13 * @brief 14 * Probe helper that validates the provided parameters whenever 15 * a NtSet*** system call is invoked from user or kernel mode. 16 * 17 * @param[in] Class 18 * The specific class information that the caller explicitly 19 * requested information to be set into an object. 20 * 21 * @param[in] ClassList 22 * An internal INFORMATION_CLASS_INFO consisting of a list array 23 * of information classes checked against the requested information 24 * classes given in Class parameter. 25 * 26 * @param[in] ClassListEntries 27 * Specifies the number of class entries in an array, provided by 28 * the ClassList parameter. 29 * 30 * @param[in] Buffer 31 * A pointer to an arbitrary data content in memory to be validated. 32 * Such pointer points to the actual arbitrary information class buffer 33 * to be set into the object. This buffer is validated only if the 34 * calling processor mode is UM (aka user mode). 35 * 36 * @param[in] BufferLength 37 * The length of the buffer pointed by the Buffer parameter, whose size 38 * is in bytes. 39 * 40 * @param[in] PreviousMode 41 * The processor calling level mode. This level mode determines the procedure 42 * of probing validation in action. If the level calling mode is KM (aka kernel mode) 43 * this function will only validate the properties of the information class itself 44 * such as the required information length size. If the calling mode is UM, the 45 * pointer buffer provided by Buffer parameter is also validated. 46 * 47 * @return 48 * The outcome of the probe validation is based upon the returned NTSTATUS code. 49 * STATUS_SUCCESS is returned if the validation succeeded. Otherwise, one of the 50 * following failure status codes is returned: 51 * 52 * STATUS_INVALID_INFO_CLASS -- Indicates the given information class is not a valid 53 * valid SET class (ICIF_SET flag is not set to the corresponding information class) 54 * or the actual class is not present in the class list array. 55 * 56 * STATUS_INFO_LENGTH_MISMATCH -- Indicates the information length doesn't match with 57 * the one that the information class itself expects. This is the case with classes 58 * ICIF_SET_SIZE_VARIABLE is not set, which means that the class requires a fixed 59 * length size. 60 * 61 * STATUS_ACCESS_VIOLATION -- Indicates the buffer is not within the user mode probe 62 * address range. The function will raise an exception. 63 * 64 * STATUS_DATATYPE_MISALIGNMENT -- Indicates the address of the buffer in memory is 65 * not aligned to the required alignment set. 66 */ 67 static 68 __inline 69 NTSTATUS 70 DefaultSetInfoBufferCheck( 71 _In_ ULONG Class, 72 _In_ const INFORMATION_CLASS_INFO *ClassList, 73 _In_ ULONG ClassListEntries, 74 _In_ PVOID Buffer, 75 _In_ ULONG BufferLength, 76 _In_ KPROCESSOR_MODE PreviousMode) 77 { 78 NTSTATUS Status = STATUS_SUCCESS; 79 80 if (Class < ClassListEntries) 81 { 82 if (!(ClassList[Class].Flags & ICIF_SET)) 83 { 84 Status = STATUS_INVALID_INFO_CLASS; 85 } 86 else if (ClassList[Class].RequiredSizeSET > 0 && 87 BufferLength != ClassList[Class].RequiredSizeSET) 88 { 89 if (!(ClassList[Class].Flags & ICIF_SET_SIZE_VARIABLE)) 90 { 91 Status = STATUS_INFO_LENGTH_MISMATCH; 92 } 93 } 94 95 if (NT_SUCCESS(Status)) 96 { 97 if (PreviousMode != KernelMode) 98 { 99 _SEH2_TRY 100 { 101 ProbeForRead(Buffer, 102 BufferLength, 103 ClassList[Class].AlignmentSET); 104 } 105 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 106 { 107 Status = _SEH2_GetExceptionCode(); 108 } 109 _SEH2_END; 110 } 111 } 112 } 113 else 114 Status = STATUS_INVALID_INFO_CLASS; 115 116 return Status; 117 } 118 119 /** 120 * @brief 121 * Probe helper that validates the provided parameters whenever 122 * a NtQuery*** system call is invoked from user or kernel mode. 123 * 124 * @param[in] Class 125 * The specific class information that the caller explicitly 126 * requested information to be queried from an object. 127 * 128 * @param[in] ClassList 129 * An internal INFORMATION_CLASS_INFO consisting of a list array 130 * of information classes checked against the requested information 131 * classes given in Class parameter. 132 * 133 * @param[in] ClassListEntries 134 * Specifies the number of class entries in an array, provided by 135 * the ClassList parameter. 136 * 137 * @param[in] Flags 138 * Specifies a bit mask flag that influences how the query probe 139 * validation must be performed against Buffer and ReturnLength 140 * parameters. For further information in regard of this parameter, 141 * see remarks. 142 * 143 * @param[in] Buffer 144 * A pointer to an arbitrary data content in memory to be validated. 145 * Such parameter must be an initialized variable where the queried 146 * information is going to be received into this pointer. If the calling 147 * processor mode is UM (aka user mode) this parameter is validated. 148 * This parameter can be NULL (see remarks for more details). 149 * 150 * @param[in] BufferLength 151 * The length of the buffer pointed by the Buffer parameter, whose size 152 * is in bytes. If the Buffer parameter is NULL, this parameter can be 0. 153 * 154 * @param[in] ReturnLength 155 * The returned length of the buffer whose size is in bytes. If Buffer is 156 * NULL as well as BufferLength is 0, this parameter receives the actual 157 * return length needed to store the buffer in memory space. If the 158 * processor level calling mode is UM, this parameter is validated. 159 * If ICIF_FORCE_RETURN_LENGTH_PROBE is specified in Flags parameter, 160 * ReturnLength mustn't be NULL (see remarks). Otherwise it can be NULL. 161 * 162 * @param[in] ReturnLengthPtr 163 * This parameter is of the same nature as the ReturnLength one, with the 164 * difference being that the type parameter can be a ULONG on x86 systems 165 * or a ULONGLONG on AMD64 systems. If the processor level calling mode is 166 * UM, this parameter is validated. This parameter is currently unused. 167 * 168 * @param[in] PreviousMode 169 * The processor calling level mode. This level mode determines the procedure 170 * of probing validation in action. If the level calling mode is KM (aka kernel mode) 171 * this function will only validate the properties of the information class itself 172 * such as the required information length size. If the calling mode is UM, the 173 * pointer buffer provided by Buffer parameter is also validated as well as 174 * the return length parameter. 175 * 176 * @return 177 * The outcome of the probe validation is based upon the returned NTSTATUS code. 178 * STATUS_SUCCESS is returned if the validation succeeded. Otherwise, one of the 179 * following failure status codes is returned: 180 * 181 * STATUS_INVALID_INFO_CLASS -- Indicates the given information class is not a valid 182 * QUERY class (ICIF_QUERY flag is not set to the corresponding information class) 183 * or the actual class is not present in the class list array. 184 * 185 * STATUS_INFO_LENGTH_MISMATCH -- Indicates the information length doesn't match with the 186 * one that the information class itself expects. This is the case with classes where 187 * ICIF_QUERY_SIZE_VARIABLE is not set, which means that the class requires a fixed length size. 188 * 189 * STATUS_ACCESS_VIOLATION -- Indicates the buffer is not within the user mode probe address range 190 * or the buffer variable is not writable (see remarks). The function will raise an exception. 191 * 192 * STATUS_DATATYPE_MISALIGNMENT -- Indicates the address of the buffer in memory is not 193 * aligned to the required alignment set. 194 * 195 * @remarks 196 * The probing of Buffer and ReturnLength are influenced based on the probe flags 197 * pointed by Flags parameter. The following flags are: 198 * 199 * ICIF_PROBE_READ_WRITE -- This flag explicitly tells the function to do a read and 200 * write probe against Buffer parameter. ProbeForWrite is invoked in this case. 201 * This is the default mechanism. 202 * 203 * ICIF_PROBE_READ -- This flag explicitly tells the function to do a read probe against 204 * Buffer parameter only, that is, the function does not probe if the parameter is actually 205 * writable. ProbeForRead is invoked in this case. 206 * 207 * ICIF_FORCE_RETURN_LENGTH_PROBE -- If this flag is set, the function will force probe 208 * the ReturnLength parameter. In this scenario if ReturnLength is NULL a STATUS_ACCESS_VIOLATION 209 * exception is raised. NtQueryInformationToken is the only NT system call where ReturnLength 210 * has to be properly initialized and not NULL. 211 * 212 * Buffer parameter can be NULL if the caller does not want to actually query a certain information 213 * from an object. This is typically with query NT syscalls where a caller has to query the actual 214 * buffer length needed to store the queried information before doing a "real" query in the first place. 215 */ 216 static 217 __inline 218 NTSTATUS 219 DefaultQueryInfoBufferCheck( 220 _In_ ULONG Class, 221 _In_ const INFORMATION_CLASS_INFO *ClassList, 222 _In_ ULONG ClassListEntries, 223 _In_ ULONG Flags, 224 _In_opt_ PVOID Buffer, 225 _In_ ULONG BufferLength, 226 _In_opt_ PULONG ReturnLength, 227 _In_opt_ PULONG_PTR ReturnLengthPtr, 228 _In_ KPROCESSOR_MODE PreviousMode) 229 { 230 NTSTATUS Status = STATUS_SUCCESS; 231 232 if (Class < ClassListEntries) 233 { 234 if (!(ClassList[Class].Flags & ICIF_QUERY)) 235 { 236 Status = STATUS_INVALID_INFO_CLASS; 237 } 238 else if (ClassList[Class].RequiredSizeQUERY > 0 && 239 BufferLength != ClassList[Class].RequiredSizeQUERY) 240 { 241 if (!(ClassList[Class].Flags & ICIF_QUERY_SIZE_VARIABLE)) 242 { 243 Status = STATUS_INFO_LENGTH_MISMATCH; 244 } 245 } 246 247 if (NT_SUCCESS(Status)) 248 { 249 if (PreviousMode != KernelMode) 250 { 251 _SEH2_TRY 252 { 253 if (Buffer != NULL) 254 { 255 if (Flags & ICIF_PROBE_READ) 256 { 257 ProbeForRead(Buffer, 258 BufferLength, 259 ClassList[Class].AlignmentQUERY); 260 } 261 else 262 { 263 ProbeForWrite(Buffer, 264 BufferLength, 265 ClassList[Class].AlignmentQUERY); 266 } 267 } 268 269 if ((Flags & ICIF_FORCE_RETURN_LENGTH_PROBE) || (ReturnLength != NULL)) 270 { 271 ProbeForWriteUlong(ReturnLength); 272 } 273 274 if (ReturnLengthPtr != NULL) 275 { 276 ProbeForWrite(ReturnLengthPtr, sizeof(ULONG_PTR), sizeof(ULONG_PTR)); 277 } 278 } 279 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 280 { 281 Status = _SEH2_GetExceptionCode(); 282 } 283 _SEH2_END; 284 } 285 } 286 } 287 else 288 Status = STATUS_INVALID_INFO_CLASS; 289 290 return Status; 291 } 292