* Unprivileged containers and co-ordinating user namespaces
@ 2016-04-28 22:02 ` James Bottomley
0 siblings, 0 replies; 28+ messages in thread
From: James Bottomley @ 2016-04-28 22:02 UTC (permalink / raw)
To: Linux Containers, util-linux-u79uwXL29TY76Z2rM5mHXA,
systemd-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
It's always been annoying to me that we never co-ordinate our use of
namespace resources, but it's never really mattered until the user
namespace came along because namespaces didn't overlap and the only
annoyance was not being able to use existing tools to manipulate other
containers (mainly not being able to us ip netns).
However, with the user namespace, it's become necessary to co-ordinate
if you're giving users a range of uids beyond their own because you
don't want to have two separate container users owning overlapping uid
numbers (especially if they're unprivileged) because that will lead to
all sorts of security issues. I think we need two things: a file
describing this for other things (like container orchestration systems
that want to know) and a mechanism for delegating the alloted uids to
the user. One possible way of doing this would be to have the init
system set up the correctly owned user namespace at boot time. It's
appealing to have the user sort out their own administration by simply
spawning new child user namespaces, but it adds the complexity that we
have to know what we're mapping to inside the namespace, whereas all
the administrator really cares about is what exterior uid range is
allocated (and that it remain that same range between reboots, because
these are the uids that's going to appear on disk).
Assuming everyone agrees it's a file and a utility, I'd propose the
file be
/etc/usernamespaces
and the format be <user>:<start>:<length>:<flags>
For the allocated uids. <user>,<start> and <length> are obvious but
<flags> would be used for things like deny setgroups and possibly other
privilege reductions.
Then we need a utility, say userns that has cap_setuid+cap_setgid and
takes as an argument the raw uid_map, gid_map the user wants to install
plus similar arguments to unshare. It then validates that the exterior
range are allowed by /etc/usernamespaces and sets up the usernamespace
with that range owned by the invoking user.
Container orchestration systems can either register their (probably
huge) ranges in the file, or simply use the file to know what ranges to
avoid.
If this sounds OK to people, I can code up a utility that does this,
which should probably belong in util-linux.
James
^ permalink raw reply [flat|nested] 28+ messages in thread
* Unprivileged containers and co-ordinating user namespaces
@ 2016-04-28 22:02 ` James Bottomley
0 siblings, 0 replies; 28+ messages in thread
From: James Bottomley @ 2016-04-28 22:02 UTC (permalink / raw)
To: Linux Containers, util-linux, systemd-devel
It's always been annoying to me that we never co-ordinate our use of
namespace resources, but it's never really mattered until the user
namespace came along because namespaces didn't overlap and the only
annoyance was not being able to use existing tools to manipulate other
containers (mainly not being able to us ip netns).
However, with the user namespace, it's become necessary to co-ordinate
if you're giving users a range of uids beyond their own because you
don't want to have two separate container users owning overlapping uid
numbers (especially if they're unprivileged) because that will lead to
all sorts of security issues. I think we need two things: a file
describing this for other things (like container orchestration systems
that want to know) and a mechanism for delegating the alloted uids to
the user. One possible way of doing this would be to have the init
system set up the correctly owned user namespace at boot time. It's
appealing to have the user sort out their own administration by simply
spawning new child user namespaces, but it adds the complexity that we
have to know what we're mapping to inside the namespace, whereas all
the administrator really cares about is what exterior uid range is
allocated (and that it remain that same range between reboots, because
these are the uids that's going to appear on disk).
Assuming everyone agrees it's a file and a utility, I'd propose the
file be
/etc/usernamespaces
and the format be <user>:<start>:<length>:<flags>
For the allocated uids. <user>,<start> and <length> are obvious but
<flags> would be used for things like deny setgroups and possibly other
privilege reductions.
Then we need a utility, say userns that has cap_setuid+cap_setgid and
takes as an argument the raw uid_map, gid_map the user wants to install
plus similar arguments to unshare. It then validates that the exterior
range are allowed by /etc/usernamespaces and sets up the usernamespace
with that range owned by the invoking user.
Container orchestration systems can either register their (probably
huge) ranges in the file, or simply use the file to know what ranges to
avoid.
If this sounds OK to people, I can code up a utility that does this,
which should probably belong in util-linux.
James
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
2016-04-28 22:02 ` James Bottomley
@ 2016-04-28 23:00 ` W. Trevor King
-1 siblings, 0 replies; 28+ messages in thread
From: W. Trevor King @ 2016-04-28 23:00 UTC (permalink / raw)
To: James Bottomley
Cc: Linux Containers, systemd-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
util-linux-u79uwXL29TY76Z2rM5mHXA
[-- Attachment #1.1: Type: text/plain, Size: 735 bytes --]
On Thu, Apr 28, 2016 at 03:02:08PM -0700, James Bottomley wrote:
> /etc/usernamespaces
>
> and the format be <user>:<start>:<length>:<flags>
>
> …
>
> If this sounds OK to people, I can code up a utility that does this,
> which should probably belong in util-linux.
This sounds a lot like shadow's newuidmap and newgidmap [1,2,3].
Cheers,
Trevor
[1]: https://github.com/shadow-maint/shadow/commit/673c2a6f9aa6c69588f4c1be08589b8d3475a520
[2]: http://man7.org/linux/man-pages/man1/newuidmap.1.html
[3]: http://man7.org/linux/man-pages/man5/subuid.5.html
--
This email may be signed or encrypted with GnuPG (http://www.gnupg.org).
For more information, see http://en.wikipedia.org/wiki/Pretty_Good_Privacy
[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
[-- Attachment #2: Type: text/plain, Size: 205 bytes --]
_______________________________________________
Containers mailing list
Containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
https://lists.linuxfoundation.org/mailman/listinfo/containers
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
@ 2016-04-28 23:00 ` W. Trevor King
0 siblings, 0 replies; 28+ messages in thread
From: W. Trevor King @ 2016-04-28 23:00 UTC (permalink / raw)
To: James Bottomley; +Cc: Linux Containers, util-linux, systemd-devel
[-- Attachment #1: Type: text/plain, Size: 735 bytes --]
On Thu, Apr 28, 2016 at 03:02:08PM -0700, James Bottomley wrote:
> /etc/usernamespaces
>
> and the format be <user>:<start>:<length>:<flags>
>
> …
>
> If this sounds OK to people, I can code up a utility that does this,
> which should probably belong in util-linux.
This sounds a lot like shadow's newuidmap and newgidmap [1,2,3].
Cheers,
Trevor
[1]: https://github.com/shadow-maint/shadow/commit/673c2a6f9aa6c69588f4c1be08589b8d3475a520
[2]: http://man7.org/linux/man-pages/man1/newuidmap.1.html
[3]: http://man7.org/linux/man-pages/man5/subuid.5.html
--
This email may be signed or encrypted with GnuPG (http://www.gnupg.org).
For more information, see http://en.wikipedia.org/wiki/Pretty_Good_Privacy
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
2016-04-28 23:00 ` W. Trevor King
@ 2016-04-29 15:38 ` James Bottomley
-1 siblings, 0 replies; 28+ messages in thread
From: James Bottomley @ 2016-04-29 15:38 UTC (permalink / raw)
To: W. Trevor King
Cc: Linux Containers, systemd-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
util-linux-u79uwXL29TY76Z2rM5mHXA
[-- Attachment #1.1: Type: text/plain, Size: 1141 bytes --]
On Thu, 2016-04-28 at 16:00 -0700, W. Trevor King wrote:
> On Thu, Apr 28, 2016 at 03:02:08PM -0700, James Bottomley wrote:
> > /etc/usernamespaces
> >
> > and the format be :::
> >
> > …
> >
> > If this sounds OK to people, I can code up a utility that does this,
> > which should probably belong in util-linux.
>
> This sounds a lot like shadow's newuidmap and newgidmap [1,2,3].
>
> Cheers,
> Trevor
>
> [1]: https://github.com/shadow-maint/shadow/commit/673c2a6f9aa6c69588f4c1be08589b8d3475a520
> [2]: http://man7.org/linux/man-pages/man1/newuidmap.1.html
> [3]: http://man7.org/linux/man-pages/man5/subuid.5.html
I think that mostly works. No-one's packaging it yet, which is why I
didn't notice. It also looks like the build dependencies have vastly
expanded, so I can't get it to build in the build service yet.
It looks like the only addition it needs is the setgroups flag for
newgidmap, which the security people will need, so I can patch that.
Plus it's trying to install newgidmap/newuidmap as setuid root rather
than cap_setuid/cap_setgid, but that's fixable in the spec file.
James
[-- Attachment #1.2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 473 bytes --]
[-- Attachment #2: Type: text/plain, Size: 205 bytes --]
_______________________________________________
Containers mailing list
Containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
https://lists.linuxfoundation.org/mailman/listinfo/containers
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
@ 2016-04-29 15:38 ` James Bottomley
0 siblings, 0 replies; 28+ messages in thread
From: James Bottomley @ 2016-04-29 15:38 UTC (permalink / raw)
To: W. Trevor King; +Cc: Linux Containers, util-linux, systemd-devel
[-- Attachment #1: Type: text/plain, Size: 1141 bytes --]
On Thu, 2016-04-28 at 16:00 -0700, W. Trevor King wrote:
> On Thu, Apr 28, 2016 at 03:02:08PM -0700, James Bottomley wrote:
> > /etc/usernamespaces
> >
> > and the format be :::
> >
> > …
> >
> > If this sounds OK to people, I can code up a utility that does this,
> > which should probably belong in util-linux.
>
> This sounds a lot like shadow's newuidmap and newgidmap [1,2,3].
>
> Cheers,
> Trevor
>
> [1]: https://github.com/shadow-maint/shadow/commit/673c2a6f9aa6c69588f4c1be08589b8d3475a520
> [2]: http://man7.org/linux/man-pages/man1/newuidmap.1.html
> [3]: http://man7.org/linux/man-pages/man5/subuid.5.html
I think that mostly works. No-one's packaging it yet, which is why I
didn't notice. It also looks like the build dependencies have vastly
expanded, so I can't get it to build in the build service yet.
It looks like the only addition it needs is the setgroups flag for
newgidmap, which the security people will need, so I can patch that.
Plus it's trying to install newgidmap/newuidmap as setuid root rather
than cap_setuid/cap_setgid, but that's fixable in the spec file.
James
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 473 bytes --]
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
[not found] ` <1461944328.2311.10.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
@ 2016-04-29 15:53 ` Serge E. Hallyn
2016-04-29 22:18 ` James Bottomley
2016-05-04 15:02 ` Eric W. Biederman
2 siblings, 0 replies; 28+ messages in thread
From: Serge E. Hallyn @ 2016-04-29 15:53 UTC (permalink / raw)
To: James Bottomley
Cc: systemd-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Linux Containers,
util-linux-u79uwXL29TY76Z2rM5mHXA
Quoting James Bottomley (James.Bottomley@HansenPartnership.com):
> On Thu, 2016-04-28 at 16:00 -0700, W. Trevor King wrote:
> > On Thu, Apr 28, 2016 at 03:02:08PM -0700, James Bottomley wrote:
> > > /etc/usernamespaces
> > >
> > > and the format be :::
> > >
> > > …
> > >
> > > If this sounds OK to people, I can code up a utility that does this,
> > > which should probably belong in util-linux.
> >
> > This sounds a lot like shadow's newuidmap and newgidmap [1,2,3].
> >
> > Cheers,
> > Trevor
> >
> > [1]: https://github.com/shadow-maint/shadow/commit/673c2a6f9aa6c69588f4c1be08589b8d3475a520
> > [2]: http://man7.org/linux/man-pages/man1/newuidmap.1.html
> > [3]: http://man7.org/linux/man-pages/man5/subuid.5.html
>
> I think that mostly works. No-one's packaging it yet, which is why I
https://packages.debian.org/jessie/uidmap
https://launchpad.net/ubuntu/yakkety/+package/uidmap
http://rpm.pbone.net/index.php3/stat/45/idpl/28763248/numer/1/nazwa/newuidmap
> didn't notice. It also looks like the build dependencies have vastly
> expanded, so I can't get it to build in the build service yet.
>
> It looks like the only addition it needs is the setgroups flag for
> newgidmap, which the security people will need, so I can patch that.
> Plus it's trying to install newgidmap/newuidmap as setuid root rather
> than cap_setuid/cap_setgid, but that's fixable in the spec file.
That would prevent it being installed inside user namespaces, until
the user namespaced file capabilities (see separate thread :) hit.
-serge
_______________________________________________
Containers mailing list
Containers@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/containers
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
2016-04-29 15:38 ` James Bottomley
(?)
@ 2016-04-29 15:53 ` Serge E. Hallyn
[not found] ` <20160429155303.GA8900-7LNsyQBKDXoIagZqoN9o3w@public.gmane.org>
-1 siblings, 1 reply; 28+ messages in thread
From: Serge E. Hallyn @ 2016-04-29 15:53 UTC (permalink / raw)
To: James Bottomley
Cc: W. Trevor King, Linux Containers, systemd-devel, util-linux
Quoting James Bottomley (James.Bottomley@HansenPartnership.com):
> On Thu, 2016-04-28 at 16:00 -0700, W. Trevor King wrote:
> > On Thu, Apr 28, 2016 at 03:02:08PM -0700, James Bottomley wrote:
> > > /etc/usernamespaces
> > >
> > > and the format be :::
> > >
> > > …
> > >
> > > If this sounds OK to people, I can code up a utility that does this,
> > > which should probably belong in util-linux.
> >
> > This sounds a lot like shadow's newuidmap and newgidmap [1,2,3].
> >
> > Cheers,
> > Trevor
> >
> > [1]: https://github.com/shadow-maint/shadow/commit/673c2a6f9aa6c69588f4c1be08589b8d3475a520
> > [2]: http://man7.org/linux/man-pages/man1/newuidmap.1.html
> > [3]: http://man7.org/linux/man-pages/man5/subuid.5.html
>
> I think that mostly works. No-one's packaging it yet, which is why I
https://packages.debian.org/jessie/uidmap
https://launchpad.net/ubuntu/yakkety/+package/uidmap
http://rpm.pbone.net/index.php3/stat/45/idpl/28763248/numer/1/nazwa/newuidmap
> didn't notice. It also looks like the build dependencies have vastly
> expanded, so I can't get it to build in the build service yet.
>
> It looks like the only addition it needs is the setgroups flag for
> newgidmap, which the security people will need, so I can patch that.
> Plus it's trying to install newgidmap/newuidmap as setuid root rather
> than cap_setuid/cap_setgid, but that's fixable in the spec file.
That would prevent it being installed inside user namespaces, until
the user namespaced file capabilities (see separate thread :) hit.
-serge
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
2016-04-29 15:53 ` Serge E. Hallyn
@ 2016-04-29 18:34 ` W. Trevor King
0 siblings, 0 replies; 28+ messages in thread
From: W. Trevor King @ 2016-04-29 18:34 UTC (permalink / raw)
To: Serge E. Hallyn
Cc: James Bottomley, Linux Containers,
systemd-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
util-linux-u79uwXL29TY76Z2rM5mHXA
[-- Attachment #1.1: Type: text/plain, Size: 944 bytes --]
On Fri, Apr 29, 2016 at 10:53:03AM -0500, Serge E. Hallyn wrote:
> Quoting James Bottomley:
> > I think that mostly works. No-one's packaging it yet, which is why I
>
> https://packages.debian.org/jessie/uidmap
> https://launchpad.net/ubuntu/yakkety/+package/uidmap
> http://rpm.pbone.net/index.php3/stat/45/idpl/28763248/numer/1/nazwa/newuidmap
On the other hand, Gentoo is waiting on a clean release tarball [1].
It looks like 4.3-1 was missing a clean autoreconf [2]? Has anything
been pushed since?
Cheers,
Trevor
[1]: https://bugs.gentoo.org/show_bug.cgi?id=580432#c3
[2]: https://lists.alioth.debian.org/pipermail/pkg-shadow-devel/2016-March/010924.html
Subject: [Pkg-shadow-devel] new shadow release candidate
Date: Tue Mar 22 18:58:55 UTC 2016
--
This email may be signed or encrypted with GnuPG (http://www.gnupg.org).
For more information, see http://en.wikipedia.org/wiki/Pretty_Good_Privacy
[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
[-- Attachment #2: Type: text/plain, Size: 205 bytes --]
_______________________________________________
Containers mailing list
Containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
https://lists.linuxfoundation.org/mailman/listinfo/containers
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
@ 2016-04-29 18:34 ` W. Trevor King
0 siblings, 0 replies; 28+ messages in thread
From: W. Trevor King @ 2016-04-29 18:34 UTC (permalink / raw)
To: Serge E. Hallyn
Cc: James Bottomley, Linux Containers, systemd-devel, util-linux
[-- Attachment #1: Type: text/plain, Size: 944 bytes --]
On Fri, Apr 29, 2016 at 10:53:03AM -0500, Serge E. Hallyn wrote:
> Quoting James Bottomley:
> > I think that mostly works. No-one's packaging it yet, which is why I
>
> https://packages.debian.org/jessie/uidmap
> https://launchpad.net/ubuntu/yakkety/+package/uidmap
> http://rpm.pbone.net/index.php3/stat/45/idpl/28763248/numer/1/nazwa/newuidmap
On the other hand, Gentoo is waiting on a clean release tarball [1].
It looks like 4.3-1 was missing a clean autoreconf [2]? Has anything
been pushed since?
Cheers,
Trevor
[1]: https://bugs.gentoo.org/show_bug.cgi?id=580432#c3
[2]: https://lists.alioth.debian.org/pipermail/pkg-shadow-devel/2016-March/010924.html
Subject: [Pkg-shadow-devel] new shadow release candidate
Date: Tue Mar 22 18:58:55 UTC 2016
--
This email may be signed or encrypted with GnuPG (http://www.gnupg.org).
For more information, see http://en.wikipedia.org/wiki/Pretty_Good_Privacy
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
[not found] ` <20160429183404.GE22888-q4NCUed9G3sTnwFZoN752g@public.gmane.org>
@ 2016-04-29 21:50 ` Serge E. Hallyn
0 siblings, 0 replies; 28+ messages in thread
From: Serge E. Hallyn @ 2016-04-29 21:50 UTC (permalink / raw)
To: W. Trevor King
Cc: James Bottomley, Linux Containers,
systemd-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
util-linux-u79uwXL29TY76Z2rM5mHXA
Quoting W. Trevor King (wking-vJI2gpByivqcqzYg7KEe8g@public.gmane.org):
> On Fri, Apr 29, 2016 at 10:53:03AM -0500, Serge E. Hallyn wrote:
> > Quoting James Bottomley:
> > > I think that mostly works. No-one's packaging it yet, which is why I
> >
> > https://packages.debian.org/jessie/uidmap
> > https://launchpad.net/ubuntu/yakkety/+package/uidmap
> > http://rpm.pbone.net/index.php3/stat/45/idpl/28763248/numer/1/nazwa/newuidmap
>
> On the other hand, Gentoo is waiting on a clean release tarball [1].
> It looks like 4.3-1 was missing a clean autoreconf [2]? Has anything
> been pushed since?
Nope, I've not had time to push it and noone has offered a patch.
Maybe I'll find time next week.
> Cheers,
> Trevor
>
> [1]: https://bugs.gentoo.org/show_bug.cgi?id=580432#c3
> [2]: https://lists.alioth.debian.org/pipermail/pkg-shadow-devel/2016-March/010924.html
> Subject: [Pkg-shadow-devel] new shadow release candidate
> Date: Tue Mar 22 18:58:55 UTC 2016
>
> --
> This email may be signed or encrypted with GnuPG (http://www.gnupg.org).
> For more information, see http://en.wikipedia.org/wiki/Pretty_Good_Privacy
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
2016-04-29 18:34 ` W. Trevor King
(?)
@ 2016-04-29 21:50 ` Serge E. Hallyn
-1 siblings, 0 replies; 28+ messages in thread
From: Serge E. Hallyn @ 2016-04-29 21:50 UTC (permalink / raw)
To: W. Trevor King
Cc: Serge E. Hallyn, James Bottomley, Linux Containers, systemd-devel,
util-linux
Quoting W. Trevor King (wking@tremily.us):
> On Fri, Apr 29, 2016 at 10:53:03AM -0500, Serge E. Hallyn wrote:
> > Quoting James Bottomley:
> > > I think that mostly works. No-one's packaging it yet, which is why I
> >
> > https://packages.debian.org/jessie/uidmap
> > https://launchpad.net/ubuntu/yakkety/+package/uidmap
> > http://rpm.pbone.net/index.php3/stat/45/idpl/28763248/numer/1/nazwa/newuidmap
>
> On the other hand, Gentoo is waiting on a clean release tarball [1].
> It looks like 4.3-1 was missing a clean autoreconf [2]? Has anything
> been pushed since?
Nope, I've not had time to push it and noone has offered a patch.
Maybe I'll find time next week.
> Cheers,
> Trevor
>
> [1]: https://bugs.gentoo.org/show_bug.cgi?id=580432#c3
> [2]: https://lists.alioth.debian.org/pipermail/pkg-shadow-devel/2016-March/010924.html
> Subject: [Pkg-shadow-devel] new shadow release candidate
> Date: Tue Mar 22 18:58:55 UTC 2016
>
> --
> This email may be signed or encrypted with GnuPG (http://www.gnupg.org).
> For more information, see http://en.wikipedia.org/wiki/Pretty_Good_Privacy
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
[not found] ` <1461944328.2311.10.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
2016-04-29 15:53 ` Serge E. Hallyn
@ 2016-04-29 22:18 ` James Bottomley
2016-05-04 15:02 ` Eric W. Biederman
2 siblings, 0 replies; 28+ messages in thread
From: James Bottomley @ 2016-04-29 22:18 UTC (permalink / raw)
To: Serge E. Hallyn
Cc: Linux Containers, systemd-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
util-linux-u79uwXL29TY76Z2rM5mHXA
[-- Attachment #1.1: Type: text/plain, Size: 9250 bytes --]
On Fri, 2016-04-29 at 08:38 -0700, James Bottomley wrote:
> On Thu, 2016-04-28 at 16:00 -0700, W. Trevor King wrote:
> > On Thu, Apr 28, 2016 at 03:02:08PM -0700, James Bottomley wrote:
> > > /etc/usernamespaces
> > >
> > > and the format be :::
> > >
> > > …
> > >
> > > If this sounds OK to people, I can code up a utility that does
> > > this,
> > > which should probably belong in util-linux.
> >
> > This sounds a lot like shadow's newuidmap and newgidmap [1,2,3].
> >
> > Cheers,
> > Trevor
> >
> > [1]: https://github.com/shadow-maint/shadow/commit/673c2a6f9aa6c695
> > 88f4c1be08589b8d3475a520
> > [2]: http://man7.org/linux/man-pages/man1/newuidmap.1.html
> > [3]: http://man7.org/linux/man-pages/man5/subuid.5.html
>
> I think that mostly works. No-one's packaging it yet, which is why I
> didn't notice. It also looks like the build dependencies have vastly
> expanded, so I can't get it to build in the build service yet.
>
> It looks like the only addition it needs is the setgroups flag for
> newgidmap, which the security people will need, so I can patch that.
How does this look for a patch?
James
---
diff --git a/lib/subordinateio.c b/lib/subordinateio.c
index 0d64a91..aa3c968 100644
--- a/lib/subordinateio.c
+++ b/lib/subordinateio.c
@@ -18,9 +18,10 @@ struct subordinate_range {
const char *owner;
unsigned long start;
unsigned long count;
+ const char *flags;
};
-#define NFIELDS 3
+#define NFIELDS 4
/*
* subordinate_dup: create a duplicate range
@@ -44,6 +45,16 @@ static /*@null@*/ /*@only@*/void *subordinate_dup (const void *ent)
free(range);
return NULL;
}
+ if (rangeent->flags) {
+ range->flags = strdup (rangeent->flags);
+ if (NULL == range->flags) {
+ free((void *)range->owner);
+ free(range);
+ return NULL;
+ }
+ } else {
+ range->flags = NULL;
+ }
range->start = rangeent->start;
range->count = rangeent->count;
@@ -111,13 +122,17 @@ static void *subordinate_parse (const char *line)
* There must be exactly NFIELDS colon separated fields or
* the entry is invalid. Also, fields must be non-blank.
*/
- if (i != NFIELDS || *fields[0] == '\0' || *fields[1] == '\0' || *fields[2] == '\0')
+ if ((i != NFIELDS && i != NFIELDS -1) || *fields[0] == '\0' || *fields[1] == '\0' || *fields[2] == '\0')
return NULL;
range.owner = fields[0];
if (getulong (fields[1], &range.start) == 0)
return NULL;
if (getulong (fields[2], &range.count) == 0)
return NULL;
+ if (i == NFIELDS)
+ range.flags = fields[3];
+ else
+ range.flags = NULL;
return ⦥
}
@@ -134,10 +149,11 @@ static int subordinate_put (const void *ent, FILE * file)
{
const struct subordinate_range *range = ent;
- return fprintf(file, "%s:%lu:%lu\n",
+ return fprintf(file, "%s:%lu:%lu:%s\n",
range->owner,
range->start,
- range->count) < 0 ? -1 : 0;
+ range->count,
+ range->flags ? range->flags : "") < 0 ? -1 : 0;
}
static struct commonio_ops subordinate_ops = {
@@ -295,7 +311,8 @@ static const struct subordinate_range *find_range(struct commonio_db *db,
* Returns true if @owner is authorized to use the range, false otherwise.
*/
static bool have_range(struct commonio_db *db,
- const char *owner, unsigned long start, unsigned long count)
+ const char *owner, unsigned long start, unsigned long count,
+ const char **flags)
{
const struct subordinate_range *range;
unsigned long end;
@@ -309,8 +326,11 @@ static bool have_range(struct commonio_db *db,
unsigned long last;
last = range->start + range->count - 1;
- if (last >= (start + count - 1))
+ if (last >= (start + count - 1)) {
+ if (flags)
+ *flags = range->flags;
return true;
+ }
count = end - last;
start = last + 1;
@@ -430,7 +450,7 @@ static int add_range(struct commonio_db *db,
range.count = count;
/* See if the range is already present */
- if (have_range(db, owner, start, count))
+ if (have_range(db, owner, start, count, NULL))
return 1;
/* Otherwise append the range */
@@ -585,7 +605,7 @@ bool sub_uid_assigned(const char *owner)
bool have_sub_uids(const char *owner, uid_t start, unsigned long count)
{
- return have_range (&subordinate_uid_db, owner, start, count);
+ return have_range (&subordinate_uid_db, owner, start, count, NULL);
}
int sub_uid_add (const char *owner, uid_t start, unsigned long count)
@@ -659,9 +679,9 @@ int sub_gid_open (int mode)
return commonio_open (&subordinate_gid_db, mode);
}
-bool have_sub_gids(const char *owner, gid_t start, unsigned long count)
+bool have_sub_gids(const char *owner, gid_t start, unsigned long count, const char **flags)
{
- return have_range(&subordinate_gid_db, owner, start, count);
+ return have_range(&subordinate_gid_db, owner, start, count, flags);
}
bool sub_gid_assigned(const char *owner)
diff --git a/lib/subordinateio.h b/lib/subordinateio.h
index a21d72b..7e47659 100644
--- a/lib/subordinateio.h
+++ b/lib/subordinateio.h
@@ -25,7 +25,7 @@ extern int sub_uid_remove (const char *owner, uid_t start, unsigned long count);
extern uid_t sub_uid_find_free_range(uid_t min, uid_t max, unsigned long count);
extern int sub_gid_close(void);
-extern bool have_sub_gids(const char *owner, gid_t start, unsigned long count);
+extern bool have_sub_gids(const char *owner, gid_t start, unsigned long count, const char **flags);
extern bool sub_gid_file_present (void);
extern bool sub_gid_assigned(const char *owner);
extern int sub_gid_lock (void);
diff --git a/libmisc/idmapping.c b/libmisc/idmapping.c
index 0dce634..7f7de88 100644
--- a/libmisc/idmapping.c
+++ b/libmisc/idmapping.c
@@ -106,7 +106,6 @@ void write_mapping(int proc_dir_fd, int ranges, struct map_range *mappings,
struct map_range *mapping;
size_t bufsize;
char *buf, *pos;
- int fd;
bufsize = ranges * ((ULONG_DIGITS + 1) * 3);
pos = buf = xmalloc(bufsize);
@@ -128,13 +127,20 @@ void write_mapping(int proc_dir_fd, int ranges, struct map_range *mappings,
}
/* Write the mapping to the maping file */
+ write_proc(proc_dir_fd, map_file, buf, pos - buf);
+}
+
+void write_proc(int proc_dir_fd, const char *map_file, void *buf, int len)
+{
+ int fd;
+
fd = openat(proc_dir_fd, map_file, O_WRONLY);
if (fd < 0) {
fprintf(stderr, _("%s: open of %s failed: %s\n"),
Prog, map_file, strerror(errno));
exit(EXIT_FAILURE);
}
- if (write(fd, buf, pos - buf) != (pos - buf)) {
+ if (write(fd, buf, len) != len) {
fprintf(stderr, _("%s: write to %s failed: %s\n"),
Prog, map_file, strerror(errno));
exit(EXIT_FAILURE);
diff --git a/libmisc/idmapping.h b/libmisc/idmapping.h
index 58d000f..c2cec38 100644
--- a/libmisc/idmapping.h
+++ b/libmisc/idmapping.h
@@ -39,6 +39,7 @@ struct map_range {
extern struct map_range *get_map_ranges(int ranges, int argc, char **argv);
extern void write_mapping(int proc_dir_fd, int ranges,
struct map_range *mappings, const char *map_file);
+extern void write_proc(int proc_dir_fd, const char *map_file, void *buf, int len);
#endif /* _ID_MAPPING_H_ */
diff --git a/src/newgidmap.c b/src/newgidmap.c
index 451c6a6..8d64e3b 100644
--- a/src/newgidmap.c
+++ b/src/newgidmap.c
@@ -46,14 +46,14 @@
*/
const char *Prog;
-static bool verify_range(struct passwd *pw, struct map_range *range)
+static bool verify_range(struct passwd *pw, struct map_range *range, const char **flags)
{
/* An empty range is invalid */
if (range->count == 0)
return false;
/* Test /etc/subgid */
- if (have_sub_gids(pw->pw_name, range->lower, range->count))
+ if (have_sub_gids(pw->pw_name, range->lower, range->count, flags))
return true;
/* Allow a process to map it's own gid */
@@ -64,14 +64,14 @@ static bool verify_range(struct passwd *pw, struct map_range *range)
}
static void verify_ranges(struct passwd *pw, int ranges,
- struct map_range *mappings)
+ struct map_range *mappings, const char **flags)
{
struct map_range *mapping;
int idx;
mapping = mappings;
for (idx = 0; idx < ranges; idx++, mapping++) {
- if (!verify_range(pw, mapping)) {
+ if (!verify_range(pw, mapping, flags)) {
fprintf(stderr, _( "%s: gid range [%lu-%lu) -> [%lu-%lu) not allowed\n"),
Prog,
mapping->upper,
@@ -103,6 +103,7 @@ int main(int argc, char **argv)
struct stat st;
struct passwd *pw;
int written;
+ const char *flags;
Prog = Basename (argv[0]);
@@ -177,7 +178,18 @@ int main(int argc, char **argv)
if (!mappings)
usage();
- verify_ranges(pw, ranges, mappings);
+ verify_ranges(pw, ranges, mappings, &flags);
+
+ if (flags && strlen(flags) != 0) {
+ /* only allowed flag is currently deny */
+ if (strcmp(flags, "deny") == 0) {
+ write_proc(proc_dir_fd, "setgroups", "deny", strlen("deny"));
+ } else {
+ fprintf(stderr, _("%s: illegal flag in map file: %s\n"),
+ Prog, flags);
+ exit(EXIT_FAILURE);
+ }
+ }
write_mapping(proc_dir_fd, ranges, mappings, "gid_map");
sub_gid_close();
[-- Attachment #1.2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 473 bytes --]
[-- Attachment #2: Type: text/plain, Size: 205 bytes --]
_______________________________________________
Containers mailing list
Containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
https://lists.linuxfoundation.org/mailman/listinfo/containers
^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
2016-04-29 15:38 ` James Bottomley
(?)
(?)
@ 2016-04-29 22:18 ` James Bottomley
2016-05-01 16:37 ` Serge Hallyn
[not found] ` <1461968310.16292.20.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
-1 siblings, 2 replies; 28+ messages in thread
From: James Bottomley @ 2016-04-29 22:18 UTC (permalink / raw)
To: Serge E. Hallyn; +Cc: Linux Containers, systemd-devel, util-linux
[-- Attachment #1: Type: text/plain, Size: 9250 bytes --]
On Fri, 2016-04-29 at 08:38 -0700, James Bottomley wrote:
> On Thu, 2016-04-28 at 16:00 -0700, W. Trevor King wrote:
> > On Thu, Apr 28, 2016 at 03:02:08PM -0700, James Bottomley wrote:
> > > /etc/usernamespaces
> > >
> > > and the format be :::
> > >
> > > …
> > >
> > > If this sounds OK to people, I can code up a utility that does
> > > this,
> > > which should probably belong in util-linux.
> >
> > This sounds a lot like shadow's newuidmap and newgidmap [1,2,3].
> >
> > Cheers,
> > Trevor
> >
> > [1]: https://github.com/shadow-maint/shadow/commit/673c2a6f9aa6c695
> > 88f4c1be08589b8d3475a520
> > [2]: http://man7.org/linux/man-pages/man1/newuidmap.1.html
> > [3]: http://man7.org/linux/man-pages/man5/subuid.5.html
>
> I think that mostly works. No-one's packaging it yet, which is why I
> didn't notice. It also looks like the build dependencies have vastly
> expanded, so I can't get it to build in the build service yet.
>
> It looks like the only addition it needs is the setgroups flag for
> newgidmap, which the security people will need, so I can patch that.
How does this look for a patch?
James
---
diff --git a/lib/subordinateio.c b/lib/subordinateio.c
index 0d64a91..aa3c968 100644
--- a/lib/subordinateio.c
+++ b/lib/subordinateio.c
@@ -18,9 +18,10 @@ struct subordinate_range {
const char *owner;
unsigned long start;
unsigned long count;
+ const char *flags;
};
-#define NFIELDS 3
+#define NFIELDS 4
/*
* subordinate_dup: create a duplicate range
@@ -44,6 +45,16 @@ static /*@null@*/ /*@only@*/void *subordinate_dup (const void *ent)
free(range);
return NULL;
}
+ if (rangeent->flags) {
+ range->flags = strdup (rangeent->flags);
+ if (NULL == range->flags) {
+ free((void *)range->owner);
+ free(range);
+ return NULL;
+ }
+ } else {
+ range->flags = NULL;
+ }
range->start = rangeent->start;
range->count = rangeent->count;
@@ -111,13 +122,17 @@ static void *subordinate_parse (const char *line)
* There must be exactly NFIELDS colon separated fields or
* the entry is invalid. Also, fields must be non-blank.
*/
- if (i != NFIELDS || *fields[0] == '\0' || *fields[1] == '\0' || *fields[2] == '\0')
+ if ((i != NFIELDS && i != NFIELDS -1) || *fields[0] == '\0' || *fields[1] == '\0' || *fields[2] == '\0')
return NULL;
range.owner = fields[0];
if (getulong (fields[1], &range.start) == 0)
return NULL;
if (getulong (fields[2], &range.count) == 0)
return NULL;
+ if (i == NFIELDS)
+ range.flags = fields[3];
+ else
+ range.flags = NULL;
return ⦥
}
@@ -134,10 +149,11 @@ static int subordinate_put (const void *ent, FILE * file)
{
const struct subordinate_range *range = ent;
- return fprintf(file, "%s:%lu:%lu\n",
+ return fprintf(file, "%s:%lu:%lu:%s\n",
range->owner,
range->start,
- range->count) < 0 ? -1 : 0;
+ range->count,
+ range->flags ? range->flags : "") < 0 ? -1 : 0;
}
static struct commonio_ops subordinate_ops = {
@@ -295,7 +311,8 @@ static const struct subordinate_range *find_range(struct commonio_db *db,
* Returns true if @owner is authorized to use the range, false otherwise.
*/
static bool have_range(struct commonio_db *db,
- const char *owner, unsigned long start, unsigned long count)
+ const char *owner, unsigned long start, unsigned long count,
+ const char **flags)
{
const struct subordinate_range *range;
unsigned long end;
@@ -309,8 +326,11 @@ static bool have_range(struct commonio_db *db,
unsigned long last;
last = range->start + range->count - 1;
- if (last >= (start + count - 1))
+ if (last >= (start + count - 1)) {
+ if (flags)
+ *flags = range->flags;
return true;
+ }
count = end - last;
start = last + 1;
@@ -430,7 +450,7 @@ static int add_range(struct commonio_db *db,
range.count = count;
/* See if the range is already present */
- if (have_range(db, owner, start, count))
+ if (have_range(db, owner, start, count, NULL))
return 1;
/* Otherwise append the range */
@@ -585,7 +605,7 @@ bool sub_uid_assigned(const char *owner)
bool have_sub_uids(const char *owner, uid_t start, unsigned long count)
{
- return have_range (&subordinate_uid_db, owner, start, count);
+ return have_range (&subordinate_uid_db, owner, start, count, NULL);
}
int sub_uid_add (const char *owner, uid_t start, unsigned long count)
@@ -659,9 +679,9 @@ int sub_gid_open (int mode)
return commonio_open (&subordinate_gid_db, mode);
}
-bool have_sub_gids(const char *owner, gid_t start, unsigned long count)
+bool have_sub_gids(const char *owner, gid_t start, unsigned long count, const char **flags)
{
- return have_range(&subordinate_gid_db, owner, start, count);
+ return have_range(&subordinate_gid_db, owner, start, count, flags);
}
bool sub_gid_assigned(const char *owner)
diff --git a/lib/subordinateio.h b/lib/subordinateio.h
index a21d72b..7e47659 100644
--- a/lib/subordinateio.h
+++ b/lib/subordinateio.h
@@ -25,7 +25,7 @@ extern int sub_uid_remove (const char *owner, uid_t start, unsigned long count);
extern uid_t sub_uid_find_free_range(uid_t min, uid_t max, unsigned long count);
extern int sub_gid_close(void);
-extern bool have_sub_gids(const char *owner, gid_t start, unsigned long count);
+extern bool have_sub_gids(const char *owner, gid_t start, unsigned long count, const char **flags);
extern bool sub_gid_file_present (void);
extern bool sub_gid_assigned(const char *owner);
extern int sub_gid_lock (void);
diff --git a/libmisc/idmapping.c b/libmisc/idmapping.c
index 0dce634..7f7de88 100644
--- a/libmisc/idmapping.c
+++ b/libmisc/idmapping.c
@@ -106,7 +106,6 @@ void write_mapping(int proc_dir_fd, int ranges, struct map_range *mappings,
struct map_range *mapping;
size_t bufsize;
char *buf, *pos;
- int fd;
bufsize = ranges * ((ULONG_DIGITS + 1) * 3);
pos = buf = xmalloc(bufsize);
@@ -128,13 +127,20 @@ void write_mapping(int proc_dir_fd, int ranges, struct map_range *mappings,
}
/* Write the mapping to the maping file */
+ write_proc(proc_dir_fd, map_file, buf, pos - buf);
+}
+
+void write_proc(int proc_dir_fd, const char *map_file, void *buf, int len)
+{
+ int fd;
+
fd = openat(proc_dir_fd, map_file, O_WRONLY);
if (fd < 0) {
fprintf(stderr, _("%s: open of %s failed: %s\n"),
Prog, map_file, strerror(errno));
exit(EXIT_FAILURE);
}
- if (write(fd, buf, pos - buf) != (pos - buf)) {
+ if (write(fd, buf, len) != len) {
fprintf(stderr, _("%s: write to %s failed: %s\n"),
Prog, map_file, strerror(errno));
exit(EXIT_FAILURE);
diff --git a/libmisc/idmapping.h b/libmisc/idmapping.h
index 58d000f..c2cec38 100644
--- a/libmisc/idmapping.h
+++ b/libmisc/idmapping.h
@@ -39,6 +39,7 @@ struct map_range {
extern struct map_range *get_map_ranges(int ranges, int argc, char **argv);
extern void write_mapping(int proc_dir_fd, int ranges,
struct map_range *mappings, const char *map_file);
+extern void write_proc(int proc_dir_fd, const char *map_file, void *buf, int len);
#endif /* _ID_MAPPING_H_ */
diff --git a/src/newgidmap.c b/src/newgidmap.c
index 451c6a6..8d64e3b 100644
--- a/src/newgidmap.c
+++ b/src/newgidmap.c
@@ -46,14 +46,14 @@
*/
const char *Prog;
-static bool verify_range(struct passwd *pw, struct map_range *range)
+static bool verify_range(struct passwd *pw, struct map_range *range, const char **flags)
{
/* An empty range is invalid */
if (range->count == 0)
return false;
/* Test /etc/subgid */
- if (have_sub_gids(pw->pw_name, range->lower, range->count))
+ if (have_sub_gids(pw->pw_name, range->lower, range->count, flags))
return true;
/* Allow a process to map it's own gid */
@@ -64,14 +64,14 @@ static bool verify_range(struct passwd *pw, struct map_range *range)
}
static void verify_ranges(struct passwd *pw, int ranges,
- struct map_range *mappings)
+ struct map_range *mappings, const char **flags)
{
struct map_range *mapping;
int idx;
mapping = mappings;
for (idx = 0; idx < ranges; idx++, mapping++) {
- if (!verify_range(pw, mapping)) {
+ if (!verify_range(pw, mapping, flags)) {
fprintf(stderr, _( "%s: gid range [%lu-%lu) -> [%lu-%lu) not allowed\n"),
Prog,
mapping->upper,
@@ -103,6 +103,7 @@ int main(int argc, char **argv)
struct stat st;
struct passwd *pw;
int written;
+ const char *flags;
Prog = Basename (argv[0]);
@@ -177,7 +178,18 @@ int main(int argc, char **argv)
if (!mappings)
usage();
- verify_ranges(pw, ranges, mappings);
+ verify_ranges(pw, ranges, mappings, &flags);
+
+ if (flags && strlen(flags) != 0) {
+ /* only allowed flag is currently deny */
+ if (strcmp(flags, "deny") == 0) {
+ write_proc(proc_dir_fd, "setgroups", "deny", strlen("deny"));
+ } else {
+ fprintf(stderr, _("%s: illegal flag in map file: %s\n"),
+ Prog, flags);
+ exit(EXIT_FAILURE);
+ }
+ }
write_mapping(proc_dir_fd, ranges, mappings, "gid_map");
sub_gid_close();
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 473 bytes --]
^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
[not found] ` <1461968310.16292.20.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
@ 2016-05-01 16:37 ` Serge Hallyn
0 siblings, 0 replies; 28+ messages in thread
From: Serge Hallyn @ 2016-05-01 16:37 UTC (permalink / raw)
To: James Bottomley
Cc: Linux Containers, systemd-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
util-linux-u79uwXL29TY76Z2rM5mHXA
> > It looks like the only addition it needs is the setgroups flag for
> > newgidmap, which the security people will need, so I can patch that.
>
> How does this look for a patch?
Certainly deny is a terrible keyword for this, given the somewhat convoluted case it represents. Maybe lockgroups or nosetgroup? And of course it'll need a clear explanation of what it does in the subgid manpage. But really i don't know that this can work the way you want it to. Can you describe your use case?
The intent of setgroups is to keep *unprivileged* writers of gid_map from dropping a gid which is blocking a file access from the user. But newgidmap runs suid root (or cap_gid when you are through :), so the user can trivially assign just one authorized gid, not the whole range, and bypass the acls that way.
At the very least you would want to enforce the use of a whole range in the lockgroup case, but even there i question it's value.
-Serge
> James
>
> ---
>
> diff --git a/lib/subordinateio.c b/lib/subordinateio.c
> index 0d64a91..aa3c968 100644
> --- a/lib/subordinateio.c
> +++ b/lib/subordinateio.c
> @@ -18,9 +18,10 @@ struct subordinate_range {
> const char *owner;
> unsigned long start;
> unsigned long count;
> + const char *flags;
> };
>
> -#define NFIELDS 3
> +#define NFIELDS 4
>
> /*
> * subordinate_dup: create a duplicate range
> @@ -44,6 +45,16 @@ static /*@null@*/ /*@only@*/void *subordinate_dup
> (const void *ent) free(range);
> return NULL;
> }
> + if (rangeent->flags) {
> + range->flags = strdup (rangeent->flags);
> + if (NULL == range->flags) {
> + free((void *)range->owner);
> + free(range);
> + return NULL;
> + }
> + } else {
> + range->flags = NULL;
> + }
> range->start = rangeent->start;
> range->count = rangeent->count;
>
> @@ -111,13 +122,17 @@ static void *subordinate_parse (const char *line)
> * There must be exactly NFIELDS colon separated fields or
> * the entry is invalid. Also, fields must be non-blank.
> */
> - if (i != NFIELDS || *fields[0] == '\0' || *fields[1] == '\0' ||
> *fields[2] == '\0') + if ((i != NFIELDS && i != NFIELDS -1) ||
> *fields[0] == '\0' || *fields[1] == '\0' || *fields[2] == '\0') return
> NULL; range.owner = fields[0];
> if (getulong (fields[1], &range.start) == 0)
> return NULL;
> if (getulong (fields[2], &range.count) == 0)
> return NULL;
> + if (i == NFIELDS)
> + range.flags = fields[3];
> + else
> + range.flags = NULL;
>
> return ⦥
> }
> @@ -134,10 +149,11 @@ static int subordinate_put (const void *ent, FILE
> * file) {
> const struct subordinate_range *range = ent;
>
> - return fprintf(file, "%s:%lu:%lu\n",
> + return fprintf(file, "%s:%lu:%lu:%s\n",
> range->owner,
> range->start,
> - range->count) < 0 ? -1 : 0;
> + range->count,
> + range->flags ? range->flags : "") < 0 ? -1 : 0;
> }
>
> static struct commonio_ops subordinate_ops = {
> @@ -295,7 +311,8 @@ static const struct subordinate_range
> *find_range(struct commonio_db *db, * Returns true if @owner is
> authorized to use the range, false otherwise. */
> static bool have_range(struct commonio_db *db,
> - const char *owner, unsigned long start, unsigned long count)
> + const char *owner, unsigned long start, unsigned long count,
> + const char **flags)
> {
> const struct subordinate_range *range;
> unsigned long end;
> @@ -309,8 +326,11 @@ static bool have_range(struct commonio_db *db,
> unsigned long last;
>
> last = range->start + range->count - 1;
> - if (last >= (start + count - 1))
> + if (last >= (start + count - 1)) {
> + if (flags)
> + *flags = range->flags;
> return true;
> + }
>
> count = end - last;
> start = last + 1;
> @@ -430,7 +450,7 @@ static int add_range(struct commonio_db *db,
> range.count = count;
>
> /* See if the range is already present */
> - if (have_range(db, owner, start, count))
> + if (have_range(db, owner, start, count, NULL))
> return 1;
>
> /* Otherwise append the range */
> @@ -585,7 +605,7 @@ bool sub_uid_assigned(const char *owner)
>
> bool have_sub_uids(const char *owner, uid_t start, unsigned long count)
> {
> - return have_range (&subordinate_uid_db, owner, start, count);
> + return have_range (&subordinate_uid_db, owner, start, count, NULL);
> }
>
> int sub_uid_add (const char *owner, uid_t start, unsigned long count)
> @@ -659,9 +679,9 @@ int sub_gid_open (int mode)
> return commonio_open (&subordinate_gid_db, mode);
> }
>
> -bool have_sub_gids(const char *owner, gid_t start, unsigned long count)
> +bool have_sub_gids(const char *owner, gid_t start, unsigned long count,
> const char **flags) {
> - return have_range(&subordinate_gid_db, owner, start, count);
> + return have_range(&subordinate_gid_db, owner, start, count, flags);
> }
>
> bool sub_gid_assigned(const char *owner)
> diff --git a/lib/subordinateio.h b/lib/subordinateio.h
> index a21d72b..7e47659 100644
> --- a/lib/subordinateio.h
> +++ b/lib/subordinateio.h
> @@ -25,7 +25,7 @@ extern int sub_uid_remove (const char *owner, uid_t
> start, unsigned long count); extern uid_t sub_uid_find_free_range(uid_t
> min, uid_t max, unsigned long count);
> extern int sub_gid_close(void);
> -extern bool have_sub_gids(const char *owner, gid_t start, unsigned long
> count); +extern bool have_sub_gids(const char *owner, gid_t start,
> unsigned long count, const char **flags); extern bool
> sub_gid_file_present (void); extern bool sub_gid_assigned(const char
> *owner); extern int sub_gid_lock (void);
> diff --git a/libmisc/idmapping.c b/libmisc/idmapping.c
> index 0dce634..7f7de88 100644
> --- a/libmisc/idmapping.c
> +++ b/libmisc/idmapping.c
> @@ -106,7 +106,6 @@ void write_mapping(int proc_dir_fd, int ranges,
> struct map_range *mappings, struct map_range *mapping;
> size_t bufsize;
> char *buf, *pos;
> - int fd;
>
> bufsize = ranges * ((ULONG_DIGITS + 1) * 3);
> pos = buf = xmalloc(bufsize);
> @@ -128,13 +127,20 @@ void write_mapping(int proc_dir_fd, int ranges,
> struct map_range *mappings, }
>
> /* Write the mapping to the maping file */
> + write_proc(proc_dir_fd, map_file, buf, pos - buf);
> +}
> +
> +void write_proc(int proc_dir_fd, const char *map_file, void *buf, int
> len) +{
> + int fd;
> +
> fd = openat(proc_dir_fd, map_file, O_WRONLY);
> if (fd < 0) {
> fprintf(stderr, _("%s: open of %s failed: %s\n"),
> Prog, map_file, strerror(errno));
> exit(EXIT_FAILURE);
> }
> - if (write(fd, buf, pos - buf) != (pos - buf)) {
> + if (write(fd, buf, len) != len) {
> fprintf(stderr, _("%s: write to %s failed: %s\n"),
> Prog, map_file, strerror(errno));
> exit(EXIT_FAILURE);
> diff --git a/libmisc/idmapping.h b/libmisc/idmapping.h
> index 58d000f..c2cec38 100644
> --- a/libmisc/idmapping.h
> +++ b/libmisc/idmapping.h
> @@ -39,6 +39,7 @@ struct map_range {
> extern struct map_range *get_map_ranges(int ranges, int argc, char
> **argv); extern void write_mapping(int proc_dir_fd, int ranges,
> struct map_range *mappings, const char *map_file);
> +extern void write_proc(int proc_dir_fd, const char *map_file, void
> *buf, int len);
> #endif /* _ID_MAPPING_H_ */
>
> diff --git a/src/newgidmap.c b/src/newgidmap.c
> index 451c6a6..8d64e3b 100644
> --- a/src/newgidmap.c
> +++ b/src/newgidmap.c
> @@ -46,14 +46,14 @@
> */
> const char *Prog;
>
> -static bool verify_range(struct passwd *pw, struct map_range *range)
> +static bool verify_range(struct passwd *pw, struct map_range *range,
> const char **flags) {
> /* An empty range is invalid */
> if (range->count == 0)
> return false;
>
> /* Test /etc/subgid */
> - if (have_sub_gids(pw->pw_name, range->lower, range->count))
> + if (have_sub_gids(pw->pw_name, range->lower, range->count, flags))
> return true;
>
> /* Allow a process to map it's own gid */
> @@ -64,14 +64,14 @@ static bool verify_range(struct passwd *pw, struct
> map_range *range) }
>
> static void verify_ranges(struct passwd *pw, int ranges,
> - struct map_range *mappings)
> + struct map_range *mappings, const char **flags)
> {
> struct map_range *mapping;
> int idx;
>
> mapping = mappings;
> for (idx = 0; idx < ranges; idx++, mapping++) {
> - if (!verify_range(pw, mapping)) {
> + if (!verify_range(pw, mapping, flags)) {
> fprintf(stderr, _( "%s: gid range [%lu-%lu) -> [%lu-%lu) not
> allowed\n"), Prog,
> mapping->upper,
> @@ -103,6 +103,7 @@ int main(int argc, char **argv)
> struct stat st;
> struct passwd *pw;
> int written;
> + const char *flags;
>
> Prog = Basename (argv[0]);
>
> @@ -177,7 +178,18 @@ int main(int argc, char **argv)
> if (!mappings)
> usage();
>
> - verify_ranges(pw, ranges, mappings);
> + verify_ranges(pw, ranges, mappings, &flags);
> +
> + if (flags && strlen(flags) != 0) {
> + /* only allowed flag is currently deny */
> + if (strcmp(flags, "deny") == 0) {
> + write_proc(proc_dir_fd, "setgroups", "deny", strlen("deny"));
> + } else {
> + fprintf(stderr, _("%s: illegal flag in map file: %s\n"),
> + Prog, flags);
> + exit(EXIT_FAILURE);
> + }
> + }
>
> write_mapping(proc_dir_fd, ranges, mappings, "gid_map");
> sub_gid_close();
_______________________________________________
Containers mailing list
Containers@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/containers
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
2016-04-29 22:18 ` James Bottomley
@ 2016-05-01 16:37 ` Serge Hallyn
2016-05-01 23:29 ` James Bottomley
2016-05-01 23:29 ` James Bottomley
[not found] ` <1461968310.16292.20.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
1 sibling, 2 replies; 28+ messages in thread
From: Serge Hallyn @ 2016-05-01 16:37 UTC (permalink / raw)
To: James Bottomley; +Cc: Linux Containers, systemd-devel, util-linux
> > It looks like the only addition it needs is the setgroups flag for
> > newgidmap, which the security people will need, so I can patch that.
>
> How does this look for a patch?
Certainly deny is a terrible keyword for this, given the somewhat convoluted case it represents. Maybe lockgroups or nosetgroup? And of course it'll need a clear explanation of what it does in the subgid manpage. But really i don't know that this can work the way you want it to. Can you describe your use case?
The intent of setgroups is to keep *unprivileged* writers of gid_map from dropping a gid which is blocking a file access from the user. But newgidmap runs suid root (or cap_gid when you are through :), so the user can trivially assign just one authorized gid, not the whole range, and bypass the acls that way.
At the very least you would want to enforce the use of a whole range in the lockgroup case, but even there i question it's value.
-Serge
> James
>
> ---
>
> diff --git a/lib/subordinateio.c b/lib/subordinateio.c
> index 0d64a91..aa3c968 100644
> --- a/lib/subordinateio.c
> +++ b/lib/subordinateio.c
> @@ -18,9 +18,10 @@ struct subordinate_range {
> const char *owner;
> unsigned long start;
> unsigned long count;
> + const char *flags;
> };
>
> -#define NFIELDS 3
> +#define NFIELDS 4
>
> /*
> * subordinate_dup: create a duplicate range
> @@ -44,6 +45,16 @@ static /*@null@*/ /*@only@*/void *subordinate_dup
> (const void *ent) free(range);
> return NULL;
> }
> + if (rangeent->flags) {
> + range->flags = strdup (rangeent->flags);
> + if (NULL == range->flags) {
> + free((void *)range->owner);
> + free(range);
> + return NULL;
> + }
> + } else {
> + range->flags = NULL;
> + }
> range->start = rangeent->start;
> range->count = rangeent->count;
>
> @@ -111,13 +122,17 @@ static void *subordinate_parse (const char *line)
> * There must be exactly NFIELDS colon separated fields or
> * the entry is invalid. Also, fields must be non-blank.
> */
> - if (i != NFIELDS || *fields[0] == '\0' || *fields[1] == '\0' ||
> *fields[2] == '\0') + if ((i != NFIELDS && i != NFIELDS -1) ||
> *fields[0] == '\0' || *fields[1] == '\0' || *fields[2] == '\0') return
> NULL; range.owner = fields[0];
> if (getulong (fields[1], &range.start) == 0)
> return NULL;
> if (getulong (fields[2], &range.count) == 0)
> return NULL;
> + if (i == NFIELDS)
> + range.flags = fields[3];
> + else
> + range.flags = NULL;
>
> return ⦥
> }
> @@ -134,10 +149,11 @@ static int subordinate_put (const void *ent, FILE
> * file) {
> const struct subordinate_range *range = ent;
>
> - return fprintf(file, "%s:%lu:%lu\n",
> + return fprintf(file, "%s:%lu:%lu:%s\n",
> range->owner,
> range->start,
> - range->count) < 0 ? -1 : 0;
> + range->count,
> + range->flags ? range->flags : "") < 0 ? -1 : 0;
> }
>
> static struct commonio_ops subordinate_ops = {
> @@ -295,7 +311,8 @@ static const struct subordinate_range
> *find_range(struct commonio_db *db, * Returns true if @owner is
> authorized to use the range, false otherwise. */
> static bool have_range(struct commonio_db *db,
> - const char *owner, unsigned long start, unsigned long count)
> + const char *owner, unsigned long start, unsigned long count,
> + const char **flags)
> {
> const struct subordinate_range *range;
> unsigned long end;
> @@ -309,8 +326,11 @@ static bool have_range(struct commonio_db *db,
> unsigned long last;
>
> last = range->start + range->count - 1;
> - if (last >= (start + count - 1))
> + if (last >= (start + count - 1)) {
> + if (flags)
> + *flags = range->flags;
> return true;
> + }
>
> count = end - last;
> start = last + 1;
> @@ -430,7 +450,7 @@ static int add_range(struct commonio_db *db,
> range.count = count;
>
> /* See if the range is already present */
> - if (have_range(db, owner, start, count))
> + if (have_range(db, owner, start, count, NULL))
> return 1;
>
> /* Otherwise append the range */
> @@ -585,7 +605,7 @@ bool sub_uid_assigned(const char *owner)
>
> bool have_sub_uids(const char *owner, uid_t start, unsigned long count)
> {
> - return have_range (&subordinate_uid_db, owner, start, count);
> + return have_range (&subordinate_uid_db, owner, start, count, NULL);
> }
>
> int sub_uid_add (const char *owner, uid_t start, unsigned long count)
> @@ -659,9 +679,9 @@ int sub_gid_open (int mode)
> return commonio_open (&subordinate_gid_db, mode);
> }
>
> -bool have_sub_gids(const char *owner, gid_t start, unsigned long count)
> +bool have_sub_gids(const char *owner, gid_t start, unsigned long count,
> const char **flags) {
> - return have_range(&subordinate_gid_db, owner, start, count);
> + return have_range(&subordinate_gid_db, owner, start, count, flags);
> }
>
> bool sub_gid_assigned(const char *owner)
> diff --git a/lib/subordinateio.h b/lib/subordinateio.h
> index a21d72b..7e47659 100644
> --- a/lib/subordinateio.h
> +++ b/lib/subordinateio.h
> @@ -25,7 +25,7 @@ extern int sub_uid_remove (const char *owner, uid_t
> start, unsigned long count); extern uid_t sub_uid_find_free_range(uid_t
> min, uid_t max, unsigned long count);
> extern int sub_gid_close(void);
> -extern bool have_sub_gids(const char *owner, gid_t start, unsigned long
> count); +extern bool have_sub_gids(const char *owner, gid_t start,
> unsigned long count, const char **flags); extern bool
> sub_gid_file_present (void); extern bool sub_gid_assigned(const char
> *owner); extern int sub_gid_lock (void);
> diff --git a/libmisc/idmapping.c b/libmisc/idmapping.c
> index 0dce634..7f7de88 100644
> --- a/libmisc/idmapping.c
> +++ b/libmisc/idmapping.c
> @@ -106,7 +106,6 @@ void write_mapping(int proc_dir_fd, int ranges,
> struct map_range *mappings, struct map_range *mapping;
> size_t bufsize;
> char *buf, *pos;
> - int fd;
>
> bufsize = ranges * ((ULONG_DIGITS + 1) * 3);
> pos = buf = xmalloc(bufsize);
> @@ -128,13 +127,20 @@ void write_mapping(int proc_dir_fd, int ranges,
> struct map_range *mappings, }
>
> /* Write the mapping to the maping file */
> + write_proc(proc_dir_fd, map_file, buf, pos - buf);
> +}
> +
> +void write_proc(int proc_dir_fd, const char *map_file, void *buf, int
> len) +{
> + int fd;
> +
> fd = openat(proc_dir_fd, map_file, O_WRONLY);
> if (fd < 0) {
> fprintf(stderr, _("%s: open of %s failed: %s\n"),
> Prog, map_file, strerror(errno));
> exit(EXIT_FAILURE);
> }
> - if (write(fd, buf, pos - buf) != (pos - buf)) {
> + if (write(fd, buf, len) != len) {
> fprintf(stderr, _("%s: write to %s failed: %s\n"),
> Prog, map_file, strerror(errno));
> exit(EXIT_FAILURE);
> diff --git a/libmisc/idmapping.h b/libmisc/idmapping.h
> index 58d000f..c2cec38 100644
> --- a/libmisc/idmapping.h
> +++ b/libmisc/idmapping.h
> @@ -39,6 +39,7 @@ struct map_range {
> extern struct map_range *get_map_ranges(int ranges, int argc, char
> **argv); extern void write_mapping(int proc_dir_fd, int ranges,
> struct map_range *mappings, const char *map_file);
> +extern void write_proc(int proc_dir_fd, const char *map_file, void
> *buf, int len);
> #endif /* _ID_MAPPING_H_ */
>
> diff --git a/src/newgidmap.c b/src/newgidmap.c
> index 451c6a6..8d64e3b 100644
> --- a/src/newgidmap.c
> +++ b/src/newgidmap.c
> @@ -46,14 +46,14 @@
> */
> const char *Prog;
>
> -static bool verify_range(struct passwd *pw, struct map_range *range)
> +static bool verify_range(struct passwd *pw, struct map_range *range,
> const char **flags) {
> /* An empty range is invalid */
> if (range->count == 0)
> return false;
>
> /* Test /etc/subgid */
> - if (have_sub_gids(pw->pw_name, range->lower, range->count))
> + if (have_sub_gids(pw->pw_name, range->lower, range->count, flags))
> return true;
>
> /* Allow a process to map it's own gid */
> @@ -64,14 +64,14 @@ static bool verify_range(struct passwd *pw, struct
> map_range *range) }
>
> static void verify_ranges(struct passwd *pw, int ranges,
> - struct map_range *mappings)
> + struct map_range *mappings, const char **flags)
> {
> struct map_range *mapping;
> int idx;
>
> mapping = mappings;
> for (idx = 0; idx < ranges; idx++, mapping++) {
> - if (!verify_range(pw, mapping)) {
> + if (!verify_range(pw, mapping, flags)) {
> fprintf(stderr, _( "%s: gid range [%lu-%lu) -> [%lu-%lu) not
> allowed\n"), Prog,
> mapping->upper,
> @@ -103,6 +103,7 @@ int main(int argc, char **argv)
> struct stat st;
> struct passwd *pw;
> int written;
> + const char *flags;
>
> Prog = Basename (argv[0]);
>
> @@ -177,7 +178,18 @@ int main(int argc, char **argv)
> if (!mappings)
> usage();
>
> - verify_ranges(pw, ranges, mappings);
> + verify_ranges(pw, ranges, mappings, &flags);
> +
> + if (flags && strlen(flags) != 0) {
> + /* only allowed flag is currently deny */
> + if (strcmp(flags, "deny") == 0) {
> + write_proc(proc_dir_fd, "setgroups", "deny", strlen("deny"));
> + } else {
> + fprintf(stderr, _("%s: illegal flag in map file: %s\n"),
> + Prog, flags);
> + exit(EXIT_FAILURE);
> + }
> + }
>
> write_mapping(proc_dir_fd, ranges, mappings, "gid_map");
> sub_gid_close();
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
2016-05-01 16:37 ` Serge Hallyn
2016-05-01 23:29 ` James Bottomley
@ 2016-05-01 23:29 ` James Bottomley
1 sibling, 0 replies; 28+ messages in thread
From: James Bottomley @ 2016-05-01 23:29 UTC (permalink / raw)
To: Serge Hallyn
Cc: Linux Containers, systemd-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
util-linux-u79uwXL29TY76Z2rM5mHXA
On Sun, 2016-05-01 at 12:37 -0400, Serge Hallyn wrote:
> > > It looks like the only addition it needs is the setgroups flag
> > > for
> > > newgidmap, which the security people will need, so I can patch
> > > that.
> >
> > How does this look for a patch?
>
> Certainly deny is a terrible keyword for this, given the somewhat
> convoluted case it represents. Maybe lockgroups or nosetgroup?
OK, nosegroups seems to be less scary.
> And of course it'll need a clear explanation of what it does in the
> subgid manpage. But really i don't know that this can work the way
> you want it to.
Yes, docs and tests were to be added after everyone was happy with the
implementation.
> Can you describe your use case?
basically not getting a CVE filed against this utility for allowing the
dropping of groups. I don't have a use case for group membership
denying permissions.
> The intent of setgroups is to keep *unprivileged* writers of gid_map
> from dropping a gid which is blocking a file access from the user.
You can't do that with the map write. Even if you set no gid_map at
all, the attributes checks are done on the kernel side groups (i.e. the
ones you possess outside the namespace even if they have no interior
mapping). The only way to drop groups is with the setgroups() system
call.
> But newgidmap runs suid root (or cap_gid when you are through :), so
> the user can trivially assign just one authorized gid, not the whole
> range, and bypass the acls that way.
It does more than that: it also blocks the sys_setgroups() call in the
namespace, even for the namespace owner, which is the primary CVE
preventing use case.
> At the very least you would want to enforce the use of a whole range
> in the lockgroup case, but even there i question it's value.
I think, if you were going to enforce deny sys_setgroups() on a user
you otherwise trusted, you'd probably only allow them a single range.
But I suppose the flag should be or'd over all ranges.
James
> -Serge
>
>
>
> > James
> >
> > ---
> >
> > diff --git a/lib/subordinateio.c b/lib/subordinateio.c
> > index 0d64a91..aa3c968 100644
> > --- a/lib/subordinateio.c
> > +++ b/lib/subordinateio.c
> > @@ -18,9 +18,10 @@ struct subordinate_range {
> > const char *owner;
> > unsigned long start;
> > unsigned long count;
> > + const char *flags;
> > };
> >
> > -#define NFIELDS 3
> > +#define NFIELDS 4
> >
> > /*
> > * subordinate_dup: create a duplicate range
> > @@ -44,6 +45,16 @@ static /*@null@*/ /*@only@*/void
> > *subordinate_dup
> > (const void *ent) free(range);
> > return NULL;
> > }
> > + if (rangeent->flags) {
> > + range->flags = strdup (rangeent->flags);
> > + if (NULL == range->flags) {
> > + free((void *)range->owner);
> > + free(range);
> > + return NULL;
> > + }
> > + } else {
> > + range->flags = NULL;
> > + }
> > range->start = rangeent->start;
> > range->count = rangeent->count;
> >
> > @@ -111,13 +122,17 @@ static void *subordinate_parse (const char
> > *line)
> > * There must be exactly NFIELDS colon separated fields or
> > * the entry is invalid. Also, fields must be non-blank.
> > */
> > - if (i != NFIELDS || *fields[0] == '\0' || *fields[1] == '\0'
> > ||
> > *fields[2] == '\0') + if ((i != NFIELDS && i != NFIELDS -1) ||
> > *fields[0] == '\0' || *fields[1] == '\0' || *fields[2] == '\0')
> > return
> > NULL; range.owner = fields[0];
> > if (getulong (fields[1], &range.start) == 0)
> > return NULL;
> > if (getulong (fields[2], &range.count) == 0)
> > return NULL;
> > + if (i == NFIELDS)
> > + range.flags = fields[3];
> > + else
> > + range.flags = NULL;
> >
> > return ⦥
> > }
> > @@ -134,10 +149,11 @@ static int subordinate_put (const void *ent,
> > FILE
> > * file) {
> > const struct subordinate_range *range = ent;
> >
> > - return fprintf(file, "%s:%lu:%lu\n",
> > + return fprintf(file, "%s:%lu:%lu:%s\n",
> > range->owner,
> > range->start,
> > - range->count) < 0 ? -1 : 0;
> > + range->count,
> > + range->flags ? range->flags : "") < 0 ?
> > -1 : 0;
> > }
> >
> > static struct commonio_ops subordinate_ops = {
> > @@ -295,7 +311,8 @@ static const struct subordinate_range
> > *find_range(struct commonio_db *db, * Returns true if @owner is
> > authorized to use the range, false otherwise. */
> > static bool have_range(struct commonio_db *db,
> > - const char *owner, unsigned long start,
> > unsigned long count)
> > + const char *owner, unsigned long start,
> > unsigned long count,
> > + const char **flags)
> > {
> > const struct subordinate_range *range;
> > unsigned long end;
> > @@ -309,8 +326,11 @@ static bool have_range(struct commonio_db *db,
> > unsigned long last;
> >
> > last = range->start + range->count - 1;
> > - if (last >= (start + count - 1))
> > + if (last >= (start + count - 1)) {
> > + if (flags)
> > + *flags = range->flags;
> > return true;
> > + }
> >
> > count = end - last;
> > start = last + 1;
> > @@ -430,7 +450,7 @@ static int add_range(struct commonio_db *db,
> > range.count = count;
> >
> > /* See if the range is already present */
> > - if (have_range(db, owner, start, count))
> > + if (have_range(db, owner, start, count, NULL))
> > return 1;
> >
> > /* Otherwise append the range */
> > @@ -585,7 +605,7 @@ bool sub_uid_assigned(const char *owner)
> >
> > bool have_sub_uids(const char *owner, uid_t start, unsigned long
> > count)
> > {
> > - return have_range (&subordinate_uid_db, owner, start, count);
> > + return have_range (&subordinate_uid_db, owner, start, count,
> > NULL);
> > }
> >
> > int sub_uid_add (const char *owner, uid_t start, unsigned long
> > count)
> > @@ -659,9 +679,9 @@ int sub_gid_open (int mode)
> > return commonio_open (&subordinate_gid_db, mode);
> > }
> >
> > -bool have_sub_gids(const char *owner, gid_t start, unsigned long
> > count)
> > +bool have_sub_gids(const char *owner, gid_t start, unsigned long
> > count,
> > const char **flags) {
> > - return have_range(&subordinate_gid_db, owner, start, count);
> > + return have_range(&subordinate_gid_db, owner, start, count,
> > flags);
> > }
> >
> > bool sub_gid_assigned(const char *owner)
> > diff --git a/lib/subordinateio.h b/lib/subordinateio.h
> > index a21d72b..7e47659 100644
> > --- a/lib/subordinateio.h
> > +++ b/lib/subordinateio.h
> > @@ -25,7 +25,7 @@ extern int sub_uid_remove (const char *owner,
> > uid_t
> > start, unsigned long count); extern uid_t
> > sub_uid_find_free_range(uid_t
> > min, uid_t max, unsigned long count);
> > extern int sub_gid_close(void);
> > -extern bool have_sub_gids(const char *owner, gid_t start, unsigned
> > long
> > count); +extern bool have_sub_gids(const char *owner, gid_t start,
> > unsigned long count, const char **flags); extern bool
> > sub_gid_file_present (void); extern bool sub_gid_assigned(const
> > char
> > *owner); extern int sub_gid_lock (void);
> > diff --git a/libmisc/idmapping.c b/libmisc/idmapping.c
> > index 0dce634..7f7de88 100644
> > --- a/libmisc/idmapping.c
> > +++ b/libmisc/idmapping.c
> > @@ -106,7 +106,6 @@ void write_mapping(int proc_dir_fd, int ranges,
> > struct map_range *mappings, struct map_range *mapping;
> > size_t bufsize;
> > char *buf, *pos;
> > - int fd;
> >
> > bufsize = ranges * ((ULONG_DIGITS + 1) * 3);
> > pos = buf = xmalloc(bufsize);
> > @@ -128,13 +127,20 @@ void write_mapping(int proc_dir_fd, int
> > ranges,
> > struct map_range *mappings, }
> >
> > /* Write the mapping to the maping file */
> > + write_proc(proc_dir_fd, map_file, buf, pos - buf);
> > +}
> > +
> > +void write_proc(int proc_dir_fd, const char *map_file, void *buf,
> > int
> > len) +{
> > + int fd;
> > +
> > fd = openat(proc_dir_fd, map_file, O_WRONLY);
> > if (fd < 0) {
> > fprintf(stderr, _("%s: open of %s failed: %s\n"),
> > Prog, map_file, strerror(errno));
> > exit(EXIT_FAILURE);
> > }
> > - if (write(fd, buf, pos - buf) != (pos - buf)) {
> > + if (write(fd, buf, len) != len) {
> > fprintf(stderr, _("%s: write to %s failed: %s\n"),
> > Prog, map_file, strerror(errno));
> > exit(EXIT_FAILURE);
> > diff --git a/libmisc/idmapping.h b/libmisc/idmapping.h
> > index 58d000f..c2cec38 100644
> > --- a/libmisc/idmapping.h
> > +++ b/libmisc/idmapping.h
> > @@ -39,6 +39,7 @@ struct map_range {
> > extern struct map_range *get_map_ranges(int ranges, int argc,
> > char
> > **argv); extern void write_mapping(int proc_dir_fd, int ranges,
> > struct map_range *mappings, const char *map_file);
> > +extern void write_proc(int proc_dir_fd, const char *map_file, void
> > *buf, int len);
> > #endif /* _ID_MAPPING_H_ */
> >
> > diff --git a/src/newgidmap.c b/src/newgidmap.c
> > index 451c6a6..8d64e3b 100644
> > --- a/src/newgidmap.c
> > +++ b/src/newgidmap.c
> > @@ -46,14 +46,14 @@
> > */
> > const char *Prog;
> >
> > -static bool verify_range(struct passwd *pw, struct map_range
> > *range)
> > +static bool verify_range(struct passwd *pw, struct map_range
> > *range,
> > const char **flags) {
> > /* An empty range is invalid */
> > if (range->count == 0)
> > return false;
> >
> > /* Test /etc/subgid */
> > - if (have_sub_gids(pw->pw_name, range->lower, range->count))
> > + if (have_sub_gids(pw->pw_name, range->lower, range->count,
> > flags))
> > return true;
> >
> > /* Allow a process to map it's own gid */
> > @@ -64,14 +64,14 @@ static bool verify_range(struct passwd *pw,
> > struct
> > map_range *range) }
> >
> > static void verify_ranges(struct passwd *pw, int ranges,
> > - struct map_range *mappings)
> > + struct map_range *mappings, const char **flags)
> > {
> > struct map_range *mapping;
> > int idx;
> >
> > mapping = mappings;
> > for (idx = 0; idx < ranges; idx++, mapping++) {
> > - if (!verify_range(pw, mapping)) {
> > + if (!verify_range(pw, mapping, flags)) {
> > fprintf(stderr, _( "%s: gid range [%lu-%lu) -> [%lu
> > -%lu) not
> > allowed\n"), Prog,
> > mapping->upper,
> > @@ -103,6 +103,7 @@ int main(int argc, char **argv)
> > struct stat st;
> > struct passwd *pw;
> > int written;
> > + const char *flags;
> >
> > Prog = Basename (argv[0]);
> >
> > @@ -177,7 +178,18 @@ int main(int argc, char **argv)
> > if (!mappings)
> > usage();
> >
> > - verify_ranges(pw, ranges, mappings);
> > + verify_ranges(pw, ranges, mappings, &flags);
> > +
> > + if (flags && strlen(flags) != 0) {
> > + /* only allowed flag is currently deny */
> > + if (strcmp(flags, "deny") == 0) {
> > + write_proc(proc_dir_fd, "setgroups", "deny",
> > strlen("deny"));
> > + } else {
> > + fprintf(stderr, _("%s: illegal flag in map file:
> > %s\n"),
> > + Prog, flags);
> > + exit(EXIT_FAILURE);
> > + }
> > + }
> >
> > write_mapping(proc_dir_fd, ranges, mappings, "gid_map");
> > sub_gid_close();
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
2016-05-01 16:37 ` Serge Hallyn
@ 2016-05-01 23:29 ` James Bottomley
[not found] ` <1462145366.2337.18.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
2016-05-01 23:29 ` James Bottomley
1 sibling, 1 reply; 28+ messages in thread
From: James Bottomley @ 2016-05-01 23:29 UTC (permalink / raw)
To: Serge Hallyn; +Cc: Linux Containers, systemd-devel, util-linux
On Sun, 2016-05-01 at 12:37 -0400, Serge Hallyn wrote:
> > > It looks like the only addition it needs is the setgroups flag
> > > for
> > > newgidmap, which the security people will need, so I can patch
> > > that.
> >
> > How does this look for a patch?
>
> Certainly deny is a terrible keyword for this, given the somewhat
> convoluted case it represents. Maybe lockgroups or nosetgroup?
OK, nosegroups seems to be less scary.
> And of course it'll need a clear explanation of what it does in the
> subgid manpage. But really i don't know that this can work the way
> you want it to.
Yes, docs and tests were to be added after everyone was happy with the
implementation.
> Can you describe your use case?
basically not getting a CVE filed against this utility for allowing the
dropping of groups. I don't have a use case for group membership
denying permissions.
> The intent of setgroups is to keep *unprivileged* writers of gid_map
> from dropping a gid which is blocking a file access from the user.
You can't do that with the map write. Even if you set no gid_map at
all, the attributes checks are done on the kernel side groups (i.e. the
ones you possess outside the namespace even if they have no interior
mapping). The only way to drop groups is with the setgroups() system
call.
> But newgidmap runs suid root (or cap_gid when you are through :), so
> the user can trivially assign just one authorized gid, not the whole
> range, and bypass the acls that way.
It does more than that: it also blocks the sys_setgroups() call in the
namespace, even for the namespace owner, which is the primary CVE
preventing use case.
> At the very least you would want to enforce the use of a whole range
> in the lockgroup case, but even there i question it's value.
I think, if you were going to enforce deny sys_setgroups() on a user
you otherwise trusted, you'd probably only allow them a single range.
But I suppose the flag should be or'd over all ranges.
James
> -Serge
>
>
>
> > James
> >
> > ---
> >
> > diff --git a/lib/subordinateio.c b/lib/subordinateio.c
> > index 0d64a91..aa3c968 100644
> > --- a/lib/subordinateio.c
> > +++ b/lib/subordinateio.c
> > @@ -18,9 +18,10 @@ struct subordinate_range {
> > const char *owner;
> > unsigned long start;
> > unsigned long count;
> > + const char *flags;
> > };
> >
> > -#define NFIELDS 3
> > +#define NFIELDS 4
> >
> > /*
> > * subordinate_dup: create a duplicate range
> > @@ -44,6 +45,16 @@ static /*@null@*/ /*@only@*/void
> > *subordinate_dup
> > (const void *ent) free(range);
> > return NULL;
> > }
> > + if (rangeent->flags) {
> > + range->flags = strdup (rangeent->flags);
> > + if (NULL == range->flags) {
> > + free((void *)range->owner);
> > + free(range);
> > + return NULL;
> > + }
> > + } else {
> > + range->flags = NULL;
> > + }
> > range->start = rangeent->start;
> > range->count = rangeent->count;
> >
> > @@ -111,13 +122,17 @@ static void *subordinate_parse (const char
> > *line)
> > * There must be exactly NFIELDS colon separated fields or
> > * the entry is invalid. Also, fields must be non-blank.
> > */
> > - if (i != NFIELDS || *fields[0] == '\0' || *fields[1] == '\0'
> > ||
> > *fields[2] == '\0') + if ((i != NFIELDS && i != NFIELDS -1) ||
> > *fields[0] == '\0' || *fields[1] == '\0' || *fields[2] == '\0')
> > return
> > NULL; range.owner = fields[0];
> > if (getulong (fields[1], &range.start) == 0)
> > return NULL;
> > if (getulong (fields[2], &range.count) == 0)
> > return NULL;
> > + if (i == NFIELDS)
> > + range.flags = fields[3];
> > + else
> > + range.flags = NULL;
> >
> > return ⦥
> > }
> > @@ -134,10 +149,11 @@ static int subordinate_put (const void *ent,
> > FILE
> > * file) {
> > const struct subordinate_range *range = ent;
> >
> > - return fprintf(file, "%s:%lu:%lu\n",
> > + return fprintf(file, "%s:%lu:%lu:%s\n",
> > range->owner,
> > range->start,
> > - range->count) < 0 ? -1 : 0;
> > + range->count,
> > + range->flags ? range->flags : "") < 0 ?
> > -1 : 0;
> > }
> >
> > static struct commonio_ops subordinate_ops = {
> > @@ -295,7 +311,8 @@ static const struct subordinate_range
> > *find_range(struct commonio_db *db, * Returns true if @owner is
> > authorized to use the range, false otherwise. */
> > static bool have_range(struct commonio_db *db,
> > - const char *owner, unsigned long start,
> > unsigned long count)
> > + const char *owner, unsigned long start,
> > unsigned long count,
> > + const char **flags)
> > {
> > const struct subordinate_range *range;
> > unsigned long end;
> > @@ -309,8 +326,11 @@ static bool have_range(struct commonio_db *db,
> > unsigned long last;
> >
> > last = range->start + range->count - 1;
> > - if (last >= (start + count - 1))
> > + if (last >= (start + count - 1)) {
> > + if (flags)
> > + *flags = range->flags;
> > return true;
> > + }
> >
> > count = end - last;
> > start = last + 1;
> > @@ -430,7 +450,7 @@ static int add_range(struct commonio_db *db,
> > range.count = count;
> >
> > /* See if the range is already present */
> > - if (have_range(db, owner, start, count))
> > + if (have_range(db, owner, start, count, NULL))
> > return 1;
> >
> > /* Otherwise append the range */
> > @@ -585,7 +605,7 @@ bool sub_uid_assigned(const char *owner)
> >
> > bool have_sub_uids(const char *owner, uid_t start, unsigned long
> > count)
> > {
> > - return have_range (&subordinate_uid_db, owner, start, count);
> > + return have_range (&subordinate_uid_db, owner, start, count,
> > NULL);
> > }
> >
> > int sub_uid_add (const char *owner, uid_t start, unsigned long
> > count)
> > @@ -659,9 +679,9 @@ int sub_gid_open (int mode)
> > return commonio_open (&subordinate_gid_db, mode);
> > }
> >
> > -bool have_sub_gids(const char *owner, gid_t start, unsigned long
> > count)
> > +bool have_sub_gids(const char *owner, gid_t start, unsigned long
> > count,
> > const char **flags) {
> > - return have_range(&subordinate_gid_db, owner, start, count);
> > + return have_range(&subordinate_gid_db, owner, start, count,
> > flags);
> > }
> >
> > bool sub_gid_assigned(const char *owner)
> > diff --git a/lib/subordinateio.h b/lib/subordinateio.h
> > index a21d72b..7e47659 100644
> > --- a/lib/subordinateio.h
> > +++ b/lib/subordinateio.h
> > @@ -25,7 +25,7 @@ extern int sub_uid_remove (const char *owner,
> > uid_t
> > start, unsigned long count); extern uid_t
> > sub_uid_find_free_range(uid_t
> > min, uid_t max, unsigned long count);
> > extern int sub_gid_close(void);
> > -extern bool have_sub_gids(const char *owner, gid_t start, unsigned
> > long
> > count); +extern bool have_sub_gids(const char *owner, gid_t start,
> > unsigned long count, const char **flags); extern bool
> > sub_gid_file_present (void); extern bool sub_gid_assigned(const
> > char
> > *owner); extern int sub_gid_lock (void);
> > diff --git a/libmisc/idmapping.c b/libmisc/idmapping.c
> > index 0dce634..7f7de88 100644
> > --- a/libmisc/idmapping.c
> > +++ b/libmisc/idmapping.c
> > @@ -106,7 +106,6 @@ void write_mapping(int proc_dir_fd, int ranges,
> > struct map_range *mappings, struct map_range *mapping;
> > size_t bufsize;
> > char *buf, *pos;
> > - int fd;
> >
> > bufsize = ranges * ((ULONG_DIGITS + 1) * 3);
> > pos = buf = xmalloc(bufsize);
> > @@ -128,13 +127,20 @@ void write_mapping(int proc_dir_fd, int
> > ranges,
> > struct map_range *mappings, }
> >
> > /* Write the mapping to the maping file */
> > + write_proc(proc_dir_fd, map_file, buf, pos - buf);
> > +}
> > +
> > +void write_proc(int proc_dir_fd, const char *map_file, void *buf,
> > int
> > len) +{
> > + int fd;
> > +
> > fd = openat(proc_dir_fd, map_file, O_WRONLY);
> > if (fd < 0) {
> > fprintf(stderr, _("%s: open of %s failed: %s\n"),
> > Prog, map_file, strerror(errno));
> > exit(EXIT_FAILURE);
> > }
> > - if (write(fd, buf, pos - buf) != (pos - buf)) {
> > + if (write(fd, buf, len) != len) {
> > fprintf(stderr, _("%s: write to %s failed: %s\n"),
> > Prog, map_file, strerror(errno));
> > exit(EXIT_FAILURE);
> > diff --git a/libmisc/idmapping.h b/libmisc/idmapping.h
> > index 58d000f..c2cec38 100644
> > --- a/libmisc/idmapping.h
> > +++ b/libmisc/idmapping.h
> > @@ -39,6 +39,7 @@ struct map_range {
> > extern struct map_range *get_map_ranges(int ranges, int argc,
> > char
> > **argv); extern void write_mapping(int proc_dir_fd, int ranges,
> > struct map_range *mappings, const char *map_file);
> > +extern void write_proc(int proc_dir_fd, const char *map_file, void
> > *buf, int len);
> > #endif /* _ID_MAPPING_H_ */
> >
> > diff --git a/src/newgidmap.c b/src/newgidmap.c
> > index 451c6a6..8d64e3b 100644
> > --- a/src/newgidmap.c
> > +++ b/src/newgidmap.c
> > @@ -46,14 +46,14 @@
> > */
> > const char *Prog;
> >
> > -static bool verify_range(struct passwd *pw, struct map_range
> > *range)
> > +static bool verify_range(struct passwd *pw, struct map_range
> > *range,
> > const char **flags) {
> > /* An empty range is invalid */
> > if (range->count == 0)
> > return false;
> >
> > /* Test /etc/subgid */
> > - if (have_sub_gids(pw->pw_name, range->lower, range->count))
> > + if (have_sub_gids(pw->pw_name, range->lower, range->count,
> > flags))
> > return true;
> >
> > /* Allow a process to map it's own gid */
> > @@ -64,14 +64,14 @@ static bool verify_range(struct passwd *pw,
> > struct
> > map_range *range) }
> >
> > static void verify_ranges(struct passwd *pw, int ranges,
> > - struct map_range *mappings)
> > + struct map_range *mappings, const char **flags)
> > {
> > struct map_range *mapping;
> > int idx;
> >
> > mapping = mappings;
> > for (idx = 0; idx < ranges; idx++, mapping++) {
> > - if (!verify_range(pw, mapping)) {
> > + if (!verify_range(pw, mapping, flags)) {
> > fprintf(stderr, _( "%s: gid range [%lu-%lu) -> [%lu
> > -%lu) not
> > allowed\n"), Prog,
> > mapping->upper,
> > @@ -103,6 +103,7 @@ int main(int argc, char **argv)
> > struct stat st;
> > struct passwd *pw;
> > int written;
> > + const char *flags;
> >
> > Prog = Basename (argv[0]);
> >
> > @@ -177,7 +178,18 @@ int main(int argc, char **argv)
> > if (!mappings)
> > usage();
> >
> > - verify_ranges(pw, ranges, mappings);
> > + verify_ranges(pw, ranges, mappings, &flags);
> > +
> > + if (flags && strlen(flags) != 0) {
> > + /* only allowed flag is currently deny */
> > + if (strcmp(flags, "deny") == 0) {
> > + write_proc(proc_dir_fd, "setgroups", "deny",
> > strlen("deny"));
> > + } else {
> > + fprintf(stderr, _("%s: illegal flag in map file:
> > %s\n"),
> > + Prog, flags);
> > + exit(EXIT_FAILURE);
> > + }
> > + }
> >
> > write_mapping(proc_dir_fd, ranges, mappings, "gid_map");
> > sub_gid_close();
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
2016-05-01 23:29 ` James Bottomley
@ 2016-05-02 4:13 ` Serge E. Hallyn
0 siblings, 0 replies; 28+ messages in thread
From: Serge E. Hallyn @ 2016-05-02 4:13 UTC (permalink / raw)
To: James Bottomley
Cc: Linux Containers, systemd-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
util-linux-u79uwXL29TY76Z2rM5mHXA
On Sun, May 01, 2016 at 04:29:26PM -0700, James Bottomley wrote:
> On Sun, 2016-05-01 at 12:37 -0400, Serge Hallyn wrote:
> > > > It looks like the only addition it needs is the setgroups flag
> > > > for
> > > > newgidmap, which the security people will need, so I can patch
> > > > that.
> > >
> > > How does this look for a patch?
> >
> > Certainly deny is a terrible keyword for this, given the somewhat
> > convoluted case it represents. Maybe lockgroups or nosetgroup?
>
> OK, nosegroups seems to be less scary.
>
> > And of course it'll need a clear explanation of what it does in the
> > subgid manpage. But really i don't know that this can work the way
> > you want it to.
>
> Yes, docs and tests were to be added after everyone was happy with the
> implementation.
>
> > Can you describe your use case?
>
> basically not getting a CVE filed against this utility for allowing the
> dropping of groups. I don't have a use case for group membership
> denying permissions.
>
> > The intent of setgroups is to keep *unprivileged* writers of gid_map
> > from dropping a gid which is blocking a file access from the user.
>
>
> You can't do that with the map write. Even if you set no gid_map at
> all, the attributes checks are done on the kernel side groups (i.e. the
> ones you possess outside the namespace even if they have no interior
> mapping). The only way to drop groups is with the setgroups() system
> call.
>
> > But newgidmap runs suid root (or cap_gid when you are through :), so
> > the user can trivially assign just one authorized gid, not the whole
> > range, and bypass the acls that way.
>
> It does more than that: it also blocks the sys_setgroups() call in the
> namespace, even for the namespace owner, which is the primary CVE
> preventing use case.
>
> > At the very least you would want to enforce the use of a whole range
> > in the lockgroup case, but even there i question it's value.
>
> I think, if you were going to enforce deny sys_setgroups() on a user
> you otherwise trusted, you'd probably only allow them a single range.
> But I suppose the flag should be or'd over all ranges.
Ok, yeah. My thought this afternoon was that the point of the CVE was
that an unprivileged user, in the absence of any admin-provided
/etc/sub{u,g}id or new{u,g}idmap at all, and who was being denied a file
access through one of his aux groups, could use a user namespace to drop
the aux group and access the file. That if an admin went to the trouble
to grant subuid and subgids then it wasn't an issue. But of course
allocations are being done automatically now so that's not a valid
point.
So let's proceed with the patch :)
A PR using nosetgroups against git://github.com/shadow-maint/shadow would
be great.
thanks,
-serge
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
@ 2016-05-02 4:13 ` Serge E. Hallyn
0 siblings, 0 replies; 28+ messages in thread
From: Serge E. Hallyn @ 2016-05-02 4:13 UTC (permalink / raw)
To: James Bottomley; +Cc: Serge Hallyn, Linux Containers, systemd-devel, util-linux
On Sun, May 01, 2016 at 04:29:26PM -0700, James Bottomley wrote:
> On Sun, 2016-05-01 at 12:37 -0400, Serge Hallyn wrote:
> > > > It looks like the only addition it needs is the setgroups flag
> > > > for
> > > > newgidmap, which the security people will need, so I can patch
> > > > that.
> > >
> > > How does this look for a patch?
> >
> > Certainly deny is a terrible keyword for this, given the somewhat
> > convoluted case it represents. Maybe lockgroups or nosetgroup?
>
> OK, nosegroups seems to be less scary.
>
> > And of course it'll need a clear explanation of what it does in the
> > subgid manpage. But really i don't know that this can work the way
> > you want it to.
>
> Yes, docs and tests were to be added after everyone was happy with the
> implementation.
>
> > Can you describe your use case?
>
> basically not getting a CVE filed against this utility for allowing the
> dropping of groups. I don't have a use case for group membership
> denying permissions.
>
> > The intent of setgroups is to keep *unprivileged* writers of gid_map
> > from dropping a gid which is blocking a file access from the user.
>
>
> You can't do that with the map write. Even if you set no gid_map at
> all, the attributes checks are done on the kernel side groups (i.e. the
> ones you possess outside the namespace even if they have no interior
> mapping). The only way to drop groups is with the setgroups() system
> call.
>
> > But newgidmap runs suid root (or cap_gid when you are through :), so
> > the user can trivially assign just one authorized gid, not the whole
> > range, and bypass the acls that way.
>
> It does more than that: it also blocks the sys_setgroups() call in the
> namespace, even for the namespace owner, which is the primary CVE
> preventing use case.
>
> > At the very least you would want to enforce the use of a whole range
> > in the lockgroup case, but even there i question it's value.
>
> I think, if you were going to enforce deny sys_setgroups() on a user
> you otherwise trusted, you'd probably only allow them a single range.
> But I suppose the flag should be or'd over all ranges.
Ok, yeah. My thought this afternoon was that the point of the CVE was
that an unprivileged user, in the absence of any admin-provided
/etc/sub{u,g}id or new{u,g}idmap at all, and who was being denied a file
access through one of his aux groups, could use a user namespace to drop
the aux group and access the file. That if an admin went to the trouble
to grant subuid and subgids then it wasn't an issue. But of course
allocations are being done automatically now so that's not a valid
point.
So let's proceed with the patch :)
A PR using nosetgroups against git://github.com/shadow-maint/shadow would
be great.
thanks,
-serge
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
[not found] ` <1461944328.2311.10.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
2016-04-29 15:53 ` Serge E. Hallyn
2016-04-29 22:18 ` James Bottomley
@ 2016-05-04 15:02 ` Eric W. Biederman
2 siblings, 0 replies; 28+ messages in thread
From: Eric W. Biederman @ 2016-05-04 15:02 UTC (permalink / raw)
To: James Bottomley
Cc: systemd-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Linux Containers,
util-linux-u79uwXL29TY76Z2rM5mHXA
James Bottomley <James.Bottomley@HansenPartnership.com> writes:
> On Thu, 2016-04-28 at 16:00 -0700, W. Trevor King wrote:
>> On Thu, Apr 28, 2016 at 03:02:08PM -0700, James Bottomley wrote:
>> > /etc/usernamespaces
>> >
>> > and the format be :::
>> >
>> > …
>> >
>> > If this sounds OK to people, I can code up a utility that does this,
>> > which should probably belong in util-linux.
>>
>> This sounds a lot like shadow's newuidmap and newgidmap [1,2,3].
>>
>> Cheers,
>> Trevor
>>
>> [1]: https://github.com/shadow-maint/shadow/commit/673c2a6f9aa6c69588f4c1be08589b8d3475a520
>> [2]: http://man7.org/linux/man-pages/man1/newuidmap.1.html
>> [3]: http://man7.org/linux/man-pages/man5/subuid.5.html
>
> I think that mostly works. No-one's packaging it yet, which is why I
> didn't notice. It also looks like the build dependencies have vastly
> expanded, so I can't get it to build in the build service yet.
Both Fedora and Ubuntu should be packaging it. Further Docker should
already be using these files.
> It looks like the only addition it needs is the setgroups flag for
> newgidmap, which the security people will need, so I can patch that.
> Plus it's trying to install newgidmap/newuidmap as setuid root rather
> than cap_setuid/cap_setgid, but that's fixable in the spec file.
I read the rest of this thread and I don't understand the setgroups flag
that you desire. It sounds like someone with an incomplete grasp on the
situtation being cautious.
As far as I can tell the use cases for containers not supporting
setgroups is very limited. Basically just using user namespaces to
drop privileges, and mapping the existing uids and gids to 0.
I don't think it actually makes sense to have a knob. From a practical
standpoint entering any subordinate ids into the subgid file for a user
is a permission to use groups in such a way that can not use them as a
negative acl (because we allow them to be dropped).
Certainly it has been that way for quite a while now.
Except for the negative acl aspect there are no issues with dropping
groups, as setgroups will limit you to the groups allowed in your user
namespace.
Eric
_______________________________________________
Containers mailing list
Containers@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/containers
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
2016-04-29 15:38 ` James Bottomley
` (2 preceding siblings ...)
(?)
@ 2016-05-04 15:02 ` Eric W. Biederman
2016-05-04 15:21 ` Phil Estes
` (2 more replies)
-1 siblings, 3 replies; 28+ messages in thread
From: Eric W. Biederman @ 2016-05-04 15:02 UTC (permalink / raw)
To: James Bottomley
Cc: W. Trevor King, Linux Containers, systemd-devel, util-linux,
Serge E. Hallyn
James Bottomley <James.Bottomley@HansenPartnership.com> writes:
> On Thu, 2016-04-28 at 16:00 -0700, W. Trevor King wrote:
>> On Thu, Apr 28, 2016 at 03:02:08PM -0700, James Bottomley wrote:
>> > /etc/usernamespaces
>> >
>> > and the format be :::
>> >
>> > …
>> >
>> > If this sounds OK to people, I can code up a utility that does this,
>> > which should probably belong in util-linux.
>>
>> This sounds a lot like shadow's newuidmap and newgidmap [1,2,3].
>>
>> Cheers,
>> Trevor
>>
>> [1]: https://github.com/shadow-maint/shadow/commit/673c2a6f9aa6c69588f4c1be08589b8d3475a520
>> [2]: http://man7.org/linux/man-pages/man1/newuidmap.1.html
>> [3]: http://man7.org/linux/man-pages/man5/subuid.5.html
>
> I think that mostly works. No-one's packaging it yet, which is why I
> didn't notice. It also looks like the build dependencies have vastly
> expanded, so I can't get it to build in the build service yet.
Both Fedora and Ubuntu should be packaging it. Further Docker should
already be using these files.
> It looks like the only addition it needs is the setgroups flag for
> newgidmap, which the security people will need, so I can patch that.
> Plus it's trying to install newgidmap/newuidmap as setuid root rather
> than cap_setuid/cap_setgid, but that's fixable in the spec file.
I read the rest of this thread and I don't understand the setgroups flag
that you desire. It sounds like someone with an incomplete grasp on the
situtation being cautious.
As far as I can tell the use cases for containers not supporting
setgroups is very limited. Basically just using user namespaces to
drop privileges, and mapping the existing uids and gids to 0.
I don't think it actually makes sense to have a knob. From a practical
standpoint entering any subordinate ids into the subgid file for a user
is a permission to use groups in such a way that can not use them as a
negative acl (because we allow them to be dropped).
Certainly it has been that way for quite a while now.
Except for the negative acl aspect there are no issues with dropping
groups, as setgroups will limit you to the groups allowed in your user
namespace.
Eric
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
[not found] ` <87wpn9988a.fsf-JOvCrm2gF+uungPnsOpG7nhyD016LWXt@public.gmane.org>
@ 2016-05-04 15:21 ` Phil Estes
2016-05-04 18:17 ` James Bottomley
1 sibling, 0 replies; 28+ messages in thread
From: Phil Estes @ 2016-05-04 15:21 UTC (permalink / raw)
To: Eric W. Biederman
Cc: James Bottomley, Linux Containers,
systemd-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
util-linux-u79uwXL29TY76Z2rM5mHXA
Eric W. Biederman wrote:
> James Bottomley<James.Bottomley-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org> writes:
>
>> On Thu, 2016-04-28 at 16:00 -0700, W. Trevor King wrote:
>>> On Thu, Apr 28, 2016 at 03:02:08PM -0700, James Bottomley wrote:
>>>> /etc/usernamespaces
>>>>
>>>> and the format be :::
>>>>
>>>> …
>>>>
>>>> If this sounds OK to people, I can code up a utility that does this,
>>>> which should probably belong in util-linux.
>>> This sounds a lot like shadow's newuidmap and newgidmap [1,2,3].
>>>
>>> Cheers,
>>> Trevor
>>>
>>> [1]: https://github.com/shadow-maint/shadow/commit/673c2a6f9aa6c69588f4c1be08589b8d3475a520
>>> [2]: http://man7.org/linux/man-pages/man1/newuidmap.1.html
>>> [3]: http://man7.org/linux/man-pages/man5/subuid.5.html
>> I think that mostly works. No-one's packaging it yet, which is why I
>> didn't notice. It also looks like the build dependencies have vastly
>> expanded, so I can't get it to build in the build service yet.
>
> Both Fedora and Ubuntu should be packaging it. Further Docker should
> already be using these files.
Yes, based on our discussion in the PRs when user namespaces
capabilities were added to Docker, we respect the /etc/sub{u,g}id files
for sourcing mappings for userns-confined processes.
- Phil
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
2016-05-04 15:02 ` Eric W. Biederman
@ 2016-05-04 15:21 ` Phil Estes
[not found] ` <87wpn9988a.fsf-JOvCrm2gF+uungPnsOpG7nhyD016LWXt@public.gmane.org>
2016-05-04 18:17 ` James Bottomley
2 siblings, 0 replies; 28+ messages in thread
From: Phil Estes @ 2016-05-04 15:21 UTC (permalink / raw)
To: Eric W. Biederman
Cc: James Bottomley, systemd-devel, Linux Containers, util-linux
Eric W. Biederman wrote:
> James Bottomley<James.Bottomley@HansenPartnership.com> writes:
>
>> On Thu, 2016-04-28 at 16:00 -0700, W. Trevor King wrote:
>>> On Thu, Apr 28, 2016 at 03:02:08PM -0700, James Bottomley wrote:
>>>> /etc/usernamespaces
>>>>
>>>> and the format be :::
>>>>
>>>> …
>>>>
>>>> If this sounds OK to people, I can code up a utility that does this,
>>>> which should probably belong in util-linux.
>>> This sounds a lot like shadow's newuidmap and newgidmap [1,2,3].
>>>
>>> Cheers,
>>> Trevor
>>>
>>> [1]: https://github.com/shadow-maint/shadow/commit/673c2a6f9aa6c69588f4c1be08589b8d3475a520
>>> [2]: http://man7.org/linux/man-pages/man1/newuidmap.1.html
>>> [3]: http://man7.org/linux/man-pages/man5/subuid.5.html
>> I think that mostly works. No-one's packaging it yet, which is why I
>> didn't notice. It also looks like the build dependencies have vastly
>> expanded, so I can't get it to build in the build service yet.
>
> Both Fedora and Ubuntu should be packaging it. Further Docker should
> already be using these files.
Yes, based on our discussion in the PRs when user namespaces
capabilities were added to Docker, we respect the /etc/sub{u,g}id files
for sourcing mappings for userns-confined processes.
- Phil
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
[not found] ` <87wpn9988a.fsf-JOvCrm2gF+uungPnsOpG7nhyD016LWXt@public.gmane.org>
2016-05-04 15:21 ` Phil Estes
@ 2016-05-04 18:17 ` James Bottomley
1 sibling, 0 replies; 28+ messages in thread
From: James Bottomley @ 2016-05-04 18:17 UTC (permalink / raw)
To: Eric W. Biederman
Cc: Linux Containers, systemd-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
util-linux-u79uwXL29TY76Z2rM5mHXA
On Wed, 2016-05-04 at 10:02 -0500, Eric W. Biederman wrote:
> James Bottomley <James.Bottomley@HansenPartnership.com> writes:
>
> > On Thu, 2016-04-28 at 16:00 -0700, W. Trevor King wrote:
> > > On Thu, Apr 28, 2016 at 03:02:08PM -0700, James Bottomley wrote:
> > > > /etc/usernamespaces
> > > >
> > > > and the format be :::
> > > >
> > > > …
> > > >
> > > > If this sounds OK to people, I can code up a utility that does
> > > > this, which should probably belong in util-linux.
> > >
> > > This sounds a lot like shadow's newuidmap and newgidmap [1,2,3].
> > >
> > > Cheers,
> > > Trevor
> > >
> > > [1]: https://github.com/shadow-maint/shadow/commit/673c2a6f9aa6c6
> > > 9588f4c1be08589b8d3475a520
> > > [2]: http://man7.org/linux/man-pages/man1/newuidmap.1.html
> > > [3]: http://man7.org/linux/man-pages/man5/subuid.5.html
> >
> > I think that mostly works. No-one's packaging it yet, which is why
> > I didn't notice. It also looks like the build dependencies have
> > vastly expanded, so I can't get it to build in the build service
> > yet.
>
> Both Fedora and Ubuntu should be packaging it. Further Docker should
> already be using these files.
>
> > It looks like the only addition it needs is the setgroups flag for
> > newgidmap, which the security people will need, so I can patch
> > that. Plus it's trying to install newgidmap/newuidmap as setuid
> > root rather than cap_setuid/cap_setgid, but that's fixable in the
> > spec file.
>
> I read the rest of this thread and I don't understand the setgroups
> flag that you desire. It sounds like someone with an incomplete
> grasp on the situtation being cautious.
>
> As far as I can tell the use cases for containers not supporting
> setgroups is very limited. Basically just using user namespaces to
> drop privileges, and mapping the existing uids and gids to 0.
>
> I don't think it actually makes sense to have a knob. From a
> practical standpoint entering any subordinate ids into the subgid
> file for a user is a permission to use groups in such a way that can
> not use them as a negative acl (because we allow them to be dropped).
>
> Certainly it has been that way for quite a while now.
I don't quite get this. If setgroups is set to deny and I have a set
of group mappings, I still can't get rid of the negative acl group. I
can map it to a different gid inside my container, or I can not map it
at all, but in either case I still can't get access to anything with
the negative acl group marker because the group permission checks
occurs with the kguid_t set which includes my mapped or unmapped group.
The only way I can lose it is to call sys_setgroups().
It's a bit ugly because I have to enter the container with --preserve
-credentials and I can't su to myself if I enter as root (-S 0), I have
to re-enter as myself instead, but it works.
> Except for the negative acl aspect there are no issues with dropping
> groups, as setgroups will limit you to the groups allowed in your
> user namespace.
Well, notwithstanding the merits of negative acls, which I don't want
to debate because I don't think they're that useful, the use case might
be that a user possessing a negative acl still wants to use an
architecture emulation container for building. Installing such a
container requires being able to set a set of groups and uids (required
by the installer), but it doesn't require the sys_setgroups() system
call, so they could reasonably be given the ability to set one up with
the nosetgroups flag and a range of gids allocated in subgid to ensure
they still can't get access to resources denied by the negative acl
group.
James
_______________________________________________
Containers mailing list
Containers@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/containers
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
2016-05-04 15:02 ` Eric W. Biederman
2016-05-04 15:21 ` Phil Estes
[not found] ` <87wpn9988a.fsf-JOvCrm2gF+uungPnsOpG7nhyD016LWXt@public.gmane.org>
@ 2016-05-04 18:17 ` James Bottomley
2016-05-04 18:21 ` James Bottomley
[not found] ` <1462385876.14310.90.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
2 siblings, 2 replies; 28+ messages in thread
From: James Bottomley @ 2016-05-04 18:17 UTC (permalink / raw)
To: Eric W. Biederman; +Cc: systemd-devel, Linux Containers, util-linux
On Wed, 2016-05-04 at 10:02 -0500, Eric W. Biederman wrote:
> James Bottomley <James.Bottomley@HansenPartnership.com> writes:
>
> > On Thu, 2016-04-28 at 16:00 -0700, W. Trevor King wrote:
> > > On Thu, Apr 28, 2016 at 03:02:08PM -0700, James Bottomley wrote:
> > > > /etc/usernamespaces
> > > >
> > > > and the format be :::
> > > >
> > > > …
> > > >
> > > > If this sounds OK to people, I can code up a utility that does
> > > > this, which should probably belong in util-linux.
> > >
> > > This sounds a lot like shadow's newuidmap and newgidmap [1,2,3].
> > >
> > > Cheers,
> > > Trevor
> > >
> > > [1]: https://github.com/shadow-maint/shadow/commit/673c2a6f9aa6c6
> > > 9588f4c1be08589b8d3475a520
> > > [2]: http://man7.org/linux/man-pages/man1/newuidmap.1.html
> > > [3]: http://man7.org/linux/man-pages/man5/subuid.5.html
> >
> > I think that mostly works. No-one's packaging it yet, which is why
> > I didn't notice. It also looks like the build dependencies have
> > vastly expanded, so I can't get it to build in the build service
> > yet.
>
> Both Fedora and Ubuntu should be packaging it. Further Docker should
> already be using these files.
>
> > It looks like the only addition it needs is the setgroups flag for
> > newgidmap, which the security people will need, so I can patch
> > that. Plus it's trying to install newgidmap/newuidmap as setuid
> > root rather than cap_setuid/cap_setgid, but that's fixable in the
> > spec file.
>
> I read the rest of this thread and I don't understand the setgroups
> flag that you desire. It sounds like someone with an incomplete
> grasp on the situtation being cautious.
>
> As far as I can tell the use cases for containers not supporting
> setgroups is very limited. Basically just using user namespaces to
> drop privileges, and mapping the existing uids and gids to 0.
>
> I don't think it actually makes sense to have a knob. From a
> practical standpoint entering any subordinate ids into the subgid
> file for a user is a permission to use groups in such a way that can
> not use them as a negative acl (because we allow them to be dropped).
>
> Certainly it has been that way for quite a while now.
I don't quite get this. If setgroups is set to deny and I have a set
of group mappings, I still can't get rid of the negative acl group. I
can map it to a different gid inside my container, or I can not map it
at all, but in either case I still can't get access to anything with
the negative acl group marker because the group permission checks
occurs with the kguid_t set which includes my mapped or unmapped group.
The only way I can lose it is to call sys_setgroups().
It's a bit ugly because I have to enter the container with --preserve
-credentials and I can't su to myself if I enter as root (-S 0), I have
to re-enter as myself instead, but it works.
> Except for the negative acl aspect there are no issues with dropping
> groups, as setgroups will limit you to the groups allowed in your
> user namespace.
Well, notwithstanding the merits of negative acls, which I don't want
to debate because I don't think they're that useful, the use case might
be that a user possessing a negative acl still wants to use an
architecture emulation container for building. Installing such a
container requires being able to set a set of groups and uids (required
by the installer), but it doesn't require the sys_setgroups() system
call, so they could reasonably be given the ability to set one up with
the nosetgroups flag and a range of gids allocated in subgid to ensure
they still can't get access to resources denied by the negative acl
group.
James
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
[not found] ` <1462385876.14310.90.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
@ 2016-05-04 18:21 ` James Bottomley
0 siblings, 0 replies; 28+ messages in thread
From: James Bottomley @ 2016-05-04 18:21 UTC (permalink / raw)
To: Eric W. Biederman
Cc: Linux Containers, systemd-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
util-linux-u79uwXL29TY76Z2rM5mHXA
On Wed, 2016-05-04 at 14:17 -0400, James Bottomley wrote:
> > Certainly it has been that way for quite a while now.
>
> I don't quite get this. If setgroups is set to deny and I have a set
> of group mappings, I still can't get rid of the negative acl group.
> I can map it to a different gid inside my container, or I can not
> map it at all, but in either case I still can't get access to
> anything with the negative acl group marker because the group
> permission checks occurs with the kguid_t set which includes my
> mapped or unmapped group. The only way I can lose it is to call
> sys_setgroups().
Sorry, this next bit should be at the end of the email (I was playing
and typing at the same time):
> It's a bit ugly because I have to enter the container with --preserve
> -credentials and I can't su to myself if I enter as root (-S 0), I
> have to re-enter as myself instead, but it works.
>
> > Except for the negative acl aspect there are no issues with
> > dropping groups, as setgroups will limit you to the groups allowed
> > in your user namespace.
>
> Well, notwithstanding the merits of negative acls, which I don't want
> to debate because I don't think they're that useful, the use case
> might be that a user possessing a negative acl still wants to use an
> architecture emulation container for building. Installing such a
> container requires being able to set a set of groups and uids
> (required by the installer), but it doesn't require the
> sys_setgroups() system call, so they could reasonably be given the
> ability to set one up with the nosetgroups flag and a range of gids
> allocated in subgid to ensure they still can't get access to
> resources denied by the negative acl group.
It's a bit ugly because I have to enter the container with --preserve
-credentials and I can't su to myself if I enter as root (-S 0), I have
to re-enter as myself instead, but it works.
James
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: Unprivileged containers and co-ordinating user namespaces
2016-05-04 18:17 ` James Bottomley
@ 2016-05-04 18:21 ` James Bottomley
[not found] ` <1462385876.14310.90.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
1 sibling, 0 replies; 28+ messages in thread
From: James Bottomley @ 2016-05-04 18:21 UTC (permalink / raw)
To: Eric W. Biederman; +Cc: Linux Containers, systemd-devel, util-linux
On Wed, 2016-05-04 at 14:17 -0400, James Bottomley wrote:
> > Certainly it has been that way for quite a while now.
>
> I don't quite get this. If setgroups is set to deny and I have a set
> of group mappings, I still can't get rid of the negative acl group.
> I can map it to a different gid inside my container, or I can not
> map it at all, but in either case I still can't get access to
> anything with the negative acl group marker because the group
> permission checks occurs with the kguid_t set which includes my
> mapped or unmapped group. The only way I can lose it is to call
> sys_setgroups().
Sorry, this next bit should be at the end of the email (I was playing
and typing at the same time):
> It's a bit ugly because I have to enter the container with --preserve
> -credentials and I can't su to myself if I enter as root (-S 0), I
> have to re-enter as myself instead, but it works.
>
> > Except for the negative acl aspect there are no issues with
> > dropping groups, as setgroups will limit you to the groups allowed
> > in your user namespace.
>
> Well, notwithstanding the merits of negative acls, which I don't want
> to debate because I don't think they're that useful, the use case
> might be that a user possessing a negative acl still wants to use an
> architecture emulation container for building. Installing such a
> container requires being able to set a set of groups and uids
> (required by the installer), but it doesn't require the
> sys_setgroups() system call, so they could reasonably be given the
> ability to set one up with the nosetgroups flag and a range of gids
> allocated in subgid to ensure they still can't get access to
> resources denied by the negative acl group.
It's a bit ugly because I have to enter the container with --preserve
-credentials and I can't su to myself if I enter as root (-S 0), I have
to re-enter as myself instead, but it works.
James
^ permalink raw reply [flat|nested] 28+ messages in thread
end of thread, other threads:[~2016-05-04 18:21 UTC | newest]
Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-04-28 22:02 Unprivileged containers and co-ordinating user namespaces James Bottomley
2016-04-28 22:02 ` James Bottomley
[not found] ` <1461880928.2307.48.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
2016-04-28 23:00 ` W. Trevor King
2016-04-28 23:00 ` W. Trevor King
[not found] ` <20160428230045.GS22888-q4NCUed9G3sTnwFZoN752g@public.gmane.org>
2016-04-29 15:38 ` James Bottomley
2016-04-29 15:38 ` James Bottomley
2016-04-29 15:53 ` Serge E. Hallyn
[not found] ` <20160429155303.GA8900-7LNsyQBKDXoIagZqoN9o3w@public.gmane.org>
2016-04-29 18:34 ` W. Trevor King
2016-04-29 18:34 ` W. Trevor King
2016-04-29 21:50 ` Serge E. Hallyn
[not found] ` <20160429183404.GE22888-q4NCUed9G3sTnwFZoN752g@public.gmane.org>
2016-04-29 21:50 ` Serge E. Hallyn
2016-04-29 22:18 ` James Bottomley
2016-05-01 16:37 ` Serge Hallyn
2016-05-01 23:29 ` James Bottomley
[not found] ` <1462145366.2337.18.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
2016-05-02 4:13 ` Serge E. Hallyn
2016-05-02 4:13 ` Serge E. Hallyn
2016-05-01 23:29 ` James Bottomley
[not found] ` <1461968310.16292.20.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
2016-05-01 16:37 ` Serge Hallyn
2016-05-04 15:02 ` Eric W. Biederman
2016-05-04 15:21 ` Phil Estes
[not found] ` <87wpn9988a.fsf-JOvCrm2gF+uungPnsOpG7nhyD016LWXt@public.gmane.org>
2016-05-04 15:21 ` Phil Estes
2016-05-04 18:17 ` James Bottomley
2016-05-04 18:17 ` James Bottomley
2016-05-04 18:21 ` James Bottomley
[not found] ` <1462385876.14310.90.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
2016-05-04 18:21 ` James Bottomley
[not found] ` <1461944328.2311.10.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
2016-04-29 15:53 ` Serge E. Hallyn
2016-04-29 22:18 ` James Bottomley
2016-05-04 15:02 ` Eric W. Biederman
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.