https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=153b51ee08efc39068ed2cc897855ea4aba5d96e

commit 153b51ee08efc39068ed2cc897855ea4aba5d96e
Author:     Christian Franke <[email protected]>
AuthorDate: Wed Nov 27 10:26:38 2024 +0100
Commit:     Corinna Vinschen <[email protected]>
CommitDate: Wed Nov 27 16:38:39 2024 +0100

    Cygwin: setpriority, sched_setparam: fail if Windows sets a lower priority
    
    Windows silently sets a lower priority than requested if the new priority
    requires administrator privileges.  Revert to previous priority and fail
    with EACCES or EPERM in this case.
    
    Signed-off-by: Christian Franke <[email protected]>

Diff:
---
 winsup/cygwin/local_includes/miscfuncs.h |  1 +
 winsup/cygwin/miscfuncs.cc               | 29 +++++++++++++++++++++++++++++
 winsup/cygwin/release/3.6.0              |  5 +++++
 winsup/cygwin/sched.cc                   |  2 +-
 winsup/cygwin/syscalls.cc                |  4 ++--
 5 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/winsup/cygwin/local_includes/miscfuncs.h 
b/winsup/cygwin/local_includes/miscfuncs.h
index d52debad1a1d..efd7e516b7dc 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 4220f6275785..e3bf35cf7552 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 468a2ab248d0..ef7e4018fbd2 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 22ff0c8e8e77..18741600796e 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 433739cda6e0..72537bc5ad52 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;

Reply via email to