Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

521 lines
27 KiB

  1. /*++
  2. Copyright (c) 1998-2002 Microsoft Corporation
  3. Module Name:
  4. ioctlp.h
  5. Abstract:
  6. Validation macros for IOCTL handlers
  7. Author:
  8. George V. Reilly (GeorgeRe) May 2001 Hardened the IOCTLs
  9. Revision History:
  10. --*/
  11. #ifndef _IOCTLP_H_
  12. #define _IOCTLP_H_
  13. /*++
  14. IOCTL buffering methods
  15. InputBuffer |METHOD_BUFFERED|METHOD_IN_DIRECT|METHOD_OUT_DIRECT|METHOD_NEITHER
  16. ------------+---------------+----------------+-----------------+--------------
  17. Uses | Buffered I/O | Buffered I/O | Buffered I/O | Requestor's
  18. | | | | virtual addr
  19. ------------+---------------+----------------+-----------------+--------------
  20. located | Kernel virtual address in | Parameters.
  21. (if present)| Irp->AssociatedIrp.SystemBuffer | DeviceIoContr
  22. | | ol.Type3Input
  23. | | Buffer
  24. ------------+--------------------------------------------------+--------------
  25. length | Parameters.DeviceIoControlInputBufferLength
  26. ------------+-----------------------------------------------------------------
  27. OutBuffer
  28. ------------+---------------+----------------+-----------------+--------------
  29. Uses | Buffered I/O | Direct I/O | Direct I/O | Requestor's
  30. | | | | virtual addr
  31. ------------+---------------+----------------------------------+--------------
  32. located |Kernel virtual | MDL pointed to by | Irp->
  33. (if present)|addr Irp->Assoc| Irp->MdlAddress | UserBuffer
  34. |iatedIrp.System| |
  35. |Buffer | |
  36. ------------+---------------+----------------------------------+--------------
  37. length | Length in bytes at Parameters.DeviceIoControl.OutputBufferLength
  38. ------------+-----------------------------------------------------------------
  39. --*/
  40. // METHOD_BUFFERED, METHOD_IN_DIRECT, METHOD_OUT_DIRECT, or METHOD_NEITHER
  41. #define METHOD_FROM_CTL_CODE(ctlcode) ((ctlcode) & 3)
  42. // Used in each ioctl handler to document the kind of parameter probing
  43. // that needs to be done.
  44. #define ASSERT_IOCTL_METHOD(method, ioctl) \
  45. C_ASSERT(METHOD_##method == METHOD_FROM_CTL_CODE(IOCTL_HTTP_##ioctl))
  46. #define VALIDATE_INFORMATION_CLASS( pInfo, Class, Type, Max ) \
  47. Class = pInfo->InformationClass; \
  48. if ( (Class < 0) || (Class >= Max) ) \
  49. { \
  50. Status = STATUS_INVALID_PARAMETER; \
  51. goto end; \
  52. }
  53. #define OUTPUT_BUFFER_TOO_SMALL(pIrpSp, Type) \
  54. ((pIrpSp->Parameters.DeviceIoControl.OutputBufferLength) < sizeof(Type))
  55. #define VALIDATE_OUTPUT_BUFFER_SIZE(pIrpSp, Type) \
  56. /* Ensure the output buffer is large enough. */ \
  57. if ( OUTPUT_BUFFER_TOO_SMALL(pIrpSp,Type) ) \
  58. { \
  59. /* output buffer too small. */ \
  60. Status = STATUS_BUFFER_TOO_SMALL; \
  61. goto end; \
  62. }
  63. //
  64. // We check for alignment problems as well as obtain a virtual address
  65. // for the MdlAddress
  66. //
  67. #define VALIDATE_BUFFER_ALIGNMENT(pInfo, Type) \
  68. if ( ((ULONG_PTR) pInfo) & (TYPE_ALIGNMENT(Type)-1) ) \
  69. { \
  70. Status = STATUS_DATATYPE_MISALIGNMENT_ERROR; \
  71. pInfo = NULL; \
  72. goto end; \
  73. }
  74. #define GET_OUTPUT_BUFFER_ADDRESS_FROM_MDL(pIrp, pInfo) \
  75. /* Ensure MdlAddress is non-null */ \
  76. if (NULL == pIrp->MdlAddress) \
  77. { \
  78. Status = STATUS_INVALID_PARAMETER; \
  79. goto end; \
  80. } \
  81. \
  82. /* Try to obtain virtual address */ \
  83. pInfo = MmGetSystemAddressForMdlSafe( \
  84. pIrp->MdlAddress, \
  85. LowPagePriority \
  86. ); \
  87. \
  88. if (NULL == pInfo) \
  89. { \
  90. Status = STATUS_INSUFFICIENT_RESOURCES; \
  91. goto end; \
  92. }
  93. #define VALIDATE_OUTPUT_BUFFER_ADDRESS_FROM_MDL(pIrp, Type) \
  94. /* Ensure MdlAddress is non-null */ \
  95. if (NULL == pIrp->MdlAddress) \
  96. { \
  97. Status = STATUS_INVALID_PARAMETER; \
  98. goto end; \
  99. } \
  100. \
  101. /* Check alignment using of MdlAddress's virtual address */ \
  102. if (((ULONG_PTR) MmGetMdlVirtualAddress(pIrp->MdlAddress)) & \
  103. (TYPE_ALIGNMENT(Type) - 1)) \
  104. { \
  105. Status = STATUS_DATATYPE_MISALIGNMENT_ERROR; \
  106. goto end; \
  107. }
  108. //
  109. // Because we are using pIrp->AssociatedIrp.SystemBuffer below to check for a
  110. // valid output buffer, this macro only works properly with METHOD_BUFFERED
  111. // ioctl's.
  112. //
  113. #define VALIDATE_OUTPUT_BUFFER(pIrp, pIrpSp, Type, pInfo) \
  114. /* Ensure the output buffer is large enough. */ \
  115. VALIDATE_OUTPUT_BUFFER_SIZE(pIrpSp, Type); \
  116. \
  117. /* Fetch out the output buffer */ \
  118. pInfo = (Type*) pIrp->AssociatedIrp.SystemBuffer; \
  119. \
  120. if (NULL == pInfo) \
  121. { \
  122. Status = STATUS_INVALID_PARAMETER; \
  123. goto end; \
  124. }
  125. //
  126. // Because we are using Irp->MdlAddress below to check for a valid output
  127. // buffer, this macro does *not* work for METHOD_BUFFERED ioctl's. For
  128. // METHOD_BUFFERED ioctl's use VALIDATE_OUTPUT_BUFFER above.
  129. //
  130. #define VALIDATE_OUTPUT_MDL(pIrp, pIrpSp, Type, pInfo) \
  131. /* Ensure the output buffer is large enough. */ \
  132. VALIDATE_OUTPUT_BUFFER_SIZE(pIrpSp, Type); \
  133. \
  134. /* Obtain virtual address from Mdl */ \
  135. GET_OUTPUT_BUFFER_ADDRESS_FROM_MDL(pIrp, pInfo); \
  136. \
  137. /* Check alignment */ \
  138. VALIDATE_BUFFER_ALIGNMENT(pInfo, Type);
  139. #define VALIDATE_OUTPUT_BUFFER_FROM_MDL(pIrpSp, pInfo, Type) \
  140. /* Ensure the output buffer is large enough. */ \
  141. VALIDATE_OUTPUT_BUFFER_SIZE(pIrpSp, Type); \
  142. \
  143. /* Check alignment */ \
  144. VALIDATE_BUFFER_ALIGNMENT(pInfo, Type);
  145. #define HANDLE_BUFFER_LENGTH_REQUEST(pIrp, pIrpSp, Type) \
  146. if ( (NULL == pIrp->MdlAddress) || \
  147. OUTPUT_BUFFER_TOO_SMALL(pIrpSp, Type) ) \
  148. { \
  149. pIrp->IoStatus.Information = sizeof(Type); \
  150. Status = STATUS_BUFFER_OVERFLOW; \
  151. goto end; \
  152. }
  153. #define VALIDATE_INPUT_BUFFER(pIrp, pIrpSp, INFO_TYPE, pInfo) \
  154. /* Ensure the input buffer looks good */ \
  155. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength \
  156. < sizeof(INFO_TYPE)) \
  157. { \
  158. /* input buffer too small. */ \
  159. Status = STATUS_BUFFER_TOO_SMALL; \
  160. goto end; \
  161. } \
  162. \
  163. /* Fetch out the input buffer */ \
  164. pInfo = (INFO_TYPE*) pIrp->AssociatedIrp.SystemBuffer; \
  165. \
  166. if (NULL == pInfo) \
  167. { \
  168. Status = STATUS_INVALID_PARAMETER; \
  169. goto end; \
  170. }
  171. #define VALIDATE_SEND_INFO( \
  172. pIrp, \
  173. pIrpSp, \
  174. pSendInfo, \
  175. LocalSendInfo, \
  176. pEntityChunk, \
  177. pLocalEntityChunks, \
  178. LocalEntityChunks \
  179. ) \
  180. /* Ensure the input buffer looks good */ \
  181. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength \
  182. < sizeof(HTTP_SEND_HTTP_RESPONSE_INFO)) \
  183. { \
  184. /* input buffer too small. */ \
  185. Status = STATUS_BUFFER_TOO_SMALL; \
  186. goto end; \
  187. } \
  188. \
  189. pSendInfo = (PHTTP_SEND_HTTP_RESPONSE_INFO) \
  190. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer; \
  191. \
  192. if (NULL == pSendInfo) \
  193. { \
  194. Status = STATUS_INVALID_PARAMETER; \
  195. goto end; \
  196. } \
  197. \
  198. /* Probe the input buffer before copying it, to check address range */ \
  199. UlProbeForRead( \
  200. pSendInfo, \
  201. sizeof(HTTP_SEND_HTTP_RESPONSE_INFO), \
  202. sizeof(PVOID), \
  203. pIrp->RequestorMode \
  204. ); \
  205. \
  206. /* Copy the input buffer into a local variable, to prevent user */ \
  207. /* remapping it after we've probed it. */ \
  208. LocalSendInfo = *pSendInfo; \
  209. \
  210. /* Prevent arithmetic overflows in the multiplication below */ \
  211. if (LocalSendInfo.EntityChunkCount >= UL_MAX_CHUNKS) \
  212. { \
  213. Status = STATUS_INVALID_PARAMETER; \
  214. goto end; \
  215. } \
  216. \
  217. /* Third parameter should be TYPE_ALIGNMENT(HTTP_DATA_CHUNK) */ \
  218. UlProbeForRead( \
  219. LocalSendInfo.pEntityChunks, \
  220. sizeof(HTTP_DATA_CHUNK) * LocalSendInfo.EntityChunkCount, \
  221. sizeof(PVOID), \
  222. pIrp->RequestorMode \
  223. ); \
  224. \
  225. /* Copy the data chunks to a local chunk arrary. */ \
  226. if (UserMode == pIrp->RequestorMode) \
  227. { \
  228. if (LocalSendInfo.EntityChunkCount > UL_LOCAL_CHUNKS) \
  229. { \
  230. pLocalEntityChunks = (PHTTP_DATA_CHUNK) \
  231. UL_ALLOCATE_POOL( \
  232. PagedPool, \
  233. sizeof(HTTP_DATA_CHUNK) * LocalSendInfo.EntityChunkCount,\
  234. UL_DATA_CHUNK_POOL_TAG \
  235. ); \
  236. \
  237. if (NULL == pLocalEntityChunks) \
  238. { \
  239. Status = STATUS_NO_MEMORY; \
  240. goto end; \
  241. } \
  242. \
  243. pEntityChunks = pLocalEntityChunks; \
  244. } \
  245. else \
  246. { \
  247. pEntityChunks = LocalEntityChunks; \
  248. } \
  249. \
  250. RtlCopyMemory( \
  251. pEntityChunks, \
  252. LocalSendInfo.pEntityChunks, \
  253. sizeof(HTTP_DATA_CHUNK) * LocalSendInfo.EntityChunkCount \
  254. ); \
  255. } \
  256. else \
  257. { \
  258. pEntityChunks = LocalSendInfo.pEntityChunks; \
  259. }
  260. #define VALIDATE_LOG_DATA(pIrp,LocalSendInfo, LocalLogData) \
  261. /* Capture and make a local copy of LogData. */ \
  262. /* pSendInfo is already captured and LocalSendInfo.pLogData is */ \
  263. /* pointing to user's pLogData at the beginning */ \
  264. if (LocalSendInfo.pLogData && UserMode == pIrp->RequestorMode) \
  265. { \
  266. UlProbeForRead( \
  267. LocalSendInfo.pLogData, \
  268. sizeof(HTTP_LOG_FIELDS_DATA), \
  269. sizeof(USHORT), \
  270. pIrp->RequestorMode \
  271. ); \
  272. \
  273. LocalLogData = *(LocalSendInfo.pLogData); \
  274. LocalSendInfo.pLogData = &LocalLogData; \
  275. } else
  276. // better be an application pool
  277. #define VALIDATE_APP_POOL_FO(pFileObject, pProcess, CheckWorkerProcess) \
  278. if (!IS_APP_POOL_FO(pFileObject)) \
  279. { \
  280. Status = STATUS_INVALID_DEVICE_REQUEST; \
  281. goto end; \
  282. } \
  283. \
  284. pProcess = GET_APP_POOL_PROCESS(pFileObject); \
  285. \
  286. if (!IS_VALID_AP_PROCESS(pProcess) \
  287. || !IS_VALID_AP_OBJECT(pProcess->pAppPool)) \
  288. { \
  289. Status = STATUS_INVALID_PARAMETER; \
  290. goto end; \
  291. } \
  292. \
  293. if (CheckWorkerProcess && pProcess->Controller) \
  294. { \
  295. Status = STATUS_NOT_SUPPORTED; \
  296. goto end; \
  297. } else
  298. #define VALIDATE_APP_POOL(pIrpSp, pProcess, CheckWorkerProcess) \
  299. VALIDATE_APP_POOL_FO(pIrpSp->FileObject, pProcess, CheckWorkerProcess)
  300. // better be a control channel
  301. #define VALIDATE_CONTROL_CHANNEL(pIrpSp, pControlChannel) \
  302. if (!IS_CONTROL_CHANNEL(pIrpSp->FileObject)) \
  303. { \
  304. Status = STATUS_INVALID_DEVICE_REQUEST; \
  305. goto end; \
  306. } \
  307. else \
  308. { \
  309. pControlChannel = GET_CONTROL_CHANNEL(pIrpSp->FileObject); \
  310. \
  311. if (!IS_ACTIVE_CONTROL_CHANNEL(pControlChannel)) \
  312. { \
  313. Status = STATUS_INVALID_PARAMETER; \
  314. goto end; \
  315. } \
  316. }
  317. // better be a filter channel
  318. #define VALIDATE_FILTER_PROCESS(pIrpSp, pFilterProcess) \
  319. if (!IS_FILTER_PROCESS_FO(pIrpSp->FileObject)) \
  320. { \
  321. Status = STATUS_INVALID_DEVICE_REQUEST; \
  322. goto end; \
  323. } \
  324. \
  325. pFilterProcess = GET_FILTER_PROCESS(pIrpSp->FileObject); \
  326. \
  327. if (!IS_VALID_FILTER_PROCESS(pFilterProcess)) \
  328. { \
  329. Status = STATUS_INVALID_PARAMETER; \
  330. goto end; \
  331. } else
  332. // Complete the request and return Status
  333. #define COMPLETE_REQUEST_AND_RETURN(pIrp, Status) \
  334. if (Status != STATUS_PENDING) \
  335. { \
  336. pIrp->IoStatus.Status = Status; \
  337. UlCompleteRequest( pIrp, IO_NO_INCREMENT ); \
  338. } \
  339. \
  340. RETURN( Status );
  341. /***************************************************************************++
  342. Routine Description:
  343. Check to see if the connection is a zombie. If that's the case
  344. proceed with logging only handling of the connection. Basically
  345. if this is the last sendresponse with the logging data, do the
  346. logging otherwise reject. But this zombie connection may already
  347. been terminated by the timeout code, guard against that by
  348. looking at the ZombieCheck flag.
  349. Arguments:
  350. pRequest - Request which reeceives the ioctl
  351. pHttpConn - Check connection for zombie state
  352. Falgs - To understant whether this is final send or not
  353. pUserLogData - The user logging data
  354. --***************************************************************************/
  355. __inline
  356. NTSTATUS
  357. UlCheckForZombieConnection(
  358. IN PUL_INTERNAL_REQUEST pRequest,
  359. IN PUL_HTTP_CONNECTION pHttpConn,
  360. IN ULONG Flags,
  361. IN PHTTP_LOG_FIELDS_DATA pUserLogData,
  362. IN KPROCESSOR_MODE RequestorMode
  363. )
  364. {
  365. NTSTATUS Status;
  366. BOOLEAN LastSend;
  367. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pHttpConn));
  368. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  369. LastSend = (BOOLEAN)(((Flags) & HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0);
  370. Status = STATUS_SUCCESS;
  371. if (!LastSend)
  372. {
  373. if (pHttpConn->Zombified)
  374. {
  375. //
  376. // Reject any send ioctl other than the last one
  377. // if the connection is in zombie state.
  378. //
  379. Status = STATUS_CONNECTION_INVALID;
  380. }
  381. else
  382. {
  383. //
  384. // Proceed with the normal send path.
  385. //
  386. }
  387. }
  388. else
  389. {
  390. //
  391. // Only if the destroy-connection raced before us, then
  392. // acquire the eresource and do the zombie check.
  393. //
  394. if (1 == InterlockedCompareExchange(
  395. (PLONG) &pRequest->ZombieCheck,
  396. 1,
  397. 0
  398. ))
  399. {
  400. UlAcquirePushLockExclusive(&pHttpConn->PushLock);
  401. if (pHttpConn->Zombified)
  402. {
  403. //
  404. // Avoid the logging path if the zombie connection is
  405. // already timed out.
  406. //
  407. if (1 == InterlockedCompareExchange(
  408. (PLONG) &pHttpConn->CleanedUp,
  409. 1,
  410. 0
  411. ))
  412. {
  413. Status = STATUS_CONNECTION_INVALID;
  414. }
  415. else
  416. {
  417. Status = UlLogZombieConnection(
  418. pRequest,
  419. pHttpConn,
  420. pUserLogData,
  421. RequestorMode
  422. );
  423. }
  424. }
  425. else
  426. {
  427. //
  428. // Not a zombie connection proceed with the normal
  429. // last send path.
  430. //
  431. }
  432. UlReleasePushLockExclusive(&pHttpConn->PushLock);
  433. }
  434. }
  435. return Status;
  436. } // UlCheckForZombieConnection
  437. // Forward declarations
  438. VOID
  439. UlpRestartSendHttpResponse(
  440. IN PVOID pCompletionContext,
  441. IN NTSTATUS Status,
  442. IN ULONG_PTR Information
  443. );
  444. #endif // _IOCTLP_H_