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.

651 lines
18 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. psctx.c
  5. Abstract:
  6. This procedure implements Get/Set Context Thread
  7. Author:
  8. Mark Lucovsky (markl) 25-May-1989
  9. Revision History:
  10. --*/
  11. #include "psp.h"
  12. VOID
  13. PspQueueApcSpecialApc(
  14. IN PKAPC Apc,
  15. IN PKNORMAL_ROUTINE *NormalRoutine,
  16. IN PVOID *NormalContext,
  17. IN PVOID *SystemArgument1,
  18. IN PVOID *SystemArgument2
  19. );
  20. #ifdef ALLOC_PRAGMA
  21. #pragma alloc_text(PAGE, NtGetContextThread)
  22. #pragma alloc_text(PAGE, NtSetContextThread)
  23. #pragma alloc_text(PAGE, PsGetContextThread)
  24. #pragma alloc_text(PAGE, PsSetContextThread)
  25. #pragma alloc_text(PAGE, NtQueueApcThread)
  26. #pragma alloc_text(PAGE, PspQueueApcSpecialApc)
  27. #endif
  28. VOID
  29. PspQueueApcSpecialApc(
  30. IN PKAPC Apc,
  31. IN PKNORMAL_ROUTINE *NormalRoutine,
  32. IN PVOID *NormalContext,
  33. IN PVOID *SystemArgument1,
  34. IN PVOID *SystemArgument2
  35. )
  36. {
  37. PAGED_CODE();
  38. UNREFERENCED_PARAMETER (NormalRoutine);
  39. UNREFERENCED_PARAMETER (NormalContext);
  40. UNREFERENCED_PARAMETER (SystemArgument1);
  41. UNREFERENCED_PARAMETER (SystemArgument2);
  42. ExFreePool(Apc);
  43. }
  44. NTSYSAPI
  45. NTSTATUS
  46. NTAPI
  47. NtQueueApcThread(
  48. IN HANDLE ThreadHandle,
  49. IN PPS_APC_ROUTINE ApcRoutine,
  50. IN PVOID ApcArgument1,
  51. IN PVOID ApcArgument2,
  52. IN PVOID ApcArgument3
  53. )
  54. /*++
  55. Routine Description:
  56. This function is used to queue a user-mode APC to the specified thread. The APC
  57. will fire when the specified thread does an alertable wait
  58. Arguments:
  59. ThreadHandle - Supplies a handle to a thread object. The caller
  60. must have THREAD_SET_CONTEXT access to the thread.
  61. ApcRoutine - Supplies the address of the APC routine to execute when the
  62. APC fires.
  63. ApcArgument1 - Supplies the first PVOID passed to the APC
  64. ApcArgument2 - Supplies the second PVOID passed to the APC
  65. ApcArgument3 - Supplies the third PVOID passed to the APC
  66. Return Value:
  67. Returns an NT Status code indicating success or failure of the API
  68. --*/
  69. {
  70. PETHREAD Thread;
  71. NTSTATUS st;
  72. KPROCESSOR_MODE Mode;
  73. PKAPC Apc;
  74. PAGED_CODE();
  75. Mode = KeGetPreviousMode ();
  76. st = ObReferenceObjectByHandle (ThreadHandle,
  77. THREAD_SET_CONTEXT,
  78. PsThreadType,
  79. Mode,
  80. &Thread,
  81. NULL);
  82. if (NT_SUCCESS (st)) {
  83. st = STATUS_SUCCESS;
  84. if (IS_SYSTEM_THREAD (Thread)) {
  85. st = STATUS_INVALID_HANDLE;
  86. } else {
  87. Apc = ExAllocatePoolWithQuotaTag (NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
  88. sizeof(*Apc),
  89. 'pasP');
  90. if (Apc == NULL) {
  91. st = STATUS_NO_MEMORY;
  92. } else {
  93. KeInitializeApc (Apc,
  94. &Thread->Tcb,
  95. OriginalApcEnvironment,
  96. PspQueueApcSpecialApc,
  97. NULL,
  98. (PKNORMAL_ROUTINE)ApcRoutine,
  99. UserMode,
  100. ApcArgument1);
  101. if (!KeInsertQueueApc (Apc, ApcArgument2, ApcArgument3, 0)) {
  102. ExFreePool (Apc);
  103. st = STATUS_UNSUCCESSFUL;
  104. }
  105. }
  106. }
  107. ObDereferenceObject (Thread);
  108. }
  109. return st;
  110. }
  111. NTSTATUS
  112. PsGetContextThread(
  113. IN PETHREAD Thread,
  114. IN OUT PCONTEXT ThreadContext,
  115. IN KPROCESSOR_MODE Mode
  116. )
  117. /*++
  118. Routine Description:
  119. This function returns the usermode context of the specified thread. This
  120. function will fail if the specified thread is a system thread. It will
  121. return the wrong answer if the thread is a non-system thread that does
  122. not execute in user-mode.
  123. Arguments:
  124. Thread - Supplies a pointer to the thread object from
  125. which to retrieve context information.
  126. ThreadContext - Supplies the address of a buffer that will receive
  127. the context of the specified thread.
  128. Mode - Mode to use for validation checks.
  129. Return Value:
  130. None.
  131. --*/
  132. {
  133. ULONG ContextFlags=0;
  134. GETSETCONTEXT ContextFrame = {0};
  135. ULONG ContextLength=0;
  136. NTSTATUS Status;
  137. PETHREAD CurrentThread;
  138. PAGED_CODE();
  139. Status = STATUS_SUCCESS;
  140. //
  141. // Get previous mode and reference specified thread.
  142. //
  143. CurrentThread = PsGetCurrentThread ();
  144. //
  145. // Attempt to get the context of the specified thread.
  146. //
  147. try {
  148. //
  149. // Set the default alignment, capture the context flags,
  150. // and set the default size of the context record.
  151. //
  152. if (Mode != KernelMode) {
  153. ProbeForReadSmallStructure (ThreadContext,
  154. FIELD_OFFSET (CONTEXT, ContextFlags) + sizeof (ThreadContext->ContextFlags),
  155. CONTEXT_ALIGN);
  156. }
  157. ContextFlags = ThreadContext->ContextFlags;
  158. //
  159. // We don't need to re-probe here so long as the structure is smaller
  160. // than the guard region
  161. //
  162. ContextLength = sizeof(CONTEXT);
  163. ASSERT (ContextLength < 0x10000);
  164. #if defined(_X86_)
  165. //
  166. // CONTEXT_EXTENDED_REGISTERS is SET, then we want sizeof(CONTEXT) set above
  167. // otherwise (not set) we only want the old part of the context record.
  168. //
  169. if ((ContextFlags & CONTEXT_EXTENDED_REGISTERS) != CONTEXT_EXTENDED_REGISTERS) {
  170. ContextLength = FIELD_OFFSET(CONTEXT, ExtendedRegisters);
  171. }
  172. #endif
  173. } except (EXCEPTION_EXECUTE_HANDLER) {
  174. return GetExceptionCode ();
  175. }
  176. KeInitializeEvent (&ContextFrame.OperationComplete,
  177. NotificationEvent,
  178. FALSE);
  179. ContextFrame.Context.ContextFlags = ContextFlags;
  180. ContextFrame.Mode = Mode;
  181. if (Thread == CurrentThread) {
  182. ContextFrame.Apc.SystemArgument1 = NULL;
  183. ContextFrame.Apc.SystemArgument2 = Thread;
  184. KeEnterGuardedRegionThread (&CurrentThread->Tcb);
  185. PspGetSetContextSpecialApc (&ContextFrame.Apc,
  186. NULL,
  187. NULL,
  188. &ContextFrame.Apc.SystemArgument1,
  189. &ContextFrame.Apc.SystemArgument2);
  190. KeLeaveGuardedRegionThread (&CurrentThread->Tcb);
  191. //
  192. // Move context to specfied context record. If an exception
  193. // occurs, then return the error.
  194. //
  195. try {
  196. RtlCopyMemory (ThreadContext,
  197. &ContextFrame.Context,
  198. ContextLength);
  199. } except (EXCEPTION_EXECUTE_HANDLER) {
  200. Status = GetExceptionCode ();
  201. }
  202. } else {
  203. KeInitializeApc (&ContextFrame.Apc,
  204. &Thread->Tcb,
  205. OriginalApcEnvironment,
  206. PspGetSetContextSpecialApc,
  207. NULL,
  208. NULL,
  209. KernelMode,
  210. NULL);
  211. if (!KeInsertQueueApc (&ContextFrame.Apc, NULL, Thread, 2)) {
  212. Status = STATUS_UNSUCCESSFUL;
  213. } else {
  214. KeWaitForSingleObject (&ContextFrame.OperationComplete,
  215. Executive,
  216. KernelMode,
  217. FALSE,
  218. NULL);
  219. //
  220. // Move context to specfied context record. If an
  221. // exception occurs, then silently handle it and
  222. // return success.
  223. //
  224. try {
  225. RtlCopyMemory (ThreadContext,
  226. &ContextFrame.Context,
  227. ContextLength);
  228. } except (EXCEPTION_EXECUTE_HANDLER) {
  229. Status = GetExceptionCode ();
  230. }
  231. }
  232. }
  233. return Status;
  234. }
  235. NTSTATUS
  236. NtGetContextThread(
  237. IN HANDLE ThreadHandle,
  238. IN OUT PCONTEXT ThreadContext
  239. )
  240. /*++
  241. Routine Description:
  242. This function returns the usermode context of the specified thread. This
  243. function will fail if the specified thread is a system thread. It will
  244. return the wrong answer if the thread is a non-system thread that does
  245. not execute in user-mode.
  246. Arguments:
  247. ThreadHandle - Supplies an open handle to the thread object from
  248. which to retrieve context information. The handle
  249. must allow THREAD_GET_CONTEXT access to the thread.
  250. ThreadContext - Supplies the address of a buffer that will receive
  251. the context of the specified thread.
  252. Return Value:
  253. None.
  254. --*/
  255. {
  256. KPROCESSOR_MODE Mode;
  257. NTSTATUS Status;
  258. PETHREAD Thread;
  259. PETHREAD CurrentThread;
  260. PAGED_CODE();
  261. //
  262. // Get previous mode and reference specified thread.
  263. //
  264. CurrentThread = PsGetCurrentThread ();
  265. Mode = KeGetPreviousModeByThread (&CurrentThread->Tcb);
  266. Status = ObReferenceObjectByHandle (ThreadHandle,
  267. THREAD_GET_CONTEXT,
  268. PsThreadType,
  269. Mode,
  270. &Thread,
  271. NULL);
  272. //
  273. // If the reference was successful, the check if the specified thread
  274. // is a system thread.
  275. //
  276. if (NT_SUCCESS (Status)) {
  277. //
  278. // If the thread is not a system thread, then attempt to get the
  279. // context of the thread.
  280. //
  281. if (IS_SYSTEM_THREAD (Thread) == FALSE) {
  282. Status = PsGetContextThread (Thread, ThreadContext, Mode);
  283. } else {
  284. Status = STATUS_INVALID_HANDLE;
  285. }
  286. ObDereferenceObject (Thread);
  287. }
  288. return Status;
  289. }
  290. NTSTATUS
  291. PsSetContextThread(
  292. IN PETHREAD Thread,
  293. IN PCONTEXT ThreadContext,
  294. IN KPROCESSOR_MODE Mode
  295. )
  296. /*++
  297. Routine Description:
  298. This function sets the usermode context of the specified thread. This
  299. function will fail if the specified thread is a system thread. It will
  300. return the wrong answer if the thread is a non-system thread that does
  301. not execute in user-mode.
  302. Arguments:
  303. Thread - Supplies the thread object from
  304. which to retrieve context information.
  305. ThreadContext - Supplies the address of a buffer that contains new
  306. context for the specified thread.
  307. Mode - Mode to use for validation checks.
  308. Return Value:
  309. None.
  310. --*/
  311. {
  312. ULONG ContextFlags=0;
  313. GETSETCONTEXT ContextFrame;
  314. ULONG ContextLength=0;
  315. NTSTATUS Status;
  316. PETHREAD CurrentThread;
  317. PAGED_CODE();
  318. Status = STATUS_SUCCESS;
  319. //
  320. // Get previous mode and reference specified thread.
  321. //
  322. CurrentThread = PsGetCurrentThread ();
  323. //
  324. // Attempt to get the context of the specified thread.
  325. //
  326. try {
  327. //
  328. // Capture the context flags,
  329. // and set the default size of the context record.
  330. //
  331. if (Mode != KernelMode) {
  332. ProbeForReadSmallStructure (ThreadContext,
  333. FIELD_OFFSET (CONTEXT, ContextFlags) + sizeof (ThreadContext->ContextFlags),
  334. CONTEXT_ALIGN);
  335. }
  336. //
  337. // We don't need to re-probe here so long as the structure is small
  338. // enough not to cross the guard region.
  339. //
  340. ContextFlags = ThreadContext->ContextFlags;
  341. ContextLength = sizeof (CONTEXT);
  342. ASSERT (ContextLength < 0x10000);
  343. #if defined(_X86_)
  344. //
  345. // CONTEXT_EXTENDED_REGISTERS is SET, then we want sizeof(CONTEXT) set above
  346. // otherwise (not set) we only want the old part of the context record.
  347. //
  348. if ((ContextFlags & CONTEXT_EXTENDED_REGISTERS) != CONTEXT_EXTENDED_REGISTERS) {
  349. ContextLength = FIELD_OFFSET(CONTEXT, ExtendedRegisters);
  350. }
  351. #endif
  352. RtlCopyMemory (&ContextFrame.Context, ThreadContext, ContextLength);
  353. } except (EXCEPTION_EXECUTE_HANDLER) {
  354. return GetExceptionCode ();
  355. }
  356. //
  357. // set the context of the target thread.
  358. //
  359. #if defined (_IA64_)
  360. //
  361. // On IA64 we need to fix up the PC if its a PLABEL address.
  362. //
  363. if ((ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) {
  364. PLABEL_DESCRIPTOR Label, *LabelAddress;
  365. SIZE_T BytesCopied;
  366. if (ContextFrame.Context.IntGp == 0) {
  367. LabelAddress = (PPLABEL_DESCRIPTOR)ContextFrame.Context.StIIP;
  368. try {
  369. //
  370. // We are in the wrong process here but it doesn't matter.
  371. // We just want to make sure this isn't a kernel address.
  372. //
  373. ProbeForReadSmallStructure (LabelAddress,
  374. sizeof (*LabelAddress),
  375. sizeof (ULONGLONG));
  376. } except (EXCEPTION_EXECUTE_HANDLER) {
  377. return GetExceptionCode ();
  378. }
  379. Status = MmCopyVirtualMemory (THREAD_TO_PROCESS (Thread),
  380. LabelAddress,
  381. PsGetCurrentProcessByThread (CurrentThread),
  382. &Label,
  383. sizeof (Label),
  384. KernelMode, // Needed to write to local stack
  385. &BytesCopied);
  386. if (NT_SUCCESS (Status)) {
  387. ContextFrame.Context.IntGp = Label.GlobalPointer;
  388. ContextFrame.Context.StIIP = Label.EntryPoint;
  389. ContextFrame.Context.StIPSR &= ~ISR_EI_MASK;
  390. } else {
  391. return Status;
  392. }
  393. }
  394. }
  395. #endif
  396. KeInitializeEvent (&ContextFrame.OperationComplete,
  397. NotificationEvent,
  398. FALSE);
  399. ContextFrame.Context.ContextFlags = ContextFlags;
  400. ContextFrame.Mode = Mode;
  401. if (Thread == CurrentThread) {
  402. ContextFrame.Apc.SystemArgument1 = (PVOID)1;
  403. ContextFrame.Apc.SystemArgument2 = Thread;
  404. KeEnterGuardedRegionThread (&CurrentThread->Tcb);
  405. PspGetSetContextSpecialApc (&ContextFrame.Apc,
  406. NULL,
  407. NULL,
  408. &ContextFrame.Apc.SystemArgument1,
  409. &ContextFrame.Apc.SystemArgument2);
  410. KeLeaveGuardedRegionThread (&CurrentThread->Tcb);
  411. } else {
  412. KeInitializeApc (&ContextFrame.Apc,
  413. &Thread->Tcb,
  414. OriginalApcEnvironment,
  415. PspGetSetContextSpecialApc,
  416. NULL,
  417. NULL,
  418. KernelMode,
  419. NULL);
  420. if (!KeInsertQueueApc (&ContextFrame.Apc, (PVOID)1, Thread, 2)) {
  421. Status = STATUS_UNSUCCESSFUL;
  422. } else {
  423. KeWaitForSingleObject (&ContextFrame.OperationComplete,
  424. Executive,
  425. KernelMode,
  426. FALSE,
  427. NULL);
  428. }
  429. }
  430. return Status;
  431. }
  432. NTSTATUS
  433. NtSetContextThread(
  434. IN HANDLE ThreadHandle,
  435. IN PCONTEXT ThreadContext
  436. )
  437. /*++
  438. Routine Description:
  439. This function sets the usermode context of the specified thread. This
  440. function will fail if the specified thread is a system thread. It will
  441. return the wrong answer if the thread is a non-system thread that does
  442. not execute in user-mode.
  443. Arguments:
  444. ThreadHandle - Supplies an open handle to the thread object from
  445. which to retrieve context information. The handle
  446. must allow THREAD_SET_CONTEXT access to the thread.
  447. ThreadContext - Supplies the address of a buffer that contains new
  448. context for the specified thread.
  449. Return Value:
  450. None.
  451. --*/
  452. {
  453. KPROCESSOR_MODE Mode;
  454. NTSTATUS Status;
  455. PETHREAD Thread;
  456. PETHREAD CurrentThread;
  457. PAGED_CODE();
  458. //
  459. // Get previous mode and reference specified thread.
  460. //
  461. CurrentThread = PsGetCurrentThread ();
  462. Mode = KeGetPreviousModeByThread (&CurrentThread->Tcb);
  463. Status = ObReferenceObjectByHandle (ThreadHandle,
  464. THREAD_SET_CONTEXT,
  465. PsThreadType,
  466. Mode,
  467. &Thread,
  468. NULL);
  469. //
  470. // If the reference was successful, the check if the specified thread
  471. // is a system thread.
  472. //
  473. if (NT_SUCCESS (Status)) {
  474. //
  475. // If the thread is not a system thread, then attempt to get the
  476. // context of the thread.
  477. //
  478. if (IS_SYSTEM_THREAD (Thread) == FALSE) {
  479. Status = PsSetContextThread (Thread, ThreadContext, Mode);
  480. } else {
  481. Status = STATUS_INVALID_HANDLE;
  482. }
  483. ObDereferenceObject (Thread);
  484. }
  485. return Status;
  486. }