#691195 ioprio_get(2): document IOPRIO_WHO_USER and who==0

#691195#5
Date:
2011-12-17 10:26:37 UTC
From:
To:
The ioprio_get(2) manual page describes the meanings of the which
and who parameters:
IOPRIO_WHO_PGRP also allow who==0.  As implemented in
fs/ioprio.c, who==0 means the calling process or its process
group.  The ioprio program in util-linux already uses the
feature.  This is worth documenting separately because
e.g. tcsetpgrp does not treat pgrp==0 in that way.

For IOPRIO_WHO_USER, the situation is more complex: who==0 means
the root user in ioprio_set but the current user (I think the
real UID of the calling process) in ioprio_get.  (That
inconsistency might even be a bug.)

#691195#10
Date:
2012-07-29 06:32:49 UTC
From:
To:
[CCing Jens because of the discussion below about IOPRIO_WHO_USER
below; he may have a comment]
[CCing Марк, who independently noted the lack of documentation for
IOPRIO_WHO_PROCESS, who==0 .]
[CCing Colin McCabe who sent other recent fixes for the ioprio_set.2 page]

Yes.

Agreed, this should be documented since various APIs interpret pgrp==0
differently. Some (e.g., killpg(2)) are like this syscall, others are
not.

So, I'm not sure I'm following the kernel code too well here...
@Jens, your comments would be very welovem.

In ioprio_get() (Linux 3.5 kernel source file fs/ioprio.c), I see the following:

                case IOPRIO_WHO_USER:
                        uid = make_kuid(current_user_ns(), who);
                        if (!who)
                                user = current_user();
                        else
                                user = find_user(uid);

                        if (!user)
                                break;

                        do_each_thread(g, p) {
                                if (!uid_eq(task_uid(p), user->uid))
                                        continue;
                                tmpio = get_task_ioprio(p);
                                if (tmpio < 0)
                                        continue;
                                if (ret == -ESRCH)
                                        ret = tmpio;
                                else
                                        ret = ioprio_best(ret, tmpio);
                        } while_each_thread(g, p);

                        if (who)
                                free_uid(user);
                        break;

In ioprio_set(), I see:

                case IOPRIO_WHO_USER:
                        uid = make_kuid(current_user_ns(), who);
                        if (!uid_valid(uid))
                                break;
                        if (!who)
                                user = current_user();
                        else
                                user = find_user(uid);

                        if (!user)
                                break;

                        do_each_thread(g, p) {
                                if (!uid_eq(task_uid(p), uid))
                                        continue;
                                ret = set_task_ioprio(p, ioprio);
                                if (ret)
                                        goto free_uid;
                        } while_each_thread(g, p);
free_uid:
                        if (who)
                                free_uid(user);
                        break;

This suggests to me that you are right Kalle, in your interpretation
of who==0 for the IOPRIO_WHO_USER, since ioprio_get() uses
current_iser()->uid for its scan while ioprio_get() uses the UID
returned by make_kuid() (So, to be precise, I think who==0 in this
case means "the UID of the uer who is thye super user in this user
namespace"). If that's correct, it does of course need to be
documented. I'd be happy to get confirmation from Jens on this point.

I suppose that the differing meaning of who==0 for IOPRIO_WHO_USER in
ioprio_get() versus ioprio_set() is by design. But if so, like you
Kalle, I agree that it's a design point that is likely to surprise
users (and surprises here might have security implications). Again,
I'd like to get input from Jens.

In the meantime, I've applied the patch below to cover the other two cases.

Thanks,

Michael
--- a/man2/ioprio_set.2 +++ b/man2/ioprio_set.2 @@ -56,10 +56,16 @@ is interpreted, and has one of the following values: .B IOPRIO_WHO_PROCESS .I who is a process ID or thread ID identifying a single process or thread. +If +.I who +is 0, then operate on the calling thread. .TP .B IOPRIO_WHO_PGRP .I who is a process group ID identifying all the members of a process group. +If +.I who +is 0, then operate on the process group of which the caller is a member. .TP .B IOPRIO_WHO_USER .I who
#691195#15
Date:
2012-08-13 08:41:14 UTC
From:
To:
Hi Jens,

Would you be able to comment please...

Thanks,

Michael

On Sun, Jul 29, 2012 at 8:32 AM, Michael Kerrisk (man-pages) <mtk.manpages@gmail.com> wrote:

#691195#24
Date:
2012-10-22 20:05:11 UTC
From:
To:
Version: 3.42-1

Documented by Michael in 82fdd7c7d0, already in manpages 3.42.

Remaning items as http://bugs.debian.org/691195

#691195#29
Date:
2013-02-12 21:06:43 UTC
From:
To:
Hi Jens,

Would you be able to comment on
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=691195 please? Either
in that bug, or to this mail?

Thanks,

Michael