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.

584 lines
20 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Module: validate.cpp
  4. //
  5. // Description:
  6. //
  7. //
  8. //@@BEGIN_MSINTERNAL
  9. // Development Team:
  10. // Alper Selcuk
  11. //
  12. // History: Date Author Comment
  13. // 02/28/02 AlperS Created
  14. //
  15. // To Do: Date Author Comment
  16. //
  17. //@@END_MSINTERNAL
  18. //
  19. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  20. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  21. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  22. // PURPOSE.
  23. //
  24. // Copyright (c) 2002-2002 Microsoft Corporation. All Rights Reserved.
  25. //
  26. //---------------------------------------------------------------------------
  27. #include "common.h"
  28. DEFINE_KSPROPERTY_TABLE(AudioPropertyValidationHandlers)
  29. {
  30. DEFINE_KSPROPERTY_ITEM(
  31. KSPROPERTY_AUDIO_QUALITY, // idProperty
  32. NULL, // pfnGetHandler
  33. sizeof(KSPROPERTY), // cbMinGetPropertyInput
  34. sizeof(ULONG), // cbMinGetDataInput
  35. SadValidateAudioQuality, // pfnSetHandler
  36. NULL, // Values
  37. 0, // RelationsCount
  38. NULL, // Relations
  39. NULL, // SupportHandler
  40. 0 // SerializedSize
  41. ),
  42. DEFINE_KSPROPERTY_ITEM(
  43. KSPROPERTY_AUDIO_MIX_LEVEL_CAPS, // idProperty
  44. NULL, // pfnGetHandler
  45. sizeof(KSPROPERTY), // cbMinGetPropertyInput
  46. sizeof(ULONG) + sizeof(ULONG), // cbMinGetDataInput
  47. SadValidateAudioMixLevelCaps, // pfnSetHandler
  48. NULL, // Values
  49. 0, // RelationsCount
  50. NULL, // Relations
  51. NULL, // SupportHandler
  52. 0 // SerializedSize
  53. ),
  54. DEFINE_KSPROPERTY_ITEM(
  55. KSPROPERTY_AUDIO_STEREO_ENHANCE, // idProperty
  56. NULL, // pfnGetHandler
  57. sizeof(KSPROPERTY), // cbMinGetPropertyInput
  58. sizeof(KSAUDIO_STEREO_ENHANCE), // cbMinGetDataInput
  59. SadValidateAudioStereoEnhance, // pfnSetHandler
  60. NULL, // Values
  61. 0, // RelationsCount
  62. NULL, // Relations
  63. NULL, // SupportHandler
  64. 0 // SerializedSize
  65. ),
  66. DEFINE_KSPROPERTY_ITEM(
  67. KSPROPERTY_AUDIO_PREFERRED_STATUS, // idProperty
  68. NULL, // pfnGetHandler
  69. sizeof(KSPROPERTY), // cbMinGetPropertyInput
  70. sizeof(KSAUDIO_PREFERRED_STATUS), // cbMinGetDataInput
  71. SadValidateAudioPreferredStatus, // pfnSetHandler
  72. NULL, // Values
  73. 0, // RelationsCount
  74. NULL, // Relations
  75. NULL, // SupportHandler
  76. 0 // SerializedSize
  77. )
  78. };
  79. DEFINE_KSPROPERTY_TABLE(PinConnectionValidationHandlers)
  80. {
  81. DEFINE_KSPROPERTY_ITEM(
  82. KSPROPERTY_CONNECTION_STATE, // idProperty
  83. NULL, // pfnGetHandler
  84. sizeof(KSPROPERTY), // cbMinGetPropertyInput
  85. sizeof(ULONG), // cbMinGetDataInput
  86. SadValidateConnectionState, // pfnSetHandler
  87. NULL, // Values
  88. 0, // RelationsCount
  89. NULL, // Relations
  90. NULL, // SupportHandler
  91. 0 // SerializedSize
  92. ),
  93. DEFINE_KSPROPERTY_ITEM(
  94. KSPROPERTY_CONNECTION_DATAFORMAT, // idProperty
  95. SadValidateDataFormat, // pfnGetHandler
  96. sizeof(KSPROPERTY), // cbMinGetPropertyInput
  97. sizeof(KSDATAFORMAT_WAVEFORMATEX), // cbMinGetDataInput
  98. SadValidateDataFormat, // pfnSetHandler
  99. NULL, // Values
  100. 0, // RelationsCount
  101. NULL, // Relations
  102. NULL, // SupportHandler
  103. 0 // SerializedSize
  104. )
  105. };
  106. DEFINE_KSPROPERTY_SET_TABLE(ValidationPropertySet)
  107. {
  108. DEFINE_KSPROPERTY_SET(
  109. &KSPROPSETID_Audio, // Set
  110. SIZEOF_ARRAY(AudioPropertyValidationHandlers), // PropertiesCount
  111. AudioPropertyValidationHandlers, // PropertyItem
  112. 0, // FastIoCount
  113. NULL // FastIoTable
  114. ),
  115. DEFINE_KSPROPERTY_SET(
  116. &KSPROPSETID_Connection, // Set
  117. SIZEOF_ARRAY(PinConnectionValidationHandlers), // PropertiesCount
  118. PinConnectionValidationHandlers, // PropertyItem
  119. 0, // FastIoCount
  120. NULL // FastIoTable
  121. )
  122. };
  123. //===========================================================================
  124. //
  125. // Validates the integrity of KSDATAFORMAT structure for AUDIO.
  126. // Assumptions:
  127. // - pDataFormat is totally trusted. It has been probed and buffered
  128. // properly.
  129. // - This function should only be called if MajorFormat is AUDIO.
  130. //
  131. NTSTATUS
  132. ValidateAudioDataFormats(
  133. PKSDATAFORMAT pDataFormat
  134. )
  135. {
  136. NTSTATUS ntStatus = STATUS_SUCCESS;
  137. ULONG cbAudioFormat;
  138. PWAVEFORMATEX pWaveFormatEx;
  139. ASSERT(pDataFormat);
  140. ASSERT(IsEqualGUID(&pDataFormat->MajorFormat, &KSDATAFORMAT_TYPE_AUDIO));
  141. //
  142. // We only support two specifiers in audio land. All the rest will be
  143. // accepted without further checks, because we don't know how to validate
  144. // them.
  145. //
  146. pWaveFormatEx = GetWaveFormatExFromKsDataFormat(pDataFormat, &cbAudioFormat);
  147. if (NULL == pWaveFormatEx) {
  148. DPF(5, "ValidataAudioDataFormats : invalid format specifier");
  149. ntStatus = STATUS_SUCCESS;
  150. goto exit;
  151. }
  152. //
  153. // Make sure that we have enough space for the actual format packet.
  154. // Note that this will make sure we can at least touch the WAVEFORMATEX
  155. // part.
  156. //
  157. if (pDataFormat->FormatSize < cbAudioFormat)
  158. {
  159. DPF(10, "ValidataAudioDataFormats : format size does not match specifier");
  160. ntStatus = STATUS_INVALID_PARAMETER;
  161. goto exit;
  162. }
  163. //
  164. // Check to see if WAVEFORMATEXTENSIBLE size is specified correctly.
  165. //
  166. if ((WAVE_FORMAT_EXTENSIBLE == pWaveFormatEx->wFormatTag) &&
  167. (pWaveFormatEx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))
  168. {
  169. DPF1(4, "ValidataAudioDataFormats : WAVEFORMATEXTENSIBLE size does not match %d", pWaveFormatEx->cbSize);
  170. ntStatus = STATUS_INVALID_PARAMETER;
  171. goto exit;
  172. }
  173. //
  174. // Now that WaveFormatEx is guaranteed to be safe, check if we have extended
  175. // information in WAVEFORMATEX.
  176. // cbSize specifies the size of the extension structure.
  177. // Validate that FormatSize accomodates cbSize
  178. // Validate that cbSize does not cause an overflow.
  179. //
  180. if (pDataFormat->FormatSize < cbAudioFormat + pWaveFormatEx->cbSize ||
  181. cbAudioFormat + pWaveFormatEx->cbSize < cbAudioFormat)
  182. {
  183. DPF1(10, "ValidataAudioDataFormats : format size does not match waveformatex.cbSize %d", pWaveFormatEx->cbSize);
  184. ntStatus = STATUS_INVALID_PARAMETER;
  185. goto exit;
  186. }
  187. //
  188. // Now we validated that the data buffer passed to us actually matches
  189. // with its specifier.
  190. //
  191. exit:
  192. return ntStatus;
  193. } // ValidateAudioDataFormats
  194. //===========================================================================
  195. //
  196. // Validates the integrity of KSDATAFORMAT structure.
  197. // Calls ValidateAudioDataFormat if MajorFormat is audio.
  198. // Or checks the buffers size if Specifier is NONE.
  199. // Assumptions:
  200. // - pDataFormat is totally trusted. It has been probed and buffered
  201. // properly.
  202. //
  203. NTSTATUS
  204. ValidateDataFormat(
  205. PKSDATAFORMAT pDataFormat
  206. )
  207. {
  208. NTSTATUS ntStatus = STATUS_SUCCESS;
  209. ASSERT(pDataFormat);
  210. if (IsEqualGUID(&pDataFormat->MajorFormat, &KSDATAFORMAT_TYPE_AUDIO))
  211. {
  212. ntStatus = ValidateAudioDataFormats(pDataFormat);
  213. }
  214. return ntStatus;
  215. } // ValidateDataFormat
  216. //===========================================================================
  217. //
  218. // ValidateDeviceIoControl
  219. //
  220. // Probe Ioctl parameters by calling KS functions.
  221. // All the KS functions called here first probe the input and output buffers
  222. // and then copy them to Irp->SystemBuffer for further safe usage.
  223. // Calling these functions with NULL parameter basically means probe and copy
  224. // the buffers and return.
  225. //
  226. NTSTATUS
  227. ValidateDeviceIoControl(
  228. PIRP pIrp
  229. )
  230. {
  231. NTSTATUS Status = STATUS_SUCCESS;
  232. PIO_STACK_LOCATION pIrpStack;
  233. ASSERT(pIrp);
  234. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  235. switch (pIrpStack->Parameters.DeviceIoControl.IoControlCode)
  236. {
  237. case IOCTL_KS_PROPERTY:
  238. Status = KsPropertyHandler(
  239. pIrp,
  240. SIZEOF_ARRAY(ValidationPropertySet),
  241. ValidationPropertySet);
  242. break;
  243. case IOCTL_KS_ENABLE_EVENT:
  244. Status = KsEnableEvent(pIrp, 0, NULL, NULL, KSEVENTS_NONE, NULL);
  245. break;
  246. case IOCTL_KS_METHOD:
  247. Status = KsMethodHandler(pIrp, 0, NULL);
  248. break;
  249. //
  250. // IOCTL_KS_DISABLE_EVENT
  251. // KsDisableEvent does not use and touch input parameters.
  252. // So input buffer validation is not necessary.
  253. //
  254. //
  255. // IOCTL_KS_RESET_STATE
  256. // The reset request only takes a ULONG. KsAcquireResetValue safely
  257. // extracts the RESET value from the IRP.
  258. // Sysaudio cannot do any validation here, because KsAcquireResetValue
  259. // works on Input buffer directly.
  260. //
  261. //
  262. // IOCTL_KS_WRITE_STREAM
  263. // IOCTL_KS_READ_STREAM
  264. // We are not doing any validation on these.
  265. //
  266. default:
  267. Status = STATUS_NOT_FOUND;
  268. }
  269. //
  270. // If there is no validation function ValidationPropertySet, Ks
  271. // will return one of these. Even in this case buffers must have
  272. // been probed and copied to kernel.
  273. //
  274. if (Status == STATUS_NOT_FOUND || Status == STATUS_PROPSET_NOT_FOUND)
  275. {
  276. Status = STATUS_SUCCESS;
  277. }
  278. if (!NT_SUCCESS(Status))
  279. {
  280. DPF1(5, "Rejected DeviceIOCTL - %X", pIrpStack->Parameters.DeviceIoControl.IoControlCode);
  281. }
  282. return Status;
  283. } // ValidateDeviceIoControl
  284. //===========================================================================
  285. //
  286. // Return TRUE if sysaudio is interested in handling this IoControlCode
  287. // Otherwise return FALSE.
  288. //
  289. BOOL
  290. IsSysaudioIoctlCode(
  291. ULONG IoControlCode
  292. )
  293. {
  294. if (IOCTL_KS_PROPERTY == IoControlCode ||
  295. IOCTL_KS_ENABLE_EVENT == IoControlCode ||
  296. IOCTL_KS_DISABLE_EVENT == IoControlCode ||
  297. IOCTL_KS_METHOD == IoControlCode)
  298. {
  299. return TRUE;
  300. }
  301. return FALSE;
  302. } // IsSysaudioIoctlCode
  303. //===========================================================================
  304. //
  305. // SadValidateConnectionState
  306. // Check that the KSSTATE is valid.
  307. //
  308. NTSTATUS
  309. SadValidateConnectionState(
  310. IN PIRP pIrp,
  311. IN PKSPROPERTY pProperty,
  312. IN PKSSTATE pState
  313. )
  314. {
  315. ASSERT(pState);
  316. if (KSSTATE_STOP <= *pState &&
  317. KSSTATE_RUN >= *pState)
  318. {
  319. return STATUS_SUCCESS;
  320. }
  321. DPF1(5, "SadValidateConnectionState: Invalid State %d", *pState);
  322. return STATUS_INVALID_PARAMETER;
  323. } // SadValidateConnectionState
  324. //===========================================================================
  325. //
  326. // SadValidateDataFormat
  327. // Checks whether the given format is valid.
  328. //
  329. NTSTATUS
  330. SadValidateDataFormat(
  331. IN PIRP pIrp,
  332. IN PKSPROPERTY pProperty,
  333. PKSDATAFORMAT pDataFormat
  334. )
  335. {
  336. ASSERT(pDataFormat);
  337. return ValidateDataFormat(pDataFormat);
  338. } // SadValidateDataFormat
  339. //===========================================================================
  340. //
  341. // SadValidateAudioQuality
  342. // Checks if the quality is valid.
  343. //
  344. NTSTATUS
  345. SadValidateAudioQuality(
  346. IN PIRP pIrp,
  347. IN PKSPROPERTY pProperty,
  348. IN PLONG pQuality
  349. )
  350. {
  351. ASSERT(pQuality);
  352. if (KSAUDIO_QUALITY_WORST <= *pQuality &&
  353. KSAUDIO_QUALITY_ADVANCED >= *pQuality)
  354. {
  355. return STATUS_SUCCESS;
  356. }
  357. DPF1(5, "SadValidateAudioQuality: Invalid Quality %d", *pQuality);
  358. return STATUS_INVALID_PARAMETER;
  359. } // SadValidateAudioQuality
  360. //===========================================================================
  361. //
  362. // SadValidateAudioQuality
  363. // Checks if the structure is valid.
  364. //
  365. NTSTATUS
  366. SadValidateAudioMixLevelCaps(
  367. IN PIRP pIrp,
  368. IN PKSPROPERTY pProperty,
  369. IN OUT PVOID pVoid
  370. )
  371. {
  372. ASSERT(pVoid);
  373. ASSERT(pIrp->AssociatedIrp.SystemBuffer);
  374. PKSAUDIO_MIXCAP_TABLE pMixTable;
  375. PIO_STACK_LOCATION pIrpStack;
  376. ULONG ulTotalChannels;
  377. ULONG cbRequiredSize;
  378. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  379. pMixTable = (PKSAUDIO_MIXCAP_TABLE) pVoid;
  380. if (pMixTable->InputChannels > 10000 ||
  381. pMixTable->OutputChannels > 10000)
  382. {
  383. DPF2(5, "SadValidateAudioMixLevelCaps: Huge Channel numbers %d %d", pMixTable->InputChannels, pMixTable->OutputChannels);
  384. return STATUS_INVALID_PARAMETER;
  385. }
  386. ulTotalChannels = pMixTable->InputChannels + pMixTable->OutputChannels;
  387. if (ulTotalChannels)
  388. {
  389. cbRequiredSize =
  390. sizeof(KSAUDIO_MIXCAP_TABLE) + ulTotalChannels * sizeof(KSAUDIO_MIX_CAPS);
  391. if (cbRequiredSize <
  392. pIrpStack->Parameters.DeviceIoControl.InputBufferLength)
  393. {
  394. DPF1(5, "SadValidateAudioMixLevelCaps: Buffer too small %d",
  395. pIrpStack->Parameters.DeviceIoControl.InputBufferLength);
  396. return STATUS_BUFFER_TOO_SMALL;
  397. }
  398. }
  399. return STATUS_SUCCESS;
  400. } // SadValidateAudioMixLevelCaps
  401. //===========================================================================
  402. //
  403. // SadValidateAudioQuality
  404. // Checks if the Technique is valid.
  405. //
  406. NTSTATUS
  407. SadValidateAudioStereoEnhance(
  408. IN PIRP pIrp,
  409. IN PKSPROPERTY pProperty,
  410. IN PKSAUDIO_STEREO_ENHANCE pStereoEnhance
  411. )
  412. {
  413. ASSERT(pStereoEnhance);
  414. if (SE_TECH_NONE <= pStereoEnhance->Technique &&
  415. SE_TECH_VLSI_TECH >= pStereoEnhance->Technique)
  416. {
  417. return STATUS_SUCCESS;
  418. }
  419. DPF1(5, "SadValidateAudioStereoEnhance: Invalid Technique %d", pStereoEnhance->Technique);
  420. return STATUS_INVALID_PARAMETER;
  421. } // SadValidateAudioStereoEnhance
  422. //===========================================================================
  423. //
  424. // SadValidateAudioQuality
  425. // Checks if the quality is valid.
  426. //
  427. NTSTATUS
  428. SadValidateAudioPreferredStatus(
  429. IN PIRP pIrp,
  430. IN PKSPROPERTY pProperty,
  431. IN PKSAUDIO_PREFERRED_STATUS pPreferredStatus
  432. )
  433. {
  434. ASSERT(pPreferredStatus);
  435. if (KSPROPERTY_SYSAUDIO_NORMAL_DEFAULT <= pPreferredStatus->DeviceType &&
  436. KSPROPERTY_SYSAUDIO_MIXER_DEFAULT >= pPreferredStatus->DeviceType)
  437. {
  438. return STATUS_SUCCESS;
  439. }
  440. DPF1(5, "SadValidateAudioPreferredStatus: Invalid DeviceType %d", pPreferredStatus->DeviceType);
  441. return STATUS_INVALID_PARAMETER;
  442. } // SadValidateAudioPreferredStatus
  443. //===========================================================================
  444. //
  445. // SadValidateDataIntersection
  446. // Checks the integrity of dataranges following pPin.
  447. //
  448. NTSTATUS
  449. SadValidateDataIntersection(
  450. IN PIRP pIrp,
  451. IN PKSP_PIN pPin
  452. )
  453. {
  454. PIO_STACK_LOCATION pIrpStack;
  455. PKSMULTIPLE_ITEM pKsMultipleItem;
  456. PKSDATARANGE pKsDataRange;
  457. ULONG cbTotal;
  458. ASSERT(pIrp);
  459. ASSERT(pPin);
  460. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  461. pKsMultipleItem = (PKSMULTIPLE_ITEM) (pPin + 1);
  462. pKsDataRange = (PKSDATARANGE) (pKsMultipleItem + 1);
  463. cbTotal = pKsMultipleItem->Size - sizeof(KSMULTIPLE_ITEM);
  464. //
  465. // Make sure that the Irp Input Size is valid. Basically
  466. // InputBufferLength must be greater or equal to
  467. // KSP_PIN + MULTIPLE_ITEM.Size
  468. //
  469. if (pIrpStack->Parameters.DeviceIoControl.InputBufferLength - sizeof(KSP_PIN) <
  470. pKsMultipleItem->Size)
  471. {
  472. DPF(5, "SadValidateDataIntersection: InputBuffer too small");
  473. return STATUS_INVALID_BUFFER_SIZE;
  474. }
  475. //
  476. // Make sure that the MULTIPLE_ITEM contains at least one DATARANGE.
  477. //
  478. if (cbTotal < sizeof(KSDATARANGE))
  479. {
  480. DPF(5, "SadValidateDataIntersection: Not enough data for datarange");
  481. return STATUS_INVALID_BUFFER_SIZE;
  482. }
  483. for (ULONG ii = 0; ii < pKsMultipleItem->Count; ii++)
  484. {
  485. //
  486. // Check if we can touch the FormatSize field.
  487. // Check if we the next data-range is fully available.
  488. //
  489. if (cbTotal < sizeof(ULONG) ||
  490. cbTotal < pKsDataRange->FormatSize ||
  491. pKsDataRange->FormatSize < sizeof(KSDATARANGE))
  492. {
  493. DPF3(5, "SadValidateDataIntersection: Not enough data for datarange %d %d %d", ii, pKsDataRange->FormatSize, cbTotal);
  494. return STATUS_INVALID_BUFFER_SIZE;
  495. }
  496. //
  497. // Check if the MajorFormat and size are consistent.
  498. //
  499. if (IsEqualGUID(&pKsDataRange->MajorFormat, &KSDATAFORMAT_TYPE_AUDIO))
  500. {
  501. if (pKsDataRange->FormatSize < sizeof(KSDATARANGE_AUDIO))
  502. {
  503. DPF(5, "SadValidateDataIntersection: InputBuffer too small for AUDIO");
  504. return STATUS_INVALID_BUFFER_SIZE;
  505. }
  506. }
  507. //
  508. // Set next data range.
  509. //
  510. cbTotal -= pKsDataRange->FormatSize;
  511. pKsDataRange = (PKSDATARANGE) ( ((PBYTE) pKsDataRange) + pKsDataRange->FormatSize );
  512. }
  513. //
  514. // SECURITY NOTE:
  515. // We are not checking the output buffer integrity. The underlying drivers
  516. // are responsible for checking the size of the output buffer, based on
  517. // the result of the intersection.
  518. //
  519. return STATUS_SUCCESS;
  520. } // SadValidateDataIntersection