Quoting Christian Brauner (christian.brau...@mailbox.org): > As ls_get() is non-tail recursive we face the inherent danger of blowing up > the > stack at some level of nesting. To have at least some security we define > MAX_NESTLVL to be 5. That should be sufficient for most users. The argument > lvl > to ls_get() can be used to keep track of the level of nesting we are at. If > lvl > is greater than the allowed default level return (without error) and unwind > the > stack. > > --nesting gains an optional numeric argument. This allows the user to specify > the maximum level of nesting she/he wants to see. Fair warning: If your > nesting > level is really deep and/or you have a lot of containers your might run into > trouble. > > Signed-off-by: Christian Brauner <christian.brau...@mailbox.org>
Acked-by: Serge E. Hallyn <serge.hal...@ubuntu.com> > --- > src/lxc/arguments.h | 2 +- > src/lxc/lxc_ls.c | 37 ++++++++++++++++++++++++++++++++++--- > 2 files changed, 35 insertions(+), 4 deletions(-) > > diff --git a/src/lxc/arguments.h b/src/lxc/arguments.h > index 898a9ce..a3d2932 100644 > --- a/src/lxc/arguments.h > +++ b/src/lxc/arguments.h > @@ -124,11 +124,11 @@ struct lxc_arguments { > char *ls_fancy_format; > char *ls_groups; > char *ls_regex; > + unsigned int ls_nesting; /* maximum allowed nesting level */ > bool ls_active; > bool ls_fancy; > bool ls_frozen; > bool ls_line; > - bool ls_nesting; > bool ls_running; > bool ls_stopped; > > diff --git a/src/lxc/lxc_ls.c b/src/lxc/lxc_ls.c > index 3a7fa15..a4ab9b6 100644 > --- a/src/lxc/lxc_ls.c > +++ b/src/lxc/lxc_ls.c > @@ -40,6 +40,10 @@ > lxc_log_define(lxc_ls, lxc); > > #define LINELEN 1024 > +/* Per default we only allow five levels of recursion to protect the stack at > + * least a little bit. */ > +#define MAX_NESTLVL 5 > + > #define LS_FROZEN 1 > #define LS_STOPPED 2 > #define LS_ACTIVE 3 > @@ -154,7 +158,7 @@ static const struct option my_longopts[] = { > {"running", no_argument, 0, LS_RUNNING}, > {"frozen", no_argument, 0, LS_FROZEN}, > {"stopped", no_argument, 0, LS_STOPPED}, > - {"nesting", no_argument, 0, LS_NESTING}, > + {"nesting", optional_argument, 0, LS_NESTING}, > {"groups", required_argument, 0, 'g'}, > {"regex", required_argument, 0, 'r'}, > LXC_COMMON_OPTIONS > @@ -177,11 +181,12 @@ Options :\n\ > --running list only running containers\n\ > --frozen list only frozen containers\n\ > --stopped list only stopped containers\n\ > - --nesting list nested containers\n\ > + --nesting=NUM list nested containers up to NUM (default is 5) levels > of nesting\n\ > -r --regex filter container names by regular expression\n\ > -g --groups comma separated list of groups a container must have to > be displayed\n", > .options = my_longopts, > .parser = my_parser, > + .ls_nesting = MAX_NESTLVL, > }; > > int main(int argc, char *argv[]) > @@ -300,6 +305,16 @@ static int ls_get(struct ls **m, size_t *size, const > struct lxc_arguments *args, > struct lengths *lht, const char *basepath, const char *parent, > unsigned int lvl) > { > + /* As ls_get() is non-tail recursive we face the inherent danger of > + * blowing up the stack at some level of nesting. To have at least some > + * security we define MAX_NESTLVL to be 5. That should be sufficient for > + * most users. The argument lvl can be used to keep track of the level > + * of nesting we are at. If lvl is greater than the allowed default > + * level or the level the user specified on the command line we return > + * and unwind the stack. */ > + if (lvl > args->ls_nesting) > + return 0; > + > int num = 0, ret = -1; > char **containers = NULL; > /* If we, at some level of nesting, encounter a stopped container but > @@ -855,6 +870,8 @@ static void ls_print_table(struct ls *l, struct lengths > *lht, > > static int my_parser(struct lxc_arguments *args, int c, char *arg) > { > + char *invalid; > + unsigned long int m, n = MAX_NESTLVL; > switch (c) { > case '1': > args->ls_line = true; > @@ -875,7 +892,21 @@ static int my_parser(struct lxc_arguments *args, int c, > char *arg) > args->ls_stopped = true; > break; > case LS_NESTING: > - args->ls_nesting = true; > + /* In case strtoul() receives a string that represents a > + * negative number it will return ULONG_MAX - the number that > + * string represents if the number the string represents is < > + * ULONG_MAX and ULONG_MAX otherwise. But it will consider this > + * valid input and not set errno. So we check manually if the > + * first character of num_string == '-'. Otherwise the default > + * level remains set. */ > + if (arg && !(*arg == '-')) { > + errno = 0; > + m = strtoul(arg, &invalid, 0); > + /* ls_nesting has type unsigned int. */ > + if (!errno && (*invalid == '\0') && (m <= UINT_MAX)) > + n = m; > + } > + args->ls_nesting = n; > break; > case 'g': > args->groups = arg; > -- > 2.7.0 > _______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel