sched_setattr(2) does via kernel/sched/core.c:__sched_setscheduler()
issue a CAP_SYS_NICE audit event unconditionally, even when the requested
operation does not require that capability / is un-privileged.

Perform privilged/unprivileged catigorization first and perform a
capable test only if needed.

Signed-off-by: Christian Göttsche <cgzo...@googlemail.com>
---
 kernel/sched/core.c | 65 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 47 insertions(+), 18 deletions(-)

diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 8471a0f7eb32..954f968d2466 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -5249,13 +5249,19 @@ static int __sched_setscheduler(struct task_struct *p,
                return -EINVAL;
 
        /*
-        * Allow unprivileged RT tasks to decrease priority:
+        * Allow unprivileged RT tasks to decrease priority.
+        * Only issue a capable test if needed to avoid audit
+        * event on non-privileged operations:
         */
-       if (user && !capable(CAP_SYS_NICE)) {
+       if (user) {
                if (fair_policy(policy)) {
                        if (attr->sched_nice < task_nice(p) &&
-                           !can_nice(p, attr->sched_nice))
-                               return -EPERM;
+                           !can_nice(p, attr->sched_nice)) {
+                               if (capable(CAP_SYS_NICE))
+                                       goto sys_nice_capable;
+                               else
+                                       return -EPERM;
+                       }
                }
 
                if (rt_policy(policy)) {
@@ -5263,13 +5269,21 @@ static int __sched_setscheduler(struct task_struct *p,
                                        task_rlimit(p, RLIMIT_RTPRIO);
 
                        /* Can't set/change the rt policy: */
-                       if (policy != p->policy && !rlim_rtprio)
-                               return -EPERM;
+                       if (policy != p->policy && !rlim_rtprio) {
+                               if (capable(CAP_SYS_NICE))
+                                       goto sys_nice_capable;
+                               else
+                                       return -EPERM;
+                       }
 
                        /* Can't increase priority: */
                        if (attr->sched_priority > p->rt_priority &&
-                           attr->sched_priority > rlim_rtprio)
-                               return -EPERM;
+                           attr->sched_priority > rlim_rtprio) {
+                               if (capable(CAP_SYS_NICE))
+                                       goto sys_nice_capable;
+                               else
+                                       return -EPERM;
+                       }
                }
 
                 /*
@@ -5278,28 +5292,43 @@ static int __sched_setscheduler(struct task_struct *p,
                  * unprivileged DL tasks to increase their relative deadline
                  * or reduce their runtime (both ways reducing utilization)
                  */
-               if (dl_policy(policy))
-                       return -EPERM;
+               if (dl_policy(policy)) {
+                       if (capable(CAP_SYS_NICE))
+                               goto sys_nice_capable;
+                       else
+                               return -EPERM;
+               }
 
                /*
                 * Treat SCHED_IDLE as nice 20. Only allow a switch to
                 * SCHED_NORMAL if the RLIMIT_NICE would normally permit it.
                 */
                if (task_has_idle_policy(p) && !idle_policy(policy)) {
-                       if (!can_nice(p, task_nice(p)))
-                               return -EPERM;
+                       if (!can_nice(p, task_nice(p))) {
+                               if (capable(CAP_SYS_NICE))
+                                       goto sys_nice_capable;
+                               else
+                                       return -EPERM;
+                       }
                }
 
                /* Can't change other user's priorities: */
-               if (!check_same_owner(p))
-                       return -EPERM;
+               if (!check_same_owner(p)) {
+                       if (capable(CAP_SYS_NICE))
+                               goto sys_nice_capable;
+                       else
+                               return -EPERM;
+               }
 
                /* Normal users shall not reset the sched_reset_on_fork flag: */
-               if (p->sched_reset_on_fork && !reset_on_fork)
-                       return -EPERM;
-       }
+               if (p->sched_reset_on_fork && !reset_on_fork) {
+                       if (capable(CAP_SYS_NICE))
+                               goto sys_nice_capable;
+                       else
+                               return -EPERM;
+               }
 
-       if (user) {
+sys_nice_capable:
                if (attr->sched_flags & SCHED_FLAG_SUGOV)
                        return -EINVAL;
 
-- 
2.28.0

Reply via email to