special.c 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399
  1. /*++
  2. Copyright (c) 2012 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. special.c
  9. Abstract:
  10. This module implements the special file driver.
  11. Author:
  12. Evan Green 23-Sep-2013
  13. Environment:
  14. Kernel
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <minoca/kernel/driver.h>
  20. #include <minoca/intrface/random.h>
  21. #include <minoca/lib/crypto.h>
  22. //
  23. // ---------------------------------------------------------------- Definitions
  24. //
  25. #define SPECIAL_DEVICE_ALLOCATION_TAG 0x76447053 // 'vDpS'
  26. #define SPECIAL_DEVICE_NULL_NAME "null"
  27. #define SPECIAL_DEVICE_ZERO_NAME "zero"
  28. #define SPECIAL_DEVICE_FULL_NAME "full"
  29. #define SPECIAL_DEVICE_RANDOM_NAME "random"
  30. #define SPECIAL_DEVICE_URANDOM_NAME "urandom"
  31. #define SPECIAL_DEVICE_CURRENT_TERMINAL_NAME "tty"
  32. #define SPECIAL_URANDOM_BUFFER_SIZE 2048
  33. //
  34. // ------------------------------------------------------ Data Type Definitions
  35. //
  36. typedef enum _SPECIAL_DEVICE_TYPE {
  37. SpecialDeviceInvalid,
  38. SpecialDeviceNull,
  39. SpecialDeviceZero,
  40. SpecialDeviceFull,
  41. SpecialDevicePseudoRandom,
  42. SpecialDeviceCurrentTerminal,
  43. } SPECIAL_DEVICE_TYPE, *PSPECIAL_DEVICE_TYPE;
  44. /*++
  45. Structure Description:
  46. This structure defines the context for a pseudo-random device.
  47. Members:
  48. FortunaContext - Stores a pointer to the fortuna context.
  49. Lock - Stores the lock protecting the Fortuna context.
  50. Interface - Stores a pointer to the pseudo-random source interface.
  51. InterfaceRegistered - Stores a pointer indicating whether or not the
  52. interface has been registered.
  53. --*/
  54. typedef struct _SPECIAL_PSEUDO_RANDOM_DEVICE {
  55. FORTUNA_CONTEXT FortunaContext;
  56. KSPIN_LOCK Lock;
  57. INTERFACE_PSEUDO_RANDOM_SOURCE Interface;
  58. BOOL InterfaceRegistered;
  59. } SPECIAL_PSEUDO_RANDOM_DEVICE, *PSPECIAL_PSEUDO_RANDOM_DEVICE;
  60. /*++
  61. Structure Description:
  62. This structure defines the context for a special device.
  63. Members:
  64. Type - Stores the type of device this is representing.
  65. CreationTime - Stores the system time when the device was created.
  66. ReferenceCount - Stores the number of references held on the device.
  67. U - Stores the union of pointers to more specific special device contexts.
  68. --*/
  69. typedef struct _SPECIAL_DEVICE {
  70. SPECIAL_DEVICE_TYPE Type;
  71. SYSTEM_TIME CreationTime;
  72. volatile ULONG ReferenceCount;
  73. union {
  74. PSPECIAL_PSEUDO_RANDOM_DEVICE PseudoRandom;
  75. } U;
  76. } SPECIAL_DEVICE, *PSPECIAL_DEVICE;
  77. //
  78. // ----------------------------------------------- Internal Function Prototypes
  79. //
  80. KSTATUS
  81. SpecialAddDevice (
  82. PVOID Driver,
  83. PCSTR DeviceId,
  84. PCSTR ClassId,
  85. PCSTR CompatibleIds,
  86. PVOID DeviceToken
  87. );
  88. VOID
  89. SpecialDispatchStateChange (
  90. PIRP Irp,
  91. PVOID DeviceContext,
  92. PVOID IrpContext
  93. );
  94. VOID
  95. SpecialDispatchOpen (
  96. PIRP Irp,
  97. PVOID DeviceContext,
  98. PVOID IrpContext
  99. );
  100. VOID
  101. SpecialDispatchClose (
  102. PIRP Irp,
  103. PVOID DeviceContext,
  104. PVOID IrpContext
  105. );
  106. VOID
  107. SpecialDispatchIo (
  108. PIRP Irp,
  109. PVOID DeviceContext,
  110. PVOID IrpContext
  111. );
  112. VOID
  113. SpecialDispatchSystemControl (
  114. PIRP Irp,
  115. PVOID DeviceContext,
  116. PVOID IrpContext
  117. );
  118. VOID
  119. SpecialDispatchUserControl (
  120. PIRP Irp,
  121. PVOID DeviceContext,
  122. PVOID IrpContext
  123. );
  124. KSTATUS
  125. SpecialFillZeroes (
  126. PIRP Irp
  127. );
  128. KSTATUS
  129. SpecialPseudoRandomStartDevice (
  130. PSPECIAL_DEVICE Device,
  131. PIRP Irp
  132. );
  133. KSTATUS
  134. SpecialPseudoRandomRemoveDevice (
  135. PSPECIAL_DEVICE Device,
  136. PIRP Irp
  137. );
  138. KSTATUS
  139. SpecialPerformPseudoRandomIo (
  140. PSPECIAL_DEVICE Device,
  141. PIRP Irp
  142. );
  143. VOID
  144. SpecialPseudoRandomAddEntropy (
  145. PINTERFACE_PSEUDO_RANDOM_SOURCE Interface,
  146. PVOID Data,
  147. UINTN Length
  148. );
  149. VOID
  150. SpecialPseudoRandomAddTimePointEntropy (
  151. PINTERFACE_PSEUDO_RANDOM_SOURCE Interface
  152. );
  153. VOID
  154. SpecialPseudoRandomGetBytes (
  155. PINTERFACE_PSEUDO_RANDOM_SOURCE Interface,
  156. PVOID Data,
  157. UINTN Length
  158. );
  159. VOID
  160. SpecialDeviceAddReference (
  161. PSPECIAL_DEVICE Device
  162. );
  163. VOID
  164. SpecialDeviceReleaseReference (
  165. PSPECIAL_DEVICE Device
  166. );
  167. VOID
  168. SpecialDestroyDevice (
  169. PSPECIAL_DEVICE Device
  170. );
  171. //
  172. // -------------------------------------------------------------------- Globals
  173. //
  174. PDRIVER SpecialDriver = NULL;
  175. INTERFACE_PSEUDO_RANDOM_SOURCE SpecialPseudoRandomInterfaceTemplate = {
  176. NULL,
  177. SpecialPseudoRandomAddEntropy,
  178. SpecialPseudoRandomAddTimePointEntropy,
  179. SpecialPseudoRandomGetBytes
  180. };
  181. UUID SpecialPseudoRandomInterfaceUuid = UUID_PSEUDO_RANDOM_SOURCE_INTERFACE;
  182. //
  183. // ------------------------------------------------------------------ Functions
  184. //
  185. __USED
  186. KSTATUS
  187. DriverEntry (
  188. PDRIVER Driver
  189. )
  190. /*++
  191. Routine Description:
  192. This routine is the entry point for the special driver. It registers its
  193. other dispatch functions, and performs driver-wide initialization.
  194. Arguments:
  195. Driver - Supplies a pointer to the driver object.
  196. Return Value:
  197. STATUS_SUCCESS on success.
  198. Failure code on error.
  199. --*/
  200. {
  201. DRIVER_FUNCTION_TABLE FunctionTable;
  202. KSTATUS Status;
  203. SpecialDriver = Driver;
  204. RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
  205. FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
  206. FunctionTable.AddDevice = SpecialAddDevice;
  207. FunctionTable.DispatchStateChange = SpecialDispatchStateChange;
  208. FunctionTable.DispatchOpen = SpecialDispatchOpen;
  209. FunctionTable.DispatchClose = SpecialDispatchClose;
  210. FunctionTable.DispatchIo = SpecialDispatchIo;
  211. FunctionTable.DispatchSystemControl = SpecialDispatchSystemControl;
  212. FunctionTable.DispatchUserControl = SpecialDispatchUserControl;
  213. Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
  214. return Status;
  215. }
  216. KSTATUS
  217. SpecialAddDevice (
  218. PVOID Driver,
  219. PCSTR DeviceId,
  220. PCSTR ClassId,
  221. PCSTR CompatibleIds,
  222. PVOID DeviceToken
  223. )
  224. /*++
  225. Routine Description:
  226. This routine is called when a device is detected for which the null device
  227. acts as the function driver. The driver will attach itself to the stack.
  228. Arguments:
  229. Driver - Supplies a pointer to the driver being called.
  230. DeviceId - Supplies a pointer to a string with the device ID.
  231. ClassId - Supplies a pointer to a string containing the device's class ID.
  232. CompatibleIds - Supplies a pointer to a string containing device IDs
  233. that would be compatible with this device.
  234. DeviceToken - Supplies an opaque token that the driver can use to identify
  235. the device in the system. This token should be used when attaching to
  236. the stack.
  237. Return Value:
  238. STATUS_SUCCESS on success.
  239. Failure code if the driver was unsuccessful in attaching itself.
  240. --*/
  241. {
  242. UINTN AllocationSize;
  243. PSPECIAL_DEVICE Context;
  244. SPECIAL_DEVICE_TYPE DeviceType;
  245. PSPECIAL_PSEUDO_RANDOM_DEVICE PseudoRandom;
  246. KSTATUS Status;
  247. Context = NULL;
  248. if (IoAreDeviceIdsEqual(DeviceId, SPECIAL_DEVICE_NULL_NAME) != FALSE) {
  249. DeviceType = SpecialDeviceNull;
  250. } else if (IoAreDeviceIdsEqual(DeviceId, SPECIAL_DEVICE_ZERO_NAME) !=
  251. FALSE) {
  252. DeviceType = SpecialDeviceZero;
  253. } else if (IoAreDeviceIdsEqual(DeviceId, SPECIAL_DEVICE_FULL_NAME) !=
  254. FALSE) {
  255. DeviceType = SpecialDeviceFull;
  256. } else if (IoAreDeviceIdsEqual(DeviceId, SPECIAL_DEVICE_URANDOM_NAME) !=
  257. FALSE) {
  258. DeviceType = SpecialDevicePseudoRandom;
  259. //
  260. // Random and urandom are the same. Convincing arguments have been made
  261. // that trying to estimate the amount of entropy in a source (and therefore
  262. // block random until there is enough) is perilous.
  263. //
  264. } else if (IoAreDeviceIdsEqual(DeviceId, SPECIAL_DEVICE_RANDOM_NAME) !=
  265. FALSE) {
  266. DeviceType = SpecialDevicePseudoRandom;
  267. } else if (IoAreDeviceIdsEqual(DeviceId,
  268. SPECIAL_DEVICE_CURRENT_TERMINAL_NAME) !=
  269. FALSE) {
  270. DeviceType = SpecialDeviceCurrentTerminal;
  271. } else {
  272. RtlDebugPrint("Special device %s not recognized.\n", DeviceId);
  273. Status = STATUS_NOT_SUPPORTED;
  274. goto AddDeviceEnd;
  275. }
  276. //
  277. // The urandom special device must be created non-paged as entropy can be
  278. // added from dispatch level.
  279. //
  280. if (DeviceType == SpecialDevicePseudoRandom) {
  281. AllocationSize = sizeof(SPECIAL_DEVICE) +
  282. sizeof(SPECIAL_PSEUDO_RANDOM_DEVICE);
  283. Context = MmAllocateNonPagedPool(AllocationSize,
  284. SPECIAL_DEVICE_ALLOCATION_TAG);
  285. if (Context == NULL) {
  286. Status = STATUS_INSUFFICIENT_RESOURCES;
  287. goto AddDeviceEnd;
  288. }
  289. RtlZeroMemory(Context, AllocationSize);
  290. PseudoRandom = (PSPECIAL_PSEUDO_RANDOM_DEVICE)(Context + 1);
  291. Context->U.PseudoRandom = PseudoRandom;
  292. CyFortunaInitialize(&(PseudoRandom->FortunaContext),
  293. HlQueryTimeCounter,
  294. HlQueryTimeCounterFrequency());
  295. KeInitializeSpinLock(&(PseudoRandom->Lock));
  296. RtlCopyMemory(&(PseudoRandom->Interface),
  297. &SpecialPseudoRandomInterfaceTemplate,
  298. sizeof(INTERFACE_PSEUDO_RANDOM_SOURCE));
  299. PseudoRandom->Interface.DeviceToken = Context;
  300. //
  301. // Create a regular special device.
  302. //
  303. } else {
  304. AllocationSize = sizeof(SPECIAL_DEVICE);
  305. Context = MmAllocatePagedPool(AllocationSize,
  306. SPECIAL_DEVICE_ALLOCATION_TAG);
  307. if (Context == NULL) {
  308. Status = STATUS_INSUFFICIENT_RESOURCES;
  309. goto AddDeviceEnd;
  310. }
  311. RtlZeroMemory(Context, AllocationSize);
  312. }
  313. Context->Type = DeviceType;
  314. Context->ReferenceCount = 1;
  315. KeGetSystemTime(&(Context->CreationTime));
  316. Status = IoAttachDriverToDevice(Driver, DeviceToken, Context);
  317. if (!KSUCCESS(Status)) {
  318. goto AddDeviceEnd;
  319. }
  320. AddDeviceEnd:
  321. if (!KSUCCESS(Status)) {
  322. if (Context != NULL) {
  323. SpecialDeviceReleaseReference(Context);
  324. }
  325. }
  326. return Status;
  327. }
  328. VOID
  329. SpecialDispatchStateChange (
  330. PIRP Irp,
  331. PVOID DeviceContext,
  332. PVOID IrpContext
  333. )
  334. /*++
  335. Routine Description:
  336. This routine handles State Change IRPs.
  337. Arguments:
  338. Irp - Supplies a pointer to the I/O request packet.
  339. DeviceContext - Supplies the context pointer supplied by the driver when it
  340. attached itself to the driver stack. Presumably this pointer contains
  341. driver-specific device context.
  342. IrpContext - Supplies the context pointer supplied by the driver when
  343. the IRP was created.
  344. Return Value:
  345. None.
  346. --*/
  347. {
  348. PSPECIAL_DEVICE Device;
  349. KSTATUS Status;
  350. ASSERT(Irp->MajorCode == IrpMajorStateChange);
  351. Device = (PSPECIAL_DEVICE)DeviceContext;
  352. switch (Irp->MinorCode) {
  353. case IrpMinorQueryResources:
  354. if (Irp->Direction == IrpUp) {
  355. IoCompleteIrp(SpecialDriver, Irp, STATUS_SUCCESS);
  356. }
  357. break;
  358. case IrpMinorStartDevice:
  359. if (Irp->Direction == IrpUp) {
  360. if (Device->Type == SpecialDevicePseudoRandom) {
  361. Status = SpecialPseudoRandomStartDevice(Device, Irp);
  362. } else {
  363. Status = STATUS_SUCCESS;
  364. }
  365. IoCompleteIrp(SpecialDriver, Irp, Status);
  366. }
  367. break;
  368. case IrpMinorQueryChildren:
  369. IoCompleteIrp(SpecialDriver, Irp, STATUS_SUCCESS);
  370. break;
  371. case IrpMinorRemoveDevice:
  372. if (Irp->Direction == IrpUp) {
  373. if (Device->Type == SpecialDevicePseudoRandom) {
  374. Status = SpecialPseudoRandomRemoveDevice(Device, Irp);
  375. } else {
  376. Status = STATUS_SUCCESS;
  377. }
  378. if (KSUCCESS(Status)) {
  379. SpecialDeviceReleaseReference(Device);
  380. }
  381. IoCompleteIrp(SpecialDriver, Irp, Status);
  382. }
  383. break;
  384. //
  385. // For all other IRPs, do nothing.
  386. //
  387. default:
  388. break;
  389. }
  390. return;
  391. }
  392. VOID
  393. SpecialDispatchOpen (
  394. PIRP Irp,
  395. PVOID DeviceContext,
  396. PVOID IrpContext
  397. )
  398. /*++
  399. Routine Description:
  400. This routine handles Open IRPs.
  401. Arguments:
  402. Irp - Supplies a pointer to the I/O request packet.
  403. DeviceContext - Supplies the context pointer supplied by the driver when it
  404. attached itself to the driver stack. Presumably this pointer contains
  405. driver-specific device context.
  406. IrpContext - Supplies the context pointer supplied by the driver when
  407. the IRP was created.
  408. Return Value:
  409. None.
  410. --*/
  411. {
  412. PSPECIAL_DEVICE Device;
  413. KSTATUS Status;
  414. Device = (PSPECIAL_DEVICE)DeviceContext;
  415. //
  416. // For the current terminal, open the actual controlling terminal. This
  417. // driver then does not get a close call.
  418. //
  419. if (Device->Type == SpecialDeviceCurrentTerminal) {
  420. Status = IoOpenControllingTerminal(Irp->U.Open.IoHandle);
  421. IoCompleteIrp(SpecialDriver, Irp, Status);
  422. //
  423. // Open a data sink device.
  424. //
  425. } else {
  426. SpecialDeviceAddReference(Device);
  427. ASSERT(Irp->U.Open.IoState != NULL);
  428. //
  429. // The data sink devices are always ready for I/O.
  430. //
  431. IoSetIoObjectState(Irp->U.Open.IoState,
  432. POLL_EVENT_IN | POLL_EVENT_OUT,
  433. TRUE);
  434. IoCompleteIrp(SpecialDriver, Irp, STATUS_SUCCESS);
  435. }
  436. return;
  437. }
  438. VOID
  439. SpecialDispatchClose (
  440. PIRP Irp,
  441. PVOID DeviceContext,
  442. PVOID IrpContext
  443. )
  444. /*++
  445. Routine Description:
  446. This routine handles Close IRPs.
  447. Arguments:
  448. Irp - Supplies a pointer to the I/O request packet.
  449. DeviceContext - Supplies the context pointer supplied by the driver when it
  450. attached itself to the driver stack. Presumably this pointer contains
  451. driver-specific device context.
  452. IrpContext - Supplies the context pointer supplied by the driver when
  453. the IRP was created.
  454. Return Value:
  455. None.
  456. --*/
  457. {
  458. PSPECIAL_DEVICE Device;
  459. Device = (PSPECIAL_DEVICE)DeviceContext;
  460. ASSERT(Device->Type != SpecialDeviceCurrentTerminal);
  461. SpecialDeviceReleaseReference(Device);
  462. IoCompleteIrp(SpecialDriver, Irp, STATUS_SUCCESS);
  463. return;
  464. }
  465. VOID
  466. SpecialDispatchIo (
  467. PIRP Irp,
  468. PVOID DeviceContext,
  469. PVOID IrpContext
  470. )
  471. /*++
  472. Routine Description:
  473. This routine handles I/O IRPs.
  474. Arguments:
  475. Irp - Supplies a pointer to the I/O request packet.
  476. DeviceContext - Supplies the context pointer supplied by the driver when it
  477. attached itself to the driver stack. Presumably this pointer contains
  478. driver-specific device context.
  479. IrpContext - Supplies the context pointer supplied by the driver when
  480. the IRP was created.
  481. Return Value:
  482. None.
  483. --*/
  484. {
  485. PSPECIAL_DEVICE Device;
  486. KSTATUS Status;
  487. ASSERT(Irp->MajorCode == IrpMajorIo);
  488. ASSERT(Irp->Direction == IrpDown);
  489. Device = (PSPECIAL_DEVICE)DeviceContext;
  490. switch (Device->Type) {
  491. //
  492. // The null device accepts and discards all input, and produces no output.
  493. //
  494. case SpecialDeviceNull:
  495. if (Irp->MinorCode == IrpMinorIoRead) {
  496. Irp->U.ReadWrite.IoBytesCompleted = 0;
  497. } else {
  498. ASSERT(Irp->MinorCode == IrpMinorIoWrite);
  499. Irp->U.ReadWrite.IoBytesCompleted = Irp->U.ReadWrite.IoSizeInBytes;
  500. }
  501. Status = STATUS_SUCCESS;
  502. break;
  503. //
  504. // The zero device accepts and discards all input, and produces a
  505. // continuous stream of zero bytes.
  506. //
  507. case SpecialDeviceZero:
  508. if (Irp->MinorCode == IrpMinorIoRead) {
  509. Status = SpecialFillZeroes(Irp);
  510. } else {
  511. ASSERT(Irp->MinorCode == IrpMinorIoWrite);
  512. Irp->U.ReadWrite.IoBytesCompleted = Irp->U.ReadWrite.IoSizeInBytes;
  513. Status = STATUS_SUCCESS;
  514. }
  515. break;
  516. //
  517. // The full device produces a continuous stream of zero bytes when read,
  518. // and returns "disk full" when written to.
  519. //
  520. case SpecialDeviceFull:
  521. if (Irp->MinorCode == IrpMinorIoRead) {
  522. Status = SpecialFillZeroes(Irp);
  523. } else {
  524. ASSERT(Irp->MinorCode == IrpMinorIoWrite);
  525. Status = STATUS_VOLUME_FULL;
  526. }
  527. break;
  528. //
  529. // The urandom device produces psuedo-random numbers when read, and adds
  530. // entropy when written to.
  531. //
  532. case SpecialDevicePseudoRandom:
  533. Status = SpecialPerformPseudoRandomIo(Device, Irp);
  534. break;
  535. default:
  536. ASSERT(FALSE);
  537. Status = STATUS_FILE_CORRUPT;
  538. break;
  539. }
  540. IoCompleteIrp(SpecialDriver, Irp, Status);
  541. return;
  542. }
  543. VOID
  544. SpecialDispatchSystemControl (
  545. PIRP Irp,
  546. PVOID DeviceContext,
  547. PVOID IrpContext
  548. )
  549. /*++
  550. Routine Description:
  551. This routine handles System Control IRPs.
  552. Arguments:
  553. Irp - Supplies a pointer to the I/O request packet.
  554. DeviceContext - Supplies the context pointer supplied by the driver when it
  555. attached itself to the driver stack. Presumably this pointer contains
  556. driver-specific device context.
  557. IrpContext - Supplies the context pointer supplied by the driver when
  558. the IRP was created.
  559. Return Value:
  560. None.
  561. --*/
  562. {
  563. PVOID Context;
  564. PSPECIAL_DEVICE Device;
  565. PSYSTEM_CONTROL_LOOKUP Lookup;
  566. PFILE_PROPERTIES Properties;
  567. KSTATUS Status;
  568. Device = (PSPECIAL_DEVICE)DeviceContext;
  569. Context = Irp->U.SystemControl.SystemContext;
  570. switch (Irp->MinorCode) {
  571. case IrpMinorSystemControlLookup:
  572. Lookup = (PSYSTEM_CONTROL_LOOKUP)Context;
  573. Status = STATUS_PATH_NOT_FOUND;
  574. if (Lookup->Root != FALSE) {
  575. //
  576. // Enable opening of the root as a single file.
  577. //
  578. Properties = Lookup->Properties;
  579. Properties->FileId = 0;
  580. Properties->Type = IoObjectCharacterDevice;
  581. Properties->HardLinkCount = 1;
  582. Properties->BlockSize = 1;
  583. Properties->BlockCount = 0;
  584. Properties->UserId = 0;
  585. Properties->GroupId = 0;
  586. Properties->StatusChangeTime = Device->CreationTime;
  587. Properties->ModifiedTime = Properties->StatusChangeTime;
  588. Properties->AccessTime = Properties->StatusChangeTime;
  589. Properties->Permissions = FILE_PERMISSION_ALL;
  590. Properties->Size = 0;
  591. Status = STATUS_SUCCESS;
  592. }
  593. IoCompleteIrp(SpecialDriver, Irp, Status);
  594. break;
  595. //
  596. // Succeed for the basics.
  597. //
  598. case IrpMinorSystemControlWriteFileProperties:
  599. case IrpMinorSystemControlTruncate:
  600. Status = STATUS_SUCCESS;
  601. IoCompleteIrp(SpecialDriver, Irp, Status);
  602. break;
  603. //
  604. // Ignore everything unrecognized.
  605. //
  606. default:
  607. ASSERT(FALSE);
  608. break;
  609. }
  610. return;
  611. }
  612. VOID
  613. SpecialDispatchUserControl (
  614. PIRP Irp,
  615. PVOID DeviceContext,
  616. PVOID IrpContext
  617. )
  618. /*++
  619. Routine Description:
  620. This routine handles User Control IRPs.
  621. Arguments:
  622. Irp - Supplies a pointer to the I/O request packet.
  623. DeviceContext - Supplies the context pointer supplied by the driver when it
  624. attached itself to the driver stack. Presumably this pointer contains
  625. driver-specific device context.
  626. IrpContext - Supplies the context pointer supplied by the driver when
  627. the IRP was created.
  628. Return Value:
  629. None.
  630. --*/
  631. {
  632. return;
  633. }
  634. KSTATUS
  635. SpecialFillZeroes (
  636. PIRP Irp
  637. )
  638. /*++
  639. Routine Description:
  640. This routine fills a read buffer with zeroes.
  641. Arguments:
  642. Irp - Supplies a pointer to the I/O request packet.
  643. Return Value:
  644. Status code.
  645. --*/
  646. {
  647. KSTATUS Status;
  648. ASSERT(Irp->MinorCode == IrpMinorIoRead);
  649. ASSERT(Irp->U.ReadWrite.IoBuffer != NULL);
  650. Status = MmZeroIoBuffer(Irp->U.ReadWrite.IoBuffer,
  651. 0,
  652. Irp->U.ReadWrite.IoSizeInBytes);
  653. if (!KSUCCESS(Status)) {
  654. return Status;
  655. }
  656. Irp->U.ReadWrite.IoBytesCompleted = Irp->U.ReadWrite.IoSizeInBytes;
  657. return STATUS_SUCCESS;
  658. }
  659. KSTATUS
  660. SpecialPseudoRandomStartDevice (
  661. PSPECIAL_DEVICE Device,
  662. PIRP Irp
  663. )
  664. /*++
  665. Routine Description:
  666. This routine starts a urandom device.
  667. Arguments:
  668. Device - Supplies a pointer to the special device context.
  669. Irp - Supplies a pointer to the request.
  670. Return Value:
  671. Status code.
  672. --*/
  673. {
  674. PSPECIAL_PSEUDO_RANDOM_DEVICE PseudoRandom;
  675. KSTATUS Status;
  676. ASSERT(Device->Type == SpecialDevicePseudoRandom);
  677. PseudoRandom = Device->U.PseudoRandom;
  678. if (PseudoRandom->InterfaceRegistered != FALSE) {
  679. return STATUS_SUCCESS;
  680. }
  681. Status = IoCreateInterface(&SpecialPseudoRandomInterfaceUuid,
  682. Irp->Device,
  683. &(PseudoRandom->Interface),
  684. sizeof(INTERFACE_PSEUDO_RANDOM_SOURCE));
  685. if (KSUCCESS(Status)) {
  686. PseudoRandom->InterfaceRegistered = TRUE;
  687. }
  688. //
  689. // Seed the generator with at least this somewhat random point in time.
  690. //
  691. SpecialPseudoRandomAddTimePointEntropy(&(PseudoRandom->Interface));
  692. return Status;
  693. }
  694. KSTATUS
  695. SpecialPseudoRandomRemoveDevice (
  696. PSPECIAL_DEVICE Device,
  697. PIRP Irp
  698. )
  699. /*++
  700. Routine Description:
  701. This routine stops a urandom device.
  702. Arguments:
  703. Device - Supplies a pointer to the special device context.
  704. Irp - Supplies a pointer to the request.
  705. Return Value:
  706. Status code.
  707. --*/
  708. {
  709. PSPECIAL_PSEUDO_RANDOM_DEVICE PseudoRandom;
  710. KSTATUS Status;
  711. ASSERT(Device->Type == SpecialDevicePseudoRandom);
  712. PseudoRandom = Device->U.PseudoRandom;
  713. if (PseudoRandom->InterfaceRegistered == FALSE) {
  714. return STATUS_SUCCESS;
  715. }
  716. Status = IoDestroyInterface(&SpecialPseudoRandomInterfaceUuid,
  717. Irp->Device,
  718. &(PseudoRandom->Interface));
  719. if (KSUCCESS(Status)) {
  720. PseudoRandom->InterfaceRegistered = FALSE;
  721. }
  722. return Status;
  723. }
  724. KSTATUS
  725. SpecialPerformPseudoRandomIo (
  726. PSPECIAL_DEVICE Device,
  727. PIRP Irp
  728. )
  729. /*++
  730. Routine Description:
  731. This routine fills a buffer with random data, or adds entropy to the pools.
  732. Arguments:
  733. Device - Supplies a pointer to the special device context.
  734. Irp - Supplies a pointer to the I/O request packet.
  735. Return Value:
  736. Status code.
  737. --*/
  738. {
  739. PVOID Buffer;
  740. UINTN BytesRemaining;
  741. PFORTUNA_CONTEXT Fortuna;
  742. PIO_BUFFER IoBuffer;
  743. UINTN IoBufferOffset;
  744. RUNLEVEL OldRunLevel;
  745. PSPECIAL_PSEUDO_RANDOM_DEVICE PseudoRandom;
  746. UINTN Size;
  747. KSTATUS Status;
  748. ASSERT(Irp->U.ReadWrite.IoBuffer != NULL);
  749. IoBuffer = Irp->U.ReadWrite.IoBuffer;
  750. IoBufferOffset = 0;
  751. BytesRemaining = Irp->U.ReadWrite.IoSizeInBytes;
  752. //
  753. // Allocate a non-paged buffer because acquiring the lock raises to
  754. // dispatch level, since entropy can be added at dispatch.
  755. //
  756. Buffer = MmAllocateNonPagedPool(SPECIAL_URANDOM_BUFFER_SIZE,
  757. SPECIAL_DEVICE_ALLOCATION_TAG);
  758. if (Buffer == NULL) {
  759. Status = STATUS_INSUFFICIENT_RESOURCES;
  760. goto PerformPseudoRandomIoEnd;
  761. }
  762. PseudoRandom = Device->U.PseudoRandom;
  763. Fortuna = &(PseudoRandom->FortunaContext);
  764. while (BytesRemaining != 0) {
  765. Size = SPECIAL_URANDOM_BUFFER_SIZE;
  766. if (Size > BytesRemaining) {
  767. Size = BytesRemaining;
  768. }
  769. if (Irp->MinorCode == IrpMinorIoWrite) {
  770. Status = MmCopyIoBufferData(IoBuffer,
  771. Buffer,
  772. IoBufferOffset,
  773. Size,
  774. FALSE);
  775. if (!KSUCCESS(Status)) {
  776. goto PerformPseudoRandomIoEnd;
  777. }
  778. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  779. KeAcquireSpinLock(&(PseudoRandom->Lock));
  780. CyFortunaAddEntropy(Fortuna, Buffer, Size);
  781. KeReleaseSpinLock(&(PseudoRandom->Lock));
  782. KeLowerRunLevel(OldRunLevel);
  783. } else {
  784. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  785. KeAcquireSpinLock(&(PseudoRandom->Lock));
  786. CyFortunaGetRandomBytes(Fortuna, Buffer, Size);
  787. KeReleaseSpinLock(&(PseudoRandom->Lock));
  788. KeLowerRunLevel(OldRunLevel);
  789. Status = MmCopyIoBufferData(IoBuffer,
  790. Buffer,
  791. IoBufferOffset,
  792. Size,
  793. TRUE);
  794. if (!KSUCCESS(Status)) {
  795. goto PerformPseudoRandomIoEnd;
  796. }
  797. }
  798. BytesRemaining -= Size;
  799. IoBufferOffset += Size;
  800. }
  801. Status = STATUS_SUCCESS;
  802. PerformPseudoRandomIoEnd:
  803. if (Buffer != NULL) {
  804. MmFreeNonPagedPool(Buffer);
  805. }
  806. Irp->U.ReadWrite.IoBytesCompleted = Irp->U.ReadWrite.IoSizeInBytes -
  807. BytesRemaining;
  808. return Status;
  809. }
  810. VOID
  811. SpecialPseudoRandomAddEntropy (
  812. PINTERFACE_PSEUDO_RANDOM_SOURCE Interface,
  813. PVOID Data,
  814. UINTN Length
  815. )
  816. /*++
  817. Routine Description:
  818. This routine adds entropy to a pseudo-random device. This function can be
  819. called at or below dispatch level.
  820. Arguments:
  821. Interface - Supplies a pointer to the interface instance.
  822. Data - Supplies a pointer to the entropy data to add. This data must be
  823. non-paged.
  824. Length - Supplies the number of bytes in the data.
  825. Return Value:
  826. None.
  827. --*/
  828. {
  829. PSPECIAL_DEVICE Device;
  830. RUNLEVEL OldRunLevel;
  831. PSPECIAL_PSEUDO_RANDOM_DEVICE PseudoRandom;
  832. Device = Interface->DeviceToken;
  833. ASSERT(Device->Type == SpecialDevicePseudoRandom);
  834. PseudoRandom = Device->U.PseudoRandom;
  835. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  836. KeAcquireSpinLock(&(PseudoRandom->Lock));
  837. CyFortunaAddEntropy(&(PseudoRandom->FortunaContext), Data, Length);
  838. KeReleaseSpinLock(&(PseudoRandom->Lock));
  839. KeLowerRunLevel(OldRunLevel);
  840. return;
  841. }
  842. VOID
  843. SpecialPseudoRandomAddTimePointEntropy (
  844. PINTERFACE_PSEUDO_RANDOM_SOURCE Interface
  845. )
  846. /*++
  847. Routine Description:
  848. This routine adds entropy to a pseudo-random device based on the fact that
  849. this current moment in time is a random one. Said differently, it adds
  850. entropy based on the current timestamp, with the assumption that this
  851. function is called by a source that generates such events randomly. This
  852. function can be called at or below dispatch level.
  853. Arguments:
  854. Interface - Supplies a pointer to the interface instance.
  855. Return Value:
  856. None.
  857. --*/
  858. {
  859. ULONGLONG Counter;
  860. PSPECIAL_DEVICE Device;
  861. RUNLEVEL OldRunLevel;
  862. PSPECIAL_PSEUDO_RANDOM_DEVICE PseudoRandom;
  863. Device = Interface->DeviceToken;
  864. ASSERT(Device->Type == SpecialDevicePseudoRandom);
  865. PseudoRandom = Device->U.PseudoRandom;
  866. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  867. Counter = HlQueryProcessorCounter();
  868. KeAcquireSpinLock(&(PseudoRandom->Lock));
  869. CyFortunaAddEntropy(&(PseudoRandom->FortunaContext),
  870. &Counter,
  871. sizeof(ULONGLONG));
  872. KeReleaseSpinLock(&(PseudoRandom->Lock));
  873. KeLowerRunLevel(OldRunLevel);
  874. return;
  875. }
  876. VOID
  877. SpecialPseudoRandomGetBytes (
  878. PINTERFACE_PSEUDO_RANDOM_SOURCE Interface,
  879. PVOID Data,
  880. UINTN Length
  881. )
  882. /*++
  883. Routine Description:
  884. This routine gets random data from a pseudo-random number generator. This
  885. function can be called at or below dispatch level.
  886. Arguments:
  887. Interface - Supplies a pointer to the interface instance.
  888. Data - Supplies a pointer where the random data will be returned. This
  889. buffer must be non-paged.
  890. Length - Supplies the number of bytes of random data to return.
  891. Return Value:
  892. None.
  893. --*/
  894. {
  895. PSPECIAL_DEVICE Device;
  896. RUNLEVEL OldRunLevel;
  897. PSPECIAL_PSEUDO_RANDOM_DEVICE PseudoRandom;
  898. Device = Interface->DeviceToken;
  899. ASSERT(Device->Type == SpecialDevicePseudoRandom);
  900. PseudoRandom = Device->U.PseudoRandom;
  901. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  902. KeAcquireSpinLock(&(PseudoRandom->Lock));
  903. CyFortunaGetRandomBytes(&(PseudoRandom->FortunaContext), Data, Length);
  904. KeReleaseSpinLock(&(PseudoRandom->Lock));
  905. KeLowerRunLevel(OldRunLevel);
  906. return;
  907. }
  908. VOID
  909. SpecialDeviceAddReference (
  910. PSPECIAL_DEVICE Device
  911. )
  912. /*++
  913. Routine Description:
  914. This routine adds a reference on a special device.
  915. Arguments:
  916. Device - Supplies a pointer to a special device.
  917. Return Value:
  918. None.
  919. --*/
  920. {
  921. ULONG OldReferenceCount;
  922. OldReferenceCount = RtlAtomicAdd32(&(Device->ReferenceCount), 1);
  923. ASSERT(OldReferenceCount < 0x10000000);
  924. return;
  925. }
  926. VOID
  927. SpecialDeviceReleaseReference (
  928. PSPECIAL_DEVICE Device
  929. )
  930. /*++
  931. Routine Description:
  932. This routine releases a reference on a special device.
  933. Arguments:
  934. Device - Supplies a pointer to a special device.
  935. Return Value:
  936. None.
  937. --*/
  938. {
  939. ULONG OldReferenceCount;
  940. OldReferenceCount = RtlAtomicAdd32(&(Device->ReferenceCount), (ULONG)-1);
  941. ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));
  942. if (OldReferenceCount == 1) {
  943. SpecialDestroyDevice(Device);
  944. }
  945. return;
  946. }
  947. VOID
  948. SpecialDestroyDevice (
  949. PSPECIAL_DEVICE Device
  950. )
  951. /*++
  952. Routine Description:
  953. This routine destroys a special device.
  954. Arguments:
  955. Device - Supplies a pointer to a special device.
  956. Return Value:
  957. None.
  958. --*/
  959. {
  960. ASSERT(Device->U.PseudoRandom->InterfaceRegistered == FALSE);
  961. if (Device->Type == SpecialDevicePseudoRandom) {
  962. MmFreeNonPagedPool(Device);
  963. } else {
  964. MmFreePagedPool(Device);
  965. }
  966. return;
  967. }