diff --git a/winsup/cygwin/local_includes/miscfuncs.h b/winsup/cygwin/local_includes/miscfuncs.h index d52debad1..efd7e516b 100644 --- a/winsup/cygwin/local_includes/miscfuncs.h +++ b/winsup/cygwin/local_includes/miscfuncs.h @@ -46,6 +46,7 @@ is_alt_numpad_event (PINPUT_RECORD pirec) int winprio_to_nice (DWORD); DWORD nice_to_winprio (int &); +bool set_and_check_winprio (HANDLE proc, DWORD prio); bool create_pipe (PHANDLE, PHANDLE, LPSECURITY_ATTRIBUTES, DWORD); diff --git a/winsup/cygwin/miscfuncs.cc b/winsup/cygwin/miscfuncs.cc index 4220f6275..e3bf35cf7 100644 --- a/winsup/cygwin/miscfuncs.cc +++ b/winsup/cygwin/miscfuncs.cc @@ -183,6 +183,35 @@ nice_to_winprio (int &nice) return prio; } +/* Set Win32 priority or return false on failure. Also return + false and revert to the original priority if a different (lower) + priority is set instead. */ +bool +set_and_check_winprio (HANDLE proc, DWORD prio) +{ + DWORD prev_prio = GetPriorityClass (proc); + if (prev_prio == prio) + return true; + + if (!SetPriorityClass (proc, prio)) + return false; + + /* Windows silently sets a lower priority (HIGH_PRIORITY_CLASS) if + the new priority (REALTIME_PRIORITY_CLASS) requires administrator + privileges. */ + DWORD curr_prio = GetPriorityClass (proc); + if (curr_prio != prio) + { + debug_printf ("Failed to set priority 0x%x, revert from 0x%x to 0x%x", + prio, curr_prio, prev_prio); + SetPriorityClass (proc, prev_prio); + return false; + } + + debug_printf ("Changed priority from 0x%x to 0x%x", prev_prio, curr_prio); + return true; +} + /* Minimal overlapped pipe I/O implementation for signal and commune stuff. */ BOOL diff --git a/winsup/cygwin/release/3.6.0 b/winsup/cygwin/release/3.6.0 index 468a2ab24..ef7e4018f 100644 --- a/winsup/cygwin/release/3.6.0 +++ b/winsup/cygwin/release/3.6.0 @@ -43,3 +43,8 @@ What changed: - Now using AVX/AVX2/AVX-512 instructions in signal handler does not break their context. + +- nice(2), setpriority(2) and sched_setparam(2) now fail with EACCES + or EPERM if Windows would silently set a lower priority + (HIGH_PRIORITY_CLASS instead of REALTIME_PRIORITY_CLASS) due to + missing administrator privileges. diff --git a/winsup/cygwin/sched.cc b/winsup/cygwin/sched.cc index 22ff0c8e8..187416007 100644 --- a/winsup/cygwin/sched.cc +++ b/winsup/cygwin/sched.cc @@ -266,7 +266,7 @@ sched_setparam (pid_t pid, const struct sched_param *param) set_errno (ESRCH); return -1; } - if (!SetPriorityClass (process, pclass)) + if (!set_and_check_winprio (process, pclass)) { CloseHandle (process); set_errno (EPERM); diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 433739cda..72537bc5a 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -3826,7 +3826,7 @@ setpriority (int which, id_t who, int value) who = myself->pid; if ((pid_t) who == myself->pid) { - if (!SetPriorityClass (GetCurrentProcess (), prio)) + if (!set_and_check_winprio (GetCurrentProcess (), prio)) { set_errno (EACCES); return -1; @@ -3875,7 +3875,7 @@ setpriority (int which, id_t who, int value) error = EPERM; else { - if (!SetPriorityClass (proc_h, prio)) + if (!set_and_check_winprio (proc_h, prio)) error = EACCES; else p->nice = value;