perm.c 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. perm.c
  5. Abstract:
  6. This module implements support routines for thread permission and identity
  7. management.
  8. Author:
  9. Evan Green 4-Dec-2014
  10. Environment:
  11. Kernel
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <minoca/kernel/kernel.h>
  17. #include "psp.h"
  18. //
  19. // This macro evaluates to non-zero if the given user ID matches any of
  20. // the real user ID, effective user ID, or saved user ID of the given identity.
  21. //
  22. #define MATCHES_IDENTITY_USER(_UserId, _Identity) \
  23. (((_UserId) == ((_Identity)->RealUserId)) || \
  24. ((_UserId) == ((_Identity)->EffectiveUserId)) || \
  25. ((_UserId) == ((_Identity)->SavedUserId)))
  26. //
  27. // This macro evaluates to non-zero if the given group ID matches any of the
  28. // real group ID, effective group ID, or saved group ID of the given identity.
  29. //
  30. #define MATCHES_IDENTITY_GROUP(_GroupId, _Identity) \
  31. (((_GroupId) == ((_Identity)->RealGroupId)) || \
  32. ((_GroupId) == ((_Identity)->EffectiveGroupId)) || \
  33. ((_GroupId) == ((_Identity)->SavedGroupId)))
  34. //
  35. // ---------------------------------------------------------------- Definitions
  36. //
  37. //
  38. // ------------------------------------------------------ Data Type Definitions
  39. //
  40. //
  41. // ----------------------------------------------- Internal Function Prototypes
  42. //
  43. KSTATUS
  44. PspSetThreadIdentity (
  45. ULONG FieldsToSet,
  46. PTHREAD_IDENTITY Identity
  47. );
  48. KSTATUS
  49. PspSetThreadPermissions (
  50. ULONG FieldsToSet,
  51. PTHREAD_PERMISSIONS Permissions
  52. );
  53. //
  54. // -------------------------------------------------------------------- Globals
  55. //
  56. //
  57. // ------------------------------------------------------------------ Functions
  58. //
  59. KERNEL_API
  60. KSTATUS
  61. PsCheckPermission (
  62. ULONG Permission
  63. )
  64. /*++
  65. Routine Description:
  66. This routine checks to see if the calling thread currently has the given
  67. permission.
  68. Arguments:
  69. Permission - Supplies the permission number to check. See PERMISSION_*
  70. definitions.
  71. Return Value:
  72. STATUS_SUCCESS if the current thread has the given permission.
  73. STATUS_PERMISSION_DENIED if the thread does not have the given permission.
  74. --*/
  75. {
  76. PKTHREAD Thread;
  77. Thread = KeGetCurrentThread();
  78. if (PERMISSION_CHECK(Thread->Permissions.Effective, Permission)) {
  79. return STATUS_SUCCESS;
  80. }
  81. return STATUS_PERMISSION_DENIED;
  82. }
  83. BOOL
  84. PsIsUserInGroup (
  85. GROUP_ID Group
  86. )
  87. /*++
  88. Routine Description:
  89. This routine determines if the given group ID matches the effective
  90. group ID or any of the supplementary group IDs of the calling thread. The
  91. current thread must not be a kernel thread.
  92. Arguments:
  93. Group - Supplies the group ID to check against.
  94. Return Value:
  95. TRUE if the calling thread is a member of the given group.
  96. FALSE if the calling thread is not a member of the given group.
  97. --*/
  98. {
  99. UINTN GroupIndex;
  100. PSUPPLEMENTARY_GROUPS SupplementaryGroups;
  101. PKTHREAD Thread;
  102. Thread = KeGetCurrentThread();
  103. if ((Thread->Flags & THREAD_FLAG_USER_MODE) == 0) {
  104. ASSERT(FALSE);
  105. return FALSE;
  106. }
  107. if (Thread->Identity.EffectiveGroupId == Group) {
  108. return TRUE;
  109. }
  110. SupplementaryGroups = Thread->SupplementaryGroups;
  111. while (SupplementaryGroups != NULL) {
  112. for (GroupIndex = 0;
  113. GroupIndex < SupplementaryGroups->Count;
  114. GroupIndex += 1) {
  115. if (Group == SupplementaryGroups->Groups[GroupIndex]) {
  116. return TRUE;
  117. }
  118. }
  119. SupplementaryGroups = SupplementaryGroups->Next;
  120. }
  121. return FALSE;
  122. }
  123. VOID
  124. PsSysSetThreadIdentity (
  125. ULONG SystemCallNumber,
  126. PVOID SystemCallParameter,
  127. PTRAP_FRAME TrapFrame,
  128. PULONG ResultSize
  129. )
  130. /*++
  131. Routine Description:
  132. This routine implements the get/set thread identity system call.
  133. Arguments:
  134. SystemCallNumber - Supplies the system call number that was requested.
  135. SystemCallParameter - Supplies a pointer to the parameters supplied with
  136. the system call. This structure will be a stack-local copy of the
  137. actual parameters passed from user-mode.
  138. TrapFrame - Supplies a pointer to the trap frame generated by this jump
  139. from user mode to kernel mode.
  140. ResultSize - Supplies a pointer where the system call routine returns the
  141. size of the parameter structure to be copied back to user mode. The
  142. value returned here must be no larger than the original parameter
  143. structure size. The default is the original size of the parameters.
  144. Return Value:
  145. None.
  146. --*/
  147. {
  148. PSYSTEM_CALL_SET_THREAD_IDENTITY Parameters;
  149. ASSERT(SystemCallNumber == SystemCallSetThreadIdentity);
  150. Parameters = SystemCallParameter;
  151. Parameters->Status = PspSetThreadIdentity(Parameters->Request.FieldsToSet,
  152. &(Parameters->Request.Identity));
  153. return;
  154. }
  155. VOID
  156. PsSysSetThreadPermissions (
  157. ULONG SystemCallNumber,
  158. PVOID SystemCallParameter,
  159. PTRAP_FRAME TrapFrame,
  160. PULONG ResultSize
  161. )
  162. /*++
  163. Routine Description:
  164. This routine implements the get/set thread permissions system call.
  165. Arguments:
  166. SystemCallNumber - Supplies the system call number that was requested.
  167. SystemCallParameter - Supplies a pointer to the parameters supplied with
  168. the system call. This structure will be a stack-local copy of the
  169. actual parameters passed from user-mode.
  170. TrapFrame - Supplies a pointer to the trap frame generated by this jump
  171. from user mode to kernel mode.
  172. ResultSize - Supplies a pointer where the system call routine returns the
  173. size of the parameter structure to be copied back to user mode. The
  174. value returned here must be no larger than the original parameter
  175. structure size. The default is the original size of the parameters.
  176. Return Value:
  177. None.
  178. --*/
  179. {
  180. PSYSTEM_CALL_SET_THREAD_PERMISSIONS Parameters;
  181. ASSERT(SystemCallNumber == SystemCallSetThreadPermissions);
  182. Parameters = SystemCallParameter;
  183. Parameters->Status = PspSetThreadPermissions(
  184. Parameters->Request.FieldsToSet,
  185. &(Parameters->Request.Permissions));
  186. return;
  187. }
  188. VOID
  189. PsSysSetSupplementaryGroups (
  190. ULONG SystemCallNumber,
  191. PVOID SystemCallParameter,
  192. PTRAP_FRAME TrapFrame,
  193. PULONG ResultSize
  194. )
  195. /*++
  196. Routine Description:
  197. This routine implements the get/set supplementary groups system call.
  198. Arguments:
  199. SystemCallNumber - Supplies the system call number that was requested.
  200. SystemCallParameter - Supplies a pointer to the parameters supplied with
  201. the system call. This structure will be a stack-local copy of the
  202. actual parameters passed from user-mode.
  203. TrapFrame - Supplies a pointer to the trap frame generated by this jump
  204. from user mode to kernel mode.
  205. ResultSize - Supplies a pointer where the system call routine returns the
  206. size of the parameter structure to be copied back to user mode. The
  207. value returned here must be no larger than the original parameter
  208. structure size. The default is the original size of the parameters.
  209. Return Value:
  210. None.
  211. --*/
  212. {
  213. UINTN AllocationSize;
  214. PSUPPLEMENTARY_GROUPS Block;
  215. UINTN BlockCapacity;
  216. UINTN BlockIndex;
  217. UINTN Count;
  218. PSUPPLEMENTARY_GROUPS NewBlock;
  219. PSYSTEM_CALL_SET_SUPPLEMENTARY_GROUPS Parameters;
  220. PKPROCESS Process;
  221. KSTATUS Status;
  222. PKTHREAD Thread;
  223. ASSERT(SystemCallNumber == SystemCallSetSupplementaryGroups);
  224. NewBlock = NULL;
  225. Thread = KeGetCurrentThread();
  226. Process = PsGetCurrentProcess();
  227. Parameters = SystemCallParameter;
  228. if (Parameters->Set != FALSE) {
  229. //
  230. // Set an (arbitrary) cap.
  231. //
  232. if (Parameters->Count > SUPPLEMENTARY_GROUP_MAX) {
  233. Status = STATUS_INVALID_PARAMETER;
  234. goto SysSetSupplementaryGroupsEnd;
  235. }
  236. //
  237. // Ensure the caller has the privileges to do this.
  238. //
  239. Status = PsCheckPermission(PERMISSION_SET_GROUP_ID);
  240. if (!KSUCCESS(Status)) {
  241. goto SysSetSupplementaryGroupsEnd;
  242. }
  243. //
  244. // Count the current capacity.
  245. //
  246. Count = 0;
  247. Block = Thread->SupplementaryGroups;
  248. while (Block != NULL) {
  249. Count += Block->Capacity;
  250. Block = Block->Next;
  251. }
  252. //
  253. // Allocate a new block if needed.
  254. //
  255. if (Count < Parameters->Count) {
  256. BlockCapacity = Parameters->Count - Count;
  257. BlockCapacity = ALIGN_RANGE_UP(BlockCapacity,
  258. SUPPLEMENTARY_GROUP_MIN);
  259. AllocationSize = sizeof(SUPPLEMENTARY_GROUPS) +
  260. (BlockCapacity * sizeof(GROUP_ID));
  261. NewBlock = MmAllocatePagedPool(AllocationSize,
  262. PS_GROUP_ALLOCATION_TAG);
  263. if (NewBlock == NULL) {
  264. Status = STATUS_INSUFFICIENT_RESOURCES;
  265. goto SysSetSupplementaryGroupsEnd;
  266. }
  267. //
  268. // Initialize to all ones instead of zeros to avoid
  269. // accidents that assign groups with IDs of root.
  270. //
  271. RtlSetMemory(NewBlock, -1, AllocationSize);
  272. NewBlock->Capacity = BlockCapacity;
  273. NewBlock->Groups = (PGROUP_ID)(NewBlock + 1);
  274. NewBlock->Count = 0;
  275. }
  276. KeAcquireQueuedLock(Process->QueuedLock);
  277. Status = STATUS_SUCCESS;
  278. Count = 0;
  279. Block = Thread->SupplementaryGroups;
  280. while (Block != NULL) {
  281. //
  282. // Set each entry in the block, up to the total count.
  283. //
  284. for (BlockIndex = 0;
  285. BlockIndex < Block->Capacity;
  286. BlockIndex += 1) {
  287. if (Count == Parameters->Count) {
  288. break;
  289. }
  290. Status = MmCopyFromUserMode(&(Block->Groups[BlockIndex]),
  291. &(Parameters->Groups[Count]),
  292. sizeof(GROUP_ID));
  293. if (!KSUCCESS(Status)) {
  294. break;
  295. }
  296. Count += 1;
  297. }
  298. //
  299. // Set the number of valid entries to be however many were filled
  300. // in.
  301. //
  302. Block->Count = BlockIndex;
  303. if (!KSUCCESS(Status)) {
  304. break;
  305. }
  306. Block = Block->Next;
  307. }
  308. //
  309. // Add the remainder of the groups to the brand new block.
  310. //
  311. if (Count < Parameters->Count) {
  312. ASSERT((NewBlock != NULL) &&
  313. ((Parameters->Count - Count) <= NewBlock->Capacity));
  314. BlockIndex = 0;
  315. while (Count < Parameters->Count) {
  316. Status = MmCopyFromUserMode(&(NewBlock->Groups[BlockIndex]),
  317. &(Parameters->Groups[Count]),
  318. sizeof(GROUP_ID));
  319. if (!KSUCCESS(Status)) {
  320. break;
  321. }
  322. Count += 1;
  323. BlockIndex += 1;
  324. }
  325. //
  326. // Only add the new block if it worked, otherwise memory could
  327. // accumulate via user mode calls with bad pointers.
  328. //
  329. NewBlock->Count = BlockIndex;
  330. if (KSUCCESS(Status)) {
  331. NewBlock->Next = Thread->SupplementaryGroups;
  332. Thread->SupplementaryGroups = NewBlock;
  333. NewBlock = NULL;
  334. }
  335. }
  336. KeReleaseQueuedLock(Process->QueuedLock);
  337. //
  338. // Just get the groups.
  339. //
  340. } else {
  341. Count = 0;
  342. Block = Thread->SupplementaryGroups;
  343. Status = STATUS_SUCCESS;
  344. while (Block != NULL) {
  345. for (BlockIndex = 0; BlockIndex < Block->Count; BlockIndex += 1) {
  346. if ((Count < Parameters->Count) && (KSUCCESS(Status))) {
  347. Status = MmCopyToUserMode(&(Parameters->Groups[Count]),
  348. &(Block->Groups[BlockIndex]),
  349. sizeof(GROUP_ID));
  350. }
  351. Count += 1;
  352. }
  353. Block = Block->Next;
  354. }
  355. Parameters->Count = Count;
  356. }
  357. SysSetSupplementaryGroupsEnd:
  358. if (NewBlock != NULL) {
  359. MmFreePagedPool(NewBlock);
  360. }
  361. Parameters->Status = Status;
  362. return;
  363. }
  364. VOID
  365. PsSysSetResourceLimit (
  366. ULONG SystemCallNumber,
  367. PVOID SystemCallParameter,
  368. PTRAP_FRAME TrapFrame,
  369. PULONG ResultSize
  370. )
  371. /*++
  372. Routine Description:
  373. This routine implements the system call that gets or sets a resource limit
  374. for the current thread.
  375. Arguments:
  376. SystemCallNumber - Supplies the system call number that was requested.
  377. SystemCallParameter - Supplies a pointer to the parameters supplied with
  378. the system call. This structure will be a stack-local copy of the
  379. actual parameters passed from user-mode.
  380. TrapFrame - Supplies a pointer to the trap frame generated by this jump
  381. from user mode to kernel mode.
  382. ResultSize - Supplies a pointer where the system call routine returns the
  383. size of the parameter structure to be copied back to user mode. The
  384. value returned here must be no larger than the original parameter
  385. structure size. The default is the original size of the parameters.
  386. Return Value:
  387. None.
  388. --*/
  389. {
  390. RESOURCE_LIMIT NewValue;
  391. PSYSTEM_CALL_SET_RESOURCE_LIMIT Parameters;
  392. KSTATUS Status;
  393. PKTHREAD Thread;
  394. RESOURCE_LIMIT_TYPE Type;
  395. Thread = KeGetCurrentThread();
  396. Parameters = SystemCallParameter;
  397. Type = Parameters->Type;
  398. if ((Type >= ResourceLimitCount) || (Type < 0)) {
  399. Status = STATUS_INVALID_PARAMETER;
  400. goto SysSetResourceLimitEnd;
  401. }
  402. //
  403. // Copy the values to potentially set into a local, and copy the current
  404. // values to be returned.
  405. //
  406. NewValue.Current = Parameters->Value.Current;
  407. NewValue.Max = Parameters->Value.Max;
  408. Parameters->Value.Current = Thread->Limits[Type].Current;
  409. Parameters->Value.Max = Thread->Limits[Type].Max;
  410. //
  411. // If not setting, that's all there is to do.
  412. //
  413. if (Parameters->Set == FALSE) {
  414. Status = STATUS_SUCCESS;
  415. goto SysSetResourceLimitEnd;
  416. }
  417. //
  418. // The caller wants to set new limits. Make sure current isn't greater than
  419. // max.
  420. //
  421. if (NewValue.Current > NewValue.Max) {
  422. Status = STATUS_INVALID_PARAMETER;
  423. goto SysSetResourceLimitEnd;
  424. }
  425. //
  426. // If trying to raise the max, the caller had better have the appropriate
  427. // permissions.
  428. //
  429. if (NewValue.Max > Parameters->Value.Max) {
  430. Status = PsCheckPermission(PERMISSION_RESOURCES);
  431. if (!KSUCCESS(Status)) {
  432. goto SysSetResourceLimitEnd;
  433. }
  434. //
  435. // Don't allow the file count go beyond what the kernel can handle.
  436. //
  437. if ((Type == ResourceLimitFileCount) &&
  438. (NewValue.Max > OB_MAX_HANDLES)) {
  439. Status = STATUS_PERMISSION_DENIED;
  440. goto SysSetResourceLimitEnd;
  441. }
  442. }
  443. Thread->Limits[Type].Max = NewValue.Max;
  444. Thread->Limits[Type].Current = NewValue.Current;
  445. //
  446. // Attempt to set the new stack size now, and silently ignore failures.
  447. //
  448. if (Type == ResourceLimitStack) {
  449. if ((Thread->Flags & THREAD_FLAG_FREE_USER_STACK) != 0) {
  450. PspSetThreadUserStackSize(Thread, NewValue.Current);
  451. }
  452. }
  453. Status = STATUS_SUCCESS;
  454. SysSetResourceLimitEnd:
  455. Parameters->Status = Status;
  456. return;
  457. }
  458. VOID
  459. PspPerformExecutePermissionChanges (
  460. PIO_HANDLE ExecutableHandle
  461. )
  462. /*++
  463. Routine Description:
  464. This routine fixes up the user identity and potentially permissions in
  465. preparation for executing an image.
  466. Arguments:
  467. ExecutableHandle - Supplies an open file handle to the executable image.
  468. Return Value:
  469. None.
  470. --*/
  471. {
  472. BOOL FileEffective;
  473. PERMISSION_SET FileInheritable;
  474. PERMISSION_SET FilePermitted;
  475. FILE_PROPERTIES FileProperties;
  476. PERMISSION_SET NewPermitted;
  477. BOOL SetRoot;
  478. KSTATUS Status;
  479. PKTHREAD Thread;
  480. Thread = KeGetCurrentThread();
  481. FileEffective = FALSE;
  482. FileInheritable = PERMISSION_SET_EMPTY;
  483. FilePermitted = PERMISSION_SET_EMPTY;
  484. //
  485. // Always clear the keep capabilities bit.
  486. //
  487. Thread->Permissions.Behavior &= ~PERMISSION_BEHAVIOR_KEEP_PERMISSIONS;
  488. Status = IoGetFileInformation(ExecutableHandle, &FileProperties);
  489. if (!KSUCCESS(Status)) {
  490. //
  491. // Save the effective user and group IDs into the saved user and group
  492. // IDs.
  493. //
  494. Thread->Identity.SavedUserId = Thread->Identity.EffectiveUserId;
  495. Thread->Identity.SavedGroupId = Thread->Identity.EffectiveGroupId;
  496. return;
  497. }
  498. //
  499. // TODO: Return immediately if the mount flags specify no-setuid.
  500. //
  501. //
  502. // If the set-group-id bit is set in the file permissions, then change the
  503. // effective group ID to that of the file.
  504. //
  505. if ((FileProperties.Permissions & FILE_PERMISSION_SET_GROUP_ID) != 0) {
  506. Thread->Identity.EffectiveGroupId = FileProperties.GroupId;
  507. }
  508. //
  509. // If the set-user-id bit is set in the file permissions, then change the
  510. // effective user ID to that of the file.
  511. //
  512. SetRoot = FALSE;
  513. if ((FileProperties.Permissions & FILE_PERMISSION_SET_USER_ID) != 0) {
  514. Thread->Identity.EffectiveUserId = FileProperties.UserId;
  515. if (FileProperties.UserId == USER_ID_ROOT) {
  516. SetRoot = TRUE;
  517. }
  518. }
  519. //
  520. // Initialize the saved user and group IDs to be equal to the effective
  521. // ones.
  522. //
  523. Thread->Identity.SavedUserId = Thread->Identity.EffectiveUserId;
  524. Thread->Identity.SavedGroupId = Thread->Identity.EffectiveGroupId;
  525. if ((Thread->Permissions.Behavior & PERMISSION_BEHAVIOR_NO_ROOT) == 0) {
  526. //
  527. // If it's a set-user-id-root program, or the real user ID is root, and
  528. // the user hasn't set the no-root flag, then adjust the permissions
  529. // mask.
  530. //
  531. if ((SetRoot != FALSE) ||
  532. (Thread->Identity.RealUserId == USER_ID_ROOT)) {
  533. FilePermitted = PERMISSION_SET_FULL;
  534. FileInheritable = PERMISSION_SET_FULL;
  535. }
  536. //
  537. // If the new effective user is root, either by setuid methods or just
  538. // because they were before, then the file effective bit is set so that
  539. // they have these permissions on startup.
  540. //
  541. if (Thread->Identity.EffectiveUserId == USER_ID_ROOT) {
  542. FileEffective = TRUE;
  543. }
  544. }
  545. //
  546. // Modify the permission sets for the execution. The new permitted mask is
  547. // (OldPermitted & FileInheritable) | (FilePermited & Limit). The effective
  548. // permissions are set to the permitted permissions if the file "effective"
  549. // bit is set, or just wiped otherwise.
  550. //
  551. NewPermitted = Thread->Permissions.Inheritable;
  552. PERMISSION_AND(NewPermitted, FileInheritable);
  553. PERMISSION_AND(FilePermitted, Thread->Permissions.Limit);
  554. PERMISSION_OR(NewPermitted, FilePermitted);
  555. Thread->Permissions.Permitted = NewPermitted;
  556. if (FileEffective != FALSE) {
  557. Thread->Permissions.Effective = NewPermitted;
  558. } else {
  559. Thread->Permissions.Effective = PERMISSION_SET_EMPTY;
  560. }
  561. return;
  562. }
  563. KSTATUS
  564. PspCopyThreadCredentials (
  565. PKTHREAD NewThread,
  566. PKTHREAD ThreadToCopy
  567. )
  568. /*++
  569. Routine Description:
  570. This routine copies the credentials of a thread onto a new yet-to-be-run
  571. thread.
  572. Arguments:
  573. NewThread - Supplies a pointer to the new thread to initialize.
  574. ThreadToCopy - Supplies a pointer to the thread to copy identity and
  575. permissions from.
  576. Return Value:
  577. STATUS_SUCCESS on success.
  578. STATUS_INSUFFICIENT_RESOURCES if an allocation failed.
  579. --*/
  580. {
  581. UINTN AllocationSize;
  582. PSUPPLEMENTARY_GROUPS Block;
  583. UINTN Count;
  584. PSUPPLEMENTARY_GROUPS NewBlock;
  585. KSTATUS Status;
  586. //
  587. // Just copy the identity, permissions, and limits straight over.
  588. //
  589. RtlCopyMemory(&(NewThread->Identity),
  590. &(ThreadToCopy->Identity),
  591. sizeof(THREAD_IDENTITY));
  592. RtlCopyMemory(&(NewThread->Permissions),
  593. &(ThreadToCopy->Permissions),
  594. sizeof(THREAD_PERMISSIONS));
  595. RtlCopyMemory(&(NewThread->Limits),
  596. &(ThreadToCopy->Limits),
  597. sizeof(NewThread->Limits));
  598. //
  599. // Count up the old thread supplementary group count so it can be allocated
  600. // in a single block.
  601. //
  602. Count = 0;
  603. Block = ThreadToCopy->SupplementaryGroups;
  604. while (Block != NULL) {
  605. Count += Block->Count;
  606. Block = Block->Next;
  607. }
  608. if (Count != 0) {
  609. Count = ALIGN_RANGE_UP(Count, SUPPLEMENTARY_GROUP_MIN);
  610. AllocationSize = sizeof(SUPPLEMENTARY_GROUPS) +
  611. (Count * sizeof(GROUP_ID));
  612. NewBlock = MmAllocatePagedPool(AllocationSize, PS_GROUP_ALLOCATION_TAG);
  613. if (NewBlock == NULL) {
  614. Status = STATUS_INSUFFICIENT_RESOURCES;
  615. goto CopyThreadCredentialsEnd;
  616. }
  617. NewBlock->Capacity = Count;
  618. NewBlock->Count = 0;
  619. NewBlock->Groups = (PGROUP_ID)(NewBlock + 1);
  620. NewBlock->Next = NULL;
  621. //
  622. // Now copy all the blocks over into the new biggy block.
  623. //
  624. Block = ThreadToCopy->SupplementaryGroups;
  625. Count = 0;
  626. while (Block != NULL) {
  627. if (Block->Count != 0) {
  628. RtlCopyMemory(&(NewBlock->Groups[Count]),
  629. Block->Groups,
  630. Block->Count * sizeof(GROUP_ID));
  631. Count += Block->Count;
  632. }
  633. Block = Block->Next;
  634. }
  635. ASSERT(Count <= NewBlock->Capacity);
  636. NewBlock->Count = Count;
  637. NewThread->SupplementaryGroups = NewBlock;
  638. }
  639. Status = STATUS_SUCCESS;
  640. CopyThreadCredentialsEnd:
  641. return Status;
  642. }
  643. VOID
  644. PspDestroyCredentials (
  645. PKTHREAD Thread
  646. )
  647. /*++
  648. Routine Description:
  649. This routine destroys credentials associated with a dying thread.
  650. Arguments:
  651. Thread - Supplies a pointer to the thread being terminated.
  652. Return Value:
  653. None.
  654. --*/
  655. {
  656. PSUPPLEMENTARY_GROUPS Groups;
  657. PSUPPLEMENTARY_GROUPS Next;
  658. Groups = Thread->SupplementaryGroups;
  659. Thread->SupplementaryGroups = NULL;
  660. while (Groups != NULL) {
  661. Next = Groups->Next;
  662. MmFreePagedPool(Groups);
  663. Groups = Next;
  664. }
  665. return;
  666. }
  667. //
  668. // --------------------------------------------------------- Internal Functions
  669. //
  670. KSTATUS
  671. PspSetThreadIdentity (
  672. ULONG FieldsToSet,
  673. PTHREAD_IDENTITY Identity
  674. )
  675. /*++
  676. Routine Description:
  677. This routine gets or sets the current thread's identity.
  678. Arguments:
  679. FieldsToSet - Supplies the bitmask of fields to set. Supply 0 to simply get
  680. the current thread identity. See the THREAD_IDENTITY_FIELD_*
  681. definitions.
  682. Identity - Supplies a pointer that on input contains the new identity to
  683. set. Only the fields specified in the fields to set mask will be
  684. examined. On output, contains the complete new thread identity
  685. information.
  686. Return Value:
  687. STATUS_SUCCESS on success.
  688. STATUS_PERMISSION_DENIED if the caller does not have appropriate
  689. permissions (set user ID and/or set group ID permissions).
  690. --*/
  691. {
  692. PTHREAD_IDENTITY CurrentIdentity;
  693. BOOL Match;
  694. KSTATUS Status;
  695. PKTHREAD Thread;
  696. BOOL WasRoot;
  697. Thread = KeGetCurrentThread();
  698. CurrentIdentity = &(Thread->Identity);
  699. if (FieldsToSet == 0) {
  700. Status = STATUS_SUCCESS;
  701. goto SetThreadIdentityEnd;
  702. }
  703. //
  704. // Before making any changes, ensure the caller isn't overstepping
  705. // permissions. If changing a user ID, a caller without the set user ID
  706. // permission can set any user ID to any of its existing user IDs.
  707. //
  708. Status = STATUS_SUCCESS;
  709. if ((FieldsToSet & THREAD_IDENTITY_FIELDS_USER) != 0) {
  710. Status = PsCheckPermission(PERMISSION_SET_USER_ID);
  711. if (!KSUCCESS(Status)) {
  712. Status = STATUS_SUCCESS;
  713. if ((FieldsToSet & THREAD_IDENTITY_FIELD_REAL_USER_ID) != 0) {
  714. Match = MATCHES_IDENTITY_USER(Identity->RealUserId,
  715. CurrentIdentity);
  716. if (Match == FALSE) {
  717. Status = STATUS_PERMISSION_DENIED;
  718. }
  719. }
  720. if ((FieldsToSet & THREAD_IDENTITY_FIELD_EFFECTIVE_USER_ID) != 0) {
  721. Match = MATCHES_IDENTITY_USER(Identity->EffectiveUserId,
  722. CurrentIdentity);
  723. if (Match == FALSE) {
  724. Status = STATUS_PERMISSION_DENIED;
  725. }
  726. }
  727. if ((FieldsToSet & THREAD_IDENTITY_FIELD_SAVED_USER_ID) != 0) {
  728. Match = MATCHES_IDENTITY_USER(Identity->SavedUserId,
  729. CurrentIdentity);
  730. if (Match == FALSE) {
  731. Status = STATUS_PERMISSION_DENIED;
  732. }
  733. }
  734. }
  735. if (!KSUCCESS(Status)) {
  736. goto SetThreadIdentityEnd;
  737. }
  738. }
  739. //
  740. // Check permissions on the group IDs being set. If the special permission
  741. // isn't there, then the caller can set a group ID to one of its existing
  742. // group IDs.
  743. //
  744. if ((FieldsToSet & THREAD_IDENTITY_FIELDS_GROUP) != 0) {
  745. Status = PsCheckPermission(PERMISSION_SET_GROUP_ID);
  746. if (!KSUCCESS(Status)) {
  747. Status = STATUS_SUCCESS;
  748. if ((FieldsToSet & THREAD_IDENTITY_FIELD_REAL_GROUP_ID) != 0) {
  749. Match = MATCHES_IDENTITY_GROUP(Identity->RealGroupId,
  750. CurrentIdentity);
  751. if (Match == FALSE) {
  752. Status = STATUS_PERMISSION_DENIED;
  753. }
  754. }
  755. if ((FieldsToSet & THREAD_IDENTITY_FIELD_EFFECTIVE_GROUP_ID) != 0) {
  756. Match = MATCHES_IDENTITY_GROUP(Identity->EffectiveGroupId,
  757. CurrentIdentity);
  758. if (Match == FALSE) {
  759. Status = STATUS_PERMISSION_DENIED;
  760. }
  761. }
  762. if ((FieldsToSet & THREAD_IDENTITY_FIELD_SAVED_GROUP_ID) != 0) {
  763. Match = MATCHES_IDENTITY_GROUP(Identity->SavedGroupId,
  764. CurrentIdentity);
  765. if (Match == FALSE) {
  766. Status = STATUS_PERMISSION_DENIED;
  767. }
  768. }
  769. }
  770. if (!KSUCCESS(Status)) {
  771. goto SetThreadIdentityEnd;
  772. }
  773. }
  774. //
  775. // Determine if any of the original user IDs were root.
  776. //
  777. WasRoot = FALSE;
  778. if ((CurrentIdentity->RealUserId == USER_ID_ROOT) ||
  779. (CurrentIdentity->EffectiveUserId == USER_ID_ROOT) ||
  780. (CurrentIdentity->SavedUserId == USER_ID_ROOT)) {
  781. WasRoot = TRUE;
  782. }
  783. //
  784. // The permissions all check out, write the new IDs.
  785. //
  786. if ((FieldsToSet & THREAD_IDENTITY_FIELD_REAL_USER_ID) != 0) {
  787. CurrentIdentity->RealUserId = Identity->RealUserId;
  788. }
  789. if ((FieldsToSet & THREAD_IDENTITY_FIELD_EFFECTIVE_USER_ID) != 0) {
  790. //
  791. // Unless the "no fixup" flag is set, modify the permissions if the
  792. // effective user ID is moving to or from the traditional root user.
  793. //
  794. if ((Thread->Permissions.Behavior &
  795. PERMISSION_BEHAVIOR_NO_SETUID_FIXUP) == 0) {
  796. //
  797. // If the effective user ID goes from zero to non-zero, clear all
  798. // effective permissions.
  799. //
  800. if ((CurrentIdentity->EffectiveUserId == USER_ID_ROOT) &&
  801. (Identity->EffectiveUserId != USER_ID_ROOT)) {
  802. Thread->Permissions.Effective = PERMISSION_SET_EMPTY;
  803. }
  804. //
  805. // If the effective user ID goes from non-zero to zero, then copy
  806. // the permitted permissions to the effective permissions.
  807. //
  808. if ((CurrentIdentity->EffectiveUserId != USER_ID_ROOT) &&
  809. (Identity->EffectiveUserId == USER_ID_ROOT)) {
  810. Thread->Permissions.Effective = Thread->Permissions.Permitted;
  811. }
  812. }
  813. CurrentIdentity->EffectiveUserId = Identity->EffectiveUserId;
  814. }
  815. if ((FieldsToSet & THREAD_IDENTITY_FIELD_SAVED_USER_ID) != 0) {
  816. CurrentIdentity->SavedUserId = Identity->SavedUserId;
  817. }
  818. //
  819. // If at least one of the real, effective, or saved user IDs was zero and
  820. // all three are now non-zero, then all permissions are cleared from the
  821. // permitted and effective sets.
  822. //
  823. if ((WasRoot != FALSE) &&
  824. (CurrentIdentity->RealUserId != USER_ID_ROOT) &&
  825. (CurrentIdentity->EffectiveUserId != USER_ID_ROOT) &&
  826. (CurrentIdentity->SavedUserId != USER_ID_ROOT)) {
  827. if ((Thread->Permissions.Behavior &
  828. PERMISSION_BEHAVIOR_KEEP_PERMISSIONS) == 0) {
  829. Thread->Permissions.Permitted = PERMISSION_SET_EMPTY;
  830. Thread->Permissions.Effective = PERMISSION_SET_EMPTY;
  831. }
  832. }
  833. if ((FieldsToSet & THREAD_IDENTITY_FIELD_REAL_GROUP_ID) != 0) {
  834. CurrentIdentity->RealGroupId = Identity->RealGroupId;
  835. }
  836. if ((FieldsToSet & THREAD_IDENTITY_FIELD_EFFECTIVE_GROUP_ID) != 0) {
  837. CurrentIdentity->EffectiveGroupId = Identity->EffectiveGroupId;
  838. }
  839. if ((FieldsToSet & THREAD_IDENTITY_FIELD_SAVED_GROUP_ID) != 0) {
  840. CurrentIdentity->SavedGroupId = Identity->SavedGroupId;
  841. }
  842. SetThreadIdentityEnd:
  843. RtlCopyMemory(Identity, CurrentIdentity, sizeof(THREAD_IDENTITY));
  844. return Status;
  845. }
  846. KSTATUS
  847. PspSetThreadPermissions (
  848. ULONG FieldsToSet,
  849. PTHREAD_PERMISSIONS Permissions
  850. )
  851. /*++
  852. Routine Description:
  853. This routine gets or sets the current thread's permission masks.
  854. Arguments:
  855. FieldsToSet - Supplies the bitmask of fields to set. Supply 0 to simply get
  856. the current thread identity. See the THREAD_PERMISSION_FIELD_*
  857. definitions.
  858. Permissions - Supplies a pointer that on input contains the new
  859. permissions to set. Only the fields specified in the fields to set
  860. mask will be examined. On output, contains the complete new thread
  861. permission masks.
  862. Return Value:
  863. STATUS_SUCCESS on success.
  864. STATUS_PERMISSION_DENIED if the caller does not have appropriate
  865. permissions (potentially the permission to add permissions).
  866. --*/
  867. {
  868. PTHREAD_PERMISSIONS CurrentPermissions;
  869. ULONG DifferentBits;
  870. PERMISSION_SET IllegalBits;
  871. PERMISSION_SET InheritablePlusLimit;
  872. PERMISSION_SET InheritablePlusPermitted;
  873. ULONG SameMask;
  874. KSTATUS Status;
  875. PKTHREAD Thread;
  876. Thread = KeGetCurrentThread();
  877. CurrentPermissions = &(Thread->Permissions);
  878. if (FieldsToSet == 0) {
  879. Status = STATUS_SUCCESS;
  880. goto SetThreadPermissionsEnd;
  881. }
  882. //
  883. // If the thread does not have permission to set more permissions, then
  884. // additional rules apply.
  885. //
  886. Status = PsCheckPermission(PERMISSION_SET_PERMISSIONS);
  887. if (!KSUCCESS(Status)) {
  888. Status = STATUS_SUCCESS;
  889. //
  890. // The "set permissions" permission is required to change the behavior
  891. // mask and the limit set.
  892. //
  893. if ((FieldsToSet &
  894. (THREAD_PERMISSION_FIELD_BEHAVIOR |
  895. THREAD_PERMISSION_FIELD_LIMIT)) != 0) {
  896. Status = STATUS_PERMISSION_DENIED;
  897. }
  898. //
  899. // The new inheritable mask must only have permissions from the
  900. // inheritable and permitted sets.
  901. //
  902. if ((FieldsToSet & THREAD_PERMISSION_FIELD_INHERITABLE) != 0) {
  903. InheritablePlusPermitted = CurrentPermissions->Inheritable;
  904. PERMISSION_OR(InheritablePlusPermitted,
  905. CurrentPermissions->Permitted);
  906. IllegalBits = Permissions->Inheritable;
  907. PERMISSION_REMOVE_SET(IllegalBits, InheritablePlusPermitted);
  908. if (!PERMISSION_IS_EMPTY(IllegalBits)) {
  909. Status = STATUS_PERMISSION_DENIED;
  910. }
  911. }
  912. }
  913. //
  914. // Bits can never be added to the limit set.
  915. //
  916. if ((FieldsToSet & THREAD_PERMISSION_FIELD_LIMIT) != 0) {
  917. IllegalBits = Permissions->Limit;
  918. PERMISSION_REMOVE_SET(IllegalBits, CurrentPermissions->Limit);
  919. if (!PERMISSION_IS_EMPTY(IllegalBits)) {
  920. Status = STATUS_PERMISSION_DENIED;
  921. }
  922. }
  923. //
  924. // The lock bits are like fuses, once they're blown they can no longer
  925. // be changed. For each lock bit that is set, if either the lock bit
  926. // or the bit itself is different, then fail.
  927. //
  928. if ((FieldsToSet & THREAD_PERMISSION_FIELD_BEHAVIOR) != 0) {
  929. if ((Permissions->Behavior & ~PERMISSION_BEHAVIOR_VALID_MASK) != 0) {
  930. Status = STATUS_INVALID_PARAMETER;
  931. }
  932. SameMask = 0;
  933. if ((CurrentPermissions->Behavior &
  934. PERMISSION_BEHAVIOR_KEEP_PERMISSIONS_LOCKED) != 0) {
  935. SameMask |= PERMISSION_BEHAVIOR_KEEP_PERMISSIONS_LOCKED |
  936. PERMISSION_BEHAVIOR_KEEP_PERMISSIONS;
  937. }
  938. if ((CurrentPermissions->Behavior &
  939. PERMISSION_BEHAVIOR_NO_SETUID_FIXUP_LOCKED) != 0) {
  940. SameMask |= PERMISSION_BEHAVIOR_NO_SETUID_FIXUP_LOCKED |
  941. PERMISSION_BEHAVIOR_NO_SETUID_FIXUP;
  942. }
  943. if ((CurrentPermissions->Behavior &
  944. PERMISSION_BEHAVIOR_NO_ROOT_LOCKED) != 0) {
  945. SameMask |= PERMISSION_BEHAVIOR_NO_ROOT_LOCKED |
  946. PERMISSION_BEHAVIOR_NO_ROOT;
  947. }
  948. //
  949. // If any of the bits that are required to be the same are actually
  950. // different, then the request is denied.
  951. //
  952. DifferentBits = Permissions->Behavior ^ CurrentPermissions->Behavior;
  953. if ((DifferentBits & SameMask) != 0) {
  954. Status = STATUS_PERMISSION_DENIED;
  955. }
  956. }
  957. //
  958. // The new inheritable set must be a subset of the existing inheritable
  959. // set plus the limit.
  960. //
  961. if ((FieldsToSet & THREAD_PERMISSION_FIELD_INHERITABLE) != 0) {
  962. InheritablePlusLimit = CurrentPermissions->Inheritable;
  963. PERMISSION_OR(InheritablePlusLimit, CurrentPermissions->Limit);
  964. IllegalBits = Permissions->Inheritable;
  965. PERMISSION_REMOVE_SET(IllegalBits, InheritablePlusLimit);
  966. if (!PERMISSION_IS_EMPTY(IllegalBits)) {
  967. Status = STATUS_PERMISSION_DENIED;
  968. }
  969. }
  970. //
  971. // Bits cannot be added to the permitted set.
  972. //
  973. if ((FieldsToSet & THREAD_PERMISSION_FIELD_PERMITTED) != 0) {
  974. IllegalBits = Permissions->Permitted;
  975. PERMISSION_REMOVE_SET(IllegalBits, CurrentPermissions->Permitted);
  976. if (!PERMISSION_IS_EMPTY(IllegalBits)) {
  977. Status = STATUS_PERMISSION_DENIED;
  978. }
  979. }
  980. //
  981. // The effective set is limited to the permitted set.
  982. //
  983. if ((FieldsToSet & THREAD_PERMISSION_FIELD_EFFECTIVE) != 0) {
  984. IllegalBits = Permissions->Effective;
  985. PERMISSION_REMOVE_SET(IllegalBits, CurrentPermissions->Permitted);
  986. if (!PERMISSION_IS_EMPTY(IllegalBits)) {
  987. Status = STATUS_PERMISSION_DENIED;
  988. }
  989. }
  990. //
  991. // If any of those conditions tripped a failure, don't change any settings.
  992. //
  993. if (!KSUCCESS(Status)) {
  994. goto SetThreadPermissionsEnd;
  995. }
  996. //
  997. // All the checks passed, set the desired fields.
  998. //
  999. if ((FieldsToSet & THREAD_PERMISSION_FIELD_BEHAVIOR) != 0) {
  1000. CurrentPermissions->Behavior = Permissions->Behavior;
  1001. }
  1002. if ((FieldsToSet & THREAD_PERMISSION_FIELD_LIMIT) != 0) {
  1003. CurrentPermissions->Limit = Permissions->Limit;
  1004. }
  1005. if ((FieldsToSet & THREAD_PERMISSION_FIELD_INHERITABLE) != 0) {
  1006. CurrentPermissions->Inheritable = Permissions->Inheritable;
  1007. }
  1008. if ((FieldsToSet & THREAD_PERMISSION_FIELD_PERMITTED) != 0) {
  1009. CurrentPermissions->Permitted = Permissions->Permitted;
  1010. }
  1011. if ((FieldsToSet & THREAD_PERMISSION_FIELD_EFFECTIVE) != 0) {
  1012. CurrentPermissions->Effective = Permissions->Effective;
  1013. }
  1014. Status = STATUS_SUCCESS;
  1015. SetThreadPermissionsEnd:
  1016. RtlCopyMemory(Permissions, CurrentPermissions, sizeof(THREAD_PERMISSIONS));
  1017. return Status;
  1018. }