diff mbox

[RFC,1/2,v2] proc: Relax /proc/<tid>/timerslack_ns capability requirements

Message ID 1468603460-17034-1-git-send-email-john.stultz@linaro.org
State New
Headers show

Commit Message

John Stultz July 15, 2016, 5:24 p.m. UTC
When an interface to allow a task to change another tasks
timerslack was first proposed, it was suggested that something
greater then CAP_SYS_NICE would be needed, as a task could be
delayed further then what normally could be done with nice
adjustments.

So CAP_SYS_PTRACE was adopted instead for what became the
/proc/<tid>/timerslack_ns interface. However, for Android (where
this feature originates), giving the system_server
CAP_SYS_PTRACE would allow it to observe and modify all tasks
memory. This is considered too high a privilege level for only
needing to change the timerslack.

After some discussion, it was realized that a CAP_SYS_NICE
process can set a task as SCHED_FIFO, so they could fork some
spinning processes and set them all SCHED_FIFO 99, in effect
delaying all other tasks for an infinite amount of time.

So as a CAP_SYS_NICE task can already cause trouble for other
tasks, using it as a required capability for accessing and
modifying /proc/<tid>/timerslack_ns seems sufficient.

Thus, this patch loosens the capability requirements to
CAP_SYS_NICE and removes CAP_SYS_PTRACE, simplifying some
of the code flow as well.

This is technically an ABI change, but as the feature just
landed in 4.6, I suspect no one is yet using it.

Cc: Kees Cook <keescook@chromium.org>
Cc: "Serge E. Hallyn" <serge@hallyn.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
CC: Arjan van de Ven <arjan@linux.intel.com>
Cc: Oren Laadan <orenl@cellrox.com>
Cc: Ruchi Kandoi <kandoiruchi@google.com>
Cc: Rom Lemarchand <romlem@android.com>
Cc: Todd Kjos <tkjos@google.com>
Cc: Colin Cross <ccross@android.com>
Cc: Nick Kralevich <nnk@google.com>
Cc: Dmitry Shmidt <dimitrysh@google.com>
Cc: Elliott Hughes <enh@google.com>
Cc: Android Kernel Team <kernel-team@android.com>
Signed-off-by: John Stultz <john.stultz@linaro.org>

---
v2: Removed CAP_SYS_PTRACE check and simplified code flow

 fs/proc/base.c | 33 ++++++++++++++++-----------------
 1 file changed, 16 insertions(+), 17 deletions(-)

-- 
1.9.1

Comments

John Stultz July 15, 2016, 6:42 p.m. UTC | #1
On Fri, Jul 15, 2016 at 10:51 AM, Nick Kralevich <nnk@google.com> wrote:
> On Fri, Jul 15, 2016 at 10:24 AM, John Stultz <john.stultz@linaro.org> wrote:

>> +       if (!capable(CAP_SYS_NICE))

>> +               return -EPERM;

>> +

>

> Since you're going the LSM route (from your second patch of this


Well, you suggested it, so I sent out an RFC. I'm not married to it yet. :)


> series), the capability check above should be moved to the LSM hook in

> security/commoncap.c.  Only one security call to

> security_task_settimerslack is needed, which will cover the standard

> capabilities check as well as the SELinux check.


Huh. Ok. I was looking at the implementation of nice(), which does:

 if (increment < 0 && !can_nice(current, nice))
                return -EPERM;
retval = security_task_setnice(current, nice);
if (retval)
...

Which made it seem like standard checks are done first, then finer
grain lsm checks second.

(...and now you can guess where my accidental "current" usage in the
next patch came from :)


>

>>         p = get_proc_task(inode);

>>         if (!p)

>>                 return -ESRCH;

>>

>

> Per your patch #2, you'd call security_task_settimerslack here. This

> would call into the capability LSM hook you added in

> security/commoncap.c


Though I was hoping to keep the CAP_SYS_PTRACE -> CAP_SYS_NICE change
first, then add the LSM hooks, as it makes the needed ABI change more
obvious. I worry swapping it around with the LSM hook being added
first makes it significantly less obvious, as (at least for me) the
security_task_* functions get indirect and difficult to follow quickly
("wait, why are we checking SETSCHED for nice?").

A side curiosity: why does "git grep PROCESS__SETSCHED" miss the
definition? Is the av_permissions.h file somehow caught by .gitignore?

thanks
-john
John Stultz July 15, 2016, 8:03 p.m. UTC | #2
On Fri, Jul 15, 2016 at 12:55 PM, Nick Kralevich <nnk@google.com> wrote:
> On Fri, Jul 15, 2016 at 10:24 AM, John Stultz <john.stultz@linaro.org> wrote:

>> +       if (!capable(CAP_SYS_NICE))

>> +               return -EPERM;

>> +

>>         p = get_proc_task(inode);

>>         if (!p)

>>                 return -ESRCH;

>

> The capable(CAP_SYS_NICE) permission check should be moved to this

> point, since it doesn't make sense to return EPERM if the task

> structure doesn't exist.


Ok. Will move it.

>> @@ -2300,22 +2300,21 @@ static int timerslack_ns_show(struct seq_file *m, void *v)

>>  {

>>         struct inode *inode = m->private;

>>         struct task_struct *p;

>> -       int err =  0;

>> +

>> +       if (!capable(CAP_SYS_NICE))

>> +               return -EPERM;

>

> This should also have a similar LSM check for reads. For the SELinux

> implementation, this can map to the PROCESS__GETSCHED permission.


Ok. I'll wire that in as well.

Would adding both selinux_task_get and set methods in the same patch
be ok? Or would folks prefer they be split into two?

Thanks for the feedback!
-john
diff mbox

Patch

diff --git a/fs/proc/base.c b/fs/proc/base.c
index a11eb71..8f4f8d7 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2277,19 +2277,19 @@  static ssize_t timerslack_ns_write(struct file *file, const char __user *buf,
 	if (err < 0)
 		return err;
 
+	if (!capable(CAP_SYS_NICE))
+		return -EPERM;
+
 	p = get_proc_task(inode);
 	if (!p)
 		return -ESRCH;
 
-	if (ptrace_may_access(p, PTRACE_MODE_ATTACH_FSCREDS)) {
-		task_lock(p);
-		if (slack_ns == 0)
-			p->timer_slack_ns = p->default_timer_slack_ns;
-		else
-			p->timer_slack_ns = slack_ns;
-		task_unlock(p);
-	} else
-		count = -EPERM;
+	task_lock(p);
+	if (slack_ns == 0)
+		p->timer_slack_ns = p->default_timer_slack_ns;
+	else
+		p->timer_slack_ns = slack_ns;
+	task_unlock(p);
 
 	put_task_struct(p);
 
@@ -2300,22 +2300,21 @@  static int timerslack_ns_show(struct seq_file *m, void *v)
 {
 	struct inode *inode = m->private;
 	struct task_struct *p;
-	int err =  0;
+
+	if (!capable(CAP_SYS_NICE))
+		return -EPERM;
 
 	p = get_proc_task(inode);
 	if (!p)
 		return -ESRCH;
 
-	if (ptrace_may_access(p, PTRACE_MODE_ATTACH_FSCREDS)) {
-		task_lock(p);
-		seq_printf(m, "%llu\n", p->timer_slack_ns);
-		task_unlock(p);
-	} else
-		err = -EPERM;
+	task_lock(p);
+	seq_printf(m, "%llu\n", p->timer_slack_ns);
+	task_unlock(p);
 
 	put_task_struct(p);
 
-	return err;
+	return 0;
 }
 
 static int timerslack_ns_open(struct inode *inode, struct file *filp)