From: ebiederm@xmission.com (Eric W. Biederman)
To: Josh Triplett <josh@joshtriplett.org>
Cc: Andrew Morton <akpm@linux-foundation.org>,
Kees Cook <keescook@chromium.org>,
mtk.manpages@gmail.com, linux-api@vger.kernel.org,
linux-man@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH 2/2] groups: Allow unprivileged processes to use setgroups to drop groups
Date: Sat, 15 Nov 2014 09:37:27 -0600 [thread overview]
Message-ID: <87d28osceg.fsf@x220.int.ebiederm.org> (raw)
In-Reply-To: <0895c1f268bc0b01cc6c8ed4607d7c3953f49728.1416041823.git.josh@joshtriplett.org> (Josh Triplett's message of "Sat, 15 Nov 2014 01:01:02 -0800")
Josh Triplett <josh@joshtriplett.org> writes:
> Currently, unprivileged processes (without CAP_SETGID) cannot call
> setgroups at all. In particular, processes with a set of supplementary
> groups cannot further drop permissions without obtaining elevated
> permissions first.
>
> Allow unprivileged processes to call setgroups with a subset of their
> current groups; only require CAP_SETGID to add a group the process does
> not currently have.
A couple of questions.
- Is there precedence in other unix flavors for this?
- What motiviates this change?
- Have you looked to see if anything might for bug compatibilty
require applications not to be able to drop supplementary groups?
> The kernel already maintains the list of supplementary group IDs in
> sorted order, and setgroups already needs to sort the new list, so this
> just requires a linear comparison of the two sorted lists.
>
> This moves the CAP_SETGID test from setgroups into set_current_groups.
>
> Tested via the following test program:
>
> #include <err.h>
> #include <grp.h>
> #include <stdio.h>
> #include <sys/types.h>
> #include <unistd.h>
>
> void run_id(void)
> {
> pid_t p = fork();
> switch (p) {
> case -1:
> err(1, "fork");
> case 0:
> execl("/usr/bin/id", "id", NULL);
> err(1, "exec");
> default:
> if (waitpid(p, NULL, 0) < 0)
> err(1, "waitpid");
> }
> }
>
> int main(void)
> {
> gid_t list1[] = { 1, 2, 3, 4, 5 };
> gid_t list2[] = { 2, 3, 4 };
> run_id();
> if (setgroups(5, list1) < 0)
> err(1, "setgroups 1");
> run_id();
> if (setresgid(1, 1, 1) < 0)
> err(1, "setresgid");
> if (setresuid(1, 1, 1) < 0)
> err(1, "setresuid");
> run_id();
> if (setgroups(3, list2) < 0)
> err(1, "setgroups 2");
> run_id();
> if (setgroups(5, list1) < 0)
> err(1, "setgroups 3");
> run_id();
>
> return 0;
> }
>
> Without this patch, the test program gets EPERM from the second
> setgroups call, after dropping root privileges. With this patch, the
> test program successfully drops groups 1 and 5, but then gets EPERM from
> the third setgroups call, since that call attempts to add groups the
> process does not currently have.
>
> Signed-off-by: Josh Triplett <josh@joshtriplett.org>
> ---
> kernel/groups.c | 33 ++++++++++++++++++++++++++++++---
> kernel/uid16.c | 2 --
> 2 files changed, 30 insertions(+), 5 deletions(-)
>
> diff --git a/kernel/groups.c b/kernel/groups.c
> index f0667e7..fe7367d 100644
> --- a/kernel/groups.c
> +++ b/kernel/groups.c
> @@ -153,6 +153,29 @@ int groups_search(const struct group_info *group_info, kgid_t grp)
> return 0;
> }
>
> +/* Compare two sorted group lists; return true if the first is a subset of the
> + * second.
> + */
> +static bool is_subset(const struct group_info *g1, const struct group_info *g2)
> +{
> + unsigned int i, j;
> +
> + for (i = 0, j = 0; i < g1->ngroups; i++) {
> + kgid_t gid1 = GROUP_AT(g1, i);
> + kgid_t gid2;
> + for (; j < g2->ngroups; j++) {
> + gid2 = GROUP_AT(g2, j);
> + if (gid_lte(gid1, gid2))
> + break;
> + }
> + if (j >= g2->ngroups || !gid_eq(gid1, gid2))
> + return false;
> + j++;
> + }
> +
> + return true;
> +}
> +
> /**
> * set_groups_sorted - Change a group subscription in a set of credentials
> * @new: The newly prepared set of credentials to alter
> @@ -189,11 +212,17 @@ int set_current_groups(struct group_info *group_info)
> {
> struct cred *new;
>
> + groups_sort(group_info);
> new = prepare_creds();
> if (!new)
> return -ENOMEM;
> + if (!ns_capable(current_user_ns(), CAP_SETGID)
> + && !is_subset(group_info, new->group_info)) {
> + abort_creds(new);
> + return -EPERM;
> + }
>
> - set_groups(new, group_info);
> + set_groups_sorted(new, group_info);
> return commit_creds(new);
> }
>
> @@ -233,8 +262,6 @@ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist)
> struct group_info *group_info;
> int retval;
>
> - if (!ns_capable(current_user_ns(), CAP_SETGID))
> - return -EPERM;
> if ((unsigned)gidsetsize > NGROUPS_MAX)
> return -EINVAL;
>
> diff --git a/kernel/uid16.c b/kernel/uid16.c
> index 602e5bb..b27e167 100644
> --- a/kernel/uid16.c
> +++ b/kernel/uid16.c
> @@ -176,8 +176,6 @@ SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist)
> struct group_info *group_info;
> int retval;
>
> - if (!ns_capable(current_user_ns(), CAP_SETGID))
> - return -EPERM;
> if ((unsigned)gidsetsize > NGROUPS_MAX)
> return -EINVAL;
next prev parent reply other threads:[~2014-11-15 15:38 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-11-15 9:00 [PATCH 1/2] groups: Factor out a function to set a pre-sorted group list Josh Triplett
2014-11-15 9:01 ` [PATCH 2/2] groups: Allow unprivileged processes to use setgroups to drop groups Josh Triplett
2014-11-15 15:37 ` Eric W. Biederman [this message]
2014-11-15 19:29 ` Josh Triplett
2014-11-15 20:06 ` Andy Lutomirski
2014-11-15 20:20 ` Josh Triplett
2014-11-16 2:05 ` Theodore Ts'o
2014-11-16 2:35 ` Josh Triplett
2014-11-16 3:08 ` Eric W. Biederman
2014-11-16 5:07 ` Josh Triplett
2014-11-16 13:32 ` Theodore Ts'o
2014-11-16 15:42 ` Andy Lutomirski
2014-11-16 19:12 ` Josh Triplett
2014-11-16 19:09 ` Josh Triplett
2014-11-16 3:40 ` Theodore Ts'o
2014-11-16 4:52 ` Josh Triplett
2014-11-17 11:37 ` One Thousand Gnomes
2014-11-17 18:07 ` Andy Lutomirski
2014-11-17 22:11 ` Eric W.Biederman
2014-11-17 22:22 ` Andy Lutomirski
2014-11-17 22:37 ` josh
2014-11-18 0:56 ` Casey Schaufler
2014-11-17 18:06 ` Casey Schaufler
2014-11-17 18:31 ` Andy Lutomirski
2014-11-17 18:46 ` Andy Lutomirski
2014-11-17 18:51 ` Casey Schaufler
2014-11-27 16:59 ` [CFT][PATCH] userns: Avoid problems with negative groups Eric W. Biederman
2014-11-27 20:52 ` Andy Lutomirski
2014-11-28 5:21 ` Eric W. Biederman
2014-11-28 5:22 ` [CFT][PATCH v2] " Eric W. Biederman
2014-11-28 15:11 ` [CFT][PATCH] " Andy Lutomirski
2014-11-28 16:34 ` Eric W. Biederman
2014-11-28 17:11 ` Andy Lutomirski
2014-11-17 22:41 ` [PATCH 2/2] groups: Allow unprivileged processes to use setgroups to drop groups Eric W.Biederman
2014-11-17 22:50 ` Andy Lutomirski
2014-11-17 23:13 ` josh
2014-11-15 9:01 ` [PATCH manpages] getgroups.2: Document unprivileged setgroups calls Josh Triplett
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87d28osceg.fsf@x220.int.ebiederm.org \
--to=ebiederm@xmission.com \
--cc=akpm@linux-foundation.org \
--cc=josh@joshtriplett.org \
--cc=keescook@chromium.org \
--cc=linux-api@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-man@vger.kernel.org \
--cc=mtk.manpages@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome