[systemd-devel] [PATCH] Add detect_userns to detect uid/gid shifts (V2)

Stéphane Graber stgraber at ubuntu.com
Fri Jan 9 07:14:39 PST 2015


On Fri, Jan 09, 2015 at 11:08:26AM +0100, David Herrmann wrote:
> Hi
> 
> On Fri, Jan 9, 2015 at 12:07 AM, Stéphane Graber <stgraber at ubuntu.com> wrote:
> > This adds a new detect_userns function in virt.c which will check
> > whether systemd is running in the host user namespace (single map of all
> > available uids and gids) or is using a uid/gid map.
> >
> > The check makes sure that uid_map and gid_map are both exactly equal to
> > the default host map (assuming 32bit uid_t) for a process running in the
> > host namespace.
> > ---
> >  src/shared/virt.c | 43 +++++++++++++++++++++++++++++++++++++++++++
> >  src/shared/virt.h |  1 +
> >  2 files changed, 44 insertions(+)
> >
> > diff --git a/src/shared/virt.c b/src/shared/virt.c
> > index f10baab..7fa8d0b 100644
> > --- a/src/shared/virt.c
> > +++ b/src/shared/virt.c
> > @@ -22,6 +22,7 @@
> >  #include <string.h>
> >  #include <errno.h>
> >  #include <unistd.h>
> > +#include <limits.h>
> >
> >  #include "util.h"
> >  #include "virt.h"
> > @@ -363,3 +364,45 @@ int detect_virtualization(const char **id) {
> >
> >          return VIRTUALIZATION_NONE;
> >  }
> > +
> > +/* Detect whether we run in a uid/gid shifted namespace */
> > +int detect_userns(void) {
> > +        int r;
> > +
> > +        _cleanup_free_ char* uid_map = NULL;
> > +        _cleanup_free_ char* gid_map = NULL;
> > +
> > +        uid_t id_host = 0;
> > +        uid_t id_container = 0;
> > +        uid_t id_count = 0;
> > +
> > +        /* Check if we are uid-shifted */
> > +        r = read_one_line_file("/proc/self/uid_map", &uid_map);
> > +        if (r == 0 &&
> > +            sscanf(uid_map, "%u %u %u", &id_host, &id_container, &id_count) &&
> > +            (id_host != 0 || id_container != 0 || id_count != UINT_MAX))
> > +                return 1;
> > +
> > +        /* Check if we are gid-shifted */
> > +        r = read_one_line_file("/proc/self/gid_map", &gid_map);
> > +        if (r == 0 &&
> > +            sscanf(gid_map, "%u %u %u", &id_host, &id_container, &id_count) &&
> > +            (id_host != 0 || id_container != 0 || id_count != UINT_MAX))
> > +                return 1;
> > +
> 
> Do these files describe the mapping into the init_user_ns or into the
> parent namespace? Because in the second case, if you create a
> user-namespace with a non-identity mapping and inside of it a user-ns
> with an identity-mapping, your detect_userns() will return 0, even
> though you run in a user-namespace.

Into the parent namespace.

An example is:
 - host (0 0 4294967295) (init_user_ns all uids mapped)
   - container (0 1000000 1000000) (a million uids mapped from 0 to 1000000 in the namespace, corresponding to 1000000 to 1999999 on the host)
     - sub-container (0 100000 65536) (65536 uids mapped from 0 to 65536 in the namespace, corresponding to 100000 to 165534 in container and 1100000 to 1165534 on the host)

You can't create a new userns mapping uids which aren't in your own
userns so the child userns map will at most be the same as its parent.

So it's therefore impossible to have a sub-userns with a map of "0 0
4294967295" if its parent userns has something more restrictive. If it
doesn't, then we're back in that last corner case where you can indeed
create userns with a map identical to the init_user_ns map in which case
uid 0 in container == uid 0 on the host.

> 
> Thanks
> David
> 
> > +        /* In the following cases, let's assume we are in the host namespace:
> > +           - Neither uid_map nor gid_map exist in /proc/self.
> > +             (this indicates lack of userns support in the kernel)
> > +
> > +           - Both the uid and gid map equals to the complete set of available
> > +             uids or gids. This can only be true on the host namespace or if a
> > +             container was setup to have the same map as the host.
> > +
> > +             That last possibility isn't detectable short of guessing
> > +             based on syscall results but there's also no real use case
> > +             for such a setup (why create a new uid/gid mapping namespace
> > +             if you then re-use the host map as-is?).
> > +         */
> > +
> > +        return 0;
> > +}
> > diff --git a/src/shared/virt.h b/src/shared/virt.h
> > index 7194ab2..e19c7e8 100644
> > --- a/src/shared/virt.h
> > +++ b/src/shared/virt.h
> > @@ -33,3 +33,4 @@ enum {
> >  };
> >
> >  int detect_virtualization(const char **id);
> > +int detect_userns(void);
> > --
> > 1.9.1
> >
> > _______________________________________________
> > systemd-devel mailing list
> > systemd-devel at lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/systemd-devel

-- 
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.freedesktop.org/archives/systemd-devel/attachments/20150109/3b256dd0/attachment-0001.sig>


More information about the systemd-devel mailing list