[CRIU] [PATCH 4/4] Move dump of credentials to parasite

Sophie Blee-Goldman ableegoldman at google.com
Mon Aug 11 23:02:52 PDT 2014


Yes, it seems like it would be easiest to get the correct uids and gids for
ghost files in this way. More on this in my other response, to [PATCH 1/4].


On Mon, Aug 11, 2014 at 6:27 AM, Andrew Vagin <avagin at parallels.com> wrote:

> On Fri, Aug 08, 2014 at 10:23:09PM -0700, Sophie Blee-Goldman wrote:
> > Moves the dump of credentials to the parasite, in case the process
> > lives in a user namespace and has different uids, gids, or
> > capabilities inside it.
>
> We save uid-s for ghost files, which should be remapped too.
>
> Can we remap uid-s and gid-s during dump according with uid_maps and
> gid_maps?
>
> https://github.com/avagin/criu/commit/9ae1b290bccc6d4add75107b95aca6b336aa3845
>
> >
> > Signed-off-by: Sophie Blee-Goldman <ableegoldman at google.com>
> >
> > diff --git a/arch/arm/syscall.def b/arch/arm/syscall.def
> > index c539e3e..5df83cb 100644
> > --- a/arch/arm/syscall.def
> > +++ b/arch/arm/syscall.def
> > @@ -54,11 +54,14 @@ readlink                  78      85      (const
> char *path, char *buf, int bufsize)
> >  umask                                166     60      (int mask)
> >  getgroups                    158     205     (int gsize, unsigned int
> *groups)
> >  setresuid                    147     164     (int uid, int euid, int
> suid)
> > +getresuid                    148     165     (unsigned int *uid,
> unsigned int *euid, unsigned int *suid)
> >  setresgid                    149     170     (int gid, int egid, int
> sgid)
> > +getresgid                    150     171     (unsigned int *uid,
> unsigned int *euid, unsigned int *suid)
> >  getpgid                              155     132     (pid_t pid)
> >  setfsuid                     151     138     (int fsuid)
> >  setfsgid                     152     139     (int fsgid)
> >  getsid                               156     147     (void)
> > +capget                               90      184     (struct cap_header
> *h, struct cap_data *d)
> >  capset                               91      185     (struct cap_header
> *h, struct cap_data *d)
> >  rt_sigqueueinfo                      138     178     (pid_t pid, int
> sig, siginfo_t *info)
> >  setpriority                  140     97      (int which, int who, int
> nice)
> > diff --git a/arch/x86/syscall-x86-64.def b/arch/x86/syscall-x86-64.def
> > index 878cf79..112366b 100644
> > --- a/arch/x86/syscall-x86-64.def
> > +++ b/arch/x86/syscall-x86-64.def
> > @@ -54,11 +54,14 @@ __NR_readlink             89
>  sys_readlink            (const char *path, char *buf, int bufsize)
> >  __NR_umask           95              sys_umask               (int mask)
> >  __NR_getgroups               115             sys_getgroups
> (int gsize, unsigned int *groups)
> >  __NR_setresuid               117             sys_setresuid
> (int uid, int euid, int suid)
> > +__NR_getresuid               118             sys_getresuid
> (unsigned int *uid, unsigned int *euid, unsigned int *suid)
> >  __NR_setresgid               119             sys_setresgid
> (int gid, int egid, int sgid)
> > +__NR_getresgid               120             sys_getresgid
> (unsigned int *uid, unsigned int *euid, unsigned int *suid)
> >  __NR_getpgid         121             sys_getpgid             (pid_t pid)
> >  __NR_setfsuid                122             sys_setfsuid
>  (int fsuid)
> >  __NR_setfsgid                123             sys_setfsgid
>  (int fsgid)
> >  __NR_getsid          124             sys_getsid              (void)
> > +__NR_capget          125             sys_capget              (struct
> cap_header *h, struct cap_data *d)
> >  __NR_capset          126             sys_capset              (struct
> cap_header *h, struct cap_data *d)
> >  __NR_rt_sigqueueinfo 129             sys_rt_sigqueueinfo     (pid_t
> pid, int sig, siginfo_t *info)
> >  __NR_sigaltstack     131             sys_sigaltstack         (const
> void *uss, void *uoss)
> > diff --git a/cr-dump.c b/cr-dump.c
> > index 1700d9d..b4bc8a8 100644
> > --- a/cr-dump.c
> > +++ b/cr-dump.c
> > @@ -497,8 +497,7 @@ err:
> >  }
> >
> >  static int dump_task_creds(struct parasite_ctl *ctl,
> > -                        const struct cr_fdset *fds,
> > -                        struct proc_status_creds *cr)
> > +                        const struct cr_fdset *fds)
> >  {
> >       CredsEntry ce = CREDS_ENTRY__INIT;
> >
> > @@ -506,26 +505,6 @@ static int dump_task_creds(struct parasite_ctl *ctl,
> >       pr_info("Dumping creds for %d)\n", ctl->pid.real);
> >       pr_info("----------------------------------------\n");
> >
> > -     ce.uid   = cr->uids[0];
> > -     ce.gid   = cr->gids[0];
> > -     ce.euid  = cr->uids[1];
> > -     ce.egid  = cr->gids[1];
> > -     ce.suid  = cr->uids[2];
> > -     ce.sgid  = cr->gids[2];
> > -     ce.fsuid = cr->uids[3];
> > -     ce.fsgid = cr->gids[3];
> > -
> > -     BUILD_BUG_ON(CR_CAP_SIZE != PROC_CAP_SIZE);
> > -
> > -     ce.n_cap_inh = CR_CAP_SIZE;
> > -     ce.cap_inh = cr->cap_inh;
> > -     ce.n_cap_prm = CR_CAP_SIZE;
> > -     ce.cap_prm = cr->cap_prm;
> > -     ce.n_cap_eff = CR_CAP_SIZE;
> > -     ce.cap_eff = cr->cap_eff;
> > -     ce.n_cap_bnd = CR_CAP_SIZE;
> > -     ce.cap_bnd = cr->cap_bnd;
> > -
> >       if (parasite_dump_creds(ctl, &ce) < 0)
> >               return -1;
> >
> > @@ -1608,7 +1587,7 @@ static int dump_one_task(struct pstree_item *item)
> >               goto err_cure;
> >       }
> >
> > -     ret = dump_task_creds(parasite_ctl, cr_fdset, &cr);
> > +     ret = dump_task_creds(parasite_ctl, cr_fdset);
> >       if (ret) {
> >               pr_err("Dump creds (pid: %d) failed with %d\n", pid, ret);
> >               goto err;
> > diff --git a/include/parasite.h b/include/parasite.h
> > index af81d85..a6a60bb 100644
> > --- a/include/parasite.h
> > +++ b/include/parasite.h
> > @@ -166,10 +166,24 @@ struct parasite_dump_misc {
> >   * Calculate how long we can make the groups array in
> parasite_dump_creds
> >   * and still fit the struct in one page
> >   */
> > -#define PARASITE_MAX_GROUPS  \
> > -     ((PAGE_SIZE - 2 * sizeof(unsigned int)) / sizeof(unsigned int))
> > +#define PARASITE_MAX_GROUPS
>      \
> > +     (PAGE_SIZE
>      \
> > +      - sizeof(unsigned int)                 /* cap_last_cap */
>      \
> > +      - 8 * sizeof(unsigned int)             /* uids + gids */
>       \
> > +      - 4 * CR_CAP_SIZE * sizeof(u32)        /* cap_{inh,prm,eff,bnd}
> */     \
> > +      - 2 * sizeof(unsigned int)             /* secbits, ngroups*/
>       \
> > +     ) / sizeof(unsigned int)                /* groups */
> >
> >  struct parasite_dump_creds {
> > +     unsigned int            cap_last_cap;
> > +     unsigned int            uids[4];
> > +     unsigned int            gids[4];
> > +
> > +     u32                     cap_inh[CR_CAP_SIZE];
> > +     u32                     cap_prm[CR_CAP_SIZE];
> > +     u32                     cap_eff[CR_CAP_SIZE];
> > +     u32                     cap_bnd[CR_CAP_SIZE];
> > +
> >       unsigned int            secbits;
> >       unsigned int            ngroups;
> >       unsigned int            groups[PARASITE_MAX_GROUPS];
> > diff --git a/include/prctl.h b/include/prctl.h
> > index b815b96..70db7b9 100644
> > --- a/include/prctl.h
> > +++ b/include/prctl.h
> > @@ -7,6 +7,9 @@
> >  #ifndef PR_GET_NAME
> >  # define PR_GET_NAME         16
> >  #endif
> > +#ifndef PR_CAPBSET_READ
> > +# define PR_CAPBSET_READ     23
> > +#endif
> >  #ifndef PR_CAPBSET_DROP
> >  # define PR_CAPBSET_DROP     24
> >  #endif
> > diff --git a/kerndat.c b/kerndat.c
> > index 0fee20b..3c87f6c 100644
> > --- a/kerndat.c
> > +++ b/kerndat.c
> > @@ -229,6 +229,8 @@ int kerndat_init(void)
> >               ret = kerndat_get_dirty_track();
> >       if (!ret)
> >               ret = init_zero_page_pfn();
> > +     if (!ret)
> > +             ret = get_last_cap();
> >
> >       return ret;
> >  }
> > diff --git a/parasite-syscall.c b/parasite-syscall.c
> > index dad2570..7e52108 100644
> > --- a/parasite-syscall.c
> > +++ b/parasite-syscall.c
> > @@ -738,9 +738,29 @@ int parasite_dump_creds(struct parasite_ctl *ctl,
> CredsEntry *ce)
> >       BUILD_BUG_ON(sizeof(*pc) > PAGE_SIZE);
> >
> >       pc = parasite_args(ctl, struct parasite_dump_creds);
> > +     pc->cap_last_cap = kern_last_cap;
> > +
> >       if (parasite_execute_daemon(PARASITE_CMD_DUMP_CREDS, ctl) < 0)
> >               return -1;
> >
> > +     ce->uid   = pc->uids[0];
> > +     ce->gid   = pc->gids[0];
> > +     ce->euid  = pc->uids[1];
> > +     ce->egid  = pc->gids[1];
> > +     ce->suid  = pc->uids[2];
> > +     ce->sgid  = pc->gids[2];
> > +     ce->fsuid = pc->uids[3];
> > +     ce->fsgid = pc->gids[3];
> > +
> > +     ce->n_cap_inh = CR_CAP_SIZE;
> > +     ce->cap_inh = pc->cap_inh;
> > +     ce->n_cap_prm = CR_CAP_SIZE;
> > +     ce->cap_prm = pc->cap_prm;
> > +     ce->n_cap_eff = CR_CAP_SIZE;
> > +     ce->cap_eff = pc->cap_eff;
> > +     ce->n_cap_bnd = CR_CAP_SIZE;
> > +     ce->cap_bnd = pc->cap_bnd;
> > +
> >       ce->secbits = pc->secbits;
> >       ce->n_groups = pc->ngroups;
> >
> > diff --git a/pie/parasite.c b/pie/parasite.c
> > index 92e7708..948718f 100644
> > --- a/pie/parasite.c
> > +++ b/pie/parasite.c
> > @@ -2,6 +2,7 @@
> >  #include <errno.h>
> >  #include <signal.h>
> >  #include <linux/limits.h>
> > +#include <linux/capability.h>
> >  #include <sys/mount.h>
> >  #include <stdarg.h>
> >  #include <sys/ioctl.h>
> > @@ -177,7 +178,59 @@ static int dump_misc(struct parasite_dump_misc
> *args)
> >
> >  static int dump_creds(struct parasite_dump_creds *args)
> >  {
> > -     int ret;
> > +     int ret, i, j;
> > +     struct cap_data data[_LINUX_CAPABILITY_U32S_3];
> > +     struct cap_header hdr = {_LINUX_CAPABILITY_VERSION_3, 0};
> > +
> > +     ret = sys_getresuid(&args->uids[0], &args->uids[1],
> &args->uids[2]);
> > +     if (ret < 0) {
> > +             pr_err("Error calling getresuid (%d)\n", ret);
> > +             return -1;
> > +     }
> > +
> > +     ret = sys_getresgid(&args->gids[0], &args->gids[1],
> &args->gids[2]);
> > +     if (ret < 0) {
> > +             pr_err("Error calling getresgid (%d)\n", ret);
> > +             return -1;
> > +     }
> > +
> > +     /*
> > +      * There is no getfsuid syscall, but setfsuid returns the existing
> > +      * fsuid on failure, so just call it with an invalid uid.
> > +      */
> > +     args->uids[3] = sys_setfsuid(-1);
> > +     args->gids[3] = sys_setfsgid(-1);
> > +
> > +     ret = sys_capget(&hdr, data);
> > +     if (ret < 0) {
> > +             pr_err("Unable to get capabilities: %d\n", ret);
> > +             return -1;
> > +     }
> > +
> > +     /*
> > +      * Loop through the capability constants until we reach
> cap_last_cap.
> > +      * The cap_bnd set is stored as a bitmask comprised of CR_CAP_SIZE
> number of
> > +      * 32-bit uints, hence the inner loop from 0 to 32.
> > +      */
> > +     for (i = 0; i < CR_CAP_SIZE; i++) {
> > +             args->cap_eff[i] = data[i].eff;
> > +             args->cap_prm[i] = data[i].prm;
> > +             args->cap_inh[i] = data[i].inh;
> > +             args->cap_bnd[i] = 0;
> > +
> > +             for (j = 0; j < 32; j++) {
> > +                     if (j + i * 32 > args->cap_last_cap)
> > +                             break;
> > +                     ret = sys_prctl(PR_CAPBSET_READ, j + i * 32, 0, 0,
> 0);
> > +                     if (ret < 0) {
> > +                             pr_err("Unable to read capability %d:
> %d\n",
> > +                                     j + i * 32, ret);
> > +                             return -1;
> > +                     }
> > +                     if (ret)
> > +                             args->cap_bnd[i] |= (1 << j);
> > +             }
> > +     }
> >
> >       args->secbits = sys_prctl(PR_GET_SECUREBITS, 0, 0, 0, 0);
> >
> > diff --git a/security.c b/security.c
> > index a801005..8a991d0 100644
> > --- a/security.c
> > +++ b/security.c
> > @@ -157,6 +157,12 @@ bool may_dump(struct proc_status_creds *creds)
> >               check_caps(creds->cap_inh, creds->cap_eff, creds->cap_prm);
> >  }
> >
> > +/*
> > + * TODO: The check_ids calls may incorrectly fail if criu is started by
> a
> > + * non-root user on a process in a user namespace, whose uid/gid
> matches the
> > + * caller's outside the namespace but is mapped to a different uid/gid
> > + * inside it.
> > + */
> >  bool may_restore(CredsEntry *creds)
> >  {
> >       return check_uids(creds->uid, creds->euid, creds->suid) &&
> > --
> > 2.0.0.526.g5318336
> >
> > _______________________________________________
> > CRIU mailing list
> > CRIU at openvz.org
> > https://lists.openvz.org/mailman/listinfo/criu
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openvz.org/pipermail/criu/attachments/20140811/9cc31f4e/attachment-0001.html>


More information about the CRIU mailing list