job.cc 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // Copyright (c) 2011 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "sandbox/win/src/job.h"
  5. #include <windows.h>
  6. #include <stddef.h>
  7. #include <utility>
  8. #include "base/win/windows_version.h"
  9. #include "sandbox/win/src/restricted_token.h"
  10. namespace sandbox {
  11. Job::Job() : job_handle_(nullptr) {}
  12. Job::~Job() {}
  13. DWORD Job::Init(JobLevel security_level,
  14. const wchar_t* job_name,
  15. DWORD ui_exceptions,
  16. size_t memory_limit) {
  17. if (job_handle_.IsValid())
  18. return ERROR_ALREADY_INITIALIZED;
  19. job_handle_.Set(::CreateJobObject(nullptr, // No security attribute
  20. job_name));
  21. if (!job_handle_.IsValid())
  22. return ::GetLastError();
  23. JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {};
  24. JOBOBJECT_BASIC_UI_RESTRICTIONS jbur = {};
  25. // Set the settings for the different security levels. Note: The higher levels
  26. // inherit from the lower levels.
  27. switch (security_level) {
  28. case JobLevel::kLockdown: {
  29. jeli.BasicLimitInformation.LimitFlags |=
  30. JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION;
  31. jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_WRITECLIPBOARD;
  32. jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_READCLIPBOARD;
  33. jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES;
  34. jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_GLOBALATOMS;
  35. [[fallthrough]];
  36. }
  37. case JobLevel::kLimitedUser: {
  38. jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_DISPLAYSETTINGS;
  39. jeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_ACTIVE_PROCESS;
  40. jeli.BasicLimitInformation.ActiveProcessLimit = 1;
  41. [[fallthrough]];
  42. }
  43. case JobLevel::kInteractive: {
  44. jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS;
  45. jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_DESKTOP;
  46. jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_EXITWINDOWS;
  47. [[fallthrough]];
  48. }
  49. case JobLevel::kUnprotected: {
  50. if (memory_limit) {
  51. jeli.BasicLimitInformation.LimitFlags |=
  52. JOB_OBJECT_LIMIT_PROCESS_MEMORY;
  53. jeli.ProcessMemoryLimit = memory_limit;
  54. }
  55. jeli.BasicLimitInformation.LimitFlags |=
  56. JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
  57. break;
  58. }
  59. case JobLevel::kNone: {
  60. return ERROR_BAD_ARGUMENTS;
  61. }
  62. }
  63. if (!::SetInformationJobObject(job_handle_.Get(),
  64. JobObjectExtendedLimitInformation, &jeli,
  65. sizeof(jeli))) {
  66. return ::GetLastError();
  67. }
  68. jbur.UIRestrictionsClass = jbur.UIRestrictionsClass & (~ui_exceptions);
  69. if (!::SetInformationJobObject(job_handle_.Get(),
  70. JobObjectBasicUIRestrictions, &jbur,
  71. sizeof(jbur))) {
  72. return ::GetLastError();
  73. }
  74. return ERROR_SUCCESS;
  75. }
  76. bool Job::IsValid() {
  77. return job_handle_.IsValid();
  78. }
  79. HANDLE Job::GetHandle() {
  80. return job_handle_.Get();
  81. }
  82. DWORD Job::UserHandleGrantAccess(HANDLE handle) {
  83. if (!job_handle_.IsValid())
  84. return ERROR_NO_DATA;
  85. if (!::UserHandleGrantAccess(handle, job_handle_.Get(),
  86. true)) { // Access allowed.
  87. return ::GetLastError();
  88. }
  89. return ERROR_SUCCESS;
  90. }
  91. DWORD Job::AssignProcessToJob(HANDLE process_handle) {
  92. if (!job_handle_.IsValid())
  93. return ERROR_NO_DATA;
  94. if (!::AssignProcessToJobObject(job_handle_.Get(), process_handle))
  95. return ::GetLastError();
  96. return ERROR_SUCCESS;
  97. }
  98. DWORD Job::SetActiveProcessLimit(DWORD processes) {
  99. JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {};
  100. if (!job_handle_.IsValid())
  101. return ERROR_NO_DATA;
  102. if (!::QueryInformationJobObject(job_handle_.Get(),
  103. JobObjectExtendedLimitInformation, &jeli,
  104. sizeof(jeli), nullptr)) {
  105. return ::GetLastError();
  106. }
  107. jeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_ACTIVE_PROCESS;
  108. jeli.BasicLimitInformation.ActiveProcessLimit = processes;
  109. if (!::SetInformationJobObject(job_handle_.Get(),
  110. JobObjectExtendedLimitInformation, &jeli,
  111. sizeof(jeli))) {
  112. return ::GetLastError();
  113. }
  114. return ERROR_SUCCESS;
  115. }
  116. } // namespace sandbox